first cut at full 8-bit data capability
authorEric Allman <eric@ucbvax.Berkeley.EDU>
Mon, 8 Aug 1994 01:02:37 +0000 (17:02 -0800)
committerEric Allman <eric@ucbvax.Berkeley.EDU>
Mon, 8 Aug 1994 01:02:37 +0000 (17:02 -0800)
SCCS-vsn: usr.sbin/sendmail/src/collect.c 8.19
SCCS-vsn: usr.sbin/sendmail/src/util.c 8.43
SCCS-vsn: usr.sbin/sendmail/src/deliver.c 8.90

usr/src/usr.sbin/sendmail/src/collect.c
usr/src/usr.sbin/sendmail/src/deliver.c
usr/src/usr.sbin/sendmail/src/util.c

index 397760e..c22b5b9 100644 (file)
@@ -7,7 +7,7 @@
  */
 
 #ifndef lint
  */
 
 #ifndef lint
-static char sccsid[] = "@(#)collect.c  8.18 (Berkeley) %G%";
+static char sccsid[] = "@(#)collect.c  8.19 (Berkeley) %G%";
 #endif /* not lint */
 
 # include <errno.h>
 #endif /* not lint */
 
 # include <errno.h>
@@ -39,18 +39,43 @@ static char sccsid[] = "@(#)collect.c       8.18 (Berkeley) %G%";
 char   *CollectErrorMessage;
 bool   CollectErrno;
 
 char   *CollectErrorMessage;
 bool   CollectErrno;
 
