dovecot-2.2: pop3: Use POP3 order sorting only when directly lis...

dovecot at dovecot.org dovecot at dovecot.org
Fri Feb 7 20:03:43 UTC 2014


details:   http://hg.dovecot.org/dovecot-2.2/rev/59decc957b39
changeset: 17135:59decc957b39
user:      Timo Sirainen <tss at iki.fi>
date:      Fri Feb 07 15:03:33 2014 -0500
description:
pop3: Use POP3 order sorting only when directly listing UIDLs.
"Message ordering changed unexpectedly" errors can be completely avoided by
using either pop3_lock_session=yes or adding %u to pop3_logout_format.

diffstat:

 src/pop3/pop3-commands.c |  74 +++++++++++++++++++++++++++--------------------
 1 files changed, 43 insertions(+), 31 deletions(-)

diffs (136 lines):

diff -r 36d11bf4e58d -r 59decc957b39 src/pop3/pop3-commands.c
--- a/src/pop3/pop3-commands.c	Fri Feb 07 14:24:44 2014 -0500
+++ b/src/pop3/pop3-commands.c	Fri Feb 07 15:03:33 2014 -0500
@@ -237,6 +237,7 @@
 	struct mail_search_args *search_args;
 	struct mail_search_context *ctx;
 	struct mail *mail;
+	ARRAY_TYPE(seq_range) deleted_msgs, seen_msgs;
 	uint32_t msgnum, bit;
 	bool ret = TRUE;
 
@@ -245,27 +246,35 @@
 		return TRUE;
 	}
 
+	/* translate msgnums to sequences (in case POP3 ordering is
+	   different) */
+	t_array_init(&deleted_msgs, 8);
+	if (client->deleted_bitmask != NULL) {
+		for (msgnum = 0; msgnum < client->messages_count; msgnum++) {
+			bit = 1 << (msgnum % CHAR_BIT);
+			if ((client->deleted_bitmask[msgnum / CHAR_BIT] & bit) != 0)
+				seq_range_array_add(&deleted_msgs, client->msgnum_to_seq_map[msgnum]);
+		}
+	}
+	t_array_init(&seen_msgs, 8);
+	if (client->seen_bitmask != NULL) {
+		for (msgnum = 0; msgnum < client->messages_count; msgnum++) {
+			bit = 1 << (msgnum % CHAR_BIT);
+			if ((client->seen_bitmask[msgnum / CHAR_BIT] & bit) != 0)
+				seq_range_array_add(&seen_msgs, client->msgnum_to_seq_map[msgnum]);
+		}
+	}
+
 	search_args = pop3_search_build(client, 0);
-	ctx = mailbox_search_init(client->trans, search_args,
-				  pop3_sort_program, 0, NULL);
+	ctx = mailbox_search_init(client->trans, search_args, NULL, 0, NULL);
 	mail_search_args_unref(&search_args);
 
 	msgnum = 0;
 	while (mailbox_search_next(ctx, &mail)) {
-		if (client_verify_ordering(client, mail, msgnum) < 0) {
-			ret = FALSE;
-			break;
-		}
-
-		bit = 1 << (msgnum % CHAR_BIT);
-		if (client->deleted_bitmask != NULL &&
-		    (client->deleted_bitmask[msgnum / CHAR_BIT] & bit) != 0) {
+		if (seq_range_exists(&deleted_msgs, mail->seq))
 			client_expunge(client, mail);
-		} else if (client->seen_bitmask != NULL &&
-			   (client->seen_bitmask[msgnum / CHAR_BIT] & bit) != 0) {
+		else if (seq_range_exists(&seen_msgs, mail->seq))
 			mail_update_flags(mail, MODIFY_ADD, MAIL_SEEN);
-		}
-		msgnum++;
 	}
 
 	client->seen_change_count = 0;
@@ -762,6 +771,7 @@
 	struct mail_search_args *search_args;
 	struct mail *mail;
 	HASH_TABLE_TYPE(uidl_counter) prev_uidls;
+	const char **seq_uidls;
 	string_t *str;
 	char *uidl;
 	enum mail_fetch_field wanted_fields;
@@ -776,47 +786,49 @@
 		wanted_fields |= MAIL_FETCH_HEADER_MD5;
 
 	search_ctx = mailbox_search_init(client->trans, search_args,
-					 pop3_sort_program,
-					 wanted_fields, NULL);
+					 NULL, wanted_fields, NULL);
 	mail_search_args_unref(&search_args);
 
 	uidl_duplicates_rename =
 		strcmp(client->set->pop3_uidl_duplicates, "rename") == 0;
 	hash_table_create(&prev_uidls, default_pool, 0, str_hash, strcmp);
 	client->uidl_pool = pool_alloconly_create("message uidls", 1024);
-	client->message_uidls = p_new(client->uidl_pool, const char *,
-				      client->messages_count+1);
 
-	str = t_str_new(128); msgnum = 0;
+	/* first read all the UIDLs into a temporary [seq] array */
+	seq_uidls = i_new(const char *, client->messages_count);
+	str = t_str_new(128);
 	while (mailbox_search_next(search_ctx, &mail)) {
-		if (client_verify_ordering(client, mail, msgnum) < 0) {
-			failed = TRUE;
-			break;
-		}
-
 		str_truncate(str, 0);
 		if (pop3_get_uid(client, mail, str, &permanent_uidl) < 0) {
 			failed = TRUE;
 			break;
 		}
-
-		if (client->set->pop3_save_uidl && !permanent_uidl)
-			mail_update_pop3_uidl(mail, str_c(str));
-
 		if (uidl_duplicates_rename)
 			uidl_rename_duplicate(str, prev_uidls);
+
 		uidl = p_strdup(client->uidl_pool, str_c(str));
-		client->message_uidls[msgnum] = uidl;
+		if (client->set->pop3_save_uidl && !permanent_uidl)
+			mail_update_pop3_uidl(mail, uidl);
+
+		seq_uidls[mail->seq-1] = uidl;
 		hash_table_insert(prev_uidls, uidl, POINTER_CAST(1));
-		msgnum++;
 	}
 	(void)mailbox_search_deinit(&search_ctx);
 	hash_table_destroy(&prev_uidls);
 
 	if (failed) {
 		pool_unref(&client->uidl_pool);
-		client->message_uidls = NULL;
+		i_free(seq_uidls);
+		return;
 	}
+	/* map UIDLs to msgnums (in case POP3 sort ordering is different) */
+	client->message_uidls = p_new(client->uidl_pool, const char *,
+				      client->messages_count+1);
+	for (msgnum = 0; msgnum < client->messages_count; msgnum++) {
+		client->message_uidls[msgnum] =
+			seq_uidls[client->msgnum_to_seq_map[msgnum]];
+	}
+	i_free(seq_uidls);
 }
 
 static struct cmd_uidl_context *


More information about the dovecot-cvs mailing list