From 339866c1ae21e2b5e3d3da81a3dfecb141307fbb Mon Sep 17 00:00:00 2001 From: Colin Leroy Date: Tue, 4 Oct 2005 16:31:25 +0000 Subject: [PATCH 1/1] 2005-10-04 [colin] 1.9.15cvs9 * src/folder.c * src/folder.h * src/folderview.c * src/imap.c * src/etpan/imap-thread.c * src/etpan/imap-thread.h Try to make IMAP faster, by simplifying SEARCH commands, avoiding sending two STATUS in a row, and deferring flags sync and processing just after displaying the folder. This will update the SummaryView in certain cases (new mails not already fetched, flags changed from another client) but in a non- blocking manner. --- ChangeLog-gtk2.claws | 17 +++++ PATCHSETS | 1 + configure.ac | 2 +- src/etpan/imap-thread.c | 26 +++++-- src/etpan/imap-thread.h | 3 +- src/folder.c | 27 +++++-- src/folder.h | 2 +- src/folderview.c | 26 +++++++ src/imap.c | 164 +++++++++++++++++++++++++++++++--------- 9 files changed, 212 insertions(+), 56 deletions(-) diff --git a/ChangeLog-gtk2.claws b/ChangeLog-gtk2.claws index 504852aad..523d9fbeb 100644 --- a/ChangeLog-gtk2.claws +++ b/ChangeLog-gtk2.claws @@ -1,3 +1,20 @@ +2005-10-04 [colin] 1.9.15cvs9 + + * src/folder.c + * src/folder.h + * src/folderview.c + * src/imap.c + * src/etpan/imap-thread.c + * src/etpan/imap-thread.h + Try to make IMAP faster, by simplifying SEARCH + commands, avoiding sending two STATUS in a row, + and deferring flags sync and processing just + after displaying the folder. + This will update the SummaryView in certain + cases (new mails not already fetched, flags + changed from another client) but in a non- + blocking manner. + 2005-10-04 [colin] 1.9.15cvs8 * src/plugins/trayicon/trayicon.c diff --git a/PATCHSETS b/PATCHSETS index 570ded649..5702d0776 100644 --- a/PATCHSETS +++ b/PATCHSETS @@ -845,3 +845,4 @@ ( cvs diff -u -r 1.213.2.59 -r 1.213.2.60 src/folder.c; cvs diff -u -r 1.207.2.65 -r 1.207.2.66 src/folderview.c; cvs diff -u -r 1.395.2.129 -r 1.395.2.130 src/summaryview.c; ) > 1.9.15cvs6.patchset ( cvs diff -u -r 1.8.2.10 -r 1.8.2.11 src/export.c; cvs diff -u -r 1.13.2.10 -r 1.13.2.11 src/import.c; cvs diff -u -r 1.28.2.10 -r 1.28.2.11 src/mbox.c; cvs diff -u -r 1.14.2.21 -r 1.14.2.22 src/plugins/trayicon/trayicon.c; ) > 1.9.15cvs7.patchset ( cvs diff -u -r 1.14.2.22 -r 1.14.2.23 src/plugins/trayicon/trayicon.c; ) > 1.9.15cvs8.patchset +( cvs diff -u -r 1.213.2.60 -r 1.213.2.61 src/folder.c; cvs diff -u -r 1.87.2.19 -r 1.87.2.20 src/folder.h; cvs diff -u -r 1.207.2.66 -r 1.207.2.67 src/folderview.c; cvs diff -u -r 1.179.2.74 -r 1.179.2.75 src/imap.c; cvs diff -u -r 1.1.4.21 -r 1.1.4.22 src/etpan/imap-thread.c; cvs diff -u -r 1.1.4.6 -r 1.1.4.7 src/etpan/imap-thread.h; ) > 1.9.15cvs9.patchset diff --git a/configure.ac b/configure.ac index 6a6d494c5..65f49d890 100644 --- a/configure.ac +++ b/configure.ac @@ -11,7 +11,7 @@ MINOR_VERSION=9 MICRO_VERSION=15 INTERFACE_AGE=0 BINARY_AGE=0 -EXTRA_VERSION=8 +EXTRA_VERSION=9 EXTRA_RELEASE= EXTRA_GTK2_VERSION= diff --git a/src/etpan/imap-thread.c b/src/etpan/imap-thread.c index f53cd2df5..97dee7c1f 100644 --- a/src/etpan/imap-thread.c +++ b/src/etpan/imap-thread.c @@ -572,7 +572,8 @@ static void status_run(struct etpan_thread_op * op) } int imap_threaded_status(Folder * folder, const char * mb, - struct mailimap_mailbox_data_status ** data_status) + struct mailimap_mailbox_data_status ** data_status, + guint mask) { struct status_param param; struct status_result result; @@ -581,17 +582,26 @@ int imap_threaded_status(Folder * folder, const char * mb, debug_print("imap status - begin\n"); status_att_list = mailimap_status_att_list_new_empty(); - mailimap_status_att_list_add(status_att_list, + if (mask & 1 << 0) { + mailimap_status_att_list_add(status_att_list, MAILIMAP_STATUS_ATT_MESSAGES); - mailimap_status_att_list_add(status_att_list, + } + if (mask & 1 << 1) { + mailimap_status_att_list_add(status_att_list, MAILIMAP_STATUS_ATT_RECENT); - mailimap_status_att_list_add(status_att_list, + } + if (mask & 1 << 2) { + mailimap_status_att_list_add(status_att_list, MAILIMAP_STATUS_ATT_UIDNEXT); - mailimap_status_att_list_add(status_att_list, + } + if (mask & 1 << 3) { + mailimap_status_att_list_add(status_att_list, MAILIMAP_STATUS_ATT_UIDVALIDITY); - mailimap_status_att_list_add(status_att_list, + } + if (mask & 1 << 4) { + mailimap_status_att_list_add(status_att_list, MAILIMAP_STATUS_ATT_UNSEEN); - + } param.imap = get_imap(folder); param.mb = mb; param.status_att_list = status_att_list; @@ -1065,7 +1075,7 @@ int imap_threaded_search(Folder * folder, int search_type, mailimap * imap; debug_print("imap search - begin\n"); - + imap = get_imap(folder); param.imap = imap; param.set = set; diff --git a/src/etpan/imap-thread.h b/src/etpan/imap-thread.h index ea40eac1d..562d6df84 100644 --- a/src/etpan/imap-thread.h +++ b/src/etpan/imap-thread.h @@ -29,7 +29,8 @@ int imap_threaded_login(Folder * folder, const char * login, const char * password, const char * type); int imap_threaded_status(Folder * folder, const char * mb, - struct mailimap_mailbox_data_status ** data_status); + struct mailimap_mailbox_data_status ** data_status, + guint mask); int imap_threaded_noop(Folder * folder, unsigned int * p_exists); int imap_threaded_starttls(Folder * folder); diff --git a/src/folder.c b/src/folder.c index 7b136962e..ccb93f747 100644 --- a/src/folder.c +++ b/src/folder.c @@ -1461,16 +1461,17 @@ static gint folder_sort_folder_list(gconstpointer a, gconstpointer b) return (gint_a - gint_b); } -gint folder_item_open(FolderItem *item) +void folder_item_process_open(FolderItem *item) { gchar *buf; - g_return_val_if_fail(item->no_select == FALSE, -1); - + if (item == NULL) + return; if((item->folder->klass->scan_required != NULL) && (item->folder->klass->scan_required(item->folder, item))) { folder_item_scan_full(item, TRUE); + } else { + folder_item_syncronize_flags(item); } - folder_item_syncronize_flags(item); /* Processing */ buf = g_strdup_printf(_("Processing (%s)...\n"), @@ -1480,9 +1481,15 @@ gint folder_item_open(FolderItem *item) folder_item_apply_processing(item); - item->opened = TRUE; - debug_print("done.\n"); + return; +} + +gint folder_item_open(FolderItem *item) +{ + g_return_val_if_fail(item->no_select == FALSE, -1); + + item->opened = TRUE; return 0; } @@ -1783,12 +1790,16 @@ gint folder_item_scan_full(FolderItem *item, gboolean filtering) g_slist_free(folder_list); if (new_list != NULL) { + GSList *tmp_list = NULL; newmsg_list = get_msginfos(item, new_list); g_slist_free(new_list); + tmp_list = g_slist_concat(g_slist_copy(exists_list), g_slist_copy(newmsg_list)); + syncronize_flags(item, tmp_list); + g_slist_free(tmp_list); + } else { + syncronize_flags(item, exists_list); } - syncronize_flags(item, exists_list); - folder_item_update_freeze(); if (newmsg_list != NULL) { GSList *elem; diff --git a/src/folder.h b/src/folder.h index 67aa94f3c..e06f26486 100644 --- a/src/folder.h +++ b/src/folder.h @@ -811,5 +811,5 @@ void folder_item_set_batch (FolderItem *item, gboolean batch); gboolean folder_has_parent_of_type (FolderItem *item, SpecialFolderItemType type); void folder_synchronise (Folder *folder); gboolean folder_want_synchronise (Folder *folder); - +void folder_item_process_open (FolderItem *item); #endif /* __FOLDER_H__ */ diff --git a/src/folderview.c b/src/folderview.c index 0ce82f4de..8b8fd5a02 100644 --- a/src/folderview.c +++ b/src/folderview.c @@ -1766,6 +1766,29 @@ static gboolean folderview_key_pressed(GtkWidget *widget, GdkEventKey *event, return FALSE; } +gboolean folderview_process_open(gpointer data) +{ + FolderView *folderview = (FolderView *)data; + FolderItem *item = NULL; + + if (!folderview || !folderview->opened) { + debug_print("opened NULL\n"); + return FALSE; + } + item = gtk_ctree_node_get_row_data( + GTK_CTREE(folderview->ctree), + folderview->opened); + + if (!item) + return FALSE; + + folder_item_update_freeze(); + folder_item_process_open(item); + folder_item_update_thaw(); + + return FALSE; +} + static void folderview_selected(GtkCTree *ctree, GtkCTreeNode *row, gint column, FolderView *folderview) { @@ -1852,6 +1875,7 @@ static void folderview_selected(GtkCTree *ctree, GtkCTreeNode *row, return; } + main_window_cursor_normal(folderview->mainwin); @@ -1871,6 +1895,8 @@ static void folderview_selected(GtkCTree *ctree, GtkCTreeNode *row, gtk_ctree_node_moveto(ctree, row, -1, 0.5, 0); } + g_timeout_add(0, folderview_process_open, folderview); + STATUSBAR_POP(folderview->mainwin); folderview->open_folder = FALSE; diff --git a/src/imap.c b/src/imap.c index 9a5904084..98db8d5bc 100644 --- a/src/imap.c +++ b/src/imap.c @@ -156,6 +156,12 @@ struct _IMAPFolderItem guint uid_next; GSList *uid_list; gboolean batching; + + time_t use_cache; + gint c_messages; + guint32 c_uid_next; + guint32 c_uid_validity; + gint c_unseen; }; static void imap_folder_init (Folder *folder, @@ -271,8 +277,8 @@ static gint imap_select (IMAPSession *session, static gint imap_status (IMAPSession *session, IMAPFolder *folder, const gchar *path, + IMAPFolderItem *item, gint *messages, - gint *recent, guint32 *uid_next, guint32 *uid_validity, gint *unseen, @@ -997,6 +1003,7 @@ static gint imap_add_msgs(Folder *folder, FolderItem *dest, GSList *file_list, GSList *cur; MsgFileInfo *fileinfo; gint ok; + gint curnum = 0, total = 0; g_return_val_if_fail(folder != NULL, -1); @@ -1009,6 +1016,8 @@ static gint imap_add_msgs(Folder *folder, FolderItem *dest, GSList *file_list, } destdir = imap_get_real_path(IMAP_FOLDER(folder), dest->path); + statusbar_print_all(_("Adding messages...")); + total = g_slist_length(file_list); for (cur = file_list; cur != NULL; cur = cur->next) { IMAPFlags iflags = 0; guint32 new_uid = 0; @@ -1016,6 +1025,9 @@ static gint imap_add_msgs(Folder *folder, FolderItem *dest, GSList *file_list, gboolean file_is_tmp = FALSE; fileinfo = (MsgFileInfo *)cur->data; + statusbar_progress_all(curnum, total, 1); + curnum++; + if (fileinfo->flags) { if (MSG_IS_MARKED(*fileinfo->flags)) iflags |= IMAP_FLAG_FLAGGED; @@ -1071,6 +1083,8 @@ static gint imap_add_msgs(Folder *folder, FolderItem *dest, GSList *file_list, if (file_is_tmp) g_unlink(real_file); } + statusbar_progress_all(0,0,0); + statusbar_pop_all(); g_free(destdir); @@ -1088,7 +1102,7 @@ static gint imap_do_copy_msgs(Folder *folder, FolderItem *dest, gint ok = IMAP_SUCCESS; GRelation *uid_mapping; gint last_num = 0; - + g_return_val_if_fail(folder != NULL, -1); g_return_val_if_fail(dest != NULL, -1); g_return_val_if_fail(msglist != NULL, -1); @@ -1117,11 +1131,11 @@ static gint imap_do_copy_msgs(Folder *folder, FolderItem *dest, uid_mapping = g_relation_new(2); g_relation_index(uid_mapping, 0, g_direct_hash, g_direct_equal); + statusbar_print_all(_("Copying messages...")); for (cur = seq_list; cur != NULL; cur = g_slist_next(cur)) { struct mailimap_set * seq_set; - seq_set = cur->data; - + debug_print("Copying messages from %s to %s ...\n", src->path, destdir); @@ -1151,6 +1165,7 @@ static gint imap_do_copy_msgs(Folder *folder, FolderItem *dest, GPOINTER_TO_INT(0)); g_tuples_destroy(tuples); } + statusbar_pop_all(); g_relation_destroy(uid_mapping); imap_lep_set_free(seq_list); @@ -2195,8 +2210,8 @@ static gint imap_select(IMAPSession *session, IMAPFolder *folder, } static gint imap_status(IMAPSession *session, IMAPFolder *folder, - const gchar *path, - gint *messages, gint *recent, + const gchar *path, IMAPFolderItem *item, + gint *messages, guint32 *uid_next, guint32 *uid_validity, gint *unseen, gboolean block) { @@ -2205,10 +2220,64 @@ static gint imap_status(IMAPSession *session, IMAPFolder *folder, struct mailimap_mailbox_data_status * data_status; int got_values; gchar *real_path; - + guint mask = 0; + real_path = imap_get_real_path(folder, path); - r = imap_threaded_status(FOLDER(folder), real_path, &data_status); +#if 0 + if (time(NULL) - item->last_update >= 5 && item->last_update != 1) { + /* do the full stuff */ + item->last_update = 1; /* force update */ + debug_print("updating everything\n"); + r = imap_status(session, folder, path, item, + &item->c_messages, &item->c_uid_next, + &item->c_uid_validity, &item->c_unseen, block); + if (r != MAILIMAP_NO_ERROR) { + debug_print("status err %d\n", r); + return IMAP_ERROR; + } + item->last_update = time(NULL); + if (messages) + *messages = item->c_messages; + if (uid_next) + *uid_next = item->c_uid_next; + if (uid_validity) + *uid_validity = item->c_uid_validity; + if (unseen) + *unseen = item->c_unseen; + return 0; + } else if (time(NULL) - item->last_update < 5) { + /* return cached stuff */ + debug_print("using cache\n"); + if (messages) + *messages = item->c_messages; + if (uid_next) + *uid_next = item->c_uid_next; + if (uid_validity) + *uid_validity = item->c_uid_validity; + if (unseen) + *unseen = item->c_unseen; + return 0; + } +#endif + + /* if we get there, we're updating cache */ + + if (messages) { + mask |= 1 << 0; + } + if (uid_next) { + mask |= 1 << 2; + } + if (uid_validity) { + mask |= 1 << 3; + } + if (unseen) { + mask |= 1 << 4; + } + r = imap_threaded_status(FOLDER(folder), real_path, + &data_status, mask); + g_free(real_path); if (r != MAILIMAP_NO_ERROR) { debug_print("status err %d\n", r); @@ -2233,11 +2302,6 @@ static gint imap_status(IMAPSession *session, IMAPFolder *folder, got_values |= 1 << 0; break; - case MAILIMAP_STATUS_ATT_RECENT: - * recent = info->st_value; - got_values |= 1 << 1; - break; - case MAILIMAP_STATUS_ATT_UIDNEXT: * uid_next = info->st_value; got_values |= 1 << 2; @@ -2256,8 +2320,7 @@ static gint imap_status(IMAPSession *session, IMAPFolder *folder, } mailimap_mailbox_data_status_free(data_status); - if (got_values != ((1 << 4) + (1 << 3) + - (1 << 2) + (1 << 1) + (1 << 0))) { + if (got_values != mask) { debug_print("status: incomplete values received (%d)\n", got_values); return IMAP_ERROR; } @@ -2516,10 +2579,8 @@ static gint imap_cmd_append(IMAPSession *session, const gchar *destfolder, g_return_val_if_fail(file != NULL, IMAP_ERROR); flag_list = imap_flag_to_lep(flags); - statusbar_print_all(_("Adding messages...")); r = imap_threaded_append(session->folder, destfolder, file, flag_list); - statusbar_pop_all(); if (new_uid != NULL) *new_uid = 0; @@ -2539,9 +2600,7 @@ static gint imap_cmd_copy(IMAPSession *session, struct mailimap_set * set, g_return_val_if_fail(set != NULL, IMAP_ERROR); g_return_val_if_fail(destfolder != NULL, IMAP_ERROR); - statusbar_print_all(_("Copying messages...")); r = imap_threaded_copy(session->folder, set, destfolder); - statusbar_pop_all(); if (r != MAILIMAP_NO_ERROR) { return IMAP_ERROR; @@ -2853,6 +2912,7 @@ static void *get_list_of_uids_thread(void *data) uidlist = NULL; set = mailimap_set_new_interval(item->lastuid + 1, 0); + r = imap_threaded_search(folder, IMAP_SEARCH_TYPE_SIMPLE, set, &lep_uidlist); if (r == MAILIMAP_NO_ERROR) { @@ -2923,7 +2983,7 @@ gint imap_get_num_list(Folder *folder, FolderItem *_item, GSList **msgnum_list, { IMAPFolderItem *item = (IMAPFolderItem *)_item; IMAPSession *session; - gint ok, nummsgs = 0, exists, recent, uid_val, uid_next, unseen; + gint ok, nummsgs = 0, exists, uid_val, uid_next; GSList *uidlist = NULL; gchar *dir; gboolean selected_folder; @@ -2958,8 +3018,17 @@ gint imap_get_num_list(Folder *folder, FolderItem *_item, GSList **msgnum_list, *old_uids_valid = TRUE; } else { - ok = imap_status(session, IMAP_FOLDER(folder), item->item.path, - &exists, &recent, &uid_next, &uid_val, &unseen, FALSE); + if (item->use_cache && time(NULL) - item->use_cache < 2) { + exists = item->c_messages; + uid_next = item->c_uid_next; + uid_val = item->c_uid_validity; + ok = IMAP_SUCCESS; + debug_print("using cache %d %d %d\n", exists, uid_next, uid_val); + } else { + ok = imap_status(session, IMAP_FOLDER(folder), item->item.path, item, + &exists, &uid_next, &uid_val, NULL, FALSE); + } + item->use_cache = (time_t)0; if (ok != IMAP_SUCCESS) { statusbar_pop_all(); return -1; @@ -3165,8 +3234,8 @@ gboolean imap_scan_required(Folder *folder, FolderItem *_item) { IMAPSession *session; IMAPFolderItem *item = (IMAPFolderItem *)_item; - gint ok, exists = 0, recent = 0, unseen = 0; - guint32 uid_next, uid_val = 0; + gint ok, exists = 0, unseen = 0; + guint32 uid_next, uid_val; gboolean selected_folder; g_return_val_if_fail(folder != NULL, FALSE); @@ -3195,11 +3264,17 @@ gboolean imap_scan_required(Folder *folder, FolderItem *_item) || session->exists != item->item.total_msgs) return TRUE; } else { - ok = imap_status(session, IMAP_FOLDER(folder), item->item.path, - &exists, &recent, &uid_next, &uid_val, &unseen, FALSE); + ok = imap_status(session, IMAP_FOLDER(folder), item->item.path, IMAP_FOLDER_ITEM(item), + &exists, &uid_next, &uid_val, &unseen, FALSE); if (ok != IMAP_SUCCESS) return FALSE; + item->use_cache = time(NULL); + item->c_messages = exists; + item->c_uid_next = uid_next; + item->c_uid_validity = uid_val; + item->c_unseen = unseen; + if ((uid_next != item->uid_next) || (exists != item->item.total_msgs)) return TRUE; } @@ -3388,6 +3463,7 @@ typedef struct _get_flags_data { FolderItem *item; MsgInfoList *msginfo_list; GRelation *msgflags; + gboolean full_search; gboolean done; } get_flags_data; @@ -3398,8 +3474,9 @@ static /*gint*/ void *imap_get_flags_thread(void *data) FolderItem *item = stuff->item; MsgInfoList *msginfo_list = stuff->msginfo_list; GRelation *msgflags = stuff->msgflags; + gboolean full_search = stuff->full_search; IMAPSession *session; - GSList *sorted_list; + GSList *sorted_list = NULL; GSList *unseen = NULL, *answered = NULL, *flagged = NULL, *deleted = NULL; GSList *p_unseen, *p_answered, *p_flagged, *p_deleted; GSList *elem; @@ -3407,18 +3484,13 @@ static /*gint*/ void *imap_get_flags_thread(void *data) gboolean reverse_seen = FALSE; GString *cmd_buf; gint ok; - gint exists_cnt, recent_cnt, unseen_cnt, uid_next; - guint32 uidvalidity; + gint exists_cnt, unseen_cnt; gboolean selected_folder; if (folder == NULL || item == NULL) { stuff->done = TRUE; return GINT_TO_POINTER(-1); } - if (msginfo_list == NULL) { - stuff->done = TRUE; - return GINT_TO_POINTER(0); - } session = imap_session_get(folder); if (session == NULL) { @@ -3430,8 +3502,8 @@ static /*gint*/ void *imap_get_flags_thread(void *data) (!strcmp(session->mbox, item->path)); if (!selected_folder) { - ok = imap_status(session, IMAP_FOLDER(folder), item->path, - &exists_cnt, &recent_cnt, &uid_next, &uidvalidity, &unseen_cnt, TRUE); + ok = imap_status(session, IMAP_FOLDER(folder), item->path, IMAP_FOLDER_ITEM(item), + &exists_cnt, NULL, NULL, &unseen_cnt, TRUE); ok = imap_select(session, IMAP_FOLDER(folder), item->path, NULL, NULL, NULL, NULL, TRUE); if (ok != IMAP_SUCCESS) { @@ -3450,8 +3522,13 @@ static /*gint*/ void *imap_get_flags_thread(void *data) cmd_buf = g_string_new(NULL); sorted_list = g_slist_sort(g_slist_copy(msginfo_list), compare_msginfo); - - seq_list = imap_get_lep_set_from_msglist(msginfo_list); + if (!full_search) { + seq_list = imap_get_lep_set_from_msglist(msginfo_list); + } else { + struct mailimap_set * set; + set = mailimap_set_new_interval(1, 0); + seq_list = g_slist_append(NULL, set); + } for (cur = seq_list; cur != NULL; cur = g_slist_next(cur)) { struct mailimap_set * imapset; @@ -3571,12 +3648,25 @@ static gint imap_get_flags(Folder *folder, FolderItem *item, data->item = item; data->msginfo_list = msginfo_list; data->msgflags = msgflags; + data->full_search = FALSE; + GSList *tmp = NULL, *cur; + if (prefs_common.work_offline && !inc_offline_should_override()) { g_free(data); return -1; } + tmp = folder_item_get_msg_list(item); + + if (g_slist_length(tmp) == g_slist_length(msginfo_list)) + data->full_search = TRUE; + + for (cur = tmp; cur; cur = cur->next) + procmsg_msginfo_free((MsgInfo *)cur->data); + + g_slist_free(tmp); + result = GPOINTER_TO_INT(imap_get_flags_thread(data)); g_free(data); -- 2.25.1