This commit was manufactured by cvs2svn to create tag 'FreeBSD-release/1.0'.
[unix-history] / usr.sbin / sendmail / src / collect.c
index a96df15..4398b85 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Copyright (c) 1983 Eric P. Allman
 /*
  * Copyright (c) 1983 Eric P. Allman
- * Copyright (c) 1988 Regents of the University of California.
- * All rights reserved.
+ * Copyright (c) 1988, 1993
+ *     The Regents of the University of California.  All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -33,7 +33,7 @@
  */
 
 #ifndef lint
  */
 
 #ifndef lint
-static char sccsid[] = "@(#)collect.c  5.9 (Berkeley) 6/1/90";
+static char sccsid[] = "@(#)collect.c  8.1 (Berkeley) 6/7/93";
 #endif /* not lint */
 
 # include <errno.h>
 #endif /* not lint */
 
 # include <errno.h>
@@ -47,8 +47,13 @@ static char sccsid[] = "@(#)collect.c        5.9 (Berkeley) 6/1/90";
 **     stripped off (after important information is extracted).
 **
 **     Parameters:
 **     stripped off (after important information is extracted).
 **
 **     Parameters:
-**             sayok -- if set, give an ARPANET style message
-**                     to say we are ready to collect input.
+**             smtpmode -- if set, we are running SMTP: give an RFC821
+**                     style message to say we are ready to collect
+**                     input, and never ignore a single dot to mean
+**                     end of message.
+**             requeueflag -- this message will be requeued later, so
+**                     don't do final processing on it.
+**             e -- the current envelope.
 **
 **     Returns:
 **             none.
 **
 **     Returns:
 **             none.
@@ -58,13 +63,15 @@ static char sccsid[] = "@(#)collect.c       5.9 (Berkeley) 6/1/90";
 **             The from person may be set.
 */
 
 **             The from person may be set.
 */
 
