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