+static jmp_buf CtxCollectTimeout;
+static int     collecttimeout();
+static bool    CollectProgress;
+static EVENT   *CollectTimeout;
+
+/* values for input state machine */
+#define IS_NORM                0       /* middle of line */
+#define IS_BOL         1       /* beginning of line */
+#define IS_DOT         2       /* read a dot at beginning of line */
+#define IS_DOTCR       3       /* read ".\r" at beginning of line */
+#define IS_CR          4       /* read a carriage return */
+
+/* values for message state machine */
+#define MS_UFROM       0       /* reading Unix from line */
+#define MS_HEADER      1       /* reading message header */
+#define MS_BODY                2       /* reading message body */
+
+
 maketemp(from)
        char *from;
 {
        register FILE *tf;
        bool ignrdot = smtpmode ? FALSE : IgnrDot;
        time_t dbto = smtpmode ? TimeOuts.to_datablock : 0;
 maketemp(from)
        char *from;
 {
        register FILE *tf;
        bool ignrdot = smtpmode ? FALSE : IgnrDot;
        time_t dbto = smtpmode ? TimeOuts.to_datablock : 0;
-       register char *workbuf, *freebuf;
+       register char *bp;
+       register int c;
        bool inputerr = FALSE;
        bool headeronly = FALSE;
        bool inputerr = FALSE;
        bool headeronly = FALSE;
-       char buf[MAXLINE], buf2[MAXLINE];
+       char *buf;
+       int buflen;
+       int istate;
+       int mstate;
+       char *pbp;
+       char peekbuf[8];
+       char bufbuf[MAXLINE];
        extern char *hvalue();
        extern char *hvalue();
-       extern bool isheader(), flusheol();
+       extern bool isheader();
        extern char *index();
 
        CollectErrorMessage = NULL;
        extern char *index();
 
        CollectErrorMessage = NULL;
@@ -84,194 +109,246 @@ maketemp(from)
        if (smtpmode)
                message("354 Enter mail, end with \".\" on a line by itself");
 
        if (smtpmode)
                message("354 Enter mail, end with \".\" on a line by itself");
 
-       /* set global timer to monitor progress */
-       sfgetset(dbto);
-
        /*
        /*
-       **  Try to read a UNIX-style From line
+       **  Read the message.
+       **
+       **      This is done using two interleaved state machines.
+       **      The input state machine is looking for things like
+       **      hidden dots; the message state machine is handling
+       **      the larger picture (e.g., header versus body).
        */
 
        */
 
-       if (sfgets(buf, MAXLINE, fp, dbto, "initial message read") == NULL)
-               goto readerr;
-       fixcrlf(buf, FALSE);
-# ifndef NOTUNIX
-       if (!headeronly && !SaveFrom && strncmp(buf, "From ", 5) == 0)
-       {
-               if (!flusheol(buf, fp, dbto))
-                       goto readerr;
-               eatfrom(buf, e);
-               if (sfgets(buf, MAXLINE, fp, dbto,
-                               "message header read") == NULL)
-                       goto readerr;
-               fixcrlf(buf, FALSE);
-       }
-# endif /* NOTUNIX */
+       buf = bp = bufbuf;
+       buflen = sizeof bufbuf;
+       pbp = peekbuf;
+       istate = IS_BOL;
+       mstate = SaveFrom ? MS_HEADER : MS_UFROM;
+       CollectProgress = FALSE;
 
 
-       /*
-       **  Copy fp to temp file & do message editing.
-       **      To keep certain mailers from getting confused,
-       **      and to keep the output clean, lines that look
-       **      like UNIX "From" lines are deleted in the header.
-       */
+       /* if transmitting binary, don't map NL to EOL */
+       if (e->e_bodytype != NULL && strcasecmp(e->e_bodytype, "8BITMIME") == 0)
+               e->e_flags |= EF_NL_NOT_EOL;
 
 
-       workbuf = buf;          /* `workbuf' contains a header field */
-       freebuf = buf2;         /* `freebuf' can be used for read-ahead */
-       for (;;)
+       if (dbto != 0)
        {
        {
-               char *curbuf;
-               int curbuffree;
-               register int curbuflen;
-               char *p;
-
-               /* first, see if the header is over */
-               if (!isheader(workbuf))
+               /* handle possible input timeout */
+               if (setjmp(CtxCollectTimeout) != 0)
                {
                {
-                       fixcrlf(workbuf, TRUE);
-                       break;
-               }
-
-               /* if the line is too long, throw the rest away */
-               if (!flusheol(workbuf, fp, dbto))
+#ifdef LOG
+                       syslog(LOG_NOTICE,
+                           "timeout waiting for input from %s during message collect",
+                           CurHostName ? CurHostName : "<local machine>");
+#endif
+                       errno = 0;
+                       usrerr("451 timeout waiting for input during message collect");
                        goto readerr;
                        goto readerr;
+               }
+               CollectTimeout = setevent(dbto, collecttimeout, dbto);
+       }
 
 
-               /* it's okay to toss '\n' now (flusheol() needed it) */
-               fixcrlf(workbuf, TRUE);
-
-               curbuf = workbuf;
-               curbuflen = strlen(curbuf);
-               curbuffree = MAXLINE - curbuflen;
-               p = curbuf + curbuflen;
-
-               /* get the rest of this field */
+       for (;;)
+       {
+               if (tTd(30, 35))
+                       printf("top, istate=%d, mstate=%d\n", istate, mstate);
                for (;;)
                {
                for (;;)
                {
-                       int clen;
-
-                       if (sfgets(freebuf, MAXLINE, fp, dbto,
-                                       "message header read") == NULL)
+                       if (pbp > peekbuf)
+                               c = *--pbp;
+                       else
                        {
                        {
-                               freebuf[0] = '\0';
-                               break;
+                               while (!feof(InChannel) && !ferror(InChannel))
+                               {
+                                       errno = 0;
+                                       c = fgetc(InChannel);
+                                       if (errno != EINTR)
+                                               break;
+                                       clearerr(InChannel);
+                               }
+                               CollectProgress = TRUE;
+                               if (TrafficLogFile != NULL)
+                               {
+                                       if (istate == IS_BOL)
+                                               fprintf(TrafficLogFile, "%05d <<< ",
+                                                       getpid());
+                                       if (c == EOF)
+                                               fprintf(TrafficLogFile, "[EOF]\n");
+                                       else
+                                               fputc(c, TrafficLogFile);
+                               }
+                               if (c == EOF)
+                                       goto readerr;
+                               if (SevenBitInput)
+                                       c &= 0x7f;
+                               else
+                                       HasEightBits |= bitset(0x80, c);
+                               e->e_msgsize++;
                        }
                        }
+                       if (tTd(30, 94))
+                               printf("istate=%d, c=%c (0x%x)\n",
+                                       istate, c, c);
+                       switch (istate)
+                       {
+                         case IS_BOL:
+                               if (c == '.')
+                               {
+                                       istate = IS_DOT;
+                                       continue;
+                               }
+                               break;
 
 
-                       /* is this a continuation line? */
-                       if (*freebuf != ' ' && *freebuf != '\t')
+                         case IS_DOT:
+                               if (c == '\n' && !ignrdot &&
+                                   !bitset(EF_NL_NOT_EOL, e->e_flags))
+                                       goto readerr;
+                               else if (c == '\r' &&
+                                        !bitset(EF_CRLF_NOT_EOL, e->e_flags))
+                               {
+                                       istate = IS_DOTCR;
+                                       continue;
+                               }
+                               else if (c != '.' ||
+                                        (OpMode != MD_SMTP &&
+                                         OpMode != MD_DAEMON &&
+                                         OpMode != MD_ARPAFTP))
+                               {
+                                       *pbp++ = c;
+                                       c = '.';
+                               }
                                break;
 
                                break;
 
-                       if (!flusheol(freebuf, fp, dbto))
-                               goto readerr;
+                         case IS_DOTCR:
+                               if (c == '\n')
+                                       goto readerr;
+                               else
+                               {
+                                       /* push back the ".\rx" */
+                                       *pbp++ = c;
+                                       *pbp++ = '\r';
+                                       c = '.';
+                               }
+                               break;
 
 
-                       fixcrlf(freebuf, TRUE);
-                       clen = strlen(freebuf) + 1;
+                         case IS_CR:
+                               if (c != '\n')
+                               {
+                                       ungetc(c, InChannel);
+                                       c = '\r';
+                               }
+                               else if (!bitset(EF_CRLF_NOT_EOL, e->e_flags))
+                                       istate = IS_BOL;
+                               break;
+                       }
 
 
-                       /* if insufficient room, dynamically allocate buffer */
-                       if (clen >= curbuffree)
+                       if (c == '\r')
                        {
                        {
-                               /* 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;
+                               istate = IS_CR;
+                               continue;
                        }
                        }
-                       *p++ = '\n';
-                       bcopy(freebuf, p, clen - 1);
-                       p += clen - 1;
-                       curbuffree -= clen;
-                       curbuflen += clen;
-               }
-               *p++ = '\0';
-
-               e->e_msgsize += curbuflen;
-
-               /*
-               **  The working buffer now becomes the free buffer, since
-               **  the free buffer contains a new header field.
-               **
-               **  This is premature, since we still havent called
-               **  chompheader() to process the field we just created
-               **  (so the call to chompheader() will use `freebuf').
-               **  This convolution is necessary so that if we break out
-               **  of the loop due to H_EOH, `workbuf' will always be
-               **  the next unprocessed buffer.
-               */
+                       else if (c == '\n' && !bitset(EF_NL_NOT_EOL, e->e_flags))
+                               istate = IS_BOL;
+                       else
+                               istate = IS_NORM;
 
 
-               {
-                       register char *tmp = workbuf;
-                       workbuf = freebuf;
-                       freebuf = tmp;
-               }
-
-               /*
-               **  Snarf header away.
-               */
-
-               if (bitset(H_EOH, chompheader(curbuf, FALSE, e)))
-                       break;
-
-               /*
-               **  If the buffer was dynamically allocated, free it.
-               */
-
-               if (curbuf != buf && curbuf != buf2)
-                       free(curbuf);
-       }
-
-       if (tTd(30, 1))
-               printf("EOH\n");
-
-       if (headeronly)
-       {
-               if (*workbuf != '\0')
-                       syserr("collect: lost first line of message");
-               goto readerr;
-       }
+                       if (mstate == MS_BODY)
+                       {
+                               /* just put the character out */
+                               fputc(c, tf);
+                               continue;
+                       }
 
 
-       if (*workbuf == '\0')
-       {
-               /* throw away a blank line */
-               if (sfgets(buf, MAXLINE, fp, dbto,
-                               "message separator read") == NULL)
-                       goto readerr;
-       }
-       else if (workbuf == buf2)       /* guarantee `buf' contains data */
-               (void) strcpy(buf, buf2);
+                       /* header -- buffer up */
+                       if (bp >= &buf[buflen - 2])
+                       {
+                               char *obuf;
+
+                               if (mstate != MS_HEADER)
+                                       break;
+
+                               /* out of space for header */
+                               obuf = buf;
+                               if (buflen < MEMCHUNKSIZE)
+                                       buflen *= 2;
+                               else
+                                       buflen += MEMCHUNKSIZE;
+                               buf = xalloc(buflen);
+                               bcopy(obuf, buf, bp - obuf);
+                               bp = &buf[bp - obuf];
+                               if (obuf != bufbuf)
+                                       free(obuf);
+                       }
+                       *bp++ = c;
+                       if (istate == IS_BOL)
+                               break;
+               }
+               *bp = '\0';
 
 
-       /*
-       **  Collect the body of the message.
-       */
+nextstate:
+               if (tTd(30, 35))
+                       printf("nextstate, istate=%d, mstate=%d, line = \"%s\"\n",
+                               istate, mstate, buf);
+               switch (mstate)
+               {
+                 case MS_UFROM:
+                       mstate = MS_HEADER;
+                       if (strncmp(buf, "From ", 5) == 0)
+                       {
+                               eatfrom(buf, e);
+                               continue;
+                       }
+                       /* fall through */
 
 
-       for (;;)
-       {
-               register char *bp = buf;
+                 case MS_HEADER:
+                       if (!isheader(buf))
+                       {
+                               mstate = MS_BODY;
+                               goto nextstate;
+                       }
 
 
-               fixcrlf(buf, TRUE);
+                       /* check for possible continuation line */
+                       do
+                       {
+                               clearerr(InChannel);
+                               errno = 0;
+                               c = fgetc(InChannel);
+                       } while (errno == EINTR);
+                       if (c != EOF)
+                               ungetc(c, InChannel);
+                       if (c == ' ' || c == '\t')
+                       {
+                               /* yep -- defer this */
+                               continue;
+                       }
 
 
-               /* check for end-of-message */
-               if (!ignrdot && buf[0] == '.' && (buf[1] == '\n' || buf[1] == '\0'))
+                       /* trim off trailing CRLF or NL */
+                       if (*--bp != '\n' || *--bp != '\r')
+                               bp++;
+                       *bp = '\0';
+                       if (bitset(H_EOH, chompheader(buf, FALSE, e)))
+                               mstate = MS_BODY;
                        break;
 
                        break;
 
-               /* check for transparent dot */
-               if ((OpMode == MD_SMTP || OpMode == MD_DAEMON) &&
-                   bp[0] == '.' && bp[1] == '.')
-                       bp++;
+                 case MS_BODY:
+                       if (tTd(30, 1))
+                               printf("EOH\n");
+                       if (headeronly)
+                               goto readerr;
+                       bp = buf;
 
 
-               /*
-               **  Figure message length, output the line to the temp
-               **  file, and insert a newline if missing.
-               */
+                       /* toss blank line */
+                       if ((!bitset(EF_CRLF_NOT_EOL, e->e_flags) &&
+                               bp[0] == '\r' && bp[1] == '\n') ||
+                           (!bitset(EF_NL_NOT_EOL, e->e_flags) &&
+                               bp[0] == '\n'))
+                       {
+                               break;
+                       }
 
 
-               e->e_msgsize += strlen(bp) + 1;
-               fputs(bp, tf);
-               fputs("\n", tf);
-               if (ferror(tf))
-                       tferror(tf, e);
-               if (sfgets(buf, MAXLINE, fp, dbto, "message body read") == NULL)
-                       goto readerr;
+                       /* if not a blank separator, write it out */
+                       while (*bp != '\0')
+                               fputc(*bp++, tf);
+                       break;
+               }
+               bp = buf;
        }
 
 readerr:
        }
 
 readerr:
@@ -283,7 +360,7 @@ readerr:
        }
 
        /* reset global timer */
        }
 
        /* reset global timer */
-       sfgetset((time_t) 0);
+       clrevent(CollectTimeout);
 
        if (headeronly)
                return;
 
        if (headeronly)
                return;
@@ -418,40 +495,19 @@ readerr:
                finis();
        }
 }
                finis();
        }
 }
