dovecot-2.0: pop3: Code cleanup for mailbox opening code.

dovecot at dovecot.org dovecot at dovecot.org
Fri Oct 1 18:14:13 EEST 2010


details:   http://hg.dovecot.org/dovecot-2.0/rev/0da6f86c0ef5
changeset: 12219:0da6f86c0ef5
user:      Timo Sirainen <tss at iki.fi>
date:      Fri Oct 01 16:14:08 2010 +0100
description:
pop3: Code cleanup for mailbox opening code.

diffstat:

 src/pop3/pop3-client.c |  152 +++++++++++++++++++++++++++-----------------------
 1 files changed, 81 insertions(+), 71 deletions(-)

diffs (200 lines):

diff -r 90642b388d7e -r 0da6f86c0ef5 src/pop3/pop3-client.c
--- a/src/pop3/pop3-client.c	Fri Oct 01 15:37:19 2010 +0100
+++ b/src/pop3/pop3-client.c	Fri Oct 01 16:14:08 2010 +0100
@@ -1,7 +1,7 @@
 /* Copyright (c) 2002-2010 Dovecot authors, see the included COPYING file */
 
 #include "pop3-common.h"
-#include "buffer.h"
+#include "array.h"
 #include "ioloop.h"
 #include "network.h"
 #include "istream.h"
@@ -64,99 +64,109 @@
 	}
 }
 
