xref: /freebsd/contrib/sendmail/src/collect.c (revision 8774250cea278e6e89c2edc49f341828de307fb4)
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
158774250cSGregory Neil Shapiro static char id[] = "@(#)$Id: collect.c,v 8.136.4.21 2001/05/17 18:10:14 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;
508774250cSGregory Neil Shapiro static bool	volatile CollectProgress;
518774250cSGregory Neil Shapiro static EVENT	*volatile CollectTimeout = NULL;
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)
2158774250cSGregory Neil Shapiro 						(void) fprintf(TrafficLogFile,
2168774250cSGregory Neil Shapiro 							       "%05d <<< ",
217c2aa98e2SPeter Wemm 							       (int) getpid());
218c2aa98e2SPeter Wemm 					if (c == EOF)
2198774250cSGregory Neil Shapiro 						(void) fprintf(TrafficLogFile,
2208774250cSGregory Neil Shapiro 							       "[EOF]\n");
221c2aa98e2SPeter Wemm 					else
22206f25ae9SGregory Neil Shapiro 						(void) putc(c, TrafficLogFile);
223c2aa98e2SPeter Wemm 				}
224c2aa98e2SPeter Wemm 				if (c == EOF)
225c2aa98e2SPeter Wemm 					goto readerr;
226c2aa98e2SPeter Wemm 				if (SevenBitInput)
227c2aa98e2SPeter Wemm 					c &= 0x7f;
228c2aa98e2SPeter Wemm 				else
229c2aa98e2SPeter Wemm 					HasEightBits |= bitset(0x80, c);
230c2aa98e2SPeter Wemm 			}
231c2aa98e2SPeter Wemm 			if (tTd(30, 94))
23206f25ae9SGregory Neil Shapiro 				dprintf("istate=%d, c=%c (0x%x)\n",
23306f25ae9SGregory Neil Shapiro 					istate, (char) c, c);
234c2aa98e2SPeter Wemm 			switch (istate)
235c2aa98e2SPeter Wemm 			{
236c2aa98e2SPeter Wemm 			  case IS_BOL:
237c2aa98e2SPeter Wemm 				if (c == '.')
238c2aa98e2SPeter Wemm 				{
239c2aa98e2SPeter Wemm 					istate = IS_DOT;
240c2aa98e2SPeter Wemm 					continue;
241c2aa98e2SPeter Wemm 				}
242c2aa98e2SPeter Wemm 				break;
243c2aa98e2SPeter Wemm 
244c2aa98e2SPeter Wemm 			  case IS_DOT:
245c2aa98e2SPeter Wemm 				if (c == '\n' && !ignrdot &&
246c2aa98e2SPeter Wemm 				    !bitset(EF_NL_NOT_EOL, e->e_flags))
247c2aa98e2SPeter Wemm 					goto readerr;
248c2aa98e2SPeter Wemm 				else if (c == '\r' &&
249c2aa98e2SPeter Wemm 					 !bitset(EF_CRLF_NOT_EOL, e->e_flags))
250c2aa98e2SPeter Wemm 				{
251c2aa98e2SPeter Wemm 					istate = IS_DOTCR;
252c2aa98e2SPeter Wemm 					continue;
253c2aa98e2SPeter Wemm 				}
254c2aa98e2SPeter Wemm 				else if (c != '.' ||
255c2aa98e2SPeter Wemm 					 (OpMode != MD_SMTP &&
256c2aa98e2SPeter Wemm 					  OpMode != MD_DAEMON &&
257c2aa98e2SPeter Wemm 					  OpMode != MD_ARPAFTP))
258c2aa98e2SPeter Wemm 				{
259c2aa98e2SPeter Wemm 					*pbp++ = c;
260c2aa98e2SPeter Wemm 					c = '.';
261c2aa98e2SPeter Wemm 				}
262c2aa98e2SPeter Wemm 				break;
263c2aa98e2SPeter Wemm 
264c2aa98e2SPeter Wemm 			  case IS_DOTCR:
265c2aa98e2SPeter Wemm 				if (c == '\n' && !ignrdot)
266c2aa98e2SPeter Wemm 					goto readerr;
267c2aa98e2SPeter Wemm 				else
268c2aa98e2SPeter Wemm 				{
269c2aa98e2SPeter Wemm 					/* push back the ".\rx" */
270c2aa98e2SPeter Wemm 					*pbp++ = c;
271c2aa98e2SPeter Wemm 					*pbp++ = '\r';
272c2aa98e2SPeter Wemm 					c = '.';
273c2aa98e2SPeter Wemm 				}
274c2aa98e2SPeter Wemm 				break;
275c2aa98e2SPeter Wemm 
276c2aa98e2SPeter Wemm 			  case IS_CR:
277c2aa98e2SPeter Wemm 				if (c == '\n')
278c2aa98e2SPeter Wemm 					istate = IS_BOL;
279c2aa98e2SPeter Wemm 				else
280c2aa98e2SPeter Wemm 				{
28106f25ae9SGregory Neil Shapiro 					(void) ungetc(c, fp);
282c2aa98e2SPeter Wemm 					c = '\r';
283c2aa98e2SPeter Wemm 					istate = IS_NORM;
284c2aa98e2SPeter Wemm 				}
285c2aa98e2SPeter Wemm 				goto bufferchar;
286c2aa98e2SPeter Wemm 			}
287c2aa98e2SPeter Wemm 
288c2aa98e2SPeter Wemm 			if (c == '\r' && !bitset(EF_CRLF_NOT_EOL, e->e_flags))
289c2aa98e2SPeter Wemm 			{
290c2aa98e2SPeter Wemm 				istate = IS_CR;
291c2aa98e2SPeter Wemm 				continue;
292c2aa98e2SPeter Wemm 			}
293c2aa98e2SPeter Wemm 			else if (c == '\n' && !bitset(EF_NL_NOT_EOL, e->e_flags))
294c2aa98e2SPeter Wemm 				istate = IS_BOL;
295c2aa98e2SPeter Wemm 			else
296c2aa98e2SPeter Wemm 				istate = IS_NORM;
297c2aa98e2SPeter Wemm 
298c2aa98e2SPeter Wemm bufferchar:
299c2aa98e2SPeter Wemm 			if (!headeronly)
30042e5d165SGregory Neil Shapiro 			{
30142e5d165SGregory Neil Shapiro 				/* no overflow? */
30242e5d165SGregory Neil Shapiro 				if (e->e_msgsize >= 0)
30342e5d165SGregory Neil Shapiro 				{
304c2aa98e2SPeter Wemm 					e->e_msgsize++;
30542e5d165SGregory Neil Shapiro 					if (MaxMessageSize > 0 &&
30642e5d165SGregory Neil Shapiro 					    !bitset(EF_TOOBIG, e->e_flags) &&
30742e5d165SGregory Neil Shapiro 					    e->e_msgsize > MaxMessageSize)
30842e5d165SGregory Neil Shapiro 						 e->e_flags |= EF_TOOBIG;
30942e5d165SGregory Neil Shapiro 				}
31042e5d165SGregory Neil Shapiro 			}
31125bab6e9SPeter Wemm 			switch (mstate)
312c2aa98e2SPeter Wemm 			{
31325bab6e9SPeter Wemm 			  case MS_BODY:
314c2aa98e2SPeter Wemm 				/* just put the character out */
31542e5d165SGregory Neil Shapiro 				if (!bitset(EF_TOOBIG, e->e_flags))
31606f25ae9SGregory Neil Shapiro 					(void) putc(c, df);
31706f25ae9SGregory Neil Shapiro 				/* FALLTHROUGH */
31825bab6e9SPeter Wemm 
31925bab6e9SPeter Wemm 			  case MS_DISCARD:
320c2aa98e2SPeter Wemm 				continue;
321c2aa98e2SPeter Wemm 			}
322c2aa98e2SPeter Wemm 
323c2aa98e2SPeter Wemm 			/* header -- buffer up */
324c2aa98e2SPeter Wemm 			if (bp >= &buf[buflen - 2])
325c2aa98e2SPeter Wemm 			{
326c2aa98e2SPeter Wemm 				char *obuf;
327c2aa98e2SPeter Wemm 
328c2aa98e2SPeter Wemm 				if (mstate != MS_HEADER)
329c2aa98e2SPeter Wemm 					break;
330c2aa98e2SPeter Wemm 
331c2aa98e2SPeter Wemm 				/* out of space for header */
332c2aa98e2SPeter Wemm 				obuf = buf;
333c2aa98e2SPeter Wemm 				if (buflen < MEMCHUNKSIZE)
334c2aa98e2SPeter Wemm 					buflen *= 2;
335c2aa98e2SPeter Wemm 				else
336c2aa98e2SPeter Wemm 					buflen += MEMCHUNKSIZE;
337c2aa98e2SPeter Wemm 				buf = xalloc(buflen);
33806f25ae9SGregory Neil Shapiro 				memmove(buf, obuf, bp - obuf);
339c2aa98e2SPeter Wemm 				bp = &buf[bp - obuf];
340c2aa98e2SPeter Wemm 				if (obuf != bufbuf)
3418774250cSGregory Neil Shapiro 					sm_free(obuf);
342c2aa98e2SPeter Wemm 			}
343c2aa98e2SPeter Wemm 			if (c >= 0200 && c <= 0237)
344c2aa98e2SPeter Wemm 			{
34506f25ae9SGregory Neil Shapiro #if 0	/* causes complaints -- figure out something for 8.11 */
346c2aa98e2SPeter Wemm 				usrerr("Illegal character 0x%x in header", c);
34706f25ae9SGregory Neil Shapiro #else /* 0 */
34806f25ae9SGregory Neil Shapiro 				/* EMPTY */
34906f25ae9SGregory Neil Shapiro #endif /* 0 */
350c2aa98e2SPeter Wemm 			}
351c2aa98e2SPeter Wemm 			else if (c != '\0')
35225bab6e9SPeter Wemm 			{
353c2aa98e2SPeter Wemm 				*bp++ = c;
354602a2b1bSGregory Neil Shapiro 				hdrslen++;
3552e43090eSPeter Wemm 				if (MaxHeadersLength > 0 &&
356602a2b1bSGregory Neil Shapiro 				    hdrslen > MaxHeadersLength)
35725bab6e9SPeter Wemm 				{
35825bab6e9SPeter Wemm 					sm_syslog(LOG_NOTICE, e->e_id,
3592e43090eSPeter Wemm 						  "headers too large (%d max) from %s during message collect",
3602e43090eSPeter Wemm 						  MaxHeadersLength,
36125bab6e9SPeter Wemm 						  CurHostName != NULL ? CurHostName : "localhost");
36225bab6e9SPeter Wemm 					errno = 0;
36325bab6e9SPeter Wemm 					e->e_flags |= EF_CLRQUEUE;
36425bab6e9SPeter Wemm 					e->e_status = "5.6.0";
36506f25ae9SGregory Neil Shapiro 					usrerrenh(e->e_status,
36606f25ae9SGregory Neil Shapiro 						  "552 Headers too large (%d max)",
3672e43090eSPeter Wemm 						  MaxHeadersLength);
36825bab6e9SPeter Wemm 					mstate = MS_DISCARD;
36925bab6e9SPeter Wemm 				}
37025bab6e9SPeter Wemm 			}
371c2aa98e2SPeter Wemm 			if (istate == IS_BOL)
372c2aa98e2SPeter Wemm 				break;
373c2aa98e2SPeter Wemm 		}
374c2aa98e2SPeter Wemm 		*bp = '\0';
375c2aa98e2SPeter Wemm 
376c2aa98e2SPeter Wemm nextstate:
377c2aa98e2SPeter Wemm 		if (tTd(30, 35))
37806f25ae9SGregory Neil Shapiro 			dprintf("nextstate, istate=%d, mstate=%d, line = \"%s\"\n",
379c2aa98e2SPeter Wemm 				istate, mstate, buf);
380c2aa98e2SPeter Wemm 		switch (mstate)
381c2aa98e2SPeter Wemm 		{
382c2aa98e2SPeter Wemm 		  case MS_UFROM:
383c2aa98e2SPeter Wemm 			mstate = MS_HEADER;
384c2aa98e2SPeter Wemm #ifndef NOTUNIX
385c2aa98e2SPeter Wemm 			if (strncmp(buf, "From ", 5) == 0)
386c2aa98e2SPeter Wemm 			{
387c2aa98e2SPeter Wemm 				bp = buf;
388c2aa98e2SPeter Wemm 				eatfrom(buf, e);
389c2aa98e2SPeter Wemm 				continue;
390c2aa98e2SPeter Wemm 			}
39106f25ae9SGregory Neil Shapiro #endif /* ! NOTUNIX */
39206f25ae9SGregory Neil Shapiro 			/* FALLTHROUGH */
393c2aa98e2SPeter Wemm 
394c2aa98e2SPeter Wemm 		  case MS_HEADER:
395c2aa98e2SPeter Wemm 			if (!isheader(buf))
396c2aa98e2SPeter Wemm 			{
397c2aa98e2SPeter Wemm 				mstate = MS_BODY;
398c2aa98e2SPeter Wemm 				goto nextstate;
399c2aa98e2SPeter Wemm 			}
400c2aa98e2SPeter Wemm 
401c2aa98e2SPeter Wemm 			/* check for possible continuation line */
402c2aa98e2SPeter Wemm 			do
403c2aa98e2SPeter Wemm 			{
404c2aa98e2SPeter Wemm 				clearerr(fp);
405c2aa98e2SPeter Wemm 				errno = 0;
406c2aa98e2SPeter Wemm 				c = getc(fp);
40742e5d165SGregory Neil Shapiro 			} while (c == EOF && errno == EINTR);
408c2aa98e2SPeter Wemm 			if (c != EOF)
40906f25ae9SGregory Neil Shapiro 				(void) ungetc(c, fp);
410c2aa98e2SPeter Wemm 			if (c == ' ' || c == '\t')
411c2aa98e2SPeter Wemm 			{
412c2aa98e2SPeter Wemm 				/* yep -- defer this */
413c2aa98e2SPeter Wemm 				continue;
414c2aa98e2SPeter Wemm 			}
415c2aa98e2SPeter Wemm 
416c2aa98e2SPeter Wemm 			/* trim off trailing CRLF or NL */
417c2aa98e2SPeter Wemm 			if (*--bp != '\n' || *--bp != '\r')
418c2aa98e2SPeter Wemm 				bp++;
419c2aa98e2SPeter Wemm 			*bp = '\0';
42025bab6e9SPeter Wemm 
42106f25ae9SGregory Neil Shapiro 			if (bitset(H_EOH, chompheader(buf,
42206f25ae9SGregory Neil Shapiro 						      CHHDR_CHECK | CHHDR_USER,
42306f25ae9SGregory Neil Shapiro 						      hdrp, e)))
424c2aa98e2SPeter Wemm 			{
425c2aa98e2SPeter Wemm 				mstate = MS_BODY;
426c2aa98e2SPeter Wemm 				goto nextstate;
427c2aa98e2SPeter Wemm 			}
42806f25ae9SGregory Neil Shapiro 			numhdrs++;
429c2aa98e2SPeter Wemm 			break;
430c2aa98e2SPeter Wemm 
431c2aa98e2SPeter Wemm 		  case MS_BODY:
432c2aa98e2SPeter Wemm 			if (tTd(30, 1))
43306f25ae9SGregory Neil Shapiro 				dprintf("EOH\n");
43406f25ae9SGregory Neil Shapiro 
435c2aa98e2SPeter Wemm 			if (headeronly)
436c2aa98e2SPeter Wemm 				goto readerr;
43706f25ae9SGregory Neil Shapiro 
43806f25ae9SGregory Neil Shapiro 			/* call the end-of-header check ruleset */
43906f25ae9SGregory Neil Shapiro 			snprintf(hnum, sizeof hnum, "%d", numhdrs);
44006f25ae9SGregory Neil Shapiro 			snprintf(hsize, sizeof hsize, "%d", hdrslen);
44106f25ae9SGregory Neil Shapiro 			if (tTd(30, 10))
44206f25ae9SGregory Neil Shapiro 				dprintf("collect: rscheck(\"check_eoh\", \"%s $| %s\")\n",
44306f25ae9SGregory Neil Shapiro 					hnum, hsize);
44406f25ae9SGregory Neil Shapiro 			rstat = rscheck("check_eoh", hnum, hsize, e, FALSE,
445193538b7SGregory Neil Shapiro 					TRUE, 4, NULL);
44606f25ae9SGregory Neil Shapiro 
447c2aa98e2SPeter Wemm 			bp = buf;
448c2aa98e2SPeter Wemm 
449c2aa98e2SPeter Wemm 			/* toss blank line */
450c2aa98e2SPeter Wemm 			if ((!bitset(EF_CRLF_NOT_EOL, e->e_flags) &&
451c2aa98e2SPeter Wemm 				bp[0] == '\r' && bp[1] == '\n') ||
452c2aa98e2SPeter Wemm 			    (!bitset(EF_NL_NOT_EOL, e->e_flags) &&
453c2aa98e2SPeter Wemm 				bp[0] == '\n'))
454c2aa98e2SPeter Wemm 			{
455c2aa98e2SPeter Wemm 				break;
456c2aa98e2SPeter Wemm 			}
457c2aa98e2SPeter Wemm 
458c2aa98e2SPeter Wemm 			/* if not a blank separator, write it out */
45942e5d165SGregory Neil Shapiro 			if (!bitset(EF_TOOBIG, e->e_flags))
460c2aa98e2SPeter Wemm 			{
461c2aa98e2SPeter Wemm 				while (*bp != '\0')
46206f25ae9SGregory Neil Shapiro 					(void) putc(*bp++, df);
463c2aa98e2SPeter Wemm 			}
464c2aa98e2SPeter Wemm 			break;
465c2aa98e2SPeter Wemm 		}
466c2aa98e2SPeter Wemm 		bp = buf;
467c2aa98e2SPeter Wemm 	}
468c2aa98e2SPeter Wemm 
469c2aa98e2SPeter Wemm readerr:
470c2aa98e2SPeter Wemm 	if ((feof(fp) && smtpmode) || ferror(fp))
471c2aa98e2SPeter Wemm 	{
472c2aa98e2SPeter Wemm 		const char *errmsg = errstring(errno);
473c2aa98e2SPeter Wemm 
474c2aa98e2SPeter Wemm 		if (tTd(30, 1))
47506f25ae9SGregory Neil Shapiro 			dprintf("collect: premature EOM: %s\n", errmsg);
476c2aa98e2SPeter Wemm 		if (LogLevel >= 2)
477c2aa98e2SPeter Wemm 			sm_syslog(LOG_WARNING, e->e_id,
478c2aa98e2SPeter Wemm 				"collect: premature EOM: %s", errmsg);
479c2aa98e2SPeter Wemm 		inputerr = TRUE;
480c2aa98e2SPeter Wemm 	}
481c2aa98e2SPeter Wemm 
482c2aa98e2SPeter Wemm 	/* reset global timer */
4838774250cSGregory Neil Shapiro 	if (CollectTimeout != NULL)
484c2aa98e2SPeter Wemm 		clrevent(CollectTimeout);
485c2aa98e2SPeter Wemm 
486c2aa98e2SPeter Wemm 	if (headeronly)
487c2aa98e2SPeter Wemm 		return;
488c2aa98e2SPeter Wemm 
48906f25ae9SGregory Neil Shapiro 	if (df == NULL)
490c2aa98e2SPeter Wemm 	{
49106f25ae9SGregory Neil Shapiro 		/* skip next few clauses */
49206f25ae9SGregory Neil Shapiro 		/* EMPTY */
49306f25ae9SGregory Neil Shapiro 	}
49406f25ae9SGregory Neil Shapiro 	else if (fflush(df) != 0 || ferror(df))
49506f25ae9SGregory Neil Shapiro 	{
49606f25ae9SGregory Neil Shapiro 		dferror(df, "fflush||ferror", e);
497c2aa98e2SPeter Wemm 		flush_errors(TRUE);
498065a643dSPeter Wemm 		finis(TRUE, ExitStat);
49906f25ae9SGregory Neil Shapiro 		/* NOTREACHED */
50006f25ae9SGregory Neil Shapiro 	}
50106f25ae9SGregory Neil Shapiro 	else if (!SuperSafe)
50206f25ae9SGregory Neil Shapiro 	{
50306f25ae9SGregory Neil Shapiro 		/* skip next few clauses */
50406f25ae9SGregory Neil Shapiro 		/* EMPTY */
50506f25ae9SGregory Neil Shapiro 	}
50606f25ae9SGregory Neil Shapiro 	else if (bfcommit(df) < 0)
50706f25ae9SGregory Neil Shapiro 	{
50806f25ae9SGregory Neil Shapiro 		int save_errno = errno;
50906f25ae9SGregory Neil Shapiro 
51006f25ae9SGregory Neil Shapiro 		if (save_errno == EEXIST)
51106f25ae9SGregory Neil Shapiro 		{
51206f25ae9SGregory Neil Shapiro 			char *dfile;
51306f25ae9SGregory Neil Shapiro 			struct stat st;
51406f25ae9SGregory Neil Shapiro 
51506f25ae9SGregory Neil Shapiro 			dfile = queuename(e, 'd');
51606f25ae9SGregory Neil Shapiro 			if (stat(dfile, &st) < 0)
51706f25ae9SGregory Neil Shapiro 				st.st_size = -1;
51806f25ae9SGregory Neil Shapiro 			errno = EEXIST;
51906f25ae9SGregory Neil Shapiro 			syserr("collect: bfcommit(%s): already on disk, size = %ld",
52042e5d165SGregory Neil Shapiro 			       dfile, (long) st.st_size);
52106f25ae9SGregory Neil Shapiro 			dfd = fileno(df);
52206f25ae9SGregory Neil Shapiro 			if (dfd >= 0)
52306f25ae9SGregory Neil Shapiro 				dumpfd(dfd, TRUE, TRUE);
52406f25ae9SGregory Neil Shapiro 		}
52506f25ae9SGregory Neil Shapiro 		errno = save_errno;
52606f25ae9SGregory Neil Shapiro 		dferror(df, "bfcommit", e);
52706f25ae9SGregory Neil Shapiro 		flush_errors(TRUE);
52806f25ae9SGregory Neil Shapiro 		finis(save_errno != EEXIST, ExitStat);
52906f25ae9SGregory Neil Shapiro 	}
530602a2b1bSGregory Neil Shapiro 	else if (bffsync(df) < 0)
531602a2b1bSGregory Neil Shapiro 	{
532602a2b1bSGregory Neil Shapiro 		dferror(df, "bffsync", e);
533602a2b1bSGregory Neil Shapiro 		flush_errors(TRUE);
534602a2b1bSGregory Neil Shapiro 		finis(TRUE, ExitStat);
535602a2b1bSGregory Neil Shapiro 		/* NOTREACHED */
536602a2b1bSGregory Neil Shapiro 	}
53706f25ae9SGregory Neil Shapiro 	else if (bfclose(df) < 0)
53806f25ae9SGregory Neil Shapiro 	{
53906f25ae9SGregory Neil Shapiro 		dferror(df, "bfclose", e);
54006f25ae9SGregory Neil Shapiro 		flush_errors(TRUE);
54106f25ae9SGregory Neil Shapiro 		finis(TRUE, ExitStat);
54206f25ae9SGregory Neil Shapiro 		/* NOTREACHED */
54306f25ae9SGregory Neil Shapiro 	}
54406f25ae9SGregory Neil Shapiro 	else
54506f25ae9SGregory Neil Shapiro 	{
54606f25ae9SGregory Neil Shapiro 		/* everything is happily flushed to disk */
54706f25ae9SGregory Neil Shapiro 		df = NULL;
548c2aa98e2SPeter Wemm 	}
549c2aa98e2SPeter Wemm 
550c2aa98e2SPeter Wemm 	/* An EOF when running SMTP is an error */
551c2aa98e2SPeter Wemm 	if (inputerr && (OpMode == MD_SMTP || OpMode == MD_DAEMON))
552c2aa98e2SPeter Wemm 	{
553c2aa98e2SPeter Wemm 		char *host;
554c2aa98e2SPeter Wemm 		char *problem;
555c2aa98e2SPeter Wemm 
556c2aa98e2SPeter Wemm 		host = RealHostName;
557c2aa98e2SPeter Wemm 		if (host == NULL)
558c2aa98e2SPeter Wemm 			host = "localhost";
559c2aa98e2SPeter Wemm 
560c2aa98e2SPeter Wemm 		if (feof(fp))
561c2aa98e2SPeter Wemm 			problem = "unexpected close";
562c2aa98e2SPeter Wemm 		else if (ferror(fp))
563c2aa98e2SPeter Wemm 			problem = "I/O error";
564c2aa98e2SPeter Wemm 		else
565c2aa98e2SPeter Wemm 			problem = "read timeout";
566c2aa98e2SPeter Wemm 		if (LogLevel > 0 && feof(fp))
567c2aa98e2SPeter Wemm 			sm_syslog(LOG_NOTICE, e->e_id,
568c2aa98e2SPeter Wemm 			    "collect: %s on connection from %.100s, sender=%s: %s",
569c2aa98e2SPeter Wemm 			    problem, host,
570c2aa98e2SPeter Wemm 			    shortenstring(e->e_from.q_paddr, MAXSHORTSTR),
571c2aa98e2SPeter Wemm 			    errstring(errno));
572c2aa98e2SPeter Wemm 		if (feof(fp))
57306f25ae9SGregory Neil Shapiro 			usrerr("451 4.4.1 collect: %s on connection from %s, from=%s",
574c2aa98e2SPeter Wemm 				problem, host,
575c2aa98e2SPeter Wemm 				shortenstring(e->e_from.q_paddr, MAXSHORTSTR));
576c2aa98e2SPeter Wemm 		else
57706f25ae9SGregory Neil Shapiro 			syserr("451 4.4.1 collect: %s on connection from %s, from=%s",
578c2aa98e2SPeter Wemm 				problem, host,
579c2aa98e2SPeter Wemm 				shortenstring(e->e_from.q_paddr, MAXSHORTSTR));
580c2aa98e2SPeter Wemm 
581c2aa98e2SPeter Wemm 		/* don't return an error indication */
582c2aa98e2SPeter Wemm 		e->e_to = NULL;
583c2aa98e2SPeter Wemm 		e->e_flags &= ~EF_FATALERRS;
584c2aa98e2SPeter Wemm 		e->e_flags |= EF_CLRQUEUE;
585c2aa98e2SPeter Wemm 
586c2aa98e2SPeter Wemm 		/* and don't try to deliver the partial message either */
587c2aa98e2SPeter Wemm 		if (InChild)
588c2aa98e2SPeter Wemm 			ExitStat = EX_QUIT;
589065a643dSPeter Wemm 		finis(TRUE, ExitStat);
59006f25ae9SGregory Neil Shapiro 		/* NOTREACHED */
591c2aa98e2SPeter Wemm 	}
592c2aa98e2SPeter Wemm 
593c2aa98e2SPeter Wemm 	/*
594c2aa98e2SPeter Wemm 	**  Find out some information from the headers.
595c2aa98e2SPeter Wemm 	**	Examples are who is the from person & the date.
596c2aa98e2SPeter Wemm 	*/
597c2aa98e2SPeter Wemm 
598c2aa98e2SPeter Wemm 	eatheader(e, TRUE);
599c2aa98e2SPeter Wemm 
600c2aa98e2SPeter Wemm 	if (GrabTo && e->e_sendqueue == NULL)
601c2aa98e2SPeter Wemm 		usrerr("No recipient addresses found in header");
602c2aa98e2SPeter Wemm 
603c2aa98e2SPeter Wemm 	/* collect statistics */
604c2aa98e2SPeter Wemm 	if (OpMode != MD_VERIFY)
605c2aa98e2SPeter Wemm 		markstats(e, (ADDRESS *) NULL, FALSE);
606c2aa98e2SPeter Wemm 
607c2aa98e2SPeter Wemm 	/*
608c2aa98e2SPeter Wemm 	**  If we have a Return-Receipt-To:, turn it into a DSN.
609c2aa98e2SPeter Wemm 	*/
610c2aa98e2SPeter Wemm 
611c2aa98e2SPeter Wemm 	if (RrtImpliesDsn && hvalue("return-receipt-to", e->e_header) != NULL)
612c2aa98e2SPeter Wemm 	{
613c2aa98e2SPeter Wemm 		ADDRESS *q;
614c2aa98e2SPeter Wemm 
615c2aa98e2SPeter Wemm 		for (q = e->e_sendqueue; q != NULL; q = q->q_next)
616c2aa98e2SPeter Wemm 			if (!bitset(QHASNOTIFY, q->q_flags))
617c2aa98e2SPeter Wemm 				q->q_flags |= QHASNOTIFY|QPINGONSUCCESS;
618c2aa98e2SPeter Wemm 	}
619c2aa98e2SPeter Wemm 
620c2aa98e2SPeter Wemm 	/*
621c2aa98e2SPeter Wemm 	**  Add an Apparently-To: line if we have no recipient lines.
622c2aa98e2SPeter Wemm 	*/
623c2aa98e2SPeter Wemm 
624c2aa98e2SPeter Wemm 	if (hvalue("to", e->e_header) != NULL ||
625c2aa98e2SPeter Wemm 	    hvalue("cc", e->e_header) != NULL ||
626c2aa98e2SPeter Wemm 	    hvalue("apparently-to", e->e_header) != NULL)
627c2aa98e2SPeter Wemm 	{
628c2aa98e2SPeter Wemm 		/* have a valid recipient header -- delete Bcc: headers */
629c2aa98e2SPeter Wemm 		e->e_flags |= EF_DELETE_BCC;
630c2aa98e2SPeter Wemm 	}
631c2aa98e2SPeter Wemm 	else if (hvalue("bcc", e->e_header) == NULL)
632c2aa98e2SPeter Wemm 	{
633c2aa98e2SPeter Wemm 		/* no valid recipient headers */
634c2aa98e2SPeter Wemm 		register ADDRESS *q;
635c2aa98e2SPeter Wemm 		char *hdr = NULL;
636c2aa98e2SPeter Wemm 
637c2aa98e2SPeter Wemm 		/* create an Apparently-To: field */
638c2aa98e2SPeter Wemm 		/*    that or reject the message.... */
639c2aa98e2SPeter Wemm 		switch (NoRecipientAction)
640c2aa98e2SPeter Wemm 		{
641c2aa98e2SPeter Wemm 		  case NRA_ADD_APPARENTLY_TO:
642c2aa98e2SPeter Wemm 			hdr = "Apparently-To";
643c2aa98e2SPeter Wemm 			break;
644c2aa98e2SPeter Wemm 
645c2aa98e2SPeter Wemm 		  case NRA_ADD_TO:
646c2aa98e2SPeter Wemm 			hdr = "To";
647c2aa98e2SPeter Wemm 			break;
648c2aa98e2SPeter Wemm 
649c2aa98e2SPeter Wemm 		  case NRA_ADD_BCC:
65006f25ae9SGregory Neil Shapiro 			addheader("Bcc", " ", 0, &e->e_header);
651c2aa98e2SPeter Wemm 			break;
652c2aa98e2SPeter Wemm 
653c2aa98e2SPeter Wemm 		  case NRA_ADD_TO_UNDISCLOSED:
65406f25ae9SGregory Neil Shapiro 			addheader("To", "undisclosed-recipients:;", 0, &e->e_header);
655c2aa98e2SPeter Wemm 			break;
656c2aa98e2SPeter Wemm 		}
657c2aa98e2SPeter Wemm 
658c2aa98e2SPeter Wemm 		if (hdr != NULL)
659c2aa98e2SPeter Wemm 		{
660c2aa98e2SPeter Wemm 			for (q = e->e_sendqueue; q != NULL; q = q->q_next)
661c2aa98e2SPeter Wemm 			{
662c2aa98e2SPeter Wemm 				if (q->q_alias != NULL)
663c2aa98e2SPeter Wemm 					continue;
664c2aa98e2SPeter Wemm 				if (tTd(30, 3))
66506f25ae9SGregory Neil Shapiro 					dprintf("Adding %s: %s\n",
666c2aa98e2SPeter Wemm 						hdr, q->q_paddr);
66706f25ae9SGregory Neil Shapiro 				addheader(hdr, q->q_paddr, 0, &e->e_header);
668c2aa98e2SPeter Wemm 			}
669c2aa98e2SPeter Wemm 		}
670c2aa98e2SPeter Wemm 	}
671c2aa98e2SPeter Wemm 
672c2aa98e2SPeter Wemm 	/* check for message too large */
67342e5d165SGregory Neil Shapiro 	if (bitset(EF_TOOBIG, e->e_flags))
674c2aa98e2SPeter Wemm 	{
675c2aa98e2SPeter Wemm 		e->e_flags |= EF_NO_BODY_RETN|EF_CLRQUEUE;
676c2aa98e2SPeter Wemm 		e->e_status = "5.2.3";
67706f25ae9SGregory Neil Shapiro 		usrerrenh(e->e_status,
67806f25ae9SGregory Neil Shapiro 			  "552 Message exceeds maximum fixed size (%ld)",
679c2aa98e2SPeter Wemm 			  MaxMessageSize);
680c2aa98e2SPeter Wemm 		if (LogLevel > 6)
681c2aa98e2SPeter Wemm 			sm_syslog(LOG_NOTICE, e->e_id,
682c2aa98e2SPeter Wemm 				"message size (%ld) exceeds maximum (%ld)",
683c2aa98e2SPeter Wemm 				e->e_msgsize, MaxMessageSize);
684c2aa98e2SPeter Wemm 	}
685c2aa98e2SPeter Wemm 
686c2aa98e2SPeter Wemm 	/* check for illegal 8-bit data */
687c2aa98e2SPeter Wemm 	if (HasEightBits)
688c2aa98e2SPeter Wemm 	{
689c2aa98e2SPeter Wemm 		e->e_flags |= EF_HAS8BIT;
690c2aa98e2SPeter Wemm 		if (!bitset(MM_PASS8BIT|MM_MIME8BIT, MimeMode) &&
691c2aa98e2SPeter Wemm 		    !bitset(EF_IS_MIME, e->e_flags))
692c2aa98e2SPeter Wemm 		{
693c2aa98e2SPeter Wemm 			e->e_status = "5.6.1";
69406f25ae9SGregory Neil Shapiro 			usrerrenh(e->e_status, "554 Eight bit data not allowed");
695c2aa98e2SPeter Wemm 		}
696c2aa98e2SPeter Wemm 	}
697c2aa98e2SPeter Wemm 	else
698c2aa98e2SPeter Wemm 	{
699c2aa98e2SPeter Wemm 		/* if it claimed to be 8 bits, well, it lied.... */
700c2aa98e2SPeter Wemm 		if (e->e_bodytype != NULL &&
701c2aa98e2SPeter Wemm 		    strcasecmp(e->e_bodytype, "8BITMIME") == 0)
702c2aa98e2SPeter Wemm 			e->e_bodytype = "7BIT";
703c2aa98e2SPeter Wemm 	}
704c2aa98e2SPeter Wemm 
70506f25ae9SGregory Neil Shapiro 	if (SuperSafe)
70606f25ae9SGregory Neil Shapiro 	{
707c2aa98e2SPeter Wemm 		if ((e->e_dfp = fopen(dfname, "r")) == NULL)
708c2aa98e2SPeter Wemm 		{
709c2aa98e2SPeter Wemm 			/* we haven't acked receipt yet, so just chuck this */
710c2aa98e2SPeter Wemm 			syserr("Cannot reopen %s", dfname);
711065a643dSPeter Wemm 			finis(TRUE, ExitStat);
71206f25ae9SGregory Neil Shapiro 			/* NOTREACHED */
713c2aa98e2SPeter Wemm 		}
714c2aa98e2SPeter Wemm 	}
71506f25ae9SGregory Neil Shapiro 	else
71606f25ae9SGregory Neil Shapiro 		e->e_dfp = df;
71706f25ae9SGregory Neil Shapiro 	if (e->e_dfp == NULL)
71806f25ae9SGregory Neil Shapiro 		syserr("!collect: no e_dfp");
71906f25ae9SGregory Neil Shapiro }
720c2aa98e2SPeter Wemm 
721c2aa98e2SPeter Wemm 
722c2aa98e2SPeter Wemm static void
723c2aa98e2SPeter Wemm collecttimeout(timeout)
724c2aa98e2SPeter Wemm 	time_t timeout;
725c2aa98e2SPeter Wemm {
7268774250cSGregory Neil Shapiro 	int save_errno = errno;
727c2aa98e2SPeter Wemm 
7288774250cSGregory Neil Shapiro 	/*
7298774250cSGregory Neil Shapiro 	**  NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER.  DO NOT ADD
7308774250cSGregory Neil Shapiro 	**	ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
7318774250cSGregory Neil Shapiro 	**	DOING.
7328774250cSGregory Neil Shapiro 	*/
7338774250cSGregory Neil Shapiro 
7348774250cSGregory Neil Shapiro 	if (CollectProgress)
7358774250cSGregory Neil Shapiro 	{
7368774250cSGregory Neil Shapiro 		/* reset the timeout */
7378774250cSGregory Neil Shapiro 		CollectTimeout = sigsafe_setevent(timeout, collecttimeout,
7388774250cSGregory Neil Shapiro 						  timeout);
739c2aa98e2SPeter Wemm 		CollectProgress = FALSE;
740c2aa98e2SPeter Wemm 	}
7418774250cSGregory Neil Shapiro 	else
7428774250cSGregory Neil Shapiro 	{
7438774250cSGregory Neil Shapiro 		/* event is done */
7448774250cSGregory Neil Shapiro 		CollectTimeout = NULL;
7458774250cSGregory Neil Shapiro 	}
7468774250cSGregory Neil Shapiro 
7478774250cSGregory Neil Shapiro 	/* if no progress was made or problem resetting event, die now */
7488774250cSGregory Neil Shapiro 	if (CollectTimeout == NULL)
7498774250cSGregory Neil Shapiro 	{
7508774250cSGregory Neil Shapiro 		errno = ETIMEDOUT;
7518774250cSGregory Neil Shapiro 		longjmp(CtxCollectTimeout, 1);
7528774250cSGregory Neil Shapiro 	}
7538774250cSGregory Neil Shapiro 
7548774250cSGregory Neil Shapiro 	errno = save_errno;
7558774250cSGregory Neil Shapiro }
7568774250cSGregory Neil Shapiro /*
75706f25ae9SGregory Neil Shapiro **  DFERROR -- signal error on writing the data file.
758c2aa98e2SPeter Wemm **
759c2aa98e2SPeter Wemm **	Parameters:
76006f25ae9SGregory Neil Shapiro **		df -- the file pointer for the data file.
76106f25ae9SGregory Neil Shapiro **		msg -- detailed message.
762c2aa98e2SPeter Wemm **		e -- the current envelope.
763c2aa98e2SPeter Wemm **
764c2aa98e2SPeter Wemm **	Returns:
765c2aa98e2SPeter Wemm **		none.
766c2aa98e2SPeter Wemm **
767c2aa98e2SPeter Wemm **	Side Effects:
768c2aa98e2SPeter Wemm **		Gives an error message.
769c2aa98e2SPeter Wemm **		Arranges for following output to go elsewhere.
770c2aa98e2SPeter Wemm */
771c2aa98e2SPeter Wemm 
77206f25ae9SGregory Neil Shapiro static void
77306f25ae9SGregory Neil Shapiro dferror(df, msg, e)
77406f25ae9SGregory Neil Shapiro 	FILE *volatile df;
77506f25ae9SGregory Neil Shapiro 	char *msg;
776c2aa98e2SPeter Wemm 	register ENVELOPE *e;
777c2aa98e2SPeter Wemm {
77806f25ae9SGregory Neil Shapiro 	char *dfname;
77906f25ae9SGregory Neil Shapiro 
78006f25ae9SGregory Neil Shapiro 	dfname = queuename(e, 'd');
781c2aa98e2SPeter Wemm 	setstat(EX_IOERR);
782c2aa98e2SPeter Wemm 	if (errno == ENOSPC)
783c2aa98e2SPeter Wemm 	{
784c2aa98e2SPeter Wemm #if STAT64 > 0
785c2aa98e2SPeter Wemm 		struct stat64 st;
78606f25ae9SGregory Neil Shapiro #else /* STAT64 > 0 */
787c2aa98e2SPeter Wemm 		struct stat st;
78806f25ae9SGregory Neil Shapiro #endif /* STAT64 > 0 */
789c2aa98e2SPeter Wemm 		long avail;
790c2aa98e2SPeter Wemm 		long bsize;
791c2aa98e2SPeter Wemm 
792c2aa98e2SPeter Wemm 		e->e_flags |= EF_NO_BODY_RETN;
793c2aa98e2SPeter Wemm 
794c2aa98e2SPeter Wemm 		if (
795c2aa98e2SPeter Wemm #if STAT64 > 0
79606f25ae9SGregory Neil Shapiro 		    fstat64(fileno(df), &st)
79706f25ae9SGregory Neil Shapiro #else /* STAT64 > 0 */
79806f25ae9SGregory Neil Shapiro 		    fstat(fileno(df), &st)
79906f25ae9SGregory Neil Shapiro #endif /* STAT64 > 0 */
800c2aa98e2SPeter Wemm 		    < 0)
801c2aa98e2SPeter Wemm 		  st.st_size = 0;
80206f25ae9SGregory Neil Shapiro 		(void) freopen(dfname, "w", df);
803c2aa98e2SPeter Wemm 		if (st.st_size <= 0)
80406f25ae9SGregory Neil Shapiro 			fprintf(df, "\n*** Mail could not be accepted");
80506f25ae9SGregory Neil Shapiro 		/*CONSTCOND*/
806c2aa98e2SPeter Wemm 		else if (sizeof st.st_size > sizeof (long))
80706f25ae9SGregory Neil Shapiro 			fprintf(df, "\n*** Mail of at least %s bytes could not be accepted\n",
808c2aa98e2SPeter Wemm 				quad_to_string(st.st_size));
809c2aa98e2SPeter Wemm 		else
81006f25ae9SGregory Neil Shapiro 			fprintf(df, "\n*** Mail of at least %lu bytes could not be accepted\n",
811c2aa98e2SPeter Wemm 				(unsigned long) st.st_size);
81206f25ae9SGregory Neil Shapiro 		fprintf(df, "*** at %s due to lack of disk space for temp file.\n",
813c2aa98e2SPeter Wemm 			MyHostName);
81406f25ae9SGregory Neil Shapiro 		avail = freediskspace(qid_printqueue(e->e_queuedir), &bsize);
815c2aa98e2SPeter Wemm 		if (avail > 0)
816c2aa98e2SPeter Wemm 		{
817c2aa98e2SPeter Wemm 			if (bsize > 1024)
818c2aa98e2SPeter Wemm 				avail *= bsize / 1024;
819c2aa98e2SPeter Wemm 			else if (bsize < 1024)
820c2aa98e2SPeter Wemm 				avail /= 1024 / bsize;
82106f25ae9SGregory Neil Shapiro 			fprintf(df, "*** Currently, %ld kilobytes are available for mail temp files.\n",
822c2aa98e2SPeter Wemm 				avail);
823c2aa98e2SPeter Wemm 		}
824c2aa98e2SPeter Wemm 		e->e_status = "4.3.1";
82506f25ae9SGregory Neil Shapiro 		usrerrenh(e->e_status, "452 Out of disk space for temp file");
826c2aa98e2SPeter Wemm 	}
827c2aa98e2SPeter Wemm 	else
82806f25ae9SGregory Neil Shapiro 		syserr("collect: Cannot write %s (%s, uid=%d)",
82906f25ae9SGregory Neil Shapiro 			dfname, msg, geteuid());
83006f25ae9SGregory Neil Shapiro 	if (freopen("/dev/null", "w", df) == NULL)
831c2aa98e2SPeter Wemm 		sm_syslog(LOG_ERR, e->e_id,
83206f25ae9SGregory Neil Shapiro 			  "dferror: freopen(\"/dev/null\") failed: %s",
833c2aa98e2SPeter Wemm 			  errstring(errno));
834c2aa98e2SPeter Wemm }
835c2aa98e2SPeter Wemm /*
836c2aa98e2SPeter Wemm **  EATFROM -- chew up a UNIX style from line and process
837c2aa98e2SPeter Wemm **
838c2aa98e2SPeter Wemm **	This does indeed make some assumptions about the format
839c2aa98e2SPeter Wemm **	of UNIX messages.
840c2aa98e2SPeter Wemm **
841c2aa98e2SPeter Wemm **	Parameters:
842c2aa98e2SPeter Wemm **		fm -- the from line.
843c2aa98e2SPeter Wemm **
844c2aa98e2SPeter Wemm **	Returns:
845c2aa98e2SPeter Wemm **		none.
846c2aa98e2SPeter Wemm **
847c2aa98e2SPeter Wemm **	Side Effects:
848c2aa98e2SPeter Wemm **		extracts what information it can from the header,
849c2aa98e2SPeter Wemm **		such as the date.
850c2aa98e2SPeter Wemm */
851c2aa98e2SPeter Wemm 
852c2aa98e2SPeter Wemm #ifndef NOTUNIX
853c2aa98e2SPeter Wemm 
85406f25ae9SGregory Neil Shapiro static char	*DowList[] =
855c2aa98e2SPeter Wemm {
856c2aa98e2SPeter Wemm 	"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", NULL
857c2aa98e2SPeter Wemm };
858c2aa98e2SPeter Wemm 
85906f25ae9SGregory Neil Shapiro static char	*MonthList[] =
860c2aa98e2SPeter Wemm {
861c2aa98e2SPeter Wemm 	"Jan", "Feb", "Mar", "Apr", "May", "Jun",
862c2aa98e2SPeter Wemm 	"Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
863c2aa98e2SPeter Wemm 	NULL
864c2aa98e2SPeter Wemm };
865c2aa98e2SPeter Wemm 
86606f25ae9SGregory Neil Shapiro static void
867c2aa98e2SPeter Wemm eatfrom(fm, e)
868c2aa98e2SPeter Wemm 	char *volatile fm;
869c2aa98e2SPeter Wemm 	register ENVELOPE *e;
870c2aa98e2SPeter Wemm {
871c2aa98e2SPeter Wemm 	register char *p;
872c2aa98e2SPeter Wemm 	register char **dt;
873c2aa98e2SPeter Wemm 
874c2aa98e2SPeter Wemm 	if (tTd(30, 2))
87506f25ae9SGregory Neil Shapiro 		dprintf("eatfrom(%s)\n", fm);
876c2aa98e2SPeter Wemm 
877c2aa98e2SPeter Wemm 	/* find the date part */
878c2aa98e2SPeter Wemm 	p = fm;
879c2aa98e2SPeter Wemm 	while (*p != '\0')
880c2aa98e2SPeter Wemm 	{
881c2aa98e2SPeter Wemm 		/* skip a word */
882c2aa98e2SPeter Wemm 		while (*p != '\0' && *p != ' ')
883c2aa98e2SPeter Wemm 			p++;
884c2aa98e2SPeter Wemm 		while (*p == ' ')
885c2aa98e2SPeter Wemm 			p++;
886193538b7SGregory Neil Shapiro 		if (strlen(p) < 17)
887193538b7SGregory Neil Shapiro 		{
888193538b7SGregory Neil Shapiro 			/* no room for the date */
889193538b7SGregory Neil Shapiro 			return;
890193538b7SGregory Neil Shapiro 		}
891c2aa98e2SPeter Wemm 		if (!(isascii(*p) && isupper(*p)) ||
892c2aa98e2SPeter Wemm 		    p[3] != ' ' || p[13] != ':' || p[16] != ':')
893c2aa98e2SPeter Wemm 			continue;
894c2aa98e2SPeter Wemm 
895c2aa98e2SPeter Wemm 		/* we have a possible date */
896c2aa98e2SPeter Wemm 		for (dt = DowList; *dt != NULL; dt++)
897c2aa98e2SPeter Wemm 			if (strncmp(*dt, p, 3) == 0)
898c2aa98e2SPeter Wemm 				break;
899c2aa98e2SPeter Wemm 		if (*dt == NULL)
900c2aa98e2SPeter Wemm 			continue;
901c2aa98e2SPeter Wemm 
902c2aa98e2SPeter Wemm 		for (dt = MonthList; *dt != NULL; dt++)
903193538b7SGregory Neil Shapiro 		{
904c2aa98e2SPeter Wemm 			if (strncmp(*dt, &p[4], 3) == 0)
905c2aa98e2SPeter Wemm 				break;
906193538b7SGregory Neil Shapiro 		}
907c2aa98e2SPeter Wemm 		if (*dt != NULL)
908c2aa98e2SPeter Wemm 			break;
909c2aa98e2SPeter Wemm 	}
910c2aa98e2SPeter Wemm 
911c2aa98e2SPeter Wemm 	if (*p != '\0')
912c2aa98e2SPeter Wemm 	{
913c2aa98e2SPeter Wemm 		char *q;
914c2aa98e2SPeter Wemm 
915c2aa98e2SPeter Wemm 		/* we have found a date */
916c2aa98e2SPeter Wemm 		q = xalloc(25);
91706f25ae9SGregory Neil Shapiro 		(void) strlcpy(q, p, 25);
918c2aa98e2SPeter Wemm 		q = arpadate(q);
919c2aa98e2SPeter Wemm 		define('a', newstr(q), e);
920c2aa98e2SPeter Wemm 	}
921c2aa98e2SPeter Wemm }
92206f25ae9SGregory Neil Shapiro #endif /* ! NOTUNIX */
923