From e08e5a23758e36466a64345bd56d515a4ada9552 Mon Sep 17 00:00:00 2001 From: Sunil Shetye Date: Wed, 9 May 2012 13:40:12 +0530 Subject: fetchmail workaround for a bug in Microsoft Exchange treat missing header in response to a FETCH command as a transient error (Reported by John Connett) if there are too many transient errors, log it. --- NEWS | 5 +++++ driver.c | 25 ++++++++++++++++++++++--- imap.c | 2 +- tunable.h | 3 +++ 4 files changed, 31 insertions(+), 4 deletions(-) diff --git a/NEWS b/NEWS index 1e297d6f..11155c9b 100644 --- a/NEWS +++ b/NEWS @@ -95,6 +95,11 @@ fetchmail-6.3.22 (not yet released): a header request, in the face of message corruption. fetchmail now treats these as temporary errors. Report and Patch by Mikulas Patocka, Red Hat. +* Some servers, notably Microsoft Exchange, return "A0009 OK FETCH completed." + without any header in response to a header request for meeting reminder + messages (with a "meeting.ics" attachment). fetchmail now treats these as + transient errors. Report by John Connett, Patch by Sunil Shetye. + fetchmail-6.3.21 (released 2011-08-21, 26011 LoC): diff --git a/driver.c b/driver.c index 25fed3bd..c2917268 100644 --- a/driver.c +++ b/driver.c @@ -438,7 +438,8 @@ static int eat_trailer(int sock, struct query *ctl) static int fetch_messages(int mailserver_socket, struct query *ctl, int count, int **msgsizes, int maxfetch, - int *fetches, int *dispatches, int *deletions) + int *fetches, int *dispatches, int *deletions, + int *transient_errors) /* fetch messages in lockstep mode */ { flag force_retrieval; @@ -612,6 +613,7 @@ static int fetch_messages(int mailserver_socket, struct query *ctl, GT_("couldn't fetch headers, message %s@%s:%d (%d octets)\n"), ctl->remotename, ctl->server.truename, num, msgsize); + (*transient_errors)++; continue; } else if (err != 0) @@ -653,7 +655,10 @@ static int fetch_messages(int mailserver_socket, struct query *ctl, if (err == PS_RETAINED) suppress_forward = suppress_delete = retained = TRUE; else if (err == PS_TRANSIENT) + { suppress_delete = suppress_forward = TRUE; + (*transient_errors)++; + } else if (err == PS_REFUSED) suppress_forward = TRUE; else if (err) @@ -714,7 +719,10 @@ static int fetch_messages(int mailserver_socket, struct query *ctl, len); if (err == PS_TRANSIENT) + { suppress_delete = suppress_forward = TRUE; + (*transient_errors)++; + } else if (err) return(err); @@ -940,7 +948,7 @@ static int do_session( /* sigsetjmp returned zero -> normal operation */ char buf[MSGBUFSIZE+1], *realhost; int count, newm, bytes; - int fetches, dispatches, oldphase; + int fetches, dispatches, transient_errors, oldphase; struct idlist *idp; /* execute pre-initialization command, if any */ @@ -1297,6 +1305,7 @@ is restored.")); pass = 0; do { dispatches = 0; + transient_errors = 0; ++pass; /* reset timeout, in case we did an IDLE */ @@ -1426,10 +1435,20 @@ is restored.")); err = fetch_messages(mailserver_socket, ctl, count, &msgsizes, maxfetch, - &fetches, &dispatches, &deletions); + &fetches, &dispatches, &deletions, + &transient_errors); if (err != PS_SUCCESS && err != PS_MAXFETCH) goto cleanUp; + if (transient_errors > MAX_TRANSIENT_ERRORS) + { + if (outlevel > O_SILENT) + { + report(stderr, GT_("Too many mails skipped (%d > %d) due to transient errors for %s\n"), + transient_errors, MAX_TRANSIENT_ERRORS, buf); + } + } + if (!check_only && ctl->skipped && run.poll_interval > 0 && !nodetach) { diff --git a/imap.c b/imap.c index 93f05f2c..cb87eda5 100644 --- a/imap.c +++ b/imap.c @@ -1182,7 +1182,7 @@ static int imap_fetch_headers(int sock, struct query *ctl,int number,int *lenp) /* an unexpected tagged response */ if (outlevel > O_SILENT) report(stderr, GT_("Incorrect FETCH response: %s.\n"), buf); - return(PS_ERROR); + return(PS_TRANSIENT); } return(ok); } diff --git a/tunable.h b/tunable.h index 6202e7bd..fddeaf9b 100644 --- a/tunable.h +++ b/tunable.h @@ -21,3 +21,6 @@ /* default skipped message warning interval in seconds */ #define WARNING_INTERVAL 3600 + +/* maximum transient errors to accept */ +#define MAX_TRANSIENT_ERRORS 20 -- cgit v1.2.3