changeset 2976:96a4ab34c8f1 HEAD

Added pop3_uidl_format setting.
author Timo Sirainen <tss@iki.fi>
date Wed, 15 Dec 2004 22:05:15 +0200
parents c59fd95ad3ee
children 4a6788997812
files dovecot-example.conf src/lib-storage/index/index-mail.c src/lib-storage/index/mbox/mbox-storage.c src/lib-storage/mail-storage.h src/master/mail-process.c src/master/master-settings.c src/master/master-settings.h src/pop3/client.c src/pop3/client.h src/pop3/commands.c src/pop3/common.h src/pop3/main.c
diffstat 12 files changed, 126 insertions(+), 19 deletions(-) [+]
line wrap: on
line diff
--- a/dovecot-example.conf	Wed Dec 15 21:31:06 2004 +0200
+++ b/dovecot-example.conf	Wed Dec 15 22:05:15 2004 +0200
@@ -444,6 +444,25 @@
   # from new ones. Some clients still wish to use this though. Enabling this
   # makes RSET command clear all \Seen flags from messages.
   #pop3_enable_last = no
+  
+  # POP3 UIDL format to use. You can use following variables:
+  #
+  #  %v - Mailbox UIDVALIDITY
+  #  %u - Mail UID
+  #  %m - MD5 sum of the mailbox headers in hex (mbox only)
+  #
+  # If you want UIDL compatibility with other POP3 servers, use:
+  #  UW's ipop3d         : %08Xv%08Xu
+  #  Courier version 0   : (maildir filename, not supported)
+  #  Courier version 1   : %u
+  #  Courier version 2   : %v-%u
+  #  Cyrus (old)         : %u
+  #  Cyrus (new)         : %v.%u
+  #
+  # Note that Outlook 2003 seems to have problems with %v.%u format which is
+  # Dovecot's default, so if you're building a new server it would be a good
+  # idea to change this. %08Xu%08Xv should be pretty fail-safe.
+  #pop3_uidl_format = %v.%u
 
   # Support for dynamically loadable modules.
   #mail_use_modules = no
--- a/src/lib-storage/index/index-mail.c	Wed Dec 15 21:31:06 2004 +0200
+++ b/src/lib-storage/index/index-mail.c	Wed Dec 15 22:05:15 2004 +0200
@@ -3,6 +3,7 @@
 #include "lib.h"
 #include "buffer.h"
 #include "istream.h"
+#include "hex-binary.h"
 #include "str.h"
 #include "message-date.h"
 #include "message-part-serialize.h"
@@ -518,6 +519,7 @@
 	struct index_mail_data *data = &mail->data;
 	struct mail_cache_field *cache_fields = mail->ibox->cache_fields;
 	string_t *str;
