xref: /freebsd/contrib/sendmail/src/collect.c (revision 06f25ae9f1d6020a600a10f713046203d1a82570)
1c2aa98e2SPeter Wemm /*
206f25ae9SGregory Neil Shapiro  * Copyright (c) 1998-2000 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
1506f25ae9SGregory Neil Shapiro static char id[] = "@(#)$Id: collect.c,v 8.136.4.3 2000/06/22 22:13:45 geir 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 afd;
8806f25ae9SGregory Neil Shapiro 	volatile int rstat = EX_OK;
89c2aa98e2SPeter Wemm 	u_char *volatile pbp;
90c2aa98e2SPeter Wemm 	u_char peekbuf[8];
9106f25ae9SGregory Neil Shapiro 	char hsize[16];
9206f25ae9SGregory Neil Shapiro 	char hnum[16];
9306f25ae9SGregory Neil Shapiro 	char dfname[MAXPATHLEN];
94c2aa98e2SPeter Wemm 	char bufbuf[MAXLINE];
95c2aa98e2SPeter Wemm 
96c2aa98e2SPeter Wemm 	headeronly = hdrp != NULL;
97c2aa98e2SPeter Wemm 
98c2aa98e2SPeter Wemm 	/*
99c2aa98e2SPeter Wemm 	**  Create the temp file name and create the file.
100c2aa98e2SPeter Wemm 	*/
101c2aa98e2SPeter Wemm 
102c2aa98e2SPeter Wemm 	if (!headeronly)
103c2aa98e2SPeter Wemm 	{
104c2aa98e2SPeter Wemm 		struct stat stbuf;
105c2aa98e2SPeter Wemm 
10606f25ae9SGregory Neil Shapiro 		(void) strlcpy(dfname, queuename(e, 'd'), sizeof dfname);
10706f25ae9SGregory Neil Shapiro #if _FFR_QUEUE_FILE_MODE
10806f25ae9SGregory Neil Shapiro 		{
10906f25ae9SGregory Neil Shapiro 			MODE_T oldumask;
11006f25ae9SGregory Neil Shapiro 
11106f25ae9SGregory Neil Shapiro 			if (bitset(S_IWGRP, QueueFileMode))
11206f25ae9SGregory Neil Shapiro 				oldumask = umask(002);
11306f25ae9SGregory Neil Shapiro 			df = bfopen(dfname, QueueFileMode, DataFileBufferSize,
11406f25ae9SGregory Neil Shapiro 				    SFF_OPENASROOT);
11506f25ae9SGregory Neil Shapiro 			if (bitset(S_IWGRP, QueueFileMode))
11606f25ae9SGregory Neil Shapiro 				(void) umask(oldumask);
11706f25ae9SGregory Neil Shapiro 		}
11806f25ae9SGregory Neil Shapiro #else /* _FFR_QUEUE_FILE_MODE */
11906f25ae9SGregory Neil Shapiro 		df = bfopen(dfname, FileMode, DataFileBufferSize,
12006f25ae9SGregory Neil Shapiro 			    SFF_OPENASROOT);
12106f25ae9SGregory Neil Shapiro #endif /* _FFR_QUEUE_FILE_MODE */
12206f25ae9SGregory Neil Shapiro 		if (df == NULL)
123c2aa98e2SPeter Wemm 		{
124c2aa98e2SPeter Wemm 			syserr("Cannot create %s", dfname);
125c2aa98e2SPeter Wemm 			e->e_flags |= EF_NO_BODY_RETN;
126065a643dSPeter Wemm 			finis(TRUE, ExitStat);
12706f25ae9SGregory Neil Shapiro 			/* NOTREACHED */
128c2aa98e2SPeter Wemm 		}
12906f25ae9SGregory Neil Shapiro 		dfd = fileno(df);
13006f25ae9SGregory Neil Shapiro 		if (dfd < 0 || fstat(dfd, &stbuf) < 0)
131c2aa98e2SPeter Wemm 			e->e_dfino = -1;
132c2aa98e2SPeter Wemm 		else
133c2aa98e2SPeter Wemm 		{
134c2aa98e2SPeter Wemm 			e->e_dfdev = stbuf.st_dev;
135c2aa98e2SPeter Wemm 			e->e_dfino = stbuf.st_ino;
136c2aa98e2SPeter Wemm 		}
137c2aa98e2SPeter Wemm 		HasEightBits = FALSE;
138c2aa98e2SPeter Wemm 		e->e_msgsize = 0;
139c2aa98e2SPeter Wemm 		e->e_flags |= EF_HAS_DF;
140c2aa98e2SPeter Wemm 	}
141c2aa98e2SPeter Wemm 
142c2aa98e2SPeter Wemm 	/*
143c2aa98e2SPeter Wemm 	**  Tell ARPANET to go ahead.
144c2aa98e2SPeter Wemm 	*/
145c2aa98e2SPeter Wemm 
146c2aa98e2SPeter Wemm 	if (smtpmode)
147c2aa98e2SPeter Wemm 		message("354 Enter mail, end with \".\" on a line by itself");
148c2aa98e2SPeter Wemm 
149c2aa98e2SPeter Wemm 	if (tTd(30, 2))
15006f25ae9SGregory Neil Shapiro 		dprintf("collect\n");
151c2aa98e2SPeter Wemm 
152c2aa98e2SPeter Wemm 	/*
153c2aa98e2SPeter Wemm 	**  Read the message.
154c2aa98e2SPeter Wemm 	**
155c2aa98e2SPeter Wemm 	**	This is done using two interleaved state machines.
156c2aa98e2SPeter Wemm 	**	The input state machine is looking for things like
157c2aa98e2SPeter Wemm 	**	hidden dots; the message state machine is handling
158c2aa98e2SPeter Wemm 	**	the larger picture (e.g., header versus body).
159c2aa98e2SPeter Wemm 	*/
160c2aa98e2SPeter Wemm 
161c2aa98e2SPeter Wemm 	buf = bp = bufbuf;
162c2aa98e2SPeter Wemm 	buflen = sizeof bufbuf;
163c2aa98e2SPeter Wemm 	pbp = peekbuf;
164c2aa98e2SPeter Wemm 	istate = IS_BOL;
165c2aa98e2SPeter Wemm 	mstate = SaveFrom ? MS_HEADER : MS_UFROM;
166c2aa98e2SPeter Wemm 	CollectProgress = FALSE;
167c2aa98e2SPeter Wemm 
168c2aa98e2SPeter Wemm 	if (dbto != 0)
169c2aa98e2SPeter Wemm 	{
170c2aa98e2SPeter Wemm 		/* handle possible input timeout */
171c2aa98e2SPeter Wemm 		if (setjmp(CtxCollectTimeout) != 0)
172c2aa98e2SPeter Wemm 		{
173c2aa98e2SPeter Wemm 			if (LogLevel > 2)
174c2aa98e2SPeter Wemm 				sm_syslog(LOG_NOTICE, e->e_id,
175c2aa98e2SPeter Wemm 				    "timeout waiting for input from %s during message collect",
176c2aa98e2SPeter Wemm 				    CurHostName ? CurHostName : "<local machine>");
177c2aa98e2SPeter Wemm 			errno = 0;
17806f25ae9SGregory Neil Shapiro 			usrerr("451 4.4.1 timeout waiting for input during message collect");
179c2aa98e2SPeter Wemm 			goto readerr;
180c2aa98e2SPeter Wemm 		}
181c2aa98e2SPeter Wemm 		CollectTimeout = setevent(dbto, collecttimeout, dbto);
182c2aa98e2SPeter Wemm 	}
183c2aa98e2SPeter Wemm 
184c2aa98e2SPeter Wemm 	for (;;)
185c2aa98e2SPeter Wemm 	{
186c2aa98e2SPeter Wemm 		if (tTd(30, 35))
18706f25ae9SGregory Neil Shapiro 			dprintf("top, istate=%d, mstate=%d\n", istate, mstate);
188c2aa98e2SPeter Wemm 		for (;;)
189c2aa98e2SPeter Wemm 		{
190c2aa98e2SPeter Wemm 			if (pbp > peekbuf)
191c2aa98e2SPeter Wemm 				c = *--pbp;
192c2aa98e2SPeter Wemm 			else
193c2aa98e2SPeter Wemm 			{
194c2aa98e2SPeter Wemm 				while (!feof(fp) && !ferror(fp))
195c2aa98e2SPeter Wemm 				{
196c2aa98e2SPeter Wemm 					errno = 0;
197c2aa98e2SPeter Wemm 					c = getc(fp);
198c2aa98e2SPeter Wemm 					if (errno != EINTR)
199c2aa98e2SPeter Wemm 						break;
200c2aa98e2SPeter Wemm 					clearerr(fp);
201c2aa98e2SPeter Wemm 				}
202c2aa98e2SPeter Wemm 				CollectProgress = TRUE;
203c2aa98e2SPeter Wemm 				if (TrafficLogFile != NULL && !headeronly)
204c2aa98e2SPeter Wemm 				{
205c2aa98e2SPeter Wemm 					if (istate == IS_BOL)
20606f25ae9SGregory Neil Shapiro 						(void) fprintf(TrafficLogFile, "%05d <<< ",
207c2aa98e2SPeter Wemm 							(int) getpid());
208c2aa98e2SPeter Wemm 					if (c == EOF)
20906f25ae9SGregory Neil Shapiro 						(void) fprintf(TrafficLogFile, "[EOF]\n");
210c2aa98e2SPeter Wemm 					else
21106f25ae9SGregory Neil Shapiro 						(void) putc(c, TrafficLogFile);
212c2aa98e2SPeter Wemm 				}
213c2aa98e2SPeter Wemm 				if (c == EOF)
214c2aa98e2SPeter Wemm 					goto readerr;
215c2aa98e2SPeter Wemm 				if (SevenBitInput)
216c2aa98e2SPeter Wemm 					c &= 0x7f;
217c2aa98e2SPeter Wemm 				else
218c2aa98e2SPeter Wemm 					HasEightBits |= bitset(0x80, c);
219c2aa98e2SPeter Wemm 			}
220c2aa98e2SPeter Wemm 			if (tTd(30, 94))
22106f25ae9SGregory Neil Shapiro 				dprintf("istate=%d, c=%c (0x%x)\n",
22206f25ae9SGregory Neil Shapiro 					istate, (char) c, c);
223c2aa98e2SPeter Wemm 			switch (istate)
224c2aa98e2SPeter Wemm 			{
225c2aa98e2SPeter Wemm 			  case IS_BOL:
226c2aa98e2SPeter Wemm 				if (c == '.')
227c2aa98e2SPeter Wemm 				{
228c2aa98e2SPeter Wemm 					istate = IS_DOT;
229c2aa98e2SPeter Wemm 					continue;
230c2aa98e2SPeter Wemm 				}
231c2aa98e2SPeter Wemm 				break;
232c2aa98e2SPeter Wemm 
233c2aa98e2SPeter Wemm 			  case IS_DOT:
234c2aa98e2SPeter Wemm 				if (c == '\n' && !ignrdot &&
235c2aa98e2SPeter Wemm 				    !bitset(EF_NL_NOT_EOL, e->e_flags))
236c2aa98e2SPeter Wemm 					goto readerr;
237c2aa98e2SPeter Wemm 				else if (c == '\r' &&
238c2aa98e2SPeter Wemm 					 !bitset(EF_CRLF_NOT_EOL, e->e_flags))
239c2aa98e2SPeter Wemm 				{
240c2aa98e2SPeter Wemm 					istate = IS_DOTCR;
241c2aa98e2SPeter Wemm 					continue;
242c2aa98e2SPeter Wemm 				}
243c2aa98e2SPeter Wemm 				else if (c != '.' ||
244c2aa98e2SPeter Wemm 					 (OpMode != MD_SMTP &&
245c2aa98e2SPeter Wemm 					  OpMode != MD_DAEMON &&
246c2aa98e2SPeter Wemm 					  OpMode != MD_ARPAFTP))
247c2aa98e2SPeter Wemm 				{
248c2aa98e2SPeter Wemm 					*pbp++ = c;
249c2aa98e2SPeter Wemm 					c = '.';
250c2aa98e2SPeter Wemm 				}
251c2aa98e2SPeter Wemm 				break;
252c2aa98e2SPeter Wemm 
253c2aa98e2SPeter Wemm 			  case IS_DOTCR:
254c2aa98e2SPeter Wemm 				if (c == '\n' && !ignrdot)
255c2aa98e2SPeter Wemm 					goto readerr;
256c2aa98e2SPeter Wemm 				else
257c2aa98e2SPeter Wemm 				{
258c2aa98e2SPeter Wemm 					/* push back the ".\rx" */
259c2aa98e2SPeter Wemm 					*pbp++ = c;
260c2aa98e2SPeter Wemm 					*pbp++ = '\r';
261c2aa98e2SPeter Wemm 					c = '.';
262c2aa98e2SPeter Wemm 				}
263c2aa98e2SPeter Wemm 				break;
264c2aa98e2SPeter Wemm 
265c2aa98e2SPeter Wemm 			  case IS_CR:
266c2aa98e2SPeter Wemm 				if (c == '\n')
267c2aa98e2SPeter Wemm 					istate = IS_BOL;
268c2aa98e2SPeter Wemm 				else
269c2aa98e2SPeter Wemm 				{
27006f25ae9SGregory Neil Shapiro 					(void) ungetc(c, fp);
271c2aa98e2SPeter Wemm 					c = '\r';
272c2aa98e2SPeter Wemm 					istate = IS_NORM;
273c2aa98e2SPeter Wemm 				}
274c2aa98e2SPeter Wemm 				goto bufferchar;
275c2aa98e2SPeter Wemm 			}
276c2aa98e2SPeter Wemm 
277c2aa98e2SPeter Wemm 			if (c == '\r' && !bitset(EF_CRLF_NOT_EOL, e->e_flags))
278c2aa98e2SPeter Wemm 			{
279c2aa98e2SPeter Wemm 				istate = IS_CR;
280c2aa98e2SPeter Wemm 				continue;
281c2aa98e2SPeter Wemm 			}
282c2aa98e2SPeter Wemm 			else if (c == '\n' && !bitset(EF_NL_NOT_EOL, e->e_flags))
283c2aa98e2SPeter Wemm 				istate = IS_BOL;
284c2aa98e2SPeter Wemm 			else
285c2aa98e2SPeter Wemm 				istate = IS_NORM;
286c2aa98e2SPeter Wemm 
287c2aa98e2SPeter Wemm bufferchar:
288c2aa98e2SPeter Wemm 			if (!headeronly)
289c2aa98e2SPeter Wemm 				e->e_msgsize++;
29025bab6e9SPeter Wemm 			switch (mstate)
291c2aa98e2SPeter Wemm 			{
29225bab6e9SPeter Wemm 			  case MS_BODY:
293c2aa98e2SPeter Wemm 				/* just put the character out */
294c2aa98e2SPeter Wemm 				if (MaxMessageSize <= 0 ||
295c2aa98e2SPeter Wemm 				    e->e_msgsize <= MaxMessageSize)
29606f25ae9SGregory Neil Shapiro 					(void) putc(c, df);
29725bab6e9SPeter Wemm 
29806f25ae9SGregory Neil Shapiro 				/* FALLTHROUGH */
29925bab6e9SPeter Wemm 
30025bab6e9SPeter Wemm 			  case MS_DISCARD:
301c2aa98e2SPeter Wemm 				continue;
302c2aa98e2SPeter Wemm 			}
303c2aa98e2SPeter Wemm 
304c2aa98e2SPeter Wemm 			/* header -- buffer up */
305c2aa98e2SPeter Wemm 			if (bp >= &buf[buflen - 2])
306c2aa98e2SPeter Wemm 			{
307c2aa98e2SPeter Wemm 				char *obuf;
308c2aa98e2SPeter Wemm 
309c2aa98e2SPeter Wemm 				if (mstate != MS_HEADER)
310c2aa98e2SPeter Wemm 					break;
311c2aa98e2SPeter Wemm 
312c2aa98e2SPeter Wemm 				/* out of space for header */
313c2aa98e2SPeter Wemm 				obuf = buf;
314c2aa98e2SPeter Wemm 				if (buflen < MEMCHUNKSIZE)
315c2aa98e2SPeter Wemm 					buflen *= 2;
316c2aa98e2SPeter Wemm 				else
317c2aa98e2SPeter Wemm 					buflen += MEMCHUNKSIZE;
318c2aa98e2SPeter Wemm 				buf = xalloc(buflen);
31906f25ae9SGregory Neil Shapiro 				memmove(buf, obuf, bp - obuf);
320c2aa98e2SPeter Wemm 				bp = &buf[bp - obuf];
321c2aa98e2SPeter Wemm 				if (obuf != bufbuf)
322c2aa98e2SPeter Wemm 					free(obuf);
323c2aa98e2SPeter Wemm 			}
324c2aa98e2SPeter Wemm 			if (c >= 0200 && c <= 0237)
325c2aa98e2SPeter Wemm 			{
32606f25ae9SGregory Neil Shapiro #if 0	/* causes complaints -- figure out something for 8.11 */
327c2aa98e2SPeter Wemm 				usrerr("Illegal character 0x%x in header", c);
32806f25ae9SGregory Neil Shapiro #else /* 0 */
32906f25ae9SGregory Neil Shapiro 				/* EMPTY */
33006f25ae9SGregory Neil Shapiro #endif /* 0 */
331c2aa98e2SPeter Wemm 			}
332c2aa98e2SPeter Wemm 			else if (c != '\0')
33325bab6e9SPeter Wemm 			{
334c2aa98e2SPeter Wemm 				*bp++ = c;
3352e43090eSPeter Wemm 				if (MaxHeadersLength > 0 &&
3362e43090eSPeter Wemm 				    ++hdrslen > MaxHeadersLength)
33725bab6e9SPeter Wemm 				{
33825bab6e9SPeter Wemm 					sm_syslog(LOG_NOTICE, e->e_id,
3392e43090eSPeter Wemm 						  "headers too large (%d max) from %s during message collect",
3402e43090eSPeter Wemm 						  MaxHeadersLength,
34125bab6e9SPeter Wemm 						  CurHostName != NULL ? CurHostName : "localhost");
34225bab6e9SPeter Wemm 					errno = 0;
34325bab6e9SPeter Wemm 					e->e_flags |= EF_CLRQUEUE;
34425bab6e9SPeter Wemm 					e->e_status = "5.6.0";
34506f25ae9SGregory Neil Shapiro 					usrerrenh(e->e_status,
34606f25ae9SGregory Neil Shapiro 						  "552 Headers too large (%d max)",
3472e43090eSPeter Wemm 						  MaxHeadersLength);
34825bab6e9SPeter Wemm 					mstate = MS_DISCARD;
34925bab6e9SPeter Wemm 				}
35025bab6e9SPeter Wemm 			}
351c2aa98e2SPeter Wemm 			if (istate == IS_BOL)
352c2aa98e2SPeter Wemm 				break;
353c2aa98e2SPeter Wemm 		}
354c2aa98e2SPeter Wemm 		*bp = '\0';
355c2aa98e2SPeter Wemm 
356c2aa98e2SPeter Wemm nextstate:
357c2aa98e2SPeter Wemm 		if (tTd(30, 35))
35806f25ae9SGregory Neil Shapiro 			dprintf("nextstate, istate=%d, mstate=%d, line = \"%s\"\n",
359c2aa98e2SPeter Wemm 				istate, mstate, buf);
360c2aa98e2SPeter Wemm 		switch (mstate)
361c2aa98e2SPeter Wemm 		{
362c2aa98e2SPeter Wemm 		  case MS_UFROM:
363c2aa98e2SPeter Wemm 			mstate = MS_HEADER;
364c2aa98e2SPeter Wemm #ifndef NOTUNIX
365c2aa98e2SPeter Wemm 			if (strncmp(buf, "From ", 5) == 0)
366c2aa98e2SPeter Wemm 			{
367c2aa98e2SPeter Wemm 				bp = buf;
368c2aa98e2SPeter Wemm 				eatfrom(buf, e);
369c2aa98e2SPeter Wemm 				continue;
370c2aa98e2SPeter Wemm 			}
37106f25ae9SGregory Neil Shapiro #endif /* ! NOTUNIX */
37206f25ae9SGregory Neil Shapiro 			/* FALLTHROUGH */
373c2aa98e2SPeter Wemm 
374c2aa98e2SPeter Wemm 		  case MS_HEADER:
375c2aa98e2SPeter Wemm 			if (!isheader(buf))
376c2aa98e2SPeter Wemm 			{
377c2aa98e2SPeter Wemm 				mstate = MS_BODY;
378c2aa98e2SPeter Wemm 				goto nextstate;
379c2aa98e2SPeter Wemm 			}
380c2aa98e2SPeter Wemm 
381c2aa98e2SPeter Wemm 			/* check for possible continuation line */
382c2aa98e2SPeter Wemm 			do
383c2aa98e2SPeter Wemm 			{
384c2aa98e2SPeter Wemm 				clearerr(fp);
385c2aa98e2SPeter Wemm 				errno = 0;
386c2aa98e2SPeter Wemm 				c = getc(fp);
387c2aa98e2SPeter Wemm 			} while (errno == EINTR);
388c2aa98e2SPeter Wemm 			if (c != EOF)
38906f25ae9SGregory Neil Shapiro 				(void) ungetc(c, fp);
390c2aa98e2SPeter Wemm 			if (c == ' ' || c == '\t')
391c2aa98e2SPeter Wemm 			{
392c2aa98e2SPeter Wemm 				/* yep -- defer this */
393c2aa98e2SPeter Wemm 				continue;
394c2aa98e2SPeter Wemm 			}
395c2aa98e2SPeter Wemm 
396c2aa98e2SPeter Wemm 			/* trim off trailing CRLF or NL */
397c2aa98e2SPeter Wemm 			if (*--bp != '\n' || *--bp != '\r')
398c2aa98e2SPeter Wemm 				bp++;
399c2aa98e2SPeter Wemm 			*bp = '\0';
40025bab6e9SPeter Wemm 
40106f25ae9SGregory Neil Shapiro 			if (bitset(H_EOH, chompheader(buf,
40206f25ae9SGregory Neil Shapiro 						      CHHDR_CHECK | CHHDR_USER,
40306f25ae9SGregory Neil Shapiro 						      hdrp, e)))
404c2aa98e2SPeter Wemm 			{
405c2aa98e2SPeter Wemm 				mstate = MS_BODY;
406c2aa98e2SPeter Wemm 				goto nextstate;
407c2aa98e2SPeter Wemm 			}
40806f25ae9SGregory Neil Shapiro 			numhdrs++;
409c2aa98e2SPeter Wemm 			break;
410c2aa98e2SPeter Wemm 
411c2aa98e2SPeter Wemm 		  case MS_BODY:
412c2aa98e2SPeter Wemm 			if (tTd(30, 1))
41306f25ae9SGregory Neil Shapiro 				dprintf("EOH\n");
41406f25ae9SGregory Neil Shapiro 
415c2aa98e2SPeter Wemm 			if (headeronly)
416c2aa98e2SPeter Wemm 				goto readerr;
41706f25ae9SGregory Neil Shapiro 
41806f25ae9SGregory Neil Shapiro 			/* call the end-of-header check ruleset */
41906f25ae9SGregory Neil Shapiro 			snprintf(hnum, sizeof hnum, "%d", numhdrs);
42006f25ae9SGregory Neil Shapiro 			snprintf(hsize, sizeof hsize, "%d", hdrslen);
42106f25ae9SGregory Neil Shapiro 			if (tTd(30, 10))
42206f25ae9SGregory Neil Shapiro 				dprintf("collect: rscheck(\"check_eoh\", \"%s $| %s\")\n",
42306f25ae9SGregory Neil Shapiro 					hnum, hsize);
42406f25ae9SGregory Neil Shapiro 			rstat = rscheck("check_eoh", hnum, hsize, e, FALSE,
42506f25ae9SGregory Neil Shapiro 					TRUE, 4);
42606f25ae9SGregory Neil Shapiro 
427c2aa98e2SPeter Wemm 			bp = buf;
428c2aa98e2SPeter Wemm 
429c2aa98e2SPeter Wemm 			/* toss blank line */
430c2aa98e2SPeter Wemm 			if ((!bitset(EF_CRLF_NOT_EOL, e->e_flags) &&
431c2aa98e2SPeter Wemm 				bp[0] == '\r' && bp[1] == '\n') ||
432c2aa98e2SPeter Wemm 			    (!bitset(EF_NL_NOT_EOL, e->e_flags) &&
433c2aa98e2SPeter Wemm 				bp[0] == '\n'))
434c2aa98e2SPeter Wemm 			{
435c2aa98e2SPeter Wemm 				break;
436c2aa98e2SPeter Wemm 			}
437c2aa98e2SPeter Wemm 
438c2aa98e2SPeter Wemm 			/* if not a blank separator, write it out */
439c2aa98e2SPeter Wemm 			if (MaxMessageSize <= 0 ||
440c2aa98e2SPeter Wemm 			    e->e_msgsize <= MaxMessageSize)
441c2aa98e2SPeter Wemm 			{
442c2aa98e2SPeter Wemm 				while (*bp != '\0')
44306f25ae9SGregory Neil Shapiro 					(void) putc(*bp++, df);
444c2aa98e2SPeter Wemm 			}
445c2aa98e2SPeter Wemm 			break;
446c2aa98e2SPeter Wemm 		}
447c2aa98e2SPeter Wemm 		bp = buf;
448c2aa98e2SPeter Wemm 	}
449c2aa98e2SPeter Wemm 
450c2aa98e2SPeter Wemm readerr:
451c2aa98e2SPeter Wemm 	if ((feof(fp) && smtpmode) || ferror(fp))
452c2aa98e2SPeter Wemm 	{
453c2aa98e2SPeter Wemm 		const char *errmsg = errstring(errno);
454c2aa98e2SPeter Wemm 
455c2aa98e2SPeter Wemm 		if (tTd(30, 1))
45606f25ae9SGregory Neil Shapiro 			dprintf("collect: premature EOM: %s\n", errmsg);
457c2aa98e2SPeter Wemm 		if (LogLevel >= 2)
458c2aa98e2SPeter Wemm 			sm_syslog(LOG_WARNING, e->e_id,
459c2aa98e2SPeter Wemm 				"collect: premature EOM: %s", errmsg);
460c2aa98e2SPeter Wemm 		inputerr = TRUE;
461c2aa98e2SPeter Wemm 	}
462c2aa98e2SPeter Wemm 
463c2aa98e2SPeter Wemm 	/* reset global timer */
464c2aa98e2SPeter Wemm 	clrevent(CollectTimeout);
465c2aa98e2SPeter Wemm 
466c2aa98e2SPeter Wemm 	if (headeronly)
467c2aa98e2SPeter Wemm 		return;
468c2aa98e2SPeter Wemm 
46906f25ae9SGregory Neil Shapiro 	if (df == NULL)
470c2aa98e2SPeter Wemm 	{
47106f25ae9SGregory Neil Shapiro 		/* skip next few clauses */
47206f25ae9SGregory Neil Shapiro 		/* EMPTY */
47306f25ae9SGregory Neil Shapiro 	}
47406f25ae9SGregory Neil Shapiro 	else if (fflush(df) != 0 || ferror(df))
47506f25ae9SGregory Neil Shapiro 	{
47606f25ae9SGregory Neil Shapiro 		dferror(df, "fflush||ferror", e);
477c2aa98e2SPeter Wemm 		flush_errors(TRUE);
478065a643dSPeter Wemm 		finis(TRUE, ExitStat);
47906f25ae9SGregory Neil Shapiro 		/* NOTREACHED */
48006f25ae9SGregory Neil Shapiro 	}
48106f25ae9SGregory Neil Shapiro 	else if (!SuperSafe)
48206f25ae9SGregory Neil Shapiro 	{
48306f25ae9SGregory Neil Shapiro 		/* skip next few clauses */
48406f25ae9SGregory Neil Shapiro 		/* EMPTY */
48506f25ae9SGregory Neil Shapiro 	}
48606f25ae9SGregory Neil Shapiro 	else if ((afd = fileno(df)) >= 0 && fsync(afd) < 0)
48706f25ae9SGregory Neil Shapiro 	{
48806f25ae9SGregory Neil Shapiro 		dferror(df, "fsync", e);
48906f25ae9SGregory Neil Shapiro 		flush_errors(TRUE);
49006f25ae9SGregory Neil Shapiro 		finis(TRUE, ExitStat);
49106f25ae9SGregory Neil Shapiro 		/* NOTREACHED */
49206f25ae9SGregory Neil Shapiro 	}
49306f25ae9SGregory Neil Shapiro 	else if (bfcommit(df) < 0)
49406f25ae9SGregory Neil Shapiro 	{
49506f25ae9SGregory Neil Shapiro 		int save_errno = errno;
49606f25ae9SGregory Neil Shapiro 
49706f25ae9SGregory Neil Shapiro 		if (save_errno == EEXIST)
49806f25ae9SGregory Neil Shapiro 		{
49906f25ae9SGregory Neil Shapiro 			char *dfile;
50006f25ae9SGregory Neil Shapiro 			struct stat st;
50106f25ae9SGregory Neil Shapiro 
50206f25ae9SGregory Neil Shapiro 			dfile = queuename(e, 'd');
50306f25ae9SGregory Neil Shapiro 			if (stat(dfile, &st) < 0)
50406f25ae9SGregory Neil Shapiro 				st.st_size = -1;
50506f25ae9SGregory Neil Shapiro 			errno = EEXIST;
50606f25ae9SGregory Neil Shapiro 			syserr("collect: bfcommit(%s): already on disk, size = %ld",
50706f25ae9SGregory Neil Shapiro 			       dfile, st.st_size);
50806f25ae9SGregory Neil Shapiro 			dfd = fileno(df);
50906f25ae9SGregory Neil Shapiro 			if (dfd >= 0)
51006f25ae9SGregory Neil Shapiro 				dumpfd(dfd, TRUE, TRUE);
51106f25ae9SGregory Neil Shapiro 		}
51206f25ae9SGregory Neil Shapiro 		errno = save_errno;
51306f25ae9SGregory Neil Shapiro 		dferror(df, "bfcommit", e);
51406f25ae9SGregory Neil Shapiro 		flush_errors(TRUE);
51506f25ae9SGregory Neil Shapiro 		finis(save_errno != EEXIST, ExitStat);
51606f25ae9SGregory Neil Shapiro 	}
51706f25ae9SGregory Neil Shapiro 	else if (bfclose(df) < 0)
51806f25ae9SGregory Neil Shapiro 	{
51906f25ae9SGregory Neil Shapiro 		dferror(df, "bfclose", e);
52006f25ae9SGregory Neil Shapiro 		flush_errors(TRUE);
52106f25ae9SGregory Neil Shapiro 		finis(TRUE, ExitStat);
52206f25ae9SGregory Neil Shapiro 		/* NOTREACHED */
52306f25ae9SGregory Neil Shapiro 	}
52406f25ae9SGregory Neil Shapiro 	else
52506f25ae9SGregory Neil Shapiro 	{
52606f25ae9SGregory Neil Shapiro 		/* everything is happily flushed to disk */
52706f25ae9SGregory Neil Shapiro 		df = NULL;
528c2aa98e2SPeter Wemm 	}
529c2aa98e2SPeter Wemm 
530c2aa98e2SPeter Wemm 	/* An EOF when running SMTP is an error */
531c2aa98e2SPeter Wemm 	if (inputerr && (OpMode == MD_SMTP || OpMode == MD_DAEMON))
532c2aa98e2SPeter Wemm 	{
533c2aa98e2SPeter Wemm 		char *host;
534c2aa98e2SPeter Wemm 		char *problem;
535c2aa98e2SPeter Wemm 
536c2aa98e2SPeter Wemm 		host = RealHostName;
537c2aa98e2SPeter Wemm 		if (host == NULL)
538c2aa98e2SPeter Wemm 			host = "localhost";
539c2aa98e2SPeter Wemm 
540c2aa98e2SPeter Wemm 		if (feof(fp))
541c2aa98e2SPeter Wemm 			problem = "unexpected close";
542c2aa98e2SPeter Wemm 		else if (ferror(fp))
543c2aa98e2SPeter Wemm 			problem = "I/O error";
544c2aa98e2SPeter Wemm 		else
545c2aa98e2SPeter Wemm 			problem = "read timeout";
546c2aa98e2SPeter Wemm 		if (LogLevel > 0 && feof(fp))
547c2aa98e2SPeter Wemm 			sm_syslog(LOG_NOTICE, e->e_id,
548c2aa98e2SPeter Wemm 			    "collect: %s on connection from %.100s, sender=%s: %s",
549c2aa98e2SPeter Wemm 			    problem, host,
550c2aa98e2SPeter Wemm 			    shortenstring(e->e_from.q_paddr, MAXSHORTSTR),
551c2aa98e2SPeter Wemm 			    errstring(errno));
552c2aa98e2SPeter Wemm 		if (feof(fp))
55306f25ae9SGregory Neil Shapiro 			usrerr("451 4.4.1 collect: %s on connection from %s, from=%s",
554c2aa98e2SPeter Wemm 				problem, host,
555c2aa98e2SPeter Wemm 				shortenstring(e->e_from.q_paddr, MAXSHORTSTR));
556c2aa98e2SPeter Wemm 		else
55706f25ae9SGregory Neil Shapiro 			syserr("451 4.4.1 collect: %s on connection from %s, from=%s",
558c2aa98e2SPeter Wemm 				problem, host,
559c2aa98e2SPeter Wemm 				shortenstring(e->e_from.q_paddr, MAXSHORTSTR));
560c2aa98e2SPeter Wemm 
561c2aa98e2SPeter Wemm 		/* don't return an error indication */
562c2aa98e2SPeter Wemm 		e->e_to = NULL;
563c2aa98e2SPeter Wemm 		e->e_flags &= ~EF_FATALERRS;
564c2aa98e2SPeter Wemm 		e->e_flags |= EF_CLRQUEUE;
565c2aa98e2SPeter Wemm 
566c2aa98e2SPeter Wemm 		/* and don't try to deliver the partial message either */
567c2aa98e2SPeter Wemm 		if (InChild)
568c2aa98e2SPeter Wemm 			ExitStat = EX_QUIT;
569065a643dSPeter Wemm 		finis(TRUE, ExitStat);
57006f25ae9SGregory Neil Shapiro 		/* NOTREACHED */
571c2aa98e2SPeter Wemm 	}
572c2aa98e2SPeter Wemm 
573c2aa98e2SPeter Wemm 	/*
574c2aa98e2SPeter Wemm 	**  Find out some information from the headers.
575c2aa98e2SPeter Wemm 	**	Examples are who is the from person & the date.
576c2aa98e2SPeter Wemm 	*/
577c2aa98e2SPeter Wemm 
578c2aa98e2SPeter Wemm 	eatheader(e, TRUE);
579c2aa98e2SPeter Wemm 
580c2aa98e2SPeter Wemm 	if (GrabTo && e->e_sendqueue == NULL)
581c2aa98e2SPeter Wemm 		usrerr("No recipient addresses found in header");
582c2aa98e2SPeter Wemm 
583c2aa98e2SPeter Wemm 	/* collect statistics */
584c2aa98e2SPeter Wemm 	if (OpMode != MD_VERIFY)
585c2aa98e2SPeter Wemm 		markstats(e, (ADDRESS *) NULL, FALSE);
586c2aa98e2SPeter Wemm 
587c2aa98e2SPeter Wemm 	/*
588c2aa98e2SPeter Wemm 	**  If we have a Return-Receipt-To:, turn it into a DSN.
589c2aa98e2SPeter Wemm 	*/
590c2aa98e2SPeter Wemm 
591c2aa98e2SPeter Wemm 	if (RrtImpliesDsn && hvalue("return-receipt-to", e->e_header) != NULL)
592c2aa98e2SPeter Wemm 	{
593c2aa98e2SPeter Wemm 		ADDRESS *q;
594c2aa98e2SPeter Wemm 
595c2aa98e2SPeter Wemm 		for (q = e->e_sendqueue; q != NULL; q = q->q_next)
596c2aa98e2SPeter Wemm 			if (!bitset(QHASNOTIFY, q->q_flags))
597c2aa98e2SPeter Wemm 				q->q_flags |= QHASNOTIFY|QPINGONSUCCESS;
598c2aa98e2SPeter Wemm 	}
599c2aa98e2SPeter Wemm 
600c2aa98e2SPeter Wemm 	/*
601c2aa98e2SPeter Wemm 	**  Add an Apparently-To: line if we have no recipient lines.
602c2aa98e2SPeter Wemm 	*/
603c2aa98e2SPeter Wemm 
604c2aa98e2SPeter Wemm 	if (hvalue("to", e->e_header) != NULL ||
605c2aa98e2SPeter Wemm 	    hvalue("cc", e->e_header) != NULL ||
606c2aa98e2SPeter Wemm 	    hvalue("apparently-to", e->e_header) != NULL)
607c2aa98e2SPeter Wemm 	{
608c2aa98e2SPeter Wemm 		/* have a valid recipient header -- delete Bcc: headers */
609c2aa98e2SPeter Wemm 		e->e_flags |= EF_DELETE_BCC;
610c2aa98e2SPeter Wemm 	}
611c2aa98e2SPeter Wemm 	else if (hvalue("bcc", e->e_header) == NULL)
612c2aa98e2SPeter Wemm 	{
613c2aa98e2SPeter Wemm 		/* no valid recipient headers */
614c2aa98e2SPeter Wemm 		register ADDRESS *q;
615c2aa98e2SPeter Wemm 		char *hdr = NULL;
616c2aa98e2SPeter Wemm 
617c2aa98e2SPeter Wemm 		/* create an Apparently-To: field */
618c2aa98e2SPeter Wemm 		/*    that or reject the message.... */
619c2aa98e2SPeter Wemm 		switch (NoRecipientAction)
620c2aa98e2SPeter Wemm 		{
621c2aa98e2SPeter Wemm 		  case NRA_ADD_APPARENTLY_TO:
622c2aa98e2SPeter Wemm 			hdr = "Apparently-To";
623c2aa98e2SPeter Wemm 			break;
624c2aa98e2SPeter Wemm 
625c2aa98e2SPeter Wemm 		  case NRA_ADD_TO:
626c2aa98e2SPeter Wemm 			hdr = "To";
627c2aa98e2SPeter Wemm 			break;
628c2aa98e2SPeter Wemm 
629c2aa98e2SPeter Wemm 		  case NRA_ADD_BCC:
63006f25ae9SGregory Neil Shapiro 			addheader("Bcc", " ", 0, &e->e_header);
631c2aa98e2SPeter Wemm 			break;
632c2aa98e2SPeter Wemm 
633c2aa98e2SPeter Wemm 		  case NRA_ADD_TO_UNDISCLOSED:
63406f25ae9SGregory Neil Shapiro 			addheader("To", "undisclosed-recipients:;", 0, &e->e_header);
635c2aa98e2SPeter Wemm 			break;
636c2aa98e2SPeter Wemm 		}
637c2aa98e2SPeter Wemm 
638c2aa98e2SPeter Wemm 		if (hdr != NULL)
639c2aa98e2SPeter Wemm 		{
640c2aa98e2SPeter Wemm 			for (q = e->e_sendqueue; q != NULL; q = q->q_next)
641c2aa98e2SPeter Wemm 			{
642c2aa98e2SPeter Wemm 				if (q->q_alias != NULL)
643c2aa98e2SPeter Wemm 					continue;
644c2aa98e2SPeter Wemm 				if (tTd(30, 3))
64506f25ae9SGregory Neil Shapiro 					dprintf("Adding %s: %s\n",
646c2aa98e2SPeter Wemm 						hdr, q->q_paddr);
64706f25ae9SGregory Neil Shapiro 				addheader(hdr, q->q_paddr, 0, &e->e_header);
648c2aa98e2SPeter Wemm 			}
649c2aa98e2SPeter Wemm 		}
650c2aa98e2SPeter Wemm 	}
651c2aa98e2SPeter Wemm 
652c2aa98e2SPeter Wemm 	/* check for message too large */
653c2aa98e2SPeter Wemm 	if (MaxMessageSize > 0 && e->e_msgsize > MaxMessageSize)
654c2aa98e2SPeter Wemm 	{
655c2aa98e2SPeter Wemm 		e->e_flags |= EF_NO_BODY_RETN|EF_CLRQUEUE;
656c2aa98e2SPeter Wemm 		e->e_status = "5.2.3";
65706f25ae9SGregory Neil Shapiro 		usrerrenh(e->e_status,
65806f25ae9SGregory Neil Shapiro 			  "552 Message exceeds maximum fixed size (%ld)",
659c2aa98e2SPeter Wemm 			  MaxMessageSize);
660c2aa98e2SPeter Wemm 		if (LogLevel > 6)
661c2aa98e2SPeter Wemm 			sm_syslog(LOG_NOTICE, e->e_id,
662c2aa98e2SPeter Wemm 				"message size (%ld) exceeds maximum (%ld)",
663c2aa98e2SPeter Wemm 				e->e_msgsize, MaxMessageSize);
664c2aa98e2SPeter Wemm 	}
665c2aa98e2SPeter Wemm 
666c2aa98e2SPeter Wemm 	/* check for illegal 8-bit data */
667c2aa98e2SPeter Wemm 	if (HasEightBits)
668c2aa98e2SPeter Wemm 	{
669c2aa98e2SPeter Wemm 		e->e_flags |= EF_HAS8BIT;
670c2aa98e2SPeter Wemm 		if (!bitset(MM_PASS8BIT|MM_MIME8BIT, MimeMode) &&
671c2aa98e2SPeter Wemm 		    !bitset(EF_IS_MIME, e->e_flags))
672c2aa98e2SPeter Wemm 		{
673c2aa98e2SPeter Wemm 			e->e_status = "5.6.1";
67406f25ae9SGregory Neil Shapiro 			usrerrenh(e->e_status, "554 Eight bit data not allowed");
675c2aa98e2SPeter Wemm 		}
676c2aa98e2SPeter Wemm 	}
677c2aa98e2SPeter Wemm 	else
678c2aa98e2SPeter Wemm 	{
679c2aa98e2SPeter Wemm 		/* if it claimed to be 8 bits, well, it lied.... */
680c2aa98e2SPeter Wemm 		if (e->e_bodytype != NULL &&
681c2aa98e2SPeter Wemm 		    strcasecmp(e->e_bodytype, "8BITMIME") == 0)
682c2aa98e2SPeter Wemm 			e->e_bodytype = "7BIT";
683c2aa98e2SPeter Wemm 	}
684c2aa98e2SPeter Wemm 
68506f25ae9SGregory Neil Shapiro 	if (SuperSafe)
68606f25ae9SGregory Neil Shapiro 	{
687c2aa98e2SPeter Wemm 		if ((e->e_dfp = fopen(dfname, "r")) == NULL)
688c2aa98e2SPeter Wemm 		{
689c2aa98e2SPeter Wemm 			/* we haven't acked receipt yet, so just chuck this */
690c2aa98e2SPeter Wemm 			syserr("Cannot reopen %s", dfname);
691065a643dSPeter Wemm 			finis(TRUE, ExitStat);
69206f25ae9SGregory Neil Shapiro 			/* NOTREACHED */
693c2aa98e2SPeter Wemm 		}
694c2aa98e2SPeter Wemm 	}
69506f25ae9SGregory Neil Shapiro 	else
69606f25ae9SGregory Neil Shapiro 		e->e_dfp = df;
69706f25ae9SGregory Neil Shapiro 	if (e->e_dfp == NULL)
69806f25ae9SGregory Neil Shapiro 		syserr("!collect: no e_dfp");
69906f25ae9SGregory Neil Shapiro }
700c2aa98e2SPeter Wemm 
701c2aa98e2SPeter Wemm 
702c2aa98e2SPeter Wemm static void
703c2aa98e2SPeter Wemm collecttimeout(timeout)
704c2aa98e2SPeter Wemm 	time_t timeout;
705c2aa98e2SPeter Wemm {
706c2aa98e2SPeter Wemm 	/* if no progress was made, die now */
707c2aa98e2SPeter Wemm 	if (!CollectProgress)
708c2aa98e2SPeter Wemm 		longjmp(CtxCollectTimeout, 1);
709c2aa98e2SPeter Wemm 
710c2aa98e2SPeter Wemm 	/* otherwise reset the timeout */
711c2aa98e2SPeter Wemm 	CollectTimeout = setevent(timeout, collecttimeout, timeout);
712c2aa98e2SPeter Wemm 	CollectProgress = FALSE;
713c2aa98e2SPeter Wemm }
71406f25ae9SGregory Neil Shapiro /*
71506f25ae9SGregory Neil Shapiro **  DFERROR -- signal error on writing the data file.
716c2aa98e2SPeter Wemm **
717c2aa98e2SPeter Wemm **	Parameters:
71806f25ae9SGregory Neil Shapiro **		df -- the file pointer for the data file.
71906f25ae9SGregory Neil Shapiro **		msg -- detailed message.
720c2aa98e2SPeter Wemm **		e -- the current envelope.
721c2aa98e2SPeter Wemm **
722c2aa98e2SPeter Wemm **	Returns:
723c2aa98e2SPeter Wemm **		none.
724c2aa98e2SPeter Wemm **
725c2aa98e2SPeter Wemm **	Side Effects:
726c2aa98e2SPeter Wemm **		Gives an error message.
727c2aa98e2SPeter Wemm **		Arranges for following output to go elsewhere.
728c2aa98e2SPeter Wemm */
729c2aa98e2SPeter Wemm 
73006f25ae9SGregory Neil Shapiro static void
73106f25ae9SGregory Neil Shapiro dferror(df, msg, e)
73206f25ae9SGregory Neil Shapiro 	FILE *volatile df;
73306f25ae9SGregory Neil Shapiro 	char *msg;
734c2aa98e2SPeter Wemm 	register ENVELOPE *e;
735c2aa98e2SPeter Wemm {
73606f25ae9SGregory Neil Shapiro 	char *dfname;
73706f25ae9SGregory Neil Shapiro 
73806f25ae9SGregory Neil Shapiro 	dfname = queuename(e, 'd');
739c2aa98e2SPeter Wemm 	setstat(EX_IOERR);
740c2aa98e2SPeter Wemm 	if (errno == ENOSPC)
741c2aa98e2SPeter Wemm 	{
742c2aa98e2SPeter Wemm #if STAT64 > 0
743c2aa98e2SPeter Wemm 		struct stat64 st;
74406f25ae9SGregory Neil Shapiro #else /* STAT64 > 0 */
745c2aa98e2SPeter Wemm 		struct stat st;
74606f25ae9SGregory Neil Shapiro #endif /* STAT64 > 0 */
747c2aa98e2SPeter Wemm 		long avail;
748c2aa98e2SPeter Wemm 		long bsize;
749c2aa98e2SPeter Wemm 
750c2aa98e2SPeter Wemm 		e->e_flags |= EF_NO_BODY_RETN;
751c2aa98e2SPeter Wemm 
752c2aa98e2SPeter Wemm 		if (
753c2aa98e2SPeter Wemm #if STAT64 > 0
75406f25ae9SGregory Neil Shapiro 		    fstat64(fileno(df), &st)
75506f25ae9SGregory Neil Shapiro #else /* STAT64 > 0 */
75606f25ae9SGregory Neil Shapiro 		    fstat(fileno(df), &st)
75706f25ae9SGregory Neil Shapiro #endif /* STAT64 > 0 */
758c2aa98e2SPeter Wemm 		    < 0)
759c2aa98e2SPeter Wemm 		  st.st_size = 0;
76006f25ae9SGregory Neil Shapiro 		(void) freopen(dfname, "w", df);
761c2aa98e2SPeter Wemm 		if (st.st_size <= 0)
76206f25ae9SGregory Neil Shapiro 			fprintf(df, "\n*** Mail could not be accepted");
76306f25ae9SGregory Neil Shapiro 		/*CONSTCOND*/
764c2aa98e2SPeter Wemm 		else if (sizeof st.st_size > sizeof (long))
76506f25ae9SGregory Neil Shapiro 			fprintf(df, "\n*** Mail of at least %s bytes could not be accepted\n",
766c2aa98e2SPeter Wemm 				quad_to_string(st.st_size));
767c2aa98e2SPeter Wemm 		else
76806f25ae9SGregory Neil Shapiro 			fprintf(df, "\n*** Mail of at least %lu bytes could not be accepted\n",
769c2aa98e2SPeter Wemm 				(unsigned long) st.st_size);
77006f25ae9SGregory Neil Shapiro 		fprintf(df, "*** at %s due to lack of disk space for temp file.\n",
771c2aa98e2SPeter Wemm 			MyHostName);
77206f25ae9SGregory Neil Shapiro 		avail = freediskspace(qid_printqueue(e->e_queuedir), &bsize);
773c2aa98e2SPeter Wemm 		if (avail > 0)
774c2aa98e2SPeter Wemm 		{
775c2aa98e2SPeter Wemm 			if (bsize > 1024)
776c2aa98e2SPeter Wemm 				avail *= bsize / 1024;
777c2aa98e2SPeter Wemm 			else if (bsize < 1024)
778c2aa98e2SPeter Wemm 				avail /= 1024 / bsize;
77906f25ae9SGregory Neil Shapiro 			fprintf(df, "*** Currently, %ld kilobytes are available for mail temp files.\n",
780c2aa98e2SPeter Wemm 				avail);
781c2aa98e2SPeter Wemm 		}
782c2aa98e2SPeter Wemm 		e->e_status = "4.3.1";
78306f25ae9SGregory Neil Shapiro 		usrerrenh(e->e_status, "452 Out of disk space for temp file");
784c2aa98e2SPeter Wemm 	}
785c2aa98e2SPeter Wemm 	else
78606f25ae9SGregory Neil Shapiro 		syserr("collect: Cannot write %s (%s, uid=%d)",
78706f25ae9SGregory Neil Shapiro 			dfname, msg, geteuid());
78806f25ae9SGregory Neil Shapiro 	if (freopen("/dev/null", "w", df) == NULL)
789c2aa98e2SPeter Wemm 		sm_syslog(LOG_ERR, e->e_id,
79006f25ae9SGregory Neil Shapiro 			  "dferror: freopen(\"/dev/null\") failed: %s",
791c2aa98e2SPeter Wemm 			  errstring(errno));
792c2aa98e2SPeter Wemm }
793c2aa98e2SPeter Wemm /*
794c2aa98e2SPeter Wemm **  EATFROM -- chew up a UNIX style from line and process
795c2aa98e2SPeter Wemm **
796c2aa98e2SPeter Wemm **	This does indeed make some assumptions about the format
797c2aa98e2SPeter Wemm **	of UNIX messages.
798c2aa98e2SPeter Wemm **
799c2aa98e2SPeter Wemm **	Parameters:
800c2aa98e2SPeter Wemm **		fm -- the from line.
801c2aa98e2SPeter Wemm **
802c2aa98e2SPeter Wemm **	Returns:
803c2aa98e2SPeter Wemm **		none.
804c2aa98e2SPeter Wemm **
805c2aa98e2SPeter Wemm **	Side Effects:
806c2aa98e2SPeter Wemm **		extracts what information it can from the header,
807c2aa98e2SPeter Wemm **		such as the date.
808c2aa98e2SPeter Wemm */
809c2aa98e2SPeter Wemm 
810c2aa98e2SPeter Wemm #ifndef NOTUNIX
811c2aa98e2SPeter Wemm 
81206f25ae9SGregory Neil Shapiro static char	*DowList[] =
813c2aa98e2SPeter Wemm {
814c2aa98e2SPeter Wemm 	"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", NULL
815c2aa98e2SPeter Wemm };
816c2aa98e2SPeter Wemm 
81706f25ae9SGregory Neil Shapiro static char	*MonthList[] =
818c2aa98e2SPeter Wemm {
819c2aa98e2SPeter Wemm 	"Jan", "Feb", "Mar", "Apr", "May", "Jun",
820c2aa98e2SPeter Wemm 	"Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
821c2aa98e2SPeter Wemm 	NULL
822c2aa98e2SPeter Wemm };
823c2aa98e2SPeter Wemm 
82406f25ae9SGregory Neil Shapiro static void
825c2aa98e2SPeter Wemm eatfrom(fm, e)
826c2aa98e2SPeter Wemm 	char *volatile fm;
827c2aa98e2SPeter Wemm 	register ENVELOPE *e;
828c2aa98e2SPeter Wemm {
829c2aa98e2SPeter Wemm 	register char *p;
830c2aa98e2SPeter Wemm 	register char **dt;
831c2aa98e2SPeter Wemm 
832c2aa98e2SPeter Wemm 	if (tTd(30, 2))
83306f25ae9SGregory Neil Shapiro 		dprintf("eatfrom(%s)\n", fm);
834c2aa98e2SPeter Wemm 
835c2aa98e2SPeter Wemm 	/* find the date part */
836c2aa98e2SPeter Wemm 	p = fm;
837c2aa98e2SPeter Wemm 	while (*p != '\0')
838c2aa98e2SPeter Wemm 	{
839c2aa98e2SPeter Wemm 		/* skip a word */
840c2aa98e2SPeter Wemm 		while (*p != '\0' && *p != ' ')
841c2aa98e2SPeter Wemm 			p++;
842c2aa98e2SPeter Wemm 		while (*p == ' ')
843c2aa98e2SPeter Wemm 			p++;
844c2aa98e2SPeter Wemm 		if (!(isascii(*p) && isupper(*p)) ||
845c2aa98e2SPeter Wemm 		    p[3] != ' ' || p[13] != ':' || p[16] != ':')
846c2aa98e2SPeter Wemm 			continue;
847c2aa98e2SPeter Wemm 
848c2aa98e2SPeter Wemm 		/* we have a possible date */
849c2aa98e2SPeter Wemm 		for (dt = DowList; *dt != NULL; dt++)
850c2aa98e2SPeter Wemm 			if (strncmp(*dt, p, 3) == 0)
851c2aa98e2SPeter Wemm 				break;
852c2aa98e2SPeter Wemm 		if (*dt == NULL)
853c2aa98e2SPeter Wemm 			continue;
854c2aa98e2SPeter Wemm 
855c2aa98e2SPeter Wemm 		for (dt = MonthList; *dt != NULL; dt++)
856c2aa98e2SPeter Wemm 			if (strncmp(*dt, &p[4], 3) == 0)
857c2aa98e2SPeter Wemm 				break;
858c2aa98e2SPeter Wemm 		if (*dt != NULL)
859c2aa98e2SPeter Wemm 			break;
860c2aa98e2SPeter Wemm 	}
861c2aa98e2SPeter Wemm 
862c2aa98e2SPeter Wemm 	if (*p != '\0')
863c2aa98e2SPeter Wemm 	{
864c2aa98e2SPeter Wemm 		char *q;
865c2aa98e2SPeter Wemm 
866c2aa98e2SPeter Wemm 		/* we have found a date */
867c2aa98e2SPeter Wemm 		q = xalloc(25);
86806f25ae9SGregory Neil Shapiro 		(void) strlcpy(q, p, 25);
869c2aa98e2SPeter Wemm 		q = arpadate(q);
870c2aa98e2SPeter Wemm 		define('a', newstr(q), e);
871c2aa98e2SPeter Wemm 	}
872c2aa98e2SPeter Wemm }
87306f25ae9SGregory Neil Shapiro #endif /* ! NOTUNIX */
874