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*67599Seric static char sccsid[] = "@(#)collect.c	8.19 (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 
45*67599Seric static jmp_buf	CtxCollectTimeout;
46*67599Seric static int	collecttimeout();
47*67599Seric static bool	CollectProgress;
48*67599Seric static EVENT	*CollectTimeout;
49*67599Seric 
50*67599Seric /* values for input state machine */
51*67599Seric #define IS_NORM		0	/* middle of line */
52*67599Seric #define IS_BOL		1	/* beginning of line */
53*67599Seric #define IS_DOT		2	/* read a dot at beginning of line */
54*67599Seric #define IS_DOTCR	3	/* read ".\r" at beginning of line */
55*67599Seric #define IS_CR		4	/* read a carriage return */
56*67599Seric 
57*67599Seric /* values for message state machine */
58*67599Seric #define MS_UFROM	0	/* reading Unix from line */
59*67599Seric #define MS_HEADER	1	/* reading message header */
60*67599Seric #define MS_BODY		2	/* reading message body */
61*67599Seric 
62*67599Seric 
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;
73*67599Seric 	register char *bp;
74*67599Seric 	register int c;
7564718Seric 	bool inputerr = FALSE;
7667546Seric 	bool headeronly = FALSE;
77*67599Seric 	char *buf;
78*67599Seric 	int buflen;
79*67599Seric 	int istate;
80*67599Seric 	int mstate;
81*67599Seric 	char *pbp;
82*67599Seric 	char peekbuf[8];
83*67599Seric 	char bufbuf[MAXLINE];
842900Seric 	extern char *hvalue();
85*67599Seric 	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 	{
10067546Seric 		e->e_df = queuename(e, 'd');
10167546Seric 		e->e_df = newstr(e->e_df);
10267546Seric 		if ((tf = dfopen(e->e_df, O_WRONLY|O_CREAT|O_TRUNC, FileMode)) == NULL)
10367546Seric 		{
10467546Seric 			syserr("Cannot create %s", e->e_df);
10567546Seric 			e->e_flags |= EF_NORETURN;
10667546Seric 			finis();
10767546Seric 		}
10867546Seric 		HasEightBits = FALSE;
1091392Seric 	}
1101392Seric 
1114316Seric 	/*
1124322Seric 	**  Tell ARPANET to go ahead.
1134322Seric 	*/
1144322Seric 
11552105Seric 	if (smtpmode)
11658151Seric 		message("354 Enter mail, end with \".\" on a line by itself");
1174322Seric 
1184322Seric 	/*
119*67599Seric 	**  Read the message.
120*67599Seric 	**
121*67599Seric 	**	This is done using two interleaved state machines.
122*67599Seric 	**	The input state machine is looking for things like
123*67599Seric 	**	hidden dots; the message state machine is handling
124*67599Seric 	**	the larger picture (e.g., header versus body).
1254316Seric 	*/
1264316Seric 
127*67599Seric 	buf = bp = bufbuf;
128*67599Seric 	buflen = sizeof bufbuf;
129*67599Seric 	pbp = peekbuf;
130*67599Seric 	istate = IS_BOL;
131*67599Seric 	mstate = SaveFrom ? MS_HEADER : MS_UFROM;
132*67599Seric 	CollectProgress = FALSE;
133*67599Seric 
134*67599Seric 	/* if transmitting binary, don't map NL to EOL */
135*67599Seric 	if (e->e_bodytype != NULL && strcasecmp(e->e_bodytype, "8BITMIME") == 0)
136*67599Seric 		e->e_flags |= EF_NL_NOT_EOL;
137*67599Seric 
138*67599Seric 	if (dbto != 0)
1392900Seric 	{
140*67599Seric 		/* handle possible input timeout */
141*67599Seric 		if (setjmp(CtxCollectTimeout) != 0)
142*67599Seric 		{
143*67599Seric #ifdef LOG
144*67599Seric 			syslog(LOG_NOTICE,
145*67599Seric 			    "timeout waiting for input from %s during message collect",
146*67599Seric 			    CurHostName ? CurHostName : "<local machine>");
147*67599Seric #endif
148*67599Seric 			errno = 0;
149*67599Seric 			usrerr("451 timeout waiting for input during message collect");
15040965Sbostic 			goto readerr;
151*67599Seric 		}
152*67599Seric 		CollectTimeout = setevent(dbto, collecttimeout, dbto);
1532900Seric 	}
1542900Seric 
15540965Sbostic 	for (;;)
1561392Seric 	{
157*67599Seric 		if (tTd(30, 35))
158*67599Seric 			printf("top, istate=%d, mstate=%d\n", istate, mstate);
15940965Sbostic 		for (;;)
1601392Seric 		{
161*67599Seric 			if (pbp > peekbuf)
162*67599Seric 				c = *--pbp;
163*67599Seric 			else
16464916Seric 			{
165*67599Seric 				while (!feof(InChannel) && !ferror(InChannel))
166*67599Seric 				{
167*67599Seric 					errno = 0;
168*67599Seric 					c = fgetc(InChannel);
169*67599Seric 					if (errno != EINTR)
170*67599Seric 						break;
171*67599Seric 					clearerr(InChannel);
172*67599Seric 				}
173*67599Seric 				CollectProgress = TRUE;
174*67599Seric 				if (TrafficLogFile != NULL)
175*67599Seric 				{
176*67599Seric 					if (istate == IS_BOL)
177*67599Seric 						fprintf(TrafficLogFile, "%05d <<< ",
178*67599Seric 							getpid());
179*67599Seric 					if (c == EOF)
180*67599Seric 						fprintf(TrafficLogFile, "[EOF]\n");
181*67599Seric 					else
182*67599Seric 						fputc(c, TrafficLogFile);
183*67599Seric 				}
184*67599Seric 				if (c == EOF)
185*67599Seric 					goto readerr;
186*67599Seric 				if (SevenBitInput)
187*67599Seric 					c &= 0x7f;
188*67599Seric 				else
189*67599Seric 					HasEightBits |= bitset(0x80, c);
190*67599Seric 				e->e_msgsize++;
191*67599Seric 			}
192*67599Seric 			if (tTd(30, 94))
193*67599Seric 				printf("istate=%d, c=%c (0x%x)\n",
194*67599Seric 					istate, c, c);
195*67599Seric 			switch (istate)
196*67599Seric 			{
197*67599Seric 			  case IS_BOL:
198*67599Seric 				if (c == '.')
199*67599Seric 				{
200*67599Seric 					istate = IS_DOT;
201*67599Seric 					continue;
202*67599Seric 				}
20364916Seric 				break;
20440965Sbostic 
205*67599Seric 			  case IS_DOT:
206*67599Seric 				if (c == '\n' && !ignrdot &&
207*67599Seric 				    !bitset(EF_NL_NOT_EOL, e->e_flags))
208*67599Seric 					goto readerr;
209*67599Seric 				else if (c == '\r' &&
210*67599Seric 					 !bitset(EF_CRLF_NOT_EOL, e->e_flags))
211*67599Seric 				{
212*67599Seric 					istate = IS_DOTCR;
213*67599Seric 					continue;
214*67599Seric 				}
215*67599Seric 				else if (c != '.' ||
216*67599Seric 					 (OpMode != MD_SMTP &&
217*67599Seric 					  OpMode != MD_DAEMON &&
218*67599Seric 					  OpMode != MD_ARPAFTP))
219*67599Seric 				{
220*67599Seric 					*pbp++ = c;
221*67599Seric 					c = '.';
222*67599Seric 				}
2232900Seric 				break;
22440965Sbostic 
225*67599Seric 			  case IS_DOTCR:
226*67599Seric 				if (c == '\n')
227*67599Seric 					goto readerr;
228*67599Seric 				else
229*67599Seric 				{
230*67599Seric 					/* push back the ".\rx" */
231*67599Seric 					*pbp++ = c;
232*67599Seric 					*pbp++ = '\r';
233*67599Seric 					c = '.';
234*67599Seric 				}
235*67599Seric 				break;
23640965Sbostic 
237*67599Seric 			  case IS_CR:
238*67599Seric 				if (c != '\n')
239*67599Seric 				{
240*67599Seric 					ungetc(c, InChannel);
241*67599Seric 					c = '\r';
242*67599Seric 				}
243*67599Seric 				else if (!bitset(EF_CRLF_NOT_EOL, e->e_flags))
244*67599Seric 					istate = IS_BOL;
245*67599Seric 				break;
246*67599Seric 			}
24757135Seric 
248*67599Seric 			if (c == '\r')
24940965Sbostic 			{
250*67599Seric 				istate = IS_CR;
251*67599Seric 				continue;
252*67599Seric 			}
253*67599Seric 			else if (c == '\n' && !bitset(EF_NL_NOT_EOL, e->e_flags))
254*67599Seric 				istate = IS_BOL;
255*67599Seric 			else
256*67599Seric 				istate = IS_NORM;
25740965Sbostic 
258*67599Seric 			if (mstate == MS_BODY)
259*67599Seric 			{
260*67599Seric 				/* just put the character out */
261*67599Seric 				fputc(c, tf);
262*67599Seric 				continue;
26340965Sbostic 			}
2641392Seric 
265*67599Seric 			/* header -- buffer up */
266*67599Seric 			if (bp >= &buf[buflen - 2])
267*67599Seric 			{
268*67599Seric 				char *obuf;
2691392Seric 
270*67599Seric 				if (mstate != MS_HEADER)
271*67599Seric 					break;
27240965Sbostic 
273*67599Seric 				/* out of space for header */
274*67599Seric 				obuf = buf;
275*67599Seric 				if (buflen < MEMCHUNKSIZE)
276*67599Seric 					buflen *= 2;
277*67599Seric 				else
278*67599Seric 					buflen += MEMCHUNKSIZE;
279*67599Seric 				buf = xalloc(buflen);
280*67599Seric 				bcopy(obuf, buf, bp - obuf);
281*67599Seric 				bp = &buf[bp - obuf];
282*67599Seric 				if (obuf != bufbuf)
283*67599Seric 					free(obuf);
284*67599Seric 			}
285*67599Seric 			*bp++ = c;
286*67599Seric 			if (istate == IS_BOL)
287*67599Seric 				break;
28840965Sbostic 		}
289*67599Seric 		*bp = '\0';
29040965Sbostic 
291*67599Seric nextstate:
292*67599Seric 		if (tTd(30, 35))
293*67599Seric 			printf("nextstate, istate=%d, mstate=%d, line = \"%s\"\n",
294*67599Seric 				istate, mstate, buf);
295*67599Seric 		switch (mstate)
296*67599Seric 		{
297*67599Seric 		  case MS_UFROM:
298*67599Seric 			mstate = MS_HEADER;
299*67599Seric 			if (strncmp(buf, "From ", 5) == 0)
300*67599Seric 			{
301*67599Seric 				eatfrom(buf, e);
302*67599Seric 				continue;
303*67599Seric 			}
304*67599Seric 			/* fall through */
3052900Seric 
306*67599Seric 		  case MS_HEADER:
307*67599Seric 			if (!isheader(buf))
308*67599Seric 			{
309*67599Seric 				mstate = MS_BODY;
310*67599Seric 				goto nextstate;
311*67599Seric 			}
31257135Seric 
313*67599Seric 			/* check for possible continuation line */
314*67599Seric 			do
315*67599Seric 			{
316*67599Seric 				clearerr(InChannel);
317*67599Seric 				errno = 0;
318*67599Seric 				c = fgetc(InChannel);
319*67599Seric 			} while (errno == EINTR);
320*67599Seric 			if (c != EOF)
321*67599Seric 				ungetc(c, InChannel);
322*67599Seric 			if (c == ' ' || c == '\t')
323*67599Seric 			{
324*67599Seric 				/* yep -- defer this */
325*67599Seric 				continue;
326*67599Seric 			}
32757135Seric 
328*67599Seric 			/* trim off trailing CRLF or NL */
329*67599Seric 			if (*--bp != '\n' || *--bp != '\r')
330*67599Seric 				bp++;
331*67599Seric 			*bp = '\0';
332*67599Seric 			if (bitset(H_EOH, chompheader(buf, FALSE, e)))
333*67599Seric 				mstate = MS_BODY;
334*67599Seric 			break;
3351392Seric 
336*67599Seric 		  case MS_BODY:
337*67599Seric 			if (tTd(30, 1))
338*67599Seric 				printf("EOH\n");
339*67599Seric 			if (headeronly)
340*67599Seric 				goto readerr;
341*67599Seric 			bp = buf;
3422900Seric 
343*67599Seric 			/* toss blank line */
344*67599Seric 			if ((!bitset(EF_CRLF_NOT_EOL, e->e_flags) &&
345*67599Seric 				bp[0] == '\r' && bp[1] == '\n') ||
346*67599Seric 			    (!bitset(EF_NL_NOT_EOL, e->e_flags) &&
347*67599Seric 				bp[0] == '\n'))
348*67599Seric 			{
349*67599Seric 				break;
350*67599Seric 			}
35167546Seric 
352*67599Seric 			/* if not a blank separator, write it out */
353*67599Seric 			while (*bp != '\0')
354*67599Seric 				fputc(*bp++, tf);
3552900Seric 			break;
356*67599Seric 		}
357*67599Seric 		bp = buf;
35864718Seric 	}
35940965Sbostic 
36067546Seric readerr:
36167546Seric 	if ((feof(fp) && smtpmode) || ferror(fp))
36264718Seric 	{
36364916Seric 		if (tTd(30, 1))
36464916Seric 			printf("collect: read error\n");
36564718Seric 		inputerr = TRUE;
36664718Seric 	}
36764718Seric 
36866765Seric 	/* reset global timer */
369*67599Seric 	clrevent(CollectTimeout);
37066765Seric 
37167546Seric 	if (headeronly)
37267546Seric 		return;
37367546Seric 
37467546Seric 	if (tf != NULL)
37564762Seric 	{
37667546Seric 		if (fflush(tf) != 0)
37767546Seric 			tferror(tf, e);
37867546Seric 		if (fsync(fileno(tf)) < 0 || fclose(tf) < 0)
37967546Seric 		{
38067546Seric 			tferror(tf, e);
38167546Seric 			finis();
38267546Seric 		}
38364762Seric 	}
3842900Seric 
38566796Seric 	if (CollectErrorMessage != NULL && Errors <= 0)
38616136Seric 	{
38766796Seric 		if (CollectErrno != 0)
38866796Seric 		{
38966796Seric 			errno = CollectErrno;
39066796Seric 			syserr(CollectErrorMessage, e->e_df);
39166796Seric 			finis();
39266796Seric 		}
39366796Seric 		usrerr(CollectErrorMessage);
39466796Seric 	}
39566796Seric 	else if (inputerr && (OpMode == MD_SMTP || OpMode == MD_DAEMON))
39666796Seric 	{
39766796Seric 		/* An EOF when running SMTP is an error */
39858308Seric 		char *host;
39964718Seric 		char *problem;
40058082Seric 
40158308Seric 		host = RealHostName;
40258308Seric 		if (host == NULL)
40358308Seric 			host = "localhost";
40458308Seric 
40567546Seric 		if (feof(fp))
40664718Seric 			problem = "unexpected close";
40767546Seric 		else if (ferror(fp))
40864718Seric 			problem = "I/O error";
40964718Seric 		else
41064718Seric 			problem = "read timeout";
41136233Skarels # ifdef LOG
41267546Seric 		if (LogLevel > 0 && feof(fp))
41336230Skarels 			syslog(LOG_NOTICE,
41466864Seric 			    "collect: %s on connection from %s, sender=%s: %s\n",
41566864Seric 			    problem, host, e->e_from.q_paddr, errstring(errno));
41636233Skarels # endif
41767546Seric 		if (feof(fp))
41865951Seric 			usrerr("451 collect: %s on connection from %s, from=%s",
41964718Seric 				problem, host, e->e_from.q_paddr);
42065951Seric 		else
42165951Seric 			syserr("451 collect: %s on connection from %s, from=%s",
42265951Seric 				problem, host, e->e_from.q_paddr);
42311145Seric 
42416136Seric 		/* don't return an error indication */
42555012Seric 		e->e_to = NULL;
42655012Seric 		e->e_flags &= ~EF_FATALERRS;
42764124Seric 		e->e_flags |= EF_CLRQUEUE;
42816136Seric 
42916136Seric 		/* and don't try to deliver the partial message either */
43064718Seric 		if (InChild)
43164718Seric 			ExitStat = EX_QUIT;
43216136Seric 		finis();
43316136Seric 	}
43416136Seric 
4352900Seric 	/*
4362900Seric 	**  Find out some information from the headers.
4373386Seric 	**	Examples are who is the from person & the date.
4382900Seric 	*/
4392900Seric 
44058929Seric 	eatheader(e, !requeueflag);
4417673Seric 
44264068Seric 	/* collect statistics */
44364068Seric 	if (OpMode != MD_VERIFY)
44464068Seric 		markstats(e, (ADDRESS *) NULL);
44564068Seric 
4467782Seric 	/*
4477782Seric 	**  Add an Apparently-To: line if we have no recipient lines.
4487782Seric 	*/
4494622Seric 
45067546Seric 	if (hvalue("to", e->e_header) == NULL &&
45167546Seric 	    hvalue("cc", e->e_header) == NULL &&
45267546Seric 	    hvalue("bcc", e->e_header) == NULL &&
45367546Seric 	    hvalue("apparently-to", e->e_header) == NULL)
4547367Seric 	{
4557367Seric 		register ADDRESS *q;
4567367Seric 
4577367Seric 		/* create an Apparently-To: field */
4587367Seric 		/*    that or reject the message.... */
45955012Seric 		for (q = e->e_sendqueue; q != NULL; q = q->q_next)
4607367Seric 		{
4617389Seric 			if (q->q_alias != NULL)
4627389Seric 				continue;
4637673Seric 			if (tTd(30, 3))
4647367Seric 				printf("Adding Apparently-To: %s\n", q->q_paddr);
46567546Seric 			addheader("Apparently-To", q->q_paddr, &e->e_header);
4667367Seric 		}
4677367Seric 	}
4687367Seric 
46959320Seric 	/* check for message too large */
47059320Seric 	if (MaxMessageSize > 0 && e->e_msgsize > MaxMessageSize)
47159320Seric 	{
47259320Seric 		usrerr("552 Message exceeds maximum fixed size (%ld)",
47359320Seric 			MaxMessageSize);
47459320Seric 	}
47559320Seric 
47667547Seric 	/* check for illegal 8-bit data */
47767547Seric 	if (HasEightBits)
47867547Seric 	{
47967547Seric 		e->e_flags |= EF_HAS8BIT;
48067547Seric 		if (bitset(MM_MIME8BIT, MimeMode))
48167547Seric 		{
48267547Seric 			/* convert it to MIME */
48367547Seric 			if (hvalue("MIME-Version", e->e_header) == NULL)
48467547Seric 			{
48567547Seric 				char mimebuf[20];
48667547Seric 
48767547Seric 				strcpy(mimebuf, "MIME-Version: 1.0");
48867547Seric 				chompheader(mimebuf, FALSE, e);
48967547Seric 			}
49067547Seric 			if (e->e_bodytype == NULL)
49167547Seric 				e->e_bodytype = "8BITMIME";
49267547Seric 		}
49367547Seric 		else if (!bitset(MM_PASS8BIT, MimeMode))
49467547Seric 			usrerr("554 Eight bit data not allowed");
49567547Seric 	}
49667547Seric 
49755012Seric 	if ((e->e_dfp = fopen(e->e_df, "r")) == NULL)
49858690Seric 	{
49958690Seric 		/* we haven't acked receipt yet, so just chuck this */
50055012Seric 		syserr("Cannot reopen %s", e->e_df);
50158690Seric 		finis();
50258690Seric 	}
5031392Seric }
50440965Sbostic 
505*67599Seric 
506*67599Seric static
507*67599Seric collecttimeout(timeout)
508*67599Seric 	time_t timeout;
50940965Sbostic {
510*67599Seric 	/* if no progress was made, die now */
511*67599Seric 	if (!CollectProgress)
512*67599Seric 		longjmp(CtxCollectTimeout, 1);
51340965Sbostic 
514*67599Seric 	/* otherwise reset the timeout */
515*67599Seric 	CollectTimeout = setevent(timeout, collecttimeout, timeout);
516*67599Seric 	CollectProgress = FALSE;
51740965Sbostic }
51840965Sbostic /*
51911544Seric **  TFERROR -- signal error on writing the temporary file.
52011544Seric **
52111544Seric **	Parameters:
52211544Seric **		tf -- the file pointer for the temporary file.
52311544Seric **
52411544Seric **	Returns:
52511544Seric **		none.
52611544Seric **
52711544Seric **	Side Effects:
52811544Seric **		Gives an error message.
52911544Seric **		Arranges for following output to go elsewhere.
53011544Seric */
53111544Seric 
53255012Seric tferror(tf, e)
53311544Seric 	FILE *tf;
53455012Seric 	register ENVELOPE *e;
53511544Seric {
53666796Seric 	CollectErrno = errno;
53711544Seric 	if (errno == ENOSPC)
53811544Seric 	{
53966782Seric 		struct stat st;
54066782Seric 		long avail;
54166782Seric 		long bsize;
54266782Seric 
54367473Seric 		e->e_flags |= EF_NORETURN;
54466782Seric 		if (fstat(fileno(tf), &st) < 0)
54566782Seric 			st.st_size = 0;
54655012Seric 		(void) freopen(e->e_df, "w", tf);
54766782Seric 		if (st.st_size <= 0)
54866782Seric 			fprintf(tf, "\n*** Mail could not be accepted");
54966782Seric 		else if (sizeof st.st_size > sizeof (long))
55066782Seric 			fprintf(tf, "\n*** Mail of at least %qd bytes could not be accepted\n",
55166782Seric 				st.st_size);
55266782Seric 		else
55366782Seric 			fprintf(tf, "\n*** Mail of at least %ld bytes could not be accepted\n",
55466782Seric 				st.st_size);
55566782Seric 		fprintf(tf, "*** at %s due to lack of disk space for temp file.\n",
55666782Seric 			MyHostName);
55766782Seric 		avail = freespace(QueueDir, &bsize);
55866782Seric 		if (avail > 0)
55966782Seric 		{
56066782Seric 			if (bsize > 1024)
56166782Seric 				avail *= bsize / 1024;
56266782Seric 			else if (bsize < 1024)
56366782Seric 				avail /= 1024 / bsize;
56466782Seric 			fprintf(tf, "*** Currently, %ld kilobytes are available for mail temp files.\n",
56566782Seric 				avail);
56666782Seric 		}
56766796Seric 		CollectErrorMessage = "452 Out of disk space for temp file";
56811544Seric 	}
56911544Seric 	else
57066796Seric 	{
57166796Seric 		CollectErrorMessage = "cannot write message body to disk (%s)";
57266796Seric 	}
57311544Seric 	(void) freopen("/dev/null", "w", tf);
57411544Seric }
57511544Seric /*
5762900Seric **  EATFROM -- chew up a UNIX style from line and process
5772900Seric **
5782900Seric **	This does indeed make some assumptions about the format
5792900Seric **	of UNIX messages.
5802900Seric **
5812900Seric **	Parameters:
5822900Seric **		fm -- the from line.
5832900Seric **
5842900Seric **	Returns:
5852900Seric **		none.
5862900Seric **
5872900Seric **	Side Effects:
5882900Seric **		extracts what information it can from the header,
5893386Seric **		such as the date.
5902900Seric */
5912900Seric 
5924321Seric # ifndef NOTUNIX
5934321Seric 
5944203Seric char	*DowList[] =
5954203Seric {
5964203Seric 	"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", NULL
5974203Seric };
5984203Seric 
5992900Seric char	*MonthList[] =
6002900Seric {
6012900Seric 	"Jan", "Feb", "Mar", "Apr", "May", "Jun",
6022900Seric 	"Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
6032900Seric 	NULL
6042900Seric };
6052900Seric 
60655012Seric eatfrom(fm, e)
6072900Seric 	char *fm;
60855012Seric 	register ENVELOPE *e;
6092900Seric {
6102900Seric 	register char *p;
6112900Seric 	register char **dt;
6122900Seric 
6137673Seric 	if (tTd(30, 2))
6144203Seric 		printf("eatfrom(%s)\n", fm);
6154203Seric 
6162900Seric 	/* find the date part */
6172900Seric 	p = fm;
6182900Seric 	while (*p != '\0')
6192900Seric 	{
6202900Seric 		/* skip a word */
6212900Seric 		while (*p != '\0' && *p != ' ')
62216896Seric 			p++;
6232900Seric 		while (*p == ' ')
62416896Seric 			p++;
62558050Seric 		if (!(isascii(*p) && isupper(*p)) ||
62658050Seric 		    p[3] != ' ' || p[13] != ':' || p[16] != ':')
6272900Seric 			continue;
6282900Seric 
6292900Seric 		/* we have a possible date */
6304203Seric 		for (dt = DowList; *dt != NULL; dt++)
6312900Seric 			if (strncmp(*dt, p, 3) == 0)
6322900Seric 				break;
6334203Seric 		if (*dt == NULL)
6344203Seric 			continue;
6352900Seric 
6364203Seric 		for (dt = MonthList; *dt != NULL; dt++)
6374203Seric 			if (strncmp(*dt, &p[4], 3) == 0)
6384203Seric 				break;
6392900Seric 		if (*dt != NULL)
6402900Seric 			break;
6412900Seric 	}
6422900Seric 
64360502Seric 	if (*p != '\0')
6442900Seric 	{
6453386Seric 		char *q;
6465366Seric 		extern char *arpadate();
6473386Seric 
6482900Seric 		/* we have found a date */
6493386Seric 		q = xalloc(25);
65023103Seric 		(void) strncpy(q, p, 25);
6513386Seric 		q[24] = '\0';
6525366Seric 		q = arpadate(q);
65355012Seric 		define('a', newstr(q), e);
6542900Seric 	}
6552900Seric }
6564321Seric 
65756795Seric # endif /* NOTUNIX */
658