From 267d78cd2d5eedbe4fc5ef40931d73c8927e6d8b Mon Sep 17 00:00:00 2001 From: "Eric S. Raymond" Date: Wed, 22 Jan 1997 22:48:24 +0000 Subject: ESMTP SIZE option support. svn path=/trunk/; revision=804 --- NEWS | 6 +++++ driver.c | 85 ++++++++++++++++++++++++++++++++++++++++++++++--------------- fetchmail.h | 3 +-- smtp.c | 61 ++++++++++++++++++++++++++------------------ smtp.h | 3 +++ 5 files changed, 111 insertions(+), 47 deletions(-) diff --git a/NEWS b/NEWS index 769d933f..a6a78f8f 100644 --- a/NEWS +++ b/NEWS @@ -11,10 +11,16 @@ features -- Content-Transfer-Encoding header is 7BIT or 8BIT, it is appended to the MAIL FROM command as a BODY option. +* ESMTP SIZE option is supported when using IMAP2bis or IMAP4. This means + messages too long for the local ESMTP listener will be rejected *before* + they are downloaded. + bugs -- * Compilation fixes for non-Linux machines. +There are 202 people on the fetchmail-friends list. + ------------------------------------------------------------------------------ fetchmail-3.0 (Tue Jan 21 16:44:56 EST 1997) diff --git a/driver.c b/driver.c index 53e1b96f..b9b98cd7 100644 --- a/driver.c +++ b/driver.c @@ -395,7 +395,7 @@ char *realname; /* real name of host */ char *bufp, *headers, *fromhdr,*tohdr,*cchdr,*bcchdr,*received_for,*envto; char *fromptr, *toptr, *ctthdr; int n, oldlen, ch; - int inheaders, sizeticker; + int inheaders, sizeticker, delete_ok; FILE *sinkfp; RETSIGTYPE (*sigchld)(); #ifdef HAVE_GETHOSTBYNAME @@ -403,7 +403,7 @@ char *realname; /* real name of host */ #endif /* HAVE_GETHOSTBYNAME */ /* read the message content from the server */ - inheaders = 1; + inheaders = delete_ok = TRUE; headers = fromhdr = tohdr = cchdr = bcchdr = received_for = envto = ctthdr = NULL; sizeticker = 0; oldlen = 0; @@ -432,7 +432,7 @@ char *realname; /* real name of host */ len -= n; bufp = buf; if (buf[0] == '\r' && buf[1] == '\n') - inheaders = 0; + inheaders = FALSE; if (delimited && *bufp == '.') { if (bufp[1] == '\r' && bufp[2] == '\n') break; /* end of message */ @@ -597,6 +597,7 @@ char *realname; /* real name of host */ else { char *ap, *ctt, options[MSGBUFSIZE]; + int smtperr; /* build a connection to the SMTP listener */ if (!ctl->mda && ((sinkfp = smtp_open(ctl)) == NULL)) @@ -612,13 +613,14 @@ char *realname; /* real name of host */ * headers isn't semantically an address. But it has the * desired tokenizing effect. */ + options[0] = '\0'; 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'; + if ((ctl->server.esmtp_options & ESMTP_SIZE) && !delimited) + sprintf(options + strlen(options), " SIZE=%d", len); /* * Try to get the SMTP listener to take the header @@ -628,27 +630,67 @@ char *realname; /* real name of host */ * From address anyway. */ if (!fromhdr || !(ap = nxtaddr(fromhdr))) + ap = user; + if (SMTP_from(sinkfp, ap, options) != 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, options)!=SM_OK) - if (smtp_response == 571) + int smtperr = atoi(smtp_response); + + if (smtperr >= 400) + error(0, 0, "SMTP error: %s", smtp_response); + + /* + * There'a one problem with this flow of control; + * there's no way to avoid reading the whole message + * off the server, even if the MAIL FROM response + * tells us that it's just to be discarded. We could + * fix this under IMAP by reading headers first, then + * trying to issue the MAIL FROM, and *then* reading + * the body...but POP3 can't do this. + */ + + switch (smtperr) { + case 571: /* unsolicited email refused */ /* * SMTP listener explicitly refuses to deliver * mail coming from this address, probably due * to an anti-spam domain exclusion. Respect - * this. + * this. Don't try to ship the message, and + * don't prevent it from being deleted. */ sinkfp = (FILE *)NULL; goto skiptext; + + case 452: /* insufficient system storage */ + /* + * Temporary out-of-queue-space condition on the + * ESMTP server. Don't try to ship the message, + * and suppress deletion so it can be retried on + * a future retrieval cycle. + */ + delete_ok = FALSE; + sinkfp = (FILE *)NULL; + SMTP_rset(sockfp); /* required by RFC1870 */ + goto skiptext; + + case 552: /* message exceeds fixed maximum message size */ + /* + * Permanent no-go condition on the + * ESMTP server. Don't try to ship the message, + * and allow it to be deleted. + */ + sinkfp = (FILE *)NULL; + SMTP_rset(sockfp); /* required by RFC1870 */ + goto skiptext; + + default: /* retry with invoking user's address */ + if (SMTP_from(sinkfp, user, options) != SM_OK) + { + error(0,0,"SMTP error: %s", smtp_response); + return(PS_SMTP); /* should never happen */ + } } - else if (SMTP_from(sinkfp, user, options) != SM_OK) - return(PS_SMTP); /* should never happen */ + } /* now list the recipient addressees */ for (idp = xmit_names; idp; idp = idp->next) @@ -810,11 +852,11 @@ char *realname; /* real name of host */ if (SMTP_eom(sinkfp) != SM_OK) { error(0, 0, "SMTP listener refused delivery"); - return(PS_SMTP); + return(PS_TRANSIENT); } } - return(0); + return(delete_ok ? PS_SUCCESS : PS_TRANSIENT); } #ifdef KERBEROS_V4 @@ -1081,7 +1123,6 @@ const struct method *proto; /* protocol method table */ vtalarm(ctl->server.timeout); } - if (check_only) { if (new == -1 || ctl->fetchall) @@ -1123,6 +1164,7 @@ const struct method *proto; /* protocol method table */ int toolarge = msgsizes && (msgsizes[num-1] > ctl->limit); int fetch_it = ctl->fetchall || (!toolarge && (force_retrieval || !(protocol->is_old && (protocol->is_old)(sockfp,ctl,num)))); + int suppress_delete = FALSE; /* we may want to reject this message if it's old */ if (!fetch_it) @@ -1159,7 +1201,9 @@ const struct method *proto; /* protocol method table */ protocol->delimited, ctl, realname); - if (ok != 0) + if (ok == PS_TRANSIENT) + suppress_delete = TRUE; + else if (ok) goto cleanUp; vtalarm(ctl->server.timeout); @@ -1184,6 +1228,7 @@ const struct method *proto; /* protocol method table */ /* maybe we delete this message now? */ if (protocol->delete + && !suppress_delete && (fetch_it ? !ctl->keep : ctl->flush)) { deletions++; diff --git a/fetchmail.h b/fetchmail.h index d65c9c85..729b354e 100644 --- a/fetchmail.h +++ b/fetchmail.h @@ -37,6 +37,7 @@ #define PS_EXCLUDE 8 /* exclusion error */ #define PS_SMTP 9 /* SMTP error */ #define PS_UNDEFINED 10 /* something I hadn't thought of */ +#define PS_TRANSIENT 11 /* transient failure (internal use) */ /* output noise level */ #define O_SILENT 0 /* mute, max squelch, etc. */ @@ -172,8 +173,6 @@ extern int linelimit; /* limit # lines retrieved per site */ extern int versioninfo; /* emit only version info */ extern char *user; /* name of invoking user */ -extern int smtp_response; /* numeric value of SMTP response code */ - /* prototypes for globally callable functions */ #if defined(HAVE_STDARG_H) void error_init(int foreground); diff --git a/smtp.c b/smtp.c index b8f08f74..5cbfbcd2 100644 --- a/smtp.c +++ b/smtp.c @@ -25,11 +25,12 @@ struct opt static struct opt extensions[] = { - {"8BITMIME", ESMTP_8BITMIME}, + {"8BITMIME", ESMTP_8BITMIME}, + {"SIZE", ESMTP_SIZE}, {(char *)NULL, 0}, }; -int smtp_response; /* numeric value of SMTP response code */ +char smtp_response[MSGBUFSIZE]; int SMTP_helo(FILE *sockfp,char *host) /* send a "HELO" message to the SMTP listener */ @@ -47,7 +48,7 @@ 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; + char *ip; struct opt *hp; SockPrintf(sockfp,"EHLO %s\r\n", host); @@ -55,26 +56,25 @@ int SMTP_ehlo(FILE *sockfp, char *host, int *opt) error(0, 0, "SMTP> EHLO %s", host); *opt = 0; - while ((ip = SockGets(buf, sizeof(buf)-1, sockfp))) + while ((ip = SockGets(smtp_response, sizeof(smtp_response)-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 (smtp_response[strlen(smtp_response)-1] == '\n') + smtp_response[strlen(smtp_response)-1] = '\0'; + if (smtp_response[strlen(smtp_response)-1] == '\r') + smtp_response[strlen(smtp_response)-1] = '\r'; if (n < 4) return SM_ERROR; - buf[n] = '\0'; + smtp_response[n] = '\0'; if (outlevel == O_VERBOSE) - error(0, 0, "SMTP< %s", buf); + error(0, 0, "SMTP< %s", smtp_response); for (hp = extensions; hp->name; hp++) - if (!strncasecmp(hp->name, buf+4, strlen(hp->name))) + if (!strncasecmp(hp->name, smtp_response+4, strlen(hp->name))) *opt |= hp->value; - smtp_response = atoi(buf); - if ((buf[0] == '1' || buf[0] == '2' || buf[0] == '3') && buf[3] == ' ') + if ((smtp_response[0] == '1' || smtp_response[0] == '2' || smtp_response[0] == '3') && smtp_response[3] == ' ') return SM_OK; - else if (buf[3] != '-') + else if (smtp_response[3] != '-') return SM_ERROR; } return SM_UNRECOVERABLE; @@ -121,6 +121,18 @@ int SMTP_data(FILE *sockfp) return ok; } +int SMTP_rset(FILE *sockfp) +/* send a "RSET" message to the SMTP listener */ +{ + int ok; + + SockPrintf(sockfp,"RSET\r\n"); + if (outlevel == O_VERBOSE) + error(0, 0, "SMTP> RSET"); + ok = SMTP_ok(sockfp); + return ok; +} + int SMTP_quit(FILE *sockfp) /* send a "QUIT" message to the SMTP listener */ { @@ -148,25 +160,24 @@ int SMTP_eom(FILE *sockfp) int SMTP_ok(FILE *sockfp) /* returns status of SMTP connection */ { - char buf[SMTPBUFSIZE], *ip; + char *ip; - while ((ip = SockGets(buf, sizeof(buf)-1, sockfp))) + while ((ip = SockGets(smtp_response, sizeof(smtp_response)-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 (smtp_response[strlen(smtp_response)-1] == '\n') + smtp_response[strlen(smtp_response)-1] = '\0'; + if (smtp_response[strlen(smtp_response)-1] == '\r') + smtp_response[strlen(smtp_response)-1] = '\r'; if (n < 4) return SM_ERROR; - buf[n] = '\0'; + smtp_response[n] = '\0'; if (outlevel == O_VERBOSE) - error(0, 0, "SMTP< %s", buf); - smtp_response = atoi(buf); - if ((buf[0] == '1' || buf[0] == '2' || buf[0] == '3') && buf[3] == ' ') + error(0, 0, "SMTP< %s", smtp_response); + if ((smtp_response[0] == '1' || smtp_response[0] == '2' || smtp_response[0] == '3') && smtp_response[3] == ' ') return SM_OK; - else if (buf[3] != '-') + else if (smtp_response[3] != '-') return SM_ERROR; } return SM_UNRECOVERABLE; diff --git a/smtp.h b/smtp.h index ff3f7ac3..53b5c5c0 100644 --- a/smtp.h +++ b/smtp.h @@ -24,7 +24,10 @@ 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); +int SMTP_rset(FILE *sockfp); int SMTP_quit(FILE *sockfp); int SMTP_ok(FILE *sockfp); +extern char smtp_response[MSGBUFSIZE]; + #endif -- cgit v1.2.3