From: Timo Sirainen Date: Thu, 9 Feb 2023 14:12:35 +0000 (+0200) Subject: imapc: Don't process untagged replies in mailbox that isn't fully selected yet X-Git-Tag: 2.3.21~105 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=a11c232854aaf8e658c347ea9d9008ccd231845c;p=thirdparty%2Fdovecot%2Fcore.git imapc: Don't process untagged replies in mailbox that isn't fully selected yet For example if the communication was: C: a SELECT box1 ... C: b SELECT box2 S: * 1 EXPUNGE S: * 1 EXISTS S: * OK [UIDVALIDITY 1675948459] UIDs valid S: ... S: b OK The expunge was intended for box1, not box2. This caused: Warning: imapc(...): Mailbox '...' state corrupted: EXPUNGE received for empty mailbox - reconnecting Fixed this by ignoring untagged EXPUNGE, FETCH, SEARCH and ESEARCH replies when the UIDVALIDITY reply hasn't been yet received for a mailbox. --- diff --git a/src/lib-storage/index/imapc/imapc-mailbox.c b/src/lib-storage/index/imapc/imapc-mailbox.c index ff915d9611..5e3e55a3a8 100644 --- a/src/lib-storage/index/imapc/imapc-mailbox.c +++ b/src/lib-storage/index/imapc/imapc-mailbox.c @@ -696,6 +696,11 @@ static void imapc_untagged_fetch(const struct imapc_untagged_reply *reply, if (mbox == NULL || reply->num == 0 || !imap_arg_get_list(reply->args, &list)) return; + if (!IMAPC_MAILBOX_IS_FULLY_SELECTED(mbox)) { + /* SELECTing another mailbox - this FETCH is still for the + previous selected mailbox. */ + return; + } struct imapc_untagged_fetch_ctx *ctx = imapc_untagged_fetch_ctx_create(); @@ -737,6 +742,11 @@ static void imapc_untagged_expunge(const struct imapc_untagged_reply *reply, if (mbox == NULL || rseq == 0 || IMAPC_BOX_HAS_FEATURE(mbox, IMAPC_FEATURE_NO_MSN_UPDATES)) return; + if (!IMAPC_MAILBOX_IS_FULLY_SELECTED(mbox)) { + /* SELECTing another mailbox - this EXPUNGE is still for the + previous selected mailbox. */ + return; + } mbox->prev_skipped_rseq = 0; mbox->prev_skipped_uid = 0; @@ -819,8 +829,14 @@ imapc_untagged_esearch_gmail_pop3(const struct imap_arg *args, static void imapc_untagged_search(const struct imapc_untagged_reply *reply, struct imapc_mailbox *mbox) { - if (mbox != NULL) - imapc_search_reply_search(reply->args, mbox); + if (mbox == NULL) + return; + if (!IMAPC_MAILBOX_IS_FULLY_SELECTED(mbox)) { + /* SELECTing another mailbox - this SEARCH is still for the + previous selected mailbox. */ + return; + } + imapc_search_reply_search(reply->args, mbox); } static void imapc_untagged_esearch(const struct imapc_untagged_reply *reply, @@ -831,6 +847,11 @@ static void imapc_untagged_esearch(const struct imapc_untagged_reply *reply, if (mbox == NULL || !imap_arg_get_list(reply->args, &tag_list)) return; + if (!IMAPC_MAILBOX_IS_FULLY_SELECTED(mbox)) { + /* SELECTing another mailbox - this ESEARCH is still for the + previous selected mailbox. */ + return; + } /* ESEARCH begins with (TAG ) */ if (!imap_arg_atom_equals(&tag_list[0], "TAG") || diff --git a/src/lib-storage/index/imapc/imapc-storage.h b/src/lib-storage/index/imapc/imapc-storage.h index e02c5687e4..6624a0d1bf 100644 --- a/src/lib-storage/index/imapc/imapc-storage.h +++ b/src/lib-storage/index/imapc/imapc-storage.h @@ -39,6 +39,12 @@ struct imapc_mailbox_event_callback { #define IMAPC_BOX_HAS_FEATURE(mbox, feature) \ (((mbox)->storage->set->parsed_features & feature) != 0) +/* Returns TRUE if we can assume from now on that untagged EXPUNGE, FETCH, etc. + replies belong to this mailbox instead of to the previously selected + mailbox. */ +#define IMAPC_MAILBOX_IS_FULLY_SELECTED(mbox) \ + ((mbox)->sync_uid_validity != 0) + struct imapc_namespace { const char *prefix; char separator;