From 335cb5e4606e4f5265292ae76b95793b2ed9f047 Mon Sep 17 00:00:00 2001 From: Matthias Andree Date: Tue, 13 Dec 2005 00:36:18 +0000 Subject: Merge patch by Sunil Sheteye to fix five bugs: * Close SMTP sockets early, to reduce resource usage, trigger earlier delivery with some MTAs and avoid SIGPIPE (SIG 13) when the SMTP listener gets bored and drops the connection after timeout. * Don't treat hitting a fetch limit (PS_MAXFETCH) as error. * Fix negative "messages left on server" on idle/repoll with fetchlimit. * Properly track logout stage (STAGE_LOGOUT). * Preserve error conditions across postconnect script. svn path=/branches/BRANCH_6-3/; revision=4541 --- NEWS | 8 ++++++++ driver.c | 58 ++++++++++++++++++++++++++++++++++++++++++++++------------ fetchmail.c | 29 ----------------------------- 3 files changed, 54 insertions(+), 41 deletions(-) diff --git a/NEWS b/NEWS index c075606b..a74c403f 100644 --- a/NEWS +++ b/NEWS @@ -39,6 +39,14 @@ fetchmail 6.3.1 (not yet released): * Fix segfault (null pointer dereference) on some operating systems with fetchmail's obsolete DNS MX/host alias lookups in multidrop mode. Patch by Dr.-Ing. Andreas Haakh. (MA) +* Close SMTP sockets early, to reduce resource usage, trigger earlier delivery + with some MTAs and avoid SIGPIPE (SIG 13) when the SMTP listener gets bored + and drops the connection after timeout. Patch by Sunil Shetye. (MA) +* Don't treat hitting a fetch limit as error. Patch by Sunil Shetye. (MA) +* Fix negative "messages left on server" on idle/repoll with fetchlimit. + Patch by Sunil Shetye. (MA) +* Properly track logout stage. Patch by Sunil Shetye. (MA) +* Preserve error conditions across postconnect script. Sunil Shetye. (MA) fetchmail 6.3.0 (released 2005-11-30): diff --git a/driver.c b/driver.c index 4dffcb41..cc009c12 100644 --- a/driver.c +++ b/driver.c @@ -427,6 +427,7 @@ static int fetch_messages(int mailserver_socket, struct query *ctl, int num, firstnum = 1, lastnum = 0, err, len; int fetchsizelimit = ctl->fetchsizelimit; int msgsize; + int initialfetches = *fetches; if (ctl->server.base_protocol->getpartialsizes && NUM_NONZERO(fetchsizelimit)) { @@ -814,10 +815,11 @@ flagthemail: /* perhaps this as many as we're ready to handle */ if (maxfetch && maxfetch <= *fetches && num < count) { + int remcount = count - (*fetches - initialfetches); report(stdout, ngettext("fetchlimit %d reached; %d message left on server %s account %s\n", - "fetchlimit %d reached; %d messages left on server %s account %s\n", count - *fetches), - maxfetch, count - *fetches, ctl->server.truename, ctl->remotename); + "fetchlimit %d reached; %d messages left on server %s account %s\n", remcount), + maxfetch, remcount, ctl->server.truename, ctl->remotename); return(PS_MAXFETCH); } } /* for (num = 1; num <= count; num++) */ @@ -836,6 +838,7 @@ static int do_session( { static int *msgsizes; volatile int err, mailserver_socket = -1; /* pacifies -Wall */ + int tmperr; int deletions = 0, js; const char *msg; SIGHANDLERTYPE pipesave; @@ -1136,6 +1139,7 @@ static int do_session( #endif /* KERBEROS_V5 */ /* accept greeting message from mail server */ + stage = STAGE_PREAUTH; err = (ctl->server.base_protocol->parse_response)(mailserver_socket, buf); if (err != 0) goto cleanUp; @@ -1416,7 +1420,7 @@ is restored.")); count, &msgsizes, maxfetch, &fetches, &dispatches, &deletions); - if (err) + if (err != PS_SUCCESS && err != PS_MAXFETCH) goto cleanUp; if (!check_only && ctl->skipped @@ -1434,6 +1438,9 @@ is restored.")); if (err) goto cleanUp; } + /* Return now if we have reached the fetchlimit */ + if (maxfetch && maxfetch <= fetches) + goto no_error; } while /* * Only re-poll if we either had some actual forwards and @@ -1443,15 +1450,33 @@ is restored.")); (dispatches && ctl->server.base_protocol->retry && !ctl->keep && !ctl->errcount); } - /* no_error: */ - /* ordinary termination with no errors -- officially log out */ - err = (ctl->server.base_protocol->logout_cmd)(mailserver_socket, ctl); + /* XXX: From this point onwards, preserve err unless a new error has occurred */ + + no_error: + /* PS_SUCCESS, PS_MAXFETCH: ordinary termination with no errors -- officially log out */ + stage = STAGE_LOGOUT; + tmperr = (ctl->server.base_protocol->logout_cmd)(mailserver_socket, ctl); + if (tmperr != PS_SUCCESS) + err = tmperr; /* * Hmmmm...arguably this would be incorrect if we had fetches but * no dispatches (due to oversized messages, etc.) */ - if (err == 0) - err = (fetches > 0) ? PS_SUCCESS : PS_NOMAIL; + else if (err == PS_SUCCESS && fetches == 0) + err = PS_NOMAIL; + /* + * Close all SMTP delivery sockets. For optimum performance + * we'd like to hold them open til end of run, but (1) this + * loses if our poll interval is longer than the MTA's + * inactivity timeout, and (2) some MTAs (like smail) don't + * deliver after each message, but rather queue up mail and + * wait to actually deliver it until the input socket is + * closed. + * + * don't send QUIT for ODMR case because we're acting as a + * proxy between the SMTP server and client. + */ + smtp_close(ctl, ctl->server.protocol != P_ODMR); cleanupSockClose(mailserver_socket); goto closeUp; @@ -1465,6 +1490,15 @@ is restored.")); /* try to clean up all streams */ release_sink(ctl); + /* + * Sending SMTP QUIT on signal is theoretically nice, but led + * to a subtle bug. If fetchmail was terminated by signal + * while it was shipping message text, it would hang forever + * waiting for a command acknowledge. In theory we could + * enable the QUIT only outside of the message send. In + * practice, we don't care. All mailservers hang up on a + * dropped TCP/IP connection anyway. + */ smtp_close(ctl, 0); if (mailserver_socket != -1) { cleanupSockClose(mailserver_socket); @@ -1479,7 +1513,7 @@ is restored.")); } } - /* no report on PS_MAXFETCH or PS_UNDEFINED or PS_AUTHFAIL */ + /* no report on PS_AUTHFAIL */ msg = NULL; switch (err) { @@ -1508,7 +1542,7 @@ is restored.")); msg = GT_("DNS lookup"); break; case PS_UNDEFINED: - report(stderr, GT_("undefined error\n")); + msg = GT_("undefined"); break; } if (msg) { @@ -1526,9 +1560,9 @@ closeUp: xfree(msgsizes); /* execute wrapup command, if any */ - if (ctl->postconnect && (err = system(ctl->postconnect))) + if (ctl->postconnect && (tmperr = system(ctl->postconnect))) { - report(stderr, GT_("post-connection command failed with status %d\n"), err); + report(stderr, GT_("post-connection command failed with status %d\n"), tmperr); if (err == PS_SUCCESS) err = PS_SYNTAX; } diff --git a/fetchmail.c b/fetchmail.c index 1f468bb8..9ee0d627 100644 --- a/fetchmail.c +++ b/fetchmail.c @@ -1277,38 +1277,9 @@ static int load_params(int argc, char **argv, int optind) static RETSIGTYPE terminate_poll(int sig) /* to be executed at the end of a poll cycle */ { - /* - * Close all SMTP delivery sockets. For optimum performance - * we'd like to hold them open til end of run, but (1) this - * loses if our poll interval is longer than the MTA's inactivity - * timeout, and (2) some MTAs (like smail) don't deliver after - * each message, but rather queue up mail and wait to actually - * deliver it until the input socket is closed. - * - * Sending SMTP QUIT on signal is theoretically nice, but led to a - * subtle bug. If fetchmail was terminated by signal while it was - * shipping message text, it would hang forever waiting for a - * command acknowledge. In theory we could enable the QUIT - * only outside of the message send. In practice, we don't - * care. All mailservers hang up on a dropped TCP/IP connection - * anyway. - */ if (sig != 0) report(stdout, GT_("terminated with signal %d\n"), sig); - else - { - struct query *ctl; - - /* terminate all SMTP connections cleanly */ - for (ctl = querylist; ctl; ctl = ctl->next) - if (ctl->smtp_socket != -1) - { - /* don't send QUIT for ODMR case because we're acting - as a proxy between the SMTP server and client. */ - smtp_close(ctl, ctl->server.protocol != P_ODMR); - } - } #ifdef POP3_ENABLE /* -- cgit v1.2.3