-\f/*
-**  FLUSHEOL -- if not at EOL, throw away rest of input line.
-**
-**     Parameters:
-**             buf -- last line read in (checked for '\n'),
-**             fp -- file to be read from.
-**
-**     Returns:
-**             FALSE on error from sfgets(), TRUE otherwise.
-**
-**     Side Effects:
-**             none.
-*/
 
 
-bool
-flusheol(buf, fp, dbto)
-       char *buf;
-       FILE *fp;
-       time_t dbto;
-{
-       register char *p = buf;
-       char junkbuf[MAXLINE];
 
 
-       while (strchr(p, '\n') == NULL)
-       {
-               CollectErrorMessage = "553 header line too long";
-               CollectErrno = 0;
-               if (sfgets(junkbuf, MAXLINE, fp, dbto,
-                               "long line flush") == NULL)
-                       return (FALSE);
-               p = junkbuf;
-       }
+static
+collecttimeout(timeout)
+       time_t timeout;
+{
+       /* if no progress was made, die now */
+       if (!CollectProgress)
+               longjmp(CtxCollectTimeout, 1);
 
 
-       return (TRUE);
+       /* otherwise reset the timeout */
+       CollectTimeout = setevent(timeout, collecttimeout, timeout);
+       CollectProgress = FALSE;
 }
 \f/*
 **  TFERROR -- signal error on writing the temporary file.
 }
 \f/*
 **  TFERROR -- signal error on writing the temporary file.
index ac55424..4e5e026 100644 (file)
@@ -7,7 +7,7 @@
  */
 
 #ifndef lint
  */
 
 #ifndef lint
-static char sccsid[] = "@(#)deliver.c  8.89 (Berkeley) %G%";
+static char sccsid[] = "@(#)deliver.c  8.90 (Berkeley) %G%";
 #endif /* not lint */
 
 #include "sendmail.h"
 #endif /* not lint */
 
 #include "sendmail.h"
@@ -2048,6 +2048,11 @@ putfromline(mci, e)
 **             The message is written onto fp.
 */
 
 **             The message is written onto fp.
 */
 
+/* values for output state variable */
+#define OS_HEAD                0       /* at beginning of line */
+#define OS_CR          1       /* read a carriage return */
+#define OS_INLINE      2       /* putting rest of line */
+
 putbody(mci, e, separator)
        register MCI *mci;
        register ENVELOPE *e;
 putbody(mci, e, separator)
        register MCI *mci;
        register ENVELOPE *e;
@@ -2076,34 +2081,74 @@ putbody(mci, e, separator)
                                mci->mci_flags &= ~MCIF_INHEADER;
                        }
                        putline("<<< No Message Collected >>>", mci);
                                mci->mci_flags &= ~MCIF_INHEADER;
                        }
                        putline("<<< No Message Collected >>>", mci);
