dovecot-2.1: pop3: Added pop3_uidl_duplicates setting.

dovecot at dovecot.org dovecot at dovecot.org
Mon May 14 21:07:52 EEST 2012


details:   http://hg.dovecot.org/dovecot-2.1/rev/3a095892242b
changeset: 14527:3a095892242b
user:      Timo Sirainen <tss at iki.fi>
date:      Mon May 14 21:07:43 2012 +0300
description:
pop3: Added pop3_uidl_duplicates setting.

diffstat:

 doc/example-config/conf.d/20-pop3.conf |    5 +
 src/pop3/pop3-client.c                 |   37 ++-
 src/pop3/pop3-client.h                 |    5 +-
 src/pop3/pop3-commands.c               |  272 ++++++++++++++++++++++----------
 src/pop3/pop3-settings.c               |    4 +-
 src/pop3/pop3-settings.h               |    1 +
 6 files changed, 220 insertions(+), 104 deletions(-)

diffs (truncated from 509 to 300 lines):

diff -r 4bbc12a87a29 -r 3a095892242b doc/example-config/conf.d/20-pop3.conf
--- a/doc/example-config/conf.d/20-pop3.conf	Mon May 14 19:30:03 2012 +0300
+++ b/doc/example-config/conf.d/20-pop3.conf	Mon May 14 21:07:43 2012 +0300
@@ -54,6 +54,11 @@
   # won't change those UIDLs. Currently this works only with Maildir.
   #pop3_save_uidl = no
 
+  # What to do about duplicate UIDLs if they exist?
+  #   allow: Show duplicates to clients.
+  #   rename: Append a temporary -2, -3, etc. counter after the UIDL.
+  #pop3_uidl_duplicates = allow
+
   # POP3 logout format string:
   #  %i - total number of bytes read from client
   #  %o - total number of bytes sent to client
diff -r 4bbc12a87a29 -r 3a095892242b src/pop3/pop3-client.c
--- a/src/pop3/pop3-client.c	Mon May 14 19:30:03 2012 +0300
+++ b/src/pop3/pop3-client.c	Mon May 14 21:07:43 2012 +0300
@@ -6,6 +6,7 @@
 #include "network.h"
 #include "istream.h"
 #include "ostream.h"
+#include "crc32.h"
 #include "str.h"
 #include "llist.h"
 #include "hostpid.h"
@@ -344,15 +345,20 @@
 		return NULL;
 	}
 
-	if (var_has_key(set->pop3_logout_format, 'u', "uidl_change") &&
-	    client->messages_count > 0)
-		client->message_uidl_hashes_save = TRUE;
-
 	client->uidl_keymask =
 		parse_uidl_keymask(client->mail_set->pop3_uidl_format);
 	if (client->uidl_keymask == 0)
 		i_fatal("Invalid pop3_uidl_format");
 
+	if (var_has_key(set->pop3_logout_format, 'u', "uidl_change")) {
+		/* logging uidl_change. we need hashes of the UIDLs */
+		client->message_uidls_save = TRUE;
+	} else if (strcmp(set->pop3_uidl_duplicates, "allow") != 0) {
+		/* UIDL duplicates aren't allowed, so we'll need to
+		   keep track of them */
+		client->message_uidls_save = TRUE;
+	}
+
 	if (!set->pop3_no_flag_updates && client->messages_count > 0)
 		client->seen_bitmask = i_malloc(MSGS_BITMASK_SIZE(client));
 
@@ -375,12 +381,8 @@
 	uint32_t i, old_hash, new_hash;
 	unsigned int old_msg_count, new_msg_count;
 
