diff options
-rw-r--r-- | NEWS | 15 | ||||
-rw-r--r-- | README | 2 | ||||
-rw-r--r-- | driver.c | 46 | ||||
-rw-r--r-- | fetchmail.h | 1 | ||||
-rw-r--r-- | smtp.c | 60 | ||||
-rw-r--r-- | smtp.h | 7 |
6 files changed, 120 insertions, 11 deletions
@@ -1,6 +1,21 @@ Release Notes: ------------------------------------------------------------------------------ +fetchmail-3.1 () + +features -- + +* Forwarding is now done via ESMTP where possible. + +* ESMTP 8BITMIME option is supported; when 8BITMIME is supported and the + Content-Transfer-Encoding header is 7BIT or 8BIT, it is appended to the + MAIL FROM command as a BODY option. + +bugs -- + +* Compilation fixes for non-Linux machines. + +------------------------------------------------------------------------------ fetchmail-3.0 (Tue Jan 21 16:44:56 EST 1997) features -- @@ -69,6 +69,8 @@ pop-perl5-1.2, popc, popmail-1.6 and upop) are marked with **. * Strict conformance to relevant RFCs and good debugging options. You could use fetchmail to test and debug server implementatations. + * Message and header processing are 8-bit clean. + * Carefully written, comprehensive and up-to-date man page describing not only modes of operation but also (**) how to diagnose the most common kinds of problems and what to do about deficient servers @@ -352,7 +352,22 @@ static FILE *smtp_open(struct query *ctl) batchcount = 0; } - /* if no socket to this host is already set up, try to open one */ + /* if no socket to this host is already set up, try to open ESMTP */ + 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_ehlo(lead->smtp_sockfp, + ctl->server.names->id, + &lead->server.esmtp_options) != SM_OK) + { + fclose(lead->smtp_sockfp); + lead->smtp_sockfp = (FILE *)NULL; + } + } + + /* if opening for ESMTP failed, try SMTP */ if (lead->smtp_sockfp == (FILE *)NULL) { if ((lead->smtp_sockfp = SockOpen(lead->smtphost, SMTP_PORT)) == (FILE *)NULL) @@ -378,7 +393,7 @@ char *realname; /* real name of host */ { char buf [MSGBUFSIZE+1]; char *bufp, *headers, *fromhdr,*tohdr,*cchdr,*bcchdr,*received_for,*envto; - char *fromptr, *toptr; + char *fromptr, *toptr, *ctthdr; int n, oldlen, ch; int inheaders, sizeticker; FILE *sinkfp; @@ -389,7 +404,7 @@ char *realname; /* real name of host */ /* read the message content from the server */ inheaders = 1; - headers = fromhdr = tohdr = cchdr = bcchdr = received_for = envto = NULL; + headers = fromhdr = tohdr = cchdr = bcchdr = received_for = envto = ctthdr = NULL; sizeticker = 0; oldlen = 0; while (delimited || len > 0) @@ -469,6 +484,9 @@ char *realname; /* real name of host */ else if (!strncasecmp("Bcc:", bufp, 4)) bcchdr = bufp; + else if (!strncasecmp("Content-Transfer-Encoding:", bufp, 26)) + ctthdr = bufp; + #ifdef HAVE_RES_SEARCH else if (MULTIDROP(ctl) && !strncasecmp("Received:", bufp, 9)) received_for = parse_received(ctl, bufp); @@ -578,7 +596,7 @@ char *realname; /* real name of host */ } else { - char *ap; + char *ap, *ctt, options[MSGBUFSIZE]; /* build a connection to the SMTP listener */ if (!ctl->mda && ((sinkfp = smtp_open(ctl)) == NULL)) @@ -589,6 +607,20 @@ char *realname; /* real name of host */ } /* + * Compute ESMTP options. It's a kluge to use nxtaddr() + * here because the contents of the Content-Transfer-Encoding + * headers isn't semantically an address. But it has the + * desired tokenizing effect. + */ + if ((ctl->server.esmtp_options & ESMTP_8BITMIME) + && ctthdr + && (ctt = nxtaddr(ctthdr)) + && (!strcasecmp(ctt,"7BIT")||!strcasecmp(ctt,"8BIT"))) + sprintf(options, " BODY=%s", ctt); + else + options[0] = '\0'; + + /* * Try to get the SMTP listener to take the header * From address as MAIL FROM (this makes the logging * nicer). If it won't, fall back on the calling-user @@ -597,13 +629,13 @@ char *realname; /* real name of host */ */ if (!fromhdr || !(ap = nxtaddr(fromhdr))) { - if (SMTP_from(sinkfp, user) != SM_OK) + if (SMTP_from(sinkfp, user, options)!=SM_OK) { error(0, 0, "%s not accepted as From address?", user); return(PS_SMTP); /* should never happen */ } } - else if (SMTP_from(sinkfp, ap) != SM_OK) + else if (SMTP_from(sinkfp, ap, options)!=SM_OK) if (smtp_response == 571) { /* @@ -615,7 +647,7 @@ char *realname; /* real name of host */ sinkfp = (FILE *)NULL; goto skiptext; } - else if (SMTP_from(sinkfp, user) != SM_OK) + else if (SMTP_from(sinkfp, user, options) != SM_OK) return(PS_SMTP); /* should never happen */ /* now list the recipient addressees */ diff --git a/fetchmail.h b/fetchmail.h index c1913f1a..d65c9c85 100644 --- a/fetchmail.h +++ b/fetchmail.h @@ -82,6 +82,7 @@ struct hostdata /* shared among all user connections to given server */ char *canonical_name; /* DNS canonical name of server host */ #endif /* HAVE_GETHOSTBYNAME */ struct hostdata *lead_server; /* ptr to lead query for this server */ + int esmtp_options; }; struct query @@ -17,6 +17,18 @@ #include "socket.h" #include "smtp.h" +struct opt +{ + char *name; + int value; +}; + +static struct opt extensions[] = +{ + {"8BITMIME", ESMTP_8BITMIME}, + {(char *)NULL, 0}, +}; + int smtp_response; /* numeric value of SMTP response code */ int SMTP_helo(FILE *sockfp,char *host) @@ -31,14 +43,56 @@ int SMTP_helo(FILE *sockfp,char *host) return ok; } -int SMTP_from(FILE *sockfp, char *from) +int SMTP_ehlo(FILE *sockfp, char *host, int *opt) +/* send a "EHLO" message to the SMTP listener, return extension status bits */ +{ + int ok; + char buf[SMTPBUFSIZE], *ip; + struct opt *hp; + + SockPrintf(sockfp,"EHLO %s\r\n", host); + if (outlevel == O_VERBOSE) + error(0, 0, "SMTP> EHLO %s", host); + + *opt = 0; + while ((ip = SockGets(buf, sizeof(buf)-1, sockfp))) + { + int n = strlen(ip); + + if (buf[strlen(buf)-1] == '\n') + buf[strlen(buf)-1] = '\0'; + if (buf[strlen(buf)-1] == '\r') + buf[strlen(buf)-1] = '\r'; + if (n < 4) + return SM_ERROR; + buf[n] = '\0'; + if (outlevel == O_VERBOSE) + error(0, 0, "SMTP< %s", buf); + for (hp = extensions; hp->name; hp++) + if (!strncasecmp(hp->name, buf+4, strlen(hp->name))) + *opt |= hp->value; + smtp_response = atoi(buf); + if ((buf[0] == '1' || buf[0] == '2' || buf[0] == '3') && buf[3] == ' ') + return SM_OK; + else if (buf[3] != '-') + return SM_ERROR; + } + return SM_UNRECOVERABLE; +} + +int SMTP_from(FILE *sockfp, char *from, char *opts) /* send a "MAIL FROM:" message to the SMTP listener */ { int ok; + struct opt *hp; + char buf[MSGBUFSIZE]; - SockPrintf(sockfp,"MAIL FROM:<%s>\r\n", from); + sprintf(buf, "MAIL FROM:<%s>", from); + if (opts) + strcat(buf, opts); + SockPrintf(sockfp,"%s\r\n", buf); if (outlevel == O_VERBOSE) - error(0, 0, "SMTP> MAIL FROM:<%s>", from); + error(0, 0, "SMTP> %s", buf); ok = SMTP_ok(sockfp); return ok; } @@ -14,8 +14,13 @@ #define SM_ERROR 128 #define SM_UNRECOVERABLE 129 +/* ESMTP extension option masks (not all options are listed here) */ +#define ESMTP_8BITMIME 0x01 +#define ESMTP_SIZE 0x02 + int SMTP_helo(FILE *sockfp,char *host); -int SMTP_from(FILE *sockfp,char *from); +int SMTP_ehlo(FILE *sockfp,char *host,int *opt); +int SMTP_from(FILE *sockfp,char *from,char *opts); int SMTP_rcpt(FILE *sockfp,char *to); int SMTP_data(FILE *sockfp); int SMTP_eom(FILE *sockfp); |