+                       goto endofmessage;
                }
        }
                }
        }
-       if (e->e_dfp != NULL)
+       rewind(e->e_dfp);
+
+       if (bitset(MCIF_CVT8TO7, mci->mci_flags))
+       {
+               /* do 8 to 7 bit MIME conversion */
+               if (hvalue("MIME-Version", e->e_header) == NULL)
+                       putline("MIME-Version: 1.0", mci);
+               mime8to7(mci, e->e_header, e, NULL);
+       }
+       else
        {
        {
-               rewind(e->e_dfp);
+               int ostate;
+               register char *bp;
+               register char *pbp;
+               register int c;
+               int padc;
+               char *buflim;
+               int pos;
+               char peekbuf[10];
 
 
-               if (bitset(MCIF_CVT8TO7, mci->mci_flags))
+               /* we can pass it through unmodified */
+               if (bitset(MCIF_INHEADER, mci->mci_flags))
                {
                {
-                       /* do 8 to 7 bit MIME conversion */
-                       if (hvalue("MIME-Version", e->e_header) == NULL)
-                               putline("MIME-Version: 1.0", mci);
-                       mime8to7(mci, e->e_header, e, NULL);
+                       putline("", mci);
+                       mci->mci_flags &= ~MCIF_INHEADER;
                }
                }
-               else
+
+               /* determine end of buffer; allow for short mailer lines */
+               buflim = &buf[sizeof buf - 1];
+               if (mci->mci_mailer->m_linelimit < sizeof buf - 1)
+                       buflim = &buf[mci->mci_mailer->m_linelimit - 1];
+
+               /* copy temp file to output with mapping */
+               ostate = OS_HEAD;
+               bp = buf;
+               pbp = peekbuf;
+               while (!ferror(mci->mci_out))
                {
                {
-                       /* we can pass it through unmodified */
-                       if (bitset(MCIF_INHEADER, mci->mci_flags))
-                       {
-                               putline("", mci);
-                               mci->mci_flags &= ~MCIF_INHEADER;
-                       }
-                       while (!ferror(mci->mci_out) &&
-                              fgets(buf, sizeof buf, e->e_dfp) != NULL)
+                       register char *xp;
+
+                       if (pbp > peekbuf)
+                               c = *--pbp;
+                       else if ((c = fgetc(e->e_dfp)) == EOF)
+                               break;
+                       if (bitset(MCIF_7BIT, mci->mci_flags))
+                               c &= 0x7f;
+                       switch (ostate)
                        {
                        {
+                         case OS_HEAD:
+                               if (c != '\r' && c != '\n' && bp < buflim)
+                               {
+                                       *bp++ = c;
+                                       break;
+                               }
+
+                               /* check beginning of line for special cases */
+                               *bp = '\0';
+                               pos = 0;
+                               padc = EOF;
                                if (buf[0] == 'F' &&
                                    bitnset(M_ESCFROM, mci->mci_mailer->m_flags) &&
                                    strncmp(buf, "From ", 5) == 0)
                                if (buf[0] == 'F' &&
                                    bitnset(M_ESCFROM, mci->mci_mailer->m_flags) &&
                                    strncmp(buf, "From ", 5) == 0)
-                                       (void) putc('>', mci->mci_out);
+                               {
+                                       padc = '>';
+                               }
                                if (buf[0] == '-' && buf[1] == '-' &&
                                    separator != NULL)
                                {
                                if (buf[0] == '-' && buf[1] == '-' &&
                                    separator != NULL)
                                {
@@ -2111,19 +2156,113 @@ putbody(mci, e, separator)
                                        int sl = strlen(separator);
 
                                        if (strncmp(&buf[2], separator, sl) == 0)
                                        int sl = strlen(separator);
 
                                        if (strncmp(&buf[2], separator, sl) == 0)
-                                               (void) putc(' ', mci->mci_out);
+                                               padc = ' ';
+                               }
+                               if (buf[0] == '.' &&
+                                   bitnset(M_XDOT, mci->mci_mailer->m_flags))
+                               {
+                                       padc = '.';
+                               }
+
+                               /* now copy out saved line */
+                               if (TrafficLogFile != NULL)
+                               {
+                                       fprintf(TrafficLogFile, "%05d >>> ", getpid());
+                                       if (padc != EOF)
+                                               fputc(padc, TrafficLogFile);
+                                       for (xp = buf; xp < bp; xp++)
+                                               fputc(*xp, TrafficLogFile);
+                                       if (c == '\n')
+                                               fputs(mci->mci_mailer->m_eol,
+                                                     TrafficLogFile);
+                               }
+                               if (padc != EOF)
+                               {
+                                       fputc(padc, mci->mci_out);
+                                       pos++;
+                               }
+                               for (xp = buf; xp < bp; xp++)
+                                       fputc(*xp, mci->mci_out);
+                               if (c == '\n')
+                               {
+                                       fputs(mci->mci_mailer->m_eol,
+                                             mci->mci_out);
+                                       pos = 0;
+                               }
+                               else
+                               {
+                                       pos += bp - buf;
+                                       *pbp++ = c;
                                }
                                }
-                               putline(buf, mci);
+                               bp = buf;
+
+                               /* determine next state */
+                               if (c == '\n')
+                                       ostate = OS_HEAD;
+                               else if (c == '\r')
+                                       ostate = OS_CR;
+                               else
+                                       ostate = OS_INLINE;
+                               continue;
+
+                         case OS_CR:
+                               if (c == '\n')
+                               {
+                                       /* got CRLF */
+                                       fputs(mci->mci_mailer->m_eol, mci->mci_out);
+                                       if (TrafficLogFile != NULL)
+                                       {
+                                               fputs(mci->mci_mailer->m_eol,
+                                                     TrafficLogFile);
+                                       }
+                                       ostate = OS_HEAD;
+                                       continue;
+                               }
+
+                               /* had a naked carriage return */
+                               *pbp++ = c;
+                               c = '\r';
+                               goto putchar;
+
+                         case OS_INLINE:
+                               if (c == '\r')
+                               {
+                                       ostate = OS_CR;
+                                       continue;
+                               }
+putchar:
+                               if (pos > mci->mci_mailer->m_linelimit &&
+                                   c != '\n')
+                               {
+                                       putc('!', mci->mci_out);
+                                       fputs(mci->mci_mailer->m_eol, mci->mci_out);
+                                       if (TrafficLogFile != NULL)
+                                       {
+                                               fprintf(TrafficLogFile, "!%s",
+                                                       mci->mci_mailer->m_eol);
+                                       }
+                                       ostate = OS_HEAD;
+                                       *pbp++ = c;
+                                       continue;
+                               }
+                               if (TrafficLogFile != NULL)
+                                       fputc(c, TrafficLogFile);
+                               putc(c, mci->mci_out);
+                               pos++;
+                               if (c == '\n')
+                                       ostate = OS_HEAD;
+                               break;
                        }
                }
                        }
                }
+       }
 
 
-               if (ferror(e->e_dfp))
-               {
-                       syserr("putbody: %s: read error", e->e_df);
-                       ExitStat = EX_IOERR;
-               }
+       if (ferror(e->e_dfp))
+       {
+               syserr("putbody: %s: read error", e->e_df);
+               ExitStat = EX_IOERR;
        }
 
        }
 