-collect(sayok)
-       bool sayok;
+collect(smtpmode, requeueflag, e)
+       bool smtpmode;
+       bool requeueflag;
+       register ENVELOPE *e;
 {
        register FILE *tf;
 {
        register FILE *tf;
-       char buf[MAXFIELD], buf2[MAXFIELD];
+       bool ignrdot = smtpmode ? FALSE : IgnrDot;
+       char buf[MAXLINE], buf2[MAXLINE];
        register char *workbuf, *freebuf;
        register char *workbuf, *freebuf;
-       register int workbuflen;
        extern char *hvalue();
        extern bool isheader(), flusheol();
 
        extern char *hvalue();
        extern bool isheader(), flusheol();
 
@@ -72,27 +79,27 @@ collect(sayok)
        **  Create the temp file name and create the file.
        */
 
        **  Create the temp file name and create the file.
        */
 
-       CurEnv->e_df = newstr(queuename(CurEnv, 'd'));
-       if ((tf = dfopen(CurEnv->e_df, "w")) == NULL)
+       e->e_df = newstr(queuename(e, 'd'));
+       if ((tf = dfopen(e->e_df, O_WRONLY|O_CREAT, FileMode)) == NULL)
        {
        {
-               syserr("Cannot create %s", CurEnv->e_df);
+               syserr("Cannot create %s", e->e_df);
                NoReturn = TRUE;
                finis();
        }
                NoReturn = TRUE;
                finis();
        }
-       (void) chmod(CurEnv->e_df, FileMode);
 
        /*
        **  Tell ARPANET to go ahead.
        */
 
 
        /*
        **  Tell ARPANET to go ahead.
        */
 
-       if (sayok)
-               message("354", "Enter mail, end with \".\" on a line by itself");
+       if (smtpmode)
+               message("354 Enter mail, end with \".\" on a line by itself");
 
        /*
        **  Try to read a UNIX-style From line
        */
 
 
        /*
        **  Try to read a UNIX-style From line
        */
 
-       if (sfgets(buf, MAXFIELD, InChannel) == NULL)
+       if (sfgets(buf, MAXLINE, InChannel, TimeOuts.to_datablock,
+                       "initial message read") == NULL)
                goto readerr;
        fixcrlf(buf, FALSE);
 # ifndef NOTUNIX
                goto readerr;
        fixcrlf(buf, FALSE);
 # ifndef NOTUNIX
@@ -100,12 +107,13 @@ collect(sayok)
        {
                if (!flusheol(buf, InChannel))
                        goto readerr;
        {
                if (!flusheol(buf, InChannel))
                        goto readerr;
-               eatfrom(buf);
-               if (sfgets(buf, MAXFIELD, InChannel) == NULL)
+               eatfrom(buf, e);
+               if (sfgets(buf, MAXLINE, InChannel, TimeOuts.to_datablock,
+                               "message header read") == NULL)
                        goto readerr;
                fixcrlf(buf, FALSE);
        }
                        goto readerr;
                fixcrlf(buf, FALSE);
        }
-# endif NOTUNIX
+# endif /* NOTUNIX */
 
        /*
        **  Copy InChannel to temp file & do message editing.
 
        /*
        **  Copy InChannel to temp file & do message editing.
@@ -118,6 +126,11 @@ collect(sayok)
        freebuf = buf2;         /* `freebuf' can be used for read-ahead */
        for (;;)
        {
        freebuf = buf2;         /* `freebuf' can be used for read-ahead */
        for (;;)
        {
+               char *curbuf;
+               int curbuffree;
+               register int curbuflen;
+               char *p;
+
                /* first, see if the header is over */
                if (!isheader(workbuf))
                {
                /* first, see if the header is over */
                if (!isheader(workbuf))
                {
@@ -132,12 +145,19 @@ collect(sayok)
                /* it's okay to toss '\n' now (flusheol() needed it) */
                fixcrlf(workbuf, TRUE);
 
                /* it's okay to toss '\n' now (flusheol() needed it) */
                fixcrlf(workbuf, TRUE);
 
-               workbuflen = strlen(workbuf);
+               curbuf = workbuf;
+               curbuflen = strlen(curbuf);
+               curbuffree = MAXLINE - curbuflen;
+               p = curbuf + curbuflen;
 
                /* get the rest of this field */
                for (;;)
                {
 
                /* get the rest of this field */
                for (;;)
                {
-                       if (sfgets(freebuf, MAXFIELD, InChannel) == NULL)
+                       int clen;
+
+                       if (sfgets(freebuf, MAXLINE, InChannel,
+                                       TimeOuts.to_datablock,
+                                       "message header read") == NULL)
                                goto readerr;
 
                        /* is this a continuation line? */
                                goto readerr;
 
                        /* is this a continuation line? */
@@ -147,25 +167,32 @@ collect(sayok)
                        if (!flusheol(freebuf, InChannel))
                                goto readerr;
 
                        if (!flusheol(freebuf, InChannel))
                                goto readerr;
 
-                       /* yes; append line to `workbuf' if there's room */
-                       if (workbuflen < MAXFIELD-3)
+                       fixcrlf(freebuf, TRUE);
+                       clen = strlen(freebuf) + 1;
+
+                       /* if insufficient room, dynamically allocate buffer */
+                       if (clen >= curbuffree)
                        {
                        {
-                               register char *p = workbuf + workbuflen;
-                               register char *q = freebuf;
-
-                               /* we have room for more of this field */
-                               fixcrlf(freebuf, TRUE);
-                               *p++ = '\n'; workbuflen++;
-                               while(*q != '\0' && workbuflen < MAXFIELD-1)
-                               {
-                                       *p++ = *q++;
-                                       workbuflen++;
-                               }
-                               *p = '\0';
+                               /* reallocate buffer */
+                               int nbuflen = ((p - curbuf) + clen) * 2;
+                               char *nbuf = xalloc(nbuflen);
+
+                               p = nbuf + curbuflen;
+                               curbuffree = nbuflen - curbuflen;
+                               bcopy(curbuf, nbuf, curbuflen);
+                               if (curbuf != buf && curbuf != buf2)
+                                       free(curbuf);
+                               curbuf = nbuf;
                        }
                        }
+                       *p++ = '\n';
+                       bcopy(freebuf, p, clen - 1);
+                       p += clen - 1;
+                       curbuffree -= clen;
+                       curbuflen += clen;
                }
                }
+               *p++ = '\0';
 
 
-               CurEnv->e_msgsize += workbuflen;
+               e->e_msgsize += curbuflen;
 
                /*
                **  The working buffer now becomes the free buffer, since
 
                /*
                **  The working buffer now becomes the free buffer, since
@@ -189,8 +216,15 @@ collect(sayok)
                **  Snarf header away.
                */
 
                **  Snarf header away.
                */
 
-               if (bitset(H_EOH, chompheader(freebuf, FALSE)))
+               if (bitset(H_EOH, chompheader(curbuf, FALSE, e)))
                        break;
                        break;
+
+               /*
+               **  If the buffer was dynamically allocated, free it.
+               */
+
+               if (curbuf != buf && curbuf != buf2)
+                       free(curbuf);
        }
 
        if (tTd(30, 1))
        }
 
        if (tTd(30, 1))
@@ -199,7 +233,8 @@ collect(sayok)
        if (*workbuf == '\0')
        {
                /* throw away a blank line */
        if (*workbuf == '\0')
        {
                /* throw away a blank line */
-               if (sfgets(buf, MAXFIELD, InChannel) == NULL)
+               if (sfgets(buf, MAXLINE, InChannel, TimeOuts.to_datablock,
+                               "message separator read") == NULL)
                        goto readerr;
        }
        else if (workbuf == buf2)       /* guarantee `buf' contains data */
                        goto readerr;
        }
        else if (workbuf == buf2)       /* guarantee `buf' contains data */
@@ -216,11 +251,11 @@ collect(sayok)
                fixcrlf(buf, TRUE);
 
                /* check for end-of-message */
                fixcrlf(buf, TRUE);
 
                /* check for end-of-message */
-               if (!IgnrDot && buf[0] == '.' && (buf[1] == '\n' || buf[1] == '\0'))
+               if (!ignrdot && buf[0] == '.' && (buf[1] == '\n' || buf[1] == '\0'))
                        break;
 
                /* check for transparent dot */
                        break;
 
                /* check for transparent dot */
-               if (OpMode == MD_SMTP && !IgnrDot && bp[0] == '.' && bp[1] == '.')
+               if (OpMode == MD_SMTP && bp[0] == '.' && bp[1] == '.')
                        bp++;
 
                /*
                        bp++;
 
                /*
@@ -228,34 +263,42 @@ collect(sayok)
                **  file, and insert a newline if missing.
                */
 
                **  file, and insert a newline if missing.
                */
 
-               CurEnv->e_msgsize += strlen(bp) + 1;
+               e->e_msgsize += strlen(bp) + 1;
                fputs(bp, tf);
                fputs("\n", tf);
                if (ferror(tf))
                fputs(bp, tf);
                fputs("\n", tf);
                if (ferror(tf))
-                       tferror(tf);
-       } while (sfgets(buf, MAXFIELD, InChannel) != NULL);
+                       tferror(tf, e);
+       } while (sfgets(buf, MAXLINE, InChannel, TimeOuts.to_datablock,
+                       "message body read") != NULL);
 
 readerr:
        if (fflush(tf) != 0)
 
 readerr:
        if (fflush(tf) != 0)
-               tferror(tf);
+               tferror(tf, e);
+       (void) fsync(fileno(tf));
        (void) fclose(tf);
 
        /* An EOF when running SMTP is an error */
        if ((feof(InChannel) || ferror(InChannel)) && OpMode == MD_SMTP)
        {
        (void) fclose(tf);
 
        /* An EOF when running SMTP is an error */
        if ((feof(InChannel) || ferror(InChannel)) && OpMode == MD_SMTP)
        {
-               int usrerr(), syserr();
+               char *host;
+
+               host = RealHostName;
+               if (host == NULL)
+                       host = "localhost";
+
 # ifdef LOG
 # ifdef LOG
-               if (RealHostName != NULL && LogLevel > 0)
+               if (LogLevel > 0 && feof(InChannel))
                        syslog(LOG_NOTICE,
                        syslog(LOG_NOTICE,
-                           "collect: unexpected close on connection from %s: %m\n",
-                           CurEnv->e_from.q_paddr, RealHostName);
+                           "collect: unexpected close on connection from %s, sender=%s: %m\n",
+                           host, e->e_from.q_paddr);
 # endif
 # endif
-               (feof(InChannel) ? usrerr: syserr)
-                       ("collect: unexpected close, from=%s", CurEnv->e_from.q_paddr);
+               (feof(InChannel) ? usrerr : syserr)
+                       ("451 collect: unexpected close on connection from %s, from=%s",
+                               host, e->e_from.q_paddr);
 
                /* don't return an error indication */
 
                /* don't return an error indication */
-               CurEnv->e_to = NULL;
-               CurEnv->e_flags &= ~EF_FATALERRS;
+               e->e_to = NULL;
+               e->e_flags &= ~EF_FATALERRS;
 
                /* and don't try to deliver the partial message either */
                finis();
 
                /* and don't try to deliver the partial message either */
                finis();
@@ -266,31 +309,42 @@ readerr:
        **      Examples are who is the from person & the date.
        */
 
        **      Examples are who is the from person & the date.
        */
 
-       eatheader(CurEnv);
+       eatheader(e, !requeueflag);
 
        /*
        **  Add an Apparently-To: line if we have no recipient lines.
        */
 
 
        /*
        **  Add an Apparently-To: line if we have no recipient lines.
        */
 
-       if (hvalue("to") == NULL && hvalue("cc") == NULL &&
-           hvalue("bcc") == NULL && hvalue("apparently-to") == NULL)
+       if (hvalue("to", e) == NULL && hvalue("cc", e) == NULL &&
+           hvalue("bcc", e) == NULL && hvalue("apparently-to", e) == NULL)
        {
                register ADDRESS *q;
 
                /* create an Apparently-To: field */
                /*    that or reject the message.... */
        {
                register ADDRESS *q;
 
                /* create an Apparently-To: field */
                /*    that or reject the message.... */
-               for (q = CurEnv->e_sendqueue; q != NULL; q = q->q_next)
+               for (q = e->e_sendqueue; q != NULL; q = q->q_next)
                {
                        if (q->q_alias != NULL)
                                continue;
                        if (tTd(30, 3))
                                printf("Adding Apparently-To: %s\n", q->q_paddr);
                {
                        if (q->q_alias != NULL)
                                continue;
                        if (tTd(30, 3))
                                printf("Adding Apparently-To: %s\n", q->q_paddr);
-                       addheader("apparently-to", q->q_paddr, CurEnv);
+                       addheader("Apparently-To", q->q_paddr, e);
                }
        }
 
                }
        }
 
-       if ((CurEnv->e_dfp = fopen(CurEnv->e_df, "r")) == NULL)
-               syserr("Cannot reopen %s", CurEnv->e_df);
+       /* check for message too large */
+       if (MaxMessageSize > 0 && e->e_msgsize > MaxMessageSize)
+       {
+               usrerr("552 Message exceeds maximum fixed size (%ld)",
+                       MaxMessageSize);
+       }
+
+       if ((e->e_dfp = fopen(e->e_df, "r")) == NULL)
+       {
+               /* we haven't acked receipt yet, so just chuck this */
+               syserr("Cannot reopen %s", e->e_df);
+               finis();
+       }
 }
 \f/*
 **  FLUSHEOL -- if not at EOL, throw away rest of input line.
 }
 \f/*
 **  FLUSHEOL -- if not at EOL, throw away rest of input line.
@@ -311,16 +365,22 @@ flusheol(buf, fp)
        char *buf;
        FILE *fp;
 {
        char *buf;
        FILE *fp;
 {
-       char junkbuf[MAXLINE], *sfgets();
        register char *p = buf;
        register char *p = buf;
+       bool printmsg = TRUE;
+       char junkbuf[MAXLINE];
 
 
-       while (index(p, '\n') == NULL) {
-               if (sfgets(junkbuf,MAXLINE,fp) == NULL)
-                       return(FALSE);
+       while (strchr(p, '\n') == NULL)
+       {
+               if (printmsg)
+                       usrerr("553 header line too long");
+               printmsg = FALSE;
+               if (sfgets(junkbuf, MAXLINE, fp, TimeOuts.to_datablock,
+                               "long line flush") == NULL)
+                       return (FALSE);
                p = junkbuf;
        }
 
                p = junkbuf;
        }
 
-       return(TRUE);
+       return (TRUE);
 }
 \f/*
 **  TFERROR -- signal error on writing the temporary file.
 }
 \f/*
 **  TFERROR -- signal error on writing the temporary file.
@@ -336,17 +396,18 @@ flusheol(buf, fp)
 **             Arranges for following output to go elsewhere.
 */
 
 **             Arranges for following output to go elsewhere.
 */
 
-tferror(tf)
+tferror(tf, e)
        FILE *tf;
        FILE *tf;
+       register ENVELOPE *e;
 {
        if (errno == ENOSPC)
        {
 {
        if (errno == ENOSPC)
        {
-               (void) freopen(CurEnv->e_df, "w", tf);
+               (void) freopen(e->e_df, "w", tf);
                fputs("\nMAIL DELETED BECAUSE OF LACK OF DISK SPACE\n\n", tf);
                usrerr("452 Out of disk space for temp file");
        }
        else
                fputs("\nMAIL DELETED BECAUSE OF LACK OF DISK SPACE\n\n", tf);
                usrerr("452 Out of disk space for temp file");
        }
        else
-               syserr("collect: Cannot write %s", CurEnv->e_df);
+               syserr("collect: Cannot write %s", e->e_df);
        (void) freopen("/dev/null", "w", tf);
 }
 \f/*
        (void) freopen("/dev/null", "w", tf);
 }
 \f/*
@@ -380,8 +441,9 @@ char        *MonthList[] =
        NULL
 };
 
        NULL
 };
 
-eatfrom(fm)
+eatfrom(fm, e)
        char *fm;
        char *fm;
+       register ENVELOPE *e;
 {
        register char *p;
        register char **dt;
 {
        register char *p;
        register char **dt;
@@ -398,7 +460,8 @@ eatfrom(fm)
                        p++;
                while (*p == ' ')
                        p++;
                        p++;
                while (*p == ' ')
                        p++;
-               if (!isupper(*p) || p[3] != ' ' || p[13] != ':' || p[16] != ':')
+               if (!(isascii(*p) && isupper(*p)) ||
+                   p[3] != ' ' || p[13] != ':' || p[16] != ':')
                        continue;
 
                /* we have a possible date */
                        continue;
 
                /* we have a possible date */
@@ -415,7 +478,7 @@ eatfrom(fm)
                        break;
        }
 
                        break;
        }
 
-       if (*p != NULL)
+       if (*p != '\0')
        {
                char *q;
                extern char *arpadate();
        {
                char *q;
                extern char *arpadate();
@@ -424,10 +487,9 @@ eatfrom(fm)
                q = xalloc(25);
                (void) strncpy(q, p, 25);
                q[24] = '\0';
                q = xalloc(25);
                (void) strncpy(q, p, 25);
                q[24] = '\0';
-               define('d', q, CurEnv);
                q = arpadate(q);
                q = arpadate(q);
-               define('a', newstr(q), CurEnv);
+               define('a', newstr(q), e);
        }
 }
 
        }
 }
 
-# endif NOTUNIX
+# endif /* NOTUNIX */