+	const void *ext_data;
 
 	switch (field) {
 	case MAIL_FETCH_IMAP_BODY:
@@ -579,13 +581,16 @@
 		return data->envelope;
 	case MAIL_FETCH_FROM_ENVELOPE:
 		return NULL;
-	case MAIL_FETCH_UID_STRING:
-		if (data->uid_string == NULL) {
-			data->uid_string =
-				p_strdup_printf(mail->pool, "%u.%u",
-						mail->uid_validity, _mail->uid);
+	case MAIL_FETCH_HEADER_MD5:
+		if (mail_index_lookup_ext(mail->trans->trans_view, data->seq,
+					  mail->ibox->md5hdr_ext_idx,
+					  &ext_data) < 0) {
+			mail_storage_set_index_error(mail->ibox);
+			return NULL;
 		}
-		return data->uid_string;
+		if (ext_data == NULL)
+			return NULL;
+		return binary_to_hex(ext_data, 16);
 	default:
 		i_unreached();
 		return NULL;
--- a/src/lib-storage/index/mbox/mbox-storage.c	Wed Dec 15 21:31:06 2004 +0200
+++ b/src/lib-storage/index/mbox/mbox-storage.c	Wed Dec 15 22:05:15 2004 +0200
@@ -417,6 +417,8 @@
 
 	ibox->md5hdr_ext_idx =
 		mail_index_ext_register(ibox->index, "header-md5", 0, 16, 1);
+	if ((flags & MAILBOX_OPEN_KEEP_HEADER_MD5) != 0)
+		ibox->mbox_save_md5 = TRUE;
 
 	if (access(path, R_OK|W_OK) < 0) {
 		if (errno < EACCES)
--- a/src/lib-storage/mail-storage.h	Wed Dec 15 21:31:06 2004 +0200
+++ b/src/lib-storage/mail-storage.h	Wed Dec 15 22:05:15 2004 +0200
@@ -8,7 +8,8 @@
 enum mailbox_open_flags {
 	MAILBOX_OPEN_READONLY		= 0x01,
 	MAILBOX_OPEN_FAST		= 0x02,
-	MAILBOX_OPEN_KEEP_RECENT	= 0x04
+	MAILBOX_OPEN_KEEP_RECENT	= 0x04,
+	MAILBOX_OPEN_KEEP_HEADER_MD5	= 0x04
 };
 
 enum mailbox_list_flags {
@@ -82,7 +83,7 @@
 	MAIL_FETCH_IMAP_BODYSTRUCTURE	= 0x00002000,
 	MAIL_FETCH_IMAP_ENVELOPE	= 0x00004000,
 	MAIL_FETCH_FROM_ENVELOPE	= 0x00008000,
-	MAIL_FETCH_UID_STRING		= 0x00010000
+	MAIL_FETCH_HEADER_MD5		= 0x00010000
 };
 
 enum mailbox_sync_flags {
--- a/src/master/mail-process.c	Wed Dec 15 21:31:06 2004 +0200
+++ b/src/master/mail-process.c	Wed Dec 15 22:05:15 2004 +0200
@@ -197,6 +197,8 @@
 			    set->imap_capability, NULL));
 	env_put(t_strconcat("IMAP_CLIENT_WORKAROUNDS=",
 			    set->imap_client_workarounds, NULL));
+	env_put(t_strconcat("POP3_UIDL_FORMAT=",
+			    set->pop3_uidl_format, NULL));
 	env_put(t_strconcat("POP3_CLIENT_WORKAROUNDS=",
 			    set->pop3_client_workarounds, NULL));
 
--- a/src/master/master-settings.c	Wed Dec 15 21:31:06 2004 +0200
+++ b/src/master/master-settings.c	Wed Dec 15 22:05:15 2004 +0200
@@ -125,6 +125,7 @@
 	/* pop3 */
 	DEF(SET_BOOL, pop3_no_flag_updates),
 	DEF(SET_BOOL, pop3_enable_last),
+	DEF(SET_STR, pop3_uidl_format),
 	DEF(SET_STR, pop3_client_workarounds),
 
 	{ 0, NULL, 0 }
@@ -296,6 +297,7 @@
 	/* pop3 */
 	MEMBER(pop3_no_flag_updates) FALSE,
 	MEMBER(pop3_enable_last) FALSE,
+	MEMBER(pop3_uidl_format) "%v.%u",
 	MEMBER(pop3_client_workarounds) NULL,
 
 	/* .. */
--- a/src/master/master-settings.h	Wed Dec 15 21:31:06 2004 +0200
+++ b/src/master/master-settings.h	Wed Dec 15 22:05:15 2004 +0200
@@ -96,6 +96,7 @@
 	/* pop3 */
 	int pop3_no_flag_updates;
 	int pop3_enable_last;
+	const char *pop3_uidl_format;
 	const char *pop3_client_workarounds;
 
 	/* .. */
--- a/src/pop3/client.c	Wed Dec 15 21:31:06 2004 +0200
+++ b/src/pop3/client.c	Wed Dec 15 22:05:15 2004 +0200
@@ -37,16 +37,15 @@
 static void client_input(void *context);
 static int client_output(void *context);
 
-static int sync_mailbox(struct mailbox *box)
+static int sync_mailbox(struct mailbox *box, struct mailbox_status *status)
 {
 	struct mailbox_sync_context *ctx;
         struct mailbox_sync_rec sync_rec;
-	struct mailbox_status status;
 
 	ctx = mailbox_sync_init(box, MAILBOX_SYNC_FLAG_FULL_READ);
 	while (mailbox_sync_next(ctx, &sync_rec) > 0)
 		;
-	return mailbox_sync_deinit(ctx, &status);
+	return mailbox_sync_deinit(ctx, status);
 }
 
 static int init_mailbox(struct client *client)
@@ -54,6 +53,7 @@
 	struct mail_search_arg search_arg;
         struct mailbox_transaction_context *t;
 	struct mail_search_context *ctx;
+        struct mailbox_status status;
 	struct mail *mail;
 	buffer_t *message_sizes_buf;
 	int i, failed;
@@ -64,10 +64,11 @@
 	search_arg.type = SEARCH_ALL;
 
 	for (i = 0; i < 2; i++) {
-		if (sync_mailbox(client->mailbox) < 0) {
+		if (sync_mailbox(client->mailbox, &status) < 0) {
 			client_send_storage_error(client);
 			break;
 		}
+		client->uid_validity = status.uidvalidity;
 
 		t = mailbox_transaction_begin(client->mailbox, FALSE);
 		ctx = mailbox_search_init(t, NULL, &search_arg, NULL,
@@ -152,6 +153,8 @@
 	flags = 0;
 	if (no_flag_updates)
 		flags |= MAILBOX_OPEN_KEEP_RECENT;
+	if ((uidl_keymask & UIDL_MD5) != 0)
+		flags |= MAILBOX_OPEN_KEEP_HEADER_MD5;
 	client->mailbox = mailbox_open(storage, "INBOX", flags);
 	if (client->mailbox == NULL) {
 		i_error("Couldn't open INBOX: %s",
--- a/src/pop3/client.h	Wed Dec 15 21:31:06 2004 +0200
+++ b/src/pop3/client.h	Wed Dec 15 22:05:15 2004 +0200
@@ -22,6 +22,7 @@
 	time_t last_input, last_output;
 	unsigned int bad_counter;
 
+	unsigned int uid_validity;
 	unsigned int messages_count;
 	unsigned int deleted_count;
 	uoff_t *message_sizes;
--- a/src/pop3/commands.c	Wed Dec 15 21:31:06 2004 +0200
+++ b/src/pop3/commands.c	Wed Dec 15 22:05:15 2004 +0200
@@ -4,6 +4,7 @@
 #include "istream.h"
 #include "ostream.h"
 #include "str.h"
+#include "var-expand.h"
 #include "message-size.h"
 #include "mail-storage.h"
 #include "mail-search.h"
@@ -478,10 +479,23 @@
 
 static int list_uids_iter(struct client *client, struct cmd_uidl_context *ctx)
 {
+	static struct var_expand_table static_tab[] = {
+		{ 'v', NULL },
+		{ 'u', NULL },
+		{ 'm', NULL },
+		{ '\0', NULL }
+	};
+	struct var_expand_table *tab;
 	struct mail *mail;
-	const char *uid_str;
+	string_t *str;
 	int ret, 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);
+
+	str = str_new(default_pool, 128);
+
 	while ((mail = mailbox_search_next(ctx->search_ctx)) != NULL) {
 		if (client->deleted) {
 			uint32_t idx = mail->seq - 1;
@@ -489,21 +503,34 @@
 			    (1 << (idx % CHAR_BIT)))
 				continue;
 		}
-
-		uid_str = mail->get_special(mail, MAIL_FETCH_UID_STRING);
 		found = TRUE;
 
-		ret = client_send_line(client, ctx->message == 0 ?
-				       "%u %s" : "+OK %u %s",
-				       mail->seq, uid_str);
+		t_push();
+		if ((uidl_keymask & UIDL_UID) != 0)
+			tab[1].value = dec2str(mail->uid);
+		if ((uidl_keymask & UIDL_MD5) != 0) {
+			tab[2].value =
+				mail->get_special(mail, MAIL_FETCH_HEADER_MD5);
+		}
+
+		str_truncate(str, 0);
+		str_printfa(str, ctx->message == 0 ? "%u " : "+OK %u ",
+			    mail->seq);
+		var_expand(str, uidl_format, tab);
+
+		ret = client_send_line(client, "%s", str_c(str));
+		t_pop();
+
 		if (ret < 0)
 			break;
 		if (ret == 0 && ctx->message == 0) {
 			/* output is being buffered, continue when there's
 			   more space */
+			str_free(str);
 			return 0;
 		}
 	}
+	str_free(str);
 
 	/* finished */
 	(void)mailbox_search_deinit(ctx->search_ctx);
@@ -527,6 +554,7 @@
 cmd_uidl_init(struct client *client, unsigned int message)
 {
         struct cmd_uidl_context *ctx;
+	enum mail_fetch_field wanted_fields;
 
 	ctx = i_new(struct cmd_uidl_context, 1);
 
@@ -539,8 +567,13 @@
 		ctx->search_arg.value.seqset = &ctx->seqset;
 	}
 
+	wanted_fields = 0;
+	if ((uidl_keymask & UIDL_MD5) != 0)
+		wanted_fields |= MAIL_FETCH_HEADER_MD5;
+
 	ctx->search_ctx = mailbox_search_init(client->trans, NULL,
-					      &ctx->search_arg, NULL, 0, NULL);
+					      &ctx->search_arg, NULL,
+					      wanted_fields, NULL);
 	if (message == 0) {
 		client->cmd = cmd_uidl_callback;
 		client->cmd_context = ctx;
--- a/src/pop3/common.h	Wed Dec 15 21:31:06 2004 +0200
+++ b/src/pop3/common.h	Wed Dec 15 22:05:15 2004 +0200
@@ -9,9 +9,17 @@
 	WORKAROUND_OE_NS_EOH			= 0x02
 };
 
+enum uidl_keys {
+	UIDL_UIDVALIDITY	= 0x01,
+	UIDL_UID		= 0x02,
+	UIDL_MD5		= 0x04
+};
+
 extern struct ioloop *ioloop;
 extern enum client_workarounds client_workarounds;
 extern int enable_last_command, no_flag_updates;
+extern const char *uidl_format;
+extern enum uidl_keys uidl_keymask;
 
 extern void (*hook_mail_storage_created)(struct mail_storage **storage);
 extern void (*hook_client_created)(struct client **client);
--- a/src/pop3/main.c	Wed Dec 15 21:31:06 2004 +0200
+++ b/src/pop3/main.c	Wed Dec 15 22:05:15 2004 +0200
@@ -9,6 +9,7 @@
 #include "process-title.h"
 #include "randgen.h"
 #include "module-dir.h"
+#include "var-expand.h"
 #include "mail-storage.h"
 
 #include <stdio.h>
@@ -40,6 +41,8 @@
 enum client_workarounds client_workarounds = 0;
 int enable_last_command = FALSE;
 int no_flag_updates = FALSE;
+const char *uidl_format;
+enum uidl_keys uidl_keymask;
 
 static void sig_quit(int signo __attr_unused__)
 {
@@ -68,6 +71,28 @@
 	}
 }
 
+static enum uidl_keys parse_uidl_keymask(const char *format)
+{
+	enum uidl_keys mask = 0;
+
+	for (; *format != '\0'; format++) {
+		if (format[0] == '%' && format[1] != '\0') {
+			switch (var_get_key(++format)) {
+			case 'v':
+				mask |= UIDL_UIDVALIDITY;
+				break;
+			case 'u':
+				mask |= UIDL_UID;
+				break;
+			case 'm':
+				mask |= UIDL_MD5;
+				break;
+			}
+		}
+	}
+	return mask;
+}
+
 static void open_logfile(void)
 {
 	const char *user;
@@ -139,6 +164,11 @@
 	enable_last_command = getenv("POP3_ENABLE_LAST") != NULL;
 	no_flag_updates = getenv("POP3_NO_FLAG_UPDATES") != NULL;
 
+	uidl_format = getenv("POP3_UIDL_FORMAT");
+	if (uidl_format == NULL)
+		uidl_format = "%v.%u";
+	uidl_keymask = parse_uidl_keymask(uidl_format);
+
 	storage = mail_storage_create_with_data(mail, getenv("USER"));
 	if (storage == NULL) {
 		/* failed */