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