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*68837Seric static char sccsid[] = "@(#)collect.c	8.35 (Berkeley) 04/21/95";
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 
4267599Seric static jmp_buf	CtxCollectTimeout;
4368433Seric static void	collecttimeout();
4467599Seric static bool	CollectProgress;
4567599Seric static EVENT	*CollectTimeout;
4667599Seric 
4767599Seric /* values for input state machine */
4867599Seric #define IS_NORM		0	/* middle of line */
4967599Seric #define IS_BOL		1	/* beginning of line */
5067599Seric #define IS_DOT		2	/* read a dot at beginning of line */
5167599Seric #define IS_DOTCR	3	/* read ".\r" at beginning of line */
5267599Seric #define IS_CR		4	/* read a carriage return */
5367599Seric 
5467599Seric /* values for message state machine */
5567599Seric #define MS_UFROM	0	/* reading Unix from line */
5667599Seric #define MS_HEADER	1	/* reading message header */
5767599Seric #define MS_BODY		2	/* reading message body */
5867599Seric 
5968433Seric void
6067546Seric collect(fp, smtpmode, requeueflag, hdrp, e)
6167546Seric 	FILE *fp;
6252105Seric 	bool smtpmode;
6358929Seric 	bool requeueflag;
6467546Seric 	HDR **hdrp;
6555012Seric 	register ENVELOPE *e;
661392Seric {
671392Seric 	register FILE *tf;
6852105Seric 	bool ignrdot = smtpmode ? FALSE : IgnrDot;
6967268Seric 	time_t dbto = smtpmode ? TimeOuts.to_datablock : 0;
7067599Seric 	register char *bp;
7168433Seric 	int c = '\0';
7264718Seric 	bool inputerr = FALSE;
7368717Seric 	bool headeronly;
7467599Seric 	char *buf;
7567599Seric 	int buflen;
7667599Seric 	int istate;
7767599Seric 	int mstate;
7867599Seric 	char *pbp;
7967599Seric 	char peekbuf[8];
8068564Seric 	char dfname[20];
8167599Seric 	char bufbuf[MAXLINE];
8267599Seric 	extern bool isheader();
8368433Seric 	extern void eatheader();
8468433Seric 	extern void tferror();
851392Seric 
8668717Seric 	headeronly = hdrp != NULL;
8766796Seric 
881392Seric 	/*
891392Seric 	**  Create the temp file name and create the file.
901392Seric 	*/
911392Seric 
9267546Seric 	if (!headeronly)
931392Seric 	{
9467617Seric 		struct stat stbuf;
9567617Seric 
9668564Seric 		strcpy(dfname, queuename(e, 'd'));
9768564Seric 		if ((tf = dfopen(dfname, O_WRONLY|O_CREAT|O_TRUNC, FileMode)) == NULL)
9867546Seric 		{
9968564Seric 			syserr("Cannot create %s", dfname);
10068559Seric 			e->e_flags |= EF_NO_BODY_RETN;
10167546Seric 			finis();
10267546Seric 		}
10367617Seric 		if (fstat(fileno(tf), &stbuf) < 0)
10467617Seric 			e->e_dfino = -1;
10567617Seric 		else
10667688Seric 		{
10767688Seric 			e->e_dfdev = stbuf.st_dev;
10867617Seric 			e->e_dfino = stbuf.st_ino;
10967688Seric 		}
11067546Seric 		HasEightBits = FALSE;
11168560Seric 		e->e_msgsize = 0;
11268564Seric 		e->e_flags |= EF_HAS_DF;
1131392Seric 	}
1141392Seric 
1154316Seric 	/*
1164322Seric 	**  Tell ARPANET to go ahead.
1174322Seric 	*/
1184322Seric 
11952105Seric 	if (smtpmode)
12058151Seric 		message("354 Enter mail, end with \".\" on a line by itself");
1214322Seric 
12268717Seric 	if (tTd(30, 2))
12368717Seric 		printf("collect\n");
12468717Seric 
1254322Seric 	/*
12667599Seric 	**  Read the message.
12767599Seric 	**
12867599Seric 	**	This is done using two interleaved state machines.
12967599Seric 	**	The input state machine is looking for things like
13067599Seric 	**	hidden dots; the message state machine is handling
13167599Seric 	**	the larger picture (e.g., header versus body).
1324316Seric 	*/
1334316Seric 
13467599Seric 	buf = bp = bufbuf;
13567599Seric 	buflen = sizeof bufbuf;
13667599Seric 	pbp = peekbuf;
13767599Seric 	istate = IS_BOL;
13867599Seric 	mstate = SaveFrom ? MS_HEADER : MS_UFROM;
13967599Seric 	CollectProgress = FALSE;
14067599Seric 
14167599Seric 	/* if transmitting binary, don't map NL to EOL */
14267599Seric 	if (e->e_bodytype != NULL && strcasecmp(e->e_bodytype, "8BITMIME") == 0)
14367599Seric 		e->e_flags |= EF_NL_NOT_EOL;
14467599Seric 
14567599Seric 	if (dbto != 0)
1462900Seric 	{
14767599Seric 		/* handle possible input timeout */
14867599Seric 		if (setjmp(CtxCollectTimeout) != 0)
14967599Seric 		{
15067599Seric #ifdef LOG
15167599Seric 			syslog(LOG_NOTICE,
15267599Seric 			    "timeout waiting for input from %s during message collect",
15367599Seric 			    CurHostName ? CurHostName : "<local machine>");
15467599Seric #endif
15567599Seric 			errno = 0;
15667599Seric 			usrerr("451 timeout waiting for input during message collect");
15740965Sbostic 			goto readerr;
15867599Seric 		}
15967599Seric 		CollectTimeout = setevent(dbto, collecttimeout, dbto);
1602900Seric 	}
1612900Seric 
16240965Sbostic 	for (;;)
1631392Seric 	{
16467599Seric 		if (tTd(30, 35))
16567599Seric 			printf("top, istate=%d, mstate=%d\n", istate, mstate);
16640965Sbostic 		for (;;)
1671392Seric 		{
16867599Seric 			if (pbp > peekbuf)
16967599Seric 				c = *--pbp;
17067599Seric 			else
17164916Seric 			{
17268717Seric 				while (!feof(fp) && !ferror(fp))
17367599Seric 				{
17467599Seric 					errno = 0;
17568717Seric 					c = fgetc(fp);
17667599Seric 					if (errno != EINTR)
17767599Seric 						break;
17868717Seric 					clearerr(fp);
17967599Seric 				}
18067599Seric 				CollectProgress = TRUE;
18168717Seric 				if (TrafficLogFile != NULL && !headeronly)
18267599Seric 				{
18367599Seric 					if (istate == IS_BOL)
18467599Seric 						fprintf(TrafficLogFile, "%05d <<< ",
18567599Seric 							getpid());
18667599Seric 					if (c == EOF)
18767599Seric 						fprintf(TrafficLogFile, "[EOF]\n");
18867599Seric 					else
18967599Seric 						fputc(c, TrafficLogFile);
19067599Seric 				}
19167599Seric 				if (c == EOF)
19267599Seric 					goto readerr;
19367599Seric 				if (SevenBitInput)
19467599Seric 					c &= 0x7f;
19567599Seric 				else
19667599Seric 					HasEightBits |= bitset(0x80, c);
19768560Seric 				if (!headeronly)
19868560Seric 					e->e_msgsize++;
19967599Seric 			}
20067599Seric 			if (tTd(30, 94))
20167599Seric 				printf("istate=%d, c=%c (0x%x)\n",
20267599Seric 					istate, c, c);
20367599Seric 			switch (istate)
20467599Seric 			{
20567599Seric 			  case IS_BOL:
20667599Seric 				if (c == '.')
20767599Seric 				{
20867599Seric 					istate = IS_DOT;
20967599Seric 					continue;
21067599Seric 				}
21164916Seric 				break;
21240965Sbostic 
21367599Seric 			  case IS_DOT:
21467599Seric 				if (c == '\n' && !ignrdot &&
21567599Seric 				    !bitset(EF_NL_NOT_EOL, e->e_flags))
21667599Seric 					goto readerr;
21767599Seric 				else if (c == '\r' &&
21867599Seric 					 !bitset(EF_CRLF_NOT_EOL, e->e_flags))
21967599Seric 				{
22067599Seric 					istate = IS_DOTCR;
22167599Seric 					continue;
22267599Seric 				}
22367599Seric 				else if (c != '.' ||
22467599Seric 					 (OpMode != MD_SMTP &&
22567599Seric 					  OpMode != MD_DAEMON &&
22667599Seric 					  OpMode != MD_ARPAFTP))
22767599Seric 				{
22867599Seric 					*pbp++ = c;
22967599Seric 					c = '.';
23067599Seric 				}
2312900Seric 				break;
23240965Sbostic 
23367599Seric 			  case IS_DOTCR:
23467599Seric 				if (c == '\n')
23567599Seric 					goto readerr;
23667599Seric 				else
23767599Seric 				{
23867599Seric 					/* push back the ".\rx" */
23967599Seric 					*pbp++ = c;
24067599Seric 					*pbp++ = '\r';
24167599Seric 					c = '.';
24267599Seric 				}
24367599Seric 				break;
24440965Sbostic 
24567599Seric 			  case IS_CR:
24667689Seric 				if (c == '\n')
24767689Seric 					istate = IS_BOL;
24867689Seric 				else
24967599Seric 				{
25068717Seric 					ungetc(c, fp);
25167599Seric 					c = '\r';
25267689Seric 					istate = IS_NORM;
25367599Seric 				}
25467689Seric 				goto bufferchar;
25567599Seric 			}
25657135Seric 
25767689Seric 			if (c == '\r' && !bitset(EF_CRLF_NOT_EOL, e->e_flags))
25840965Sbostic 			{
25967599Seric 				istate = IS_CR;
26067599Seric 				continue;
26167599Seric 			}
26267599Seric 			else if (c == '\n' && !bitset(EF_NL_NOT_EOL, e->e_flags))
26367599Seric 				istate = IS_BOL;
26467599Seric 			else
26567599Seric 				istate = IS_NORM;
26640965Sbostic 
26767689Seric bufferchar:
26867599Seric 			if (mstate == MS_BODY)
26967599Seric 			{
27067599Seric 				/* just put the character out */
27167831Seric 				if (MaxMessageSize <= 0 ||
27267831Seric 				    e->e_msgsize <= MaxMessageSize)
27367831Seric 					fputc(c, tf);
27467599Seric 				continue;
27540965Sbostic 			}
2761392Seric 
27767599Seric 			/* header -- buffer up */
27867599Seric 			if (bp >= &buf[buflen - 2])
27967599Seric 			{
28067599Seric 				char *obuf;
2811392Seric 
28267599Seric 				if (mstate != MS_HEADER)
28367599Seric 					break;
28440965Sbostic 
28567599Seric 				/* out of space for header */
28667599Seric 				obuf = buf;
28767599Seric 				if (buflen < MEMCHUNKSIZE)
28867599Seric 					buflen *= 2;
28967599Seric 				else
29067599Seric 					buflen += MEMCHUNKSIZE;
29167599Seric 				buf = xalloc(buflen);
29267599Seric 				bcopy(obuf, buf, bp - obuf);
29367599Seric 				bp = &buf[bp - obuf];
29467599Seric 				if (obuf != bufbuf)
29567599Seric 					free(obuf);
29667599Seric 			}
29768738Seric 			if (c != '\0')
29868738Seric 				*bp++ = c;
29967599Seric 			if (istate == IS_BOL)
30067599Seric 				break;
30140965Sbostic 		}
30267599Seric 		*bp = '\0';
30340965Sbostic 
30467599Seric nextstate:
30567599Seric 		if (tTd(30, 35))
30667599Seric 			printf("nextstate, istate=%d, mstate=%d, line = \"%s\"\n",
30767599Seric 				istate, mstate, buf);
30867599Seric 		switch (mstate)
30967599Seric 		{
31068433Seric 			extern int chompheader();
31168433Seric 
31267599Seric 		  case MS_UFROM:
31367599Seric 			mstate = MS_HEADER;
31467599Seric 			if (strncmp(buf, "From ", 5) == 0)
31567599Seric 			{
31668433Seric 				extern void eatfrom();
31768433Seric 
31867704Seric 				bp = buf;
31967599Seric 				eatfrom(buf, e);
32067599Seric 				continue;
32167599Seric 			}
32267599Seric 			/* fall through */
3232900Seric 
32467599Seric 		  case MS_HEADER:
32567599Seric 			if (!isheader(buf))
32667599Seric 			{
32767599Seric 				mstate = MS_BODY;
32867599Seric 				goto nextstate;
32967599Seric 			}
33057135Seric 
33167599Seric 			/* check for possible continuation line */
33267599Seric 			do
33367599Seric 			{
33468717Seric 				clearerr(fp);
33567599Seric 				errno = 0;
33668717Seric 				c = fgetc(fp);
33767599Seric 			} while (errno == EINTR);
33867599Seric 			if (c != EOF)
33968717Seric 				ungetc(c, fp);
34067599Seric 			if (c == ' ' || c == '\t')
34167599Seric 			{
34267599Seric 				/* yep -- defer this */
34367599Seric 				continue;
34467599Seric 			}
34557135Seric 
34667599Seric 			/* trim off trailing CRLF or NL */
34767599Seric 			if (*--bp != '\n' || *--bp != '\r')
34867599Seric 				bp++;
34967599Seric 			*bp = '\0';
35068717Seric 			if (bitset(H_EOH, chompheader(buf, FALSE, hdrp, e)))
35167599Seric 				mstate = MS_BODY;
35267599Seric 			break;
3531392Seric 
35467599Seric 		  case MS_BODY:
35567599Seric 			if (tTd(30, 1))
35667599Seric 				printf("EOH\n");
35767599Seric 			if (headeronly)
35867599Seric 				goto readerr;
35967599Seric 			bp = buf;
3602900Seric 
36167599Seric 			/* toss blank line */
36267599Seric 			if ((!bitset(EF_CRLF_NOT_EOL, e->e_flags) &&
36367599Seric 				bp[0] == '\r' && bp[1] == '\n') ||
36467599Seric 			    (!bitset(EF_NL_NOT_EOL, e->e_flags) &&
36567599Seric 				bp[0] == '\n'))
36667599Seric 			{
36767599Seric 				break;
36867599Seric 			}
36967546Seric 
37067599Seric 			/* if not a blank separator, write it out */
37167831Seric 			if (MaxMessageSize <= 0 ||
37267831Seric 			    e->e_msgsize <= MaxMessageSize)
37367831Seric 			{
37467831Seric 				while (*bp != '\0')
37567831Seric 					fputc(*bp++, tf);
37667831Seric 			}
3772900Seric 			break;
37867599Seric 		}
37967599Seric 		bp = buf;
38064718Seric 	}
38140965Sbostic 
38267546Seric readerr:
38367546Seric 	if ((feof(fp) && smtpmode) || ferror(fp))
38464718Seric 	{
38564916Seric 		if (tTd(30, 1))
386*68837Seric 			printf("collect: %s\n", errstring(errno));
38764718Seric 		inputerr = TRUE;
38864718Seric 	}
38964718Seric 
39066765Seric 	/* reset global timer */
39167599Seric 	clrevent(CollectTimeout);
39266765Seric 
39367546Seric 	if (headeronly)
39467546Seric 		return;
39567546Seric 
39667546Seric 	if (tf != NULL)
39764762Seric 	{
39867546Seric 		if (fflush(tf) != 0)
39967546Seric 			tferror(tf, e);
40067546Seric 		if (fsync(fileno(tf)) < 0 || fclose(tf) < 0)
40167546Seric 		{
40267546Seric 			tferror(tf, e);
40367546Seric 			finis();
40467546Seric 		}
40564762Seric 	}
4062900Seric 
40768692Seric 	/* An EOF when running SMTP is an error */
40868692Seric 	if (inputerr && (OpMode == MD_SMTP || OpMode == MD_DAEMON))
40916136Seric 	{
41058308Seric 		char *host;
41164718Seric 		char *problem;
41258082Seric 
41358308Seric 		host = RealHostName;
41458308Seric 		if (host == NULL)
41558308Seric 			host = "localhost";
41658308Seric 
41767546Seric 		if (feof(fp))
41864718Seric 			problem = "unexpected close";
41967546Seric 		else if (ferror(fp))
42064718Seric 			problem = "I/O error";
42164718Seric 		else
42264718Seric 			problem = "read timeout";
42336233Skarels # ifdef LOG
42467546Seric 		if (LogLevel > 0 && feof(fp))
42536230Skarels 			syslog(LOG_NOTICE,
42666864Seric 			    "collect: %s on connection from %s, sender=%s: %s\n",
42766864Seric 			    problem, host, e->e_from.q_paddr, errstring(errno));
42836233Skarels # endif
42967546Seric 		if (feof(fp))
43065951Seric 			usrerr("451 collect: %s on connection from %s, from=%s",
43164718Seric 				problem, host, e->e_from.q_paddr);
43265951Seric 		else
43365951Seric 			syserr("451 collect: %s on connection from %s, from=%s",
43465951Seric 				problem, host, e->e_from.q_paddr);
43511145Seric 
43616136Seric 		/* don't return an error indication */
43755012Seric 		e->e_to = NULL;
43855012Seric 		e->e_flags &= ~EF_FATALERRS;
43964124Seric 		e->e_flags |= EF_CLRQUEUE;
44016136Seric 
44116136Seric 		/* and don't try to deliver the partial message either */
44264718Seric 		if (InChild)
44364718Seric 			ExitStat = EX_QUIT;
44416136Seric 		finis();
44516136Seric 	}
44616136Seric 
4472900Seric 	/*
4482900Seric 	**  Find out some information from the headers.
4493386Seric 	**	Examples are who is the from person & the date.
4502900Seric 	*/
4512900Seric 
45258929Seric 	eatheader(e, !requeueflag);
4537673Seric 
45464068Seric 	/* collect statistics */
45564068Seric 	if (OpMode != MD_VERIFY)
45668433Seric 	{
45768433Seric 		extern void markstats();
45868433Seric 
45964068Seric 		markstats(e, (ADDRESS *) NULL);
46068433Seric 	}
46164068Seric 
4627782Seric 	/*
4637782Seric 	**  Add an Apparently-To: line if we have no recipient lines.
4647782Seric 	*/
4654622Seric 
46667546Seric 	if (hvalue("to", e->e_header) == NULL &&
46767546Seric 	    hvalue("cc", e->e_header) == NULL &&
46867546Seric 	    hvalue("bcc", e->e_header) == NULL &&
46967546Seric 	    hvalue("apparently-to", e->e_header) == NULL)
4707367Seric 	{
4717367Seric 		register ADDRESS *q;
47268449Seric 		char *hdr = NULL;
47368449Seric 		extern void addheader();
4747367Seric 
4757367Seric 		/* create an Apparently-To: field */
4767367Seric 		/*    that or reject the message.... */
47768449Seric 		switch (NoRecipientAction)
4787367Seric 		{
47968449Seric 		  case NRA_ADD_APPARENTLY_TO:
48068449Seric 			hdr = "Apparently-To";
48168449Seric 			break;
48268433Seric 
48368449Seric 		  case NRA_ADD_TO:
48468449Seric 			hdr = "To";
48568449Seric 			break;
48668449Seric 
48768449Seric 		  case NRA_ADD_BCC:
48868449Seric 			addheader("Bcc", "", &e->e_header);
48968449Seric 			break;
49068449Seric 
49168449Seric 		  case NRA_ADD_TO_UNDISCLOSED:
49268449Seric 			addheader("To", "undisclosed-recipients:;", &e->e_header);
49368449Seric 			break;
4947367Seric 		}
49568449Seric 
49668449Seric 		if (hdr != NULL)
49768449Seric 		{
49868449Seric 			for (q = e->e_sendqueue; q != NULL; q = q->q_next)
49968449Seric 			{
50068449Seric 				if (q->q_alias != NULL)
50168449Seric 					continue;
50268449Seric 				if (tTd(30, 3))
50368449Seric 					printf("Adding %s: %s\n",
50468449Seric 						hdr, q->q_paddr);
50568449Seric 				addheader(hdr, q->q_paddr, &e->e_header);
50668449Seric 			}
50768449Seric 		}
5087367Seric 	}
5097367Seric 
51059320Seric 	/* check for message too large */
51159320Seric 	if (MaxMessageSize > 0 && e->e_msgsize > MaxMessageSize)
51259320Seric 	{
51359320Seric 		usrerr("552 Message exceeds maximum fixed size (%ld)",
51459320Seric 			MaxMessageSize);
51559320Seric 	}
51659320Seric 
51767547Seric 	/* check for illegal 8-bit data */
51867547Seric 	if (HasEightBits)
51967547Seric 	{
52067547Seric 		e->e_flags |= EF_HAS8BIT;
52167887Seric 		if (!bitset(MM_PASS8BIT|MM_MIME8BIT, MimeMode))
52267547Seric 			usrerr("554 Eight bit data not allowed");
52367547Seric 	}
52467547Seric 
52568564Seric 	if ((e->e_dfp = fopen(dfname, "r")) == NULL)
52658690Seric 	{
52758690Seric 		/* we haven't acked receipt yet, so just chuck this */
52868564Seric 		syserr("Cannot reopen %s", dfname);
52958690Seric 		finis();
53058690Seric 	}
5311392Seric }
53240965Sbostic 
53367599Seric 
53468433Seric static void
53567599Seric collecttimeout(timeout)
53667599Seric 	time_t timeout;
53740965Sbostic {
53867599Seric 	/* if no progress was made, die now */
53967599Seric 	if (!CollectProgress)
54067599Seric 		longjmp(CtxCollectTimeout, 1);
54140965Sbostic 
54267599Seric 	/* otherwise reset the timeout */
54367599Seric 	CollectTimeout = setevent(timeout, collecttimeout, timeout);
54467599Seric 	CollectProgress = FALSE;
54540965Sbostic }
54640965Sbostic /*
54711544Seric **  TFERROR -- signal error on writing the temporary file.
54811544Seric **
54911544Seric **	Parameters:
55011544Seric **		tf -- the file pointer for the temporary file.
55168692Seric **		e -- the current envelope.
55211544Seric **
55311544Seric **	Returns:
55411544Seric **		none.
55511544Seric **
55611544Seric **	Side Effects:
55711544Seric **		Gives an error message.
55811544Seric **		Arranges for following output to go elsewhere.
55911544Seric */
56011544Seric 
56168433Seric void
56255012Seric tferror(tf, e)
56311544Seric 	FILE *tf;
56455012Seric 	register ENVELOPE *e;
56511544Seric {
56611544Seric 	if (errno == ENOSPC)
56711544Seric 	{
56866782Seric 		struct stat st;
56966782Seric 		long avail;
57066782Seric 		long bsize;
57166782Seric 
57268559Seric 		e->e_flags |= EF_NO_BODY_RETN;
57366782Seric 		if (fstat(fileno(tf), &st) < 0)
57466782Seric 			st.st_size = 0;
57568564Seric 		(void) freopen(queuename(e, 'd'), "w", tf);
57666782Seric 		if (st.st_size <= 0)
57766782Seric 			fprintf(tf, "\n*** Mail could not be accepted");
57866782Seric 		else if (sizeof st.st_size > sizeof (long))
57966782Seric 			fprintf(tf, "\n*** Mail of at least %qd bytes could not be accepted\n",
58066782Seric 				st.st_size);
58166782Seric 		else
58266782Seric 			fprintf(tf, "\n*** Mail of at least %ld bytes could not be accepted\n",
58366782Seric 				st.st_size);
58466782Seric 		fprintf(tf, "*** at %s due to lack of disk space for temp file.\n",
58566782Seric 			MyHostName);
58666782Seric 		avail = freespace(QueueDir, &bsize);
58766782Seric 		if (avail > 0)
58866782Seric 		{
58966782Seric 			if (bsize > 1024)
59066782Seric 				avail *= bsize / 1024;
59166782Seric 			else if (bsize < 1024)
59266782Seric 				avail /= 1024 / bsize;
59366782Seric 			fprintf(tf, "*** Currently, %ld kilobytes are available for mail temp files.\n",
59466782Seric 				avail);
59566782Seric 		}
59668692Seric 		usrerr("452 Out of disk space for temp file");
59711544Seric 	}
59811544Seric 	else
59968692Seric 		syserr("collect: Cannot write tf%s", e->e_id);
60011544Seric 	(void) freopen("/dev/null", "w", tf);
60111544Seric }
60211544Seric /*
6032900Seric **  EATFROM -- chew up a UNIX style from line and process
6042900Seric **
6052900Seric **	This does indeed make some assumptions about the format
6062900Seric **	of UNIX messages.
6072900Seric **
6082900Seric **	Parameters:
6092900Seric **		fm -- the from line.
6102900Seric **
6112900Seric **	Returns:
6122900Seric **		none.
6132900Seric **
6142900Seric **	Side Effects:
6152900Seric **		extracts what information it can from the header,
6163386Seric **		such as the date.
6172900Seric */
6182900Seric 
6194321Seric # ifndef NOTUNIX
6204321Seric 
6214203Seric char	*DowList[] =
6224203Seric {
6234203Seric 	"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", NULL
6244203Seric };
6254203Seric 
6262900Seric char	*MonthList[] =
6272900Seric {
6282900Seric 	"Jan", "Feb", "Mar", "Apr", "May", "Jun",
6292900Seric 	"Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
6302900Seric 	NULL
6312900Seric };
6322900Seric 
63368433Seric void
63455012Seric eatfrom(fm, e)
6352900Seric 	char *fm;
63655012Seric 	register ENVELOPE *e;
6372900Seric {
6382900Seric 	register char *p;
6392900Seric 	register char **dt;
6402900Seric 
6417673Seric 	if (tTd(30, 2))
6424203Seric 		printf("eatfrom(%s)\n", fm);
6434203Seric 
6442900Seric 	/* find the date part */
6452900Seric 	p = fm;
6462900Seric 	while (*p != '\0')
6472900Seric 	{
6482900Seric 		/* skip a word */
6492900Seric 		while (*p != '\0' && *p != ' ')
65016896Seric 			p++;
6512900Seric 		while (*p == ' ')
65216896Seric 			p++;
65358050Seric 		if (!(isascii(*p) && isupper(*p)) ||
65458050Seric 		    p[3] != ' ' || p[13] != ':' || p[16] != ':')
6552900Seric 			continue;
6562900Seric 
6572900Seric 		/* we have a possible date */
6584203Seric 		for (dt = DowList; *dt != NULL; dt++)
6592900Seric 			if (strncmp(*dt, p, 3) == 0)
6602900Seric 				break;
6614203Seric 		if (*dt == NULL)
6624203Seric 			continue;
6632900Seric 
6644203Seric 		for (dt = MonthList; *dt != NULL; dt++)
6654203Seric 			if (strncmp(*dt, &p[4], 3) == 0)
6664203Seric 				break;
6672900Seric 		if (*dt != NULL)
6682900Seric 			break;
6692900Seric 	}
6702900Seric 
67160502Seric 	if (*p != '\0')
6722900Seric 	{
6733386Seric 		char *q;
6745366Seric 		extern char *arpadate();
6753386Seric 
6762900Seric 		/* we have found a date */
6773386Seric 		q = xalloc(25);
67823103Seric 		(void) strncpy(q, p, 25);
6793386Seric 		q[24] = '\0';
6805366Seric 		q = arpadate(q);
68155012Seric 		define('a', newstr(q), e);
6822900Seric 	}
6832900Seric }
6844321Seric 
68556795Seric # endif /* NOTUNIX */
686