+endofmessage:
        /* some mailers want extra blank line at end of message */
        if (bitnset(M_BLANKEND, mci->mci_mailer->m_flags) &&
            buf[0] != '\0' && buf[0] != '\n')
        /* some mailers want extra blank line at end of message */
        if (bitnset(M_BLANKEND, mci->mci_mailer->m_flags) &&
            buf[0] != '\0' && buf[0] != '\n')
index ccb0c79..2c98414 100644 (file)
@@ -7,7 +7,7 @@
  */
 
 #ifndef lint
  */
 
 #ifndef lint
-static char sccsid[] = "@(#)util.c     8.42 (Berkeley) %G%";
+static char sccsid[] = "@(#)util.c     8.43 (Berkeley) %G%";
 #endif /* not lint */
 
 # include "sendmail.h"
 #endif /* not lint */
 
 # include "sendmail.h"
@@ -871,9 +871,6 @@ xfclose(fp, a, b)
 
 static jmp_buf CtxReadTimeout;
 static int     readtimeout();
 
 static jmp_buf CtxReadTimeout;
 static int     readtimeout();
-static EVENT   *GlobalTimeout = NULL;
-static bool    EnableTimeout = FALSE;
-static int     ReadProgress;
 
 char *
 sfgets(buf, siz, fp, timeout, during)
 
 char *
 sfgets(buf, siz, fp, timeout, during)
