From 638734376d265a1529985755da671c09cfc22e06 Mon Sep 17 00:00:00 2001 From: Timo Sirainen Date: Wed, 27 Jan 2016 15:16:18 +0200 Subject: [PATCH] imapc: Don't use fetch-fix-broken-mails for OK and NO [SERVERBUG] FETCH replies Hopefully no servers are actually returning OK without returning a FETCH reply. If they are, maybe we need another workaround.. In any case Yahoo IMAP sometimes loses state and starts returning OK without FETCH replies to all UID FETCH requests (and BADs to FETCHes). It also may return NO [UNAVAILABLE] for both permanent and temporary FETCH failures, so we can't do anything with that. I added NO [SERVERBUG] because that's what Dovecot responds to temporary failures. I'm not sure how useful that check is though. --- .../index/imapc/imapc-mail-fetch.c | 35 +++++++++++++++++-- src/lib-storage/index/imapc/imapc-mail.c | 3 +- src/lib-storage/index/imapc/imapc-mail.h | 1 + 3 files changed, 35 insertions(+), 4 deletions(-) diff --git a/src/lib-storage/index/imapc/imapc-mail-fetch.c b/src/lib-storage/index/imapc/imapc-mail-fetch.c index 0412582fd0..7e2b513200 100644 --- a/src/lib-storage/index/imapc/imapc-mail-fetch.c +++ b/src/lib-storage/index/imapc/imapc-mail-fetch.c @@ -10,10 +10,41 @@ #include "imap-arg.h" #include "imap-date.h" #include "imap-quote.h" +#include "imap-resp-code.h" #include "imapc-client.h" #include "imapc-mail.h" #include "imapc-storage.h" +static void imapc_mail_set_failure(struct imapc_mail *mail, + const struct imapc_command_reply *reply) +{ + struct imapc_mailbox *mbox = + (struct imapc_mailbox *)mail->imail.mail.mail.box; + + switch (reply->state) { + case IMAPC_COMMAND_STATE_OK: + break; + case IMAPC_COMMAND_STATE_NO: + if (!IMAPC_BOX_HAS_FEATURE(mbox, IMAPC_FEATURE_FETCH_FIX_BROKEN_MAILS)) { + /* fetch-fix-broken-mails feature disabled - + fail any mails with missing replies */ + break; + } + if (reply->resp_text_key != NULL && + strcasecmp(reply->resp_text_key, IMAP_RESP_CODE_SERVERBUG) == 0) { + /* this is a temporary error, retrying should work. */ + } else { + /* hopefully this is a permanent failure */ + mail->fetch_ignore_if_missing = TRUE; + } + break; + case IMAPC_COMMAND_STATE_BAD: + case IMAPC_COMMAND_STATE_DISCONNECTED: + mail->fetch_failed = TRUE; + break; + } +} + static void imapc_mail_fetch_callback(const struct imapc_command_reply *reply, void *context) @@ -28,9 +59,7 @@ imapc_mail_fetch_callback(const struct imapc_command_reply *reply, struct imapc_mail *mail = *mailp; i_assert(mail->fetch_count > 0); - if (reply->state != IMAPC_COMMAND_STATE_OK && - reply->state != IMAPC_COMMAND_STATE_NO) - mail->fetch_failed = TRUE; + imapc_mail_set_failure(mail, reply); if (--mail->fetch_count == 0) mail->fetching_fields = 0; pool_unref(&mail->imail.mail.pool); diff --git a/src/lib-storage/index/imapc/imapc-mail.c b/src/lib-storage/index/imapc/imapc-mail.c index c3eddeb006..4e93b70982 100644 --- a/src/lib-storage/index/imapc/imapc-mail.c +++ b/src/lib-storage/index/imapc/imapc-mail.c @@ -61,6 +61,7 @@ static bool imapc_mail_is_expunged(struct mail *_mail) static int imapc_mail_failed(struct mail *mail, const char *field) { + struct imapc_mail *imail = (struct imapc_mail *)mail; struct imapc_mailbox *mbox = (struct imapc_mailbox *)mail->box; bool fix_broken_mail = FALSE; @@ -81,7 +82,7 @@ static int imapc_mail_failed(struct mail *mail, const char *field) versions failed to return any data for messages in Calendars mailbox. This seems to be fixed in newer versions. */ - fix_broken_mail = IMAPC_BOX_HAS_FEATURE(mbox, IMAPC_FEATURE_FETCH_FIX_BROKEN_MAILS); + fix_broken_mail = imail->fetch_ignore_if_missing; mail_storage_set_critical(mail->box->storage, "imapc: Remote server didn't send %s for UID %u in %s%s", field, mail->uid, mail->box->vname, diff --git a/src/lib-storage/index/imapc/imapc-mail.h b/src/lib-storage/index/imapc/imapc-mail.h index 52cc1c7643..c3de665fb1 100644 --- a/src/lib-storage/index/imapc/imapc-mail.h +++ b/src/lib-storage/index/imapc/imapc-mail.h @@ -20,6 +20,7 @@ struct imapc_mail { bool header_fetched; bool body_fetched; bool header_list_fetched; + bool fetch_ignore_if_missing; bool fetch_failed; };