138032Speter/*
2261194Sgshapiro * Copyright (c) 1998-2006, 2008 Proofpoint, Inc. and its suppliers.
364562Sgshapiro *	All rights reserved.
438032Speter * Copyright (c) 1983, 1995-1997 Eric P. Allman.  All rights reserved.
538032Speter * Copyright (c) 1988, 1993
638032Speter *	The Regents of the University of California.  All rights reserved.
738032Speter *
838032Speter * By using this file, you agree to the terms and conditions set
938032Speter * forth in the LICENSE file which can be found at the top level of
1038032Speter * the sendmail distribution.
1138032Speter *
1238032Speter */
1338032Speter
1464562Sgshapiro#include <sendmail.h>
1538032Speter
16266527SgshapiroSM_RCSID("@(#)$Id: collect.c,v 8.287 2013-11-22 20:51:55 ca Exp $")
1764562Sgshapiro
1864562Sgshapirostatic void	eatfrom __P((char *volatile, ENVELOPE *));
1990792Sgshapirostatic void	collect_doheader __P((ENVELOPE *));
2090792Sgshapirostatic SM_FILE_T *collect_dfopen __P((ENVELOPE *));
2190792Sgshapirostatic SM_FILE_T *collect_eoh __P((ENVELOPE *, int, int));
2264562Sgshapiro
2390792Sgshapiro/*
2490792Sgshapiro**  COLLECT_EOH -- end-of-header processing in collect()
2590792Sgshapiro**
2690792Sgshapiro**	Called by collect() when it encounters the blank line
2790792Sgshapiro**	separating the header from the message body, or when it
2890792Sgshapiro**	encounters EOF in a message that contains only a header.
2990792Sgshapiro**
3090792Sgshapiro**	Parameters:
3190792Sgshapiro**		e -- envelope
3290792Sgshapiro**		numhdrs -- number of headers
3390792Sgshapiro**		hdrslen -- length of headers
3490792Sgshapiro**
3590792Sgshapiro**	Results:
3690792Sgshapiro**		NULL, or handle to open data file
3790792Sgshapiro**
3890792Sgshapiro**	Side Effects:
3990792Sgshapiro**		end-of-header check ruleset is invoked.
4090792Sgshapiro**		envelope state is updated.
4190792Sgshapiro**		headers may be added and deleted.
4290792Sgshapiro**		selects the queue.
4390792Sgshapiro**		opens the data file.
4490792Sgshapiro*/
4590792Sgshapiro
4690792Sgshapirostatic SM_FILE_T *
4790792Sgshapirocollect_eoh(e, numhdrs, hdrslen)
4890792Sgshapiro	ENVELOPE *e;
4990792Sgshapiro	int numhdrs;
5090792Sgshapiro	int hdrslen;
5190792Sgshapiro{
5290792Sgshapiro	char hnum[16];
5390792Sgshapiro	char hsize[16];
5490792Sgshapiro
5590792Sgshapiro	/* call the end-of-header check ruleset */
56168515Sgshapiro	(void) sm_snprintf(hnum, sizeof(hnum), "%d", numhdrs);
57168515Sgshapiro	(void) sm_snprintf(hsize, sizeof(hsize), "%d", hdrslen);
5890792Sgshapiro	if (tTd(30, 10))
5990792Sgshapiro		sm_dprintf("collect: rscheck(\"check_eoh\", \"%s $| %s\")\n",
6090792Sgshapiro			   hnum, hsize);
61102528Sgshapiro	(void) rscheck("check_eoh", hnum, hsize, e, RSF_UNSTRUCTURED|RSF_COUNT,
62285229Sgshapiro			3, NULL, e->e_id, NULL, NULL);
6390792Sgshapiro
6490792Sgshapiro	/*
6590792Sgshapiro	**  Process the header,
6690792Sgshapiro	**  select the queue, open the data file.
6790792Sgshapiro	*/
6890792Sgshapiro
6990792Sgshapiro	collect_doheader(e);
7090792Sgshapiro	return collect_dfopen(e);
7190792Sgshapiro}
7290792Sgshapiro
7390792Sgshapiro/*
7490792Sgshapiro**  COLLECT_DOHEADER -- process header in collect()
7590792Sgshapiro**
7690792Sgshapiro**	Called by collect() after it has finished parsing the header,
7790792Sgshapiro**	but before it selects the queue and creates the data file.
7890792Sgshapiro**	The results of processing the header will affect queue selection.
7990792Sgshapiro**
8090792Sgshapiro**	Parameters:
8190792Sgshapiro**		e -- envelope
8290792Sgshapiro**
8390792Sgshapiro**	Results:
8490792Sgshapiro**		none.
8590792Sgshapiro**
8690792Sgshapiro**	Side Effects:
8790792Sgshapiro**		envelope state is updated.
8890792Sgshapiro**		headers may be added and deleted.
8990792Sgshapiro*/
9090792Sgshapiro
9190792Sgshapirostatic void
9290792Sgshapirocollect_doheader(e)
9390792Sgshapiro	ENVELOPE *e;
9490792Sgshapiro{
9590792Sgshapiro	/*
9690792Sgshapiro	**  Find out some information from the headers.
9790792Sgshapiro	**	Examples are who is the from person & the date.
9890792Sgshapiro	*/
9990792Sgshapiro
10090792Sgshapiro	eatheader(e, true, false);
10190792Sgshapiro
10290792Sgshapiro	if (GrabTo && e->e_sendqueue == NULL)
10390792Sgshapiro		usrerr("No recipient addresses found in header");
10490792Sgshapiro
10590792Sgshapiro	/*
10690792Sgshapiro	**  If we have a Return-Receipt-To:, turn it into a DSN.
10790792Sgshapiro	*/
10890792Sgshapiro
10990792Sgshapiro	if (RrtImpliesDsn && hvalue("return-receipt-to", e->e_header) != NULL)
11090792Sgshapiro	{
11190792Sgshapiro		ADDRESS *q;
11290792Sgshapiro
11390792Sgshapiro		for (q = e->e_sendqueue; q != NULL; q = q->q_next)
11490792Sgshapiro			if (!bitset(QHASNOTIFY, q->q_flags))
11590792Sgshapiro				q->q_flags |= QHASNOTIFY|QPINGONSUCCESS;
11690792Sgshapiro	}
11790792Sgshapiro
11890792Sgshapiro	/*
11990792Sgshapiro	**  Add an appropriate recipient line if we have none.
12090792Sgshapiro	*/
12190792Sgshapiro
12290792Sgshapiro	if (hvalue("to", e->e_header) != NULL ||
12390792Sgshapiro	    hvalue("cc", e->e_header) != NULL ||
12490792Sgshapiro	    hvalue("apparently-to", e->e_header) != NULL)
12590792Sgshapiro	{
12690792Sgshapiro		/* have a valid recipient header -- delete Bcc: headers */
12790792Sgshapiro		e->e_flags |= EF_DELETE_BCC;
12890792Sgshapiro	}
12990792Sgshapiro	else if (hvalue("bcc", e->e_header) == NULL)
13090792Sgshapiro	{
13190792Sgshapiro		/* no valid recipient headers */
13290792Sgshapiro		register ADDRESS *q;
13390792Sgshapiro		char *hdr = NULL;
13490792Sgshapiro
13590792Sgshapiro		/* create a recipient field */
13690792Sgshapiro		switch (NoRecipientAction)
13790792Sgshapiro		{
13890792Sgshapiro		  case NRA_ADD_APPARENTLY_TO:
13990792Sgshapiro			hdr = "Apparently-To";
14090792Sgshapiro			break;
14190792Sgshapiro
14290792Sgshapiro		  case NRA_ADD_TO:
14390792Sgshapiro			hdr = "To";
14490792Sgshapiro			break;
14590792Sgshapiro
14690792Sgshapiro		  case NRA_ADD_BCC:
147168515Sgshapiro			addheader("Bcc", " ", 0, e, true);
14890792Sgshapiro			break;
14990792Sgshapiro
15090792Sgshapiro		  case NRA_ADD_TO_UNDISCLOSED:
151168515Sgshapiro			addheader("To", "undisclosed-recipients:;", 0, e, true);
15290792Sgshapiro			break;
15390792Sgshapiro		}
15490792Sgshapiro
15590792Sgshapiro		if (hdr != NULL)
15690792Sgshapiro		{
15790792Sgshapiro			for (q = e->e_sendqueue; q != NULL; q = q->q_next)
15890792Sgshapiro			{
15990792Sgshapiro				if (q->q_alias != NULL)
16090792Sgshapiro					continue;
16190792Sgshapiro				if (tTd(30, 3))
16290792Sgshapiro					sm_dprintf("Adding %s: %s\n",
16390792Sgshapiro						hdr, q->q_paddr);
164168515Sgshapiro				addheader(hdr, q->q_paddr, 0, e, true);
16590792Sgshapiro			}
16690792Sgshapiro		}
16790792Sgshapiro	}
16890792Sgshapiro}
16990792Sgshapiro
17090792Sgshapiro/*
17190792Sgshapiro**  COLLECT_DFOPEN -- open the message data file
17290792Sgshapiro**
17390792Sgshapiro**	Called by collect() after it has finished processing the header.
17490792Sgshapiro**	Queue selection occurs at this point, possibly based on the
17590792Sgshapiro**	envelope's recipient list and on header information.
17690792Sgshapiro**
17790792Sgshapiro**	Parameters:
17890792Sgshapiro**		e -- envelope
17990792Sgshapiro**
18090792Sgshapiro**	Results:
18190792Sgshapiro**		NULL, or a pointer to an open data file,
18290792Sgshapiro**		into which the message body will be written by collect().
18390792Sgshapiro**
18490792Sgshapiro**	Side Effects:
18590792Sgshapiro**		Calls syserr, sets EF_FATALERRS and returns NULL
18690792Sgshapiro**		if there is insufficient disk space.
18790792Sgshapiro**		Aborts process if data file could not be opened.
18890792Sgshapiro**		Otherwise, the queue is selected,
18990792Sgshapiro**		e->e_{dfino,dfdev,msgsize,flags} are updated,
19090792Sgshapiro**		and a pointer to an open data file is returned.
19190792Sgshapiro*/
19290792Sgshapiro
19390792Sgshapirostatic SM_FILE_T *
19490792Sgshapirocollect_dfopen(e)
19590792Sgshapiro	ENVELOPE *e;
19690792Sgshapiro{
19790792Sgshapiro	MODE_T oldumask = 0;
19890792Sgshapiro	int dfd;
19990792Sgshapiro	struct stat stbuf;
20090792Sgshapiro	SM_FILE_T *df;
20190792Sgshapiro	char *dfname;
20290792Sgshapiro
20390792Sgshapiro	if (!setnewqueue(e))
20490792Sgshapiro		return NULL;
20590792Sgshapiro
20690792Sgshapiro	dfname = queuename(e, DATAFL_LETTER);
20790792Sgshapiro	if (bitset(S_IWGRP, QueueFileMode))
20890792Sgshapiro		oldumask = umask(002);
20990792Sgshapiro	df = bfopen(dfname, QueueFileMode, DataFileBufferSize,
21090792Sgshapiro		    SFF_OPENASROOT);
21190792Sgshapiro	if (bitset(S_IWGRP, QueueFileMode))
21290792Sgshapiro		(void) umask(oldumask);
21390792Sgshapiro	if (df == NULL)
21490792Sgshapiro	{
21590792Sgshapiro		syserr("@Cannot create %s", dfname);
21690792Sgshapiro		e->e_flags |= EF_NO_BODY_RETN;
21790792Sgshapiro		flush_errors(true);
218120256Sgshapiro		finis(false, true, ExitStat);
21990792Sgshapiro		/* NOTREACHED */
22090792Sgshapiro	}
22190792Sgshapiro	dfd = sm_io_getinfo(df, SM_IO_WHAT_FD, NULL);
22290792Sgshapiro	if (dfd < 0 || fstat(dfd, &stbuf) < 0)
22390792Sgshapiro		e->e_dfino = -1;
22490792Sgshapiro	else
22590792Sgshapiro	{
22690792Sgshapiro		e->e_dfdev = stbuf.st_dev;
22790792Sgshapiro		e->e_dfino = stbuf.st_ino;
22890792Sgshapiro	}
22990792Sgshapiro	e->e_flags |= EF_HAS_DF;
23090792Sgshapiro	return df;
23190792Sgshapiro}
23290792Sgshapiro
23390792Sgshapiro/*
23438032Speter**  COLLECT -- read & parse message header & make temp file.
23538032Speter**
23638032Speter**	Creates a temporary file name and copies the standard
23738032Speter**	input to that file.  Leading UNIX-style "From" lines are
23838032Speter**	stripped off (after important information is extracted).
23938032Speter**
24038032Speter**	Parameters:
24138032Speter**		fp -- file to read.
24238032Speter**		smtpmode -- if set, we are running SMTP: give an RFC821
24338032Speter**			style message to say we are ready to collect
24438032Speter**			input, and never ignore a single dot to mean
24538032Speter**			end of message.
24638032Speter**		hdrp -- the location to stash the header.
24738032Speter**		e -- the current envelope.
248120256Sgshapiro**		rsetsize -- reset e_msgsize?
24938032Speter**
25038032Speter**	Returns:
25138032Speter**		none.
25238032Speter**
25338032Speter**	Side Effects:
25490792Sgshapiro**		If successful,
25590792Sgshapiro**		- Data file is created and filled, and e->e_dfp is set.
25690792Sgshapiro**		- The from person may be set.
25790792Sgshapiro**		If the "enough disk space" check fails,
25890792Sgshapiro**		- syserr is called.
25990792Sgshapiro**		- e->e_dfp is NULL.
26090792Sgshapiro**		- e->e_flags & EF_FATALERRS is set.
26190792Sgshapiro**		- collect() returns.
26290792Sgshapiro**		If data file cannot be created, the process is terminated.
26338032Speter*/
26438032Speter
26538032Speter/* values for input state machine */
26638032Speter#define IS_NORM		0	/* middle of line */
26738032Speter#define IS_BOL		1	/* beginning of line */
26838032Speter#define IS_DOT		2	/* read a dot at beginning of line */
26938032Speter#define IS_DOTCR	3	/* read ".\r" at beginning of line */
27038032Speter#define IS_CR		4	/* read a carriage return */
27138032Speter
27238032Speter/* values for message state machine */
27338032Speter#define MS_UFROM	0	/* reading Unix from line */
27438032Speter#define MS_HEADER	1	/* reading message header */
27538032Speter#define MS_BODY		2	/* reading message body */
27643148Speter#define MS_DISCARD	3	/* discarding rest of message */
27738032Speter
27838032Spetervoid
279120256Sgshapirocollect(fp, smtpmode, hdrp, e, rsetsize)
28090792Sgshapiro	SM_FILE_T *fp;
28138032Speter	bool smtpmode;
28238032Speter	HDR **hdrp;
28338032Speter	register ENVELOPE *e;
284120256Sgshapiro	bool rsetsize;
28538032Speter{
286157001Sgshapiro	register SM_FILE_T *df;
287157001Sgshapiro	bool ignrdot;
288157001Sgshapiro	int dbto;
289157001Sgshapiro	register char *bp;
290157001Sgshapiro	int c;
291157001Sgshapiro	bool inputerr;
29238032Speter	bool headeronly;
293157001Sgshapiro	char *buf;
294157001Sgshapiro	int buflen;
295157001Sgshapiro	int istate;
296157001Sgshapiro	int mstate;
297157001Sgshapiro	int hdrslen;
298157001Sgshapiro	int numhdrs;
299157001Sgshapiro	int afd;
300285229Sgshapiro	int old_rd_tmo;
301157001Sgshapiro	unsigned char *pbp;
30290792Sgshapiro	unsigned char peekbuf[8];
30338032Speter	char bufbuf[MAXLINE];
304249729Sgshapiro#if _FFR_REJECT_NUL_BYTE
305249729Sgshapiro	bool hasNUL;		/* has at least one NUL input byte */
306363466Sgshapiro#endif
30738032Speter
30890792Sgshapiro	df = NULL;
30990792Sgshapiro	ignrdot = smtpmode ? false : IgnrDot;
310157001Sgshapiro
311157001Sgshapiro	/* timeout for I/O functions is in milliseconds */
312157001Sgshapiro	dbto = smtpmode ? ((int) TimeOuts.to_datablock * 1000)
313157001Sgshapiro			: SM_TIME_FOREVER;
314157001Sgshapiro	sm_io_setinfo(fp, SM_IO_WHAT_TIMEOUT, &dbto);
315285229Sgshapiro	old_rd_tmo = set_tls_rd_tmo(TimeOuts.to_datablock);
31690792Sgshapiro	c = SM_IO_EOF;
31790792Sgshapiro	inputerr = false;
31838032Speter	headeronly = hdrp != NULL;
31990792Sgshapiro	hdrslen = 0;
32090792Sgshapiro	numhdrs = 0;
32190792Sgshapiro	HasEightBits = false;
322249729Sgshapiro#if _FFR_REJECT_NUL_BYTE
323249729Sgshapiro	hasNUL = false;
324363466Sgshapiro#endif
32590792Sgshapiro	buf = bp = bufbuf;
326168515Sgshapiro	buflen = sizeof(bufbuf);
32790792Sgshapiro	pbp = peekbuf;
32890792Sgshapiro	istate = IS_BOL;
32990792Sgshapiro	mstate = SaveFrom ? MS_HEADER : MS_UFROM;
33038032Speter
33138032Speter	/*
33238032Speter	**  Tell ARPANET to go ahead.
33338032Speter	*/
33438032Speter
33538032Speter	if (smtpmode)
33638032Speter		message("354 Enter mail, end with \".\" on a line by itself");
33738032Speter
338157001Sgshapiro	/* simulate an I/O timeout when used as sink */
339157001Sgshapiro	if (tTd(83, 101))
340157001Sgshapiro		sleep(319);
341157001Sgshapiro
34238032Speter	if (tTd(30, 2))
34390792Sgshapiro		sm_dprintf("collect\n");
34438032Speter
34538032Speter	/*
34638032Speter	**  Read the message.
34738032Speter	**
34838032Speter	**	This is done using two interleaved state machines.
34938032Speter	**	The input state machine is looking for things like
35038032Speter	**	hidden dots; the message state machine is handling
35138032Speter	**	the larger picture (e.g., header versus body).
35238032Speter	*/
35338032Speter
354120256Sgshapiro	if (rsetsize)
355120256Sgshapiro		e->e_msgsize = 0;
35638032Speter	for (;;)
35738032Speter	{
35838032Speter		if (tTd(30, 35))
35990792Sgshapiro			sm_dprintf("top, istate=%d, mstate=%d\n", istate,
36090792Sgshapiro				   mstate);
36138032Speter		for (;;)
36238032Speter		{
36338032Speter			if (pbp > peekbuf)
36438032Speter				c = *--pbp;
36538032Speter			else
36638032Speter			{
36790792Sgshapiro				while (!sm_io_eof(fp) && !sm_io_error(fp))
36838032Speter				{
36938032Speter					errno = 0;
37090792Sgshapiro					c = sm_io_getc(fp, SM_TIME_DEFAULT);
37190792Sgshapiro					if (c == SM_IO_EOF && errno == EINTR)
37266494Sgshapiro					{
37366494Sgshapiro						/* Interrupted, retry */
37490792Sgshapiro						sm_io_clearerr(fp);
37566494Sgshapiro						continue;
37666494Sgshapiro					}
377157001Sgshapiro
378157001Sgshapiro					/* timeout? */
379157001Sgshapiro					if (c == SM_IO_EOF && errno == EAGAIN
380157001Sgshapiro					    && smtpmode)
381157001Sgshapiro					{
382157001Sgshapiro						/*
383157001Sgshapiro						**  Override e_message in
384157001Sgshapiro						**  usrerr() as this is the
385157001Sgshapiro						**  reason for failure that
386157001Sgshapiro						**  should be logged for
387157001Sgshapiro						**  undelivered recipients.
388157001Sgshapiro						*/
389157001Sgshapiro
390157001Sgshapiro						e->e_message = NULL;
391157001Sgshapiro						errno = 0;
392157001Sgshapiro						inputerr = true;
393157001Sgshapiro						goto readabort;
394157001Sgshapiro					}
39566494Sgshapiro					break;
39638032Speter				}
39738032Speter				if (TrafficLogFile != NULL && !headeronly)
39838032Speter				{
39938032Speter					if (istate == IS_BOL)
40090792Sgshapiro						(void) sm_io_fprintf(TrafficLogFile,
40190792Sgshapiro							SM_TIME_DEFAULT,
40290792Sgshapiro							"%05d <<< ",
40390792Sgshapiro							(int) CurrentPid);
40490792Sgshapiro					if (c == SM_IO_EOF)
40590792Sgshapiro						(void) sm_io_fprintf(TrafficLogFile,
40690792Sgshapiro							SM_TIME_DEFAULT,
40790792Sgshapiro							"[EOF]\n");
40838032Speter					else
40990792Sgshapiro						(void) sm_io_putc(TrafficLogFile,
41090792Sgshapiro							SM_TIME_DEFAULT,
41190792Sgshapiro							c);
41238032Speter				}
413249729Sgshapiro#if _FFR_REJECT_NUL_BYTE
414249729Sgshapiro				if (c == '\0')
415249729Sgshapiro					hasNUL = true;
416363466Sgshapiro#endif
41790792Sgshapiro				if (c == SM_IO_EOF)
41838032Speter					goto readerr;
41938032Speter				if (SevenBitInput)
42038032Speter					c &= 0x7f;
42138032Speter				else
42238032Speter					HasEightBits |= bitset(0x80, c);
42338032Speter			}
42438032Speter			if (tTd(30, 94))
42590792Sgshapiro				sm_dprintf("istate=%d, c=%c (0x%x)\n",
42664562Sgshapiro					istate, (char) c, c);
42738032Speter			switch (istate)
42838032Speter			{
42938032Speter			  case IS_BOL:
43038032Speter				if (c == '.')
43138032Speter				{
43238032Speter					istate = IS_DOT;
43338032Speter					continue;
43438032Speter				}
43538032Speter				break;
43638032Speter
43738032Speter			  case IS_DOT:
438363466Sgshapiro				if (c == '\n' && !ignrdot)
43938032Speter					goto readerr;
440363466Sgshapiro				else if (c == '\r')
44138032Speter				{
44238032Speter					istate = IS_DOTCR;
44338032Speter					continue;
44438032Speter				}
44594334Sgshapiro				else if (ignrdot ||
44694334Sgshapiro					 (c != '.' &&
44794334Sgshapiro					  OpMode != MD_SMTP &&
44838032Speter					  OpMode != MD_DAEMON &&
44938032Speter					  OpMode != MD_ARPAFTP))
45094334Sgshapiro
45138032Speter				{
452157001Sgshapiro					SM_ASSERT(pbp < peekbuf +
453157001Sgshapiro							sizeof(peekbuf));
45438032Speter					*pbp++ = c;
45538032Speter					c = '.';
45638032Speter				}
45738032Speter				break;
45838032Speter
45938032Speter			  case IS_DOTCR:
46038032Speter				if (c == '\n' && !ignrdot)
46138032Speter					goto readerr;
46238032Speter				else
46338032Speter				{
46438032Speter					/* push back the ".\rx" */
465157001Sgshapiro					SM_ASSERT(pbp < peekbuf +
466157001Sgshapiro							sizeof(peekbuf));
46738032Speter					*pbp++ = c;
46894334Sgshapiro					if (OpMode != MD_SMTP &&
46994334Sgshapiro					    OpMode != MD_DAEMON &&
47094334Sgshapiro					    OpMode != MD_ARPAFTP)
47194334Sgshapiro					{
472112810Sgshapiro						SM_ASSERT(pbp < peekbuf +
473112810Sgshapiro							 sizeof(peekbuf));
47494334Sgshapiro						*pbp++ = '\r';
47594334Sgshapiro						c = '.';
47694334Sgshapiro					}
47794334Sgshapiro					else
47894334Sgshapiro						c = '\r';
47938032Speter				}
48038032Speter				break;
48138032Speter
48238032Speter			  case IS_CR:
48338032Speter				if (c == '\n')
48438032Speter					istate = IS_BOL;
48538032Speter				else
48638032Speter				{
48790792Sgshapiro					(void) sm_io_ungetc(fp, SM_TIME_DEFAULT,
48890792Sgshapiro							    c);
48938032Speter					c = '\r';
49038032Speter					istate = IS_NORM;
49138032Speter				}
49238032Speter				goto bufferchar;
49338032Speter			}
49438032Speter
495363466Sgshapiro			if (c == '\r')
49638032Speter			{
49738032Speter				istate = IS_CR;
49838032Speter				continue;
49938032Speter			}
500363466Sgshapiro			else if (c == '\n')
50138032Speter				istate = IS_BOL;
50238032Speter			else
50338032Speter				istate = IS_NORM;
50438032Speter
50538032Speterbufferchar:
50638032Speter			if (!headeronly)
50766494Sgshapiro			{
50866494Sgshapiro				/* no overflow? */
50966494Sgshapiro				if (e->e_msgsize >= 0)
51066494Sgshapiro				{
51166494Sgshapiro					e->e_msgsize++;
51266494Sgshapiro					if (MaxMessageSize > 0 &&
51366494Sgshapiro					    !bitset(EF_TOOBIG, e->e_flags) &&
51466494Sgshapiro					    e->e_msgsize > MaxMessageSize)
51566494Sgshapiro						 e->e_flags |= EF_TOOBIG;
51666494Sgshapiro				}
51766494Sgshapiro			}
51843148Speter			switch (mstate)
51938032Speter			{
52043148Speter			  case MS_BODY:
52138032Speter				/* just put the character out */
52266494Sgshapiro				if (!bitset(EF_TOOBIG, e->e_flags))
52390792Sgshapiro					(void) sm_io_putc(df, SM_TIME_DEFAULT,
52490792Sgshapiro							  c);
52590792Sgshapiro
52664562Sgshapiro				/* FALLTHROUGH */
52743148Speter
52843148Speter			  case MS_DISCARD:
52938032Speter				continue;
53038032Speter			}
53138032Speter
532141858Sgshapiro			SM_ASSERT(mstate == MS_UFROM || mstate == MS_HEADER);
533141858Sgshapiro
53438032Speter			/* header -- buffer up */
53538032Speter			if (bp >= &buf[buflen - 2])
53638032Speter			{
53738032Speter				char *obuf;
53838032Speter
53938032Speter				/* out of space for header */
54038032Speter				obuf = buf;
54138032Speter				if (buflen < MEMCHUNKSIZE)
54238032Speter					buflen *= 2;
54338032Speter				else
54438032Speter					buflen += MEMCHUNKSIZE;
545157001Sgshapiro				if (buflen <= 0)
546157001Sgshapiro				{
547157001Sgshapiro					sm_syslog(LOG_NOTICE, e->e_id,
548157001Sgshapiro						  "header overflow from %s during message collect",
549157001Sgshapiro						  CURHOSTNAME);
550157001Sgshapiro					errno = 0;
551157001Sgshapiro					e->e_flags |= EF_CLRQUEUE;
552157001Sgshapiro					e->e_status = "5.6.0";
553157001Sgshapiro					usrerrenh(e->e_status,
554157001Sgshapiro						  "552 Headers too large");
555157001Sgshapiro					goto discard;
556157001Sgshapiro				}
55738032Speter				buf = xalloc(buflen);
55864562Sgshapiro				memmove(buf, obuf, bp - obuf);
55938032Speter				bp = &buf[bp - obuf];
56038032Speter				if (obuf != bufbuf)
56190792Sgshapiro					sm_free(obuf);  /* XXX */
56238032Speter			}
56390792Sgshapiro
564168515Sgshapiro			if (c != '\0')
56538032Speter			{
56638032Speter				*bp++ = c;
56790792Sgshapiro				++hdrslen;
56880785Sgshapiro				if (!headeronly &&
56980785Sgshapiro				    MaxHeadersLength > 0 &&
57073188Sgshapiro				    hdrslen > MaxHeadersLength)
57143148Speter				{
57243148Speter					sm_syslog(LOG_NOTICE, e->e_id,
57343730Speter						  "headers too large (%d max) from %s during message collect",
57443730Speter						  MaxHeadersLength,
57590792Sgshapiro						  CURHOSTNAME);
57643148Speter					errno = 0;
57743148Speter					e->e_flags |= EF_CLRQUEUE;
57843148Speter					e->e_status = "5.6.0";
57964562Sgshapiro					usrerrenh(e->e_status,
58064562Sgshapiro						  "552 Headers too large (%d max)",
58164562Sgshapiro						  MaxHeadersLength);
582157001Sgshapiro  discard:
58343148Speter					mstate = MS_DISCARD;
58443148Speter				}
58543148Speter			}
58638032Speter			if (istate == IS_BOL)
58738032Speter				break;
58838032Speter		}
58938032Speter		*bp = '\0';
59038032Speter
59138032Speternextstate:
59238032Speter		if (tTd(30, 35))
593168515Sgshapiro			sm_dprintf("nextstate, istate=%d, mstate=%d, line=\"%s\"\n",
59438032Speter				istate, mstate, buf);
59538032Speter		switch (mstate)
59638032Speter		{
59738032Speter		  case MS_UFROM:
59838032Speter			mstate = MS_HEADER;
59938032Speter#ifndef NOTUNIX
60038032Speter			if (strncmp(buf, "From ", 5) == 0)
60138032Speter			{
60238032Speter				bp = buf;
60338032Speter				eatfrom(buf, e);
60438032Speter				continue;
60538032Speter			}
60664562Sgshapiro#endif /* ! NOTUNIX */
60764562Sgshapiro			/* FALLTHROUGH */
60838032Speter
60938032Speter		  case MS_HEADER:
61038032Speter			if (!isheader(buf))
61138032Speter			{
61238032Speter				mstate = MS_BODY;
61338032Speter				goto nextstate;
61438032Speter			}
61538032Speter
61638032Speter			/* check for possible continuation line */
61738032Speter			do
61838032Speter			{
61990792Sgshapiro				sm_io_clearerr(fp);
62038032Speter				errno = 0;
62190792Sgshapiro				c = sm_io_getc(fp, SM_TIME_DEFAULT);
622157001Sgshapiro
623157001Sgshapiro				/* timeout? */
624157001Sgshapiro				if (c == SM_IO_EOF && errno == EAGAIN
625157001Sgshapiro				    && smtpmode)
626157001Sgshapiro				{
627157001Sgshapiro					/*
628157001Sgshapiro					**  Override e_message in
629157001Sgshapiro					**  usrerr() as this is the
630157001Sgshapiro					**  reason for failure that
631157001Sgshapiro					**  should be logged for
632157001Sgshapiro					**  undelivered recipients.
633157001Sgshapiro					*/
634157001Sgshapiro
635157001Sgshapiro					e->e_message = NULL;
636157001Sgshapiro					errno = 0;
637157001Sgshapiro					inputerr = true;
638157001Sgshapiro					goto readabort;
639157001Sgshapiro				}
64090792Sgshapiro			} while (c == SM_IO_EOF && errno == EINTR);
64190792Sgshapiro			if (c != SM_IO_EOF)
64290792Sgshapiro				(void) sm_io_ungetc(fp, SM_TIME_DEFAULT, c);
64338032Speter			if (c == ' ' || c == '\t')
64438032Speter			{
64538032Speter				/* yep -- defer this */
64638032Speter				continue;
64738032Speter			}
64838032Speter
649157001Sgshapiro			SM_ASSERT(bp > buf);
650157001Sgshapiro
651157001Sgshapiro			/* guaranteed by isheader(buf) */
652157001Sgshapiro			SM_ASSERT(*(bp - 1) != '\n' || bp > buf + 1);
653157001Sgshapiro
65438032Speter			/* trim off trailing CRLF or NL */
65538032Speter			if (*--bp != '\n' || *--bp != '\r')
65638032Speter				bp++;
65738032Speter			*bp = '\0';
65843148Speter
65964562Sgshapiro			if (bitset(H_EOH, chompheader(buf,
66064562Sgshapiro						      CHHDR_CHECK | CHHDR_USER,
66164562Sgshapiro						      hdrp, e)))
66238032Speter			{
66338032Speter				mstate = MS_BODY;
66438032Speter				goto nextstate;
66538032Speter			}
66664562Sgshapiro			numhdrs++;
66738032Speter			break;
66838032Speter
66938032Speter		  case MS_BODY:
67038032Speter			if (tTd(30, 1))
67190792Sgshapiro				sm_dprintf("EOH\n");
67264562Sgshapiro
67338032Speter			if (headeronly)
67438032Speter				goto readerr;
67564562Sgshapiro
67690792Sgshapiro			df = collect_eoh(e, numhdrs, hdrslen);
67790792Sgshapiro			if (df == NULL)
67890792Sgshapiro				e->e_flags |= EF_TOOBIG;
67964562Sgshapiro
68038032Speter			bp = buf;
68138032Speter
68238032Speter			/* toss blank line */
683363466Sgshapiro			if ((bp[0] == '\r' && bp[1] == '\n') ||
684363466Sgshapiro			    (bp[0] == '\n'))
68538032Speter			{
68638032Speter				break;
68738032Speter			}
68838032Speter
68938032Speter			/* if not a blank separator, write it out */
69066494Sgshapiro			if (!bitset(EF_TOOBIG, e->e_flags))
69138032Speter			{
69238032Speter				while (*bp != '\0')
69390792Sgshapiro					(void) sm_io_putc(df, SM_TIME_DEFAULT,
69490792Sgshapiro							  *bp++);
69538032Speter			}
69638032Speter			break;
69738032Speter		}
69838032Speter		bp = buf;
69938032Speter	}
70038032Speter
70138032Speterreaderr:
70290792Sgshapiro	if ((sm_io_eof(fp) && smtpmode) || sm_io_error(fp))
70338032Speter	{
70490792Sgshapiro		const char *errmsg;
70538032Speter
70690792Sgshapiro		if (sm_io_eof(fp))
70790792Sgshapiro			errmsg = "unexpected close";
70890792Sgshapiro		else
70990792Sgshapiro			errmsg = sm_errstring(errno);
71038032Speter		if (tTd(30, 1))
71190792Sgshapiro			sm_dprintf("collect: premature EOM: %s\n", errmsg);
71290792Sgshapiro		if (LogLevel > 1)
71338032Speter			sm_syslog(LOG_WARNING, e->e_id,
71438032Speter				"collect: premature EOM: %s", errmsg);
71590792Sgshapiro		inputerr = true;
71638032Speter	}
71738032Speter
71838032Speter	if (headeronly)
719285229Sgshapiro		goto end;
72038032Speter
72190792Sgshapiro	if (mstate != MS_BODY)
72290792Sgshapiro	{
72390792Sgshapiro		/* no body or discard, so we never opened the data file */
72490792Sgshapiro		SM_ASSERT(df == NULL);
72590792Sgshapiro		df = collect_eoh(e, numhdrs, hdrslen);
72690792Sgshapiro	}
72790792Sgshapiro
72864562Sgshapiro	if (df == NULL)
72938032Speter	{
73064562Sgshapiro		/* skip next few clauses */
73164562Sgshapiro		/* EMPTY */
73264562Sgshapiro	}
73390792Sgshapiro	else if (sm_io_flush(df, SM_TIME_DEFAULT) != 0 || sm_io_error(df))
73464562Sgshapiro	{
73590792Sgshapiro		dferror(df, "sm_io_flush||sm_io_error", e);
73690792Sgshapiro		flush_errors(true);
73790792Sgshapiro		finis(true, true, ExitStat);
73864562Sgshapiro		/* NOTREACHED */
73938032Speter	}
740132943Sgshapiro	else if (SuperSafe == SAFE_NO ||
741132943Sgshapiro		 SuperSafe == SAFE_INTERACTIVE ||
742132943Sgshapiro		 (SuperSafe == SAFE_REALLY_POSTMILTER && smtpmode))
74364562Sgshapiro	{
74464562Sgshapiro		/* skip next few clauses */
74564562Sgshapiro		/* EMPTY */
746147078Sgshapiro		/* Note: updfs() is not called in this case! */
74764562Sgshapiro	}
74890792Sgshapiro	else if (sm_io_setinfo(df, SM_BF_COMMIT, NULL) < 0 && errno != EINVAL)
74964562Sgshapiro	{
75064562Sgshapiro		int save_errno = errno;
75138032Speter
75264562Sgshapiro		if (save_errno == EEXIST)
75364562Sgshapiro		{
75464562Sgshapiro			char *dfile;
75564562Sgshapiro			struct stat st;
75690792Sgshapiro			int dfd;
75764562Sgshapiro
75890792Sgshapiro			dfile = queuename(e, DATAFL_LETTER);
75964562Sgshapiro			if (stat(dfile, &st) < 0)
76064562Sgshapiro				st.st_size = -1;
76164562Sgshapiro			errno = EEXIST;
762132943Sgshapiro			syserr("@collect: bfcommit(%s): already on disk, size=%ld",
76366494Sgshapiro			       dfile, (long) st.st_size);
76490792Sgshapiro			dfd = sm_io_getinfo(df, SM_IO_WHAT_FD, NULL);
76564562Sgshapiro			if (dfd >= 0)
76690792Sgshapiro				dumpfd(dfd, true, true);
76764562Sgshapiro		}
76864562Sgshapiro		errno = save_errno;
76964562Sgshapiro		dferror(df, "bfcommit", e);
77090792Sgshapiro		flush_errors(true);
77190792Sgshapiro		finis(save_errno != EEXIST, true, ExitStat);
77264562Sgshapiro	}
773132943Sgshapiro	else if ((afd = sm_io_getinfo(df, SM_IO_WHAT_FD, NULL)) < 0)
77473188Sgshapiro	{
775132943Sgshapiro		dferror(df, "sm_io_getinfo", e);
776132943Sgshapiro		flush_errors(true);
777132943Sgshapiro		finis(true, true, ExitStat);
778132943Sgshapiro		/* NOTREACHED */
779132943Sgshapiro	}
780132943Sgshapiro	else if (fsync(afd) < 0)
781132943Sgshapiro	{
78290792Sgshapiro		dferror(df, "fsync", e);
78390792Sgshapiro		flush_errors(true);
78490792Sgshapiro		finis(true, true, ExitStat);
78573188Sgshapiro		/* NOTREACHED */
78673188Sgshapiro	}
78790792Sgshapiro	else if (sm_io_close(df, SM_TIME_DEFAULT) < 0)
78864562Sgshapiro	{
78990792Sgshapiro		dferror(df, "sm_io_close", e);
79090792Sgshapiro		flush_errors(true);
79190792Sgshapiro		finis(true, true, ExitStat);
79264562Sgshapiro		/* NOTREACHED */
79364562Sgshapiro	}
79464562Sgshapiro	else
79564562Sgshapiro	{
79664562Sgshapiro		/* everything is happily flushed to disk */
79764562Sgshapiro		df = NULL;
79890792Sgshapiro
79990792Sgshapiro		/* remove from available space in filesystem */
800147078Sgshapiro		updfs(e, 0, 1, "collect");
80164562Sgshapiro	}
80264562Sgshapiro
80338032Speter	/* An EOF when running SMTP is an error */
804157001Sgshapiro  readabort:
80538032Speter	if (inputerr && (OpMode == MD_SMTP || OpMode == MD_DAEMON))
80638032Speter	{
80738032Speter		char *host;
80838032Speter		char *problem;
809102528Sgshapiro		ADDRESS *q;
81038032Speter
81138032Speter		host = RealHostName;
81238032Speter		if (host == NULL)
81338032Speter			host = "localhost";
81438032Speter
81590792Sgshapiro		if (sm_io_eof(fp))
81638032Speter			problem = "unexpected close";
81790792Sgshapiro		else if (sm_io_error(fp))
81838032Speter			problem = "I/O error";
81938032Speter		else
82038032Speter			problem = "read timeout";
82190792Sgshapiro		if (LogLevel > 0 && sm_io_eof(fp))
82238032Speter			sm_syslog(LOG_NOTICE, e->e_id,
82390792Sgshapiro				"collect: %s on connection from %.100s, sender=%s",
82490792Sgshapiro				problem, host,
82590792Sgshapiro				shortenstring(e->e_from.q_paddr, MAXSHORTSTR));
82690792Sgshapiro		if (sm_io_eof(fp))
827157001Sgshapiro			usrerr("421 4.4.1 collect: %s on connection from %s, from=%s",
82838032Speter				problem, host,
82938032Speter				shortenstring(e->e_from.q_paddr, MAXSHORTSTR));
83038032Speter		else
831157001Sgshapiro			syserr("421 4.4.1 collect: %s on connection from %s, from=%s",
83238032Speter				problem, host,
83338032Speter				shortenstring(e->e_from.q_paddr, MAXSHORTSTR));
834157001Sgshapiro		flush_errors(true);
83538032Speter
83638032Speter		/* don't return an error indication */
83738032Speter		e->e_to = NULL;
83838032Speter		e->e_flags &= ~EF_FATALERRS;
83938032Speter		e->e_flags |= EF_CLRQUEUE;
84038032Speter
841102528Sgshapiro		/* Don't send any message notification to sender */
842102528Sgshapiro		for (q = e->e_sendqueue; q != NULL; q = q->q_next)
843102528Sgshapiro		{
844102528Sgshapiro			if (QS_IS_DEAD(q->q_state))
845102528Sgshapiro				continue;
846102528Sgshapiro			q->q_state = QS_FATALERR;
847102528Sgshapiro		}
848102528Sgshapiro
849159609Sgshapiro		(void) sm_io_close(df, SM_TIME_DEFAULT);
850159609Sgshapiro		df = NULL;
85190792Sgshapiro		finis(true, true, ExitStat);
85264562Sgshapiro		/* NOTREACHED */
85338032Speter	}
85438032Speter
85590792Sgshapiro	/* Log collection information. */
856203004Sgshapiro	if (tTd(92, 2))
857203004Sgshapiro		sm_dprintf("collect: e_id=%s, EF_LOGSENDER=%d, LogLevel=%d\n",
858203004Sgshapiro			e->e_id, bitset(EF_LOGSENDER, e->e_flags), LogLevel);
85990792Sgshapiro	if (bitset(EF_LOGSENDER, e->e_flags) && LogLevel > 4)
86038032Speter	{
86190792Sgshapiro		logsender(e, e->e_msgid);
86290792Sgshapiro		e->e_flags &= ~EF_LOGSENDER;
86338032Speter	}
86438032Speter
86538032Speter	/* check for message too large */
86666494Sgshapiro	if (bitset(EF_TOOBIG, e->e_flags))
86738032Speter	{
86838032Speter		e->e_flags |= EF_NO_BODY_RETN|EF_CLRQUEUE;
86990792Sgshapiro		if (!bitset(EF_FATALERRS, e->e_flags))
87090792Sgshapiro		{
87190792Sgshapiro			e->e_status = "5.2.3";
87290792Sgshapiro			usrerrenh(e->e_status,
87390792Sgshapiro				"552 Message exceeds maximum fixed size (%ld)",
87490792Sgshapiro				MaxMessageSize);
87590792Sgshapiro			if (LogLevel > 6)
87690792Sgshapiro				sm_syslog(LOG_NOTICE, e->e_id,
87790792Sgshapiro					"message size (%ld) exceeds maximum (%ld)",
878244833Sgshapiro					PRT_NONNEGL(e->e_msgsize),
879244833Sgshapiro					MaxMessageSize);
88090792Sgshapiro		}
88138032Speter	}
88238032Speter
88338032Speter	/* check for illegal 8-bit data */
88438032Speter	if (HasEightBits)
88538032Speter	{
88638032Speter		e->e_flags |= EF_HAS8BIT;
88738032Speter		if (!bitset(MM_PASS8BIT|MM_MIME8BIT, MimeMode) &&
88838032Speter		    !bitset(EF_IS_MIME, e->e_flags))
88938032Speter		{
89038032Speter			e->e_status = "5.6.1";
89164562Sgshapiro			usrerrenh(e->e_status, "554 Eight bit data not allowed");
89238032Speter		}
89338032Speter	}
89438032Speter	else
89538032Speter	{
89638032Speter		/* if it claimed to be 8 bits, well, it lied.... */
89738032Speter		if (e->e_bodytype != NULL &&
89890792Sgshapiro		    sm_strcasecmp(e->e_bodytype, "8BITMIME") == 0)
89938032Speter			e->e_bodytype = "7BIT";
90038032Speter	}
90138032Speter
902249729Sgshapiro#if _FFR_REJECT_NUL_BYTE
903249729Sgshapiro	if (hasNUL && RejectNUL)
904249729Sgshapiro	{
905249729Sgshapiro		e->e_status = "5.6.1";
906249729Sgshapiro		usrerrenh(e->e_status, "554 NUL byte not allowed");
907249729Sgshapiro	}
908249729Sgshapiro#endif /* _FFR_REJECT_NUL_BYTE */
909249729Sgshapiro
91090792Sgshapiro	if (SuperSafe == SAFE_REALLY && !bitset(EF_FATALERRS, e->e_flags))
91138032Speter	{
91290792Sgshapiro		char *dfname = queuename(e, DATAFL_LETTER);
91390792Sgshapiro		if ((e->e_dfp = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, dfname,
914132943Sgshapiro					   SM_IO_RDONLY_B, NULL)) == NULL)
91564562Sgshapiro		{
91664562Sgshapiro			/* we haven't acked receipt yet, so just chuck this */
91790792Sgshapiro			syserr("@Cannot reopen %s", dfname);
91890792Sgshapiro			finis(true, true, ExitStat);
91964562Sgshapiro			/* NOTREACHED */
92064562Sgshapiro		}
92138032Speter	}
92264562Sgshapiro	else
92364562Sgshapiro		e->e_dfp = df;
92494334Sgshapiro
92594334Sgshapiro	/* collect statistics */
92694334Sgshapiro	if (OpMode != MD_VERIFY)
927120256Sgshapiro	{
928120256Sgshapiro		/*
929120256Sgshapiro		**  Recalculate e_msgpriority, it is done at in eatheader()
930120256Sgshapiro		**  which is called (in 8.12) after the header is collected,
931120256Sgshapiro		**  hence e_msgsize is (most likely) incorrect.
932120256Sgshapiro		*/
933120256Sgshapiro
934120256Sgshapiro		e->e_msgpriority = e->e_msgsize
935120256Sgshapiro				 - e->e_class * WkClassFact
936120256Sgshapiro				 + e->e_nrcpts * WkRecipFact;
93794334Sgshapiro		markstats(e, (ADDRESS *) NULL, STATS_NORMAL);
938120256Sgshapiro	}
939285229Sgshapiro
940285229Sgshapiro  end:
941285229Sgshapiro	(void) set_tls_rd_tmo(old_rd_tmo);
94238032Speter}
94338032Speter
94490792Sgshapiro/*
94564562Sgshapiro**  DFERROR -- signal error on writing the data file.
94638032Speter**
94790792Sgshapiro**	Called by collect().  Collect() always terminates the process
94890792Sgshapiro**	immediately after calling dferror(), which means that the SMTP
94990792Sgshapiro**	session will be terminated, which means that any error message
95090792Sgshapiro**	issued by dferror must be a 421 error, as per RFC 821.
95190792Sgshapiro**
95238032Speter**	Parameters:
95364562Sgshapiro**		df -- the file pointer for the data file.
95464562Sgshapiro**		msg -- detailed message.
95538032Speter**		e -- the current envelope.
95638032Speter**
95738032Speter**	Returns:
95838032Speter**		none.
95938032Speter**
96038032Speter**	Side Effects:
96138032Speter**		Gives an error message.
96238032Speter**		Arranges for following output to go elsewhere.
96338032Speter*/
96438032Speter
965132943Sgshapirovoid
96664562Sgshapirodferror(df, msg, e)
96790792Sgshapiro	SM_FILE_T *volatile df;
96864562Sgshapiro	char *msg;
96938032Speter	register ENVELOPE *e;
97038032Speter{
97164562Sgshapiro	char *dfname;
97264562Sgshapiro
97390792Sgshapiro	dfname = queuename(e, DATAFL_LETTER);
97438032Speter	setstat(EX_IOERR);
97538032Speter	if (errno == ENOSPC)
97638032Speter	{
97738032Speter#if STAT64 > 0
97838032Speter		struct stat64 st;
979363466Sgshapiro#else
98038032Speter		struct stat st;
981363466Sgshapiro#endif
98238032Speter		long avail;
98338032Speter		long bsize;
98438032Speter
98538032Speter		e->e_flags |= EF_NO_BODY_RETN;
98638032Speter
98738032Speter		if (
98838032Speter#if STAT64 > 0
98990792Sgshapiro		    fstat64(sm_io_getinfo(df, SM_IO_WHAT_FD, NULL), &st)
990363466Sgshapiro#else
99190792Sgshapiro		    fstat(sm_io_getinfo(df, SM_IO_WHAT_FD, NULL), &st)
992363466Sgshapiro#endif
99338032Speter		    < 0)
99438032Speter		  st.st_size = 0;
99590792Sgshapiro		(void) sm_io_reopen(SmFtStdio, SM_TIME_DEFAULT, dfname,
996132943Sgshapiro				    SM_IO_WRONLY_B, NULL, df);
99738032Speter		if (st.st_size <= 0)
99890792Sgshapiro			(void) sm_io_fprintf(df, SM_TIME_DEFAULT,
99990792Sgshapiro				"\n*** Mail could not be accepted");
100038032Speter		else
100190792Sgshapiro			(void) sm_io_fprintf(df, SM_TIME_DEFAULT,
100290792Sgshapiro				"\n*** Mail of at least %llu bytes could not be accepted\n",
100390792Sgshapiro				(ULONGLONG_T) st.st_size);
100490792Sgshapiro		(void) sm_io_fprintf(df, SM_TIME_DEFAULT,
100590792Sgshapiro			"*** at %s due to lack of disk space for temp file.\n",
100638032Speter			MyHostName);
100790792Sgshapiro		avail = freediskspace(qid_printqueue(e->e_qgrp, e->e_qdir),
100890792Sgshapiro				      &bsize);
100938032Speter		if (avail > 0)
101038032Speter		{
101138032Speter			if (bsize > 1024)
101238032Speter				avail *= bsize / 1024;
101338032Speter			else if (bsize < 1024)
101438032Speter				avail /= 1024 / bsize;
101590792Sgshapiro			(void) sm_io_fprintf(df, SM_TIME_DEFAULT,
101690792Sgshapiro				"*** Currently, %ld kilobytes are available for mail temp files.\n",
101738032Speter				avail);
101838032Speter		}
101990792Sgshapiro#if 0
102090792Sgshapiro		/* Wrong response code; should be 421. */
102138032Speter		e->e_status = "4.3.1";
102264562Sgshapiro		usrerrenh(e->e_status, "452 Out of disk space for temp file");
102390792Sgshapiro#else /* 0 */
102490792Sgshapiro		syserr("421 4.3.1 Out of disk space for temp file");
102590792Sgshapiro#endif /* 0 */
102638032Speter	}
102738032Speter	else
1028285229Sgshapiro		syserr("421 4.3.0 collect: Cannot write %s (%s, uid=%ld, gid=%ld)",
1029285229Sgshapiro			dfname, msg, (long) geteuid(), (long) getegid());
103090792Sgshapiro	if (sm_io_reopen(SmFtStdio, SM_TIME_DEFAULT, SM_PATH_DEVNULL,
103190792Sgshapiro			 SM_IO_WRONLY, NULL, df) == NULL)
103238032Speter		sm_syslog(LOG_ERR, e->e_id,
103390792Sgshapiro			  "dferror: sm_io_reopen(\"/dev/null\") failed: %s",
103490792Sgshapiro			  sm_errstring(errno));
103538032Speter}
103690792Sgshapiro/*
103738032Speter**  EATFROM -- chew up a UNIX style from line and process
103838032Speter**
103938032Speter**	This does indeed make some assumptions about the format
104038032Speter**	of UNIX messages.
104138032Speter**
104238032Speter**	Parameters:
104338032Speter**		fm -- the from line.
1044120256Sgshapiro**		e -- envelope
104538032Speter**
104638032Speter**	Returns:
104738032Speter**		none.
104838032Speter**
104938032Speter**	Side Effects:
105038032Speter**		extracts what information it can from the header,
105138032Speter**		such as the date.
105238032Speter*/
105338032Speter
105464562Sgshapiro#ifndef NOTUNIX
105538032Speter
105664562Sgshapirostatic char	*DowList[] =
105738032Speter{
105838032Speter	"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", NULL
105938032Speter};
106038032Speter
106164562Sgshapirostatic char	*MonthList[] =
106238032Speter{
106338032Speter	"Jan", "Feb", "Mar", "Apr", "May", "Jun",
106438032Speter	"Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
106538032Speter	NULL
106638032Speter};
106738032Speter
106864562Sgshapirostatic void
106938032Spetereatfrom(fm, e)
107038032Speter	char *volatile fm;
107138032Speter	register ENVELOPE *e;
107238032Speter{
107338032Speter	register char *p;
107438032Speter	register char **dt;
107538032Speter
107638032Speter	if (tTd(30, 2))
107790792Sgshapiro		sm_dprintf("eatfrom(%s)\n", fm);
107838032Speter
107938032Speter	/* find the date part */
108038032Speter	p = fm;
108138032Speter	while (*p != '\0')
108238032Speter	{
108338032Speter		/* skip a word */
108438032Speter		while (*p != '\0' && *p != ' ')
108538032Speter			p++;
108638032Speter		while (*p == ' ')
108738032Speter			p++;
108871345Sgshapiro		if (strlen(p) < 17)
108971345Sgshapiro		{
109071345Sgshapiro			/* no room for the date */
109171345Sgshapiro			return;
109271345Sgshapiro		}
109338032Speter		if (!(isascii(*p) && isupper(*p)) ||
109438032Speter		    p[3] != ' ' || p[13] != ':' || p[16] != ':')
109538032Speter			continue;
109638032Speter
109738032Speter		/* we have a possible date */
109838032Speter		for (dt = DowList; *dt != NULL; dt++)
109938032Speter			if (strncmp(*dt, p, 3) == 0)
110038032Speter				break;
110138032Speter		if (*dt == NULL)
110238032Speter			continue;
110338032Speter
110438032Speter		for (dt = MonthList; *dt != NULL; dt++)
110571345Sgshapiro		{
110638032Speter			if (strncmp(*dt, &p[4], 3) == 0)
110738032Speter				break;
110871345Sgshapiro		}
110938032Speter		if (*dt != NULL)
111038032Speter			break;
111138032Speter	}
111238032Speter
111338032Speter	if (*p != '\0')
111438032Speter	{
111590792Sgshapiro		char *q, buf[25];
111638032Speter
111738032Speter		/* we have found a date */
111890792Sgshapiro		(void) sm_strlcpy(buf, p, sizeof(buf));
111990792Sgshapiro		q = arpadate(buf);
112090792Sgshapiro		macdefine(&e->e_macro, A_TEMP, 'a', q);
112138032Speter	}
112238032Speter}
112364562Sgshapiro#endif /* ! NOTUNIX */
1124