@@ -911,10 +908,7 @@ sfgets(buf, siz, fp, timeout, during)
 #endif
                        return (NULL);
                }
 #endif
                        return (NULL);
                }
-               if (GlobalTimeout == NULL)
-                       ev = setevent(timeout, readtimeout, 0);
-               else
-                       EnableTimeout = TRUE;
+               ev = setevent(timeout, readtimeout, 0);
        }
 
        /* try to read */
        }
 
        /* try to read */
@@ -929,10 +923,7 @@ sfgets(buf, siz, fp, timeout, during)
        }
 
        /* clear the event if it has not sprung */
        }
 
        /* clear the event if it has not sprung */
-       if (GlobalTimeout == NULL)
-               clrevent(ev);
-       else
-               EnableTimeout = FALSE;
+       clrevent(ev);
 
        /* clean up the books and exit */
        LineNumber++;
 
        /* clean up the books and exit */
        LineNumber++;
@@ -964,44 +955,11 @@ sfgets(buf, siz, fp, timeout, during)
        return (buf);
 }
 
        return (buf);
 }
 
-void
-sfgetset(timeout)
-       time_t timeout;
-{
-       /* cancel pending timer */
-       if (GlobalTimeout != NULL)
-       {
-               clrevent(GlobalTimeout);
-               GlobalTimeout = NULL;
-       }
-
-       /* schedule fresh one if so requested */
-       if (timeout != 0)
-       {
-               ReadProgress = LineNumber;
-               GlobalTimeout = setevent(timeout, readtimeout, timeout);
-       }
-}
-
 static
 readtimeout(timeout)
        time_t timeout;
 {
 static
 readtimeout(timeout)
        time_t timeout;
 {
-       /* terminate if ordinary timeout */
-       if (GlobalTimeout == NULL)
-               longjmp(CtxReadTimeout, 1);
-
-       /* terminate if no progress was made -- reset state */
-       if (EnableTimeout && (LineNumber <= ReadProgress))
-       {
-               EnableTimeout = FALSE;
-               GlobalTimeout = NULL;
-               longjmp(CtxReadTimeout, 2);
-       }
-
-       /* schedule a new timeout */
-       GlobalTimeout = NULL;
-       sfgetset(timeout);
+       longjmp(CtxReadTimeout, 1);
 }
 \f/*
 **  FGETFOLDED -- like fgets, but know about folded lines.
 }
 \f/*
 **  FGETFOLDED -- like fgets, but know about folded lines.