dovecot-2.1: imapc: Allow accessing a mail that is being saved w...
dovecot at dovecot.org
dovecot at dovecot.org
Thu Sep 22 14:24:16 EEST 2011
details: http://hg.dovecot.org/dovecot-2.1/rev/b6633cb57814
changeset: 13542:b6633cb57814
user: Timo Sirainen <tss at iki.fi>
date: Thu Sep 22 14:24:03 2011 +0300
description:
imapc: Allow accessing a mail that is being saved without crashing.
This fixes crashes with LDA, LMTP, mail_log plugin, etc.
diffstat:
src/lib-storage/index/imapc/imapc-mail-fetch.c | 76 +++++++++++++++----------
src/lib-storage/index/imapc/imapc-mail.c | 2 +-
src/lib-storage/index/imapc/imapc-mail.h | 1 +
src/lib-storage/index/imapc/imapc-save.c | 60 ++++++++++++++++++--
4 files changed, 101 insertions(+), 38 deletions(-)
diffs (280 lines):
diff -r 645a56f9d8ee -r b6633cb57814 src/lib-storage/index/imapc/imapc-mail-fetch.c
--- a/src/lib-storage/index/imapc/imapc-mail-fetch.c Thu Sep 22 14:21:56 2011 +0300
+++ b/src/lib-storage/index/imapc/imapc-mail-fetch.c Thu Sep 22 14:24:03 2011 +0300
@@ -67,6 +67,12 @@
if (fields == 0)
return 0;
+ if (_mail->saving) {
+ mail_storage_set_critical(_mail->box->storage,
+ "Can't fetch data from uncommitted message");
+ return -1;
+ }
+
/* if we already know that the mail is expunged,
don't try to FETCH it */
view = mbox->delayed_sync_view != NULL ?
@@ -200,17 +206,50 @@
*input = filter_input;
}
+void imapc_mail_init_stream(struct imapc_mail *mail, bool have_body)
+{
+ struct index_mail *imail = &mail->imail;
+ struct mail *_mail = &imail->mail.mail;
+ struct istream *input;
+ uoff_t size;
+ int ret;
+
+ i_stream_set_name(imail->data.stream,
+ t_strdup_printf("imapc mail uid=%u", _mail->uid));
+ index_mail_set_read_buffer_size(_mail, imail->data.stream);
+
+ imapc_stream_filter(&imail->data.stream);
+ if (imail->mail.v.istream_opened != NULL) {
+ if (imail->mail.v.istream_opened(_mail,
+ &imail->data.stream) < 0) {
+ i_stream_unref(&imail->data.stream);
+ return;
+ }
+ } else if (have_body) {
+ ret = i_stream_get_size(imail->data.stream, TRUE, &size);
+ if (ret < 0) {
+ i_stream_unref(&imail->data.stream);
+ return;
+ }
+ i_assert(ret != 0);
+ imail->data.physical_size = size;
+ /* we'll assume that the remote server is working properly and
+ sending CRLF linefeeds */
+ imail->data.virtual_size = size;
+ }
+
+ if (index_mail_init_stream(imail, NULL, NULL, &input) < 0)
+ i_stream_unref(&imail->data.stream);
+}
+
static void
imapc_fetch_stream(struct imapc_mail *mail,
const struct imapc_untagged_reply *reply,
const struct imap_arg *arg, bool body)
{
struct index_mail *imail = &mail->imail;
- struct mail *_mail = &imail->mail.mail;
- struct istream *input;
- uoff_t size;
const char *value;
- int fd, ret;
+ int fd;
if (imail->data.stream != NULL) {
if (!body)
@@ -231,7 +270,7 @@
if (!imap_arg_get_nstring(arg, &value))
return;
if (value == NULL) {
- mail_set_expunged(_mail);
+ mail_set_expunged(&imail->mail.mail);
return;
}
if (mail->body == NULL) {
@@ -244,32 +283,7 @@
mail->body->used);
}
- i_stream_set_name(imail->data.stream,
- t_strdup_printf("imapc mail uid=%u", _mail->uid));
- index_mail_set_read_buffer_size(_mail, imail->data.stream);
-
- imapc_stream_filter(&imail->data.stream);
- if (imail->mail.v.istream_opened != NULL) {
- if (imail->mail.v.istream_opened(_mail,
- &imail->data.stream) < 0) {
- i_stream_unref(&imail->data.stream);
- return;
- }
- } else if (body) {
- ret = i_stream_get_size(imail->data.stream, TRUE, &size);
- if (ret < 0) {
- i_stream_unref(&imail->data.stream);
- return;
- }
- i_assert(ret != 0);
- imail->data.physical_size = size;
- /* we'll assume that the remote server is working properly and
- sending CRLF linefeeds */
- imail->data.virtual_size = size;
- }
-
- if (index_mail_init_stream(imail, NULL, NULL, &input) < 0)
- i_stream_unref(&imail->data.stream);
+ imapc_mail_init_stream(mail, body);
}
void imapc_mail_fetch_update(struct imapc_mail *mail,
diff -r 645a56f9d8ee -r b6633cb57814 src/lib-storage/index/imapc/imapc-mail.c
--- a/src/lib-storage/index/imapc/imapc-mail.c Thu Sep 22 14:21:56 2011 +0300
+++ b/src/lib-storage/index/imapc/imapc-mail.c Thu Sep 22 14:24:03 2011 +0300
@@ -218,7 +218,7 @@
}
/* searching code handles prefetching internally,
elsewhere we want to do it immediately */
- if (!mail->search_mail)
+ if (!mail->search_mail && !_mail->saving)
(void)imapc_mail_prefetch(_mail);
}
diff -r 645a56f9d8ee -r b6633cb57814 src/lib-storage/index/imapc/imapc-mail.h
--- a/src/lib-storage/index/imapc/imapc-mail.h Thu Sep 22 14:21:56 2011 +0300
+++ b/src/lib-storage/index/imapc/imapc-mail.h Thu Sep 22 14:24:03 2011 +0300
@@ -23,6 +23,7 @@
struct mailbox_header_lookup_ctx *wanted_headers);
int imapc_mail_fetch(struct mail *mail, enum mail_fetch_field fields);
bool imapc_mail_prefetch(struct mail *mail);
+void imapc_mail_init_stream(struct imapc_mail *mail, bool have_body);
void imapc_mail_fetch_update(struct imapc_mail *mail,
const struct imapc_untagged_reply *reply,
diff -r 645a56f9d8ee -r b6633cb57814 src/lib-storage/index/imapc/imapc-save.c
--- a/src/lib-storage/index/imapc/imapc-save.c Thu Sep 22 14:21:56 2011 +0300
+++ b/src/lib-storage/index/imapc/imapc-save.c Thu Sep 22 14:24:03 2011 +0300
@@ -12,6 +12,7 @@
#include "imapc-client.h"
#include "imapc-storage.h"
#include "imapc-sync.h"
+#include "imapc-mail.h"
struct imapc_save_context {
struct mail_save_context ctx;
@@ -25,6 +26,7 @@
uint32_t dest_uid_validity;
ARRAY_TYPE(seq_range) dest_saved_uids;
+ unsigned int save_count;
unsigned int failed:1;
unsigned int finished:1;
@@ -103,11 +105,14 @@
}
static void imapc_save_appenduid(struct imapc_save_context *ctx,
- const struct imapc_command_reply *reply)
+ const struct imapc_command_reply *reply,
+ uint32_t *uid_r)
{
const char *const *args;
uint32_t uid_validity, dest_uid;
+ *uid_r = 0;
+
/* <uidvalidity> <dest uid-set> */
args = t_strsplit(reply->resp_text_value, " ");
if (str_array_length(args) != 2)
@@ -120,18 +125,48 @@
else if (ctx->dest_uid_validity != uid_validity)
return;
- if (str_to_uint32(args[1], &dest_uid) == 0)
+ if (str_to_uint32(args[1], &dest_uid) == 0) {
seq_range_array_add(&ctx->dest_saved_uids, 0, dest_uid);
+ *uid_r = dest_uid;
+ }
+}
+
+static void
+imapc_save_add_to_index(struct imapc_save_context *ctx, uint32_t uid)
+{
+ struct mail *_mail = ctx->ctx.dest_mail;
+ struct index_mail *imail = (struct index_mail *)_mail;
+ uint32_t seq;
+
+ if (_mail == NULL)
+ return;
+
+ /* we'll temporarily append messages and at commit time expunge
+ them all, since we can't guarantee that no one else has saved
+ messages to remote server during our transaction */
+ mail_index_append(ctx->trans, uid, &seq);
+ mail_set_seq_saving(_mail, seq);
+ imail->data.forced_no_caching = TRUE;
+
+ if (ctx->fd != -1) {
+ imail->data.stream = i_stream_create_fd(ctx->fd, 0, TRUE);
+ imapc_mail_init_stream((struct imapc_mail *)imail, TRUE);
+ ctx->fd = -1;
+ }
+
+ ctx->save_count++;
}
static void imapc_save_callback(const struct imapc_command_reply *reply,
void *context)
{
struct imapc_save_cmd_context *ctx = context;
+ uint32_t uid = 0;
if (reply->state == IMAPC_COMMAND_STATE_OK) {
if (strcasecmp(reply->resp_text_key, "APPENDUID") == 0)
- imapc_save_appenduid(ctx->ctx, reply);
+ imapc_save_appenduid(ctx->ctx, reply, &uid);
+ imapc_save_add_to_index(ctx->ctx, uid);
ctx->ret = 0;
} else if (reply->state == IMAPC_COMMAND_STATE_NO) {
imapc_copy_error_from_reply(ctx->ctx->mbox->storage,
@@ -245,9 +280,15 @@
struct imapc_save_context *ctx = (struct imapc_save_context *)_ctx;
struct mail_transaction_commit_changes *changes =
_ctx->transaction->changes;
+ uint32_t i, last_seq;
i_assert(ctx->finished);
+ /* expunge all added messages from index before commit */
+ last_seq = mail_index_view_get_messages_count(ctx->trans->view);
+ for (i = 0; i < ctx->save_count; i++)
+ mail_index_expunge(ctx->trans, last_seq - i);
+
if (array_is_created(&ctx->dest_saved_uids)) {
changes->uid_validity = ctx->dest_uid_validity;
array_append_array(&changes->saved_uids, &ctx->dest_saved_uids);
@@ -277,11 +318,14 @@
}
static void imapc_save_copyuid(struct imapc_save_context *ctx,
- const struct imapc_command_reply *reply)
+ const struct imapc_command_reply *reply,
+ uint32_t *uid_r)
{
const char *const *args;
uint32_t uid_validity, dest_uid;
+ *uid_r = 0;
+
/* <uidvalidity> <source uid-set> <dest uid-set> */
args = t_strsplit(reply->resp_text_value, " ");
if (str_array_length(args) != 3)
@@ -294,18 +338,22 @@
else if (ctx->dest_uid_validity != uid_validity)
return;
- if (str_to_uint32(args[2], &dest_uid) == 0)
+ if (str_to_uint32(args[2], &dest_uid) == 0) {
seq_range_array_add(&ctx->dest_saved_uids, 0, dest_uid);
+ *uid_r = dest_uid;
+ }
}
static void imapc_copy_callback(const struct imapc_command_reply *reply,
void *context)
{
struct imapc_save_cmd_context *ctx = context;
+ uint32_t uid = 0;
if (reply->state == IMAPC_COMMAND_STATE_OK) {
if (strcasecmp(reply->resp_text_key, "COPYUID") == 0)
- imapc_save_copyuid(ctx->ctx, reply);
+ imapc_save_copyuid(ctx->ctx, reply, &uid);
+ imapc_save_add_to_index(ctx->ctx, uid);
ctx->ret = 0;
} else if (reply->state == IMAPC_COMMAND_STATE_NO) {
imapc_copy_error_from_reply(ctx->ctx->mbox->storage,
More information about the dovecot-cvs
mailing list