11439Seric # include <errno.h>
23309Seric # include "sendmail.h"
31392Seric 
4*7852Seric SCCSID(@(#)collect.c	3.51		08/23/82);
51392Seric 
61392Seric /*
72969Seric **  COLLECT -- read & parse message header & make temp file.
81392Seric **
91392Seric **	Creates a temporary file name and copies the standard
101392Seric **	input to that file.  While it is doing it, it looks for
111392Seric **	"From:" and "Sender:" fields to use as the from-person
121392Seric **	(but only if the -a flag is specified).  It prefers to
131392Seric **	to use the "Sender:" field.
141392Seric **
151392Seric **	MIT seems to like to produce "Sent-By:" fields instead
161392Seric **	of "Sender:" fields.  We used to catch this, but it turns
171392Seric **	out that the "Sent-By:" field doesn't always correspond
181392Seric **	to someone real ("___057", for instance), as required by
191392Seric **	the protocol.  So we limp by.....
201392Seric **
211392Seric **	Parameters:
224710Seric **		sayok -- if set, give an ARPANET style message
234710Seric **			to say we are ready to collect input.
241392Seric **
251392Seric **	Returns:
264162Seric **		none.
271392Seric **
281392Seric **	Side Effects:
291392Seric **		Temp file is created and filled.
304162Seric **		The from person may be set.
311392Seric */
321392Seric 
334710Seric collect(sayok)
344710Seric 	bool sayok;
351392Seric {
361392Seric 	register FILE *tf;
37*7852Seric 	char buf[MAXFIELD+2];
381392Seric 	register char *p;
392900Seric 	extern char *hvalue();
405192Seric 	extern char *macvalue();
411392Seric 
421392Seric 	/*
431392Seric 	**  Create the temp file name and create the file.
441392Seric 	*/
451392Seric 
467809Seric 	CurEnv->e_df = newstr(queuename(CurEnv, 'd'));
477809Seric 	if ((tf = dfopen(CurEnv->e_df, "w")) == NULL)
481392Seric 	{
497809Seric 		syserr("Cannot create %s", CurEnv->e_df);
505366Seric 		NoReturn = TRUE;
515366Seric 		finis();
521392Seric 	}
537809Seric 	(void) chmod(CurEnv->e_df, 0600);
541392Seric 
554316Seric 	/*
564322Seric 	**  Tell ARPANET to go ahead.
574322Seric 	*/
584322Seric 
594710Seric 	if (sayok)
604710Seric 		message("354", "Enter mail, end with \".\" on a line by itself");
614322Seric 
624322Seric 	/*
634316Seric 	**  Try to read a UNIX-style From line
644316Seric 	*/
654316Seric 
665975Seric 	if (fgets(buf, sizeof buf, InChannel) == NULL)
674162Seric 		return;
684557Seric 	fixcrlf(buf, FALSE);
694321Seric # ifndef NOTUNIX
704322Seric 	if (!SaveFrom && strncmp(buf, "From ", 5) == 0)
712900Seric 	{
722900Seric 		eatfrom(buf);
735975Seric 		(void) fgets(buf, sizeof buf, InChannel);
744557Seric 		fixcrlf(buf, FALSE);
752900Seric 	}
764321Seric # endif NOTUNIX
772900Seric 
781392Seric 	/*
795975Seric 	**  Copy InChannel to temp file & do message editing.
801392Seric 	**	To keep certain mailers from getting confused,
811392Seric 	**	and to keep the output clean, lines that look
821392Seric 	**	like UNIX "From" lines are deleted in the header,
831392Seric 	**	and prepended with ">" in the body.
841392Seric 	*/
851392Seric 
86*7852Seric 	for (; !feof(InChannel); !feof(InChannel) && fgets(buf, MAXFIELD, InChannel) != NULL)
871392Seric 	{
884316Seric 		register char c;
894316Seric 		extern bool isheader();
904316Seric 
917681Seric 		/* if the line is too long, throw the rest away */
927681Seric 		if (index(buf, '\n') == NULL)
937681Seric 		{
947681Seric 			while ((c = getc(InChannel)) != '\n')
957681Seric 				continue;
967681Seric 			/* give an error? */
977681Seric 		}
987681Seric 
99*7852Seric 		fixcrlf(buf, TRUE);
1004557Seric 
1012900Seric 		/* see if the header is over */
1022900Seric 		if (!isheader(buf))
1032900Seric 			break;
1042900Seric 
1052900Seric 		/* get the rest of this field */
1065975Seric 		while ((c = getc(InChannel)) == ' ' || c == '\t')
1071392Seric 		{
1082900Seric 			p = &buf[strlen(buf)];
109*7852Seric 			*p++ = '\n';
1102900Seric 			*p++ = c;
111*7852Seric 			if (fgets(p, MAXFIELD - (p - buf), InChannel) == NULL)
1122900Seric 				break;
113*7852Seric 			fixcrlf(p, TRUE);
1141392Seric 		}
1155975Seric 		if (!feof(InChannel))
1165975Seric 			(void) ungetc(c, InChannel);
1171392Seric 
1186901Seric 		CurEnv->e_msgsize += strlen(buf);
1191392Seric 
1202900Seric 		/*
1212900Seric 		**  Snarf header away.
1222900Seric 		*/
1232900Seric 
1243391Seric 		if (bitset(H_EOH, chompheader(buf, FALSE)))
1253058Seric 			break;
1262900Seric 	}
1271392Seric 
1282900Seric # ifdef DEBUG
1297673Seric 	if (tTd(30, 1))
1302900Seric 		printf("EOH\n");
1312900Seric # endif DEBUG
1322900Seric 
1332900Seric 	/* throw away a blank line */
134*7852Seric 	if (buf[0] == '\0')
1354557Seric 	{
136*7852Seric 		(void) fgets(buf, MAXFIELD, InChannel);
137*7852Seric 		fixcrlf(buf, TRUE);
1384557Seric 	}
1392900Seric 
1402900Seric 	/*
1412900Seric 	**  Collect the body of the message.
1422900Seric 	*/
1432900Seric 
1445975Seric 	for (; !feof(InChannel); !feof(InChannel) && fgets(buf, sizeof buf, InChannel) != NULL)
1452900Seric 	{
1464156Seric 		register int i;
1474551Seric 		register char *bp = buf;
1484156Seric 
149*7852Seric 		fixcrlf(buf, TRUE);
1504557Seric 
1512900Seric 		/* check for end-of-message */
1522900Seric 		if (!IgnrDot && buf[0] == '.' && (buf[1] == '\n' || buf[1] == '\0'))
1532900Seric 			break;
1542900Seric 
1554551Seric 		/* check for transparent dot */
1564551Seric 		if (Smtp && *bp == '.')
1574551Seric 			bp++;
1584551Seric 
1594321Seric # ifndef NOTUNIX
1602900Seric 		/* Hide UNIX-like From lines */
1614551Seric 		if (strncmp(bp, "From ", 5) == 0)
1621392Seric 		{
1632900Seric 			fputs(">", tf);
1646901Seric 			CurEnv->e_msgsize++;
1651392Seric 		}
1664321Seric # endif NOTUNIX
1674156Seric 
1684156Seric 		/*
1694156Seric 		**  Figure message length, output the line to the temp
1704156Seric 		**  file, and insert a newline if missing.
1714156Seric 		*/
1724156Seric 
1734551Seric 		i = strlen(bp);
174*7852Seric 		CurEnv->e_msgsize += i + 1;
1754551Seric 		fputs(bp, tf);
176*7852Seric 		fputs("\n", tf);
1771392Seric 		if (ferror(tf))
1781392Seric 		{
1791439Seric 			if (errno == ENOSPC)
1801439Seric 			{
1816986Seric 				(void) freopen(CurEnv->e_df, "w", tf);
1821439Seric 				fputs("\nMAIL DELETED BECAUSE OF LACK OF DISK SPACE\n\n", tf);
1834557Seric 				usrerr("452 Out of disk space for temp file");
1841439Seric 			}
1851439Seric 			else
1866986Seric 				syserr("collect: Cannot write %s", CurEnv->e_df);
1874083Seric 			(void) freopen("/dev/null", "w", tf);
1881392Seric 		}
1891392Seric 	}
1904083Seric 	(void) fclose(tf);
1912900Seric 
1922900Seric 	/*
1932900Seric 	**  Find out some information from the headers.
1943386Seric 	**	Examples are who is the from person & the date.
1952900Seric 	*/
1962900Seric 
1977782Seric 	eatheader();
1987673Seric 
1997782Seric 	/*
2007782Seric 	**  Add an Apparently-To: line if we have no recipient lines.
2017782Seric 	*/
2024622Seric 
2037367Seric 	if (hvalue("to") == NULL && hvalue("cc") == NULL &&
2047367Seric 	    hvalue("bcc") == NULL && hvalue("apparently-to") == NULL)
2057367Seric 	{
2067367Seric 		register ADDRESS *q;
2077367Seric 
2087367Seric 		/* create an Apparently-To: field */
2097367Seric 		/*    that or reject the message.... */
2107367Seric 		for (q = CurEnv->e_sendqueue; q != NULL; q = q->q_next)
2117367Seric 		{
2127389Seric 			if (q->q_alias != NULL)
2137389Seric 				continue;
2147367Seric # ifdef DEBUG
2157673Seric 			if (tTd(30, 3))
2167367Seric 				printf("Adding Apparently-To: %s\n", q->q_paddr);
2177367Seric # endif DEBUG
2187367Seric 			addheader("apparently-to", q->q_paddr, CurEnv);
2197367Seric 		}
2207367Seric 	}
2217367Seric 
2227364Seric 	/* check for hop count overflow */
2237364Seric 	if (HopCount > MAXHOP)
2247364Seric 		syserr("Too many hops (%d max); probably forwarding loop", MAXHOP);
2257364Seric 
2266986Seric 	if ((TempFile = fopen(CurEnv->e_df, "r")) == NULL)
2276986Seric 		syserr("Cannot reopen %s", CurEnv->e_df);
2282900Seric 
2297673Seric 	/*
2307673Seric 	**  Log collection information.
2317673Seric 	*/
2327673Seric 
2337673Seric # ifdef LOG
2347673Seric 	if (LogLevel > 1)
2357809Seric 		syslog(LOG_INFO, "%s: from=%s, size=%ld, class=%d\n",
2367809Seric 		       CurEnv->e_id, CurEnv->e_from.q_paddr, CurEnv->e_msgsize,
2377758Seric 		       CurEnv->e_class);
2387673Seric # endif LOG
2394162Seric 	return;
2401392Seric }
2411392Seric /*
2422900Seric **  EATFROM -- chew up a UNIX style from line and process
2432900Seric **
2442900Seric **	This does indeed make some assumptions about the format
2452900Seric **	of UNIX messages.
2462900Seric **
2472900Seric **	Parameters:
2482900Seric **		fm -- the from line.
2492900Seric **
2502900Seric **	Returns:
2512900Seric **		none.
2522900Seric **
2532900Seric **	Side Effects:
2542900Seric **		extracts what information it can from the header,
2553386Seric **		such as the date.
2562900Seric */
2572900Seric 
2584321Seric # ifndef NOTUNIX
2594321Seric 
2604203Seric char	*DowList[] =
2614203Seric {
2624203Seric 	"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", NULL
2634203Seric };
2644203Seric 
2652900Seric char	*MonthList[] =
2662900Seric {
2672900Seric 	"Jan", "Feb", "Mar", "Apr", "May", "Jun",
2682900Seric 	"Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
2692900Seric 	NULL
2702900Seric };
2712900Seric 
2722900Seric eatfrom(fm)
2732900Seric 	char *fm;
2742900Seric {
2752900Seric 	register char *p;
2762900Seric 	register char **dt;
2772900Seric 
2784203Seric # ifdef DEBUG
2797673Seric 	if (tTd(30, 2))
2804203Seric 		printf("eatfrom(%s)\n", fm);
2814203Seric # endif DEBUG
2824203Seric 
2832900Seric 	/* find the date part */
2842900Seric 	p = fm;
2852900Seric 	while (*p != '\0')
2862900Seric 	{
2872900Seric 		/* skip a word */
2882900Seric 		while (*p != '\0' && *p != ' ')
2892900Seric 			*p++;
2902900Seric 		while (*p == ' ')
2912900Seric 			*p++;
2922900Seric 		if (!isupper(*p) || p[3] != ' ' || p[13] != ':' || p[16] != ':')
2932900Seric 			continue;
2942900Seric 
2952900Seric 		/* we have a possible date */
2964203Seric 		for (dt = DowList; *dt != NULL; dt++)
2972900Seric 			if (strncmp(*dt, p, 3) == 0)
2982900Seric 				break;
2994203Seric 		if (*dt == NULL)
3004203Seric 			continue;
3012900Seric 
3024203Seric 		for (dt = MonthList; *dt != NULL; dt++)
3034203Seric 			if (strncmp(*dt, &p[4], 3) == 0)
3044203Seric 				break;
3052900Seric 		if (*dt != NULL)
3062900Seric 			break;
3072900Seric 	}
3082900Seric 
3092900Seric 	if (*p != NULL)
3102900Seric 	{
3113386Seric 		char *q;
3125366Seric 		extern char *arpadate();
3133386Seric 
3142900Seric 		/* we have found a date */
3153386Seric 		q = xalloc(25);
3163386Seric 		strncpy(q, p, 25);
3173386Seric 		q[24] = '\0';
3183386Seric 		define('d', q);
3195366Seric 		q = arpadate(q);
3205366Seric 		define('a', newstr(q));
3212900Seric 	}
3222900Seric }
3234321Seric 
3244321Seric # endif NOTUNIX
325