-	if (client->message_uidl_hashes == NULL) {
-		/* UIDL command not given or %u not actually used in format */
-		return "";
-	}
-	if (client->message_uidl_hashes_save) {
-		/* UIDL command not finished */
+	if (client->message_uidls == NULL) {
+		/* UIDL command not given */
 		return "";
 	}
 
@@ -388,18 +390,18 @@
 	old_msg_count = client->lowest_retr_pop3_msn > 0 ?
 		client->lowest_retr_pop3_msn - 1 : client->messages_count;
 	for (i = 0, old_hash = 0; i < old_msg_count; i++)
-		old_hash ^= client->message_uidl_hashes[i];
+		old_hash ^= crc32_str(client->message_uidls[i]);
 
 	/* assume all except deleted messages were sent to POP3 client */
 	if (!client->deleted) {
 		for (i = 0, new_hash = 0; i < client->messages_count; i++)
-			new_hash ^= client->message_uidl_hashes[i];
+			new_hash ^= crc32_str(client->message_uidls[i]);
 	} else {
 		for (i = 0, new_hash = 0; i < client->messages_count; i++) {
 			if (client->deleted_bitmask[i / CHAR_BIT] &
 			    (1 << (i % CHAR_BIT)))
 				continue;
-			new_hash ^= client->message_uidl_hashes[i];
+			new_hash ^= crc32_str(client->message_uidls[i]);
 		}
 	}
 
@@ -444,7 +446,11 @@
 	tab[6].value = dec2str(client->total_size);
 	tab[7].value = dec2str(client->input->v_offset);
 	tab[8].value = dec2str(client->output->offset);
-	tab[9].value = client_build_uidl_change_string(client);
+	if (var_has_key(client->set->pop3_logout_format,
+			tab[9].key, tab[9].long_key))
+		tab[9].value = client_build_uidl_change_string(client);
+	else
+		tab[9].value = "";
 	tab[10].value = client->session_id;
 
 	str = t_str_new(128);
@@ -498,8 +504,9 @@
 	}
 	mail_user_unref(&client->user);
 
+	if (client->uidl_pool != NULL)
+		pool_unref(&client->uidl_pool);
 	i_free(client->message_sizes);
-	i_free(client->message_uidl_hashes);
 	i_free(client->deleted_bitmask);
 	i_free(client->seen_bitmask);
 	i_free(client->msgnum_to_seq_map);
diff -r 4bbc12a87a29 -r 3a095892242b src/pop3/pop3-client.h
--- a/src/pop3/pop3-client.h	Mon May 14 19:30:03 2012 +0300
+++ b/src/pop3/pop3-client.h	Mon May 14 21:07:43 2012 +0300
@@ -55,7 +55,7 @@
 	unsigned int retr_count;
 
 	/* [msgnum] */
-	uint32_t *message_uidl_hashes;
+	const char **message_uidls;
 	uoff_t *message_sizes;
 	/* [msgnum/8] & msgnum%8 */
 	unsigned char *deleted_bitmask;
@@ -64,13 +64,14 @@
 	/* settings: */
 	const struct pop3_settings *set;
 	const struct mail_storage_settings *mail_set;
+	pool_t uidl_pool;
 	enum uidl_keys uidl_keymask;
 
 	unsigned int disconnected:1;
 	unsigned int deleted:1;
 	unsigned int waiting_input:1;
 	unsigned int anvil_sent:1;
-	unsigned int message_uidl_hashes_save:1;
+	unsigned int message_uidls_save:1;
 };
 
 extern struct client *pop3_clients;
diff -r 4bbc12a87a29 -r 3a095892242b src/pop3/pop3-commands.c
--- a/src/pop3/pop3-commands.c	Mon May 14 19:30:03 2012 +0300
+++ b/src/pop3/pop3-commands.c	Mon May 14 21:07:43 2012 +0300
@@ -4,8 +4,8 @@
 #include "array.h"
 #include "istream.h"
 #include "ostream.h"
+#include "hash.h"
 #include "str.h"
-#include "crc32.h"
 #include "var-expand.h"
 #include "message-size.h"
 #include "mail-storage.h"
@@ -550,62 +550,9 @@
 	bool list_all;
 };
 
