collect.c revision 141858
1/*
2 * Copyright (c) 1998-2004 Sendmail, Inc. and its suppliers.
3 *	All rights reserved.
4 * Copyright (c) 1983, 1995-1997 Eric P. Allman.  All rights reserved.
5 * Copyright (c) 1988, 1993
6 *	The Regents of the University of California.  All rights reserved.
7 *
8 * By using this file, you agree to the terms and conditions set
9 * forth in the LICENSE file which can be found at the top level of
10 * the sendmail distribution.
11 *
12 */
13
14#include <sendmail.h>
15
16SM_RCSID("@(#)$Id: collect.c,v 8.260 2004/11/30 23:29:15 ca Exp $")
17
18static void	collecttimeout __P((int));
19static void	eatfrom __P((char *volatile, ENVELOPE *));
20static void	collect_doheader __P((ENVELOPE *));
21static SM_FILE_T *collect_dfopen __P((ENVELOPE *));
22static SM_FILE_T *collect_eoh __P((ENVELOPE *, int, int));
23
24/*
25**  COLLECT_EOH -- end-of-header processing in collect()
26**
27**	Called by collect() when it encounters the blank line
28**	separating the header from the message body, or when it
29**	encounters EOF in a message that contains only a header.
30**
31**	Parameters:
32**		e -- envelope
33**		numhdrs -- number of headers
34**		hdrslen -- length of headers
35**
36**	Results:
37**		NULL, or handle to open data file
38**
39**	Side Effects:
40**		end-of-header check ruleset is invoked.
41**		envelope state is updated.
42**		headers may be added and deleted.
43**		selects the queue.
44**		opens the data file.
45*/
46
47static SM_FILE_T *
48collect_eoh(e, numhdrs, hdrslen)
49	ENVELOPE *e;
50	int numhdrs;
51	int hdrslen;
52{
53	char hnum[16];
54	char hsize[16];
55
56	/* call the end-of-header check ruleset */
57	(void) sm_snprintf(hnum, sizeof hnum, "%d", numhdrs);
58	(void) sm_snprintf(hsize, sizeof hsize, "%d", hdrslen);
59	if (tTd(30, 10))
60		sm_dprintf("collect: rscheck(\"check_eoh\", \"%s $| %s\")\n",
61			   hnum, hsize);
62	(void) rscheck("check_eoh", hnum, hsize, e, RSF_UNSTRUCTURED|RSF_COUNT,
63			3, NULL, e->e_id);
64
65	/*
66	**  Process the header,
67	**  select the queue, open the data file.
68	*/
69
70	collect_doheader(e);
71	return collect_dfopen(e);
72}
73
74/*
75**  COLLECT_DOHEADER -- process header in collect()
76**
77**	Called by collect() after it has finished parsing the header,
78**	but before it selects the queue and creates the data file.
79**	The results of processing the header will affect queue selection.
80**
81**	Parameters:
82**		e -- envelope
83**
84**	Results:
85**		none.
86**
87**	Side Effects:
88**		envelope state is updated.
89**		headers may be added and deleted.
90*/
91
92static void
93collect_doheader(e)
94	ENVELOPE *e;
95{
96	/*
97	**  Find out some information from the headers.
98	**	Examples are who is the from person & the date.
99	*/
100
101	eatheader(e, true, false);
102
103	if (GrabTo && e->e_sendqueue == NULL)
104		usrerr("No recipient addresses found in header");
105
106	/*
107	**  If we have a Return-Receipt-To:, turn it into a DSN.
108	*/
109
110	if (RrtImpliesDsn && hvalue("return-receipt-to", e->e_header) != NULL)
111	{
112		ADDRESS *q;
113
114		for (q = e->e_sendqueue; q != NULL; q = q->q_next)
115			if (!bitset(QHASNOTIFY, q->q_flags))
116				q->q_flags |= QHASNOTIFY|QPINGONSUCCESS;
117	}
118
119	/*
120	**  Add an appropriate recipient line if we have none.
121	*/
122
123	if (hvalue("to", e->e_header) != NULL ||
124	    hvalue("cc", e->e_header) != NULL ||
125	    hvalue("apparently-to", e->e_header) != NULL)
126	{
127		/* have a valid recipient header -- delete Bcc: headers */
128		e->e_flags |= EF_DELETE_BCC;
129	}
130	else if (hvalue("bcc", e->e_header) == NULL)
131	{
132		/* no valid recipient headers */
133		register ADDRESS *q;
134		char *hdr = NULL;
135
136		/* create a recipient field */
137		switch (NoRecipientAction)
138		{
139		  case NRA_ADD_APPARENTLY_TO:
140			hdr = "Apparently-To";
141			break;
142
143		  case NRA_ADD_TO:
144			hdr = "To";
145			break;
146
147		  case NRA_ADD_BCC:
148			addheader("Bcc", " ", 0, e);
149			break;
150
151		  case NRA_ADD_TO_UNDISCLOSED:
152			addheader("To", "undisclosed-recipients:;", 0, e);
153			break;
154		}
155
156		if (hdr != NULL)
157		{
158			for (q = e->e_sendqueue; q != NULL; q = q->q_next)
159			{
160				if (q->q_alias != NULL)
161					continue;
162				if (tTd(30, 3))
163					sm_dprintf("Adding %s: %s\n",
164						hdr, q->q_paddr);
165				addheader(hdr, q->q_paddr, 0, e);
166			}
167		}
168	}
169}
170
171/*
172**  COLLECT_DFOPEN -- open the message data file
173**
174**	Called by collect() after it has finished processing the header.
175**	Queue selection occurs at this point, possibly based on the
176**	envelope's recipient list and on header information.
177**
178**	Parameters:
179**		e -- envelope
180**
181**	Results:
182**		NULL, or a pointer to an open data file,
183**		into which the message body will be written by collect().
184**
185**	Side Effects:
186**		Calls syserr, sets EF_FATALERRS and returns NULL
187**		if there is insufficient disk space.
188**		Aborts process if data file could not be opened.
189**		Otherwise, the queue is selected,
190**		e->e_{dfino,dfdev,msgsize,flags} are updated,
191**		and a pointer to an open data file is returned.
192*/
193
194static SM_FILE_T *
195collect_dfopen(e)
196	ENVELOPE *e;
197{
198	MODE_T oldumask = 0;
199	int dfd;
200	struct stat stbuf;
201	SM_FILE_T *df;
202	char *dfname;
203
204	if (!setnewqueue(e))
205		return NULL;
206
207	dfname = queuename(e, DATAFL_LETTER);
208	if (bitset(S_IWGRP, QueueFileMode))
209		oldumask = umask(002);
210	df = bfopen(dfname, QueueFileMode, DataFileBufferSize,
211		    SFF_OPENASROOT);
212	if (bitset(S_IWGRP, QueueFileMode))
213		(void) umask(oldumask);
214	if (df == NULL)
215	{
216		syserr("@Cannot create %s", dfname);
217		e->e_flags |= EF_NO_BODY_RETN;
218		flush_errors(true);
219		finis(false, true, ExitStat);
220		/* NOTREACHED */
221	}
222	dfd = sm_io_getinfo(df, SM_IO_WHAT_FD, NULL);
223	if (dfd < 0 || fstat(dfd, &stbuf) < 0)
224		e->e_dfino = -1;
225	else
226	{
227		e->e_dfdev = stbuf.st_dev;
228		e->e_dfino = stbuf.st_ino;
229	}
230	e->e_flags |= EF_HAS_DF;
231	return df;
232}
233
234/*
235**  COLLECT -- read & parse message header & make temp file.
236**
237**	Creates a temporary file name and copies the standard
238**	input to that file.  Leading UNIX-style "From" lines are
239**	stripped off (after important information is extracted).
240**
241**	Parameters:
242**		fp -- file to read.
243**		smtpmode -- if set, we are running SMTP: give an RFC821
244**			style message to say we are ready to collect
245**			input, and never ignore a single dot to mean
246**			end of message.
247**		hdrp -- the location to stash the header.
248**		e -- the current envelope.
249**		rsetsize -- reset e_msgsize?
250**
251**	Returns:
252**		none.
253**
254**	Side Effects:
255**		If successful,
256**		- Data file is created and filled, and e->e_dfp is set.
257**		- The from person may be set.
258**		If the "enough disk space" check fails,
259**		- syserr is called.
260**		- e->e_dfp is NULL.
261**		- e->e_flags & EF_FATALERRS is set.
262**		- collect() returns.
263**		If data file cannot be created, the process is terminated.
264*/
265
266static jmp_buf	CtxCollectTimeout;
267static bool	volatile CollectProgress;
268static SM_EVENT	*volatile CollectTimeout = NULL;
269
270/* values for input state machine */
271#define IS_NORM		0	/* middle of line */
272#define IS_BOL		1	/* beginning of line */
273#define IS_DOT		2	/* read a dot at beginning of line */
274#define IS_DOTCR	3	/* read ".\r" at beginning of line */
275#define IS_CR		4	/* read a carriage return */
276
277/* values for message state machine */
278#define MS_UFROM	0	/* reading Unix from line */
279#define MS_HEADER	1	/* reading message header */
280#define MS_BODY		2	/* reading message body */
281#define MS_DISCARD	3	/* discarding rest of message */
282
283void
284collect(fp, smtpmode, hdrp, e, rsetsize)
285	SM_FILE_T *fp;
286	bool smtpmode;
287	HDR **hdrp;
288	register ENVELOPE *e;
289	bool rsetsize;
290{
291	register SM_FILE_T *volatile df;
292	volatile bool ignrdot;
293	volatile int dbto;
294	register char *volatile bp;
295	volatile int c;
296	volatile bool inputerr;
297	bool headeronly;
298	char *volatile buf;
299	volatile int buflen;
300	volatile int istate;
301	volatile int mstate;
302	volatile int hdrslen;
303	volatile int numhdrs;
304	volatile int afd;
305	unsigned char *volatile pbp;
306	unsigned char peekbuf[8];
307	char bufbuf[MAXLINE];
308
309	df = NULL;
310	ignrdot = smtpmode ? false : IgnrDot;
311	dbto = smtpmode ? (int) TimeOuts.to_datablock : 0;
312	c = SM_IO_EOF;
313	inputerr = false;
314	headeronly = hdrp != NULL;
315	hdrslen = 0;
316	numhdrs = 0;
317	HasEightBits = false;
318	buf = bp = bufbuf;
319	buflen = sizeof bufbuf;
320	pbp = peekbuf;
321	istate = IS_BOL;
322	mstate = SaveFrom ? MS_HEADER : MS_UFROM;
323	CollectProgress = false;
324
325	/*
326	**  Tell ARPANET to go ahead.
327	*/
328
329	if (smtpmode)
330		message("354 Enter mail, end with \".\" on a line by itself");
331
332	if (tTd(30, 2))
333		sm_dprintf("collect\n");
334
335	/*
336	**  Read the message.
337	**
338	**	This is done using two interleaved state machines.
339	**	The input state machine is looking for things like
340	**	hidden dots; the message state machine is handling
341	**	the larger picture (e.g., header versus body).
342	*/
343
344	if (dbto != 0)
345	{
346		/* handle possible input timeout */
347		if (setjmp(CtxCollectTimeout) != 0)
348		{
349			if (LogLevel > 2)
350				sm_syslog(LOG_NOTICE, e->e_id,
351					  "timeout waiting for input from %s during message collect",
352					  CURHOSTNAME);
353			errno = 0;
354			if (smtpmode)
355			{
356				/*
357				**  Override e_message in usrerr() as this
358				**  is the reason for failure that should
359				**  be logged for undelivered recipients.
360				*/
361
362				e->e_message = NULL;
363			}
364			usrerr("451 4.4.1 timeout waiting for input during message collect");
365			goto readerr;
366		}
367		CollectTimeout = sm_setevent(dbto, collecttimeout, dbto);
368	}
369
370	if (rsetsize)
371		e->e_msgsize = 0;
372	for (;;)
373	{
374		if (tTd(30, 35))
375			sm_dprintf("top, istate=%d, mstate=%d\n", istate,
376				   mstate);
377		for (;;)
378		{
379			if (pbp > peekbuf)
380				c = *--pbp;
381			else
382			{
383				while (!sm_io_eof(fp) && !sm_io_error(fp))
384				{
385					errno = 0;
386					c = sm_io_getc(fp, SM_TIME_DEFAULT);
387					if (c == SM_IO_EOF && errno == EINTR)
388					{
389						/* Interrupted, retry */
390						sm_io_clearerr(fp);
391						continue;
392					}
393					break;
394				}
395				CollectProgress = true;
396				if (TrafficLogFile != NULL && !headeronly)
397				{
398					if (istate == IS_BOL)
399						(void) sm_io_fprintf(TrafficLogFile,
400							SM_TIME_DEFAULT,
401							"%05d <<< ",
402							(int) CurrentPid);
403					if (c == SM_IO_EOF)
404						(void) sm_io_fprintf(TrafficLogFile,
405							SM_TIME_DEFAULT,
406							"[EOF]\n");
407					else
408						(void) sm_io_putc(TrafficLogFile,
409							SM_TIME_DEFAULT,
410							c);
411				}
412				if (c == SM_IO_EOF)
413					goto readerr;
414				if (SevenBitInput)
415					c &= 0x7f;
416				else
417					HasEightBits |= bitset(0x80, c);
418			}
419			if (tTd(30, 94))
420				sm_dprintf("istate=%d, c=%c (0x%x)\n",
421					istate, (char) c, c);
422			switch (istate)
423			{
424			  case IS_BOL:
425				if (c == '.')
426				{
427					istate = IS_DOT;
428					continue;
429				}
430				break;
431
432			  case IS_DOT:
433				if (c == '\n' && !ignrdot &&
434				    !bitset(EF_NL_NOT_EOL, e->e_flags))
435					goto readerr;
436				else if (c == '\r' &&
437					 !bitset(EF_CRLF_NOT_EOL, e->e_flags))
438				{
439					istate = IS_DOTCR;
440					continue;
441				}
442				else if (ignrdot ||
443					 (c != '.' &&
444					  OpMode != MD_SMTP &&
445					  OpMode != MD_DAEMON &&
446					  OpMode != MD_ARPAFTP))
447
448				{
449					SM_ASSERT(pbp < peekbuf + sizeof(peekbuf));
450					*pbp++ = c;
451					c = '.';
452				}
453				break;
454
455			  case IS_DOTCR:
456				if (c == '\n' && !ignrdot)
457					goto readerr;
458				else
459				{
460					/* push back the ".\rx" */
461					SM_ASSERT(pbp < peekbuf + sizeof(peekbuf));
462					*pbp++ = c;
463					if (OpMode != MD_SMTP &&
464					    OpMode != MD_DAEMON &&
465					    OpMode != MD_ARPAFTP)
466					{
467						SM_ASSERT(pbp < peekbuf +
468							 sizeof(peekbuf));
469						*pbp++ = '\r';
470						c = '.';
471					}
472					else
473						c = '\r';
474				}
475				break;
476
477			  case IS_CR:
478				if (c == '\n')
479					istate = IS_BOL;
480				else
481				{
482					(void) sm_io_ungetc(fp, SM_TIME_DEFAULT,
483							    c);
484					c = '\r';
485					istate = IS_NORM;
486				}
487				goto bufferchar;
488			}
489
490			if (c == '\r' && !bitset(EF_CRLF_NOT_EOL, e->e_flags))
491			{
492				istate = IS_CR;
493				continue;
494			}
495			else if (c == '\n' && !bitset(EF_NL_NOT_EOL,
496						      e->e_flags))
497				istate = IS_BOL;
498			else
499				istate = IS_NORM;
500
501bufferchar:
502			if (!headeronly)
503			{
504				/* no overflow? */
505				if (e->e_msgsize >= 0)
506				{
507					e->e_msgsize++;
508					if (MaxMessageSize > 0 &&
509					    !bitset(EF_TOOBIG, e->e_flags) &&
510					    e->e_msgsize > MaxMessageSize)
511						 e->e_flags |= EF_TOOBIG;
512				}
513			}
514			switch (mstate)
515			{
516			  case MS_BODY:
517				/* just put the character out */
518				if (!bitset(EF_TOOBIG, e->e_flags))
519					(void) sm_io_putc(df, SM_TIME_DEFAULT,
520							  c);
521
522				/* FALLTHROUGH */
523
524			  case MS_DISCARD:
525				continue;
526			}
527
528			SM_ASSERT(mstate == MS_UFROM || mstate == MS_HEADER);
529
530			/* header -- buffer up */
531			if (bp >= &buf[buflen - 2])
532			{
533				char *obuf;
534
535				/* out of space for header */
536				obuf = buf;
537				if (buflen < MEMCHUNKSIZE)
538					buflen *= 2;
539				else
540					buflen += MEMCHUNKSIZE;
541				buf = xalloc(buflen);
542				memmove(buf, obuf, bp - obuf);
543				bp = &buf[bp - obuf];
544				if (obuf != bufbuf)
545					sm_free(obuf);  /* XXX */
546			}
547
548			/*
549			**  XXX Notice: the logic here is broken.
550			**  An input to sendmail that doesn't contain a
551			**  header but starts immediately with the body whose
552			**  first line contain characters which match the
553			**  following "if" will cause problems: those
554			**  characters will NOT appear in the output...
555			**  Do we care?
556			*/
557
558			if (c >= 0200 && c <= 0237)
559			{
560#if 0	/* causes complaints -- figure out something for 8.n+1 */
561				usrerr("Illegal character 0x%x in header", c);
562#else /* 0 */
563				/* EMPTY */
564#endif /* 0 */
565			}
566			else if (c != '\0')
567			{
568				*bp++ = c;
569				++hdrslen;
570				if (!headeronly &&
571				    MaxHeadersLength > 0 &&
572				    hdrslen > MaxHeadersLength)
573				{
574					sm_syslog(LOG_NOTICE, e->e_id,
575						  "headers too large (%d max) from %s during message collect",
576						  MaxHeadersLength,
577						  CURHOSTNAME);
578					errno = 0;
579					e->e_flags |= EF_CLRQUEUE;
580					e->e_status = "5.6.0";
581					usrerrenh(e->e_status,
582						  "552 Headers too large (%d max)",
583						  MaxHeadersLength);
584					mstate = MS_DISCARD;
585				}
586			}
587			if (istate == IS_BOL)
588				break;
589		}
590		*bp = '\0';
591
592nextstate:
593		if (tTd(30, 35))
594			sm_dprintf("nextstate, istate=%d, mstate=%d, line = \"%s\"\n",
595				istate, mstate, buf);
596		switch (mstate)
597		{
598		  case MS_UFROM:
599			mstate = MS_HEADER;
600#ifndef NOTUNIX
601			if (strncmp(buf, "From ", 5) == 0)
602			{
603				bp = buf;
604				eatfrom(buf, e);
605				continue;
606			}
607#endif /* ! NOTUNIX */
608			/* FALLTHROUGH */
609
610		  case MS_HEADER:
611			if (!isheader(buf))
612			{
613				mstate = MS_BODY;
614				goto nextstate;
615			}
616
617			/* check for possible continuation line */
618			do
619			{
620				sm_io_clearerr(fp);
621				errno = 0;
622				c = sm_io_getc(fp, SM_TIME_DEFAULT);
623			} while (c == SM_IO_EOF && errno == EINTR);
624			if (c != SM_IO_EOF)
625				(void) sm_io_ungetc(fp, SM_TIME_DEFAULT, c);
626			if (c == ' ' || c == '\t')
627			{
628				/* yep -- defer this */
629				continue;
630			}
631
632			/* trim off trailing CRLF or NL */
633			SM_ASSERT(bp > buf);
634			if (*--bp != '\n' || *--bp != '\r')
635				bp++;
636			*bp = '\0';
637
638			if (bitset(H_EOH, chompheader(buf,
639						      CHHDR_CHECK | CHHDR_USER,
640						      hdrp, e)))
641			{
642				mstate = MS_BODY;
643				goto nextstate;
644			}
645			numhdrs++;
646			break;
647
648		  case MS_BODY:
649			if (tTd(30, 1))
650				sm_dprintf("EOH\n");
651
652			if (headeronly)
653				goto readerr;
654
655			df = collect_eoh(e, numhdrs, hdrslen);
656			if (df == NULL)
657				e->e_flags |= EF_TOOBIG;
658
659			bp = buf;
660
661			/* toss blank line */
662			if ((!bitset(EF_CRLF_NOT_EOL, e->e_flags) &&
663				bp[0] == '\r' && bp[1] == '\n') ||
664			    (!bitset(EF_NL_NOT_EOL, e->e_flags) &&
665				bp[0] == '\n'))
666			{
667				break;
668			}
669
670			/* if not a blank separator, write it out */
671			if (!bitset(EF_TOOBIG, e->e_flags))
672			{
673				while (*bp != '\0')
674					(void) sm_io_putc(df, SM_TIME_DEFAULT,
675							  *bp++);
676			}
677			break;
678		}
679		bp = buf;
680	}
681
682readerr:
683	if ((sm_io_eof(fp) && smtpmode) || sm_io_error(fp))
684	{
685		const char *errmsg;
686
687		if (sm_io_eof(fp))
688			errmsg = "unexpected close";
689		else
690			errmsg = sm_errstring(errno);
691		if (tTd(30, 1))
692			sm_dprintf("collect: premature EOM: %s\n", errmsg);
693		if (LogLevel > 1)
694			sm_syslog(LOG_WARNING, e->e_id,
695				"collect: premature EOM: %s", errmsg);
696		inputerr = true;
697	}
698
699	/* reset global timer */
700	if (CollectTimeout != NULL)
701		sm_clrevent(CollectTimeout);
702
703	if (headeronly)
704		return;
705
706	if (mstate != MS_BODY)
707	{
708		/* no body or discard, so we never opened the data file */
709		SM_ASSERT(df == NULL);
710		df = collect_eoh(e, numhdrs, hdrslen);
711	}
712
713	if (df == NULL)
714	{
715		/* skip next few clauses */
716		/* EMPTY */
717	}
718	else if (sm_io_flush(df, SM_TIME_DEFAULT) != 0 || sm_io_error(df))
719	{
720		dferror(df, "sm_io_flush||sm_io_error", e);
721		flush_errors(true);
722		finis(true, true, ExitStat);
723		/* NOTREACHED */
724	}
725	else if (SuperSafe == SAFE_NO ||
726		 SuperSafe == SAFE_INTERACTIVE ||
727		 (SuperSafe == SAFE_REALLY_POSTMILTER && smtpmode))
728	{
729		/* skip next few clauses */
730		/* EMPTY */
731	}
732	else if (sm_io_setinfo(df, SM_BF_COMMIT, NULL) < 0 && errno != EINVAL)
733	{
734		int save_errno = errno;
735
736		if (save_errno == EEXIST)
737		{
738			char *dfile;
739			struct stat st;
740			int dfd;
741
742			dfile = queuename(e, DATAFL_LETTER);
743			if (stat(dfile, &st) < 0)
744				st.st_size = -1;
745			errno = EEXIST;
746			syserr("@collect: bfcommit(%s): already on disk, size=%ld",
747			       dfile, (long) st.st_size);
748			dfd = sm_io_getinfo(df, SM_IO_WHAT_FD, NULL);
749			if (dfd >= 0)
750				dumpfd(dfd, true, true);
751		}
752		errno = save_errno;
753		dferror(df, "bfcommit", e);
754		flush_errors(true);
755		finis(save_errno != EEXIST, true, ExitStat);
756	}
757	else if ((afd = sm_io_getinfo(df, SM_IO_WHAT_FD, NULL)) < 0)
758	{
759		dferror(df, "sm_io_getinfo", e);
760		flush_errors(true);
761		finis(true, true, ExitStat);
762		/* NOTREACHED */
763	}
764	else if (fsync(afd) < 0)
765	{
766		dferror(df, "fsync", e);
767		flush_errors(true);
768		finis(true, true, ExitStat);
769		/* NOTREACHED */
770	}
771	else if (sm_io_close(df, SM_TIME_DEFAULT) < 0)
772	{
773		dferror(df, "sm_io_close", e);
774		flush_errors(true);
775		finis(true, true, ExitStat);
776		/* NOTREACHED */
777	}
778	else
779	{
780		/* everything is happily flushed to disk */
781		df = NULL;
782
783		/* remove from available space in filesystem */
784		updfs(e, false, true);
785	}
786
787	/* An EOF when running SMTP is an error */
788	if (inputerr && (OpMode == MD_SMTP || OpMode == MD_DAEMON))
789	{
790		char *host;
791		char *problem;
792		ADDRESS *q;
793
794		host = RealHostName;
795		if (host == NULL)
796			host = "localhost";
797
798		if (sm_io_eof(fp))
799			problem = "unexpected close";
800		else if (sm_io_error(fp))
801			problem = "I/O error";
802		else
803			problem = "read timeout";
804		if (LogLevel > 0 && sm_io_eof(fp))
805			sm_syslog(LOG_NOTICE, e->e_id,
806				"collect: %s on connection from %.100s, sender=%s",
807				problem, host,
808				shortenstring(e->e_from.q_paddr, MAXSHORTSTR));
809		if (sm_io_eof(fp))
810			usrerr("451 4.4.1 collect: %s on connection from %s, from=%s",
811				problem, host,
812				shortenstring(e->e_from.q_paddr, MAXSHORTSTR));
813		else
814			syserr("451 4.4.1 collect: %s on connection from %s, from=%s",
815				problem, host,
816				shortenstring(e->e_from.q_paddr, MAXSHORTSTR));
817
818		/* don't return an error indication */
819		e->e_to = NULL;
820		e->e_flags &= ~EF_FATALERRS;
821		e->e_flags |= EF_CLRQUEUE;
822
823		/* Don't send any message notification to sender */
824		for (q = e->e_sendqueue; q != NULL; q = q->q_next)
825		{
826			if (QS_IS_DEAD(q->q_state))
827				continue;
828			q->q_state = QS_FATALERR;
829		}
830
831		finis(true, true, ExitStat);
832		/* NOTREACHED */
833	}
834
835	/* Log collection information. */
836	if (bitset(EF_LOGSENDER, e->e_flags) && LogLevel > 4)
837	{
838		logsender(e, e->e_msgid);
839		e->e_flags &= ~EF_LOGSENDER;
840	}
841
842	/* check for message too large */
843	if (bitset(EF_TOOBIG, e->e_flags))
844	{
845		e->e_flags |= EF_NO_BODY_RETN|EF_CLRQUEUE;
846		if (!bitset(EF_FATALERRS, e->e_flags))
847		{
848			e->e_status = "5.2.3";
849			usrerrenh(e->e_status,
850				"552 Message exceeds maximum fixed size (%ld)",
851				MaxMessageSize);
852			if (LogLevel > 6)
853				sm_syslog(LOG_NOTICE, e->e_id,
854					"message size (%ld) exceeds maximum (%ld)",
855					e->e_msgsize, MaxMessageSize);
856		}
857	}
858
859	/* check for illegal 8-bit data */
860	if (HasEightBits)
861	{
862		e->e_flags |= EF_HAS8BIT;
863		if (!bitset(MM_PASS8BIT|MM_MIME8BIT, MimeMode) &&
864		    !bitset(EF_IS_MIME, e->e_flags))
865		{
866			e->e_status = "5.6.1";
867			usrerrenh(e->e_status, "554 Eight bit data not allowed");
868		}
869	}
870	else
871	{
872		/* if it claimed to be 8 bits, well, it lied.... */
873		if (e->e_bodytype != NULL &&
874		    sm_strcasecmp(e->e_bodytype, "8BITMIME") == 0)
875			e->e_bodytype = "7BIT";
876	}
877
878	if (SuperSafe == SAFE_REALLY && !bitset(EF_FATALERRS, e->e_flags))
879	{
880		char *dfname = queuename(e, DATAFL_LETTER);
881		if ((e->e_dfp = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, dfname,
882					   SM_IO_RDONLY_B, NULL)) == NULL)
883		{
884			/* we haven't acked receipt yet, so just chuck this */
885			syserr("@Cannot reopen %s", dfname);
886			finis(true, true, ExitStat);
887			/* NOTREACHED */
888		}
889	}
890	else
891		e->e_dfp = df;
892
893	/* collect statistics */
894	if (OpMode != MD_VERIFY)
895	{
896		/*
897		**  Recalculate e_msgpriority, it is done at in eatheader()
898		**  which is called (in 8.12) after the header is collected,
899		**  hence e_msgsize is (most likely) incorrect.
900		*/
901
902		e->e_msgpriority = e->e_msgsize
903				 - e->e_class * WkClassFact
904				 + e->e_nrcpts * WkRecipFact;
905		markstats(e, (ADDRESS *) NULL, STATS_NORMAL);
906	}
907}
908
909static void
910collecttimeout(timeout)
911	int timeout;
912{
913	int save_errno = errno;
914
915	/*
916	**  NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER.  DO NOT ADD
917	**	ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
918	**	DOING.
919	*/
920
921	if (CollectProgress)
922	{
923		/* reset the timeout */
924		CollectTimeout = sm_sigsafe_setevent(timeout, collecttimeout,
925						     timeout);
926		CollectProgress = false;
927	}
928	else
929	{
930		/* event is done */
931		CollectTimeout = NULL;
932	}
933
934	/* if no progress was made or problem resetting event, die now */
935	if (CollectTimeout == NULL)
936	{
937		errno = ETIMEDOUT;
938		longjmp(CtxCollectTimeout, 1);
939	}
940	errno = save_errno;
941}
942/*
943**  DFERROR -- signal error on writing the data file.
944**
945**	Called by collect().  Collect() always terminates the process
946**	immediately after calling dferror(), which means that the SMTP
947**	session will be terminated, which means that any error message
948**	issued by dferror must be a 421 error, as per RFC 821.
949**
950**	Parameters:
951**		df -- the file pointer for the data file.
952**		msg -- detailed message.
953**		e -- the current envelope.
954**
955**	Returns:
956**		none.
957**
958**	Side Effects:
959**		Gives an error message.
960**		Arranges for following output to go elsewhere.
961*/
962
963void
964dferror(df, msg, e)
965	SM_FILE_T *volatile df;
966	char *msg;
967	register ENVELOPE *e;
968{
969	char *dfname;
970
971	dfname = queuename(e, DATAFL_LETTER);
972	setstat(EX_IOERR);
973	if (errno == ENOSPC)
974	{
975#if STAT64 > 0
976		struct stat64 st;
977#else /* STAT64 > 0 */
978		struct stat st;
979#endif /* STAT64 > 0 */
980		long avail;
981		long bsize;
982
983		e->e_flags |= EF_NO_BODY_RETN;
984
985		if (
986#if STAT64 > 0
987		    fstat64(sm_io_getinfo(df, SM_IO_WHAT_FD, NULL), &st)
988#else /* STAT64 > 0 */
989		    fstat(sm_io_getinfo(df, SM_IO_WHAT_FD, NULL), &st)
990#endif /* STAT64 > 0 */
991		    < 0)
992		  st.st_size = 0;
993		(void) sm_io_reopen(SmFtStdio, SM_TIME_DEFAULT, dfname,
994				    SM_IO_WRONLY_B, NULL, df);
995		if (st.st_size <= 0)
996			(void) sm_io_fprintf(df, SM_TIME_DEFAULT,
997				"\n*** Mail could not be accepted");
998		else
999			(void) sm_io_fprintf(df, SM_TIME_DEFAULT,
1000				"\n*** Mail of at least %llu bytes could not be accepted\n",
1001				(ULONGLONG_T) st.st_size);
1002		(void) sm_io_fprintf(df, SM_TIME_DEFAULT,
1003			"*** at %s due to lack of disk space for temp file.\n",
1004			MyHostName);
1005		avail = freediskspace(qid_printqueue(e->e_qgrp, e->e_qdir),
1006				      &bsize);
1007		if (avail > 0)
1008		{
1009			if (bsize > 1024)
1010				avail *= bsize / 1024;
1011			else if (bsize < 1024)
1012				avail /= 1024 / bsize;
1013			(void) sm_io_fprintf(df, SM_TIME_DEFAULT,
1014				"*** Currently, %ld kilobytes are available for mail temp files.\n",
1015				avail);
1016		}
1017#if 0
1018		/* Wrong response code; should be 421. */
1019		e->e_status = "4.3.1";
1020		usrerrenh(e->e_status, "452 Out of disk space for temp file");
1021#else /* 0 */
1022		syserr("421 4.3.1 Out of disk space for temp file");
1023#endif /* 0 */
1024	}
1025	else
1026		syserr("421 4.3.0 collect: Cannot write %s (%s, uid=%d, gid=%d)",
1027			dfname, msg, (int) geteuid(), (int) getegid());
1028	if (sm_io_reopen(SmFtStdio, SM_TIME_DEFAULT, SM_PATH_DEVNULL,
1029			 SM_IO_WRONLY, NULL, df) == NULL)
1030		sm_syslog(LOG_ERR, e->e_id,
1031			  "dferror: sm_io_reopen(\"/dev/null\") failed: %s",
1032			  sm_errstring(errno));
1033}
1034/*
1035**  EATFROM -- chew up a UNIX style from line and process
1036**
1037**	This does indeed make some assumptions about the format
1038**	of UNIX messages.
1039**
1040**	Parameters:
1041**		fm -- the from line.
1042**		e -- envelope
1043**
1044**	Returns:
1045**		none.
1046**
1047**	Side Effects:
1048**		extracts what information it can from the header,
1049**		such as the date.
1050*/
1051
1052#ifndef NOTUNIX
1053
1054static char	*DowList[] =
1055{
1056	"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", NULL
1057};
1058
1059static char	*MonthList[] =
1060{
1061	"Jan", "Feb", "Mar", "Apr", "May", "Jun",
1062	"Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
1063	NULL
1064};
1065
1066static void
1067eatfrom(fm, e)
1068	char *volatile fm;
1069	register ENVELOPE *e;
1070{
1071	register char *p;
1072	register char **dt;
1073
1074	if (tTd(30, 2))
1075		sm_dprintf("eatfrom(%s)\n", fm);
1076
1077	/* find the date part */
1078	p = fm;
1079	while (*p != '\0')
1080	{
1081		/* skip a word */
1082		while (*p != '\0' && *p != ' ')
1083			p++;
1084		while (*p == ' ')
1085			p++;
1086		if (strlen(p) < 17)
1087		{
1088			/* no room for the date */
1089			return;
1090		}
1091		if (!(isascii(*p) && isupper(*p)) ||
1092		    p[3] != ' ' || p[13] != ':' || p[16] != ':')
1093			continue;
1094
1095		/* we have a possible date */
1096		for (dt = DowList; *dt != NULL; dt++)
1097			if (strncmp(*dt, p, 3) == 0)
1098				break;
1099		if (*dt == NULL)
1100			continue;
1101
1102		for (dt = MonthList; *dt != NULL; dt++)
1103		{
1104			if (strncmp(*dt, &p[4], 3) == 0)
1105				break;
1106		}
1107		if (*dt != NULL)
1108			break;
1109	}
1110
1111	if (*p != '\0')
1112	{
1113		char *q, buf[25];
1114
1115		/* we have found a date */
1116		(void) sm_strlcpy(buf, p, sizeof(buf));
1117		q = arpadate(buf);
1118		macdefine(&e->e_macro, A_TEMP, 'a', q);
1119	}
1120}
1121#endif /* ! NOTUNIX */
1122