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