-static bool pop3_get_uid(struct client *client, struct cmd_uidl_context *ctx,
-			 struct var_expand_table *tab, string_t *str)
-{
-	char uid_str[MAX_INT_STRLEN];
-	const char *uidl;
-
-	if (mail_get_special(ctx->mail, MAIL_FETCH_UIDL_BACKEND, &uidl) == 0 &&
-	    *uidl != '\0') {
-		str_append(str, uidl);
-		return TRUE;
-	}
-
-	if (client->set->pop3_reuse_xuidl &&
-	    mail_get_first_header(ctx->mail, "X-UIDL", &uidl) > 0) {
-		str_append(str, uidl);
-		return FALSE;
-	}
-
-	if ((client->uidl_keymask & UIDL_UID) != 0) {
-		i_snprintf(uid_str, sizeof(uid_str), "%u",
-			   ctx->mail->uid);
-		tab[1].value = uid_str;
-	}
-	if ((client->uidl_keymask & UIDL_MD5) != 0) {
-		if (mail_get_special(ctx->mail, MAIL_FETCH_HEADER_MD5,
-				     &tab[2].value) < 0 ||
-		    *tab[2].value == '\0') {
-			/* broken */
-			i_fatal("UIDL: Header MD5 not found "
-				"(pop3_uidl_format=%%m not supported by storage?)");
-		}
-	}
-	if ((client->uidl_keymask & UIDL_FILE_NAME) != 0) {
-		if (mail_get_special(ctx->mail,
-				     MAIL_FETCH_UIDL_FILE_NAME,
-				     &tab[3].value) < 0 ||
-		    *tab[3].value == '\0') {
-			/* broken */
-			i_fatal("UIDL: File name not found "
-				"(pop3_uidl_format=%%f not supported by storage?)");
-		}
-	}
-	if ((client->uidl_keymask & UIDL_GUID) != 0) {
-		if (mail_get_special(ctx->mail, MAIL_FETCH_GUID,
-				     &tab[4].value) < 0 ||
-		    *tab[4].value == '\0') {
-			/* broken */
-			i_fatal("UIDL: Message GUID not found "
-				"(pop3_uidl_format=%%g not supported by storage?)");
-		}
-	}
-	var_expand(str, client->mail_set->pop3_uidl_format, tab);
-	return FALSE;
-}
-
-static bool list_uids_iter(struct client *client, struct cmd_uidl_context *ctx)
+static void
+pop3_get_uid(struct client *client, struct mail *mail, string_t *str,
+	     bool *permanent_uidl_r)
 {
 	static struct var_expand_table static_tab[] = {
 		{ 'v', NULL, "uidvalidity" },
@@ -616,20 +563,108 @@
 		{ '\0', NULL, NULL }
 	};
 	struct var_expand_table *tab;
-	string_t *str;
-	int ret;
-	unsigned int uidl_pos;
-	bool save_hashes, found = FALSE;
+	char uid_str[MAX_INT_STRLEN];
+	const char *uidl;
+
+	if (mail_get_special(mail, MAIL_FETCH_UIDL_BACKEND, &uidl) == 0 &&
+	    *uidl != '\0') {
+		str_append(str, uidl);
+		/* UIDL is already permanent */
+		*permanent_uidl_r = TRUE;
+		return;
+	}
+
+	*permanent_uidl_r = FALSE;
+
+	if (client->set->pop3_reuse_xuidl &&
+	    mail_get_first_header(mail, "X-UIDL", &uidl) > 0) {
+		str_append(str, uidl);
+		return;
+	}
 
 	tab = t_malloc(sizeof(static_tab));
 	memcpy(tab, static_tab, sizeof(static_tab));
 	tab[0].value = t_strdup_printf("%u", client->uid_validity);
 
-	save_hashes = client->message_uidl_hashes_save && ctx->list_all;
-	if (save_hashes && client->message_uidl_hashes == NULL) {
-		client->message_uidl_hashes =
-			i_new(uint32_t, client->messages_count);
+	if ((client->uidl_keymask & UIDL_UID) != 0) {
+		i_snprintf(uid_str, sizeof(uid_str), "%u",
+			   mail->uid);
+		tab[1].value = uid_str;
 	}
+	if ((client->uidl_keymask & UIDL_MD5) != 0) {
+		if (mail_get_special(mail, MAIL_FETCH_HEADER_MD5,
+				     &tab[2].value) < 0 ||
+		    *tab[2].value == '\0') {
+			/* broken */
+			i_fatal("UIDL: Header MD5 not found "
+				"(pop3_uidl_format=%%m not supported by storage?)");
+		}
+	}
+	if ((client->uidl_keymask & UIDL_FILE_NAME) != 0) {
+		if (mail_get_special(mail, MAIL_FETCH_UIDL_FILE_NAME,
+				     &tab[3].value) < 0 ||
+		    *tab[3].value == '\0') {
+			/* broken */
+			i_fatal("UIDL: File name not found "
+				"(pop3_uidl_format=%%f not supported by storage?)");
+		}
+	}
+	if ((client->uidl_keymask & UIDL_GUID) != 0) {
+		if (mail_get_special(mail, MAIL_FETCH_GUID,
+				     &tab[4].value) < 0 ||
+		    *tab[4].value == '\0') {
+			/* broken */
+			i_fatal("UIDL: Message GUID not found "
+				"(pop3_uidl_format=%%g not supported by storage?)");
+		}
+	}
+	var_expand(str, client->mail_set->pop3_uidl_format, tab);
+}
+
+static bool
+list_uidls_saved_iter(struct client *client, struct cmd_uidl_context *ctx)
+{
+	bool found = FALSE;
+	int ret;
+
+	while (ctx->msgnum < client->messages_count) {
+		uint32_t msgnum = ctx->msgnum++;
+
+		if (client->deleted) {
+			if (client->deleted_bitmask[msgnum / CHAR_BIT] &


More information about the dovecot-cvs mailing list