diff options
-rw-r--r-- | NEWS | 2 | ||||
-rw-r--r-- | driver.c | 99 | ||||
-rw-r--r-- | fetchmail.c | 40 | ||||
-rw-r--r-- | fetchmail.h | 2 | ||||
-rw-r--r-- | fetchmail.man | 4 | ||||
-rw-r--r-- | options.c | 2 | ||||
-rw-r--r-- | rcfile_y.y | 11 |
7 files changed, 82 insertions, 78 deletions
@@ -5,6 +5,8 @@ fetchmail-3.7 () features -- +* You can now specify a hunt list of SMTP forwarding hosts. + * Treat unexpected EOF as a protocol error. bugs -- @@ -341,62 +341,75 @@ char *parse_received(struct query *ctl, char *bufp) static FILE *smtp_open(struct query *ctl) /* try to open a socket to the appropriate SMTP server for this query */ { - struct query *lead; - - lead = ctl->lead_smtp; /* go to the SMTP leader for this query */ + struct idlist *idp; /* maybe it's time to close the socket in order to force delivery */ - if (ctl->batchlimit && lead->smtp_sockfp && batchcount++==ctl->batchlimit) + if (ctl->batchlimit && ctl->smtp_sockfp && batchcount++ == ctl->batchlimit) { - fclose(lead->smtp_sockfp); - lead->smtp_sockfp = (FILE *)NULL; + fclose(ctl->smtp_sockfp); + ctl->smtp_sockfp = (FILE *)NULL; batchcount = 0; } - /* - * RFC 1123 requires that the domain name in HELO address is a - * "valid principal domain name" for the client host. We - * violate this with malice aforethought in order to make the - * Received headers and logging look right. - * - * In fact this code relies on the RFC1123 requirement that the - * SMTP listener must accept messages even if verification of the - * HELO name fails (RFC1123 section 5.2.5, paragraph 2). - */ - - /* if no socket to this host is already set up, try to open ESMTP */ - if (lead->smtp_sockfp == (FILE *)NULL) + /* run down the SMTP hunt list looking for a server that's up */ + for (idp = ctl->smtphunt; idp; idp = idp->next) { - if ((lead->smtp_sockfp = SockOpen(lead->smtphost, SMTP_PORT)) == (FILE *)NULL) - return((FILE *)NULL); - else if (SMTP_ok(lead->smtp_sockfp) != SM_OK - || SMTP_ehlo(lead->smtp_sockfp, - ctl->server.names->id, - &lead->server.esmtp_options) != SM_OK) + + /* + * RFC 1123 requires that the domain name in HELO address is a + * "valid principal domain name" for the client host. We + * violate this with malice aforethought in order to make the + * Received headers and logging look right. + * + * In fact this code relies on the RFC1123 requirement that the + * SMTP listener must accept messages even if verification of the + * HELO name fails (RFC1123 section 5.2.5, paragraph 2). + */ + + /* if no socket to this host is already set up, try to open ESMTP */ + if (ctl->smtp_sockfp == (FILE *)NULL) { - /* - * RFC 1869 warns that some listeners hang up on a failed EHLO, - * so it's safest not to assume the socket will still be good. - */ - fclose(lead->smtp_sockfp); - lead->smtp_sockfp = (FILE *)NULL; + if ((ctl->smtp_sockfp = SockOpen(idp->id,SMTP_PORT))==(FILE *)NULL) + return((FILE *)NULL); + else if (SMTP_ok(ctl->smtp_sockfp) != SM_OK + || SMTP_ehlo(ctl->smtp_sockfp, + ctl->server.names->id, + &ctl->server.esmtp_options) != SM_OK) + { + /* + * RFC 1869 warns that some listeners hang up on a failed EHLO, + * so it's safest not to assume the socket will still be good. + */ + fclose(ctl->smtp_sockfp); + ctl->smtp_sockfp = (FILE *)NULL; + } + else + { + ctl->smtphost = idp->id; + break; + } } - } - /* if opening for ESMTP failed, try SMTP */ - if (lead->smtp_sockfp == (FILE *)NULL) - { - if ((lead->smtp_sockfp = SockOpen(lead->smtphost, SMTP_PORT)) == (FILE *)NULL) - return((FILE *)NULL); - else if (SMTP_ok(lead->smtp_sockfp) != SM_OK - || SMTP_helo(lead->smtp_sockfp, ctl->server.names->id) != SM_OK) + /* if opening for ESMTP failed, try SMTP */ + if (ctl->smtp_sockfp == (FILE *)NULL) { - fclose(lead->smtp_sockfp); - lead->smtp_sockfp = (FILE *)NULL; + if ((ctl->smtp_sockfp = SockOpen(idp->id,SMTP_PORT))==(FILE *)NULL) + return((FILE *)NULL); + else if (SMTP_ok(ctl->smtp_sockfp) != SM_OK + || SMTP_helo(ctl->smtp_sockfp, ctl->server.names->id) != SM_OK) + { + fclose(ctl->smtp_sockfp); + ctl->smtp_sockfp = (FILE *)NULL; + } + else + { + ctl->smtphost = idp->id; + break; + } } } - return(lead->smtp_sockfp); + return(ctl->smtp_sockfp); } static int gen_readmsg(sockfp, len, delimited, ctl, realname) @@ -672,7 +685,7 @@ char *realname; /* real name of host */ if (!ctl->mda && ((sinkfp = smtp_open(ctl)) == NULL)) { free_str_list(&xmit_names); - error(0, 0, "SMTP connect failed"); + error(0, 0, "SMTP connect to %s failed", ctl->smtphost); if (return_path) free(return_path); return(PS_SMTP); diff --git a/fetchmail.c b/fetchmail.c index a351e84e..bd31e0a0 100644 --- a/fetchmail.c +++ b/fetchmail.c @@ -526,7 +526,7 @@ static int load_params(int argc, char **argv, int optind) def_opts.server.protocol = P_AUTO; def_opts.server.timeout = CLIENT_TIMEOUT; def_opts.remotename = user; - def_opts.smtphost = fetchmailhost; + save_str(&def_opts.smtphunt, -1, fetchmailhost); /* this builds the host list */ if (prc_parse_file(rcfile) != 0) @@ -608,32 +608,7 @@ static int load_params(int argc, char **argv, int optind) } #endif /* !HAVE_GETHOSTBYNAME || !HAVE_RES_SEARCH */ - /* - * Assign SMTP leaders. We want to allow all query blocks - * sharing the same server/SMTP-host pair to use the same - * SMTP connection. To accomplish this, we initialize - * each query block's leader field to point to the first - * block in the list with a matching server/SMTP-host pair. - * - * In the typical case, there will be only one SMTP host (the - * client machine) and thus just one SMTP leader (and one listener - * process) through the entire poll cycle. - */ - if (!ctl->mda) - { - ctl->smtp_sockfp = (FILE *)NULL; - for (mp = querylist; mp && mp != ctl; mp = mp->next) - if (!strcmp(mp->server.names->id, ctl->server.names->id) - && !strcmp(mp->smtphost, ctl->smtphost)) - { - ctl->lead_smtp = mp->lead_smtp; - goto no_new_leader; - } - ctl->lead_smtp = ctl; - no_new_leader:; - } - - /* similarly, compute server leaders for queries */ + /* compute server leaders for queries */ for (mp = querylist; mp && mp != ctl; mp = mp->next) if (strcmp(mp->server.names->id, ctl->server.names->id) == 0) { @@ -713,7 +688,7 @@ void termhook(int sig) else /* terminate all SMTP connections cleanly */ for (ctl = querylist; ctl; ctl = ctl->next) - if (ctl->lead_smtp == ctl && ctl->smtp_sockfp != (FILE *)NULL) + if (ctl->smtp_sockfp != (FILE *)NULL) SMTP_quit(ctl->smtp_sockfp); if (!check_only) @@ -877,7 +852,14 @@ void dump_params (struct query *ctl) if (ctl->mda) printf(" Messages will be delivered with '%s.'\n", visbuf(ctl->mda)); else - printf(" Messages will be SMTP-forwarded to '%s'.\n", visbuf(ctl->smtphost)); + { + struct idlist *idp; + + printf(" Messages will be SMTP-forwarded to:"); + for (idp = ctl->smtphunt; idp; idp = idp->next) + printf(" %s", idp->id); + printf("\n"); + } if (ctl->preconnect) printf(" Server connection will be preinitialized with '%s.'\n", visbuf(ctl->preconnect)); else if (outlevel == O_VERBOSE) diff --git a/fetchmail.h b/fetchmail.h index eed7b1ea..063b2a16 100644 --- a/fetchmail.h +++ b/fetchmail.h @@ -102,6 +102,7 @@ struct query char *remotename; char *password; char *mailbox; + struct idlist *smtphunt; char *smtphost; char *mda; char *preconnect; @@ -123,7 +124,6 @@ struct query int active; int errcount; /* count transient errors in last pass */ struct query *next; /* next query control block in chain */ - struct query *lead_smtp; /* pointer to this query's SMTP leader */ FILE *smtp_sockfp; /* socket descriptor for SMTP connection */ unsigned int uid; /* UID of user to deliver to */ char digest [DIGESTLEN]; /* md5 digest buffer */ diff --git a/fetchmail.man b/fetchmail.man index fcd5c350..2546a800 100644 --- a/fetchmail.man +++ b/fetchmail.man @@ -166,8 +166,10 @@ under POP3 or ETRN. .SS Delivery Control Options .TP .B \-S host, --smtphost host -Specify a host to forward mail to (other than localhost). +Specify a hunt list of hosts to forward mail to. In ETRN mode, set the host that the mailserver is asked to ship mail to. +Hosts are tried in list order; the first one that is up becomes the +forwarding or ETRN target for the current run. .TP .B \-m, \--mda You can force mail to be passed to an MDA directly (rather than @@ -247,7 +247,7 @@ struct query *ctl; /* option record to be initialized */ break; case 'S': case LA_SMTPHOST: - ctl->smtphost = xstrdup(optarg); + save_str(&ctl->smtphunt, -1, optarg); ocount++; break; case 'b': @@ -176,6 +176,10 @@ mapping : STRING {save_str_pair(¤t.localnames, $1, $3);} ; +smtphunt : STRING {save_str(¤t.smtphunt, -1, $1);} + | smtphunt STRING {save_str(¤t.smtphunt, -1, $2);} + ; + user_option : TO localnames HERE | TO localnames | IS localnames HERE @@ -184,7 +188,7 @@ user_option : TO localnames HERE | IS STRING THERE {current.remotename = xstrdup($2);} | PASSWORD STRING {current.password = xstrdup($2);} | FOLDER STRING {current.mailbox = xstrdup($2);} - | SMTPHOST STRING {current.smtphost = xstrdup($2);} + | SMTPHOST smtphunt | MDA STRING {current.mda = xstrdup($2);} | PRECONNECT STRING {current.preconnect = xstrdup($2);} @@ -350,7 +354,8 @@ static void record_current(void) FLAG_FORCE(remotename); FLAG_FORCE(password); FLAG_FORCE(mailbox); - FLAG_FORCE(smtphost); + if (cmd_opts.smtphunt) + save_str(¤t.smtphunt, -1, cmd_opts.smtphunt->id); FLAG_FORCE(mda); FLAG_FORCE(preconnect); @@ -373,6 +378,7 @@ void optmerge(struct query *h2, struct query *h1) { append_str_list(&h2->server.localdomains, &h1->server.localdomains); append_str_list(&h2->localnames, &h1->localnames); + append_str_list(&h2->smtphunt, &h1->smtphunt); #define FLAG_MERGE(fld) if (!h2->fld) h2->fld = h1->fld FLAG_MERGE(server.protocol); @@ -392,7 +398,6 @@ void optmerge(struct query *h2, struct query *h1) FLAG_MERGE(remotename); FLAG_MERGE(password); FLAG_MERGE(mailbox); - FLAG_MERGE(smtphost); FLAG_MERGE(mda); FLAG_MERGE(preconnect); |