From fe8e875972c8cf22a2fa884e25bc1f5bb4ef6046 Mon Sep 17 00:00:00 2001 From: Dan Winship Date: Mon, 26 Feb 2001 21:38:39 +0000 Subject: Group messages into sets with the same flags and use the IMAP message set * providers/imap/camel-imap-folder.c (imap_sync): Group messages into sets with the same flags and use the IMAP message set notation rather than doing a separate STORE FLAGS for each one. This cuts the network traffic down to just a handful of commands per sync rather than one per changed message. Removed the progress notification stuff since it's no longer meaningful and should hopefully be unnecessary. (imap_copy_message_to): move the former sync_message function into here, since it's no longer shared with imap_sync. svn path=/trunk/; revision=8396 --- camel/providers/imap/camel-imap-folder.c | 177 +++++++++++++++++++++++++------ 1 file changed, 144 insertions(+), 33 deletions(-) (limited to 'camel/providers/imap') diff --git a/camel/providers/imap/camel-imap-folder.c b/camel/providers/imap/camel-imap-folder.c index 0e840476f0..cf91bceb12 100644 --- a/camel/providers/imap/camel-imap-folder.c +++ b/camel/providers/imap/camel-imap-folder.c @@ -424,27 +424,62 @@ imap_rescan (CamelFolder *folder, int exists, CamelException *ex) camel_operation_end(NULL); } -static void -sync_message (CamelImapStore *store, CamelFolder *folder, - CamelMessageInfo *mi, CamelException *ex) +/* Find all messages in @folder with flags matching @flags and @mask. + * If no messages match, returns %NULL. Otherwise, returns an array of + * CamelMessageInfo and sets *@set to a message set corresponding the + * UIDs of the matched messages. The caller must free the infos, the + * array, and the set string. + */ +static GPtrArray * +get_matching (CamelFolder *folder, guint32 flags, guint32 mask, char **set) { - CamelImapResponse *response; - char *flags; + GPtrArray *matches; + CamelMessageInfo *info; + int i, max, range; + GString *gset; - flags = imap_create_flag_list (mi->flags); - CAMEL_IMAP_STORE_LOCK (store, command_lock); - response = camel_imap_command (store, folder, ex, - "UID STORE %s FLAGS.SILENT %s", - camel_message_info_uid (mi), flags); - CAMEL_IMAP_STORE_UNLOCK (store, command_lock); - g_free (flags); - if (camel_exception_is_set (ex)) - return; - camel_imap_response_free (response); + matches = g_ptr_array_new (); + gset = g_string_new (""); + max = camel_folder_summary_count (folder->summary); + range = -1; + for (i = 0; i < max; i++) { + info = camel_folder_summary_index (folder->summary, i); + if (!info) + continue; + if ((info->flags & mask) != flags) { + camel_folder_summary_info_free (folder->summary, info); + if (range != -1) { + if (range != i - 1) { + info = matches->pdata[matches->len - 1]; + g_string_sprintfa (gset, ":%s", camel_message_info_uid (info)); + } + range = -1; + } + continue; + } + + g_ptr_array_add (matches, info); + if (range != -1) + continue; + range = i; + if (gset->len) + g_string_append_c (gset, ','); + g_string_sprintfa (gset, "%s", camel_message_info_uid (info)); + } + if (range != -1 && range != max - 1) { + info = matches->pdata[matches->len - 1]; + g_string_sprintfa (gset, ":%s", camel_message_info_uid (info)); + } - mi->flags &= ~CAMEL_MESSAGE_FOLDER_FLAGGED; - ((CamelImapMessageInfo *)mi)->server_flags = - mi->flags & CAMEL_IMAP_SERVER_FLAGS; + if (matches->len) { + *set = gset->str; + g_string_free (gset, FALSE); + return matches; + } else { + g_string_free (gset, TRUE); + g_ptr_array_free (matches, TRUE); + return NULL; + } } static void @@ -452,26 +487,83 @@ imap_sync (CamelFolder *folder, gboolean expunge, CamelException *ex) { CamelImapStore *store = CAMEL_IMAP_STORE (folder->parent_store); CamelImapResponse *response; - int i, max; - - camel_operation_start(NULL, _("Synchronising IMAP folder")); + CamelMessageInfo *info; + GPtrArray *matches; + char *set, *flaglist; + int i, j, max; - /* Set the flags on any messages that have changed this session */ max = camel_folder_summary_count (folder->summary); - for (i = 0; i < max; i++) { - CamelMessageInfo *info; + /* If we're expunging then we don't need to be precise about the + * flags of deleted messages. Just add \Deleted to anything that + * should have it. + */ + if (expunge && (matches = get_matching (folder, CAMEL_MESSAGE_DELETED, + CAMEL_MESSAGE_DELETED, &set))) { + for (i = 0; i < matches->len; i++) { + info = matches->pdata[i]; + info->flags &= ~CAMEL_MESSAGE_FOLDER_FLAGGED; + camel_folder_summary_info_free (folder->summary, info); + } + g_ptr_array_free (matches, TRUE); + camel_folder_summary_touch (folder->summary); + + CAMEL_IMAP_STORE_LOCK (store, command_lock); + response = camel_imap_command (store, folder, ex, + "UID STORE %s +FLAGS.SILENT \\Deleted", + set); + CAMEL_IMAP_STORE_UNLOCK (store, command_lock); + g_free (set); + if (response) + camel_imap_response_free (response); + if (camel_exception_is_set (ex)) + return; + } + + /* OK, now, find a message with changed flags, find all of the + * other messages like it, sync them as a group, mark them as + * updated, and continue. + */ + for (i = 0; i < max; i++) { info = camel_folder_summary_index (folder->summary, i); - if (info && (info->flags & CAMEL_MESSAGE_FOLDER_FLAGGED)) - sync_message (store, folder, info, ex); - camel_folder_summary_info_free(folder->summary, info); + if (!info) + continue; + if (!(info->flags & CAMEL_MESSAGE_FOLDER_FLAGGED)) { + camel_folder_summary_info_free (folder->summary, info); + continue; + } - camel_operation_progress(NULL, (i+1)*100/max); + flaglist = imap_create_flag_list (info->flags); + matches = get_matching (folder, info->flags & (CAMEL_IMAP_SERVER_FLAGS | CAMEL_MESSAGE_FOLDER_FLAGGED), + CAMEL_IMAP_SERVER_FLAGS | CAMEL_MESSAGE_FOLDER_FLAGGED, &set); + camel_folder_summary_info_free (folder->summary, info); - if (camel_exception_is_set (ex)) { - camel_operation_end(NULL); - return; + CAMEL_IMAP_STORE_LOCK (store, command_lock); + response = camel_imap_command (store, folder, ex, + "UID STORE %s FLAGS.SILENT %s", + set, flaglist); + CAMEL_IMAP_STORE_UNLOCK (store, command_lock); + g_free (set); + g_free (flaglist); + if (response) + camel_imap_response_free (response); + if (!camel_exception_is_set (ex)) { + for (j = 0; j < matches->len; j++) { + info = matches->pdata[j]; + info->flags &= ~CAMEL_MESSAGE_FOLDER_FLAGGED; + ((CamelImapMessageInfo*)info)->server_flags = + info->flags & CAMEL_IMAP_SERVER_FLAGS; + } + camel_folder_summary_touch (folder->summary); + } + for (j = 0; j < matches->len; j++) { + info = matches->pdata[j]; + camel_folder_summary_info_free (folder->summary, info); } + g_ptr_array_free (matches, TRUE); + + if (camel_exception_is_set (ex)) + return; } if (expunge) { @@ -582,8 +674,27 @@ imap_copy_message_to (CamelFolder *source, const char *uid, g_return_if_fail (mi != NULL); /* Sync message flags if needed. */ - if (mi->flags & CAMEL_MESSAGE_FOLDER_FLAGGED) - sync_message (store, source, mi, ex); + if (mi->flags & CAMEL_MESSAGE_FOLDER_FLAGGED) { + char *flaglist; + + flaglist = imap_create_flag_list (mi->flags); + CAMEL_IMAP_STORE_LOCK (store, command_lock); + response = camel_imap_command (store, source, ex, + "UID STORE %s FLAGS.SILENT %s", + camel_message_info_uid (mi), + flaglist); + CAMEL_IMAP_STORE_UNLOCK (store, command_lock); + g_free (flaglist); + if (camel_exception_is_set (ex)) { + camel_folder_summary_info_free (source->summary, mi); + return; + } + camel_imap_response_free (response); + + mi->flags &= ~CAMEL_MESSAGE_FOLDER_FLAGGED; + ((CamelImapMessageInfo *)mi)->server_flags = + mi->flags & CAMEL_IMAP_SERVER_FLAGS; + } camel_folder_summary_info_free (source->summary, mi); if (camel_exception_is_set (ex)) -- cgit v1.2.3