]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
imapc: Don't crash if a newly seen uncommitted message is expunged.
authorTimo Sirainen <tss@iki.fi>
Wed, 7 Sep 2011 07:01:36 +0000 (10:01 +0300)
committerTimo Sirainen <tss@iki.fi>
Wed, 7 Sep 2011 07:01:36 +0000 (10:01 +0300)
src/lib-storage/index/imapc/imapc-mailbox.c
src/lib-storage/index/imapc/imapc-storage.c
src/lib-storage/index/imapc/imapc-storage.h
src/lib-storage/index/imapc/imapc-sync.c

index d0e3041e80603dd46d6744e6b80bd0ac641e7bad..b8d56697793b3a1aadcc81b349e2369c060e870d 100644 (file)
@@ -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);
 }
index 7f53afbcffa81527224385e50f64929de70d90ce..e1555a4cc233fe32d4d9a30c8402c5e2cc89c55e 100644 (file)
@@ -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;
 }
index b6977cc4015ddc8b6a7c2debbb00a4ee50e72653..141d2a7ebcf7357673286be151a605de15b619d5 100644 (file)
@@ -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;
index 346725d0bb7b461437dd9477b15dfe9f3187b73a..d65cfe3f8713df3ac261bd02570588f4bfc0eb81 100644 (file)
@@ -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;
 }