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
This commit is contained in:
Dan Winship
2001-02-26 21:38:39 +00:00
parent b0b0cfe95d
commit fe8e875972
2 changed files with 159 additions and 36 deletions

View File

@ -1,3 +1,15 @@
2001-02-26 Dan Winship <danw@ximian.com>
* 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.
2001-02-26 Jeffrey Stedfast <fejj@ximian.com>
* camel-mime-utils.c: Made thread-safe and moved to above the test

View File

@ -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;
}
mi->flags &= ~CAMEL_MESSAGE_FOLDER_FLAGGED;
((CamelImapMessageInfo *)mi)->server_flags =
mi->flags & CAMEL_IMAP_SERVER_FLAGS;
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));
}
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;
CamelMessageInfo *info;
GPtrArray *matches;
char *set, *flaglist;
int i, j, max;
camel_operation_start(NULL, _("Synchronising IMAP folder"));
/* 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;
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);
camel_operation_progress(NULL, (i+1)*100/max);
if (camel_exception_is_set (ex)) {
camel_operation_end(NULL);
return;
/* 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)
continue;
if (!(info->flags & CAMEL_MESSAGE_FOLDER_FLAGGED)) {
camel_folder_summary_info_free (folder->summary, info);
continue;
}
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);
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))