xref: /freebsd/contrib/sendmail/src/collect.c (revision 602a2b1b1d5877cb573baf0407540810a490b0cf)
1c2aa98e2SPeter Wemm /*
2602a2b1bSGregory Neil Shapiro  * Copyright (c) 1998-2001 Sendmail, Inc. and its suppliers.
306f25ae9SGregory Neil Shapiro  *	All rights reserved.
4c2aa98e2SPeter Wemm  * Copyright (c) 1983, 1995-1997 Eric P. Allman.  All rights reserved.
5c2aa98e2SPeter Wemm  * Copyright (c) 1988, 1993
6c2aa98e2SPeter Wemm  *	The Regents of the University of California.  All rights reserved.
7c2aa98e2SPeter Wemm  *
8c2aa98e2SPeter Wemm  * By using this file, you agree to the terms and conditions set
9c2aa98e2SPeter Wemm  * forth in the LICENSE file which can be found at the top level of
10c2aa98e2SPeter Wemm  * the sendmail distribution.
11c2aa98e2SPeter Wemm  *
12c2aa98e2SPeter Wemm  */
13c2aa98e2SPeter Wemm 
14c2aa98e2SPeter Wemm #ifndef lint
15602a2b1bSGregory Neil Shapiro static char id[] = "@(#)$Id: collect.c,v 8.136.4.15 2001/02/21 01:05:59 gshapiro Exp $";
1606f25ae9SGregory Neil Shapiro #endif /* ! lint */
17c2aa98e2SPeter Wemm 
1806f25ae9SGregory Neil Shapiro #include <sendmail.h>
19c2aa98e2SPeter Wemm 
2006f25ae9SGregory Neil Shapiro 
2106f25ae9SGregory Neil Shapiro static void	collecttimeout __P((time_t));
2206f25ae9SGregory Neil Shapiro static void	dferror __P((FILE *volatile, char *, ENVELOPE *));
2306f25ae9SGregory Neil Shapiro static void	eatfrom __P((char *volatile, ENVELOPE *));
2406f25ae9SGregory Neil Shapiro 
2506f25ae9SGregory Neil Shapiro /*
26c2aa98e2SPeter Wemm **  COLLECT -- read & parse message header & make temp file.
27c2aa98e2SPeter Wemm **
28c2aa98e2SPeter Wemm **	Creates a temporary file name and copies the standard
29c2aa98e2SPeter Wemm **	input to that file.  Leading UNIX-style "From" lines are
30c2aa98e2SPeter Wemm **	stripped off (after important information is extracted).
31c2aa98e2SPeter Wemm **
32c2aa98e2SPeter Wemm **	Parameters:
33c2aa98e2SPeter Wemm **		fp -- file to read.
34c2aa98e2SPeter Wemm **		smtpmode -- if set, we are running SMTP: give an RFC821
35c2aa98e2SPeter Wemm **			style message to say we are ready to collect
36c2aa98e2SPeter Wemm **			input, and never ignore a single dot to mean
37c2aa98e2SPeter Wemm **			end of message.
38c2aa98e2SPeter Wemm **		hdrp -- the location to stash the header.
39c2aa98e2SPeter Wemm **		e -- the current envelope.
40c2aa98e2SPeter Wemm **
41c2aa98e2SPeter Wemm **	Returns:
42c2aa98e2SPeter Wemm **		none.
43c2aa98e2SPeter Wemm **
44c2aa98e2SPeter Wemm **	Side Effects:
45c2aa98e2SPeter Wemm **		Temp file is created and filled.
46c2aa98e2SPeter Wemm **		The from person may be set.
47c2aa98e2SPeter Wemm */
48c2aa98e2SPeter Wemm 
49c2aa98e2SPeter Wemm static jmp_buf	CtxCollectTimeout;
50c2aa98e2SPeter Wemm static bool	CollectProgress;
51c2aa98e2SPeter Wemm static EVENT	*CollectTimeout;
52c2aa98e2SPeter Wemm 
53c2aa98e2SPeter Wemm /* values for input state machine */
54c2aa98e2SPeter Wemm #define IS_NORM		0	/* middle of line */
55c2aa98e2SPeter Wemm #define IS_BOL		1	/* beginning of line */
56c2aa98e2SPeter Wemm #define IS_DOT		2	/* read a dot at beginning of line */
57c2aa98e2SPeter Wemm #define IS_DOTCR	3	/* read ".\r" at beginning of line */
58c2aa98e2SPeter Wemm #define IS_CR		4	/* read a carriage return */
59c2aa98e2SPeter Wemm 
60c2aa98e2SPeter Wemm /* values for message state machine */
61c2aa98e2SPeter Wemm #define MS_UFROM	0	/* reading Unix from line */
62c2aa98e2SPeter Wemm #define MS_HEADER	1	/* reading message header */
63c2aa98e2SPeter Wemm #define MS_BODY		2	/* reading message body */
6425bab6e9SPeter Wemm #define MS_DISCARD	3	/* discarding rest of message */
65c2aa98e2SPeter Wemm 
66c2aa98e2SPeter Wemm void
67c2aa98e2SPeter Wemm collect(fp, smtpmode, hdrp, e)
68c2aa98e2SPeter Wemm 	FILE *fp;
69c2aa98e2SPeter Wemm 	bool smtpmode;
70c2aa98e2SPeter Wemm 	HDR **hdrp;
71c2aa98e2SPeter Wemm 	register ENVELOPE *e;
72c2aa98e2SPeter Wemm {
7306f25ae9SGregory Neil Shapiro 	register FILE *volatile df;
74c2aa98e2SPeter Wemm 	volatile bool ignrdot = smtpmode ? FALSE : IgnrDot;
75c2aa98e2SPeter Wemm 	volatile time_t dbto = smtpmode ? TimeOuts.to_datablock : 0;
76c2aa98e2SPeter Wemm 	register char *volatile bp;
77c2aa98e2SPeter Wemm 	volatile int c = EOF;
78c2aa98e2SPeter Wemm 	volatile bool inputerr = FALSE;
79c2aa98e2SPeter Wemm 	bool headeronly;
80c2aa98e2SPeter Wemm 	char *volatile buf;
81c2aa98e2SPeter Wemm 	volatile int buflen;
82c2aa98e2SPeter Wemm 	volatile int istate;
83c2aa98e2SPeter Wemm 	volatile int mstate;
8406f25ae9SGregory Neil Shapiro 	volatile int hdrslen = 0;
8506f25ae9SGregory Neil Shapiro 	volatile int numhdrs = 0;
8606f25ae9SGregory Neil Shapiro 	volatile int dfd;
8706f25ae9SGregory Neil Shapiro 	volatile int rstat = EX_OK;
88c2aa98e2SPeter Wemm 	u_char *volatile pbp;
89c2aa98e2SPeter Wemm 	u_char peekbuf[8];
9006f25ae9SGregory Neil Shapiro 	char hsize[16];
9106f25ae9SGregory Neil Shapiro 	char hnum[16];
9206f25ae9SGregory Neil Shapiro 	char dfname[MAXPATHLEN];
93c2aa98e2SPeter Wemm 	char bufbuf[MAXLINE];
94c2aa98e2SPeter Wemm 
95c2aa98e2SPeter Wemm 	headeronly = hdrp != NULL;
96c2aa98e2SPeter Wemm 
97c2aa98e2SPeter Wemm 	/*
98c2aa98e2SPeter Wemm 	**  Create the temp file name and create the file.
99c2aa98e2SPeter Wemm 	*/
100c2aa98e2SPeter Wemm 
101c2aa98e2SPeter Wemm 	if (!headeronly)
102c2aa98e2SPeter Wemm 	{
103c2aa98e2SPeter Wemm 		struct stat stbuf;
104602a2b1bSGregory Neil Shapiro 		long sff = SFF_OPENASROOT;
105602a2b1bSGregory Neil Shapiro 
106c2aa98e2SPeter Wemm 
10706f25ae9SGregory Neil Shapiro 		(void) strlcpy(dfname, queuename(e, 'd'), sizeof dfname);
10806f25ae9SGregory Neil Shapiro #if _FFR_QUEUE_FILE_MODE
10906f25ae9SGregory Neil Shapiro 		{
11006f25ae9SGregory Neil Shapiro 			MODE_T oldumask;
11106f25ae9SGregory Neil Shapiro 
11206f25ae9SGregory Neil Shapiro 			if (bitset(S_IWGRP, QueueFileMode))
11306f25ae9SGregory Neil Shapiro 				oldumask = umask(002);
114602a2b1bSGregory Neil Shapiro 			df = bfopen(dfname, QueueFileMode,
115602a2b1bSGregory Neil Shapiro 				    DataFileBufferSize, sff);
11606f25ae9SGregory Neil Shapiro 			if (bitset(S_IWGRP, QueueFileMode))
11706f25ae9SGregory Neil Shapiro 				(void) umask(oldumask);
11806f25ae9SGregory Neil Shapiro 		}
11906f25ae9SGregory Neil Shapiro #else /* _FFR_QUEUE_FILE_MODE */
120602a2b1bSGregory Neil Shapiro 		df = bfopen(dfname, FileMode, DataFileBufferSize, sff);
12106f25ae9SGregory Neil Shapiro #endif /* _FFR_QUEUE_FILE_MODE */
12206f25ae9SGregory Neil Shapiro 		if (df == NULL)
123c2aa98e2SPeter Wemm 		{
124602a2b1bSGregory Neil Shapiro 			HoldErrs = FALSE;
125602a2b1bSGregory Neil Shapiro 			if (smtpmode)
126602a2b1bSGregory Neil Shapiro 				syserr("421 4.3.5 Unable to create data file");
127602a2b1bSGregory Neil Shapiro 			else
128c2aa98e2SPeter Wemm 				syserr("Cannot create %s", dfname);
129c2aa98e2SPeter Wemm 			e->e_flags |= EF_NO_BODY_RETN;
130065a643dSPeter Wemm 			finis(TRUE, ExitStat);
13106f25ae9SGregory Neil Shapiro 			/* NOTREACHED */
132c2aa98e2SPeter Wemm 		}
13306f25ae9SGregory Neil Shapiro 		dfd = fileno(df);
13406f25ae9SGregory Neil Shapiro 		if (dfd < 0 || fstat(dfd, &stbuf) < 0)
135c2aa98e2SPeter Wemm 			e->e_dfino = -1;
136c2aa98e2SPeter Wemm 		else
137c2aa98e2SPeter Wemm 		{
138c2aa98e2SPeter Wemm 			e->e_dfdev = stbuf.st_dev;
139c2aa98e2SPeter Wemm 			e->e_dfino = stbuf.st_ino;
140c2aa98e2SPeter Wemm 		}
141c2aa98e2SPeter Wemm 		HasEightBits = FALSE;
142c2aa98e2SPeter Wemm 		e->e_msgsize = 0;
143c2aa98e2SPeter Wemm 		e->e_flags |= EF_HAS_DF;
144c2aa98e2SPeter Wemm 	}
145c2aa98e2SPeter Wemm 
146c2aa98e2SPeter Wemm 	/*
147c2aa98e2SPeter Wemm 	**  Tell ARPANET to go ahead.
148c2aa98e2SPeter Wemm 	*/
149c2aa98e2SPeter Wemm 
150c2aa98e2SPeter Wemm 	if (smtpmode)
151c2aa98e2SPeter Wemm 		message("354 Enter mail, end with \".\" on a line by itself");
152c2aa98e2SPeter Wemm 
153c2aa98e2SPeter Wemm 	if (tTd(30, 2))
15406f25ae9SGregory Neil Shapiro 		dprintf("collect\n");
155c2aa98e2SPeter Wemm 
156c2aa98e2SPeter Wemm 	/*
157c2aa98e2SPeter Wemm 	**  Read the message.
158c2aa98e2SPeter Wemm 	**
159c2aa98e2SPeter Wemm 	**	This is done using two interleaved state machines.
160c2aa98e2SPeter Wemm 	**	The input state machine is looking for things like
161c2aa98e2SPeter Wemm 	**	hidden dots; the message state machine is handling
162c2aa98e2SPeter Wemm 	**	the larger picture (e.g., header versus body).
163c2aa98e2SPeter Wemm 	*/
164c2aa98e2SPeter Wemm 
165c2aa98e2SPeter Wemm 	buf = bp = bufbuf;
166c2aa98e2SPeter Wemm 	buflen = sizeof bufbuf;
167c2aa98e2SPeter Wemm 	pbp = peekbuf;
168c2aa98e2SPeter Wemm 	istate = IS_BOL;
169c2aa98e2SPeter Wemm 	mstate = SaveFrom ? MS_HEADER : MS_UFROM;
170c2aa98e2SPeter Wemm 	CollectProgress = FALSE;
171c2aa98e2SPeter Wemm 
172c2aa98e2SPeter Wemm 	if (dbto != 0)
173c2aa98e2SPeter Wemm 	{
174c2aa98e2SPeter Wemm 		/* handle possible input timeout */
175c2aa98e2SPeter Wemm 		if (setjmp(CtxCollectTimeout) != 0)
176c2aa98e2SPeter Wemm 		{
177c2aa98e2SPeter Wemm 			if (LogLevel > 2)
178c2aa98e2SPeter Wemm 				sm_syslog(LOG_NOTICE, e->e_id,
179c2aa98e2SPeter Wemm 				    "timeout waiting for input from %s during message collect",
180c2aa98e2SPeter Wemm 				    CurHostName ? CurHostName : "<local machine>");
181c2aa98e2SPeter Wemm 			errno = 0;
18206f25ae9SGregory Neil Shapiro 			usrerr("451 4.4.1 timeout waiting for input during message collect");
183c2aa98e2SPeter Wemm 			goto readerr;
184c2aa98e2SPeter Wemm 		}
185c2aa98e2SPeter Wemm 		CollectTimeout = setevent(dbto, collecttimeout, dbto);
186c2aa98e2SPeter Wemm 	}
187c2aa98e2SPeter Wemm 
188c2aa98e2SPeter Wemm 	for (;;)
189c2aa98e2SPeter Wemm 	{
190c2aa98e2SPeter Wemm 		if (tTd(30, 35))
19106f25ae9SGregory Neil Shapiro 			dprintf("top, istate=%d, mstate=%d\n", istate, mstate);
192c2aa98e2SPeter Wemm 		for (;;)
193c2aa98e2SPeter Wemm 		{
194c2aa98e2SPeter Wemm 			if (pbp > peekbuf)
195c2aa98e2SPeter Wemm 				c = *--pbp;
196c2aa98e2SPeter Wemm 			else
197c2aa98e2SPeter Wemm 			{
198c2aa98e2SPeter Wemm 				while (!feof(fp) && !ferror(fp))
199c2aa98e2SPeter Wemm 				{
200c2aa98e2SPeter Wemm 					errno = 0;
201c2aa98e2SPeter Wemm 					c = getc(fp);
20242e5d165SGregory Neil Shapiro 
20342e5d165SGregory Neil Shapiro 					if (c == EOF && errno == EINTR)
20442e5d165SGregory Neil Shapiro 					{
20542e5d165SGregory Neil Shapiro 						/* Interrupted, retry */
206c2aa98e2SPeter Wemm 						clearerr(fp);
20742e5d165SGregory Neil Shapiro 						continue;
20842e5d165SGregory Neil Shapiro 					}
20942e5d165SGregory Neil Shapiro 					break;
210c2aa98e2SPeter Wemm 				}
211c2aa98e2SPeter Wemm 				CollectProgress = TRUE;
212c2aa98e2SPeter Wemm 				if (TrafficLogFile != NULL && !headeronly)
213c2aa98e2SPeter Wemm 				{
214c2aa98e2SPeter Wemm 					if (istate == IS_BOL)
21506f25ae9SGregory Neil Shapiro 						(void) fprintf(TrafficLogFile, "%05d <<< ",
216c2aa98e2SPeter Wemm 							(int) getpid());
217c2aa98e2SPeter Wemm 					if (c == EOF)
21806f25ae9SGregory Neil Shapiro 						(void) fprintf(TrafficLogFile, "[EOF]\n");
219c2aa98e2SPeter Wemm 					else
22006f25ae9SGregory Neil Shapiro 						(void) putc(c, TrafficLogFile);
221c2aa98e2SPeter Wemm 				}
222c2aa98e2SPeter Wemm 				if (c == EOF)
223c2aa98e2SPeter Wemm 					goto readerr;
224c2aa98e2SPeter Wemm 				if (SevenBitInput)
225c2aa98e2SPeter Wemm 					c &= 0x7f;
226c2aa98e2SPeter Wemm 				else
227c2aa98e2SPeter Wemm 					HasEightBits |= bitset(0x80, c);
228c2aa98e2SPeter Wemm 			}
229c2aa98e2SPeter Wemm 			if (tTd(30, 94))
23006f25ae9SGregory Neil Shapiro 				dprintf("istate=%d, c=%c (0x%x)\n",
23106f25ae9SGregory Neil Shapiro 					istate, (char) c, c);
232c2aa98e2SPeter Wemm 			switch (istate)
233c2aa98e2SPeter Wemm 			{
234c2aa98e2SPeter Wemm 			  case IS_BOL:
235c2aa98e2SPeter Wemm 				if (c == '.')
236c2aa98e2SPeter Wemm 				{
237c2aa98e2SPeter Wemm 					istate = IS_DOT;
238c2aa98e2SPeter Wemm 					continue;
239c2aa98e2SPeter Wemm 				}
240c2aa98e2SPeter Wemm 				break;
241c2aa98e2SPeter Wemm 
242c2aa98e2SPeter Wemm 			  case IS_DOT:
243c2aa98e2SPeter Wemm 				if (c == '\n' && !ignrdot &&
244c2aa98e2SPeter Wemm 				    !bitset(EF_NL_NOT_EOL, e->e_flags))
245c2aa98e2SPeter Wemm 					goto readerr;
246c2aa98e2SPeter Wemm 				else if (c == '\r' &&
247c2aa98e2SPeter Wemm 					 !bitset(EF_CRLF_NOT_EOL, e->e_flags))
248c2aa98e2SPeter Wemm 				{
249c2aa98e2SPeter Wemm 					istate = IS_DOTCR;
250c2aa98e2SPeter Wemm 					continue;
251c2aa98e2SPeter Wemm 				}
252c2aa98e2SPeter Wemm 				else if (c != '.' ||
253c2aa98e2SPeter Wemm 					 (OpMode != MD_SMTP &&
254c2aa98e2SPeter Wemm 					  OpMode != MD_DAEMON &&
255c2aa98e2SPeter Wemm 					  OpMode != MD_ARPAFTP))
256c2aa98e2SPeter Wemm 				{
257c2aa98e2SPeter Wemm 					*pbp++ = c;
258c2aa98e2SPeter Wemm 					c = '.';
259c2aa98e2SPeter Wemm 				}
260c2aa98e2SPeter Wemm 				break;
261c2aa98e2SPeter Wemm 
262c2aa98e2SPeter Wemm 			  case IS_DOTCR:
263c2aa98e2SPeter Wemm 				if (c == '\n' && !ignrdot)
264c2aa98e2SPeter Wemm 					goto readerr;
265c2aa98e2SPeter Wemm 				else
266c2aa98e2SPeter Wemm 				{
267c2aa98e2SPeter Wemm 					/* push back the ".\rx" */
268c2aa98e2SPeter Wemm 					*pbp++ = c;
269c2aa98e2SPeter Wemm 					*pbp++ = '\r';
270c2aa98e2SPeter Wemm 					c = '.';
271c2aa98e2SPeter Wemm 				}
272c2aa98e2SPeter Wemm 				break;
273c2aa98e2SPeter Wemm 
274c2aa98e2SPeter Wemm 			  case IS_CR:
275c2aa98e2SPeter Wemm 				if (c == '\n')
276c2aa98e2SPeter Wemm 					istate = IS_BOL;
277c2aa98e2SPeter Wemm 				else
278c2aa98e2SPeter Wemm 				{
27906f25ae9SGregory Neil Shapiro 					(void) ungetc(c, fp);
280c2aa98e2SPeter Wemm 					c = '\r';
281c2aa98e2SPeter Wemm 					istate = IS_NORM;
282c2aa98e2SPeter Wemm 				}
283c2aa98e2SPeter Wemm 				goto bufferchar;
284c2aa98e2SPeter Wemm 			}
285c2aa98e2SPeter Wemm 
286c2aa98e2SPeter Wemm 			if (c == '\r' && !bitset(EF_CRLF_NOT_EOL, e->e_flags))
287c2aa98e2SPeter Wemm 			{
288c2aa98e2SPeter Wemm 				istate = IS_CR;
289c2aa98e2SPeter Wemm 				continue;
290c2aa98e2SPeter Wemm 			}
291c2aa98e2SPeter Wemm 			else if (c == '\n' && !bitset(EF_NL_NOT_EOL, e->e_flags))
292c2aa98e2SPeter Wemm 				istate = IS_BOL;
293c2aa98e2SPeter Wemm 			else
294c2aa98e2SPeter Wemm 				istate = IS_NORM;
295c2aa98e2SPeter Wemm 
296c2aa98e2SPeter Wemm bufferchar:
297c2aa98e2SPeter Wemm 			if (!headeronly)
29842e5d165SGregory Neil Shapiro 			{
29942e5d165SGregory Neil Shapiro 				/* no overflow? */
30042e5d165SGregory Neil Shapiro 				if (e->e_msgsize >= 0)
30142e5d165SGregory Neil Shapiro 				{
302c2aa98e2SPeter Wemm 					e->e_msgsize++;
30342e5d165SGregory Neil Shapiro 					if (MaxMessageSize > 0 &&
30442e5d165SGregory Neil Shapiro 					    !bitset(EF_TOOBIG, e->e_flags) &&
30542e5d165SGregory Neil Shapiro 					    e->e_msgsize > MaxMessageSize)
30642e5d165SGregory Neil Shapiro 						 e->e_flags |= EF_TOOBIG;
30742e5d165SGregory Neil Shapiro 				}
30842e5d165SGregory Neil Shapiro 			}
30925bab6e9SPeter Wemm 			switch (mstate)
310c2aa98e2SPeter Wemm 			{
31125bab6e9SPeter Wemm 			  case MS_BODY:
312c2aa98e2SPeter Wemm 				/* just put the character out */
31342e5d165SGregory Neil Shapiro 				if (!bitset(EF_TOOBIG, e->e_flags))
31406f25ae9SGregory Neil Shapiro 					(void) putc(c, df);
31525bab6e9SPeter Wemm 
31606f25ae9SGregory Neil Shapiro 				/* FALLTHROUGH */
31725bab6e9SPeter Wemm 
31825bab6e9SPeter Wemm 			  case MS_DISCARD:
319c2aa98e2SPeter Wemm 				continue;
320c2aa98e2SPeter Wemm 			}
321c2aa98e2SPeter Wemm 
322c2aa98e2SPeter Wemm 			/* header -- buffer up */
323c2aa98e2SPeter Wemm 			if (bp >= &buf[buflen - 2])
324c2aa98e2SPeter Wemm 			{
325c2aa98e2SPeter Wemm 				char *obuf;
326c2aa98e2SPeter Wemm 
327c2aa98e2SPeter Wemm 				if (mstate != MS_HEADER)
328c2aa98e2SPeter Wemm 					break;
329c2aa98e2SPeter Wemm 
330c2aa98e2SPeter Wemm 				/* out of space for header */
331c2aa98e2SPeter Wemm 				obuf = buf;
332c2aa98e2SPeter Wemm 				if (buflen < MEMCHUNKSIZE)
333c2aa98e2SPeter Wemm 					buflen *= 2;
334c2aa98e2SPeter Wemm 				else
335c2aa98e2SPeter Wemm 					buflen += MEMCHUNKSIZE;
336c2aa98e2SPeter Wemm 				buf = xalloc(buflen);
33706f25ae9SGregory Neil Shapiro 				memmove(buf, obuf, bp - obuf);
338c2aa98e2SPeter Wemm 				bp = &buf[bp - obuf];
339c2aa98e2SPeter Wemm 				if (obuf != bufbuf)
340c2aa98e2SPeter Wemm 					free(obuf);
341c2aa98e2SPeter Wemm 			}
342c2aa98e2SPeter Wemm 			if (c >= 0200 && c <= 0237)
343c2aa98e2SPeter Wemm 			{
34406f25ae9SGregory Neil Shapiro #if 0	/* causes complaints -- figure out something for 8.11 */
345c2aa98e2SPeter Wemm 				usrerr("Illegal character 0x%x in header", c);
34606f25ae9SGregory Neil Shapiro #else /* 0 */
34706f25ae9SGregory Neil Shapiro 				/* EMPTY */
34806f25ae9SGregory Neil Shapiro #endif /* 0 */
349c2aa98e2SPeter Wemm 			}
350c2aa98e2SPeter Wemm 			else if (c != '\0')
35125bab6e9SPeter Wemm 			{
352c2aa98e2SPeter Wemm 				*bp++ = c;
353602a2b1bSGregory Neil Shapiro 				hdrslen++;
3542e43090eSPeter Wemm 				if (MaxHeadersLength > 0 &&
355602a2b1bSGregory Neil Shapiro 				    hdrslen > MaxHeadersLength)
35625bab6e9SPeter Wemm 				{
35725bab6e9SPeter Wemm 					sm_syslog(LOG_NOTICE, e->e_id,
3582e43090eSPeter Wemm 						  "headers too large (%d max) from %s during message collect",
3592e43090eSPeter Wemm 						  MaxHeadersLength,
36025bab6e9SPeter Wemm 						  CurHostName != NULL ? CurHostName : "localhost");
36125bab6e9SPeter Wemm 					errno = 0;
36225bab6e9SPeter Wemm 					e->e_flags |= EF_CLRQUEUE;
36325bab6e9SPeter Wemm 					e->e_status = "5.6.0";
36406f25ae9SGregory Neil Shapiro 					usrerrenh(e->e_status,
36506f25ae9SGregory Neil Shapiro 						  "552 Headers too large (%d max)",
3662e43090eSPeter Wemm 						  MaxHeadersLength);
36725bab6e9SPeter Wemm 					mstate = MS_DISCARD;
36825bab6e9SPeter Wemm 				}
36925bab6e9SPeter Wemm 			}
370c2aa98e2SPeter Wemm 			if (istate == IS_BOL)
371c2aa98e2SPeter Wemm 				break;
372c2aa98e2SPeter Wemm 		}
373c2aa98e2SPeter Wemm 		*bp = '\0';
374c2aa98e2SPeter Wemm 
375c2aa98e2SPeter Wemm nextstate:
376c2aa98e2SPeter Wemm 		if (tTd(30, 35))
37706f25ae9SGregory Neil Shapiro 			dprintf("nextstate, istate=%d, mstate=%d, line = \"%s\"\n",
378c2aa98e2SPeter Wemm 				istate, mstate, buf);
379c2aa98e2SPeter Wemm 		switch (mstate)
380c2aa98e2SPeter Wemm 		{
381c2aa98e2SPeter Wemm 		  case MS_UFROM:
382c2aa98e2SPeter Wemm 			mstate = MS_HEADER;
383c2aa98e2SPeter Wemm #ifndef NOTUNIX
384c2aa98e2SPeter Wemm 			if (strncmp(buf, "From ", 5) == 0)
385c2aa98e2SPeter Wemm 			{
386c2aa98e2SPeter Wemm 				bp = buf;
387c2aa98e2SPeter Wemm 				eatfrom(buf, e);
388c2aa98e2SPeter Wemm 				continue;
389c2aa98e2SPeter Wemm 			}
39006f25ae9SGregory Neil Shapiro #endif /* ! NOTUNIX */
39106f25ae9SGregory Neil Shapiro 			/* FALLTHROUGH */
392c2aa98e2SPeter Wemm 
393c2aa98e2SPeter Wemm 		  case MS_HEADER:
394c2aa98e2SPeter Wemm 			if (!isheader(buf))
395c2aa98e2SPeter Wemm 			{
396c2aa98e2SPeter Wemm 				mstate = MS_BODY;
397c2aa98e2SPeter Wemm 				goto nextstate;
398c2aa98e2SPeter Wemm 			}
399c2aa98e2SPeter Wemm 
400c2aa98e2SPeter Wemm 			/* check for possible continuation line */
401c2aa98e2SPeter Wemm 			do
402c2aa98e2SPeter Wemm 			{
403c2aa98e2SPeter Wemm 				clearerr(fp);
404c2aa98e2SPeter Wemm 				errno = 0;
405c2aa98e2SPeter Wemm 				c = getc(fp);
40642e5d165SGregory Neil Shapiro 			} while (c == EOF && errno == EINTR);
407c2aa98e2SPeter Wemm 			if (c != EOF)
40806f25ae9SGregory Neil Shapiro 				(void) ungetc(c, fp);
409c2aa98e2SPeter Wemm 			if (c == ' ' || c == '\t')
410c2aa98e2SPeter Wemm 			{
411c2aa98e2SPeter Wemm 				/* yep -- defer this */
412c2aa98e2SPeter Wemm 				continue;
413c2aa98e2SPeter Wemm 			}
414c2aa98e2SPeter Wemm 
415c2aa98e2SPeter Wemm 			/* trim off trailing CRLF or NL */
416c2aa98e2SPeter Wemm 			if (*--bp != '\n' || *--bp != '\r')
417c2aa98e2SPeter Wemm 				bp++;
418c2aa98e2SPeter Wemm 			*bp = '\0';
41925bab6e9SPeter Wemm 
42006f25ae9SGregory Neil Shapiro 			if (bitset(H_EOH, chompheader(buf,
42106f25ae9SGregory Neil Shapiro 						      CHHDR_CHECK | CHHDR_USER,
42206f25ae9SGregory Neil Shapiro 						      hdrp, e)))
423c2aa98e2SPeter Wemm 			{
424c2aa98e2SPeter Wemm 				mstate = MS_BODY;
425c2aa98e2SPeter Wemm 				goto nextstate;
426c2aa98e2SPeter Wemm 			}
42706f25ae9SGregory Neil Shapiro 			numhdrs++;
428c2aa98e2SPeter Wemm 			break;
429c2aa98e2SPeter Wemm 
430c2aa98e2SPeter Wemm 		  case MS_BODY:
431c2aa98e2SPeter Wemm 			if (tTd(30, 1))
43206f25ae9SGregory Neil Shapiro 				dprintf("EOH\n");
43306f25ae9SGregory Neil Shapiro 
434c2aa98e2SPeter Wemm 			if (headeronly)
435c2aa98e2SPeter Wemm 				goto readerr;
43606f25ae9SGregory Neil Shapiro 
43706f25ae9SGregory Neil Shapiro 			/* call the end-of-header check ruleset */
43806f25ae9SGregory Neil Shapiro 			snprintf(hnum, sizeof hnum, "%d", numhdrs);
43906f25ae9SGregory Neil Shapiro 			snprintf(hsize, sizeof hsize, "%d", hdrslen);
44006f25ae9SGregory Neil Shapiro 			if (tTd(30, 10))
44106f25ae9SGregory Neil Shapiro 				dprintf("collect: rscheck(\"check_eoh\", \"%s $| %s\")\n",
44206f25ae9SGregory Neil Shapiro 					hnum, hsize);
44306f25ae9SGregory Neil Shapiro 			rstat = rscheck("check_eoh", hnum, hsize, e, FALSE,
444193538b7SGregory Neil Shapiro 					TRUE, 4, NULL);
44506f25ae9SGregory Neil Shapiro 
446c2aa98e2SPeter Wemm 			bp = buf;
447c2aa98e2SPeter Wemm 
448c2aa98e2SPeter Wemm 			/* toss blank line */
449c2aa98e2SPeter Wemm 			if ((!bitset(EF_CRLF_NOT_EOL, e->e_flags) &&
450c2aa98e2SPeter Wemm 				bp[0] == '\r' && bp[1] == '\n') ||
451c2aa98e2SPeter Wemm 			    (!bitset(EF_NL_NOT_EOL, e->e_flags) &&
452c2aa98e2SPeter Wemm 				bp[0] == '\n'))
453c2aa98e2SPeter Wemm 			{
454c2aa98e2SPeter Wemm 				break;
455c2aa98e2SPeter Wemm 			}
456c2aa98e2SPeter Wemm 
457c2aa98e2SPeter Wemm 			/* if not a blank separator, write it out */
45842e5d165SGregory Neil Shapiro 			if (!bitset(EF_TOOBIG, e->e_flags))
459c2aa98e2SPeter Wemm 			{
460c2aa98e2SPeter Wemm 				while (*bp != '\0')
46106f25ae9SGregory Neil Shapiro 					(void) putc(*bp++, df);
462c2aa98e2SPeter Wemm 			}
463c2aa98e2SPeter Wemm 			break;
464c2aa98e2SPeter Wemm 		}
465c2aa98e2SPeter Wemm 		bp = buf;
466c2aa98e2SPeter Wemm 	}
467c2aa98e2SPeter Wemm 
468c2aa98e2SPeter Wemm readerr:
469c2aa98e2SPeter Wemm 	if ((feof(fp) && smtpmode) || ferror(fp))
470c2aa98e2SPeter Wemm 	{
471c2aa98e2SPeter Wemm 		const char *errmsg = errstring(errno);
472c2aa98e2SPeter Wemm 
473c2aa98e2SPeter Wemm 		if (tTd(30, 1))
47406f25ae9SGregory Neil Shapiro 			dprintf("collect: premature EOM: %s\n", errmsg);
475c2aa98e2SPeter Wemm 		if (LogLevel >= 2)
476c2aa98e2SPeter Wemm 			sm_syslog(LOG_WARNING, e->e_id,
477c2aa98e2SPeter Wemm 				"collect: premature EOM: %s", errmsg);
478c2aa98e2SPeter Wemm 		inputerr = TRUE;
479c2aa98e2SPeter Wemm 	}
480c2aa98e2SPeter Wemm 
481c2aa98e2SPeter Wemm 	/* reset global timer */
482c2aa98e2SPeter Wemm 	clrevent(CollectTimeout);
483c2aa98e2SPeter Wemm 
484c2aa98e2SPeter Wemm 	if (headeronly)
485c2aa98e2SPeter Wemm 		return;
486c2aa98e2SPeter Wemm 
48706f25ae9SGregory Neil Shapiro 	if (df == NULL)
488c2aa98e2SPeter Wemm 	{
48906f25ae9SGregory Neil Shapiro 		/* skip next few clauses */
49006f25ae9SGregory Neil Shapiro 		/* EMPTY */
49106f25ae9SGregory Neil Shapiro 	}
49206f25ae9SGregory Neil Shapiro 	else if (fflush(df) != 0 || ferror(df))
49306f25ae9SGregory Neil Shapiro 	{
49406f25ae9SGregory Neil Shapiro 		dferror(df, "fflush||ferror", e);
495c2aa98e2SPeter Wemm 		flush_errors(TRUE);
496065a643dSPeter Wemm 		finis(TRUE, ExitStat);
49706f25ae9SGregory Neil Shapiro 		/* NOTREACHED */
49806f25ae9SGregory Neil Shapiro 	}
49906f25ae9SGregory Neil Shapiro 	else if (!SuperSafe)
50006f25ae9SGregory Neil Shapiro 	{
50106f25ae9SGregory Neil Shapiro 		/* skip next few clauses */
50206f25ae9SGregory Neil Shapiro 		/* EMPTY */
50306f25ae9SGregory Neil Shapiro 	}
50406f25ae9SGregory Neil Shapiro 	else if (bfcommit(df) < 0)
50506f25ae9SGregory Neil Shapiro 	{
50606f25ae9SGregory Neil Shapiro 		int save_errno = errno;
50706f25ae9SGregory Neil Shapiro 
50806f25ae9SGregory Neil Shapiro 		if (save_errno == EEXIST)
50906f25ae9SGregory Neil Shapiro 		{
51006f25ae9SGregory Neil Shapiro 			char *dfile;
51106f25ae9SGregory Neil Shapiro 			struct stat st;
51206f25ae9SGregory Neil Shapiro 
51306f25ae9SGregory Neil Shapiro 			dfile = queuename(e, 'd');
51406f25ae9SGregory Neil Shapiro 			if (stat(dfile, &st) < 0)
51506f25ae9SGregory Neil Shapiro 				st.st_size = -1;
51606f25ae9SGregory Neil Shapiro 			errno = EEXIST;
51706f25ae9SGregory Neil Shapiro 			syserr("collect: bfcommit(%s): already on disk, size = %ld",
51842e5d165SGregory Neil Shapiro 			       dfile, (long) st.st_size);
51906f25ae9SGregory Neil Shapiro 			dfd = fileno(df);
52006f25ae9SGregory Neil Shapiro 			if (dfd >= 0)
52106f25ae9SGregory Neil Shapiro 				dumpfd(dfd, TRUE, TRUE);
52206f25ae9SGregory Neil Shapiro 		}
52306f25ae9SGregory Neil Shapiro 		errno = save_errno;
52406f25ae9SGregory Neil Shapiro 		dferror(df, "bfcommit", e);
52506f25ae9SGregory Neil Shapiro 		flush_errors(TRUE);
52606f25ae9SGregory Neil Shapiro 		finis(save_errno != EEXIST, ExitStat);
52706f25ae9SGregory Neil Shapiro 	}
528602a2b1bSGregory Neil Shapiro 	else if (bffsync(df) < 0)
529602a2b1bSGregory Neil Shapiro 	{
530602a2b1bSGregory Neil Shapiro 		dferror(df, "bffsync", e);
531602a2b1bSGregory Neil Shapiro 		flush_errors(TRUE);
532602a2b1bSGregory Neil Shapiro 		finis(TRUE, ExitStat);
533602a2b1bSGregory Neil Shapiro 		/* NOTREACHED */
534602a2b1bSGregory Neil Shapiro 	}
53506f25ae9SGregory Neil Shapiro 	else if (bfclose(df) < 0)
53606f25ae9SGregory Neil Shapiro 	{
53706f25ae9SGregory Neil Shapiro 		dferror(df, "bfclose", e);
53806f25ae9SGregory Neil Shapiro 		flush_errors(TRUE);
53906f25ae9SGregory Neil Shapiro 		finis(TRUE, ExitStat);
54006f25ae9SGregory Neil Shapiro 		/* NOTREACHED */
54106f25ae9SGregory Neil Shapiro 	}
54206f25ae9SGregory Neil Shapiro 	else
54306f25ae9SGregory Neil Shapiro 	{
54406f25ae9SGregory Neil Shapiro 		/* everything is happily flushed to disk */
54506f25ae9SGregory Neil Shapiro 		df = NULL;
546c2aa98e2SPeter Wemm 	}
547c2aa98e2SPeter Wemm 
548c2aa98e2SPeter Wemm 	/* An EOF when running SMTP is an error */
549c2aa98e2SPeter Wemm 	if (inputerr && (OpMode == MD_SMTP || OpMode == MD_DAEMON))
550c2aa98e2SPeter Wemm 	{
551c2aa98e2SPeter Wemm 		char *host;
552c2aa98e2SPeter Wemm 		char *problem;
553c2aa98e2SPeter Wemm 
554c2aa98e2SPeter Wemm 		host = RealHostName;
555c2aa98e2SPeter Wemm 		if (host == NULL)
556c2aa98e2SPeter Wemm 			host = "localhost";
557c2aa98e2SPeter Wemm 
558c2aa98e2SPeter Wemm 		if (feof(fp))
559c2aa98e2SPeter Wemm 			problem = "unexpected close";
560c2aa98e2SPeter Wemm 		else if (ferror(fp))
561c2aa98e2SPeter Wemm 			problem = "I/O error";
562c2aa98e2SPeter Wemm 		else
563c2aa98e2SPeter Wemm 			problem = "read timeout";
564c2aa98e2SPeter Wemm 		if (LogLevel > 0 && feof(fp))
565c2aa98e2SPeter Wemm 			sm_syslog(LOG_NOTICE, e->e_id,
566c2aa98e2SPeter Wemm 			    "collect: %s on connection from %.100s, sender=%s: %s",
567c2aa98e2SPeter Wemm 			    problem, host,
568c2aa98e2SPeter Wemm 			    shortenstring(e->e_from.q_paddr, MAXSHORTSTR),
569c2aa98e2SPeter Wemm 			    errstring(errno));
570c2aa98e2SPeter Wemm 		if (feof(fp))
57106f25ae9SGregory Neil Shapiro 			usrerr("451 4.4.1 collect: %s on connection from %s, from=%s",
572c2aa98e2SPeter Wemm 				problem, host,
573c2aa98e2SPeter Wemm 				shortenstring(e->e_from.q_paddr, MAXSHORTSTR));
574c2aa98e2SPeter Wemm 		else
57506f25ae9SGregory Neil Shapiro 			syserr("451 4.4.1 collect: %s on connection from %s, from=%s",
576c2aa98e2SPeter Wemm 				problem, host,
577c2aa98e2SPeter Wemm 				shortenstring(e->e_from.q_paddr, MAXSHORTSTR));
578c2aa98e2SPeter Wemm 
579c2aa98e2SPeter Wemm 		/* don't return an error indication */
580c2aa98e2SPeter Wemm 		e->e_to = NULL;
581c2aa98e2SPeter Wemm 		e->e_flags &= ~EF_FATALERRS;
582c2aa98e2SPeter Wemm 		e->e_flags |= EF_CLRQUEUE;
583c2aa98e2SPeter Wemm 
584c2aa98e2SPeter Wemm 		/* and don't try to deliver the partial message either */
585c2aa98e2SPeter Wemm 		if (InChild)
586c2aa98e2SPeter Wemm 			ExitStat = EX_QUIT;
587065a643dSPeter Wemm 		finis(TRUE, ExitStat);
58806f25ae9SGregory Neil Shapiro 		/* NOTREACHED */
589c2aa98e2SPeter Wemm 	}
590c2aa98e2SPeter Wemm 
591c2aa98e2SPeter Wemm 	/*
592c2aa98e2SPeter Wemm 	**  Find out some information from the headers.
593c2aa98e2SPeter Wemm 	**	Examples are who is the from person & the date.
594c2aa98e2SPeter Wemm 	*/
595c2aa98e2SPeter Wemm 
596c2aa98e2SPeter Wemm 	eatheader(e, TRUE);
597c2aa98e2SPeter Wemm 
598c2aa98e2SPeter Wemm 	if (GrabTo && e->e_sendqueue == NULL)
599c2aa98e2SPeter Wemm 		usrerr("No recipient addresses found in header");
600c2aa98e2SPeter Wemm 
601c2aa98e2SPeter Wemm 	/* collect statistics */
602c2aa98e2SPeter Wemm 	if (OpMode != MD_VERIFY)
603c2aa98e2SPeter Wemm 		markstats(e, (ADDRESS *) NULL, FALSE);
604c2aa98e2SPeter Wemm 
605c2aa98e2SPeter Wemm 	/*
606c2aa98e2SPeter Wemm 	**  If we have a Return-Receipt-To:, turn it into a DSN.
607c2aa98e2SPeter Wemm 	*/
608c2aa98e2SPeter Wemm 
609c2aa98e2SPeter Wemm 	if (RrtImpliesDsn && hvalue("return-receipt-to", e->e_header) != NULL)
610c2aa98e2SPeter Wemm 	{
611c2aa98e2SPeter Wemm 		ADDRESS *q;
612c2aa98e2SPeter Wemm 
613c2aa98e2SPeter Wemm 		for (q = e->e_sendqueue; q != NULL; q = q->q_next)
614c2aa98e2SPeter Wemm 			if (!bitset(QHASNOTIFY, q->q_flags))
615c2aa98e2SPeter Wemm 				q->q_flags |= QHASNOTIFY|QPINGONSUCCESS;
616c2aa98e2SPeter Wemm 	}
617c2aa98e2SPeter Wemm 
618c2aa98e2SPeter Wemm 	/*
619c2aa98e2SPeter Wemm 	**  Add an Apparently-To: line if we have no recipient lines.
620c2aa98e2SPeter Wemm 	*/
621c2aa98e2SPeter Wemm 
622c2aa98e2SPeter Wemm 	if (hvalue("to", e->e_header) != NULL ||
623c2aa98e2SPeter Wemm 	    hvalue("cc", e->e_header) != NULL ||
624c2aa98e2SPeter Wemm 	    hvalue("apparently-to", e->e_header) != NULL)
625c2aa98e2SPeter Wemm 	{
626c2aa98e2SPeter Wemm 		/* have a valid recipient header -- delete Bcc: headers */
627c2aa98e2SPeter Wemm 		e->e_flags |= EF_DELETE_BCC;
628c2aa98e2SPeter Wemm 	}
629c2aa98e2SPeter Wemm 	else if (hvalue("bcc", e->e_header) == NULL)
630c2aa98e2SPeter Wemm 	{
631c2aa98e2SPeter Wemm 		/* no valid recipient headers */
632c2aa98e2SPeter Wemm 		register ADDRESS *q;
633c2aa98e2SPeter Wemm 		char *hdr = NULL;
634c2aa98e2SPeter Wemm 
635c2aa98e2SPeter Wemm 		/* create an Apparently-To: field */
636c2aa98e2SPeter Wemm 		/*    that or reject the message.... */
637c2aa98e2SPeter Wemm 		switch (NoRecipientAction)
638c2aa98e2SPeter Wemm 		{
639c2aa98e2SPeter Wemm 		  case NRA_ADD_APPARENTLY_TO:
640c2aa98e2SPeter Wemm 			hdr = "Apparently-To";
641c2aa98e2SPeter Wemm 			break;
642c2aa98e2SPeter Wemm 
643c2aa98e2SPeter Wemm 		  case NRA_ADD_TO:
644c2aa98e2SPeter Wemm 			hdr = "To";
645c2aa98e2SPeter Wemm 			break;
646c2aa98e2SPeter Wemm 
647c2aa98e2SPeter Wemm 		  case NRA_ADD_BCC:
64806f25ae9SGregory Neil Shapiro 			addheader("Bcc", " ", 0, &e->e_header);
649c2aa98e2SPeter Wemm 			break;
650c2aa98e2SPeter Wemm 
651c2aa98e2SPeter Wemm 		  case NRA_ADD_TO_UNDISCLOSED:
65206f25ae9SGregory Neil Shapiro 			addheader("To", "undisclosed-recipients:;", 0, &e->e_header);
653c2aa98e2SPeter Wemm 			break;
654c2aa98e2SPeter Wemm 		}
655c2aa98e2SPeter Wemm 
656c2aa98e2SPeter Wemm 		if (hdr != NULL)
657c2aa98e2SPeter Wemm 		{
658c2aa98e2SPeter Wemm 			for (q = e->e_sendqueue; q != NULL; q = q->q_next)
659c2aa98e2SPeter Wemm 			{
660c2aa98e2SPeter Wemm 				if (q->q_alias != NULL)
661c2aa98e2SPeter Wemm 					continue;
662c2aa98e2SPeter Wemm 				if (tTd(30, 3))
66306f25ae9SGregory Neil Shapiro 					dprintf("Adding %s: %s\n",
664c2aa98e2SPeter Wemm 						hdr, q->q_paddr);
66506f25ae9SGregory Neil Shapiro 				addheader(hdr, q->q_paddr, 0, &e->e_header);
666c2aa98e2SPeter Wemm 			}
667c2aa98e2SPeter Wemm 		}
668c2aa98e2SPeter Wemm 	}
669c2aa98e2SPeter Wemm 
670c2aa98e2SPeter Wemm 	/* check for message too large */
67142e5d165SGregory Neil Shapiro 	if (bitset(EF_TOOBIG, e->e_flags))
672c2aa98e2SPeter Wemm 	{
673c2aa98e2SPeter Wemm 		e->e_flags |= EF_NO_BODY_RETN|EF_CLRQUEUE;
674c2aa98e2SPeter Wemm 		e->e_status = "5.2.3";
67506f25ae9SGregory Neil Shapiro 		usrerrenh(e->e_status,
67606f25ae9SGregory Neil Shapiro 			  "552 Message exceeds maximum fixed size (%ld)",
677c2aa98e2SPeter Wemm 			  MaxMessageSize);
678c2aa98e2SPeter Wemm 		if (LogLevel > 6)
679c2aa98e2SPeter Wemm 			sm_syslog(LOG_NOTICE, e->e_id,
680c2aa98e2SPeter Wemm 				"message size (%ld) exceeds maximum (%ld)",
681c2aa98e2SPeter Wemm 				e->e_msgsize, MaxMessageSize);
682c2aa98e2SPeter Wemm 	}
683c2aa98e2SPeter Wemm 
684c2aa98e2SPeter Wemm 	/* check for illegal 8-bit data */
685c2aa98e2SPeter Wemm 	if (HasEightBits)
686c2aa98e2SPeter Wemm 	{
687c2aa98e2SPeter Wemm 		e->e_flags |= EF_HAS8BIT;
688c2aa98e2SPeter Wemm 		if (!bitset(MM_PASS8BIT|MM_MIME8BIT, MimeMode) &&
689c2aa98e2SPeter Wemm 		    !bitset(EF_IS_MIME, e->e_flags))
690c2aa98e2SPeter Wemm 		{
691c2aa98e2SPeter Wemm 			e->e_status = "5.6.1";
69206f25ae9SGregory Neil Shapiro 			usrerrenh(e->e_status, "554 Eight bit data not allowed");
693c2aa98e2SPeter Wemm 		}
694c2aa98e2SPeter Wemm 	}
695c2aa98e2SPeter Wemm 	else
696c2aa98e2SPeter Wemm 	{
697c2aa98e2SPeter Wemm 		/* if it claimed to be 8 bits, well, it lied.... */
698c2aa98e2SPeter Wemm 		if (e->e_bodytype != NULL &&
699c2aa98e2SPeter Wemm 		    strcasecmp(e->e_bodytype, "8BITMIME") == 0)
700c2aa98e2SPeter Wemm 			e->e_bodytype = "7BIT";
701c2aa98e2SPeter Wemm 	}
702c2aa98e2SPeter Wemm 
70306f25ae9SGregory Neil Shapiro 	if (SuperSafe)
70406f25ae9SGregory Neil Shapiro 	{
705c2aa98e2SPeter Wemm 		if ((e->e_dfp = fopen(dfname, "r")) == NULL)
706c2aa98e2SPeter Wemm 		{
707c2aa98e2SPeter Wemm 			/* we haven't acked receipt yet, so just chuck this */
708c2aa98e2SPeter Wemm 			syserr("Cannot reopen %s", dfname);
709065a643dSPeter Wemm 			finis(TRUE, ExitStat);
71006f25ae9SGregory Neil Shapiro 			/* NOTREACHED */
711c2aa98e2SPeter Wemm 		}
712c2aa98e2SPeter Wemm 	}
71306f25ae9SGregory Neil Shapiro 	else
71406f25ae9SGregory Neil Shapiro 		e->e_dfp = df;
71506f25ae9SGregory Neil Shapiro 	if (e->e_dfp == NULL)
71606f25ae9SGregory Neil Shapiro 		syserr("!collect: no e_dfp");
71706f25ae9SGregory Neil Shapiro }
718c2aa98e2SPeter Wemm 
719c2aa98e2SPeter Wemm 
720c2aa98e2SPeter Wemm static void
721c2aa98e2SPeter Wemm collecttimeout(timeout)
722c2aa98e2SPeter Wemm 	time_t timeout;
723c2aa98e2SPeter Wemm {
724c2aa98e2SPeter Wemm 	/* if no progress was made, die now */
725c2aa98e2SPeter Wemm 	if (!CollectProgress)
726c2aa98e2SPeter Wemm 		longjmp(CtxCollectTimeout, 1);
727c2aa98e2SPeter Wemm 
728c2aa98e2SPeter Wemm 	/* otherwise reset the timeout */
729c2aa98e2SPeter Wemm 	CollectTimeout = setevent(timeout, collecttimeout, timeout);
730c2aa98e2SPeter Wemm 	CollectProgress = FALSE;
731c2aa98e2SPeter Wemm }
73206f25ae9SGregory Neil Shapiro /*
73306f25ae9SGregory Neil Shapiro **  DFERROR -- signal error on writing the data file.
734c2aa98e2SPeter Wemm **
735c2aa98e2SPeter Wemm **	Parameters:
73606f25ae9SGregory Neil Shapiro **		df -- the file pointer for the data file.
73706f25ae9SGregory Neil Shapiro **		msg -- detailed message.
738c2aa98e2SPeter Wemm **		e -- the current envelope.
739c2aa98e2SPeter Wemm **
740c2aa98e2SPeter Wemm **	Returns:
741c2aa98e2SPeter Wemm **		none.
742c2aa98e2SPeter Wemm **
743c2aa98e2SPeter Wemm **	Side Effects:
744c2aa98e2SPeter Wemm **		Gives an error message.
745c2aa98e2SPeter Wemm **		Arranges for following output to go elsewhere.
746c2aa98e2SPeter Wemm */
747c2aa98e2SPeter Wemm 
74806f25ae9SGregory Neil Shapiro static void
74906f25ae9SGregory Neil Shapiro dferror(df, msg, e)
75006f25ae9SGregory Neil Shapiro 	FILE *volatile df;
75106f25ae9SGregory Neil Shapiro 	char *msg;
752c2aa98e2SPeter Wemm 	register ENVELOPE *e;
753c2aa98e2SPeter Wemm {
75406f25ae9SGregory Neil Shapiro 	char *dfname;
75506f25ae9SGregory Neil Shapiro 
75606f25ae9SGregory Neil Shapiro 	dfname = queuename(e, 'd');
757c2aa98e2SPeter Wemm 	setstat(EX_IOERR);
758c2aa98e2SPeter Wemm 	if (errno == ENOSPC)
759c2aa98e2SPeter Wemm 	{
760c2aa98e2SPeter Wemm #if STAT64 > 0
761c2aa98e2SPeter Wemm 		struct stat64 st;
76206f25ae9SGregory Neil Shapiro #else /* STAT64 > 0 */
763c2aa98e2SPeter Wemm 		struct stat st;
76406f25ae9SGregory Neil Shapiro #endif /* STAT64 > 0 */
765c2aa98e2SPeter Wemm 		long avail;
766c2aa98e2SPeter Wemm 		long bsize;
767c2aa98e2SPeter Wemm 
768c2aa98e2SPeter Wemm 		e->e_flags |= EF_NO_BODY_RETN;
769c2aa98e2SPeter Wemm 
770c2aa98e2SPeter Wemm 		if (
771c2aa98e2SPeter Wemm #if STAT64 > 0
77206f25ae9SGregory Neil Shapiro 		    fstat64(fileno(df), &st)
77306f25ae9SGregory Neil Shapiro #else /* STAT64 > 0 */
77406f25ae9SGregory Neil Shapiro 		    fstat(fileno(df), &st)
77506f25ae9SGregory Neil Shapiro #endif /* STAT64 > 0 */
776c2aa98e2SPeter Wemm 		    < 0)
777c2aa98e2SPeter Wemm 		  st.st_size = 0;
77806f25ae9SGregory Neil Shapiro 		(void) freopen(dfname, "w", df);
779c2aa98e2SPeter Wemm 		if (st.st_size <= 0)
78006f25ae9SGregory Neil Shapiro 			fprintf(df, "\n*** Mail could not be accepted");
78106f25ae9SGregory Neil Shapiro 		/*CONSTCOND*/
782c2aa98e2SPeter Wemm 		else if (sizeof st.st_size > sizeof (long))
78306f25ae9SGregory Neil Shapiro 			fprintf(df, "\n*** Mail of at least %s bytes could not be accepted\n",
784c2aa98e2SPeter Wemm 				quad_to_string(st.st_size));
785c2aa98e2SPeter Wemm 		else
78606f25ae9SGregory Neil Shapiro 			fprintf(df, "\n*** Mail of at least %lu bytes could not be accepted\n",
787c2aa98e2SPeter Wemm 				(unsigned long) st.st_size);
78806f25ae9SGregory Neil Shapiro 		fprintf(df, "*** at %s due to lack of disk space for temp file.\n",
789c2aa98e2SPeter Wemm 			MyHostName);
79006f25ae9SGregory Neil Shapiro 		avail = freediskspace(qid_printqueue(e->e_queuedir), &bsize);
791c2aa98e2SPeter Wemm 		if (avail > 0)
792c2aa98e2SPeter Wemm 		{
793c2aa98e2SPeter Wemm 			if (bsize > 1024)
794c2aa98e2SPeter Wemm 				avail *= bsize / 1024;
795c2aa98e2SPeter Wemm 			else if (bsize < 1024)
796c2aa98e2SPeter Wemm 				avail /= 1024 / bsize;
79706f25ae9SGregory Neil Shapiro 			fprintf(df, "*** Currently, %ld kilobytes are available for mail temp files.\n",
798c2aa98e2SPeter Wemm 				avail);
799c2aa98e2SPeter Wemm 		}
800c2aa98e2SPeter Wemm 		e->e_status = "4.3.1";
80106f25ae9SGregory Neil Shapiro 		usrerrenh(e->e_status, "452 Out of disk space for temp file");
802c2aa98e2SPeter Wemm 	}
803c2aa98e2SPeter Wemm 	else
80406f25ae9SGregory Neil Shapiro 		syserr("collect: Cannot write %s (%s, uid=%d)",
80506f25ae9SGregory Neil Shapiro 			dfname, msg, geteuid());
80606f25ae9SGregory Neil Shapiro 	if (freopen("/dev/null", "w", df) == NULL)
807c2aa98e2SPeter Wemm 		sm_syslog(LOG_ERR, e->e_id,
80806f25ae9SGregory Neil Shapiro 			  "dferror: freopen(\"/dev/null\") failed: %s",
809c2aa98e2SPeter Wemm 			  errstring(errno));
810c2aa98e2SPeter Wemm }
811c2aa98e2SPeter Wemm /*
812c2aa98e2SPeter Wemm **  EATFROM -- chew up a UNIX style from line and process
813c2aa98e2SPeter Wemm **
814c2aa98e2SPeter Wemm **	This does indeed make some assumptions about the format
815c2aa98e2SPeter Wemm **	of UNIX messages.
816c2aa98e2SPeter Wemm **
817c2aa98e2SPeter Wemm **	Parameters:
818c2aa98e2SPeter Wemm **		fm -- the from line.
819c2aa98e2SPeter Wemm **
820c2aa98e2SPeter Wemm **	Returns:
821c2aa98e2SPeter Wemm **		none.
822c2aa98e2SPeter Wemm **
823c2aa98e2SPeter Wemm **	Side Effects:
824c2aa98e2SPeter Wemm **		extracts what information it can from the header,
825c2aa98e2SPeter Wemm **		such as the date.
826c2aa98e2SPeter Wemm */
827c2aa98e2SPeter Wemm 
828c2aa98e2SPeter Wemm #ifndef NOTUNIX
829c2aa98e2SPeter Wemm 
83006f25ae9SGregory Neil Shapiro static char	*DowList[] =
831c2aa98e2SPeter Wemm {
832c2aa98e2SPeter Wemm 	"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", NULL
833c2aa98e2SPeter Wemm };
834c2aa98e2SPeter Wemm 
83506f25ae9SGregory Neil Shapiro static char	*MonthList[] =
836c2aa98e2SPeter Wemm {
837c2aa98e2SPeter Wemm 	"Jan", "Feb", "Mar", "Apr", "May", "Jun",
838c2aa98e2SPeter Wemm 	"Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
839c2aa98e2SPeter Wemm 	NULL
840c2aa98e2SPeter Wemm };
841c2aa98e2SPeter Wemm 
84206f25ae9SGregory Neil Shapiro static void
843c2aa98e2SPeter Wemm eatfrom(fm, e)
844c2aa98e2SPeter Wemm 	char *volatile fm;
845c2aa98e2SPeter Wemm 	register ENVELOPE *e;
846c2aa98e2SPeter Wemm {
847c2aa98e2SPeter Wemm 	register char *p;
848c2aa98e2SPeter Wemm 	register char **dt;
849c2aa98e2SPeter Wemm 
850c2aa98e2SPeter Wemm 	if (tTd(30, 2))
85106f25ae9SGregory Neil Shapiro 		dprintf("eatfrom(%s)\n", fm);
852c2aa98e2SPeter Wemm 
853c2aa98e2SPeter Wemm 	/* find the date part */
854c2aa98e2SPeter Wemm 	p = fm;
855c2aa98e2SPeter Wemm 	while (*p != '\0')
856c2aa98e2SPeter Wemm 	{
857c2aa98e2SPeter Wemm 		/* skip a word */
858c2aa98e2SPeter Wemm 		while (*p != '\0' && *p != ' ')
859c2aa98e2SPeter Wemm 			p++;
860c2aa98e2SPeter Wemm 		while (*p == ' ')
861c2aa98e2SPeter Wemm 			p++;
862193538b7SGregory Neil Shapiro 		if (strlen(p) < 17)
863193538b7SGregory Neil Shapiro 		{
864193538b7SGregory Neil Shapiro 			/* no room for the date */
865193538b7SGregory Neil Shapiro 			return;
866193538b7SGregory Neil Shapiro 		}
867c2aa98e2SPeter Wemm 		if (!(isascii(*p) && isupper(*p)) ||
868c2aa98e2SPeter Wemm 		    p[3] != ' ' || p[13] != ':' || p[16] != ':')
869c2aa98e2SPeter Wemm 			continue;
870c2aa98e2SPeter Wemm 
871c2aa98e2SPeter Wemm 		/* we have a possible date */
872c2aa98e2SPeter Wemm 		for (dt = DowList; *dt != NULL; dt++)
873c2aa98e2SPeter Wemm 			if (strncmp(*dt, p, 3) == 0)
874c2aa98e2SPeter Wemm 				break;
875c2aa98e2SPeter Wemm 		if (*dt == NULL)
876c2aa98e2SPeter Wemm 			continue;
877c2aa98e2SPeter Wemm 
878c2aa98e2SPeter Wemm 		for (dt = MonthList; *dt != NULL; dt++)
879193538b7SGregory Neil Shapiro 		{
880c2aa98e2SPeter Wemm 			if (strncmp(*dt, &p[4], 3) == 0)
881c2aa98e2SPeter Wemm 				break;
882193538b7SGregory Neil Shapiro 		}
883c2aa98e2SPeter Wemm 		if (*dt != NULL)
884c2aa98e2SPeter Wemm 			break;
885c2aa98e2SPeter Wemm 	}
886c2aa98e2SPeter Wemm 
887c2aa98e2SPeter Wemm 	if (*p != '\0')
888c2aa98e2SPeter Wemm 	{
889c2aa98e2SPeter Wemm 		char *q;
890c2aa98e2SPeter Wemm 
891c2aa98e2SPeter Wemm 		/* we have found a date */
892c2aa98e2SPeter Wemm 		q = xalloc(25);
89306f25ae9SGregory Neil Shapiro 		(void) strlcpy(q, p, 25);
894c2aa98e2SPeter Wemm 		q = arpadate(q);
895c2aa98e2SPeter Wemm 		define('a', newstr(q), e);
896c2aa98e2SPeter Wemm 	}
897c2aa98e2SPeter Wemm }
89806f25ae9SGregory Neil Shapiro #endif /* ! NOTUNIX */
899