122697Sdist /*
234920Sbostic  * Copyright (c) 1983 Eric P. Allman
362522Sbostic  * Copyright (c) 1988, 1993
462522Sbostic  *	The Regents of the University of California.  All rights reserved.
533728Sbostic  *
642824Sbostic  * %sccs.include.redist.c%
733728Sbostic  */
822697Sdist 
922697Sdist #ifndef lint
10*67617Seric static char sccsid[] = "@(#)collect.c	8.20 (Berkeley) 08/07/94";
1133728Sbostic #endif /* not lint */
1222697Sdist 
131439Seric # include <errno.h>
143309Seric # include "sendmail.h"
151392Seric 
161392Seric /*
172969Seric **  COLLECT -- read & parse message header & make temp file.
181392Seric **
191392Seric **	Creates a temporary file name and copies the standard
209371Seric **	input to that file.  Leading UNIX-style "From" lines are
219371Seric **	stripped off (after important information is extracted).
221392Seric **
231392Seric **	Parameters:
2467546Seric **		fp -- file to read.
2552106Seric **		smtpmode -- if set, we are running SMTP: give an RFC821
2652105Seric **			style message to say we are ready to collect
2752105Seric **			input, and never ignore a single dot to mean
2852105Seric **			end of message.
2958929Seric **		requeueflag -- this message will be requeued later, so
3058929Seric **			don't do final processing on it.
3167546Seric **		hdrp -- the location to stash the header.
3258929Seric **		e -- the current envelope.
331392Seric **
341392Seric **	Returns:
354162Seric **		none.
361392Seric **
371392Seric **	Side Effects:
381392Seric **		Temp file is created and filled.
394162Seric **		The from person may be set.
401392Seric */
411392Seric 
4266796Seric char	*CollectErrorMessage;
4366796Seric bool	CollectErrno;
4466796Seric 
4567599Seric static jmp_buf	CtxCollectTimeout;
4667599Seric static int	collecttimeout();
4767599Seric static bool	CollectProgress;
4867599Seric static EVENT	*CollectTimeout;
4967599Seric 
5067599Seric /* values for input state machine */
5167599Seric #define IS_NORM		0	/* middle of line */
5267599Seric #define IS_BOL		1	/* beginning of line */
5367599Seric #define IS_DOT		2	/* read a dot at beginning of line */
5467599Seric #define IS_DOTCR	3	/* read ".\r" at beginning of line */
5567599Seric #define IS_CR		4	/* read a carriage return */
5667599Seric 
5767599Seric /* values for message state machine */
5867599Seric #define MS_UFROM	0	/* reading Unix from line */
5967599Seric #define MS_HEADER	1	/* reading message header */
6067599Seric #define MS_BODY		2	/* reading message body */
6167599Seric 
6267599Seric 
6367546Seric collect(fp, smtpmode, requeueflag, hdrp, e)
6467546Seric 	FILE *fp;
6552105Seric 	bool smtpmode;
6658929Seric 	bool requeueflag;
6767546Seric 	HDR **hdrp;
6855012Seric 	register ENVELOPE *e;
691392Seric {
701392Seric 	register FILE *tf;
7152105Seric 	bool ignrdot = smtpmode ? FALSE : IgnrDot;
7267268Seric 	time_t dbto = smtpmode ? TimeOuts.to_datablock : 0;
7367599Seric 	register char *bp;
7467599Seric 	register int c;
7564718Seric 	bool inputerr = FALSE;
7667546Seric 	bool headeronly = FALSE;
7767599Seric 	char *buf;
7867599Seric 	int buflen;
7967599Seric 	int istate;
8067599Seric 	int mstate;
8167599Seric 	char *pbp;
8267599Seric 	char peekbuf[8];
8367599Seric 	char bufbuf[MAXLINE];
842900Seric 	extern char *hvalue();
8567599Seric 	extern bool isheader();
861392Seric 
8766796Seric 	CollectErrorMessage = NULL;
8866796Seric 	CollectErrno = 0;
8967546Seric 	if (hdrp == NULL)
9067546Seric 		hdrp = &e->e_header;
9167546Seric 	else
9267546Seric 		headeronly = TRUE;
9366796Seric 
941392Seric 	/*
951392Seric 	**  Create the temp file name and create the file.
961392Seric 	*/
971392Seric 
9867546Seric 	if (!headeronly)
991392Seric 	{
100*67617Seric 		struct stat stbuf;
101*67617Seric 
10267546Seric 		e->e_df = queuename(e, 'd');
10367546Seric 		e->e_df = newstr(e->e_df);
10467546Seric 		if ((tf = dfopen(e->e_df, O_WRONLY|O_CREAT|O_TRUNC, FileMode)) == NULL)
10567546Seric 		{
10667546Seric 			syserr("Cannot create %s", e->e_df);
10767546Seric 			e->e_flags |= EF_NORETURN;
10867546Seric 			finis();
10967546Seric 		}
110*67617Seric 		if (fstat(fileno(tf), &stbuf) < 0)
111*67617Seric 			e->e_dfino = -1;
112*67617Seric 		else
113*67617Seric 			e->e_dfino = stbuf.st_ino;
11467546Seric 		HasEightBits = FALSE;
1151392Seric 	}
1161392Seric 
1174316Seric 	/*
1184322Seric 	**  Tell ARPANET to go ahead.
1194322Seric 	*/
1204322Seric 
12152105Seric 	if (smtpmode)
12258151Seric 		message("354 Enter mail, end with \".\" on a line by itself");
1234322Seric 
1244322Seric 	/*
12567599Seric 	**  Read the message.
12667599Seric 	**
12767599Seric 	**	This is done using two interleaved state machines.
12867599Seric 	**	The input state machine is looking for things like
12967599Seric 	**	hidden dots; the message state machine is handling
13067599Seric 	**	the larger picture (e.g., header versus body).
1314316Seric 	*/
1324316Seric 
13367599Seric 	buf = bp = bufbuf;
13467599Seric 	buflen = sizeof bufbuf;
13567599Seric 	pbp = peekbuf;
13667599Seric 	istate = IS_BOL;
13767599Seric 	mstate = SaveFrom ? MS_HEADER : MS_UFROM;
13867599Seric 	CollectProgress = FALSE;
13967599Seric 
14067599Seric 	/* if transmitting binary, don't map NL to EOL */
14167599Seric 	if (e->e_bodytype != NULL && strcasecmp(e->e_bodytype, "8BITMIME") == 0)
14267599Seric 		e->e_flags |= EF_NL_NOT_EOL;
14367599Seric 
14467599Seric 	if (dbto != 0)
1452900Seric 	{
14667599Seric 		/* handle possible input timeout */
14767599Seric 		if (setjmp(CtxCollectTimeout) != 0)
14867599Seric 		{
14967599Seric #ifdef LOG
15067599Seric 			syslog(LOG_NOTICE,
15167599Seric 			    "timeout waiting for input from %s during message collect",
15267599Seric 			    CurHostName ? CurHostName : "<local machine>");
15367599Seric #endif
15467599Seric 			errno = 0;
15567599Seric 			usrerr("451 timeout waiting for input during message collect");
15640965Sbostic 			goto readerr;
15767599Seric 		}
15867599Seric 		CollectTimeout = setevent(dbto, collecttimeout, dbto);
1592900Seric 	}
1602900Seric 
16140965Sbostic 	for (;;)
1621392Seric 	{
16367599Seric 		if (tTd(30, 35))
16467599Seric 			printf("top, istate=%d, mstate=%d\n", istate, mstate);
16540965Sbostic 		for (;;)
1661392Seric 		{
16767599Seric 			if (pbp > peekbuf)
16867599Seric 				c = *--pbp;
16967599Seric 			else
17064916Seric 			{
17167599Seric 				while (!feof(InChannel) && !ferror(InChannel))
17267599Seric 				{
17367599Seric 					errno = 0;
17467599Seric 					c = fgetc(InChannel);
17567599Seric 					if (errno != EINTR)
17667599Seric 						break;
17767599Seric 					clearerr(InChannel);
17867599Seric 				}
17967599Seric 				CollectProgress = TRUE;
18067599Seric 				if (TrafficLogFile != NULL)
18167599Seric 				{
18267599Seric 					if (istate == IS_BOL)
18367599Seric 						fprintf(TrafficLogFile, "%05d <<< ",
18467599Seric 							getpid());
18567599Seric 					if (c == EOF)
18667599Seric 						fprintf(TrafficLogFile, "[EOF]\n");
18767599Seric 					else
18867599Seric 						fputc(c, TrafficLogFile);
18967599Seric 				}
19067599Seric 				if (c == EOF)
19167599Seric 					goto readerr;
19267599Seric 				if (SevenBitInput)
19367599Seric 					c &= 0x7f;
19467599Seric 				else
19567599Seric 					HasEightBits |= bitset(0x80, c);
19667599Seric 				e->e_msgsize++;
19767599Seric 			}
19867599Seric 			if (tTd(30, 94))
19967599Seric 				printf("istate=%d, c=%c (0x%x)\n",
20067599Seric 					istate, c, c);
20167599Seric 			switch (istate)
20267599Seric 			{
20367599Seric 			  case IS_BOL:
20467599Seric 				if (c == '.')
20567599Seric 				{
20667599Seric 					istate = IS_DOT;
20767599Seric 					continue;
20867599Seric 				}
20964916Seric 				break;
21040965Sbostic 
21167599Seric 			  case IS_DOT:
21267599Seric 				if (c == '\n' && !ignrdot &&
21367599Seric 				    !bitset(EF_NL_NOT_EOL, e->e_flags))
21467599Seric 					goto readerr;
21567599Seric 				else if (c == '\r' &&
21667599Seric 					 !bitset(EF_CRLF_NOT_EOL, e->e_flags))
21767599Seric 				{
21867599Seric 					istate = IS_DOTCR;
21967599Seric 					continue;
22067599Seric 				}
22167599Seric 				else if (c != '.' ||
22267599Seric 					 (OpMode != MD_SMTP &&
22367599Seric 					  OpMode != MD_DAEMON &&
22467599Seric 					  OpMode != MD_ARPAFTP))
22567599Seric 				{
22667599Seric 					*pbp++ = c;
22767599Seric 					c = '.';
22867599Seric 				}
2292900Seric 				break;
23040965Sbostic 
23167599Seric 			  case IS_DOTCR:
23267599Seric 				if (c == '\n')
23367599Seric 					goto readerr;
23467599Seric 				else
23567599Seric 				{
23667599Seric 					/* push back the ".\rx" */
23767599Seric 					*pbp++ = c;
23867599Seric 					*pbp++ = '\r';
23967599Seric 					c = '.';
24067599Seric 				}
24167599Seric 				break;
24240965Sbostic 
24367599Seric 			  case IS_CR:
24467599Seric 				if (c != '\n')
24567599Seric 				{
24667599Seric 					ungetc(c, InChannel);
24767599Seric 					c = '\r';
24867599Seric 				}
24967599Seric 				else if (!bitset(EF_CRLF_NOT_EOL, e->e_flags))
25067599Seric 					istate = IS_BOL;
25167599Seric 				break;
25267599Seric 			}
25357135Seric 
25467599Seric 			if (c == '\r')
25540965Sbostic 			{
25667599Seric 				istate = IS_CR;
25767599Seric 				continue;
25867599Seric 			}
25967599Seric 			else if (c == '\n' && !bitset(EF_NL_NOT_EOL, e->e_flags))
26067599Seric 				istate = IS_BOL;
26167599Seric 			else
26267599Seric 				istate = IS_NORM;
26340965Sbostic 
26467599Seric 			if (mstate == MS_BODY)
26567599Seric 			{
26667599Seric 				/* just put the character out */
26767599Seric 				fputc(c, tf);
26867599Seric 				continue;
26940965Sbostic 			}
2701392Seric 
27167599Seric 			/* header -- buffer up */
27267599Seric 			if (bp >= &buf[buflen - 2])
27367599Seric 			{
27467599Seric 				char *obuf;
2751392Seric 
27667599Seric 				if (mstate != MS_HEADER)
27767599Seric 					break;
27840965Sbostic 
27967599Seric 				/* out of space for header */
28067599Seric 				obuf = buf;
28167599Seric 				if (buflen < MEMCHUNKSIZE)
28267599Seric 					buflen *= 2;
28367599Seric 				else
28467599Seric 					buflen += MEMCHUNKSIZE;
28567599Seric 				buf = xalloc(buflen);
28667599Seric 				bcopy(obuf, buf, bp - obuf);
28767599Seric 				bp = &buf[bp - obuf];
28867599Seric 				if (obuf != bufbuf)
28967599Seric 					free(obuf);
29067599Seric 			}
29167599Seric 			*bp++ = c;
29267599Seric 			if (istate == IS_BOL)
29367599Seric 				break;
29440965Sbostic 		}
29567599Seric 		*bp = '\0';
29640965Sbostic 
29767599Seric nextstate:
29867599Seric 		if (tTd(30, 35))
29967599Seric 			printf("nextstate, istate=%d, mstate=%d, line = \"%s\"\n",
30067599Seric 				istate, mstate, buf);
30167599Seric 		switch (mstate)
30267599Seric 		{
30367599Seric 		  case MS_UFROM:
30467599Seric 			mstate = MS_HEADER;
30567599Seric 			if (strncmp(buf, "From ", 5) == 0)
30667599Seric 			{
30767599Seric 				eatfrom(buf, e);
30867599Seric 				continue;
30967599Seric 			}
31067599Seric 			/* fall through */
3112900Seric 
31267599Seric 		  case MS_HEADER:
31367599Seric 			if (!isheader(buf))
31467599Seric 			{
31567599Seric 				mstate = MS_BODY;
31667599Seric 				goto nextstate;
31767599Seric 			}
31857135Seric 
31967599Seric 			/* check for possible continuation line */
32067599Seric 			do
32167599Seric 			{
32267599Seric 				clearerr(InChannel);
32367599Seric 				errno = 0;
32467599Seric 				c = fgetc(InChannel);
32567599Seric 			} while (errno == EINTR);
32667599Seric 			if (c != EOF)
32767599Seric 				ungetc(c, InChannel);
32867599Seric 			if (c == ' ' || c == '\t')
32967599Seric 			{
33067599Seric 				/* yep -- defer this */
33167599Seric 				continue;
33267599Seric 			}
33357135Seric 
33467599Seric 			/* trim off trailing CRLF or NL */
33567599Seric 			if (*--bp != '\n' || *--bp != '\r')
33667599Seric 				bp++;
33767599Seric 			*bp = '\0';
33867599Seric 			if (bitset(H_EOH, chompheader(buf, FALSE, e)))
33967599Seric 				mstate = MS_BODY;
34067599Seric 			break;
3411392Seric 
34267599Seric 		  case MS_BODY:
34367599Seric 			if (tTd(30, 1))
34467599Seric 				printf("EOH\n");
34567599Seric 			if (headeronly)
34667599Seric 				goto readerr;
34767599Seric 			bp = buf;
3482900Seric 
34967599Seric 			/* toss blank line */
35067599Seric 			if ((!bitset(EF_CRLF_NOT_EOL, e->e_flags) &&
35167599Seric 				bp[0] == '\r' && bp[1] == '\n') ||
35267599Seric 			    (!bitset(EF_NL_NOT_EOL, e->e_flags) &&
35367599Seric 				bp[0] == '\n'))
35467599Seric 			{
35567599Seric 				break;
35667599Seric 			}
35767546Seric 
35867599Seric 			/* if not a blank separator, write it out */
35967599Seric 			while (*bp != '\0')
36067599Seric 				fputc(*bp++, tf);
3612900Seric 			break;
36267599Seric 		}
36367599Seric 		bp = buf;
36464718Seric 	}
36540965Sbostic 
36667546Seric readerr:
36767546Seric 	if ((feof(fp) && smtpmode) || ferror(fp))
36864718Seric 	{
36964916Seric 		if (tTd(30, 1))
37064916Seric 			printf("collect: read error\n");
37164718Seric 		inputerr = TRUE;
37264718Seric 	}
37364718Seric 
37466765Seric 	/* reset global timer */
37567599Seric 	clrevent(CollectTimeout);
37666765Seric 
37767546Seric 	if (headeronly)
37867546Seric 		return;
37967546Seric 
38067546Seric 	if (tf != NULL)
38164762Seric 	{
38267546Seric 		if (fflush(tf) != 0)
38367546Seric 			tferror(tf, e);
38467546Seric 		if (fsync(fileno(tf)) < 0 || fclose(tf) < 0)
38567546Seric 		{
38667546Seric 			tferror(tf, e);
38767546Seric 			finis();
38867546Seric 		}
38964762Seric 	}
3902900Seric 
39166796Seric 	if (CollectErrorMessage != NULL && Errors <= 0)
39216136Seric 	{
39366796Seric 		if (CollectErrno != 0)
39466796Seric 		{
39566796Seric 			errno = CollectErrno;
39666796Seric 			syserr(CollectErrorMessage, e->e_df);
39766796Seric 			finis();
39866796Seric 		}
39966796Seric 		usrerr(CollectErrorMessage);
40066796Seric 	}
40166796Seric 	else if (inputerr && (OpMode == MD_SMTP || OpMode == MD_DAEMON))
40266796Seric 	{
40366796Seric 		/* An EOF when running SMTP is an error */
40458308Seric 		char *host;
40564718Seric 		char *problem;
40658082Seric 
40758308Seric 		host = RealHostName;
40858308Seric 		if (host == NULL)
40958308Seric 			host = "localhost";
41058308Seric 
41167546Seric 		if (feof(fp))
41264718Seric 			problem = "unexpected close";
41367546Seric 		else if (ferror(fp))
41464718Seric 			problem = "I/O error";
41564718Seric 		else
41664718Seric 			problem = "read timeout";
41736233Skarels # ifdef LOG
41867546Seric 		if (LogLevel > 0 && feof(fp))
41936230Skarels 			syslog(LOG_NOTICE,
42066864Seric 			    "collect: %s on connection from %s, sender=%s: %s\n",
42166864Seric 			    problem, host, e->e_from.q_paddr, errstring(errno));
42236233Skarels # endif
42367546Seric 		if (feof(fp))
42465951Seric 			usrerr("451 collect: %s on connection from %s, from=%s",
42564718Seric 				problem, host, e->e_from.q_paddr);
42665951Seric 		else
42765951Seric 			syserr("451 collect: %s on connection from %s, from=%s",
42865951Seric 				problem, host, e->e_from.q_paddr);
42911145Seric 
43016136Seric 		/* don't return an error indication */
43155012Seric 		e->e_to = NULL;
43255012Seric 		e->e_flags &= ~EF_FATALERRS;
43364124Seric 		e->e_flags |= EF_CLRQUEUE;
43416136Seric 
43516136Seric 		/* and don't try to deliver the partial message either */
43664718Seric 		if (InChild)
43764718Seric 			ExitStat = EX_QUIT;
43816136Seric 		finis();
43916136Seric 	}
44016136Seric 
4412900Seric 	/*
4422900Seric 	**  Find out some information from the headers.
4433386Seric 	**	Examples are who is the from person & the date.
4442900Seric 	*/
4452900Seric 
44658929Seric 	eatheader(e, !requeueflag);
4477673Seric 
44864068Seric 	/* collect statistics */
44964068Seric 	if (OpMode != MD_VERIFY)
45064068Seric 		markstats(e, (ADDRESS *) NULL);
45164068Seric 
4527782Seric 	/*
4537782Seric 	**  Add an Apparently-To: line if we have no recipient lines.
4547782Seric 	*/
4554622Seric 
45667546Seric 	if (hvalue("to", e->e_header) == NULL &&
45767546Seric 	    hvalue("cc", e->e_header) == NULL &&
45867546Seric 	    hvalue("bcc", e->e_header) == NULL &&
45967546Seric 	    hvalue("apparently-to", e->e_header) == NULL)
4607367Seric 	{
4617367Seric 		register ADDRESS *q;
4627367Seric 
4637367Seric 		/* create an Apparently-To: field */
4647367Seric 		/*    that or reject the message.... */
46555012Seric 		for (q = e->e_sendqueue; q != NULL; q = q->q_next)
4667367Seric 		{
4677389Seric 			if (q->q_alias != NULL)
4687389Seric 				continue;
4697673Seric 			if (tTd(30, 3))
4707367Seric 				printf("Adding Apparently-To: %s\n", q->q_paddr);
47167546Seric 			addheader("Apparently-To", q->q_paddr, &e->e_header);
4727367Seric 		}
4737367Seric 	}
4747367Seric 
47559320Seric 	/* check for message too large */
47659320Seric 	if (MaxMessageSize > 0 && e->e_msgsize > MaxMessageSize)
47759320Seric 	{
47859320Seric 		usrerr("552 Message exceeds maximum fixed size (%ld)",
47959320Seric 			MaxMessageSize);
48059320Seric 	}
48159320Seric 
48267547Seric 	/* check for illegal 8-bit data */
48367547Seric 	if (HasEightBits)
48467547Seric 	{
48567547Seric 		e->e_flags |= EF_HAS8BIT;
48667547Seric 		if (bitset(MM_MIME8BIT, MimeMode))
48767547Seric 		{
48867547Seric 			/* convert it to MIME */
48967547Seric 			if (hvalue("MIME-Version", e->e_header) == NULL)
49067547Seric 			{
49167547Seric 				char mimebuf[20];
49267547Seric 
49367547Seric 				strcpy(mimebuf, "MIME-Version: 1.0");
49467547Seric 				chompheader(mimebuf, FALSE, e);
49567547Seric 			}
49667547Seric 			if (e->e_bodytype == NULL)
49767547Seric 				e->e_bodytype = "8BITMIME";
49867547Seric 		}
49967547Seric 		else if (!bitset(MM_PASS8BIT, MimeMode))
50067547Seric 			usrerr("554 Eight bit data not allowed");
50167547Seric 	}
50267547Seric 
50355012Seric 	if ((e->e_dfp = fopen(e->e_df, "r")) == NULL)
50458690Seric 	{
50558690Seric 		/* we haven't acked receipt yet, so just chuck this */
50655012Seric 		syserr("Cannot reopen %s", e->e_df);
50758690Seric 		finis();
50858690Seric 	}
5091392Seric }
51040965Sbostic 
51167599Seric 
51267599Seric static
51367599Seric collecttimeout(timeout)
51467599Seric 	time_t timeout;
51540965Sbostic {
51667599Seric 	/* if no progress was made, die now */
51767599Seric 	if (!CollectProgress)
51867599Seric 		longjmp(CtxCollectTimeout, 1);
51940965Sbostic 
52067599Seric 	/* otherwise reset the timeout */
52167599Seric 	CollectTimeout = setevent(timeout, collecttimeout, timeout);
52267599Seric 	CollectProgress = FALSE;
52340965Sbostic }
52440965Sbostic /*
52511544Seric **  TFERROR -- signal error on writing the temporary file.
52611544Seric **
52711544Seric **	Parameters:
52811544Seric **		tf -- the file pointer for the temporary file.
52911544Seric **
53011544Seric **	Returns:
53111544Seric **		none.
53211544Seric **
53311544Seric **	Side Effects:
53411544Seric **		Gives an error message.
53511544Seric **		Arranges for following output to go elsewhere.
53611544Seric */
53711544Seric 
53855012Seric tferror(tf, e)
53911544Seric 	FILE *tf;
54055012Seric 	register ENVELOPE *e;
54111544Seric {
54266796Seric 	CollectErrno = errno;
54311544Seric 	if (errno == ENOSPC)
54411544Seric 	{
54566782Seric 		struct stat st;
54666782Seric 		long avail;
54766782Seric 		long bsize;
54866782Seric 
54967473Seric 		e->e_flags |= EF_NORETURN;
55066782Seric 		if (fstat(fileno(tf), &st) < 0)
55166782Seric 			st.st_size = 0;
55255012Seric 		(void) freopen(e->e_df, "w", tf);
55366782Seric 		if (st.st_size <= 0)
55466782Seric 			fprintf(tf, "\n*** Mail could not be accepted");
55566782Seric 		else if (sizeof st.st_size > sizeof (long))
55666782Seric 			fprintf(tf, "\n*** Mail of at least %qd bytes could not be accepted\n",
55766782Seric 				st.st_size);
55866782Seric 		else
55966782Seric 			fprintf(tf, "\n*** Mail of at least %ld bytes could not be accepted\n",
56066782Seric 				st.st_size);
56166782Seric 		fprintf(tf, "*** at %s due to lack of disk space for temp file.\n",
56266782Seric 			MyHostName);
56366782Seric 		avail = freespace(QueueDir, &bsize);
56466782Seric 		if (avail > 0)
56566782Seric 		{
56666782Seric 			if (bsize > 1024)
56766782Seric 				avail *= bsize / 1024;
56866782Seric 			else if (bsize < 1024)
56966782Seric 				avail /= 1024 / bsize;
57066782Seric 			fprintf(tf, "*** Currently, %ld kilobytes are available for mail temp files.\n",
57166782Seric 				avail);
57266782Seric 		}
57366796Seric 		CollectErrorMessage = "452 Out of disk space for temp file";
57411544Seric 	}
57511544Seric 	else
57666796Seric 	{
57766796Seric 		CollectErrorMessage = "cannot write message body to disk (%s)";
57866796Seric 	}
57911544Seric 	(void) freopen("/dev/null", "w", tf);
58011544Seric }
58111544Seric /*
5822900Seric **  EATFROM -- chew up a UNIX style from line and process
5832900Seric **
5842900Seric **	This does indeed make some assumptions about the format
5852900Seric **	of UNIX messages.
5862900Seric **
5872900Seric **	Parameters:
5882900Seric **		fm -- the from line.
5892900Seric **
5902900Seric **	Returns:
5912900Seric **		none.
5922900Seric **
5932900Seric **	Side Effects:
5942900Seric **		extracts what information it can from the header,
5953386Seric **		such as the date.
5962900Seric */
5972900Seric 
5984321Seric # ifndef NOTUNIX
5994321Seric 
6004203Seric char	*DowList[] =
6014203Seric {
6024203Seric 	"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", NULL
6034203Seric };
6044203Seric 
6052900Seric char	*MonthList[] =
6062900Seric {
6072900Seric 	"Jan", "Feb", "Mar", "Apr", "May", "Jun",
6082900Seric 	"Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
6092900Seric 	NULL
6102900Seric };
6112900Seric 
61255012Seric eatfrom(fm, e)
6132900Seric 	char *fm;
61455012Seric 	register ENVELOPE *e;
6152900Seric {
6162900Seric 	register char *p;
6172900Seric 	register char **dt;
6182900Seric 
6197673Seric 	if (tTd(30, 2))
6204203Seric 		printf("eatfrom(%s)\n", fm);
6214203Seric 
6222900Seric 	/* find the date part */
6232900Seric 	p = fm;
6242900Seric 	while (*p != '\0')
6252900Seric 	{
6262900Seric 		/* skip a word */
6272900Seric 		while (*p != '\0' && *p != ' ')
62816896Seric 			p++;
6292900Seric 		while (*p == ' ')
63016896Seric 			p++;
63158050Seric 		if (!(isascii(*p) && isupper(*p)) ||
63258050Seric 		    p[3] != ' ' || p[13] != ':' || p[16] != ':')
6332900Seric 			continue;
6342900Seric 
6352900Seric 		/* we have a possible date */
6364203Seric 		for (dt = DowList; *dt != NULL; dt++)
6372900Seric 			if (strncmp(*dt, p, 3) == 0)
6382900Seric 				break;
6394203Seric 		if (*dt == NULL)
6404203Seric 			continue;
6412900Seric 
6424203Seric 		for (dt = MonthList; *dt != NULL; dt++)
6434203Seric 			if (strncmp(*dt, &p[4], 3) == 0)
6444203Seric 				break;
6452900Seric 		if (*dt != NULL)
6462900Seric 			break;
6472900Seric 	}
6482900Seric 
64960502Seric 	if (*p != '\0')
6502900Seric 	{
6513386Seric 		char *q;
6525366Seric 		extern char *arpadate();
6533386Seric 
6542900Seric 		/* we have found a date */
6553386Seric 		q = xalloc(25);
65623103Seric 		(void) strncpy(q, p, 25);
6573386Seric 		q[24] = '\0';
6585366Seric 		q = arpadate(q);
65955012Seric 		define('a', newstr(q), e);
6602900Seric 	}
6612900Seric }
6624321Seric 
66356795Seric # endif /* NOTUNIX */
664