From d30c35e25ea6d935393e031509e6e22422b1e006 Mon Sep 17 00:00:00 2001 From: Timo Sirainen Date: Wed, 7 Sep 2011 10:01:36 +0300 Subject: [PATCH] imapc: Don't crash if a newly seen uncommitted message is expunged. --- src/lib-storage/index/imapc/imapc-mailbox.c | 42 +++++++++++++++++++-- src/lib-storage/index/imapc/imapc-storage.c | 1 + src/lib-storage/index/imapc/imapc-storage.h | 1 + src/lib-storage/index/imapc/imapc-sync.c | 7 ++++ 4 files changed, 48 insertions(+), 3 deletions(-) diff --git a/src/lib-storage/index/imapc/imapc-mailbox.c b/src/lib-storage/index/imapc/imapc-mailbox.c index d0e3041e80..b8d5669779 100644 --- a/src/lib-storage/index/imapc/imapc-mailbox.c +++ b/src/lib-storage/index/imapc/imapc-mailbox.c @@ -46,6 +46,27 @@ static void imapc_mailbox_init_delayed_trans(struct imapc_mailbox *mbox) mail_index_transaction_open_updated_view(mbox->delayed_sync_trans); } +static int imapc_mailbox_commit_delayed_expunges(struct imapc_mailbox *mbox) +{ + struct mail_index_view *view = imapc_mailbox_get_sync_view(mbox); + struct mail_index_transaction *trans; + const uint32_t *uidp; + uint32_t lseq; + int ret; + + trans = mail_index_transaction_begin(view, + MAIL_INDEX_TRANSACTION_FLAG_EXTERNAL); + array_foreach(&mbox->delayed_expunged_uids, uidp) { + if (mail_index_lookup_seq(view, *uidp, &lseq)) + mail_index_expunge(trans, lseq); + } + array_clear(&mbox->delayed_expunged_uids); + ret = mail_index_transaction_commit(&trans); + if (ret < 0) + mail_storage_set_index_error(&mbox->box); + return ret; +} + int imapc_mailbox_commit_delayed_trans(struct imapc_mailbox *mbox, bool *changes_r) { @@ -64,6 +85,13 @@ int imapc_mailbox_commit_delayed_trans(struct imapc_mailbox *mbox, } if (mbox->sync_view != NULL) mail_index_view_close(&mbox->sync_view); + + if (array_count(&mbox->delayed_expunged_uids) > 0) { + /* delayed expunges - commit them now in a separate + transaction */ + if (imapc_mailbox_commit_delayed_expunges(mbox) < 0) + ret = -1; + } return ret; } @@ -289,10 +317,18 @@ static void imapc_untagged_expunge(const struct imapc_untagged_reply *reply, imapc_msgmap_expunge(msgmap, rseq); imapc_mailbox_init_delayed_trans(mbox); - if (!mail_index_lookup_seq(mbox->delayed_sync_view, uid, &lseq)) { - /* already expunged by another session */ - } else { + if (mail_index_lookup_seq(mbox->sync_view, uid, &lseq)) mail_index_expunge(mbox->delayed_sync_trans, lseq); + else if (mail_index_lookup_seq(mbox->delayed_sync_view, uid, &lseq)) { + /* this message exists only in this transaction. lib-index + can't currently handle expunging anything except the last + appended message in a transaction, and fixing it would be + quite a lot of trouble. so instead we'll just delay doing + this expunge until after the current transaction has been + committed. */ + array_append(&mbox->delayed_expunged_uids, &uid, 1); + } else { + /* already expunged by another session */ } imapc_mailbox_idle_notify(mbox); } diff --git a/src/lib-storage/index/imapc/imapc-storage.c b/src/lib-storage/index/imapc/imapc-storage.c index 7f53afbcff..e1555a4cc2 100644 --- a/src/lib-storage/index/imapc/imapc-storage.c +++ b/src/lib-storage/index/imapc/imapc-storage.c @@ -305,6 +305,7 @@ imapc_mailbox_alloc(struct mail_storage *storage, struct mailbox_list *list, p_array_init(&mbox->resp_text_callbacks, pool, 16); p_array_init(&mbox->fetch_mails, pool, 16); p_array_init(&mbox->permanent_keywords, pool, 32); + p_array_init(&mbox->delayed_expunged_uids, pool, 16); imapc_mailbox_register_callbacks(mbox); return &mbox->box; } diff --git a/src/lib-storage/index/imapc/imapc-storage.h b/src/lib-storage/index/imapc/imapc-storage.h index b6977cc401..141d2a7ebc 100644 --- a/src/lib-storage/index/imapc/imapc-storage.h +++ b/src/lib-storage/index/imapc/imapc-storage.h @@ -57,6 +57,7 @@ struct imapc_mailbox { enum mail_flags permanent_flags; ARRAY_TYPE(keywords) permanent_keywords; + ARRAY_TYPE(uint32_t) delayed_expunged_uids; uint32_t sync_uid_validity; uint32_t sync_uid_next; uint32_t sync_fetch_first_uid; diff --git a/src/lib-storage/index/imapc/imapc-sync.c b/src/lib-storage/index/imapc/imapc-sync.c index 346725d0bb..d65cfe3f87 100644 --- a/src/lib-storage/index/imapc/imapc-sync.c +++ b/src/lib-storage/index/imapc/imapc-sync.c @@ -331,6 +331,7 @@ imapc_sync_begin(struct imapc_mailbox *mbox, static int imapc_sync_finish(struct imapc_sync_context **_ctx) { struct imapc_sync_context *ctx = *_ctx; + bool changes; int ret = ctx->failed ? -1 : 0; *_ctx = NULL; @@ -343,6 +344,12 @@ static int imapc_sync_finish(struct imapc_sync_context **_ctx) mail_index_sync_rollback(&ctx->index_sync_ctx); } ctx->mbox->syncing = FALSE; + + /* this is done simply to commit delayed expunges if there are any + (has to be done after sync is committed) */ + if (imapc_mailbox_commit_delayed_trans(ctx->mbox, &changes) < 0) + ctx->failed = TRUE; + i_free(ctx); return ret; } -- 2.47.3