collect.c revision 38032
138032Speter/*
238032Speter * Copyright (c) 1998 Sendmail, Inc.  All rights reserved.
338032Speter * Copyright (c) 1983, 1995-1997 Eric P. Allman.  All rights reserved.
438032Speter * Copyright (c) 1988, 1993
538032Speter *	The Regents of the University of California.  All rights reserved.
638032Speter *
738032Speter * By using this file, you agree to the terms and conditions set
838032Speter * forth in the LICENSE file which can be found at the top level of
938032Speter * the sendmail distribution.
1038032Speter *
1138032Speter */
1238032Speter
1338032Speter#ifndef lint
1438032Speterstatic char sccsid[] = "@(#)collect.c	8.89 (Berkeley) 6/4/98";
1538032Speter#endif /* not lint */
1638032Speter
1738032Speter# include <errno.h>
1838032Speter# include "sendmail.h"
1938032Speter
2038032Speter/*
2138032Speter**  COLLECT -- read & parse message header & make temp file.
2238032Speter**
2338032Speter**	Creates a temporary file name and copies the standard
2438032Speter**	input to that file.  Leading UNIX-style "From" lines are
2538032Speter**	stripped off (after important information is extracted).
2638032Speter**
2738032Speter**	Parameters:
2838032Speter**		fp -- file to read.
2938032Speter**		smtpmode -- if set, we are running SMTP: give an RFC821
3038032Speter**			style message to say we are ready to collect
3138032Speter**			input, and never ignore a single dot to mean
3238032Speter**			end of message.
3338032Speter**		hdrp -- the location to stash the header.
3438032Speter**		e -- the current envelope.
3538032Speter**
3638032Speter**	Returns:
3738032Speter**		none.
3838032Speter**
3938032Speter**	Side Effects:
4038032Speter**		Temp file is created and filled.
4138032Speter**		The from person may be set.
4238032Speter*/
4338032Speter
4438032Speterstatic jmp_buf	CtxCollectTimeout;
4538032Speterstatic void	collecttimeout __P((time_t));
4638032Speterstatic bool	CollectProgress;
4738032Speterstatic EVENT	*CollectTimeout;
4838032Speter
4938032Speter/* values for input state machine */
5038032Speter#define IS_NORM		0	/* middle of line */
5138032Speter#define IS_BOL		1	/* beginning of line */
5238032Speter#define IS_DOT		2	/* read a dot at beginning of line */
5338032Speter#define IS_DOTCR	3	/* read ".\r" at beginning of line */
5438032Speter#define IS_CR		4	/* read a carriage return */
5538032Speter
5638032Speter/* values for message state machine */
5738032Speter#define MS_UFROM	0	/* reading Unix from line */
5838032Speter#define MS_HEADER	1	/* reading message header */
5938032Speter#define MS_BODY		2	/* reading message body */
6038032Speter
6138032Spetervoid
6238032Spetercollect(fp, smtpmode, hdrp, e)
6338032Speter	FILE *fp;
6438032Speter	bool smtpmode;
6538032Speter	HDR **hdrp;
6638032Speter	register ENVELOPE *e;
6738032Speter{
6838032Speter	register FILE *volatile tf;
6938032Speter	volatile bool ignrdot = smtpmode ? FALSE : IgnrDot;
7038032Speter	volatile time_t dbto = smtpmode ? TimeOuts.to_datablock : 0;
7138032Speter	register char *volatile bp;
7238032Speter	volatile int c = EOF;
7338032Speter	volatile bool inputerr = FALSE;
7438032Speter	bool headeronly;
7538032Speter	char *volatile buf;
7638032Speter	volatile int buflen;
7738032Speter	volatile int istate;
7838032Speter	volatile int mstate;
7938032Speter	u_char *volatile pbp;
8038032Speter	u_char peekbuf[8];
8138032Speter	char dfname[MAXQFNAME];
8238032Speter	char bufbuf[MAXLINE];
8338032Speter	extern bool isheader __P((char *));
8438032Speter	extern void eatheader __P((ENVELOPE *, bool));
8538032Speter	extern void tferror __P((FILE *volatile, ENVELOPE *));
8638032Speter
8738032Speter	headeronly = hdrp != NULL;
8838032Speter
8938032Speter	/*
9038032Speter	**  Create the temp file name and create the file.
9138032Speter	*/
9238032Speter
9338032Speter	if (!headeronly)
9438032Speter	{
9538032Speter		int tfd;
9638032Speter		struct stat stbuf;
9738032Speter
9838032Speter		strcpy(dfname, queuename(e, 'd'));
9938032Speter		tfd = dfopen(dfname, O_WRONLY|O_CREAT|O_TRUNC, FileMode, SFF_ANYFILE);
10038032Speter		if (tfd < 0 || (tf = fdopen(tfd, "w")) == NULL)
10138032Speter		{
10238032Speter			syserr("Cannot create %s", dfname);
10338032Speter			e->e_flags |= EF_NO_BODY_RETN;
10438032Speter			finis();
10538032Speter		}
10638032Speter		if (fstat(fileno(tf), &stbuf) < 0)
10738032Speter			e->e_dfino = -1;
10838032Speter		else
10938032Speter		{
11038032Speter			e->e_dfdev = stbuf.st_dev;
11138032Speter			e->e_dfino = stbuf.st_ino;
11238032Speter		}
11338032Speter		HasEightBits = FALSE;
11438032Speter		e->e_msgsize = 0;
11538032Speter		e->e_flags |= EF_HAS_DF;
11638032Speter	}
11738032Speter
11838032Speter	/*
11938032Speter	**  Tell ARPANET to go ahead.
12038032Speter	*/
12138032Speter
12238032Speter	if (smtpmode)
12338032Speter		message("354 Enter mail, end with \".\" on a line by itself");
12438032Speter
12538032Speter	if (tTd(30, 2))
12638032Speter		printf("collect\n");
12738032Speter
12838032Speter	/*
12938032Speter	**  Read the message.
13038032Speter	**
13138032Speter	**	This is done using two interleaved state machines.
13238032Speter	**	The input state machine is looking for things like
13338032Speter	**	hidden dots; the message state machine is handling
13438032Speter	**	the larger picture (e.g., header versus body).
13538032Speter	*/
13638032Speter
13738032Speter	buf = bp = bufbuf;
13838032Speter	buflen = sizeof bufbuf;
13938032Speter	pbp = peekbuf;
14038032Speter	istate = IS_BOL;
14138032Speter	mstate = SaveFrom ? MS_HEADER : MS_UFROM;
14238032Speter	CollectProgress = FALSE;
14338032Speter
14438032Speter	if (dbto != 0)
14538032Speter	{
14638032Speter		/* handle possible input timeout */
14738032Speter		if (setjmp(CtxCollectTimeout) != 0)
14838032Speter		{
14938032Speter			if (LogLevel > 2)
15038032Speter				sm_syslog(LOG_NOTICE, e->e_id,
15138032Speter				    "timeout waiting for input from %s during message collect",
15238032Speter				    CurHostName ? CurHostName : "<local machine>");
15338032Speter			errno = 0;
15438032Speter			usrerr("451 timeout waiting for input during message collect");
15538032Speter			goto readerr;
15638032Speter		}
15738032Speter		CollectTimeout = setevent(dbto, collecttimeout, dbto);
15838032Speter	}
15938032Speter
16038032Speter	for (;;)
16138032Speter	{
16238032Speter		extern int chompheader __P((char *, bool, HDR **, ENVELOPE *));
16338032Speter
16438032Speter		if (tTd(30, 35))
16538032Speter			printf("top, istate=%d, mstate=%d\n", istate, mstate);
16638032Speter		for (;;)
16738032Speter		{
16838032Speter			if (pbp > peekbuf)
16938032Speter				c = *--pbp;
17038032Speter			else
17138032Speter			{
17238032Speter				while (!feof(fp) && !ferror(fp))
17338032Speter				{
17438032Speter					errno = 0;
17538032Speter					c = getc(fp);
17638032Speter					if (errno != EINTR)
17738032Speter						break;
17838032Speter					clearerr(fp);
17938032Speter				}
18038032Speter				CollectProgress = TRUE;
18138032Speter				if (TrafficLogFile != NULL && !headeronly)
18238032Speter				{
18338032Speter					if (istate == IS_BOL)
18438032Speter						fprintf(TrafficLogFile, "%05d <<< ",
18538032Speter							(int) getpid());
18638032Speter					if (c == EOF)
18738032Speter						fprintf(TrafficLogFile, "[EOF]\n");
18838032Speter					else
18938032Speter						putc(c, TrafficLogFile);
19038032Speter				}
19138032Speter				if (c == EOF)
19238032Speter					goto readerr;
19338032Speter				if (SevenBitInput)
19438032Speter					c &= 0x7f;
19538032Speter				else
19638032Speter					HasEightBits |= bitset(0x80, c);
19738032Speter			}
19838032Speter			if (tTd(30, 94))
19938032Speter				printf("istate=%d, c=%c (0x%x)\n",
20038032Speter					istate, c, c);
20138032Speter			switch (istate)
20238032Speter			{
20338032Speter			  case IS_BOL:
20438032Speter				if (c == '.')
20538032Speter				{
20638032Speter					istate = IS_DOT;
20738032Speter					continue;
20838032Speter				}
20938032Speter				break;
21038032Speter
21138032Speter			  case IS_DOT:
21238032Speter				if (c == '\n' && !ignrdot &&
21338032Speter				    !bitset(EF_NL_NOT_EOL, e->e_flags))
21438032Speter					goto readerr;
21538032Speter				else if (c == '\r' &&
21638032Speter					 !bitset(EF_CRLF_NOT_EOL, e->e_flags))
21738032Speter				{
21838032Speter					istate = IS_DOTCR;
21938032Speter					continue;
22038032Speter				}
22138032Speter				else if (c != '.' ||
22238032Speter					 (OpMode != MD_SMTP &&
22338032Speter					  OpMode != MD_DAEMON &&
22438032Speter					  OpMode != MD_ARPAFTP))
22538032Speter				{
22638032Speter					*pbp++ = c;
22738032Speter					c = '.';
22838032Speter				}
22938032Speter				break;
23038032Speter
23138032Speter			  case IS_DOTCR:
23238032Speter				if (c == '\n' && !ignrdot)
23338032Speter					goto readerr;
23438032Speter				else
23538032Speter				{
23638032Speter					/* push back the ".\rx" */
23738032Speter					*pbp++ = c;
23838032Speter					*pbp++ = '\r';
23938032Speter					c = '.';
24038032Speter				}
24138032Speter				break;
24238032Speter
24338032Speter			  case IS_CR:
24438032Speter				if (c == '\n')
24538032Speter					istate = IS_BOL;
24638032Speter				else
24738032Speter				{
24838032Speter					ungetc(c, fp);
24938032Speter					c = '\r';
25038032Speter					istate = IS_NORM;
25138032Speter				}
25238032Speter				goto bufferchar;
25338032Speter			}
25438032Speter
25538032Speter			if (c == '\r' && !bitset(EF_CRLF_NOT_EOL, e->e_flags))
25638032Speter			{
25738032Speter				istate = IS_CR;
25838032Speter				continue;
25938032Speter			}
26038032Speter			else if (c == '\n' && !bitset(EF_NL_NOT_EOL, e->e_flags))
26138032Speter				istate = IS_BOL;
26238032Speter			else
26338032Speter				istate = IS_NORM;
26438032Speter
26538032Speterbufferchar:
26638032Speter			if (!headeronly)
26738032Speter				e->e_msgsize++;
26838032Speter			if (mstate == MS_BODY)
26938032Speter			{
27038032Speter				/* just put the character out */
27138032Speter				if (MaxMessageSize <= 0 ||
27238032Speter				    e->e_msgsize <= MaxMessageSize)
27338032Speter					putc(c, tf);
27438032Speter				continue;
27538032Speter			}
27638032Speter
27738032Speter			/* header -- buffer up */
27838032Speter			if (bp >= &buf[buflen - 2])
27938032Speter			{
28038032Speter				char *obuf;
28138032Speter
28238032Speter				if (mstate != MS_HEADER)
28338032Speter					break;
28438032Speter
28538032Speter				/* out of space for header */
28638032Speter				obuf = buf;
28738032Speter				if (buflen < MEMCHUNKSIZE)
28838032Speter					buflen *= 2;
28938032Speter				else
29038032Speter					buflen += MEMCHUNKSIZE;
29138032Speter				buf = xalloc(buflen);
29238032Speter				bcopy(obuf, buf, bp - obuf);
29338032Speter				bp = &buf[bp - obuf];
29438032Speter				if (obuf != bufbuf)
29538032Speter					free(obuf);
29638032Speter			}
29738032Speter			if (c >= 0200 && c <= 0237)
29838032Speter			{
29938032Speter#if 0	/* causes complaints -- figure out something for 8.9 */
30038032Speter				usrerr("Illegal character 0x%x in header", c);
30138032Speter#endif
30238032Speter			}
30338032Speter			else if (c != '\0')
30438032Speter				*bp++ = c;
30538032Speter			if (istate == IS_BOL)
30638032Speter				break;
30738032Speter		}
30838032Speter		*bp = '\0';
30938032Speter
31038032Speternextstate:
31138032Speter		if (tTd(30, 35))
31238032Speter			printf("nextstate, istate=%d, mstate=%d, line = \"%s\"\n",
31338032Speter				istate, mstate, buf);
31438032Speter		switch (mstate)
31538032Speter		{
31638032Speter		  case MS_UFROM:
31738032Speter			mstate = MS_HEADER;
31838032Speter#ifndef NOTUNIX
31938032Speter			if (strncmp(buf, "From ", 5) == 0)
32038032Speter			{
32138032Speter				extern void eatfrom __P((char *volatile, ENVELOPE *));
32238032Speter
32338032Speter				bp = buf;
32438032Speter				eatfrom(buf, e);
32538032Speter				continue;
32638032Speter			}
32738032Speter#endif
32838032Speter			/* fall through */
32938032Speter
33038032Speter		  case MS_HEADER:
33138032Speter			if (!isheader(buf))
33238032Speter			{
33338032Speter				mstate = MS_BODY;
33438032Speter				goto nextstate;
33538032Speter			}
33638032Speter
33738032Speter			/* check for possible continuation line */
33838032Speter			do
33938032Speter			{
34038032Speter				clearerr(fp);
34138032Speter				errno = 0;
34238032Speter				c = getc(fp);
34338032Speter			} while (errno == EINTR);
34438032Speter			if (c != EOF)
34538032Speter				ungetc(c, fp);
34638032Speter			if (c == ' ' || c == '\t')
34738032Speter			{
34838032Speter				/* yep -- defer this */
34938032Speter				continue;
35038032Speter			}
35138032Speter
35238032Speter			/* trim off trailing CRLF or NL */
35338032Speter			if (*--bp != '\n' || *--bp != '\r')
35438032Speter				bp++;
35538032Speter			*bp = '\0';
35638032Speter			if (bitset(H_EOH, chompheader(buf, FALSE, hdrp, e)))
35738032Speter			{
35838032Speter				mstate = MS_BODY;
35938032Speter				goto nextstate;
36038032Speter			}
36138032Speter			break;
36238032Speter
36338032Speter		  case MS_BODY:
36438032Speter			if (tTd(30, 1))
36538032Speter				printf("EOH\n");
36638032Speter			if (headeronly)
36738032Speter				goto readerr;
36838032Speter			bp = buf;
36938032Speter
37038032Speter			/* toss blank line */
37138032Speter			if ((!bitset(EF_CRLF_NOT_EOL, e->e_flags) &&
37238032Speter				bp[0] == '\r' && bp[1] == '\n') ||
37338032Speter			    (!bitset(EF_NL_NOT_EOL, e->e_flags) &&
37438032Speter				bp[0] == '\n'))
37538032Speter			{
37638032Speter				break;
37738032Speter			}
37838032Speter
37938032Speter			/* if not a blank separator, write it out */
38038032Speter			if (MaxMessageSize <= 0 ||
38138032Speter			    e->e_msgsize <= MaxMessageSize)
38238032Speter			{
38338032Speter				while (*bp != '\0')
38438032Speter					putc(*bp++, tf);
38538032Speter			}
38638032Speter			break;
38738032Speter		}
38838032Speter		bp = buf;
38938032Speter	}
39038032Speter
39138032Speterreaderr:
39238032Speter	if ((feof(fp) && smtpmode) || ferror(fp))
39338032Speter	{
39438032Speter		const char *errmsg = errstring(errno);
39538032Speter
39638032Speter		if (tTd(30, 1))
39738032Speter			printf("collect: premature EOM: %s\n", errmsg);
39838032Speter		if (LogLevel >= 2)
39938032Speter			sm_syslog(LOG_WARNING, e->e_id,
40038032Speter				"collect: premature EOM: %s", errmsg);
40138032Speter		inputerr = TRUE;
40238032Speter	}
40338032Speter
40438032Speter	/* reset global timer */
40538032Speter	clrevent(CollectTimeout);
40638032Speter
40738032Speter	if (headeronly)
40838032Speter		return;
40938032Speter
41038032Speter	if (tf != NULL &&
41138032Speter	    (fflush(tf) != 0 || ferror(tf) ||
41238032Speter	     (SuperSafe && fsync(fileno(tf)) < 0) ||
41338032Speter	     fclose(tf) < 0))
41438032Speter	{
41538032Speter		tferror(tf, e);
41638032Speter		flush_errors(TRUE);
41738032Speter		finis();
41838032Speter	}
41938032Speter
42038032Speter	/* An EOF when running SMTP is an error */
42138032Speter	if (inputerr && (OpMode == MD_SMTP || OpMode == MD_DAEMON))
42238032Speter	{
42338032Speter		char *host;
42438032Speter		char *problem;
42538032Speter
42638032Speter		host = RealHostName;
42738032Speter		if (host == NULL)
42838032Speter			host = "localhost";
42938032Speter
43038032Speter		if (feof(fp))
43138032Speter			problem = "unexpected close";
43238032Speter		else if (ferror(fp))
43338032Speter			problem = "I/O error";
43438032Speter		else
43538032Speter			problem = "read timeout";
43638032Speter		if (LogLevel > 0 && feof(fp))
43738032Speter			sm_syslog(LOG_NOTICE, e->e_id,
43838032Speter			    "collect: %s on connection from %.100s, sender=%s: %s",
43938032Speter			    problem, host,
44038032Speter			    shortenstring(e->e_from.q_paddr, MAXSHORTSTR),
44138032Speter			    errstring(errno));
44238032Speter		if (feof(fp))
44338032Speter			usrerr("451 collect: %s on connection from %s, from=%s",
44438032Speter				problem, host,
44538032Speter				shortenstring(e->e_from.q_paddr, MAXSHORTSTR));
44638032Speter		else
44738032Speter			syserr("451 collect: %s on connection from %s, from=%s",
44838032Speter				problem, host,
44938032Speter				shortenstring(e->e_from.q_paddr, MAXSHORTSTR));
45038032Speter
45138032Speter		/* don't return an error indication */
45238032Speter		e->e_to = NULL;
45338032Speter		e->e_flags &= ~EF_FATALERRS;
45438032Speter		e->e_flags |= EF_CLRQUEUE;
45538032Speter
45638032Speter		/* and don't try to deliver the partial message either */
45738032Speter		if (InChild)
45838032Speter			ExitStat = EX_QUIT;
45938032Speter		finis();
46038032Speter	}
46138032Speter
46238032Speter	/*
46338032Speter	**  Find out some information from the headers.
46438032Speter	**	Examples are who is the from person & the date.
46538032Speter	*/
46638032Speter
46738032Speter	eatheader(e, TRUE);
46838032Speter
46938032Speter	if (GrabTo && e->e_sendqueue == NULL)
47038032Speter		usrerr("No recipient addresses found in header");
47138032Speter
47238032Speter	/* collect statistics */
47338032Speter	if (OpMode != MD_VERIFY)
47438032Speter		markstats(e, (ADDRESS *) NULL, FALSE);
47538032Speter
47638032Speter#if _FFR_DSN_RRT_OPTION
47738032Speter	/*
47838032Speter	**  If we have a Return-Receipt-To:, turn it into a DSN.
47938032Speter	*/
48038032Speter
48138032Speter	if (RrtImpliesDsn && hvalue("return-receipt-to", e->e_header) != NULL)
48238032Speter	{
48338032Speter		ADDRESS *q;
48438032Speter
48538032Speter		for (q = e->e_sendqueue; q != NULL; q = q->q_next)
48638032Speter			if (!bitset(QHASNOTIFY, q->q_flags))
48738032Speter				q->q_flags |= QHASNOTIFY|QPINGONSUCCESS;
48838032Speter	}
48938032Speter#endif
49038032Speter
49138032Speter	/*
49238032Speter	**  Add an Apparently-To: line if we have no recipient lines.
49338032Speter	*/
49438032Speter
49538032Speter	if (hvalue("to", e->e_header) != NULL ||
49638032Speter	    hvalue("cc", e->e_header) != NULL ||
49738032Speter	    hvalue("apparently-to", e->e_header) != NULL)
49838032Speter	{
49938032Speter		/* have a valid recipient header -- delete Bcc: headers */
50038032Speter		e->e_flags |= EF_DELETE_BCC;
50138032Speter	}
50238032Speter	else if (hvalue("bcc", e->e_header) == NULL)
50338032Speter	{
50438032Speter		/* no valid recipient headers */
50538032Speter		register ADDRESS *q;
50638032Speter		char *hdr = NULL;
50738032Speter		extern void addheader __P((char *, char *, HDR **));
50838032Speter
50938032Speter		/* create an Apparently-To: field */
51038032Speter		/*    that or reject the message.... */
51138032Speter		switch (NoRecipientAction)
51238032Speter		{
51338032Speter		  case NRA_ADD_APPARENTLY_TO:
51438032Speter			hdr = "Apparently-To";
51538032Speter			break;
51638032Speter
51738032Speter		  case NRA_ADD_TO:
51838032Speter			hdr = "To";
51938032Speter			break;
52038032Speter
52138032Speter		  case NRA_ADD_BCC:
52238032Speter			addheader("Bcc", " ", &e->e_header);
52338032Speter			break;
52438032Speter
52538032Speter		  case NRA_ADD_TO_UNDISCLOSED:
52638032Speter			addheader("To", "undisclosed-recipients:;", &e->e_header);
52738032Speter			break;
52838032Speter		}
52938032Speter
53038032Speter		if (hdr != NULL)
53138032Speter		{
53238032Speter			for (q = e->e_sendqueue; q != NULL; q = q->q_next)
53338032Speter			{
53438032Speter				if (q->q_alias != NULL)
53538032Speter					continue;
53638032Speter				if (tTd(30, 3))
53738032Speter					printf("Adding %s: %s\n",
53838032Speter						hdr, q->q_paddr);
53938032Speter				addheader(hdr, q->q_paddr, &e->e_header);
54038032Speter			}
54138032Speter		}
54238032Speter	}
54338032Speter
54438032Speter	/* check for message too large */
54538032Speter	if (MaxMessageSize > 0 && e->e_msgsize > MaxMessageSize)
54638032Speter	{
54738032Speter		e->e_flags |= EF_NO_BODY_RETN|EF_CLRQUEUE;
54838032Speter		e->e_status = "5.2.3";
54938032Speter		usrerr("552 Message exceeds maximum fixed size (%ld)",
55038032Speter			MaxMessageSize);
55138032Speter		if (LogLevel > 6)
55238032Speter			sm_syslog(LOG_NOTICE, e->e_id,
55338032Speter				"message size (%ld) exceeds maximum (%ld)",
55438032Speter				e->e_msgsize, MaxMessageSize);
55538032Speter	}
55638032Speter
55738032Speter	/* check for illegal 8-bit data */
55838032Speter	if (HasEightBits)
55938032Speter	{
56038032Speter		e->e_flags |= EF_HAS8BIT;
56138032Speter		if (!bitset(MM_PASS8BIT|MM_MIME8BIT, MimeMode) &&
56238032Speter		    !bitset(EF_IS_MIME, e->e_flags))
56338032Speter		{
56438032Speter			e->e_status = "5.6.1";
56538032Speter			usrerr("554 Eight bit data not allowed");
56638032Speter		}
56738032Speter	}
56838032Speter	else
56938032Speter	{
57038032Speter		/* if it claimed to be 8 bits, well, it lied.... */
57138032Speter		if (e->e_bodytype != NULL &&
57238032Speter		    strcasecmp(e->e_bodytype, "8BITMIME") == 0)
57338032Speter			e->e_bodytype = "7BIT";
57438032Speter	}
57538032Speter
57638032Speter	if ((e->e_dfp = fopen(dfname, "r")) == NULL)
57738032Speter	{
57838032Speter		/* we haven't acked receipt yet, so just chuck this */
57938032Speter		syserr("Cannot reopen %s", dfname);
58038032Speter		finis();
58138032Speter	}
58238032Speter}
58338032Speter
58438032Speter
58538032Speterstatic void
58638032Spetercollecttimeout(timeout)
58738032Speter	time_t timeout;
58838032Speter{
58938032Speter	/* if no progress was made, die now */
59038032Speter	if (!CollectProgress)
59138032Speter		longjmp(CtxCollectTimeout, 1);
59238032Speter
59338032Speter	/* otherwise reset the timeout */
59438032Speter	CollectTimeout = setevent(timeout, collecttimeout, timeout);
59538032Speter	CollectProgress = FALSE;
59638032Speter}
59738032Speter/*
59838032Speter**  TFERROR -- signal error on writing the temporary file.
59938032Speter**
60038032Speter**	Parameters:
60138032Speter**		tf -- the file pointer for the temporary file.
60238032Speter**		e -- the current envelope.
60338032Speter**
60438032Speter**	Returns:
60538032Speter**		none.
60638032Speter**
60738032Speter**	Side Effects:
60838032Speter**		Gives an error message.
60938032Speter**		Arranges for following output to go elsewhere.
61038032Speter*/
61138032Speter
61238032Spetervoid
61338032Spetertferror(tf, e)
61438032Speter	FILE *volatile tf;
61538032Speter	register ENVELOPE *e;
61638032Speter{
61738032Speter	setstat(EX_IOERR);
61838032Speter	if (errno == ENOSPC)
61938032Speter	{
62038032Speter#if STAT64 > 0
62138032Speter		struct stat64 st;
62238032Speter#else
62338032Speter		struct stat st;
62438032Speter#endif
62538032Speter		long avail;
62638032Speter		long bsize;
62738032Speter		extern long freediskspace __P((char *, long *));
62838032Speter
62938032Speter		e->e_flags |= EF_NO_BODY_RETN;
63038032Speter
63138032Speter		if (
63238032Speter#if STAT64 > 0
63338032Speter		    fstat64(fileno(tf), &st)
63438032Speter#else
63538032Speter		    fstat(fileno(tf), &st)
63638032Speter#endif
63738032Speter		    < 0)
63838032Speter		  st.st_size = 0;
63938032Speter		(void) freopen(queuename(e, 'd'), "w", tf);
64038032Speter		if (st.st_size <= 0)
64138032Speter			fprintf(tf, "\n*** Mail could not be accepted");
64238032Speter		else if (sizeof st.st_size > sizeof (long))
64338032Speter			fprintf(tf, "\n*** Mail of at least %s bytes could not be accepted\n",
64438032Speter				quad_to_string(st.st_size));
64538032Speter		else
64638032Speter			fprintf(tf, "\n*** Mail of at least %lu bytes could not be accepted\n",
64738032Speter				(unsigned long) st.st_size);
64838032Speter		fprintf(tf, "*** at %s due to lack of disk space for temp file.\n",
64938032Speter			MyHostName);
65038032Speter		avail = freediskspace(QueueDir, &bsize);
65138032Speter		if (avail > 0)
65238032Speter		{
65338032Speter			if (bsize > 1024)
65438032Speter				avail *= bsize / 1024;
65538032Speter			else if (bsize < 1024)
65638032Speter				avail /= 1024 / bsize;
65738032Speter			fprintf(tf, "*** Currently, %ld kilobytes are available for mail temp files.\n",
65838032Speter				avail);
65938032Speter		}
66038032Speter		e->e_status = "4.3.1";
66138032Speter		usrerr("452 Out of disk space for temp file");
66238032Speter	}
66338032Speter	else
66438032Speter		syserr("collect: Cannot write tf%s", e->e_id);
66538032Speter	if (freopen("/dev/null", "w", tf) == NULL)
66638032Speter		sm_syslog(LOG_ERR, e->e_id,
66738032Speter			  "tferror: freopen(\"/dev/null\") failed: %s",
66838032Speter			  errstring(errno));
66938032Speter}
67038032Speter/*
67138032Speter**  EATFROM -- chew up a UNIX style from line and process
67238032Speter**
67338032Speter**	This does indeed make some assumptions about the format
67438032Speter**	of UNIX messages.
67538032Speter**
67638032Speter**	Parameters:
67738032Speter**		fm -- the from line.
67838032Speter**
67938032Speter**	Returns:
68038032Speter**		none.
68138032Speter**
68238032Speter**	Side Effects:
68338032Speter**		extracts what information it can from the header,
68438032Speter**		such as the date.
68538032Speter*/
68638032Speter
68738032Speter# ifndef NOTUNIX
68838032Speter
68938032Speterchar	*DowList[] =
69038032Speter{
69138032Speter	"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", NULL
69238032Speter};
69338032Speter
69438032Speterchar	*MonthList[] =
69538032Speter{
69638032Speter	"Jan", "Feb", "Mar", "Apr", "May", "Jun",
69738032Speter	"Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
69838032Speter	NULL
69938032Speter};
70038032Speter
70138032Spetervoid
70238032Spetereatfrom(fm, e)
70338032Speter	char *volatile fm;
70438032Speter	register ENVELOPE *e;
70538032Speter{
70638032Speter	register char *p;
70738032Speter	register char **dt;
70838032Speter
70938032Speter	if (tTd(30, 2))
71038032Speter		printf("eatfrom(%s)\n", fm);
71138032Speter
71238032Speter	/* find the date part */
71338032Speter	p = fm;
71438032Speter	while (*p != '\0')
71538032Speter	{
71638032Speter		/* skip a word */
71738032Speter		while (*p != '\0' && *p != ' ')
71838032Speter			p++;
71938032Speter		while (*p == ' ')
72038032Speter			p++;
72138032Speter		if (!(isascii(*p) && isupper(*p)) ||
72238032Speter		    p[3] != ' ' || p[13] != ':' || p[16] != ':')
72338032Speter			continue;
72438032Speter
72538032Speter		/* we have a possible date */
72638032Speter		for (dt = DowList; *dt != NULL; dt++)
72738032Speter			if (strncmp(*dt, p, 3) == 0)
72838032Speter				break;
72938032Speter		if (*dt == NULL)
73038032Speter			continue;
73138032Speter
73238032Speter		for (dt = MonthList; *dt != NULL; dt++)
73338032Speter			if (strncmp(*dt, &p[4], 3) == 0)
73438032Speter				break;
73538032Speter		if (*dt != NULL)
73638032Speter			break;
73738032Speter	}
73838032Speter
73938032Speter	if (*p != '\0')
74038032Speter	{
74138032Speter		char *q;
74238032Speter
74338032Speter		/* we have found a date */
74438032Speter		q = xalloc(25);
74538032Speter		(void) strncpy(q, p, 25);
74638032Speter		q[24] = '\0';
74738032Speter		q = arpadate(q);
74838032Speter		define('a', newstr(q), e);
74938032Speter	}
75038032Speter}
75138032Speter
75238032Speter# endif /* NOTUNIX */
753