-static bool init_mailbox(struct client *client, const char **error_r)
+static int read_mailbox(struct client *client, uint32_t *failed_uid_r)
 {
+        struct mailbox_status status;
+        struct mailbox_transaction_context *t;
 	struct mail_search_args *search_args;
-        struct mailbox_transaction_context *t;
 	struct mail_search_context *ctx;
-        struct mailbox_status status;
 	struct mail *mail;
-	buffer_t *message_sizes_buf;
-	uint32_t failed_uid = 0;
 	uoff_t size;
-	int i;
-	bool failed, expunged;
+	ARRAY_DEFINE(message_sizes, uoff_t);
+	int ret = 1;
 
-	message_sizes_buf = buffer_create_dynamic(default_pool, 512);
+	*failed_uid_r = 0;
+
+	mailbox_get_status(client->mailbox, STATUS_UIDVALIDITY, &status);
+	client->uid_validity = status.uidvalidity;
+	client->messages_count = status.messages;
+
+	t = mailbox_transaction_begin(client->mailbox, 0);
 
 	search_args = mail_search_build_init();
 	mail_search_build_add_all(search_args);
+	ctx = mailbox_search_init(t, search_args, NULL);
+	mail_search_args_unref(&search_args);
 
-	for (i = 0; i < 2; i++) {
-		expunged = FALSE;
-		if (mailbox_sync(client->mailbox,
-				 MAILBOX_SYNC_FLAG_FULL_READ) < 0) {
-			client_send_storage_error(client);
-			break;
-		}
-		mailbox_get_status(client->mailbox, STATUS_UIDVALIDITY, &status);
-		client->uid_validity = status.uidvalidity;
+	client->last_seen = 0;
+	client->total_size = 0;
+	i_array_init(&message_sizes, client->messages_count);
 
-		t = mailbox_transaction_begin(client->mailbox, 0);
-		ctx = mailbox_search_init(t, search_args, NULL);
-
-		client->last_seen = 0;
-		client->total_size = 0;
-		buffer_set_used_size(message_sizes_buf, 0);
-
-		failed = FALSE;
-		mail = mail_alloc(t, MAIL_FETCH_VIRTUAL_SIZE, NULL);
-		while (mailbox_search_next(ctx, mail)) {
-			if (mail_get_virtual_size(mail, &size) < 0) {
-				expunged = mail->expunged;
-				failed = TRUE;
-				if (failed_uid == mail->uid) {
-					i_error("Getting size of message "
-						"UID=%u failed", mail->uid);
-					break;
-				}
-				failed_uid = mail->uid;
-				break;
-			}
-
-			if ((mail_get_flags(mail) & MAIL_SEEN) != 0)
-				client->last_seen = mail->seq;
-                        client->total_size += size;
-
-			buffer_append(message_sizes_buf, &size, sizeof(size));
-		}
-		client->messages_count =
-			message_sizes_buf->used / sizeof(uoff_t);
-
-		mail_free(&mail);
-		if (mailbox_search_deinit(&ctx) < 0 || (failed && !expunged)) {
-			client_send_storage_error(client);
-			(void)mailbox_transaction_commit(&t);
+	mail = mail_alloc(t, MAIL_FETCH_VIRTUAL_SIZE, NULL);
+	while (mailbox_search_next(ctx, mail)) {
+		if (mail_get_virtual_size(mail, &size) < 0) {
+			ret = mail->expunged ? 0 : -1;
+			*failed_uid_r = mail->uid;
 			break;
 		}
 
-		if (!failed) {
-			client->trans = t;
-			client->message_sizes =
-				buffer_free_without_data(&message_sizes_buf);
-			mail_search_args_unref(&search_args);
-			return TRUE;
+		if ((mail_get_flags(mail) & MAIL_SEEN) != 0)
+			client->last_seen = mail->seq;
+		client->total_size += size;
+
+		array_append(&message_sizes, &size, 1);
+	}
+	mail_free(&mail);
+
+	if (mailbox_search_deinit(&ctx) < 0)
+		ret = -1;
+
+	if (ret > 0) {
+		client->trans = t;
+		client->message_sizes =
+			buffer_free_without_data(&message_sizes.arr.buffer);
+	} else {
+		/* commit the transaction instead of rollbacking to make sure
+		   we don't lose data (virtual sizes) added to cache file */
+		(void)mailbox_transaction_commit(&t);
+		array_free(&message_sizes);
+	}
+	return ret;
+}
+
+static int init_mailbox(struct client *client, const char **error_r)
+{
+	uint32_t failed_uid = 0, last_failed_uid = 0;
+	int i, ret = -1;
+
+	for (i = 0;; i++) {
+		if (mailbox_sync(client->mailbox,
+				 MAILBOX_SYNC_FLAG_FULL_READ) < 0) {
+			ret = -1;
+			break;
 		}
 
-		/* well, sync and try again. we might have cached virtual
-		   sizes, make sure they get committed. */
-		(void)mailbox_transaction_commit(&t);
+		ret = read_mailbox(client, &failed_uid);
+		if (ret > 0)
+			return 0;
+		if (i == 2)
+			break;
+
+		/* well, sync and try again. maybe it works the second time. */
+		last_failed_uid = failed_uid;
+		failed_uid = 0;
 	}
-	mail_search_args_unref(&search_args);
 
-	if (expunged) {
-		client_send_line(client,
-				 "-ERR [IN-USE] Couldn't sync mailbox.");
-		*error_r = "Can't sync mailbox: Messages keep getting expunged";
-	} else {
+	if (ret < 0) {
 		struct mail_storage *storage;
 		enum mail_error error;
 
 		storage = mailbox_get_storage(client->mailbox);
 		*error_r = mail_storage_get_last_error(storage, &error);
+		client_send_storage_error(client);
+	} else {
+		if (failed_uid == last_failed_uid && failed_uid != 0) {
+			/* failed twice in same message */
+			*error_r = t_strdup_printf(
+				"Getting size of message UID=%u failed",
+				failed_uid);
+		} else {
+			*error_r = "Can't sync mailbox: "
+				"Messages keep getting expunged";
+		}
+		client_send_line(client, "-ERR [IN-USE] Couldn't sync mailbox.");
 	}
-	buffer_free(&message_sizes_buf);
-	return FALSE;
+	return -1;
 }
 
 static enum uidl_keys parse_uidl_keymask(const char *format)
@@ -252,7 +262,7 @@
 	}
 	client->mail_set = mail_storage_get_settings(storage);
 
-	if (!init_mailbox(client, &errmsg)) {
+	if (init_mailbox(client, &errmsg) < 0) {
 		i_error("Couldn't init INBOX: %s", errmsg);
 		client_destroy(client, "Mailbox init failed");
 		return NULL;


More information about the dovecot-cvs mailing list