aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric S. Raymond <esr@thyrsus.com>1998-01-30 05:38:21 +0000
committerEric S. Raymond <esr@thyrsus.com>1998-01-30 05:38:21 +0000
commite1c30f00b092f08e00c1f26ade947e53150935ee (patch)
treec0711db1d0726be3119689574f1a1b9649a0bcc8
parente702bc4457fe27fa096b5484c54d0733c9447126 (diff)
downloadfetchmail-e1c30f00b092f08e00c1f26ade947e53150935ee.tar.gz
fetchmail-e1c30f00b092f08e00c1f26ade947e53150935ee.tar.bz2
fetchmail-e1c30f00b092f08e00c1f26ade947e53150935ee.zip
Thomas Pitre's multidrop enhancements.
svn path=/trunk/; revision=1612
-rw-r--r--NEWS27
-rw-r--r--driver.c314
-rw-r--r--rfc822.c11
3 files changed, 242 insertions, 110 deletions
diff --git a/NEWS b/NEWS
index 1c3f54ea..4a4e5d7e 100644
--- a/NEWS
+++ b/NEWS
@@ -18,6 +18,33 @@
------------------------------------------------------------------------------
fetchmail-4.4.0 ()
* Corrected OTP support from Craig Metz.
+* Fixed a minor bug in the IMSP re-polling logic.
+* Thomas Pitre's extensive changes to multidrop:
+
+ - Seek for the true sender of a mail which is not necessarily in the
+ From: header. (see comments in the code for more explicit details).
+ This one is particularly important with list distributions...
+
+ - Respect the Resent-To/-Cc/-Bcc precedence over the To/Cc/Bcc headers
+ for recipient delivery. So avoid resending a message to a person who
+ just resent a mail to some other addresses.
+
+ - Fix a bug in find_server_names() wich caused recipient addresses to
+ figure twice in the recipient address list.
+
+ - Modified parse_received() to let full adress from the Received header to
+ pass through so local domains can be used (now has same policy as in
+ the find_server_names() function).
+
+ - Fixed memory leaks from readheaders().
+
+ - Made some strcmp() be strcasecmp() as it should be because it didn't
+ work correctly in some cases.
+
+ - Modified reply_hack() to meet the needs of above modifications.
+
+ Thomas says these changes have been tested for two weeks in a production
+ multidrop environment.
fetchmail-4.3.6 (Fri Jan 23 00:25:57 EST 1998)
* Improved RPM packaging with correct grouping and an icon.
diff --git a/driver.c b/driver.c
index 004f0f1c..2548b668 100644
--- a/driver.c
+++ b/driver.c
@@ -148,7 +148,7 @@ static int is_host_alias(const char *name, struct query *ctl)
* name doesn't match any is it time to call the bind library.
* If this happens odds are good we're looking at an MX name.
*/
- if (strcmp(lead_server->truename, name) == 0)
+ if (strcasecmp(lead_server->truename, name) == 0)
return(TRUE);
else if (str_in_list(&lead_server->akalist, name))
return(TRUE);
@@ -169,7 +169,7 @@ static int is_host_alias(const char *name, struct query *ctl)
*/
else if ((he = gethostbyname(name)) != (struct hostent *)NULL)
{
- if (strcmp(ctl->server.truename, he->h_name) == 0)
+ if (strcasecmp(ctl->server.truename, he->h_name) == 0)
goto match;
else
return(FALSE);
@@ -221,7 +221,7 @@ static int is_host_alias(const char *name, struct query *ctl)
else
{
for (mxp = mxrecords; mxp->name; mxp++)
- if (strcmp(ctl->server.truename, mxp->name) == 0)
+ if (strcasecmp(ctl->server.truename, mxp->name) == 0)
goto match;
return(FALSE);
match:;
@@ -278,59 +278,68 @@ struct idlist **xmit_names; /* list of recipient names parsed out */
{
char *cp;
- if ((cp = nxtaddr(hdr)) != (char *)NULL)
- do {
- char *atsign;
-
- if ((atsign = strchr(cp, '@')))
- {
- struct idlist *idp;
+ for (cp = nxtaddr(hdr);
+ cp != NULL;
+ cp = nxtaddr(NULL))
+ {
+ char *atsign;
- /*
- * Does a trailing segment of the hostname match something
- * on the localdomains list? If so, save the whole name
- * and keep going.
- */
- for (idp = ctl->server.localdomains; idp; idp = idp->next)
- {
- char *rhs;
+ if ((atsign = strchr(cp, '@'))) {
+ struct idlist *idp;
- rhs = atsign + (strlen(atsign) - strlen(idp->id));
- if ((rhs[-1] == '.' || rhs[-1] == '@')
- && strcasecmp(rhs, idp->id) == 0)
- {
- if (outlevel == O_VERBOSE)
- error(0, 0, "passed through %s matching %s",
- cp, idp->id);
- save_str(xmit_names, XMIT_ACCEPT, cp);
- accept_count++;
- continue;
- }
- }
+ /*
+ * Does a trailing segment of the hostname match something
+ * on the localdomains list? If so, save the whole name
+ * and keep going.
+ */
+ for (idp = ctl->server.localdomains; idp; idp = idp->next) {
+ char *rhs;
- /*
- * Check to see if the right-hand part is an alias
- * or MX equivalent of the mailserver. If it's
- * not, skip this name. If it is, we'll keep
- * going and try to find a mapping to a client name.
- */
- if (!is_host_alias(atsign+1, ctl))
+ rhs = atsign + (strlen(atsign) - strlen(idp->id));
+ if (rhs > atsign &&
+ (rhs[-1] == '.' || rhs[-1] == '@') &&
+ strcasecmp(rhs, idp->id) == 0)
{
- save_str(xmit_names, XMIT_REJECT, cp);
- reject_count++;
- continue;
+ if (outlevel == O_VERBOSE)
+ error(0, 0, "passed through %s matching %s",
+ cp, idp->id);
+ save_str(xmit_names, XMIT_ACCEPT, cp);
+ accept_count++;
+ break;
}
- atsign[0] = '\0';
}
+ /* if we matched a local domain, idp != NULL */
+ if (idp) continue;
- map_name(cp, ctl, xmit_names);
- } while
- ((cp = nxtaddr((char *)NULL)) != (char *)NULL);
+ /*
+ * Check to see if the right-hand part is an alias
+ * or MX equivalent of the mailserver. If it's
+ * not, skip this name. If it is, we'll keep
+ * going and try to find a mapping to a client name.
+ */
+ if (!is_host_alias(atsign+1, ctl))
+ {
+ save_str(xmit_names, XMIT_REJECT, cp);
+ reject_count++;
+ continue;
+ }
+ atsign[0] = '\0';
+ }
+
+ map_name(cp, ctl, xmit_names);
+ }
}
}
static char *parse_received(struct query *ctl, char *bufp)
-/* try to extract real addressee from the Received line */
+/* try to extract real address from the Received line */
+/* If a valid Received: line is found, we return the full address in
+ * a buffer wich can be parsed from nxtaddr(). This is to ansure that
+ * the local domain part of the address can be passed along in
+ * find_server_names() if it contains one.
+ * Note: We should return a dummy header containing the address
+ * which makes nxtaddr() behave correctly.
+ */
{
char *ok = (char *)NULL;
static char rbuf[HOSTLEN + USERNAMELEN + 4];
@@ -360,18 +369,20 @@ static char *parse_received(struct query *ctl, char *bufp)
* recipient name after a following "for". Otherwise
* punt.
*/
- if (!is_host_alias(rbuf, ctl))
- ok = (char *)NULL;
- else if ((ok = strstr(sp, "for ")) && isspace(ok[-1]))
+ if (is_host_alias(rbuf, ctl) &&
+ (ok = strstr(sp, "for ")) &&
+ isspace(ok[-1]))
{
tp = rbuf;
sp = ok + 4;
+ *tp++ = ':'; /* Here is the hack. This is to be friend */
+ *tp++ = ' '; /* with nxtaddr()... */
if (*sp == '<')
sp++;
while (*sp == '@') /* skip routes */
- while (*sp++ != ':')
+ while (*sp && *sp++ != ':')
continue;
- while (*sp && *sp != '>' && *sp != '@' && *sp != ';')
+ while (*sp && *sp != '>' && *sp != ';')
if (!isspace(*sp))
*tp++ = *sp++;
else
@@ -380,16 +391,24 @@ static char *parse_received(struct query *ctl, char *bufp)
ok = (char *)NULL;
break;
}
+ *tp++ = '\n';
*tp = '\0';
- }
+ if (strlen(rbuf) <= 3) /* apparently nothing has been found */
+ ok = NULL;
+ } else
+ ok = (char *)NULL;
}
if (!ok)
return(NULL);
else
{
- if (outlevel == O_VERBOSE)
- error(0, 0, "found Received address `%s'", rbuf);
+ if (outlevel == O_VERBOSE) {
+ char *lf = rbuf + strlen(rbuf)-1;
+ *lf = '\0';
+ error(0, 0, "found Received address `%s'", rbuf+2);
+ *lf = '\n';
+ }
return(rbuf);
}
}
@@ -562,25 +581,33 @@ int num; /* index of message */
{
int offset;
struct addrblk *next;
- } *addrchain = NULL, **chainptr = &addrchain;
- char buf[MSGBUFSIZE+1], return_path[MSGBUFSIZE+1];
- int from_offs, ctt_offs, env_offs, next_address;
- char *headers, *received_for, *destaddr, *rcv;
- int n, linelen, oldlen, ch, remaining, skipcount;
- char *cp;
+ };
+ struct addrblk *to_addrchain = NULL;
+ struct addrblk **to_chainptr = &to_addrchain;
+ struct addrblk *resent_to_addrchain = NULL;
+ struct addrblk **resent_to_chainptr = &resent_to_addrchain;
+
+ char buf[MSGBUFSIZE+1];
+ char return_path[HOSTLEN + USERNAMELEN + 4];
+ int from_offs, reply_to_offs, resent_from_offs;
+ int app_from_offs, sender_offs, resent_sender_offs;
+ int ctt_offs, env_offs;
+ char *headers, *received_for, *destaddr, *rcv, *cp;
+ int n, linelen, oldlen, ch, remaining, skipcount;
struct idlist *idp, *xmit_names;
flag good_addresses, bad_addresses, has_nuls;
flag no_local_matches = FALSE;
int olderrs;
- next_address = sizeticker = 0;
+ sizeticker = 0;
has_nuls = FALSE;
return_path[0] = '\0';
olderrs = ctl->errcount;
/* read message headers */
headers = received_for = NULL;
- from_offs = ctt_offs = env_offs = -1;
+ from_offs = reply_to_offs = resent_from_offs = app_from_offs =
+ sender_offs = resent_sender_offs = ctt_offs = env_offs = -1;
oldlen = 0;
msglen = 0;
skipcount = 0;
@@ -593,8 +620,11 @@ int num; /* index of message */
linelen = 0;
line[0] = '\0';
do {
- if ((n = SockRead(sock, buf, sizeof(buf)-1)) == -1)
+ if ((n = SockRead(sock, buf, sizeof(buf)-1)) == -1) {
+ free(line);
+ free(headers);
return(PS_SOCKET);
+ }
linelen += n;
msglen += n;
@@ -658,8 +688,11 @@ int num; /* index of message */
*/
if (protocol->port != 109)
#endif /* POP2_ENABLE */
- if (num == 1 && !strncasecmp(line, "X-IMAP:", 7))
+ if (num == 1 && !strncasecmp(line, "X-IMAP:", 7)) {
+ free(line);
+ free(headers);
return(PS_RETAINED);
+ }
/*
* This code prevents fetchmail from becoming an accessory after
@@ -713,6 +746,9 @@ int num; /* index of message */
}
}
+ if (ctl->rewrite)
+ line = reply_hack(line, ctl->server.truename);
+
/*
* OK, this is messy. If we're forwarding by SMTP, it's the
* SMTP-receiver's job (according to RFC821, page 22, section
@@ -729,16 +765,15 @@ int num; /* index of message */
* envelope sender from the Return-Path, the new Return-Path should be
* exactly the same as the original one.
*/
- if (!ctl->mda && !strncasecmp("Return-Path:", line, 12))
+ if (!strncasecmp("Return-Path:", line, 12))
{
strcpy(return_path, nxtaddr(line));
- free(line);
- continue;
+ if (!ctl->mda) {
+ free(line);
+ continue;
+ }
}
- if (ctl->rewrite)
- line = reply_hack(line, ctl->server.truename);
-
if (!headers)
{
oldlen = strlen(line);
@@ -753,20 +788,29 @@ int num; /* index of message */
newlen = oldlen + strlen(line);
headers = (char *) realloc(headers, newlen + 1);
- if (headers == NULL)
+ if (headers == NULL) {
+ free(line);
return(PS_IOERR);
+ }
strcpy(headers + oldlen, line);
free(line);
line = headers + oldlen;
oldlen = newlen;
}
- if (from_offs == -1 && !strncasecmp("From:", line, 5))
- from_offs = (line - headers);
- else if (from_offs == -1 && !strncasecmp("Resent-From:", line, 12))
- from_offs = (line - headers);
- else if (from_offs == -1 && !strncasecmp("Apparently-From:", line, 16))
+ if (!strncasecmp("From:", line, 5))
from_offs = (line - headers);
+ else if (!strncasecmp("Reply-To:", line, 9))
+ reply_to_offs = (line - headers);
+ else if (!strncasecmp("Resent-From:", line, 12))
+ resent_from_offs = (line - headers);
+ else if (!strncasecmp("Apparently-From:", line, 16))
+ app_from_offs = (line - headers);
+ else if (!strncasecmp("Sender:", line, 7))
+ sender_offs = (line - headers);
+ else if (!strncasecmp("Resent_Sender:", line, 14))
+ resent_sender_offs = (line - headers);
+
else if (!strncasecmp("Content-Transfer-Encoding:", line, 26))
ctt_offs = (line - headers);
else if (!strncasecmp("Message-Id:", buf, 11 ))
@@ -787,18 +831,29 @@ int num; /* index of message */
else if (!strncasecmp("To:", line, 3)
|| !strncasecmp("Cc:", line, 3)
- || !strncasecmp("Bcc:", line, 4))
+ || !strncasecmp("Bcc:", line, 4)
+ || !strncasecmp("Apparently-To:", line, 14))
{
- *chainptr = xmalloc(sizeof(struct addrblk));
- (*chainptr)->offset = (line - headers);
- chainptr = &(*chainptr)->next;
- *chainptr = NULL;
+ *to_chainptr = xmalloc(sizeof(struct addrblk));
+ (*to_chainptr)->offset = (line - headers);
+ to_chainptr = &(*to_chainptr)->next;
+ *to_chainptr = NULL;
+ }
+
+ else if (!strncasecmp("Resent-To:", line, 10)
+ || !strncasecmp("Resent-Cc:", line, 10)
+ || !strncasecmp("Resent-Bcc:", line, 11))
+ {
+ *resent_to_chainptr = xmalloc(sizeof(struct addrblk));
+ (*resent_to_chainptr)->offset = (line - headers);
+ resent_to_chainptr = &(*resent_to_chainptr)->next;
+ *resent_to_chainptr = NULL;
}
else if (ctl->server.envelope != STRING_DISABLED)
{
if (ctl->server.envelope
- && strcasecmp(ctl->server.envelope, "received"))
+ && strcasecmp(ctl->server.envelope, "Received"))
{
if (env_offs == -1 && !strncasecmp(ctl->server.envelope,
line,
@@ -844,6 +899,32 @@ int num; /* index of message */
* In fact we have to, as this will tell us where to forward to.
*/
+ /*
+ * If there is a Return-Path address on the message, this was
+ * almost certainly the MAIL FROM address given the originating
+ * sendmail. This is the best thing to use for logging the
+ * message origin (it sets up the right behavior for bounces and
+ * mailing lists). Otherwise, fall down to the next available
+ * envelope address wich is the most probable real sender
+ * respectively. *** The order is important! ***
+ * This is especially useful when receiving mailing list
+ * messages in multidrop mode. if a local address doesn't
+ * exist, the bounce message won't be returned blindly to the
+ * author or to the list itself but rather to the list manager
+ * (ex: specified by "Sender:") wich is less anoying. This is
+ * true for most mailing list packages.
+ */
+ if( !return_path[0] ){
+ char *ap = NULL;
+ if (resent_sender_offs >= 0 && (ap = nxtaddr(headers + resent_sender_offs)));
+ else if (sender_offs >= 0 && (ap = nxtaddr(headers + sender_offs)));
+ else if (resent_from_offs >= 0 && (ap = nxtaddr(headers + resent_from_offs)));
+ else if (from_offs >= 0 && (ap = nxtaddr(headers + from_offs)));
+ else if (reply_to_offs >= 0 && (ap = nxtaddr(headers + reply_to_offs)));
+ else if (app_from_offs >= 0 && (ap = nxtaddr(headers + app_from_offs)));
+ if (ap) strcpy( return_path, ap );
+ }
+
/* cons up a list of local recipients */
xmit_names = (struct idlist *)NULL;
bad_addresses = good_addresses = accept_count = reject_count = 0;
@@ -857,22 +938,36 @@ int num; /* index of message */
* We have the Received for addressee.
* It has to be a mailserver address, or we
* wouldn't have got here.
+ * We use find_server_names() to let local
+ * hostnames go through.
*/
- map_name(received_for, ctl, &xmit_names);
- else
- {
+ find_server_names(received_for, ctl, &xmit_names);
+ else {
/*
* We haven't extracted the envelope address.
- * So check all the header addresses.
+ * So check all the "Resent-To" header addresses if
+ * they exist. If and only if they don't, consider
+ * the "To" adresses.
*/
- while (addrchain)
- {
- register struct addrblk *nextptr;
-
- find_server_names(headers+addrchain->offset, ctl, &xmit_names);
- nextptr = addrchain->next;
- free(addrchain);
- addrchain = nextptr;
+ register struct addrblk *nextptr;
+ if (resent_to_addrchain) {
+ /* delete the "To" chain and substitute it
+ * with the "Resent-To" list
+ */
+ while (to_addrchain) {
+ nextptr = to_addrchain->next;
+ free(to_addrchain);
+ to_addrchain = nextptr;
+ }
+ to_addrchain = resent_to_addrchain;
+ resent_to_addrchain = NULL;
+ }
+ /* now look for remaining adresses */
+ while (to_addrchain) {
+ find_server_names(headers+to_addrchain->offset, ctl, &xmit_names);
+ nextptr = to_addrchain->next;
+ free(to_addrchain);
+ to_addrchain = nextptr;
}
}
if (!accept_count)
@@ -897,6 +992,7 @@ int num; /* index of message */
if (outlevel == O_VERBOSE)
error(0,0, "forwarding and deletion suppressed due to DNS errors");
free(headers);
+ free_str_list(&xmit_names);
return(PS_TRANSIENT);
}
else if (ctl->mda) /* we have a declared MDA */
@@ -961,7 +1057,7 @@ int num; /* index of message */
/* substitute From address for %F */
if ((cp = strstr(before, "%F")))
{
- char *from = nxtaddr(headers + from_offs);
+ char *from = return_path;
char *sp;
/* \177 had better be out-of-band for MDA commands */
@@ -1009,6 +1105,8 @@ int num; /* index of message */
if (!sinkfp)
{
error(0, 0, "MDA open failed");
+ free(headers);
+ free_str_list(&xmit_names);
return(PS_IOERR);
}
@@ -1023,6 +1121,7 @@ int num; /* index of message */
{
error(0, errno, "SMTP connect to %s failed",
ctl->smtphost ? ctl->smtphost : "localhost");
+ free(headers);
free_str_list(&xmit_names);
return(PS_SMTP);
}
@@ -1048,14 +1147,8 @@ int num; /* index of message */
sprintf(options + strlen(options), " SIZE=%ld", reallen);
/*
- * If there is a Return-Path address on the message, this was
- * almost certainly the MAIL FROM address given the originating
- * sendmail. This is the best thing to use for logging the
- * message origin (it sets up the right behavior for bounces and
- * mailing lists). Otherwise, take the From address.
- *
- * Try to get the SMTP listener to take the Return-Path or
- * From address as MAIL FROM . If it won't, fall back on the
+ * Try to get the SMTP listener to take the Return-Path
+ * address as MAIL FROM . If it won't, fall back on the
* calling-user ID. This won't affect replies, which use the
* header From address anyway.
*
@@ -1070,11 +1163,7 @@ int num; /* index of message */
* didn't pass canonicalized From/Return-Path lines, *and* the
* local SMTP listener insists on them.
*/
- ap = (char *)NULL;
- if (return_path[0])
- ap = return_path;
- else if (from_offs == -1 || !(ap = nxtaddr(headers + from_offs)))
- ap = user;
+ ap = (return_path[0]) ? return_path : user;
if (SMTP_from(ctl->smtp_socket, ap, options) != SM_OK)
{
int smtperr = atoi(smtp_response);
@@ -1100,6 +1189,7 @@ int num; /* index of message */
* don't prevent it from being deleted.
*/
free(headers);
+ free_str_list(&xmit_names);
return(PS_REFUSED);
case 452: /* insufficient system storage */
@@ -1111,6 +1201,7 @@ int num; /* index of message */
*/
SMTP_rset(ctl->smtp_socket); /* required by RFC1870 */
free(headers);
+ free_str_list(&xmit_names);
return(PS_TRANSIENT);
case 552: /* message exceeds fixed maximum message size */
@@ -1121,6 +1212,7 @@ int num; /* index of message */
*/
SMTP_rset(ctl->smtp_socket); /* required by RFC1870 */
free(headers);
+ free_str_list(&xmit_names);
return(PS_REFUSED);
default: /* retry with invoking user's address */
@@ -1128,6 +1220,7 @@ int num; /* index of message */
{
error(0, -1, "SMTP error: %s", smtp_response);
free(headers);
+ free_str_list(&xmit_names);
return(PS_SMTP); /* should never happen */
}
}
@@ -1177,6 +1270,7 @@ int num; /* index of message */
{
error(0, 0, "can't even send to calling user!");
free(headers);
+ free_str_list(&xmit_names);
return(PS_SMTP);
}
}
@@ -1274,6 +1368,8 @@ int num; /* index of message */
pclose(sinkfp);
signal(SIGCHLD, sigchld);
}
+ free(headers);
+ free_str_list(&xmit_names);
return(PS_IOERR);
}
else if (outlevel == O_VERBOSE)
@@ -1336,8 +1432,6 @@ int num; /* index of message */
stuffline(ctl, errmsg);
}
- free_str_list(&xmit_names);
-
/* issue the delimiter line */
cp = buf;
*cp++ = '\r';
@@ -1345,6 +1439,8 @@ int num; /* index of message */
*cp++ = '\0';
stuffline(ctl, buf);
+ free(headers);
+ free_str_list(&xmit_names);
return(PS_SUCCESS);
}
diff --git a/rfc822.c b/rfc822.c
index 92692745..9bb10b00 100644
--- a/rfc822.c
+++ b/rfc822.c
@@ -34,7 +34,16 @@ const char *host; /* server hostname */
&& strncasecmp("Reply-To: ", buf, 10)
&& strncasecmp("Return-Path: ", buf, 13)
&& strncasecmp("Cc: ", buf, 4)
- && strncasecmp("Bcc: ", buf, 5)) {
+ && strncasecmp("Bcc: ", buf, 5)
+ && strncasecmp("Resent-From: ", buf, 13)
+ && strncasecmp("Resent-To: ", buf, 11)
+ && strncasecmp("Resent-Cc: ", buf, 11)
+ && strncasecmp("Resent-Bcc: ", buf, 12)
+ && strncasecmp("Apparently-From:", buf, 16)
+ && strncasecmp("Apparently-To:", buf, 14)
+ && strncasecmp("Sender:", buf, 7)
+ && strncasecmp("Resent_Sender:", buf, 14)
+ ) {
return(buf);
}