aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric S. Raymond <esr@thyrsus.com>1997-01-22 22:48:24 +0000
committerEric S. Raymond <esr@thyrsus.com>1997-01-22 22:48:24 +0000
commit267d78cd2d5eedbe4fc5ef40931d73c8927e6d8b (patch)
treeb020c9065e9c0b2255f90ef4a69139a1eaa217c3
parenta0b445a903dd44b04ea114e1fb0ca48375017444 (diff)
downloadfetchmail-267d78cd2d5eedbe4fc5ef40931d73c8927e6d8b.tar.gz
fetchmail-267d78cd2d5eedbe4fc5ef40931d73c8927e6d8b.tar.bz2
fetchmail-267d78cd2d5eedbe4fc5ef40931d73c8927e6d8b.zip
ESMTP SIZE option support.
svn path=/trunk/; revision=804
-rw-r--r--NEWS6
-rw-r--r--driver.c85
-rw-r--r--fetchmail.h3
-rw-r--r--smtp.c61
-rw-r--r--smtp.h3
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