dovecot-2.0: pop3: Added %u=old/new UIDL hash to pop3_logout_for...

dovecot at dovecot.org dovecot at dovecot.org
Wed Apr 14 18:29:19 EEST 2010


details:   http://hg.dovecot.org/dovecot-2.0/rev/e019febd7eb3
changeset: 11152:e019febd7eb3
user:      Timo Sirainen <tss at iki.fi>
date:      Wed Apr 14 18:29:15 2010 +0300
description:
pop3: Added %u=old/new UIDL hash to pop3_logout_format.
It expands to "<old msg count>/<old hash> -> <new msg count>/<new hash>" or
if they're the same, simply "<msg count>/<hash>".

The idea is that if previous session's <new hash> doesn't match next one's
<old hash> and prev.new_msg_count = next.old_msg_count, it could indicate
that the UIDLs changed for some reason. But if they do match and client
still redownloaded messages, it's most likely a client side problem.

diffstat:

 doc/example-config/conf.d/20-pop3.conf |   1 +
 src/pop3/pop3-client.c                 |  50 +++++++++++++++++++++++++
 src/pop3/pop3-client.h                 |   4 +-
 src/pop3/pop3-commands.c               |  21 +++++++++-
 4 files changed, 73 insertions(+), 3 deletions(-)

diffs (190 lines):

diff -r 093591e1110b -r e019febd7eb3 doc/example-config/conf.d/20-pop3.conf
--- a/doc/example-config/conf.d/20-pop3.conf	Wed Apr 14 16:06:59 2010 +0300
+++ b/doc/example-config/conf.d/20-pop3.conf	Wed Apr 14 18:29:15 2010 +0300
@@ -57,6 +57,7 @@
   #  %d - number of deleted messages
   #  %m - number of messages (before deletion)
   #  %s - mailbox size in bytes (before deletion)
+  #  %u - old/new UIDL hash. may help finding out if UIDLs changed unexpectedly
   #pop3_logout_format = top=%t/%p, retr=%r/%b, del=%d/%m, size=%s
 
   # Maximum number of POP3 connections allowed for a user from each IP address.
diff -r 093591e1110b -r e019febd7eb3 src/pop3/pop3-client.c
--- a/src/pop3/pop3-client.c	Wed Apr 14 16:06:59 2010 +0300
+++ b/src/pop3/pop3-client.c	Wed Apr 14 18:29:15 2010 +0300
@@ -258,6 +258,10 @@
 		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)
@@ -281,6 +285,49 @@
 	return client;
 }
 
+static const char *client_build_uidl_change_string(struct client *client)
+{
+	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 */
+		return "";
+	}
+
+	/* 1..new-1 were probably left to mailbox by previous POP3 session */
+	old_msg_count = client->lowest_retr > 0 ?
+		client->lowest_retr - 1 : client->messages_count;
+	for (i = 0, old_hash = 0; i < old_msg_count; i++)
+		old_hash ^= client->message_uidl_hashes[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];
+	} 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_msg_count = client->messages_count - client->deleted_count;
+	if (old_hash == new_hash && old_msg_count == new_msg_count)
+		return t_strdup_printf("%u/%08x", old_msg_count, old_hash);
+	else {
+		return t_strdup_printf("%u/%08x -> %u/%08x",
+				       old_msg_count, old_hash,
+				       new_msg_count, new_hash);
+	}
+}
+
 static const char *client_stats(struct client *client)
 {
 	static struct var_expand_table static_tab[] = {
@@ -293,6 +340,7 @@
 		{ 's', NULL, "message_bytes" },
 		{ 'i', NULL, "input" },
 		{ 'o', NULL, "output" },
+		{ 'u', NULL, "uidl_change" },
 		{ '\0', NULL, NULL }
 	};
 	struct var_expand_table *tab;
@@ -310,6 +358,7 @@
 	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);
 
 	str = t_str_new(128);
 	var_expand(str, client->set->pop3_logout_format, tab);
@@ -363,6 +412,7 @@
 	mail_user_unref(&client->user);
 
 	i_free(client->message_sizes);
+	i_free(client->message_uidl_hashes);
 	i_free(client->deleted_bitmask);
 	i_free(client->seen_bitmask);
 
diff -r 093591e1110b -r e019febd7eb3 src/pop3/pop3-client.h
--- a/src/pop3/pop3-client.h	Wed Apr 14 16:06:59 2010 +0300
+++ b/src/pop3/pop3-client.h	Wed Apr 14 18:29:15 2010 +0300
@@ -34,10 +34,11 @@
 	unsigned int uid_validity;
 	unsigned int messages_count;
 	unsigned int deleted_count, expunged_count, seen_change_count;
+	uint32_t *message_uidl_hashes;
 	uoff_t *message_sizes;
 	uoff_t total_size;
 	uoff_t deleted_size;
-	uint32_t last_seen;
+	uint32_t last_seen, lowest_retr;
 
 	uoff_t top_bytes;
 	uoff_t retr_bytes;
@@ -59,6 +60,7 @@
 	unsigned int deleted:1;
 	unsigned int waiting_input:1;
 	unsigned int anvil_sent:1;
+	unsigned int message_uidl_hashes_save:1;
 };
 
 extern struct client *pop3_clients;
diff -r 093591e1110b -r e019febd7eb3 src/pop3/pop3-commands.c
--- a/src/pop3/pop3-commands.c	Wed Apr 14 16:06:59 2010 +0300
+++ b/src/pop3/pop3-commands.c	Wed Apr 14 18:29:15 2010 +0300
@@ -5,6 +5,7 @@
 #include "istream.h"
 #include "ostream.h"
 #include "str.h"
+#include "crc32.h"
 #include "var-expand.h"
 #include "message-size.h"
 #include "mail-storage.h"
@@ -438,6 +439,8 @@
 	if (get_msgnum(client, args, &msgnum) == NULL)
 		return -1;
 
+	if (client->lowest_retr > msgnum+1 || client->lowest_retr == 0)
+		client->lowest_retr = msgnum+1;
 	if (client->last_seen <= msgnum)
 		client->last_seen = msgnum+1;
 
@@ -586,16 +589,23 @@
 	string_t *str;
 	int ret;
 	unsigned int uidl_pos;
-	bool found = FALSE;
+	bool save_hashes, found = FALSE;
 
 	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->message == 0;
+	if (save_hashes && client->message_uidl_hashes == NULL) {
+		client->message_uidl_hashes =
+			i_new(uint32_t, client->messages_count);
+	}
+
 	str = t_str_new(128);
 	while (mailbox_search_next(ctx->search_ctx, ctx->mail)) {
+		uint32_t idx = ctx->mail->seq - 1;
+
 		if (client->deleted) {
-			uint32_t idx = ctx->mail->seq - 1;
 			if (client->deleted_bitmask[idx / CHAR_BIT] &
 			    (1 << (idx % CHAR_BIT)))
 				continue;
@@ -610,6 +620,11 @@
 		    client->set->pop3_save_uidl)
 			mail_update_pop3_uidl(ctx->mail, str_c(str) + uidl_pos);
 
+		if (save_hashes) {
+			client->message_uidl_hashes[idx] =
+				crc32_str(str_c(str) + uidl_pos);
+		}
+
 		ret = client_send_line(client, "%s", str_c(str));
 		if (ret < 0)
 			break;
@@ -626,6 +641,8 @@
 
 	client->cmd = NULL;
 
+	if (save_hashes)
+		client->message_uidl_hashes_save = FALSE;
 	if (ctx->message == 0)
 		client_send_line(client, ".");
 	i_free(ctx);


More information about the dovecot-cvs mailing list