xref: /freebsd/contrib/sendmail/src/headers.c (revision 5dd76dd0cc19450133aa379ce0ce4a68ae07fb39)
1c2aa98e2SPeter Wemm /*
2*5dd76dd0SGregory Neil Shapiro  * Copyright (c) 1998-2004, 2006, 2007 Proofpoint, Inc. and its suppliers.
33299c2f1SGregory Neil Shapiro  *	All rights reserved.
4c2aa98e2SPeter Wemm  * Copyright (c) 1983, 1995-1997 Eric P. Allman.  All rights reserved.
5c2aa98e2SPeter Wemm  * Copyright (c) 1988, 1993
6c2aa98e2SPeter Wemm  *	The Regents of the University of California.  All rights reserved.
7c2aa98e2SPeter Wemm  *
8c2aa98e2SPeter Wemm  * By using this file, you agree to the terms and conditions set
9c2aa98e2SPeter Wemm  * forth in the LICENSE file which can be found at the top level of
10c2aa98e2SPeter Wemm  * the sendmail distribution.
11c2aa98e2SPeter Wemm  *
12c2aa98e2SPeter Wemm  */
13c2aa98e2SPeter Wemm 
1412ed1c7cSGregory Neil Shapiro #include <sendmail.h>
15951742c4SGregory Neil Shapiro #include <sm/sendmail.h>
16c2aa98e2SPeter Wemm 
17*5dd76dd0SGregory Neil Shapiro SM_RCSID("@(#)$Id: headers.c,v 8.320 2013/11/22 20:51:55 ca Exp $")
183299c2f1SGregory Neil Shapiro 
19951742c4SGregory Neil Shapiro static HDR	*allocheader __P((char *, char *, int, SM_RPOOL_T *, bool));
20f9218d3dSGregory Neil Shapiro static size_t	fix_mime_header __P((HDR *, ENVELOPE *));
213299c2f1SGregory Neil Shapiro static int	priencode __P((char *));
22567a2fc9SGregory Neil Shapiro static bool	put_vanilla_header __P((HDR *, char *, MCI *));
23c2aa98e2SPeter Wemm 
24c2aa98e2SPeter Wemm /*
25c2aa98e2SPeter Wemm **  SETUPHEADERS -- initialize headers in symbol table
26c2aa98e2SPeter Wemm **
27c2aa98e2SPeter Wemm **	Parameters:
28c2aa98e2SPeter Wemm **		none
29c2aa98e2SPeter Wemm **
30c2aa98e2SPeter Wemm **	Returns:
31c2aa98e2SPeter Wemm **		none
32c2aa98e2SPeter Wemm */
33c2aa98e2SPeter Wemm 
34c2aa98e2SPeter Wemm void
35c2aa98e2SPeter Wemm setupheaders()
36c2aa98e2SPeter Wemm {
37c2aa98e2SPeter Wemm 	struct hdrinfo *hi;
38c2aa98e2SPeter Wemm 	STAB *s;
39c2aa98e2SPeter Wemm 
40c2aa98e2SPeter Wemm 	for (hi = HdrInfo; hi->hi_field != NULL; hi++)
41c2aa98e2SPeter Wemm 	{
42c2aa98e2SPeter Wemm 		s = stab(hi->hi_field, ST_HEADER, ST_ENTER);
43c2aa98e2SPeter Wemm 		s->s_header.hi_flags = hi->hi_flags;
44c2aa98e2SPeter Wemm 		s->s_header.hi_ruleset = NULL;
45c2aa98e2SPeter Wemm 	}
46c2aa98e2SPeter Wemm }
47951742c4SGregory Neil Shapiro 
4812ed1c7cSGregory Neil Shapiro /*
49951742c4SGregory Neil Shapiro **  DOCHOMPHEADER -- process and save a header line.
50c2aa98e2SPeter Wemm **
51951742c4SGregory Neil Shapiro **	Called by chompheader.
52c2aa98e2SPeter Wemm **
53c2aa98e2SPeter Wemm **	Parameters:
54c2aa98e2SPeter Wemm **		line -- header as a text line.
55d995d2baSGregory Neil Shapiro **		pflag -- flags for chompheader() (from sendmail.h)
56c2aa98e2SPeter Wemm **		hdrp -- a pointer to the place to save the header.
57c2aa98e2SPeter Wemm **		e -- the envelope including this header.
58c2aa98e2SPeter Wemm **
59c2aa98e2SPeter Wemm **	Returns:
60c2aa98e2SPeter Wemm **		flags for this header.
61c2aa98e2SPeter Wemm **
62c2aa98e2SPeter Wemm **	Side Effects:
63c2aa98e2SPeter Wemm **		The header is saved on the header list.
64c2aa98e2SPeter Wemm **		Contents of 'line' are destroyed.
65c2aa98e2SPeter Wemm */
66c2aa98e2SPeter Wemm 
673299c2f1SGregory Neil Shapiro static struct hdrinfo	NormalHeader =	{ NULL, 0, NULL };
68951742c4SGregory Neil Shapiro static unsigned long	dochompheader __P((char *, int, HDR **, ENVELOPE *));
69c2aa98e2SPeter Wemm 
70951742c4SGregory Neil Shapiro static unsigned long
71951742c4SGregory Neil Shapiro dochompheader(line, pflag, hdrp, e)
72c2aa98e2SPeter Wemm 	char *line;
733299c2f1SGregory Neil Shapiro 	int pflag;
74c2aa98e2SPeter Wemm 	HDR **hdrp;
75951742c4SGregory Neil Shapiro 	ENVELOPE *e;
76c2aa98e2SPeter Wemm {
7712ed1c7cSGregory Neil Shapiro 	unsigned char mid = '\0';
78c2aa98e2SPeter Wemm 	register char *p;
79c2aa98e2SPeter Wemm 	register HDR *h;
80c2aa98e2SPeter Wemm 	HDR **hp;
81c2aa98e2SPeter Wemm 	char *fname;
82c2aa98e2SPeter Wemm 	char *fvalue;
8312ed1c7cSGregory Neil Shapiro 	bool cond = false;
843299c2f1SGregory Neil Shapiro 	bool dropfrom;
85c2aa98e2SPeter Wemm 	bool headeronly;
86c2aa98e2SPeter Wemm 	STAB *s;
87c2aa98e2SPeter Wemm 	struct hdrinfo *hi;
8812ed1c7cSGregory Neil Shapiro 	bool nullheader = false;
893299c2f1SGregory Neil Shapiro 	BITMAP256 mopts;
90c2aa98e2SPeter Wemm 
91c2aa98e2SPeter Wemm 	headeronly = hdrp != NULL;
92c2aa98e2SPeter Wemm 	if (!headeronly)
93c2aa98e2SPeter Wemm 		hdrp = &e->e_header;
94c2aa98e2SPeter Wemm 
95c2aa98e2SPeter Wemm 	/* strip off options */
96c2aa98e2SPeter Wemm 	clrbitmap(mopts);
97c2aa98e2SPeter Wemm 	p = line;
983299c2f1SGregory Neil Shapiro 	if (!bitset(pflag, CHHDR_USER) && *p == '?')
99c2aa98e2SPeter Wemm 	{
1003299c2f1SGregory Neil Shapiro 		int c;
1013299c2f1SGregory Neil Shapiro 		register char *q;
102c2aa98e2SPeter Wemm 
1033299c2f1SGregory Neil Shapiro 		q = strchr(++p, '?');
1043299c2f1SGregory Neil Shapiro 		if (q == NULL)
1053299c2f1SGregory Neil Shapiro 			goto hse;
1063299c2f1SGregory Neil Shapiro 
1073299c2f1SGregory Neil Shapiro 		*q = '\0';
1083299c2f1SGregory Neil Shapiro 		c = *p & 0377;
1093299c2f1SGregory Neil Shapiro 
1103299c2f1SGregory Neil Shapiro 		/* possibly macro conditional */
1113299c2f1SGregory Neil Shapiro 		if (c == MACROEXPAND)
112c2aa98e2SPeter Wemm 		{
1133299c2f1SGregory Neil Shapiro 			/* catch ?$? */
1143299c2f1SGregory Neil Shapiro 			if (*++p == '\0')
1153299c2f1SGregory Neil Shapiro 			{
1163299c2f1SGregory Neil Shapiro 				*q = '?';
1173299c2f1SGregory Neil Shapiro 				goto hse;
1183299c2f1SGregory Neil Shapiro 			}
1193299c2f1SGregory Neil Shapiro 
12012ed1c7cSGregory Neil Shapiro 			mid = (unsigned char) *p++;
1213299c2f1SGregory Neil Shapiro 
1223299c2f1SGregory Neil Shapiro 			/* catch ?$abc? */
1233299c2f1SGregory Neil Shapiro 			if (*p != '\0')
1243299c2f1SGregory Neil Shapiro 			{
1253299c2f1SGregory Neil Shapiro 				*q = '?';
1263299c2f1SGregory Neil Shapiro 				goto hse;
1273299c2f1SGregory Neil Shapiro 			}
1283299c2f1SGregory Neil Shapiro 		}
1293299c2f1SGregory Neil Shapiro 		else if (*p == '$')
1303299c2f1SGregory Neil Shapiro 		{
1313299c2f1SGregory Neil Shapiro 			/* catch ?$? */
1323299c2f1SGregory Neil Shapiro 			if (*++p == '\0')
1333299c2f1SGregory Neil Shapiro 			{
1343299c2f1SGregory Neil Shapiro 				*q = '?';
1353299c2f1SGregory Neil Shapiro 				goto hse;
1363299c2f1SGregory Neil Shapiro 			}
1373299c2f1SGregory Neil Shapiro 
13812ed1c7cSGregory Neil Shapiro 			mid = (unsigned char) macid(p);
1393299c2f1SGregory Neil Shapiro 			if (bitset(0200, mid))
1407660b554SGregory Neil Shapiro 			{
1413299c2f1SGregory Neil Shapiro 				p += strlen(macname(mid)) + 2;
1427660b554SGregory Neil Shapiro 				SM_ASSERT(p <= q);
1437660b554SGregory Neil Shapiro 			}
1443299c2f1SGregory Neil Shapiro 			else
1453299c2f1SGregory Neil Shapiro 				p++;
1463299c2f1SGregory Neil Shapiro 
1473299c2f1SGregory Neil Shapiro 			/* catch ?$abc? */
1483299c2f1SGregory Neil Shapiro 			if (*p != '\0')
1493299c2f1SGregory Neil Shapiro 			{
1503299c2f1SGregory Neil Shapiro 				*q = '?';
1513299c2f1SGregory Neil Shapiro 				goto hse;
1523299c2f1SGregory Neil Shapiro 			}
153c2aa98e2SPeter Wemm 		}
154c2aa98e2SPeter Wemm 		else
1553299c2f1SGregory Neil Shapiro 		{
1563299c2f1SGregory Neil Shapiro 			while (*p != '\0')
1573299c2f1SGregory Neil Shapiro 			{
1583299c2f1SGregory Neil Shapiro 				if (!isascii(*p))
1593299c2f1SGregory Neil Shapiro 				{
1603299c2f1SGregory Neil Shapiro 					*q = '?';
1613299c2f1SGregory Neil Shapiro 					goto hse;
1623299c2f1SGregory Neil Shapiro 				}
1633299c2f1SGregory Neil Shapiro 
164c46d91b7SGregory Neil Shapiro 				setbitn(bitidx(*p), mopts);
16512ed1c7cSGregory Neil Shapiro 				cond = true;
1663299c2f1SGregory Neil Shapiro 				p++;
1673299c2f1SGregory Neil Shapiro 			}
1683299c2f1SGregory Neil Shapiro 		}
1693299c2f1SGregory Neil Shapiro 		p = q + 1;
170c2aa98e2SPeter Wemm 	}
171c2aa98e2SPeter Wemm 
172c2aa98e2SPeter Wemm 	/* find canonical name */
173c2aa98e2SPeter Wemm 	fname = p;
174c2aa98e2SPeter Wemm 	while (isascii(*p) && isgraph(*p) && *p != ':')
175c2aa98e2SPeter Wemm 		p++;
176c2aa98e2SPeter Wemm 	fvalue = p;
177c2aa98e2SPeter Wemm 	while (isascii(*p) && isspace(*p))
178c2aa98e2SPeter Wemm 		p++;
179c2aa98e2SPeter Wemm 	if (*p++ != ':' || fname == fvalue)
180c2aa98e2SPeter Wemm 	{
1813299c2f1SGregory Neil Shapiro hse:
1823299c2f1SGregory Neil Shapiro 		syserr("553 5.3.0 header syntax error, line \"%s\"", line);
183c2aa98e2SPeter Wemm 		return 0;
184c2aa98e2SPeter Wemm 	}
185c2aa98e2SPeter Wemm 	*fvalue = '\0';
186e01d6f61SPeter Wemm 	fvalue = p;
187e01d6f61SPeter Wemm 
188e01d6f61SPeter Wemm 	/* if the field is null, go ahead and use the default */
189e01d6f61SPeter Wemm 	while (isascii(*p) && isspace(*p))
190e01d6f61SPeter Wemm 		p++;
191e01d6f61SPeter Wemm 	if (*p == '\0')
19212ed1c7cSGregory Neil Shapiro 		nullheader = true;
193c2aa98e2SPeter Wemm 
194c2aa98e2SPeter Wemm 	/* security scan: long field names are end-of-header */
195c2aa98e2SPeter Wemm 	if (strlen(fname) > 100)
196c2aa98e2SPeter Wemm 		return H_EOH;
197c2aa98e2SPeter Wemm 
198c2aa98e2SPeter Wemm 	/* check to see if it represents a ruleset call */
1993299c2f1SGregory Neil Shapiro 	if (bitset(pflag, CHHDR_DEF))
200c2aa98e2SPeter Wemm 	{
201c2aa98e2SPeter Wemm 		char hbuf[50];
202c2aa98e2SPeter Wemm 
203951742c4SGregory Neil Shapiro 		(void) expand(fvalue, hbuf, sizeof(hbuf), e);
204c2aa98e2SPeter Wemm 		for (p = hbuf; isascii(*p) && isspace(*p); )
205c2aa98e2SPeter Wemm 			p++;
206c2aa98e2SPeter Wemm 		if ((*p++ & 0377) == CALLSUBR)
207c2aa98e2SPeter Wemm 		{
208c2aa98e2SPeter Wemm 			auto char *endp;
2093299c2f1SGregory Neil Shapiro 			bool strc;
210c2aa98e2SPeter Wemm 
2113299c2f1SGregory Neil Shapiro 			strc = *p == '+';	/* strip comments? */
2123299c2f1SGregory Neil Shapiro 			if (strc)
2133299c2f1SGregory Neil Shapiro 				++p;
214c2aa98e2SPeter Wemm 			if (strtorwset(p, &endp, ST_ENTER) > 0)
215c2aa98e2SPeter Wemm 			{
216c2aa98e2SPeter Wemm 				*endp = '\0';
217c2aa98e2SPeter Wemm 				s = stab(fname, ST_HEADER, ST_ENTER);
21812ed1c7cSGregory Neil Shapiro 				if (LogLevel > 9 &&
21912ed1c7cSGregory Neil Shapiro 				    s->s_header.hi_ruleset != NULL)
22012ed1c7cSGregory Neil Shapiro 					sm_syslog(LOG_WARNING, NOQID,
22112ed1c7cSGregory Neil Shapiro 						  "Warning: redefined ruleset for header=%s, old=%s, new=%s",
22212ed1c7cSGregory Neil Shapiro 						  fname,
22312ed1c7cSGregory Neil Shapiro 						  s->s_header.hi_ruleset, p);
224c2aa98e2SPeter Wemm 				s->s_header.hi_ruleset = newstr(p);
2253299c2f1SGregory Neil Shapiro 				if (!strc)
2263299c2f1SGregory Neil Shapiro 					s->s_header.hi_flags |= H_STRIPCOMM;
227c2aa98e2SPeter Wemm 			}
228c2aa98e2SPeter Wemm 			return 0;
229c2aa98e2SPeter Wemm 		}
230c2aa98e2SPeter Wemm 	}
231c2aa98e2SPeter Wemm 
232c2aa98e2SPeter Wemm 	/* see if it is a known type */
233c2aa98e2SPeter Wemm 	s = stab(fname, ST_HEADER, ST_FIND);
234c2aa98e2SPeter Wemm 	if (s != NULL)
235c2aa98e2SPeter Wemm 		hi = &s->s_header;
236c2aa98e2SPeter Wemm 	else
237c2aa98e2SPeter Wemm 		hi = &NormalHeader;
238c2aa98e2SPeter Wemm 
239c2aa98e2SPeter Wemm 	if (tTd(31, 9))
240c2aa98e2SPeter Wemm 	{
241c2aa98e2SPeter Wemm 		if (s == NULL)
24212ed1c7cSGregory Neil Shapiro 			sm_dprintf("no header flags match\n");
243c2aa98e2SPeter Wemm 		else
24412ed1c7cSGregory Neil Shapiro 			sm_dprintf("header match, flags=%lx, ruleset=%s\n",
245c2aa98e2SPeter Wemm 				   hi->hi_flags,
24612ed1c7cSGregory Neil Shapiro 				   hi->hi_ruleset == NULL ? "<NULL>"
24712ed1c7cSGregory Neil Shapiro 							  : hi->hi_ruleset);
248c2aa98e2SPeter Wemm 	}
249c2aa98e2SPeter Wemm 
250c2aa98e2SPeter Wemm 	/* see if this is a resent message */
2513299c2f1SGregory Neil Shapiro 	if (!bitset(pflag, CHHDR_DEF) && !headeronly &&
2523299c2f1SGregory Neil Shapiro 	    bitset(H_RESENT, hi->hi_flags))
253c2aa98e2SPeter Wemm 		e->e_flags |= EF_RESENT;
254c2aa98e2SPeter Wemm 
255c2aa98e2SPeter Wemm 	/* if this is an Errors-To: header keep track of it now */
2563299c2f1SGregory Neil Shapiro 	if (UseErrorsTo && !bitset(pflag, CHHDR_DEF) && !headeronly &&
257c2aa98e2SPeter Wemm 	    bitset(H_ERRORSTO, hi->hi_flags))
258c2aa98e2SPeter Wemm 		(void) sendtolist(fvalue, NULLADDR, &e->e_errorqueue, 0, e);
259c2aa98e2SPeter Wemm 
260c2aa98e2SPeter Wemm 	/* if this means "end of header" quit now */
261c2aa98e2SPeter Wemm 	if (!headeronly && bitset(H_EOH, hi->hi_flags))
262c2aa98e2SPeter Wemm 		return hi->hi_flags;
263c2aa98e2SPeter Wemm 
264c2aa98e2SPeter Wemm 	/*
265c2aa98e2SPeter Wemm 	**  Horrible hack to work around problem with Lotus Notes SMTP
266c2aa98e2SPeter Wemm 	**  mail gateway, which generates From: headers with newlines in
267c2aa98e2SPeter Wemm 	**  them and the <address> on the second line.  Although this is
268c2aa98e2SPeter Wemm 	**  legal RFC 822, many MUAs don't handle this properly and thus
269c2aa98e2SPeter Wemm 	**  never find the actual address.
270c2aa98e2SPeter Wemm 	*/
271c2aa98e2SPeter Wemm 
272c2aa98e2SPeter Wemm 	if (bitset(H_FROM, hi->hi_flags) && SingleLineFromHeader)
273c2aa98e2SPeter Wemm 	{
274c2aa98e2SPeter Wemm 		while ((p = strchr(fvalue, '\n')) != NULL)
275c2aa98e2SPeter Wemm 			*p = ' ';
276c2aa98e2SPeter Wemm 	}
277c2aa98e2SPeter Wemm 
278c2aa98e2SPeter Wemm 	/*
279c2aa98e2SPeter Wemm 	**  If there is a check ruleset, verify it against the header.
280c2aa98e2SPeter Wemm 	*/
281c2aa98e2SPeter Wemm 
2823299c2f1SGregory Neil Shapiro 	if (bitset(pflag, CHHDR_CHECK))
2833299c2f1SGregory Neil Shapiro 	{
2849d8fddc1SGregory Neil Shapiro 		int rscheckflags;
2853299c2f1SGregory Neil Shapiro 		char *rs;
2863299c2f1SGregory Neil Shapiro 
2879d8fddc1SGregory Neil Shapiro 		rscheckflags = RSF_COUNT;
2889d8fddc1SGregory Neil Shapiro 		if (!bitset(hi->hi_flags, H_FROM|H_RCPT))
2899d8fddc1SGregory Neil Shapiro 			rscheckflags |= RSF_UNSTRUCTURED;
290bfb62e91SGregory Neil Shapiro 
291bfb62e91SGregory Neil Shapiro 		/* no ruleset? look for default */
292bfb62e91SGregory Neil Shapiro 		rs = hi->hi_ruleset;
2933299c2f1SGregory Neil Shapiro 		if (rs == NULL)
2943299c2f1SGregory Neil Shapiro 		{
2953299c2f1SGregory Neil Shapiro 			s = stab("*", ST_HEADER, ST_FIND);
2963299c2f1SGregory Neil Shapiro 			if (s != NULL)
2973299c2f1SGregory Neil Shapiro 			{
2983299c2f1SGregory Neil Shapiro 				rs = (&s->s_header)->hi_ruleset;
2999d8fddc1SGregory Neil Shapiro 				if (bitset((&s->s_header)->hi_flags,
3009d8fddc1SGregory Neil Shapiro 					   H_STRIPCOMM))
3019d8fddc1SGregory Neil Shapiro 					rscheckflags |= RSF_RMCOMM;
3023299c2f1SGregory Neil Shapiro 			}
3033299c2f1SGregory Neil Shapiro 		}
3049d8fddc1SGregory Neil Shapiro 		else if (bitset(hi->hi_flags, H_STRIPCOMM))
3059d8fddc1SGregory Neil Shapiro 			rscheckflags |= RSF_RMCOMM;
3063299c2f1SGregory Neil Shapiro 		if (rs != NULL)
3073299c2f1SGregory Neil Shapiro 		{
30812ed1c7cSGregory Neil Shapiro 			int l, k;
3093299c2f1SGregory Neil Shapiro 			char qval[MAXNAME];
3103299c2f1SGregory Neil Shapiro 
3113299c2f1SGregory Neil Shapiro 			l = 0;
31212ed1c7cSGregory Neil Shapiro 			qval[l++] = '"';
31312ed1c7cSGregory Neil Shapiro 
31412ed1c7cSGregory Neil Shapiro 			/* - 3 to avoid problems with " at the end */
3157660b554SGregory Neil Shapiro 			/* should be sizeof(qval), not MAXNAME */
31612ed1c7cSGregory Neil Shapiro 			for (k = 0; fvalue[k] != '\0' && l < MAXNAME - 3; k++)
3173299c2f1SGregory Neil Shapiro 			{
31812ed1c7cSGregory Neil Shapiro 				switch (fvalue[k])
3193299c2f1SGregory Neil Shapiro 				{
32012ed1c7cSGregory Neil Shapiro 				  /* XXX other control chars? */
3213299c2f1SGregory Neil Shapiro 				  case '\011': /* ht */
3223299c2f1SGregory Neil Shapiro 				  case '\012': /* nl */
3233299c2f1SGregory Neil Shapiro 				  case '\013': /* vt */
3243299c2f1SGregory Neil Shapiro 				  case '\014': /* np */
3253299c2f1SGregory Neil Shapiro 				  case '\015': /* cr */
32612ed1c7cSGregory Neil Shapiro 					qval[l++] = ' ';
3273299c2f1SGregory Neil Shapiro 					break;
3283299c2f1SGregory Neil Shapiro 				  case '"':
32912ed1c7cSGregory Neil Shapiro 					qval[l++] = '\\';
3303299c2f1SGregory Neil Shapiro 					/* FALLTHROUGH */
3313299c2f1SGregory Neil Shapiro 				  default:
33212ed1c7cSGregory Neil Shapiro 					qval[l++] = fvalue[k];
3333299c2f1SGregory Neil Shapiro 					break;
3343299c2f1SGregory Neil Shapiro 				}
3353299c2f1SGregory Neil Shapiro 			}
33612ed1c7cSGregory Neil Shapiro 			qval[l++] = '"';
33712ed1c7cSGregory Neil Shapiro 			qval[l] = '\0';
33812ed1c7cSGregory Neil Shapiro 			k += strlen(fvalue + k);
33912ed1c7cSGregory Neil Shapiro 			if (k >= MAXNAME)
3403299c2f1SGregory Neil Shapiro 			{
3413299c2f1SGregory Neil Shapiro 				if (LogLevel > 9)
3423299c2f1SGregory Neil Shapiro 					sm_syslog(LOG_WARNING, e->e_id,
3433299c2f1SGregory Neil Shapiro 						  "Warning: truncated header '%s' before check with '%s' len=%d max=%d",
34412ed1c7cSGregory Neil Shapiro 						  fname, rs, k, MAXNAME - 1);
3453299c2f1SGregory Neil Shapiro 			}
34612ed1c7cSGregory Neil Shapiro 			macdefine(&e->e_macro, A_TEMP,
34712ed1c7cSGregory Neil Shapiro 				macid("{currHeader}"), qval);
34812ed1c7cSGregory Neil Shapiro 			macdefine(&e->e_macro, A_TEMP,
34912ed1c7cSGregory Neil Shapiro 				macid("{hdr_name}"), fname);
35012ed1c7cSGregory Neil Shapiro 
351951742c4SGregory Neil Shapiro 			(void) sm_snprintf(qval, sizeof(qval), "%d", k);
35212ed1c7cSGregory Neil Shapiro 			macdefine(&e->e_macro, A_TEMP, macid("{hdrlen}"), qval);
353bfb62e91SGregory Neil Shapiro 			if (bitset(H_FROM, hi->hi_flags))
35412ed1c7cSGregory Neil Shapiro 				macdefine(&e->e_macro, A_PERM,
35512ed1c7cSGregory Neil Shapiro 					macid("{addr_type}"), "h s");
356bfb62e91SGregory Neil Shapiro 			else if (bitset(H_RCPT, hi->hi_flags))
35712ed1c7cSGregory Neil Shapiro 				macdefine(&e->e_macro, A_PERM,
35812ed1c7cSGregory Neil Shapiro 					macid("{addr_type}"), "h r");
35912ed1c7cSGregory Neil Shapiro 			else
36012ed1c7cSGregory Neil Shapiro 				macdefine(&e->e_macro, A_PERM,
36112ed1c7cSGregory Neil Shapiro 					macid("{addr_type}"), "h");
3629d8fddc1SGregory Neil Shapiro 			(void) rscheck(rs, fvalue, NULL, e, rscheckflags, 3,
363951742c4SGregory Neil Shapiro 				       NULL, e->e_id, NULL);
3643299c2f1SGregory Neil Shapiro 		}
3653299c2f1SGregory Neil Shapiro 	}
366c2aa98e2SPeter Wemm 
367c2aa98e2SPeter Wemm 	/*
368c2aa98e2SPeter Wemm 	**  Drop explicit From: if same as what we would generate.
369c2aa98e2SPeter Wemm 	**  This is to make MH (which doesn't always give a full name)
370c2aa98e2SPeter Wemm 	**  insert the full name information in all circumstances.
371c2aa98e2SPeter Wemm 	*/
372c2aa98e2SPeter Wemm 
37312ed1c7cSGregory Neil Shapiro 	dropfrom = false;
374c2aa98e2SPeter Wemm 	p = "resent-from";
375c2aa98e2SPeter Wemm 	if (!bitset(EF_RESENT, e->e_flags))
376c2aa98e2SPeter Wemm 		p += 7;
3773299c2f1SGregory Neil Shapiro 	if (!bitset(pflag, CHHDR_DEF) && !headeronly &&
37812ed1c7cSGregory Neil Shapiro 	    !bitset(EF_QUEUERUN, e->e_flags) && sm_strcasecmp(fname, p) == 0)
379c2aa98e2SPeter Wemm 	{
380c2aa98e2SPeter Wemm 		if (e->e_from.q_paddr != NULL &&
3813299c2f1SGregory Neil Shapiro 		    e->e_from.q_mailer != NULL &&
3823299c2f1SGregory Neil Shapiro 		    bitnset(M_LOCALMAILER, e->e_from.q_mailer->m_flags) &&
383c2aa98e2SPeter Wemm 		    (strcmp(fvalue, e->e_from.q_paddr) == 0 ||
384c2aa98e2SPeter Wemm 		     strcmp(fvalue, e->e_from.q_user) == 0))
38512ed1c7cSGregory Neil Shapiro 			dropfrom = true;
386*5dd76dd0SGregory Neil Shapiro 		if (tTd(31, 2))
387*5dd76dd0SGregory Neil Shapiro 		{
388*5dd76dd0SGregory Neil Shapiro 			sm_dprintf("comparing header from (%s) against default (%s or %s), drop=%d\n",
389*5dd76dd0SGregory Neil Shapiro 				fvalue, e->e_from.q_paddr, e->e_from.q_user,
390*5dd76dd0SGregory Neil Shapiro 				dropfrom);
391*5dd76dd0SGregory Neil Shapiro 		}
392c2aa98e2SPeter Wemm 	}
393c2aa98e2SPeter Wemm 
394c2aa98e2SPeter Wemm 	/* delete default value for this header */
395c2aa98e2SPeter Wemm 	for (hp = hdrp; (h = *hp) != NULL; hp = &h->h_link)
396c2aa98e2SPeter Wemm 	{
39712ed1c7cSGregory Neil Shapiro 		if (sm_strcasecmp(fname, h->h_field) == 0 &&
3983299c2f1SGregory Neil Shapiro 		    !bitset(H_USER, h->h_flags) &&
399c2aa98e2SPeter Wemm 		    !bitset(H_FORCE, h->h_flags))
400c2aa98e2SPeter Wemm 		{
401e01d6f61SPeter Wemm 			if (nullheader)
402e01d6f61SPeter Wemm 			{
403e01d6f61SPeter Wemm 				/* user-supplied value was null */
404e01d6f61SPeter Wemm 				return 0;
405e01d6f61SPeter Wemm 			}
4063299c2f1SGregory Neil Shapiro 			if (dropfrom)
4073299c2f1SGregory Neil Shapiro 			{
4083299c2f1SGregory Neil Shapiro 				/* make this look like the user entered it */
4093299c2f1SGregory Neil Shapiro 				h->h_flags |= H_USER;
410*5dd76dd0SGregory Neil Shapiro 
411*5dd76dd0SGregory Neil Shapiro 				/*
412*5dd76dd0SGregory Neil Shapiro 				**  If the MH hack is selected, allow to turn
413*5dd76dd0SGregory Neil Shapiro 				**  it off via a mailer flag to avoid problems
414*5dd76dd0SGregory Neil Shapiro 				**  with setups that remove the F flag from
415*5dd76dd0SGregory Neil Shapiro 				**  the RCPT mailer.
416*5dd76dd0SGregory Neil Shapiro 				*/
417*5dd76dd0SGregory Neil Shapiro 
418*5dd76dd0SGregory Neil Shapiro 		    		if (bitnset(M_NOMHHACK,
419*5dd76dd0SGregory Neil Shapiro 					    e->e_from.q_mailer->m_flags))
420*5dd76dd0SGregory Neil Shapiro 				{
421*5dd76dd0SGregory Neil Shapiro 					h->h_flags &= ~H_CHECK;
422*5dd76dd0SGregory Neil Shapiro 				}
4233299c2f1SGregory Neil Shapiro 				return hi->hi_flags;
4243299c2f1SGregory Neil Shapiro 			}
425c2aa98e2SPeter Wemm 			h->h_value = NULL;
426c2aa98e2SPeter Wemm 			if (!cond)
427c2aa98e2SPeter Wemm 			{
428c2aa98e2SPeter Wemm 				/* copy conditions from default case */
4293299c2f1SGregory Neil Shapiro 				memmove((char *) mopts, (char *) h->h_mflags,
430951742c4SGregory Neil Shapiro 					sizeof(mopts));
431c2aa98e2SPeter Wemm 			}
4323299c2f1SGregory Neil Shapiro 			h->h_macro = mid;
433c2aa98e2SPeter Wemm 		}
434c2aa98e2SPeter Wemm 	}
435c2aa98e2SPeter Wemm 
436c2aa98e2SPeter Wemm 	/* create a new node */
437951742c4SGregory Neil Shapiro 	h = (HDR *) sm_rpool_malloc_x(e->e_rpool, sizeof(*h));
43812ed1c7cSGregory Neil Shapiro 	h->h_field = sm_rpool_strdup_x(e->e_rpool, fname);
43912ed1c7cSGregory Neil Shapiro 	h->h_value = sm_rpool_strdup_x(e->e_rpool, fvalue);
440c2aa98e2SPeter Wemm 	h->h_link = NULL;
441951742c4SGregory Neil Shapiro 	memmove((char *) h->h_mflags, (char *) mopts, sizeof(mopts));
4423299c2f1SGregory Neil Shapiro 	h->h_macro = mid;
443c2aa98e2SPeter Wemm 	*hp = h;
444c2aa98e2SPeter Wemm 	h->h_flags = hi->hi_flags;
445d995d2baSGregory Neil Shapiro 	if (bitset(pflag, CHHDR_USER) || bitset(pflag, CHHDR_QUEUE))
4463299c2f1SGregory Neil Shapiro 		h->h_flags |= H_USER;
447c2aa98e2SPeter Wemm 
448c2aa98e2SPeter Wemm 	/* strip EOH flag if parsing MIME headers */
449c2aa98e2SPeter Wemm 	if (headeronly)
450c2aa98e2SPeter Wemm 		h->h_flags &= ~H_EOH;
4513299c2f1SGregory Neil Shapiro 	if (bitset(pflag, CHHDR_DEF))
452c2aa98e2SPeter Wemm 		h->h_flags |= H_DEFAULT;
4533299c2f1SGregory Neil Shapiro 	if (cond || mid != '\0')
454c2aa98e2SPeter Wemm 		h->h_flags |= H_CHECK;
455c2aa98e2SPeter Wemm 
456c2aa98e2SPeter Wemm 	/* hack to see if this is a new format message */
4573299c2f1SGregory Neil Shapiro 	if (!bitset(pflag, CHHDR_DEF) && !headeronly &&
4583299c2f1SGregory Neil Shapiro 	    bitset(H_RCPT|H_FROM, h->h_flags) &&
459c2aa98e2SPeter Wemm 	    (strchr(fvalue, ',') != NULL || strchr(fvalue, '(') != NULL ||
460c2aa98e2SPeter Wemm 	     strchr(fvalue, '<') != NULL || strchr(fvalue, ';') != NULL))
461c2aa98e2SPeter Wemm 	{
462c2aa98e2SPeter Wemm 		e->e_flags &= ~EF_OLDSTYLE;
463c2aa98e2SPeter Wemm 	}
464c2aa98e2SPeter Wemm 
465c2aa98e2SPeter Wemm 	return h->h_flags;
466c2aa98e2SPeter Wemm }
467951742c4SGregory Neil Shapiro 
468951742c4SGregory Neil Shapiro /*
469951742c4SGregory Neil Shapiro **  CHOMPHEADER -- process and save a header line.
470951742c4SGregory Neil Shapiro **
471951742c4SGregory Neil Shapiro **	Called by collect, readcf, and readqf to deal with header lines.
472951742c4SGregory Neil Shapiro **	This is just a wrapper for dochompheader().
473951742c4SGregory Neil Shapiro **
474951742c4SGregory Neil Shapiro **	Parameters:
475951742c4SGregory Neil Shapiro **		line -- header as a text line.
476951742c4SGregory Neil Shapiro **		pflag -- flags for chompheader() (from sendmail.h)
477951742c4SGregory Neil Shapiro **		hdrp -- a pointer to the place to save the header.
478951742c4SGregory Neil Shapiro **		e -- the envelope including this header.
479951742c4SGregory Neil Shapiro **
480951742c4SGregory Neil Shapiro **	Returns:
481951742c4SGregory Neil Shapiro **		flags for this header.
482951742c4SGregory Neil Shapiro **
483951742c4SGregory Neil Shapiro **	Side Effects:
484951742c4SGregory Neil Shapiro **		The header is saved on the header list.
485951742c4SGregory Neil Shapiro **		Contents of 'line' are destroyed.
486951742c4SGregory Neil Shapiro */
487951742c4SGregory Neil Shapiro 
488951742c4SGregory Neil Shapiro 
489951742c4SGregory Neil Shapiro unsigned long
490951742c4SGregory Neil Shapiro chompheader(line, pflag, hdrp, e)
491951742c4SGregory Neil Shapiro 	char *line;
492951742c4SGregory Neil Shapiro 	int pflag;
493951742c4SGregory Neil Shapiro 	HDR **hdrp;
494951742c4SGregory Neil Shapiro 	register ENVELOPE *e;
495951742c4SGregory Neil Shapiro {
496951742c4SGregory Neil Shapiro 	unsigned long rval;
497951742c4SGregory Neil Shapiro 
498951742c4SGregory Neil Shapiro 	if (tTd(31, 6))
499951742c4SGregory Neil Shapiro 	{
500951742c4SGregory Neil Shapiro 		sm_dprintf("chompheader: ");
501951742c4SGregory Neil Shapiro 		xputs(sm_debug_file(), line);
502951742c4SGregory Neil Shapiro 		sm_dprintf("\n");
503951742c4SGregory Neil Shapiro 	}
504951742c4SGregory Neil Shapiro 
505951742c4SGregory Neil Shapiro 	/* quote this if user (not config file) input */
506951742c4SGregory Neil Shapiro 	if (bitset(pflag, CHHDR_USER))
507951742c4SGregory Neil Shapiro 	{
508951742c4SGregory Neil Shapiro 		char xbuf[MAXLINE];
509951742c4SGregory Neil Shapiro 		char *xbp = NULL;
510951742c4SGregory Neil Shapiro 		int xbufs;
511951742c4SGregory Neil Shapiro 
512951742c4SGregory Neil Shapiro 		xbufs = sizeof(xbuf);
513951742c4SGregory Neil Shapiro 		xbp = quote_internal_chars(line, xbuf, &xbufs);
514951742c4SGregory Neil Shapiro 		if (tTd(31, 7))
515951742c4SGregory Neil Shapiro 		{
516951742c4SGregory Neil Shapiro 			sm_dprintf("chompheader: quoted: ");
517951742c4SGregory Neil Shapiro 			xputs(sm_debug_file(), xbp);
518951742c4SGregory Neil Shapiro 			sm_dprintf("\n");
519951742c4SGregory Neil Shapiro 		}
520951742c4SGregory Neil Shapiro 		rval = dochompheader(xbp, pflag, hdrp, e);
521951742c4SGregory Neil Shapiro 		if (xbp != xbuf)
522951742c4SGregory Neil Shapiro 			sm_free(xbp);
523951742c4SGregory Neil Shapiro 	}
524951742c4SGregory Neil Shapiro 	else
525951742c4SGregory Neil Shapiro 		rval = dochompheader(line, pflag, hdrp, e);
526951742c4SGregory Neil Shapiro 
527951742c4SGregory Neil Shapiro 	return rval;
528951742c4SGregory Neil Shapiro }
529951742c4SGregory Neil Shapiro 
53012ed1c7cSGregory Neil Shapiro /*
531bfb62e91SGregory Neil Shapiro **  ALLOCHEADER -- allocate a header entry
532bfb62e91SGregory Neil Shapiro **
533bfb62e91SGregory Neil Shapiro **	Parameters:
534951742c4SGregory Neil Shapiro **		field -- the name of the header field (will not be copied).
535951742c4SGregory Neil Shapiro **		value -- the value of the field (will be copied).
536bfb62e91SGregory Neil Shapiro **		flags -- flags to add to h_flags.
537bfb62e91SGregory Neil Shapiro **		rp -- resource pool for allocations
538951742c4SGregory Neil Shapiro **		space -- add leading space?
539bfb62e91SGregory Neil Shapiro **
540bfb62e91SGregory Neil Shapiro **	Returns:
541bfb62e91SGregory Neil Shapiro **		Pointer to a newly allocated and populated HDR.
542951742c4SGregory Neil Shapiro **
543951742c4SGregory Neil Shapiro **	Notes:
544951742c4SGregory Neil Shapiro **		o field and value must be in internal format, i.e.,
545951742c4SGregory Neil Shapiro **		metacharacters must be "quoted", see quote_internal_chars().
546951742c4SGregory Neil Shapiro **		o maybe add more flags to decide:
547951742c4SGregory Neil Shapiro **		  - what to copy (field/value)
548951742c4SGregory Neil Shapiro **		  - whether to convert value to an internal format
549bfb62e91SGregory Neil Shapiro */
550bfb62e91SGregory Neil Shapiro 
551bfb62e91SGregory Neil Shapiro static HDR *
552951742c4SGregory Neil Shapiro allocheader(field, value, flags, rp, space)
553bfb62e91SGregory Neil Shapiro 	char *field;
554bfb62e91SGregory Neil Shapiro 	char *value;
555bfb62e91SGregory Neil Shapiro 	int flags;
556bfb62e91SGregory Neil Shapiro 	SM_RPOOL_T *rp;
557951742c4SGregory Neil Shapiro 	bool space;
558bfb62e91SGregory Neil Shapiro {
559bfb62e91SGregory Neil Shapiro 	HDR *h;
560bfb62e91SGregory Neil Shapiro 	STAB *s;
561bfb62e91SGregory Neil Shapiro 
562bfb62e91SGregory Neil Shapiro 	/* find info struct */
563bfb62e91SGregory Neil Shapiro 	s = stab(field, ST_HEADER, ST_FIND);
564bfb62e91SGregory Neil Shapiro 
565bfb62e91SGregory Neil Shapiro 	/* allocate space for new header */
566951742c4SGregory Neil Shapiro 	h = (HDR *) sm_rpool_malloc_x(rp, sizeof(*h));
567bfb62e91SGregory Neil Shapiro 	h->h_field = field;
568951742c4SGregory Neil Shapiro 	if (space)
569951742c4SGregory Neil Shapiro 	{
570951742c4SGregory Neil Shapiro 		size_t l;
571951742c4SGregory Neil Shapiro 		char *n;
572951742c4SGregory Neil Shapiro 
573951742c4SGregory Neil Shapiro 		l = strlen(value);
574951742c4SGregory Neil Shapiro 		SM_ASSERT(l + 2 > l);
575951742c4SGregory Neil Shapiro 		n = sm_rpool_malloc_x(rp, l + 2);
576951742c4SGregory Neil Shapiro 		n[0] = ' ';
577951742c4SGregory Neil Shapiro 		n[1] = '\0';
578951742c4SGregory Neil Shapiro 		sm_strlcpy(n + 1, value, l + 1);
579951742c4SGregory Neil Shapiro 		h->h_value = n;
580951742c4SGregory Neil Shapiro 	}
581951742c4SGregory Neil Shapiro 	else
582bfb62e91SGregory Neil Shapiro 		h->h_value = sm_rpool_strdup_x(rp, value);
583bfb62e91SGregory Neil Shapiro 	h->h_flags = flags;
584bfb62e91SGregory Neil Shapiro 	if (s != NULL)
585bfb62e91SGregory Neil Shapiro 		h->h_flags |= s->s_header.hi_flags;
586bfb62e91SGregory Neil Shapiro 	clrbitmap(h->h_mflags);
587bfb62e91SGregory Neil Shapiro 	h->h_macro = '\0';
588bfb62e91SGregory Neil Shapiro 
589bfb62e91SGregory Neil Shapiro 	return h;
590bfb62e91SGregory Neil Shapiro }
591951742c4SGregory Neil Shapiro 
592bfb62e91SGregory Neil Shapiro /*
593c2aa98e2SPeter Wemm **  ADDHEADER -- add a header entry to the end of the queue.
594c2aa98e2SPeter Wemm **
595c2aa98e2SPeter Wemm **	This bypasses the special checking of chompheader.
596c2aa98e2SPeter Wemm **
597c2aa98e2SPeter Wemm **	Parameters:
598951742c4SGregory Neil Shapiro **		field -- the name of the header field (will not be copied).
599951742c4SGregory Neil Shapiro **		value -- the value of the field (will be copied).
6003299c2f1SGregory Neil Shapiro **		flags -- flags to add to h_flags.
60112ed1c7cSGregory Neil Shapiro **		e -- envelope.
602951742c4SGregory Neil Shapiro **		space -- add leading space?
603c2aa98e2SPeter Wemm **
604c2aa98e2SPeter Wemm **	Returns:
605c2aa98e2SPeter Wemm **		none.
606c2aa98e2SPeter Wemm **
607c2aa98e2SPeter Wemm **	Side Effects:
608c2aa98e2SPeter Wemm **		adds the field on the list of headers for this envelope.
609951742c4SGregory Neil Shapiro **
610951742c4SGregory Neil Shapiro **	Notes: field and value must be in internal format, i.e.,
611951742c4SGregory Neil Shapiro **		metacharacters must be "quoted", see quote_internal_chars().
612c2aa98e2SPeter Wemm */
613c2aa98e2SPeter Wemm 
614c2aa98e2SPeter Wemm void
615951742c4SGregory Neil Shapiro addheader(field, value, flags, e, space)
616c2aa98e2SPeter Wemm 	char *field;
617c2aa98e2SPeter Wemm 	char *value;
6183299c2f1SGregory Neil Shapiro 	int flags;
61912ed1c7cSGregory Neil Shapiro 	ENVELOPE *e;
620951742c4SGregory Neil Shapiro 	bool space;
621c2aa98e2SPeter Wemm {
622c2aa98e2SPeter Wemm 	register HDR *h;
623c2aa98e2SPeter Wemm 	HDR **hp;
62412ed1c7cSGregory Neil Shapiro 	HDR **hdrlist = &e->e_header;
625c2aa98e2SPeter Wemm 
626c2aa98e2SPeter Wemm 	/* find current place in list -- keep back pointer? */
627c2aa98e2SPeter Wemm 	for (hp = hdrlist; (h = *hp) != NULL; hp = &h->h_link)
628c2aa98e2SPeter Wemm 	{
62912ed1c7cSGregory Neil Shapiro 		if (sm_strcasecmp(field, h->h_field) == 0)
630c2aa98e2SPeter Wemm 			break;
631c2aa98e2SPeter Wemm 	}
632c2aa98e2SPeter Wemm 
633c2aa98e2SPeter Wemm 	/* allocate space for new header */
634951742c4SGregory Neil Shapiro 	h = allocheader(field, value, flags, e->e_rpool, space);
635c2aa98e2SPeter Wemm 	h->h_link = *hp;
636c2aa98e2SPeter Wemm 	*hp = h;
637c2aa98e2SPeter Wemm }
638951742c4SGregory Neil Shapiro 
63912ed1c7cSGregory Neil Shapiro /*
640bfb62e91SGregory Neil Shapiro **  INSHEADER -- insert a header entry at the specified index
641bfb62e91SGregory Neil Shapiro **	This bypasses the special checking of chompheader.
642bfb62e91SGregory Neil Shapiro **
643bfb62e91SGregory Neil Shapiro **	Parameters:
644bfb62e91SGregory Neil Shapiro **		idx -- index into the header list at which to insert
645951742c4SGregory Neil Shapiro **		field -- the name of the header field (will be copied).
646951742c4SGregory Neil Shapiro **		value -- the value of the field (will be copied).
647bfb62e91SGregory Neil Shapiro **		flags -- flags to add to h_flags.
648bfb62e91SGregory Neil Shapiro **		e -- envelope.
649951742c4SGregory Neil Shapiro **		space -- add leading space?
650bfb62e91SGregory Neil Shapiro **
651bfb62e91SGregory Neil Shapiro **	Returns:
652bfb62e91SGregory Neil Shapiro **		none.
653bfb62e91SGregory Neil Shapiro **
654bfb62e91SGregory Neil Shapiro **	Side Effects:
655bfb62e91SGregory Neil Shapiro **		inserts the field on the list of headers for this envelope.
656951742c4SGregory Neil Shapiro **
657951742c4SGregory Neil Shapiro **	Notes:
658951742c4SGregory Neil Shapiro **		- field and value must be in internal format, i.e.,
659951742c4SGregory Neil Shapiro **		metacharacters must be "quoted", see quote_internal_chars().
660951742c4SGregory Neil Shapiro **		- the header list contains headers that might not be
661951742c4SGregory Neil Shapiro **		sent "out" (see putheader(): "skip"), hence there is no
662951742c4SGregory Neil Shapiro **		reliable way to insert a header at an exact position
663951742c4SGregory Neil Shapiro **		(except at the front or end).
664bfb62e91SGregory Neil Shapiro */
665bfb62e91SGregory Neil Shapiro 
666bfb62e91SGregory Neil Shapiro void
667951742c4SGregory Neil Shapiro insheader(idx, field, value, flags, e, space)
668bfb62e91SGregory Neil Shapiro 	int idx;
669bfb62e91SGregory Neil Shapiro 	char *field;
670bfb62e91SGregory Neil Shapiro 	char *value;
671bfb62e91SGregory Neil Shapiro 	int flags;
672bfb62e91SGregory Neil Shapiro 	ENVELOPE *e;
673951742c4SGregory Neil Shapiro 	bool space;
674bfb62e91SGregory Neil Shapiro {
675bfb62e91SGregory Neil Shapiro 	HDR *h, *srch, *last = NULL;
676bfb62e91SGregory Neil Shapiro 
677bfb62e91SGregory Neil Shapiro 	/* allocate space for new header */
678951742c4SGregory Neil Shapiro 	h = allocheader(field, value, flags, e->e_rpool, space);
679bfb62e91SGregory Neil Shapiro 
680bfb62e91SGregory Neil Shapiro 	/* find insertion position */
681bfb62e91SGregory Neil Shapiro 	for (srch = e->e_header; srch != NULL && idx > 0;
682bfb62e91SGregory Neil Shapiro 	     srch = srch->h_link, idx--)
683bfb62e91SGregory Neil Shapiro 		last = srch;
684bfb62e91SGregory Neil Shapiro 
685bfb62e91SGregory Neil Shapiro 	if (e->e_header == NULL)
686bfb62e91SGregory Neil Shapiro 	{
687bfb62e91SGregory Neil Shapiro 		e->e_header = h;
688bfb62e91SGregory Neil Shapiro 		h->h_link = NULL;
689bfb62e91SGregory Neil Shapiro 	}
690bfb62e91SGregory Neil Shapiro 	else if (srch == NULL)
691bfb62e91SGregory Neil Shapiro 	{
692bfb62e91SGregory Neil Shapiro 		SM_ASSERT(last != NULL);
693bfb62e91SGregory Neil Shapiro 		last->h_link = h;
694bfb62e91SGregory Neil Shapiro 		h->h_link = NULL;
695bfb62e91SGregory Neil Shapiro 	}
696bfb62e91SGregory Neil Shapiro 	else
697bfb62e91SGregory Neil Shapiro 	{
698bfb62e91SGregory Neil Shapiro 		h->h_link = srch->h_link;
699bfb62e91SGregory Neil Shapiro 		srch->h_link = h;
700bfb62e91SGregory Neil Shapiro 	}
701bfb62e91SGregory Neil Shapiro }
702951742c4SGregory Neil Shapiro 
703bfb62e91SGregory Neil Shapiro /*
704c2aa98e2SPeter Wemm **  HVALUE -- return value of a header.
705c2aa98e2SPeter Wemm **
706c2aa98e2SPeter Wemm **	Only "real" fields (i.e., ones that have not been supplied
707c2aa98e2SPeter Wemm **	as a default) are used.
708c2aa98e2SPeter Wemm **
709c2aa98e2SPeter Wemm **	Parameters:
710c2aa98e2SPeter Wemm **		field -- the field name.
711c2aa98e2SPeter Wemm **		header -- the header list.
712c2aa98e2SPeter Wemm **
713c2aa98e2SPeter Wemm **	Returns:
714951742c4SGregory Neil Shapiro **		pointer to the value part (internal format).
715c2aa98e2SPeter Wemm **		NULL if not found.
716c2aa98e2SPeter Wemm **
717c2aa98e2SPeter Wemm **	Side Effects:
718c2aa98e2SPeter Wemm **		none.
719c2aa98e2SPeter Wemm */
720c2aa98e2SPeter Wemm 
721c2aa98e2SPeter Wemm char *
722c2aa98e2SPeter Wemm hvalue(field, header)
723c2aa98e2SPeter Wemm 	char *field;
724c2aa98e2SPeter Wemm 	HDR *header;
725c2aa98e2SPeter Wemm {
726c2aa98e2SPeter Wemm 	register HDR *h;
727c2aa98e2SPeter Wemm 
728c2aa98e2SPeter Wemm 	for (h = header; h != NULL; h = h->h_link)
729c2aa98e2SPeter Wemm 	{
730c2aa98e2SPeter Wemm 		if (!bitset(H_DEFAULT, h->h_flags) &&
73112ed1c7cSGregory Neil Shapiro 		    sm_strcasecmp(h->h_field, field) == 0)
7329bd497b8SGregory Neil Shapiro 		{
7339bd497b8SGregory Neil Shapiro 			char *s;
7349bd497b8SGregory Neil Shapiro 
7359bd497b8SGregory Neil Shapiro 			s = h->h_value;
7369bd497b8SGregory Neil Shapiro 			if (s == NULL)
7379bd497b8SGregory Neil Shapiro 				return NULL;
7389bd497b8SGregory Neil Shapiro 			while (isascii(*s) && isspace(*s))
7399bd497b8SGregory Neil Shapiro 				s++;
7409bd497b8SGregory Neil Shapiro 			return s;
7419bd497b8SGregory Neil Shapiro 		}
742c2aa98e2SPeter Wemm 	}
7433299c2f1SGregory Neil Shapiro 	return NULL;
744c2aa98e2SPeter Wemm }
745951742c4SGregory Neil Shapiro 
74612ed1c7cSGregory Neil Shapiro /*
747c2aa98e2SPeter Wemm **  ISHEADER -- predicate telling if argument is a header.
748c2aa98e2SPeter Wemm **
749c2aa98e2SPeter Wemm **	A line is a header if it has a single word followed by
750c2aa98e2SPeter Wemm **	optional white space followed by a colon.
751c2aa98e2SPeter Wemm **
752c2aa98e2SPeter Wemm **	Header fields beginning with two dashes, although technically
753c2aa98e2SPeter Wemm **	permitted by RFC822, are automatically rejected in order
754c2aa98e2SPeter Wemm **	to make MIME work out.  Without this we could have a technically
755c2aa98e2SPeter Wemm **	legal header such as ``--"foo:bar"'' that would also be a legal
756c2aa98e2SPeter Wemm **	MIME separator.
757c2aa98e2SPeter Wemm **
758c2aa98e2SPeter Wemm **	Parameters:
759c2aa98e2SPeter Wemm **		h -- string to check for possible headerness.
760c2aa98e2SPeter Wemm **
761c2aa98e2SPeter Wemm **	Returns:
76212ed1c7cSGregory Neil Shapiro **		true if h is a header.
76312ed1c7cSGregory Neil Shapiro **		false otherwise.
764c2aa98e2SPeter Wemm **
765c2aa98e2SPeter Wemm **	Side Effects:
766c2aa98e2SPeter Wemm **		none.
767c2aa98e2SPeter Wemm */
768c2aa98e2SPeter Wemm 
769c2aa98e2SPeter Wemm bool
770c2aa98e2SPeter Wemm isheader(h)
771c2aa98e2SPeter Wemm 	char *h;
772c2aa98e2SPeter Wemm {
773951742c4SGregory Neil Shapiro 	char *s;
774c2aa98e2SPeter Wemm 
775951742c4SGregory Neil Shapiro 	s = h;
776c2aa98e2SPeter Wemm 	if (s[0] == '-' && s[1] == '-')
77712ed1c7cSGregory Neil Shapiro 		return false;
778c2aa98e2SPeter Wemm 
779c2aa98e2SPeter Wemm 	while (*s > ' ' && *s != ':' && *s != '\0')
780c2aa98e2SPeter Wemm 		s++;
781c2aa98e2SPeter Wemm 
782c2aa98e2SPeter Wemm 	if (h == s)
78312ed1c7cSGregory Neil Shapiro 		return false;
784c2aa98e2SPeter Wemm 
785c2aa98e2SPeter Wemm 	/* following technically violates RFC822 */
786c2aa98e2SPeter Wemm 	while (isascii(*s) && isspace(*s))
787c2aa98e2SPeter Wemm 		s++;
788c2aa98e2SPeter Wemm 
789c2aa98e2SPeter Wemm 	return (*s == ':');
790c2aa98e2SPeter Wemm }
791951742c4SGregory Neil Shapiro 
79212ed1c7cSGregory Neil Shapiro /*
793c2aa98e2SPeter Wemm **  EATHEADER -- run through the stored header and extract info.
794c2aa98e2SPeter Wemm **
795c2aa98e2SPeter Wemm **	Parameters:
796c2aa98e2SPeter Wemm **		e -- the envelope to process.
797c2aa98e2SPeter Wemm **		full -- if set, do full processing (e.g., compute
798c2aa98e2SPeter Wemm **			message priority).  This should not be set
799c2aa98e2SPeter Wemm **			when reading a queue file because some info
800c2aa98e2SPeter Wemm **			needed to compute the priority is wrong.
80112ed1c7cSGregory Neil Shapiro **		log -- call logsender()?
802c2aa98e2SPeter Wemm **
803c2aa98e2SPeter Wemm **	Returns:
804c2aa98e2SPeter Wemm **		none.
805c2aa98e2SPeter Wemm **
806c2aa98e2SPeter Wemm **	Side Effects:
807c2aa98e2SPeter Wemm **		Sets a bunch of global variables from information
808c2aa98e2SPeter Wemm **			in the collected header.
809c2aa98e2SPeter Wemm */
810c2aa98e2SPeter Wemm 
811c2aa98e2SPeter Wemm void
81212ed1c7cSGregory Neil Shapiro eatheader(e, full, log)
813c2aa98e2SPeter Wemm 	register ENVELOPE *e;
814c2aa98e2SPeter Wemm 	bool full;
81512ed1c7cSGregory Neil Shapiro 	bool log;
816c2aa98e2SPeter Wemm {
817c2aa98e2SPeter Wemm 	register HDR *h;
818c2aa98e2SPeter Wemm 	register char *p;
819c2aa98e2SPeter Wemm 	int hopcnt = 0;
820c2aa98e2SPeter Wemm 	char buf[MAXLINE];
821c2aa98e2SPeter Wemm 
822c2aa98e2SPeter Wemm 	/*
823c2aa98e2SPeter Wemm 	**  Set up macros for possible expansion in headers.
824c2aa98e2SPeter Wemm 	*/
825c2aa98e2SPeter Wemm 
82612ed1c7cSGregory Neil Shapiro 	macdefine(&e->e_macro, A_PERM, 'f', e->e_sender);
82712ed1c7cSGregory Neil Shapiro 	macdefine(&e->e_macro, A_PERM, 'g', e->e_sender);
828c2aa98e2SPeter Wemm 	if (e->e_origrcpt != NULL && *e->e_origrcpt != '\0')
82912ed1c7cSGregory Neil Shapiro 		macdefine(&e->e_macro, A_PERM, 'u', e->e_origrcpt);
830c2aa98e2SPeter Wemm 	else
83112ed1c7cSGregory Neil Shapiro 		macdefine(&e->e_macro, A_PERM, 'u', NULL);
832c2aa98e2SPeter Wemm 
833c2aa98e2SPeter Wemm 	/* full name of from person */
834c2aa98e2SPeter Wemm 	p = hvalue("full-name", e->e_header);
835c2aa98e2SPeter Wemm 	if (p != NULL)
836c2aa98e2SPeter Wemm 	{
837c2aa98e2SPeter Wemm 		if (!rfc822_string(p))
838c2aa98e2SPeter Wemm 		{
839c2aa98e2SPeter Wemm 			/*
840c2aa98e2SPeter Wemm 			**  Quote a full name with special characters
841c2aa98e2SPeter Wemm 			**  as a comment so crackaddr() doesn't destroy
842c2aa98e2SPeter Wemm 			**  the name portion of the address.
843c2aa98e2SPeter Wemm 			*/
84412ed1c7cSGregory Neil Shapiro 
84512ed1c7cSGregory Neil Shapiro 			p = addquotes(p, e->e_rpool);
846c2aa98e2SPeter Wemm 		}
84712ed1c7cSGregory Neil Shapiro 		macdefine(&e->e_macro, A_PERM, 'x', p);
848c2aa98e2SPeter Wemm 	}
849c2aa98e2SPeter Wemm 
850c2aa98e2SPeter Wemm 	if (tTd(32, 1))
85112ed1c7cSGregory Neil Shapiro 		sm_dprintf("----- collected header -----\n");
85212ed1c7cSGregory Neil Shapiro 	e->e_msgid = NULL;
853c2aa98e2SPeter Wemm 	for (h = e->e_header; h != NULL; h = h->h_link)
854c2aa98e2SPeter Wemm 	{
855c2aa98e2SPeter Wemm 		if (tTd(32, 1))
85612ed1c7cSGregory Neil Shapiro 			sm_dprintf("%s:", h->h_field);
857c2aa98e2SPeter Wemm 		if (h->h_value == NULL)
858c2aa98e2SPeter Wemm 		{
859c2aa98e2SPeter Wemm 			if (tTd(32, 1))
86012ed1c7cSGregory Neil Shapiro 				sm_dprintf("<NULL>\n");
861c2aa98e2SPeter Wemm 			continue;
862c2aa98e2SPeter Wemm 		}
863c2aa98e2SPeter Wemm 
864c2aa98e2SPeter Wemm 		/* do early binding */
8653299c2f1SGregory Neil Shapiro 		if (bitset(H_DEFAULT, h->h_flags) &&
8663299c2f1SGregory Neil Shapiro 		    !bitset(H_BINDLATE, h->h_flags))
867c2aa98e2SPeter Wemm 		{
868c2aa98e2SPeter Wemm 			if (tTd(32, 1))
869c2aa98e2SPeter Wemm 			{
87012ed1c7cSGregory Neil Shapiro 				sm_dprintf("(");
871bfb62e91SGregory Neil Shapiro 				xputs(sm_debug_file(), h->h_value);
87212ed1c7cSGregory Neil Shapiro 				sm_dprintf(") ");
873c2aa98e2SPeter Wemm 			}
874951742c4SGregory Neil Shapiro 			expand(h->h_value, buf, sizeof(buf), e);
875951742c4SGregory Neil Shapiro 			if (buf[0] != '\0' &&
876951742c4SGregory Neil Shapiro 			    (buf[0] != ' ' || buf[1] != '\0'))
877c2aa98e2SPeter Wemm 			{
878c2aa98e2SPeter Wemm 				if (bitset(H_FROM, h->h_flags))
879f9218d3dSGregory Neil Shapiro 					expand(crackaddr(buf, e),
880951742c4SGregory Neil Shapiro 					       buf, sizeof(buf), e);
88112ed1c7cSGregory Neil Shapiro 				h->h_value = sm_rpool_strdup_x(e->e_rpool, buf);
882c2aa98e2SPeter Wemm 				h->h_flags &= ~H_DEFAULT;
883c2aa98e2SPeter Wemm 			}
884c2aa98e2SPeter Wemm 		}
885c2aa98e2SPeter Wemm 		if (tTd(32, 1))
886c2aa98e2SPeter Wemm 		{
887bfb62e91SGregory Neil Shapiro 			xputs(sm_debug_file(), h->h_value);
88812ed1c7cSGregory Neil Shapiro 			sm_dprintf("\n");
889c2aa98e2SPeter Wemm 		}
890c2aa98e2SPeter Wemm 
891c2aa98e2SPeter Wemm 		/* count the number of times it has been processed */
892c2aa98e2SPeter Wemm 		if (bitset(H_TRACE, h->h_flags))
893c2aa98e2SPeter Wemm 			hopcnt++;
894c2aa98e2SPeter Wemm 
895c2aa98e2SPeter Wemm 		/* send to this person if we so desire */
896c2aa98e2SPeter Wemm 		if (GrabTo && bitset(H_RCPT, h->h_flags) &&
897c2aa98e2SPeter Wemm 		    !bitset(H_DEFAULT, h->h_flags) &&
89812ed1c7cSGregory Neil Shapiro 		    (!bitset(EF_RESENT, e->e_flags) ||
89912ed1c7cSGregory Neil Shapiro 		     bitset(H_RESENT, h->h_flags)))
900c2aa98e2SPeter Wemm 		{
901c2aa98e2SPeter Wemm #if 0
902c2aa98e2SPeter Wemm 			int saveflags = e->e_flags;
9033299c2f1SGregory Neil Shapiro #endif /* 0 */
904c2aa98e2SPeter Wemm 
90512ed1c7cSGregory Neil Shapiro 			(void) sendtolist(denlstring(h->h_value, true, false),
90612ed1c7cSGregory Neil Shapiro 					  NULLADDR, &e->e_sendqueue, 0, e);
907c2aa98e2SPeter Wemm 
908c2aa98e2SPeter Wemm #if 0
909c2aa98e2SPeter Wemm 			/*
910c2aa98e2SPeter Wemm 			**  Change functionality so a fatal error on an
911c2aa98e2SPeter Wemm 			**  address doesn't affect the entire envelope.
912c2aa98e2SPeter Wemm 			*/
913c2aa98e2SPeter Wemm 
914c2aa98e2SPeter Wemm 			/* delete fatal errors generated by this address */
915c2aa98e2SPeter Wemm 			if (!bitset(EF_FATALERRS, saveflags))
916c2aa98e2SPeter Wemm 				e->e_flags &= ~EF_FATALERRS;
9173299c2f1SGregory Neil Shapiro #endif /* 0 */
918c2aa98e2SPeter Wemm 		}
919c2aa98e2SPeter Wemm 
920c2aa98e2SPeter Wemm 		/* save the message-id for logging */
921c2aa98e2SPeter Wemm 		p = "resent-message-id";
922c2aa98e2SPeter Wemm 		if (!bitset(EF_RESENT, e->e_flags))
923c2aa98e2SPeter Wemm 			p += 7;
92412ed1c7cSGregory Neil Shapiro 		if (sm_strcasecmp(h->h_field, p) == 0)
925c2aa98e2SPeter Wemm 		{
92612ed1c7cSGregory Neil Shapiro 			e->e_msgid = h->h_value;
92712ed1c7cSGregory Neil Shapiro 			while (isascii(*e->e_msgid) && isspace(*e->e_msgid))
92812ed1c7cSGregory Neil Shapiro 				e->e_msgid++;
9291ae5b8d4SGregory Neil Shapiro 			macdefine(&e->e_macro, A_PERM, macid("{msg_id}"),
9301ae5b8d4SGregory Neil Shapiro 				  e->e_msgid);
931c2aa98e2SPeter Wemm 		}
932c2aa98e2SPeter Wemm 	}
933c2aa98e2SPeter Wemm 	if (tTd(32, 1))
93412ed1c7cSGregory Neil Shapiro 		sm_dprintf("----------------------------\n");
935c2aa98e2SPeter Wemm 
936c2aa98e2SPeter Wemm 	/* if we are just verifying (that is, sendmail -t -bv), drop out now */
937c2aa98e2SPeter Wemm 	if (OpMode == MD_VERIFY)
938c2aa98e2SPeter Wemm 		return;
939c2aa98e2SPeter Wemm 
940c2aa98e2SPeter Wemm 	/* store hop count */
941c2aa98e2SPeter Wemm 	if (hopcnt > e->e_hopcount)
94212ed1c7cSGregory Neil Shapiro 	{
943c2aa98e2SPeter Wemm 		e->e_hopcount = hopcnt;
944951742c4SGregory Neil Shapiro 		(void) sm_snprintf(buf, sizeof(buf), "%d", e->e_hopcount);
94512ed1c7cSGregory Neil Shapiro 		macdefine(&e->e_macro, A_TEMP, 'c', buf);
94612ed1c7cSGregory Neil Shapiro 	}
947c2aa98e2SPeter Wemm 
948c2aa98e2SPeter Wemm 	/* message priority */
949c2aa98e2SPeter Wemm 	p = hvalue("precedence", e->e_header);
950c2aa98e2SPeter Wemm 	if (p != NULL)
951c2aa98e2SPeter Wemm 		e->e_class = priencode(p);
952c2aa98e2SPeter Wemm 	if (e->e_class < 0)
953c2aa98e2SPeter Wemm 		e->e_timeoutclass = TOC_NONURGENT;
954c2aa98e2SPeter Wemm 	else if (e->e_class > 0)
955c2aa98e2SPeter Wemm 		e->e_timeoutclass = TOC_URGENT;
956c2aa98e2SPeter Wemm 	if (full)
957c2aa98e2SPeter Wemm 	{
958c2aa98e2SPeter Wemm 		e->e_msgpriority = e->e_msgsize
959c2aa98e2SPeter Wemm 				 - e->e_class * WkClassFact
960c2aa98e2SPeter Wemm 				 + e->e_nrcpts * WkRecipFact;
961c2aa98e2SPeter Wemm 	}
962c2aa98e2SPeter Wemm 
963bfb62e91SGregory Neil Shapiro 	/* check for DSN to properly set e_timeoutclass */
964bfb62e91SGregory Neil Shapiro 	p = hvalue("content-type", e->e_header);
965bfb62e91SGregory Neil Shapiro 	if (p != NULL)
966bfb62e91SGregory Neil Shapiro 	{
967bfb62e91SGregory Neil Shapiro 		bool oldsupr;
968bfb62e91SGregory Neil Shapiro 		char **pvp;
969bfb62e91SGregory Neil Shapiro 		char pvpbuf[MAXLINE];
970bfb62e91SGregory Neil Shapiro 		extern unsigned char MimeTokenTab[256];
971bfb62e91SGregory Neil Shapiro 
972bfb62e91SGregory Neil Shapiro 		/* tokenize header */
973bfb62e91SGregory Neil Shapiro 		oldsupr = SuprErrs;
974bfb62e91SGregory Neil Shapiro 		SuprErrs = true;
975951742c4SGregory Neil Shapiro 		pvp = prescan(p, '\0', pvpbuf, sizeof(pvpbuf), NULL,
976bfb62e91SGregory Neil Shapiro 			      MimeTokenTab, false);
977bfb62e91SGregory Neil Shapiro 		SuprErrs = oldsupr;
978bfb62e91SGregory Neil Shapiro 
979bfb62e91SGregory Neil Shapiro 		/* Check if multipart/report */
980bfb62e91SGregory Neil Shapiro 		if (pvp != NULL && pvp[0] != NULL &&
981bfb62e91SGregory Neil Shapiro 		    pvp[1] != NULL && pvp[2] != NULL &&
982bfb62e91SGregory Neil Shapiro 		    sm_strcasecmp(*pvp++, "multipart") == 0 &&
983bfb62e91SGregory Neil Shapiro 		    strcmp(*pvp++, "/") == 0 &&
984bfb62e91SGregory Neil Shapiro 		    sm_strcasecmp(*pvp++, "report") == 0)
985bfb62e91SGregory Neil Shapiro 		{
986bfb62e91SGregory Neil Shapiro 			/* Look for report-type=delivery-status */
987bfb62e91SGregory Neil Shapiro 			while (*pvp != NULL)
988bfb62e91SGregory Neil Shapiro 			{
989bfb62e91SGregory Neil Shapiro 				/* skip to semicolon separator */
990bfb62e91SGregory Neil Shapiro 				while (*pvp != NULL && strcmp(*pvp, ";") != 0)
991bfb62e91SGregory Neil Shapiro 					pvp++;
992bfb62e91SGregory Neil Shapiro 
993bfb62e91SGregory Neil Shapiro 				/* skip semicolon */
994bfb62e91SGregory Neil Shapiro 				if (*pvp++ == NULL || *pvp == NULL)
995bfb62e91SGregory Neil Shapiro 					break;
996bfb62e91SGregory Neil Shapiro 
997bfb62e91SGregory Neil Shapiro 				/* look for report-type */
998bfb62e91SGregory Neil Shapiro 				if (sm_strcasecmp(*pvp++, "report-type") != 0)
999bfb62e91SGregory Neil Shapiro 					continue;
1000bfb62e91SGregory Neil Shapiro 
1001bfb62e91SGregory Neil Shapiro 				/* skip equal */
1002bfb62e91SGregory Neil Shapiro 				if (*pvp == NULL || strcmp(*pvp, "=") != 0)
1003bfb62e91SGregory Neil Shapiro 					continue;
1004bfb62e91SGregory Neil Shapiro 
1005bfb62e91SGregory Neil Shapiro 				/* check value */
1006bfb62e91SGregory Neil Shapiro 				if (*++pvp != NULL &&
1007bfb62e91SGregory Neil Shapiro 				    sm_strcasecmp(*pvp,
1008bfb62e91SGregory Neil Shapiro 						  "delivery-status") == 0)
1009bfb62e91SGregory Neil Shapiro 					e->e_timeoutclass = TOC_DSN;
1010bfb62e91SGregory Neil Shapiro 
1011bfb62e91SGregory Neil Shapiro 				/* found report-type, no need to continue */
1012bfb62e91SGregory Neil Shapiro 				break;
1013bfb62e91SGregory Neil Shapiro 			}
1014bfb62e91SGregory Neil Shapiro 		}
1015bfb62e91SGregory Neil Shapiro 	}
1016bfb62e91SGregory Neil Shapiro 
1017c2aa98e2SPeter Wemm 	/* message timeout priority */
1018c2aa98e2SPeter Wemm 	p = hvalue("priority", e->e_header);
1019c2aa98e2SPeter Wemm 	if (p != NULL)
1020c2aa98e2SPeter Wemm 	{
1021c2aa98e2SPeter Wemm 		/* (this should be in the configuration file) */
102212ed1c7cSGregory Neil Shapiro 		if (sm_strcasecmp(p, "urgent") == 0)
1023c2aa98e2SPeter Wemm 			e->e_timeoutclass = TOC_URGENT;
102412ed1c7cSGregory Neil Shapiro 		else if (sm_strcasecmp(p, "normal") == 0)
1025c2aa98e2SPeter Wemm 			e->e_timeoutclass = TOC_NORMAL;
102612ed1c7cSGregory Neil Shapiro 		else if (sm_strcasecmp(p, "non-urgent") == 0)
1027c2aa98e2SPeter Wemm 			e->e_timeoutclass = TOC_NONURGENT;
10281ae5b8d4SGregory Neil Shapiro 		else if (bitset(EF_RESPONSE, e->e_flags))
10291ae5b8d4SGregory Neil Shapiro 			e->e_timeoutclass = TOC_DSN;
10301ae5b8d4SGregory Neil Shapiro 	}
10311ae5b8d4SGregory Neil Shapiro 	else if (bitset(EF_RESPONSE, e->e_flags))
103272936242SGregory Neil Shapiro 		e->e_timeoutclass = TOC_DSN;
103372936242SGregory Neil Shapiro 
1034c2aa98e2SPeter Wemm 	/* date message originated */
1035c2aa98e2SPeter Wemm 	p = hvalue("posted-date", e->e_header);
1036c2aa98e2SPeter Wemm 	if (p == NULL)
1037c2aa98e2SPeter Wemm 		p = hvalue("date", e->e_header);
1038c2aa98e2SPeter Wemm 	if (p != NULL)
103912ed1c7cSGregory Neil Shapiro 		macdefine(&e->e_macro, A_PERM, 'a', p);
1040c2aa98e2SPeter Wemm 
1041c2aa98e2SPeter Wemm 	/* check to see if this is a MIME message */
1042c2aa98e2SPeter Wemm 	if ((e->e_bodytype != NULL &&
104312ed1c7cSGregory Neil Shapiro 	     sm_strcasecmp(e->e_bodytype, "8BITMIME") == 0) ||
1044c2aa98e2SPeter Wemm 	    hvalue("MIME-Version", e->e_header) != NULL)
1045c2aa98e2SPeter Wemm 	{
1046c2aa98e2SPeter Wemm 		e->e_flags |= EF_IS_MIME;
1047c2aa98e2SPeter Wemm 		if (HasEightBits)
1048c2aa98e2SPeter Wemm 			e->e_bodytype = "8BITMIME";
1049c2aa98e2SPeter Wemm 	}
1050c2aa98e2SPeter Wemm 	else if ((p = hvalue("Content-Type", e->e_header)) != NULL)
1051c2aa98e2SPeter Wemm 	{
1052c2aa98e2SPeter Wemm 		/* this may be an RFC 1049 message */
1053c2aa98e2SPeter Wemm 		p = strpbrk(p, ";/");
1054c2aa98e2SPeter Wemm 		if (p == NULL || *p == ';')
1055c2aa98e2SPeter Wemm 		{
1056c2aa98e2SPeter Wemm 			/* yep, it is */
1057c2aa98e2SPeter Wemm 			e->e_flags |= EF_DONT_MIME;
1058c2aa98e2SPeter Wemm 		}
1059c2aa98e2SPeter Wemm 	}
1060c2aa98e2SPeter Wemm 
1061c2aa98e2SPeter Wemm 	/*
1062c2aa98e2SPeter Wemm 	**  From person in antiquated ARPANET mode
1063c2aa98e2SPeter Wemm 	**	required by UK Grey Book e-mail gateways (sigh)
1064c2aa98e2SPeter Wemm 	*/
1065c2aa98e2SPeter Wemm 
1066c2aa98e2SPeter Wemm 	if (OpMode == MD_ARPAFTP)
1067c2aa98e2SPeter Wemm 	{
1068c2aa98e2SPeter Wemm 		register struct hdrinfo *hi;
1069c2aa98e2SPeter Wemm 
1070c2aa98e2SPeter Wemm 		for (hi = HdrInfo; hi->hi_field != NULL; hi++)
1071c2aa98e2SPeter Wemm 		{
1072c2aa98e2SPeter Wemm 			if (bitset(H_FROM, hi->hi_flags) &&
1073c2aa98e2SPeter Wemm 			    (!bitset(H_RESENT, hi->hi_flags) ||
1074c2aa98e2SPeter Wemm 			     bitset(EF_RESENT, e->e_flags)) &&
1075c2aa98e2SPeter Wemm 			    (p = hvalue(hi->hi_field, e->e_header)) != NULL)
1076c2aa98e2SPeter Wemm 				break;
1077c2aa98e2SPeter Wemm 		}
1078c2aa98e2SPeter Wemm 		if (hi->hi_field != NULL)
1079c2aa98e2SPeter Wemm 		{
1080c2aa98e2SPeter Wemm 			if (tTd(32, 2))
108112ed1c7cSGregory Neil Shapiro 				sm_dprintf("eatheader: setsender(*%s == %s)\n",
1082c2aa98e2SPeter Wemm 					hi->hi_field, p);
108312ed1c7cSGregory Neil Shapiro 			setsender(p, e, NULL, '\0', true);
1084c2aa98e2SPeter Wemm 		}
1085c2aa98e2SPeter Wemm 	}
1086c2aa98e2SPeter Wemm 
1087c2aa98e2SPeter Wemm 	/*
1088c2aa98e2SPeter Wemm 	**  Log collection information.
1089c2aa98e2SPeter Wemm 	*/
1090c2aa98e2SPeter Wemm 
10919bd497b8SGregory Neil Shapiro 	if (tTd(92, 2))
10929bd497b8SGregory Neil Shapiro 		sm_dprintf("eatheader: e_id=%s, EF_LOGSENDER=%d, LogLevel=%d, log=%d\n",
10939bd497b8SGregory Neil Shapiro 			e->e_id, bitset(EF_LOGSENDER, e->e_flags), LogLevel,
10949bd497b8SGregory Neil Shapiro 			log);
109512ed1c7cSGregory Neil Shapiro 	if (log && bitset(EF_LOGSENDER, e->e_flags) && LogLevel > 4)
109612ed1c7cSGregory Neil Shapiro 	{
109712ed1c7cSGregory Neil Shapiro 		logsender(e, e->e_msgid);
1098c2aa98e2SPeter Wemm 		e->e_flags &= ~EF_LOGSENDER;
1099c2aa98e2SPeter Wemm 	}
110012ed1c7cSGregory Neil Shapiro }
1101951742c4SGregory Neil Shapiro 
110212ed1c7cSGregory Neil Shapiro /*
1103c2aa98e2SPeter Wemm **  LOGSENDER -- log sender information
1104c2aa98e2SPeter Wemm **
1105c2aa98e2SPeter Wemm **	Parameters:
1106c2aa98e2SPeter Wemm **		e -- the envelope to log
1107c2aa98e2SPeter Wemm **		msgid -- the message id
1108c2aa98e2SPeter Wemm **
1109c2aa98e2SPeter Wemm **	Returns:
1110c2aa98e2SPeter Wemm **		none
1111c2aa98e2SPeter Wemm */
1112c2aa98e2SPeter Wemm 
1113c2aa98e2SPeter Wemm void
1114c2aa98e2SPeter Wemm logsender(e, msgid)
1115c2aa98e2SPeter Wemm 	register ENVELOPE *e;
1116c2aa98e2SPeter Wemm 	char *msgid;
1117c2aa98e2SPeter Wemm {
1118c2aa98e2SPeter Wemm 	char *name;
1119c2aa98e2SPeter Wemm 	register char *sbp;
1120c2aa98e2SPeter Wemm 	register char *p;
1121c2aa98e2SPeter Wemm 	char hbuf[MAXNAME + 1];
1122c2aa98e2SPeter Wemm 	char sbuf[MAXLINE + 1];
1123c2aa98e2SPeter Wemm 	char mbuf[MAXNAME + 1];
1124c2aa98e2SPeter Wemm 
1125c2aa98e2SPeter Wemm 	/* don't allow newlines in the message-id */
112612ed1c7cSGregory Neil Shapiro 	/* XXX do we still need this? sm_syslog() replaces control chars */
1127c2aa98e2SPeter Wemm 	if (msgid != NULL)
1128c2aa98e2SPeter Wemm 	{
1129567a2fc9SGregory Neil Shapiro 		size_t l;
1130567a2fc9SGregory Neil Shapiro 
1131c2aa98e2SPeter Wemm 		l = strlen(msgid);
1132951742c4SGregory Neil Shapiro 		if (l > sizeof(mbuf) - 1)
1133951742c4SGregory Neil Shapiro 			l = sizeof(mbuf) - 1;
11343299c2f1SGregory Neil Shapiro 		memmove(mbuf, msgid, l);
1135c2aa98e2SPeter Wemm 		mbuf[l] = '\0';
1136c2aa98e2SPeter Wemm 		p = mbuf;
1137c2aa98e2SPeter Wemm 		while ((p = strchr(p, '\n')) != NULL)
1138c2aa98e2SPeter Wemm 			*p++ = ' ';
1139c2aa98e2SPeter Wemm 	}
1140c2aa98e2SPeter Wemm 
1141c2aa98e2SPeter Wemm 	if (bitset(EF_RESPONSE, e->e_flags))
1142c2aa98e2SPeter Wemm 		name = "[RESPONSE]";
1143c2aa98e2SPeter Wemm 	else if ((name = macvalue('_', e)) != NULL)
11443299c2f1SGregory Neil Shapiro 		/* EMPTY */
1145c2aa98e2SPeter Wemm 		;
1146c2aa98e2SPeter Wemm 	else if (RealHostName == NULL)
1147c2aa98e2SPeter Wemm 		name = "localhost";
1148c2aa98e2SPeter Wemm 	else if (RealHostName[0] == '[')
1149c2aa98e2SPeter Wemm 		name = RealHostName;
1150c2aa98e2SPeter Wemm 	else
1151c2aa98e2SPeter Wemm 	{
1152c2aa98e2SPeter Wemm 		name = hbuf;
1153951742c4SGregory Neil Shapiro 		(void) sm_snprintf(hbuf, sizeof(hbuf), "%.80s", RealHostName);
1154c2aa98e2SPeter Wemm 		if (RealHostAddr.sa.sa_family != 0)
1155c2aa98e2SPeter Wemm 		{
1156c2aa98e2SPeter Wemm 			p = &hbuf[strlen(hbuf)];
115712ed1c7cSGregory Neil Shapiro 			(void) sm_snprintf(p, SPACELEFT(hbuf, p),
115812ed1c7cSGregory Neil Shapiro 					   " (%.100s)",
1159c2aa98e2SPeter Wemm 					   anynet_ntoa(&RealHostAddr));
1160c2aa98e2SPeter Wemm 		}
1161c2aa98e2SPeter Wemm 	}
1162c2aa98e2SPeter Wemm 
1163c2aa98e2SPeter Wemm 	/* some versions of syslog only take 5 printf args */
1164c2aa98e2SPeter Wemm #if (SYSLOG_BUFSIZE) >= 256
1165c2aa98e2SPeter Wemm 	sbp = sbuf;
116612ed1c7cSGregory Neil Shapiro 	(void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp),
11673299c2f1SGregory Neil Shapiro 		"from=%.200s, size=%ld, class=%d, nrcpts=%d",
1168c2aa98e2SPeter Wemm 		e->e_from.q_paddr == NULL ? "<NONE>" : e->e_from.q_paddr,
1169ba00ec3dSGregory Neil Shapiro 		PRT_NONNEGL(e->e_msgsize), e->e_class, e->e_nrcpts);
1170c2aa98e2SPeter Wemm 	sbp += strlen(sbp);
1171c2aa98e2SPeter Wemm 	if (msgid != NULL)
1172c2aa98e2SPeter Wemm 	{
117312ed1c7cSGregory Neil Shapiro 		(void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp),
117412ed1c7cSGregory Neil Shapiro 				", msgid=%.100s", mbuf);
1175c2aa98e2SPeter Wemm 		sbp += strlen(sbp);
1176c2aa98e2SPeter Wemm 	}
1177c2aa98e2SPeter Wemm 	if (e->e_bodytype != NULL)
1178c2aa98e2SPeter Wemm 	{
117912ed1c7cSGregory Neil Shapiro 		(void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp),
118012ed1c7cSGregory Neil Shapiro 				", bodytype=%.20s", e->e_bodytype);
1181c2aa98e2SPeter Wemm 		sbp += strlen(sbp);
1182c2aa98e2SPeter Wemm 	}
1183c2aa98e2SPeter Wemm 	p = macvalue('r', e);
1184c2aa98e2SPeter Wemm 	if (p != NULL)
11853299c2f1SGregory Neil Shapiro 	{
118612ed1c7cSGregory Neil Shapiro 		(void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp),
118712ed1c7cSGregory Neil Shapiro 				", proto=%.20s", p);
11883299c2f1SGregory Neil Shapiro 		sbp += strlen(sbp);
11893299c2f1SGregory Neil Shapiro 	}
119012ed1c7cSGregory Neil Shapiro 	p = macvalue(macid("{daemon_name}"), e);
11913299c2f1SGregory Neil Shapiro 	if (p != NULL)
11923299c2f1SGregory Neil Shapiro 	{
119312ed1c7cSGregory Neil Shapiro 		(void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp),
119412ed1c7cSGregory Neil Shapiro 				", daemon=%.20s", p);
11953299c2f1SGregory Neil Shapiro 		sbp += strlen(sbp);
11963299c2f1SGregory Neil Shapiro 	}
11972ef40764SGregory Neil Shapiro 	sm_syslog(LOG_INFO, e->e_id, "%.850s, relay=%s", sbuf, name);
1198c2aa98e2SPeter Wemm 
11993299c2f1SGregory Neil Shapiro #else /* (SYSLOG_BUFSIZE) >= 256 */
1200c2aa98e2SPeter Wemm 
1201c2aa98e2SPeter Wemm 	sm_syslog(LOG_INFO, e->e_id,
1202c2aa98e2SPeter Wemm 		  "from=%s",
1203c2aa98e2SPeter Wemm 		  e->e_from.q_paddr == NULL ? "<NONE>"
120412ed1c7cSGregory Neil Shapiro 					    : shortenstring(e->e_from.q_paddr,
120512ed1c7cSGregory Neil Shapiro 							    83));
1206c2aa98e2SPeter Wemm 	sm_syslog(LOG_INFO, e->e_id,
12073299c2f1SGregory Neil Shapiro 		  "size=%ld, class=%ld, nrcpts=%d",
1208ba00ec3dSGregory Neil Shapiro 		  PRT_NONNEGL(e->e_msgsize), e->e_class, e->e_nrcpts);
1209c2aa98e2SPeter Wemm 	if (msgid != NULL)
1210c2aa98e2SPeter Wemm 		sm_syslog(LOG_INFO, e->e_id,
1211c2aa98e2SPeter Wemm 			  "msgid=%s",
1212c2aa98e2SPeter Wemm 			  shortenstring(mbuf, 83));
1213c2aa98e2SPeter Wemm 	sbp = sbuf;
1214c2aa98e2SPeter Wemm 	*sbp = '\0';
1215c2aa98e2SPeter Wemm 	if (e->e_bodytype != NULL)
1216c2aa98e2SPeter Wemm 	{
121712ed1c7cSGregory Neil Shapiro 		(void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp),
121812ed1c7cSGregory Neil Shapiro 				"bodytype=%.20s, ", e->e_bodytype);
1219c2aa98e2SPeter Wemm 		sbp += strlen(sbp);
1220c2aa98e2SPeter Wemm 	}
1221c2aa98e2SPeter Wemm 	p = macvalue('r', e);
1222c2aa98e2SPeter Wemm 	if (p != NULL)
1223c2aa98e2SPeter Wemm 	{
122412ed1c7cSGregory Neil Shapiro 		(void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp),
122512ed1c7cSGregory Neil Shapiro 				"proto=%.20s, ", p);
1226c2aa98e2SPeter Wemm 		sbp += strlen(sbp);
1227c2aa98e2SPeter Wemm 	}
1228c2aa98e2SPeter Wemm 	sm_syslog(LOG_INFO, e->e_id,
12292ef40764SGregory Neil Shapiro 		  "%.400srelay=%s", sbuf, name);
12303299c2f1SGregory Neil Shapiro #endif /* (SYSLOG_BUFSIZE) >= 256 */
1231c2aa98e2SPeter Wemm }
1232951742c4SGregory Neil Shapiro 
123312ed1c7cSGregory Neil Shapiro /*
1234c2aa98e2SPeter Wemm **  PRIENCODE -- encode external priority names into internal values.
1235c2aa98e2SPeter Wemm **
1236c2aa98e2SPeter Wemm **	Parameters:
1237c2aa98e2SPeter Wemm **		p -- priority in ascii.
1238c2aa98e2SPeter Wemm **
1239c2aa98e2SPeter Wemm **	Returns:
1240c2aa98e2SPeter Wemm **		priority as a numeric level.
1241c2aa98e2SPeter Wemm **
1242c2aa98e2SPeter Wemm **	Side Effects:
1243c2aa98e2SPeter Wemm **		none.
1244c2aa98e2SPeter Wemm */
1245c2aa98e2SPeter Wemm 
12463299c2f1SGregory Neil Shapiro static int
1247c2aa98e2SPeter Wemm priencode(p)
1248c2aa98e2SPeter Wemm 	char *p;
1249c2aa98e2SPeter Wemm {
1250c2aa98e2SPeter Wemm 	register int i;
1251c2aa98e2SPeter Wemm 
1252c2aa98e2SPeter Wemm 	for (i = 0; i < NumPriorities; i++)
1253c2aa98e2SPeter Wemm 	{
125412ed1c7cSGregory Neil Shapiro 		if (sm_strcasecmp(p, Priorities[i].pri_name) == 0)
12553299c2f1SGregory Neil Shapiro 			return Priorities[i].pri_val;
1256c2aa98e2SPeter Wemm 	}
1257c2aa98e2SPeter Wemm 
1258c2aa98e2SPeter Wemm 	/* unknown priority */
12593299c2f1SGregory Neil Shapiro 	return 0;
1260c2aa98e2SPeter Wemm }
1261951742c4SGregory Neil Shapiro 
126212ed1c7cSGregory Neil Shapiro /*
1263c2aa98e2SPeter Wemm **  CRACKADDR -- parse an address and turn it into a macro
1264c2aa98e2SPeter Wemm **
1265c2aa98e2SPeter Wemm **	This doesn't actually parse the address -- it just extracts
1266c2aa98e2SPeter Wemm **	it and replaces it with "$g".  The parse is totally ad hoc
1267c2aa98e2SPeter Wemm **	and isn't even guaranteed to leave something syntactically
1268c2aa98e2SPeter Wemm **	identical to what it started with.  However, it does leave
1269f9218d3dSGregory Neil Shapiro **	something semantically identical if possible, else at least
1270f9218d3dSGregory Neil Shapiro **	syntactically correct.
1271f9218d3dSGregory Neil Shapiro **
1272f9218d3dSGregory Neil Shapiro **	For example, it changes "Real Name <real@example.com> (Comment)"
1273f9218d3dSGregory Neil Shapiro **	to "Real Name <$g> (Comment)".
1274c2aa98e2SPeter Wemm **
1275c2aa98e2SPeter Wemm **	This algorithm has been cleaned up to handle a wider range
1276c2aa98e2SPeter Wemm **	of cases -- notably quoted and backslash escaped strings.
1277c2aa98e2SPeter Wemm **	This modification makes it substantially better at preserving
1278c2aa98e2SPeter Wemm **	the original syntax.
1279c2aa98e2SPeter Wemm **
1280c2aa98e2SPeter Wemm **	Parameters:
1281c2aa98e2SPeter Wemm **		addr -- the address to be cracked.
1282f9218d3dSGregory Neil Shapiro **		e -- the current envelope.
1283c2aa98e2SPeter Wemm **
1284c2aa98e2SPeter Wemm **	Returns:
1285c2aa98e2SPeter Wemm **		a pointer to the new version.
1286c2aa98e2SPeter Wemm **
1287c2aa98e2SPeter Wemm **	Side Effects:
1288c2aa98e2SPeter Wemm **		none.
1289c2aa98e2SPeter Wemm **
1290c2aa98e2SPeter Wemm **	Warning:
1291c2aa98e2SPeter Wemm **		The return value is saved in local storage and should
1292c2aa98e2SPeter Wemm **		be copied if it is to be reused.
1293c2aa98e2SPeter Wemm */
1294c2aa98e2SPeter Wemm 
1295f9218d3dSGregory Neil Shapiro #define SM_HAVE_ROOM		((bp < buflim) && (buflim <= bufend))
1296f9218d3dSGregory Neil Shapiro 
1297f9218d3dSGregory Neil Shapiro /*
1298f9218d3dSGregory Neil Shapiro **  Append a character to bp if we have room.
1299f9218d3dSGregory Neil Shapiro **  If not, punt and return $g.
1300f9218d3dSGregory Neil Shapiro */
1301f9218d3dSGregory Neil Shapiro 
1302f9218d3dSGregory Neil Shapiro #define SM_APPEND_CHAR(c)					\
1303f9218d3dSGregory Neil Shapiro 	do							\
1304f9218d3dSGregory Neil Shapiro 	{							\
1305f9218d3dSGregory Neil Shapiro 		if (SM_HAVE_ROOM)				\
1306f9218d3dSGregory Neil Shapiro 			*bp++ = (c);				\
1307f9218d3dSGregory Neil Shapiro 		else						\
1308f9218d3dSGregory Neil Shapiro 			goto returng;				\
1309f9218d3dSGregory Neil Shapiro 	} while (0)
1310f9218d3dSGregory Neil Shapiro 
1311f9218d3dSGregory Neil Shapiro #if MAXNAME < 10
1312f9218d3dSGregory Neil Shapiro ERROR MAXNAME must be at least 10
1313f9218d3dSGregory Neil Shapiro #endif /* MAXNAME < 10 */
1314f9218d3dSGregory Neil Shapiro 
1315c2aa98e2SPeter Wemm char *
1316f9218d3dSGregory Neil Shapiro crackaddr(addr, e)
1317c2aa98e2SPeter Wemm 	register char *addr;
1318f9218d3dSGregory Neil Shapiro 	ENVELOPE *e;
1319c2aa98e2SPeter Wemm {
1320c2aa98e2SPeter Wemm 	register char *p;
1321c2aa98e2SPeter Wemm 	register char c;
1322f9218d3dSGregory Neil Shapiro 	int cmtlev;			/* comment level in input string */
1323f9218d3dSGregory Neil Shapiro 	int realcmtlev;			/* comment level in output string */
1324f9218d3dSGregory Neil Shapiro 	int anglelev;			/* angle level in input string */
1325f9218d3dSGregory Neil Shapiro 	int copylev;			/* 0 == in address, >0 copying */
1326f9218d3dSGregory Neil Shapiro 	int bracklev;			/* bracket level for IPv6 addr check */
1327f9218d3dSGregory Neil Shapiro 	bool addangle;			/* put closing angle in output */
1328f9218d3dSGregory Neil Shapiro 	bool qmode;			/* quoting in original string? */
1329f9218d3dSGregory Neil Shapiro 	bool realqmode;			/* quoting in output string? */
1330f9218d3dSGregory Neil Shapiro 	bool putgmac = false;		/* already wrote $g */
1331f9218d3dSGregory Neil Shapiro 	bool quoteit = false;		/* need to quote next character */
1332f9218d3dSGregory Neil Shapiro 	bool gotangle = false;		/* found first '<' */
1333f9218d3dSGregory Neil Shapiro 	bool gotcolon = false;		/* found a ':' */
1334c2aa98e2SPeter Wemm 	register char *bp;
1335c2aa98e2SPeter Wemm 	char *buflim;
1336c2aa98e2SPeter Wemm 	char *bufhead;
1337c2aa98e2SPeter Wemm 	char *addrhead;
1338f9218d3dSGregory Neil Shapiro 	char *bufend;
1339c2aa98e2SPeter Wemm 	static char buf[MAXNAME + 1];
1340c2aa98e2SPeter Wemm 
1341c2aa98e2SPeter Wemm 	if (tTd(33, 1))
134212ed1c7cSGregory Neil Shapiro 		sm_dprintf("crackaddr(%s)\n", addr);
1343c2aa98e2SPeter Wemm 
1344951742c4SGregory Neil Shapiro 	buflim = bufend = &buf[sizeof(buf) - 1];
1345951742c4SGregory Neil Shapiro 	bp = bufhead = buf;
1346951742c4SGregory Neil Shapiro 
1347951742c4SGregory Neil Shapiro 	/* skip over leading spaces but preserve them */
1348c2aa98e2SPeter Wemm 	while (*addr != '\0' && isascii(*addr) && isspace(*addr))
1349951742c4SGregory Neil Shapiro 	{
1350951742c4SGregory Neil Shapiro 		SM_APPEND_CHAR(*addr);
1351c2aa98e2SPeter Wemm 		addr++;
1352951742c4SGregory Neil Shapiro 	}
1353951742c4SGregory Neil Shapiro 	bufhead = bp;
1354c2aa98e2SPeter Wemm 
1355c2aa98e2SPeter Wemm 	/*
1356c2aa98e2SPeter Wemm 	**  Start by assuming we have no angle brackets.  This will be
1357c2aa98e2SPeter Wemm 	**  adjusted later if we find them.
1358c2aa98e2SPeter Wemm 	*/
1359c2aa98e2SPeter Wemm 
1360c2aa98e2SPeter Wemm 	p = addrhead = addr;
1361f9218d3dSGregory Neil Shapiro 	copylev = anglelev = cmtlev = realcmtlev = 0;
1362c2aa98e2SPeter Wemm 	bracklev = 0;
1363f9218d3dSGregory Neil Shapiro 	qmode = realqmode = addangle = false;
1364c2aa98e2SPeter Wemm 
1365c2aa98e2SPeter Wemm 	while ((c = *p++) != '\0')
1366c2aa98e2SPeter Wemm 	{
1367c2aa98e2SPeter Wemm 		/*
1368f9218d3dSGregory Neil Shapiro 		**  Try to keep legal syntax using spare buffer space
1369f9218d3dSGregory Neil Shapiro 		**  (maintained by buflim).
1370c2aa98e2SPeter Wemm 		*/
1371c2aa98e2SPeter Wemm 
1372f9218d3dSGregory Neil Shapiro 		if (copylev > 0)
1373f9218d3dSGregory Neil Shapiro 			SM_APPEND_CHAR(c);
1374c2aa98e2SPeter Wemm 
1375c2aa98e2SPeter Wemm 		/* check for backslash escapes */
1376c2aa98e2SPeter Wemm 		if (c == '\\')
1377c2aa98e2SPeter Wemm 		{
1378c2aa98e2SPeter Wemm 			/* arrange to quote the address */
1379c2aa98e2SPeter Wemm 			if (cmtlev <= 0 && !qmode)
138012ed1c7cSGregory Neil Shapiro 				quoteit = true;
1381c2aa98e2SPeter Wemm 
1382c2aa98e2SPeter Wemm 			if ((c = *p++) == '\0')
1383c2aa98e2SPeter Wemm 			{
1384c2aa98e2SPeter Wemm 				/* too far */
1385c2aa98e2SPeter Wemm 				p--;
1386c2aa98e2SPeter Wemm 				goto putg;
1387c2aa98e2SPeter Wemm 			}
1388f9218d3dSGregory Neil Shapiro 			if (copylev > 0)
1389f9218d3dSGregory Neil Shapiro 				SM_APPEND_CHAR(c);
1390c2aa98e2SPeter Wemm 			goto putg;
1391c2aa98e2SPeter Wemm 		}
1392c2aa98e2SPeter Wemm 
1393c2aa98e2SPeter Wemm 		/* check for quoted strings */
1394c2aa98e2SPeter Wemm 		if (c == '"' && cmtlev <= 0)
1395c2aa98e2SPeter Wemm 		{
1396c2aa98e2SPeter Wemm 			qmode = !qmode;
1397f9218d3dSGregory Neil Shapiro 			if (copylev > 0 && SM_HAVE_ROOM)
1398f9218d3dSGregory Neil Shapiro 			{
1399f9218d3dSGregory Neil Shapiro 				if (realqmode)
1400f9218d3dSGregory Neil Shapiro 					buflim--;
1401f9218d3dSGregory Neil Shapiro 				else
1402f9218d3dSGregory Neil Shapiro 					buflim++;
1403c2aa98e2SPeter Wemm 				realqmode = !realqmode;
1404f9218d3dSGregory Neil Shapiro 			}
1405c2aa98e2SPeter Wemm 			continue;
1406c2aa98e2SPeter Wemm 		}
1407c2aa98e2SPeter Wemm 		if (qmode)
1408c2aa98e2SPeter Wemm 			goto putg;
1409c2aa98e2SPeter Wemm 
1410c2aa98e2SPeter Wemm 		/* check for comments */
1411c2aa98e2SPeter Wemm 		if (c == '(')
1412c2aa98e2SPeter Wemm 		{
1413c2aa98e2SPeter Wemm 			cmtlev++;
1414c2aa98e2SPeter Wemm 
1415c2aa98e2SPeter Wemm 			/* allow space for closing paren */
1416f9218d3dSGregory Neil Shapiro 			if (SM_HAVE_ROOM)
1417c2aa98e2SPeter Wemm 			{
1418c2aa98e2SPeter Wemm 				buflim--;
1419c2aa98e2SPeter Wemm 				realcmtlev++;
1420c2aa98e2SPeter Wemm 				if (copylev++ <= 0)
1421c2aa98e2SPeter Wemm 				{
1422c2aa98e2SPeter Wemm 					if (bp != bufhead)
1423f9218d3dSGregory Neil Shapiro 						SM_APPEND_CHAR(' ');
1424f9218d3dSGregory Neil Shapiro 					SM_APPEND_CHAR(c);
1425c2aa98e2SPeter Wemm 				}
1426c2aa98e2SPeter Wemm 			}
1427c2aa98e2SPeter Wemm 		}
1428c2aa98e2SPeter Wemm 		if (cmtlev > 0)
1429c2aa98e2SPeter Wemm 		{
1430c2aa98e2SPeter Wemm 			if (c == ')')
1431c2aa98e2SPeter Wemm 			{
1432c2aa98e2SPeter Wemm 				cmtlev--;
1433c2aa98e2SPeter Wemm 				copylev--;
1434f9218d3dSGregory Neil Shapiro 				if (SM_HAVE_ROOM)
1435c2aa98e2SPeter Wemm 				{
1436c2aa98e2SPeter Wemm 					realcmtlev--;
1437c2aa98e2SPeter Wemm 					buflim++;
1438c2aa98e2SPeter Wemm 				}
1439c2aa98e2SPeter Wemm 			}
1440c2aa98e2SPeter Wemm 			continue;
1441c2aa98e2SPeter Wemm 		}
1442c2aa98e2SPeter Wemm 		else if (c == ')')
1443c2aa98e2SPeter Wemm 		{
1444c2aa98e2SPeter Wemm 			/* syntax error: unmatched ) */
14457660b554SGregory Neil Shapiro 			if (copylev > 0 && SM_HAVE_ROOM && bp > bufhead)
1446c2aa98e2SPeter Wemm 				bp--;
1447c2aa98e2SPeter Wemm 		}
1448c2aa98e2SPeter Wemm 
1449c2aa98e2SPeter Wemm 		/* count nesting on [ ... ] (for IPv6 domain literals) */
1450c2aa98e2SPeter Wemm 		if (c == '[')
1451c2aa98e2SPeter Wemm 			bracklev++;
1452c2aa98e2SPeter Wemm 		else if (c == ']')
1453c2aa98e2SPeter Wemm 			bracklev--;
1454c2aa98e2SPeter Wemm 
1455c2aa98e2SPeter Wemm 		/* check for group: list; syntax */
1456c2aa98e2SPeter Wemm 		if (c == ':' && anglelev <= 0 && bracklev <= 0 &&
1457c2aa98e2SPeter Wemm 		    !gotcolon && !ColonOkInAddr)
1458c2aa98e2SPeter Wemm 		{
1459c2aa98e2SPeter Wemm 			register char *q;
1460c2aa98e2SPeter Wemm 
1461c2aa98e2SPeter Wemm 			/*
1462c2aa98e2SPeter Wemm 			**  Check for DECnet phase IV ``::'' (host::user)
1463f9218d3dSGregory Neil Shapiro 			**  or DECnet phase V ``:.'' syntaxes.  The latter
1464c2aa98e2SPeter Wemm 			**  covers ``user@DEC:.tay.myhost'' and
1465c2aa98e2SPeter Wemm 			**  ``DEC:.tay.myhost::user'' syntaxes (bletch).
1466c2aa98e2SPeter Wemm 			*/
1467c2aa98e2SPeter Wemm 
1468c2aa98e2SPeter Wemm 			if (*p == ':' || *p == '.')
1469c2aa98e2SPeter Wemm 			{
1470c2aa98e2SPeter Wemm 				if (cmtlev <= 0 && !qmode)
147112ed1c7cSGregory Neil Shapiro 					quoteit = true;
1472f9218d3dSGregory Neil Shapiro 				if (copylev > 0)
1473c2aa98e2SPeter Wemm 				{
1474f9218d3dSGregory Neil Shapiro 					SM_APPEND_CHAR(c);
1475f9218d3dSGregory Neil Shapiro 					SM_APPEND_CHAR(*p);
1476c2aa98e2SPeter Wemm 				}
1477c2aa98e2SPeter Wemm 				p++;
1478c2aa98e2SPeter Wemm 				goto putg;
1479c2aa98e2SPeter Wemm 			}
1480c2aa98e2SPeter Wemm 
148112ed1c7cSGregory Neil Shapiro 			gotcolon = true;
1482c2aa98e2SPeter Wemm 
1483c2aa98e2SPeter Wemm 			bp = bufhead;
1484c2aa98e2SPeter Wemm 			if (quoteit)
1485c2aa98e2SPeter Wemm 			{
1486f9218d3dSGregory Neil Shapiro 				SM_APPEND_CHAR('"');
1487c2aa98e2SPeter Wemm 
1488c2aa98e2SPeter Wemm 				/* back up over the ':' and any spaces */
1489c2aa98e2SPeter Wemm 				--p;
1490f9218d3dSGregory Neil Shapiro 				while (p > addr &&
1491f9218d3dSGregory Neil Shapiro 				       isascii(*--p) && isspace(*p))
1492c2aa98e2SPeter Wemm 					continue;
1493c2aa98e2SPeter Wemm 				p++;
1494c2aa98e2SPeter Wemm 			}
1495c2aa98e2SPeter Wemm 			for (q = addrhead; q < p; )
1496c2aa98e2SPeter Wemm 			{
1497c2aa98e2SPeter Wemm 				c = *q++;
1498c2aa98e2SPeter Wemm 				if (quoteit && c == '"')
1499f9218d3dSGregory Neil Shapiro 					SM_APPEND_CHAR('\\');
1500f9218d3dSGregory Neil Shapiro 				SM_APPEND_CHAR(c);
1501c2aa98e2SPeter Wemm 			}
1502c2aa98e2SPeter Wemm 			if (quoteit)
1503c2aa98e2SPeter Wemm 			{
1504c2aa98e2SPeter Wemm 				if (bp == &bufhead[1])
1505c2aa98e2SPeter Wemm 					bp--;
1506c2aa98e2SPeter Wemm 				else
1507f9218d3dSGregory Neil Shapiro 					SM_APPEND_CHAR('"');
1508c2aa98e2SPeter Wemm 				while ((c = *p++) != ':')
1509f9218d3dSGregory Neil Shapiro 					SM_APPEND_CHAR(c);
1510f9218d3dSGregory Neil Shapiro 				SM_APPEND_CHAR(c);
1511c2aa98e2SPeter Wemm 			}
1512c2aa98e2SPeter Wemm 
1513c2aa98e2SPeter Wemm 			/* any trailing white space is part of group: */
1514f9218d3dSGregory Neil Shapiro 			while (isascii(*p) && isspace(*p))
1515f9218d3dSGregory Neil Shapiro 			{
1516f9218d3dSGregory Neil Shapiro 				SM_APPEND_CHAR(*p);
1517f9218d3dSGregory Neil Shapiro 				p++;
1518f9218d3dSGregory Neil Shapiro 			}
1519c2aa98e2SPeter Wemm 			copylev = 0;
152012ed1c7cSGregory Neil Shapiro 			putgmac = quoteit = false;
1521c2aa98e2SPeter Wemm 			bufhead = bp;
1522c2aa98e2SPeter Wemm 			addrhead = p;
1523c2aa98e2SPeter Wemm 			continue;
1524c2aa98e2SPeter Wemm 		}
1525c2aa98e2SPeter Wemm 
1526c2aa98e2SPeter Wemm 		if (c == ';' && copylev <= 0 && !ColonOkInAddr)
1527f9218d3dSGregory Neil Shapiro 			SM_APPEND_CHAR(c);
1528c2aa98e2SPeter Wemm 
1529c2aa98e2SPeter Wemm 		/* check for characters that may have to be quoted */
1530c2aa98e2SPeter Wemm 		if (strchr(MustQuoteChars, c) != NULL)
1531c2aa98e2SPeter Wemm 		{
1532c2aa98e2SPeter Wemm 			/*
1533c2aa98e2SPeter Wemm 			**  If these occur as the phrase part of a <>
1534c2aa98e2SPeter Wemm 			**  construct, but are not inside of () or already
1535c2aa98e2SPeter Wemm 			**  quoted, they will have to be quoted.  Note that
1536c2aa98e2SPeter Wemm 			**  now (but don't actually do the quoting).
1537c2aa98e2SPeter Wemm 			*/
1538c2aa98e2SPeter Wemm 
1539c2aa98e2SPeter Wemm 			if (cmtlev <= 0 && !qmode)
154012ed1c7cSGregory Neil Shapiro 				quoteit = true;
1541c2aa98e2SPeter Wemm 		}
1542c2aa98e2SPeter Wemm 
1543c2aa98e2SPeter Wemm 		/* check for angle brackets */
1544c2aa98e2SPeter Wemm 		if (c == '<')
1545c2aa98e2SPeter Wemm 		{
1546c2aa98e2SPeter Wemm 			register char *q;
1547c2aa98e2SPeter Wemm 
1548c2aa98e2SPeter Wemm 			/* assume first of two angles is bogus */
1549c2aa98e2SPeter Wemm 			if (gotangle)
155012ed1c7cSGregory Neil Shapiro 				quoteit = true;
155112ed1c7cSGregory Neil Shapiro 			gotangle = true;
1552c2aa98e2SPeter Wemm 
1553c2aa98e2SPeter Wemm 			/* oops -- have to change our mind */
1554c2aa98e2SPeter Wemm 			anglelev = 1;
1555f9218d3dSGregory Neil Shapiro 			if (SM_HAVE_ROOM)
1556f9218d3dSGregory Neil Shapiro 			{
1557f9218d3dSGregory Neil Shapiro 				if (!addangle)
1558f9218d3dSGregory Neil Shapiro 					buflim--;
1559f9218d3dSGregory Neil Shapiro 				addangle = true;
1560f9218d3dSGregory Neil Shapiro 			}
1561c2aa98e2SPeter Wemm 
1562c2aa98e2SPeter Wemm 			bp = bufhead;
1563c2aa98e2SPeter Wemm 			if (quoteit)
1564c2aa98e2SPeter Wemm 			{
1565f9218d3dSGregory Neil Shapiro 				SM_APPEND_CHAR('"');
1566c2aa98e2SPeter Wemm 
1567c2aa98e2SPeter Wemm 				/* back up over the '<' and any spaces */
1568c2aa98e2SPeter Wemm 				--p;
1569f9218d3dSGregory Neil Shapiro 				while (p > addr &&
1570f9218d3dSGregory Neil Shapiro 				       isascii(*--p) && isspace(*p))
1571c2aa98e2SPeter Wemm 					continue;
1572c2aa98e2SPeter Wemm 				p++;
1573c2aa98e2SPeter Wemm 			}
1574c2aa98e2SPeter Wemm 			for (q = addrhead; q < p; )
1575c2aa98e2SPeter Wemm 			{
1576c2aa98e2SPeter Wemm 				c = *q++;
1577c2aa98e2SPeter Wemm 				if (quoteit && c == '"')
1578f9218d3dSGregory Neil Shapiro 				{
1579f9218d3dSGregory Neil Shapiro 					SM_APPEND_CHAR('\\');
1580f9218d3dSGregory Neil Shapiro 					SM_APPEND_CHAR(c);
1581c2aa98e2SPeter Wemm 				}
1582f9218d3dSGregory Neil Shapiro 				else
1583f9218d3dSGregory Neil Shapiro 					SM_APPEND_CHAR(c);
1584c2aa98e2SPeter Wemm 			}
1585c2aa98e2SPeter Wemm 			if (quoteit)
1586c2aa98e2SPeter Wemm 			{
1587c2aa98e2SPeter Wemm 				if (bp == &buf[1])
1588c2aa98e2SPeter Wemm 					bp--;
1589c2aa98e2SPeter Wemm 				else
1590f9218d3dSGregory Neil Shapiro 					SM_APPEND_CHAR('"');
1591c2aa98e2SPeter Wemm 				while ((c = *p++) != '<')
1592f9218d3dSGregory Neil Shapiro 					SM_APPEND_CHAR(c);
1593f9218d3dSGregory Neil Shapiro 				SM_APPEND_CHAR(c);
1594c2aa98e2SPeter Wemm 			}
1595c2aa98e2SPeter Wemm 			copylev = 0;
159612ed1c7cSGregory Neil Shapiro 			putgmac = quoteit = false;
1597c2aa98e2SPeter Wemm 			continue;
1598c2aa98e2SPeter Wemm 		}
1599c2aa98e2SPeter Wemm 
1600c2aa98e2SPeter Wemm 		if (c == '>')
1601c2aa98e2SPeter Wemm 		{
1602c2aa98e2SPeter Wemm 			if (anglelev > 0)
1603c2aa98e2SPeter Wemm 			{
1604c2aa98e2SPeter Wemm 				anglelev--;
1605f9218d3dSGregory Neil Shapiro 				if (SM_HAVE_ROOM)
1606c2aa98e2SPeter Wemm 				{
1607f9218d3dSGregory Neil Shapiro 					if (addangle)
1608c2aa98e2SPeter Wemm 						buflim++;
1609f9218d3dSGregory Neil Shapiro 					addangle = false;
1610c2aa98e2SPeter Wemm 				}
1611c2aa98e2SPeter Wemm 			}
1612f9218d3dSGregory Neil Shapiro 			else if (SM_HAVE_ROOM)
1613c2aa98e2SPeter Wemm 			{
1614c2aa98e2SPeter Wemm 				/* syntax error: unmatched > */
16157660b554SGregory Neil Shapiro 				if (copylev > 0 && bp > bufhead)
1616c2aa98e2SPeter Wemm 					bp--;
161712ed1c7cSGregory Neil Shapiro 				quoteit = true;
1618c2aa98e2SPeter Wemm 				continue;
1619c2aa98e2SPeter Wemm 			}
1620c2aa98e2SPeter Wemm 			if (copylev++ <= 0)
1621f9218d3dSGregory Neil Shapiro 				SM_APPEND_CHAR(c);
1622c2aa98e2SPeter Wemm 			continue;
1623c2aa98e2SPeter Wemm 		}
1624c2aa98e2SPeter Wemm 
1625c2aa98e2SPeter Wemm 		/* must be a real address character */
1626c2aa98e2SPeter Wemm 	putg:
1627c2aa98e2SPeter Wemm 		if (copylev <= 0 && !putgmac)
1628c2aa98e2SPeter Wemm 		{
1629f9218d3dSGregory Neil Shapiro 			if (bp > buf && bp[-1] == ')')
1630f9218d3dSGregory Neil Shapiro 				SM_APPEND_CHAR(' ');
1631f9218d3dSGregory Neil Shapiro 			SM_APPEND_CHAR(MACROEXPAND);
1632f9218d3dSGregory Neil Shapiro 			SM_APPEND_CHAR('g');
163312ed1c7cSGregory Neil Shapiro 			putgmac = true;
1634c2aa98e2SPeter Wemm 		}
1635c2aa98e2SPeter Wemm 	}
1636c2aa98e2SPeter Wemm 
1637c2aa98e2SPeter Wemm 	/* repair any syntactic damage */
1638f9218d3dSGregory Neil Shapiro 	if (realqmode && bp < bufend)
1639c2aa98e2SPeter Wemm 		*bp++ = '"';
1640f9218d3dSGregory Neil Shapiro 	while (realcmtlev-- > 0 && bp < bufend)
1641c2aa98e2SPeter Wemm 		*bp++ = ')';
1642f9218d3dSGregory Neil Shapiro 	if (addangle && bp < bufend)
1643c2aa98e2SPeter Wemm 		*bp++ = '>';
1644f9218d3dSGregory Neil Shapiro 	*bp = '\0';
1645f9218d3dSGregory Neil Shapiro 	if (bp < bufend)
1646f9218d3dSGregory Neil Shapiro 		goto success;
1647c2aa98e2SPeter Wemm 
1648f9218d3dSGregory Neil Shapiro  returng:
1649f9218d3dSGregory Neil Shapiro 	/* String too long, punt */
1650f9218d3dSGregory Neil Shapiro 	buf[0] = '<';
1651f9218d3dSGregory Neil Shapiro 	buf[1] = MACROEXPAND;
1652f9218d3dSGregory Neil Shapiro 	buf[2]= 'g';
1653f9218d3dSGregory Neil Shapiro 	buf[3] = '>';
1654f9218d3dSGregory Neil Shapiro 	buf[4]= '\0';
1655f9218d3dSGregory Neil Shapiro 	sm_syslog(LOG_ALERT, e->e_id,
1656f9218d3dSGregory Neil Shapiro 		  "Dropped invalid comments from header address");
1657f9218d3dSGregory Neil Shapiro 
1658f9218d3dSGregory Neil Shapiro  success:
1659c2aa98e2SPeter Wemm 	if (tTd(33, 1))
1660c2aa98e2SPeter Wemm 	{
166112ed1c7cSGregory Neil Shapiro 		sm_dprintf("crackaddr=>`");
1662bfb62e91SGregory Neil Shapiro 		xputs(sm_debug_file(), buf);
166312ed1c7cSGregory Neil Shapiro 		sm_dprintf("'\n");
1664c2aa98e2SPeter Wemm 	}
16653299c2f1SGregory Neil Shapiro 	return buf;
1666c2aa98e2SPeter Wemm }
1667951742c4SGregory Neil Shapiro 
166812ed1c7cSGregory Neil Shapiro /*
1669c2aa98e2SPeter Wemm **  PUTHEADER -- put the header part of a message from the in-core copy
1670c2aa98e2SPeter Wemm **
1671c2aa98e2SPeter Wemm **	Parameters:
1672c2aa98e2SPeter Wemm **		mci -- the connection information.
16733299c2f1SGregory Neil Shapiro **		hdr -- the header to put.
1674c2aa98e2SPeter Wemm **		e -- envelope to use.
1675e01d6f61SPeter Wemm **		flags -- MIME conversion flags.
1676c2aa98e2SPeter Wemm **
1677c2aa98e2SPeter Wemm **	Returns:
1678355d91e3SGregory Neil Shapiro **		true iff header part was written successfully
1679c2aa98e2SPeter Wemm **
1680c2aa98e2SPeter Wemm **	Side Effects:
1681c2aa98e2SPeter Wemm **		none.
1682c2aa98e2SPeter Wemm */
1683c2aa98e2SPeter Wemm 
1684567a2fc9SGregory Neil Shapiro bool
1685e01d6f61SPeter Wemm putheader(mci, hdr, e, flags)
1686c2aa98e2SPeter Wemm 	register MCI *mci;
1687c2aa98e2SPeter Wemm 	HDR *hdr;
1688c2aa98e2SPeter Wemm 	register ENVELOPE *e;
1689e01d6f61SPeter Wemm 	int flags;
1690c2aa98e2SPeter Wemm {
1691c2aa98e2SPeter Wemm 	register HDR *h;
169212ed1c7cSGregory Neil Shapiro 	char buf[SM_MAX(MAXLINE,BUFSIZ)];
1693c2aa98e2SPeter Wemm 	char obuf[MAXLINE];
1694c2aa98e2SPeter Wemm 
1695c2aa98e2SPeter Wemm 	if (tTd(34, 1))
169612ed1c7cSGregory Neil Shapiro 		sm_dprintf("--- putheader, mailer = %s ---\n",
1697c2aa98e2SPeter Wemm 			mci->mci_mailer->m_name);
1698c2aa98e2SPeter Wemm 
1699c2aa98e2SPeter Wemm 	/*
1700c2aa98e2SPeter Wemm 	**  If we're in MIME mode, we're not really in the header of the
1701c2aa98e2SPeter Wemm 	**  message, just the header of one of the parts of the body of
1702c2aa98e2SPeter Wemm 	**  the message.  Therefore MCIF_INHEADER should not be turned on.
1703c2aa98e2SPeter Wemm 	*/
1704c2aa98e2SPeter Wemm 
1705c2aa98e2SPeter Wemm 	if (!bitset(MCIF_INMIME, mci->mci_flags))
1706c2aa98e2SPeter Wemm 		mci->mci_flags |= MCIF_INHEADER;
1707c2aa98e2SPeter Wemm 
1708c2aa98e2SPeter Wemm 	for (h = hdr; h != NULL; h = h->h_link)
1709c2aa98e2SPeter Wemm 	{
1710c2aa98e2SPeter Wemm 		register char *p = h->h_value;
171112ed1c7cSGregory Neil Shapiro 		char *q;
1712c2aa98e2SPeter Wemm 
1713c2aa98e2SPeter Wemm 		if (tTd(34, 11))
1714c2aa98e2SPeter Wemm 		{
171512ed1c7cSGregory Neil Shapiro 			sm_dprintf("  %s:", h->h_field);
1716bfb62e91SGregory Neil Shapiro 			xputs(sm_debug_file(), p);
1717c2aa98e2SPeter Wemm 		}
1718c2aa98e2SPeter Wemm 
17193299c2f1SGregory Neil Shapiro 		/* Skip empty headers */
17203299c2f1SGregory Neil Shapiro 		if (h->h_value == NULL)
17213299c2f1SGregory Neil Shapiro 			continue;
17223299c2f1SGregory Neil Shapiro 
172376b7bf71SPeter Wemm 		/* heuristic shortening of MIME fields to avoid MUA overflows */
172476b7bf71SPeter Wemm 		if (MaxMimeFieldLength > 0 &&
172576b7bf71SPeter Wemm 		    wordinclass(h->h_field,
172612ed1c7cSGregory Neil Shapiro 				macid("{checkMIMEFieldHeaders}")))
172776b7bf71SPeter Wemm 		{
1728c46d91b7SGregory Neil Shapiro 			size_t len;
1729c46d91b7SGregory Neil Shapiro 
1730f9218d3dSGregory Neil Shapiro 			len = fix_mime_header(h, e);
1731c46d91b7SGregory Neil Shapiro 			if (len > 0)
173276b7bf71SPeter Wemm 			{
173376b7bf71SPeter Wemm 				sm_syslog(LOG_ALERT, e->e_id,
1734c46d91b7SGregory Neil Shapiro 					  "Truncated MIME %s header due to field size (length = %ld) (possible attack)",
1735c46d91b7SGregory Neil Shapiro 					  h->h_field, (unsigned long) len);
173676b7bf71SPeter Wemm 				if (tTd(34, 11))
173712ed1c7cSGregory Neil Shapiro 					sm_dprintf("  truncated MIME %s header due to field size  (length = %ld) (possible attack)\n",
1738c46d91b7SGregory Neil Shapiro 						   h->h_field,
1739c46d91b7SGregory Neil Shapiro 						   (unsigned long) len);
174076b7bf71SPeter Wemm 			}
174176b7bf71SPeter Wemm 		}
174276b7bf71SPeter Wemm 
174376b7bf71SPeter Wemm 		if (MaxMimeHeaderLength > 0 &&
174476b7bf71SPeter Wemm 		    wordinclass(h->h_field,
174512ed1c7cSGregory Neil Shapiro 				macid("{checkMIMETextHeaders}")))
174676b7bf71SPeter Wemm 		{
1747c46d91b7SGregory Neil Shapiro 			size_t len;
1748c46d91b7SGregory Neil Shapiro 
1749c46d91b7SGregory Neil Shapiro 			len = strlen(h->h_value);
1750c46d91b7SGregory Neil Shapiro 			if (len > (size_t) MaxMimeHeaderLength)
175176b7bf71SPeter Wemm 			{
175276b7bf71SPeter Wemm 				h->h_value[MaxMimeHeaderLength - 1] = '\0';
175376b7bf71SPeter Wemm 				sm_syslog(LOG_ALERT, e->e_id,
1754c46d91b7SGregory Neil Shapiro 					  "Truncated long MIME %s header (length = %ld) (possible attack)",
1755c46d91b7SGregory Neil Shapiro 					  h->h_field, (unsigned long) len);
175676b7bf71SPeter Wemm 				if (tTd(34, 11))
175712ed1c7cSGregory Neil Shapiro 					sm_dprintf("  truncated long MIME %s header (length = %ld) (possible attack)\n",
1758c46d91b7SGregory Neil Shapiro 						   h->h_field,
1759c46d91b7SGregory Neil Shapiro 						   (unsigned long) len);
176076b7bf71SPeter Wemm 			}
176176b7bf71SPeter Wemm 		}
176276b7bf71SPeter Wemm 
176376b7bf71SPeter Wemm 		if (MaxMimeHeaderLength > 0 &&
176476b7bf71SPeter Wemm 		    wordinclass(h->h_field,
176512ed1c7cSGregory Neil Shapiro 				macid("{checkMIMEHeaders}")))
176676b7bf71SPeter Wemm 		{
1767c46d91b7SGregory Neil Shapiro 			size_t len;
1768c46d91b7SGregory Neil Shapiro 
1769c46d91b7SGregory Neil Shapiro 			len = strlen(h->h_value);
1770c46d91b7SGregory Neil Shapiro 			if (shorten_rfc822_string(h->h_value,
1771c46d91b7SGregory Neil Shapiro 						  MaxMimeHeaderLength))
177276b7bf71SPeter Wemm 			{
1773f9218d3dSGregory Neil Shapiro 				if (len < MaxMimeHeaderLength)
1774f9218d3dSGregory Neil Shapiro 				{
1775f9218d3dSGregory Neil Shapiro 					/* we only rebalanced a bogus header */
1776f9218d3dSGregory Neil Shapiro 					sm_syslog(LOG_ALERT, e->e_id,
1777f9218d3dSGregory Neil Shapiro 						  "Fixed MIME %s header (possible attack)",
1778f9218d3dSGregory Neil Shapiro 						  h->h_field);
1779f9218d3dSGregory Neil Shapiro 					if (tTd(34, 11))
1780f9218d3dSGregory Neil Shapiro 						sm_dprintf("  fixed MIME %s header (possible attack)\n",
1781f9218d3dSGregory Neil Shapiro 							   h->h_field);
1782f9218d3dSGregory Neil Shapiro 				}
1783f9218d3dSGregory Neil Shapiro 				else
1784f9218d3dSGregory Neil Shapiro 				{
1785f9218d3dSGregory Neil Shapiro 					/* we actually shortened header */
178676b7bf71SPeter Wemm 					sm_syslog(LOG_ALERT, e->e_id,
1787c46d91b7SGregory Neil Shapiro 						  "Truncated long MIME %s header (length = %ld) (possible attack)",
1788f9218d3dSGregory Neil Shapiro 						  h->h_field,
1789f9218d3dSGregory Neil Shapiro 						  (unsigned long) len);
179076b7bf71SPeter Wemm 					if (tTd(34, 11))
179112ed1c7cSGregory Neil Shapiro 						sm_dprintf("  truncated long MIME %s header (length = %ld) (possible attack)\n",
1792c46d91b7SGregory Neil Shapiro 							   h->h_field,
1793c46d91b7SGregory Neil Shapiro 							   (unsigned long) len);
179476b7bf71SPeter Wemm 				}
179576b7bf71SPeter Wemm 			}
1796f9218d3dSGregory Neil Shapiro 		}
179776b7bf71SPeter Wemm 
1798e01d6f61SPeter Wemm 		/*
1799e01d6f61SPeter Wemm 		**  Suppress Content-Transfer-Encoding: if we are MIMEing
1800e01d6f61SPeter Wemm 		**  and we are potentially converting from 8 bit to 7 bit
1801e01d6f61SPeter Wemm 		**  MIME.  If converting, add a new CTE header in
1802e01d6f61SPeter Wemm 		**  mime8to7().
1803e01d6f61SPeter Wemm 		*/
180412ed1c7cSGregory Neil Shapiro 
1805c2aa98e2SPeter Wemm 		if (bitset(H_CTE, h->h_flags) &&
1806e01d6f61SPeter Wemm 		    bitset(MCIF_CVT8TO7|MCIF_CVT7TO8|MCIF_INMIME,
1807e01d6f61SPeter Wemm 			   mci->mci_flags) &&
1808e01d6f61SPeter Wemm 		    !bitset(M87F_NO8TO7, flags))
1809c2aa98e2SPeter Wemm 		{
1810c2aa98e2SPeter Wemm 			if (tTd(34, 11))
181112ed1c7cSGregory Neil Shapiro 				sm_dprintf(" (skipped (content-transfer-encoding))\n");
1812c2aa98e2SPeter Wemm 			continue;
1813c2aa98e2SPeter Wemm 		}
1814c2aa98e2SPeter Wemm 
1815c2aa98e2SPeter Wemm 		if (bitset(MCIF_INMIME, mci->mci_flags))
1816c2aa98e2SPeter Wemm 		{
1817c2aa98e2SPeter Wemm 			if (tTd(34, 11))
181812ed1c7cSGregory Neil Shapiro 				sm_dprintf("\n");
1819567a2fc9SGregory Neil Shapiro 			if (!put_vanilla_header(h, p, mci))
1820567a2fc9SGregory Neil Shapiro 				goto writeerr;
1821c2aa98e2SPeter Wemm 			continue;
1822c2aa98e2SPeter Wemm 		}
1823c2aa98e2SPeter Wemm 
1824c2aa98e2SPeter Wemm 		if (bitset(H_CHECK|H_ACHECK, h->h_flags) &&
18253299c2f1SGregory Neil Shapiro 		    !bitintersect(h->h_mflags, mci->mci_mailer->m_flags) &&
18263299c2f1SGregory Neil Shapiro 		    (h->h_macro == '\0' ||
182712ed1c7cSGregory Neil Shapiro 		     (q = macvalue(bitidx(h->h_macro), e)) == NULL ||
182812ed1c7cSGregory Neil Shapiro 		     *q == '\0'))
1829c2aa98e2SPeter Wemm 		{
1830c2aa98e2SPeter Wemm 			if (tTd(34, 11))
183112ed1c7cSGregory Neil Shapiro 				sm_dprintf(" (skipped)\n");
1832c2aa98e2SPeter Wemm 			continue;
1833c2aa98e2SPeter Wemm 		}
1834c2aa98e2SPeter Wemm 
1835c2aa98e2SPeter Wemm 		/* handle Resent-... headers specially */
1836c2aa98e2SPeter Wemm 		if (bitset(H_RESENT, h->h_flags) && !bitset(EF_RESENT, e->e_flags))
1837c2aa98e2SPeter Wemm 		{
1838c2aa98e2SPeter Wemm 			if (tTd(34, 11))
183912ed1c7cSGregory Neil Shapiro 				sm_dprintf(" (skipped (resent))\n");
1840c2aa98e2SPeter Wemm 			continue;
1841c2aa98e2SPeter Wemm 		}
1842c2aa98e2SPeter Wemm 
1843c2aa98e2SPeter Wemm 		/* suppress return receipts if requested */
1844c2aa98e2SPeter Wemm 		if (bitset(H_RECEIPTTO, h->h_flags) &&
1845c2aa98e2SPeter Wemm 		    (RrtImpliesDsn || bitset(EF_NORECEIPT, e->e_flags)))
1846c2aa98e2SPeter Wemm 		{
1847c2aa98e2SPeter Wemm 			if (tTd(34, 11))
184812ed1c7cSGregory Neil Shapiro 				sm_dprintf(" (skipped (receipt))\n");
1849c2aa98e2SPeter Wemm 			continue;
1850c2aa98e2SPeter Wemm 		}
1851c2aa98e2SPeter Wemm 
1852c2aa98e2SPeter Wemm 		/* macro expand value if generated internally */
18533299c2f1SGregory Neil Shapiro 		if (bitset(H_DEFAULT, h->h_flags) ||
18543299c2f1SGregory Neil Shapiro 		    bitset(H_BINDLATE, h->h_flags))
1855c2aa98e2SPeter Wemm 		{
1856951742c4SGregory Neil Shapiro 			expand(p, buf, sizeof(buf), e);
1857c2aa98e2SPeter Wemm 			p = buf;
1858c2aa98e2SPeter Wemm 			if (*p == '\0')
1859c2aa98e2SPeter Wemm 			{
1860c2aa98e2SPeter Wemm 				if (tTd(34, 11))
186112ed1c7cSGregory Neil Shapiro 					sm_dprintf(" (skipped -- null value)\n");
1862c2aa98e2SPeter Wemm 				continue;
1863c2aa98e2SPeter Wemm 			}
1864c2aa98e2SPeter Wemm 		}
1865c2aa98e2SPeter Wemm 
1866c2aa98e2SPeter Wemm 		if (bitset(H_BCC, h->h_flags))
1867c2aa98e2SPeter Wemm 		{
1868c2aa98e2SPeter Wemm 			/* Bcc: field -- either truncate or delete */
1869c2aa98e2SPeter Wemm 			if (bitset(EF_DELETE_BCC, e->e_flags))
1870c2aa98e2SPeter Wemm 			{
1871c2aa98e2SPeter Wemm 				if (tTd(34, 11))
187212ed1c7cSGregory Neil Shapiro 					sm_dprintf(" (skipped -- bcc)\n");
1873c2aa98e2SPeter Wemm 			}
1874c2aa98e2SPeter Wemm 			else
1875c2aa98e2SPeter Wemm 			{
1876c2aa98e2SPeter Wemm 				/* no other recipient headers: truncate value */
1877951742c4SGregory Neil Shapiro 				(void) sm_strlcpyn(obuf, sizeof(obuf), 2,
187812ed1c7cSGregory Neil Shapiro 						   h->h_field, ":");
1879567a2fc9SGregory Neil Shapiro 				if (!putline(obuf, mci))
1880567a2fc9SGregory Neil Shapiro 					goto writeerr;
1881c2aa98e2SPeter Wemm 			}
1882c2aa98e2SPeter Wemm 			continue;
1883c2aa98e2SPeter Wemm 		}
1884c2aa98e2SPeter Wemm 
1885c2aa98e2SPeter Wemm 		if (tTd(34, 11))
188612ed1c7cSGregory Neil Shapiro 			sm_dprintf("\n");
1887c2aa98e2SPeter Wemm 
1888c2aa98e2SPeter Wemm 		if (bitset(H_FROM|H_RCPT, h->h_flags))
1889c2aa98e2SPeter Wemm 		{
1890c2aa98e2SPeter Wemm 			/* address field */
1891c2aa98e2SPeter Wemm 			bool oldstyle = bitset(EF_OLDSTYLE, e->e_flags);
1892c2aa98e2SPeter Wemm 
1893c2aa98e2SPeter Wemm 			if (bitset(H_FROM, h->h_flags))
189412ed1c7cSGregory Neil Shapiro 				oldstyle = false;
189541f3d2ceSGregory Neil Shapiro 			commaize(h, p, oldstyle, mci, e,
189641f3d2ceSGregory Neil Shapiro 				 PXLF_HEADER | PXLF_STRIPMQUOTE);
1897c2aa98e2SPeter Wemm 		}
1898c2aa98e2SPeter Wemm 		else
1899c2aa98e2SPeter Wemm 		{
1900567a2fc9SGregory Neil Shapiro 			if (!put_vanilla_header(h, p, mci))
1901567a2fc9SGregory Neil Shapiro 				goto writeerr;
1902c2aa98e2SPeter Wemm 		}
1903c2aa98e2SPeter Wemm 	}
1904c2aa98e2SPeter Wemm 
1905c2aa98e2SPeter Wemm 	/*
1906c2aa98e2SPeter Wemm 	**  If we are converting this to a MIME message, add the
19073299c2f1SGregory Neil Shapiro 	**  MIME headers (but not in MIME mode!).
1908c2aa98e2SPeter Wemm 	*/
1909c2aa98e2SPeter Wemm 
1910c2aa98e2SPeter Wemm #if MIME8TO7
1911c2aa98e2SPeter Wemm 	if (bitset(MM_MIME8BIT, MimeMode) &&
1912c2aa98e2SPeter Wemm 	    bitset(EF_HAS8BIT, e->e_flags) &&
1913c2aa98e2SPeter Wemm 	    !bitset(EF_DONT_MIME, e->e_flags) &&
1914c2aa98e2SPeter Wemm 	    !bitnset(M_8BITS, mci->mci_mailer->m_flags) &&
19153299c2f1SGregory Neil Shapiro 	    !bitset(MCIF_CVT8TO7|MCIF_CVT7TO8|MCIF_INMIME, mci->mci_flags) &&
19163299c2f1SGregory Neil Shapiro 	    hvalue("MIME-Version", e->e_header) == NULL)
1917c2aa98e2SPeter Wemm 	{
1918567a2fc9SGregory Neil Shapiro 		if (!putline("MIME-Version: 1.0", mci))
1919567a2fc9SGregory Neil Shapiro 			goto writeerr;
1920c2aa98e2SPeter Wemm 		if (hvalue("Content-Type", e->e_header) == NULL)
1921c2aa98e2SPeter Wemm 		{
1922951742c4SGregory Neil Shapiro 			(void) sm_snprintf(obuf, sizeof(obuf),
1923c2aa98e2SPeter Wemm 					"Content-Type: text/plain; charset=%s",
1924c2aa98e2SPeter Wemm 					defcharset(e));
1925567a2fc9SGregory Neil Shapiro 			if (!putline(obuf, mci))
1926567a2fc9SGregory Neil Shapiro 				goto writeerr;
1927c2aa98e2SPeter Wemm 		}
1928567a2fc9SGregory Neil Shapiro 		if (hvalue("Content-Transfer-Encoding", e->e_header) == NULL
1929567a2fc9SGregory Neil Shapiro 		    && !putline("Content-Transfer-Encoding: 8bit", mci))
1930567a2fc9SGregory Neil Shapiro 			goto writeerr;
1931c2aa98e2SPeter Wemm 	}
19323299c2f1SGregory Neil Shapiro #endif /* MIME8TO7 */
1933567a2fc9SGregory Neil Shapiro 	return true;
1934567a2fc9SGregory Neil Shapiro 
1935567a2fc9SGregory Neil Shapiro   writeerr:
1936567a2fc9SGregory Neil Shapiro 	return false;
1937c2aa98e2SPeter Wemm }
1938951742c4SGregory Neil Shapiro 
193912ed1c7cSGregory Neil Shapiro /*
1940c2aa98e2SPeter Wemm **  PUT_VANILLA_HEADER -- output a fairly ordinary header
1941c2aa98e2SPeter Wemm **
1942c2aa98e2SPeter Wemm **	Parameters:
1943c2aa98e2SPeter Wemm **		h -- the structure describing this header
1944c2aa98e2SPeter Wemm **		v -- the value of this header
1945c2aa98e2SPeter Wemm **		mci -- the connection info for output
1946c2aa98e2SPeter Wemm **
1947c2aa98e2SPeter Wemm **	Returns:
1948355d91e3SGregory Neil Shapiro **		true iff header was written successfully
1949c2aa98e2SPeter Wemm */
1950c2aa98e2SPeter Wemm 
1951567a2fc9SGregory Neil Shapiro static bool
1952c2aa98e2SPeter Wemm put_vanilla_header(h, v, mci)
1953c2aa98e2SPeter Wemm 	HDR *h;
1954c2aa98e2SPeter Wemm 	char *v;
1955c2aa98e2SPeter Wemm 	MCI *mci;
1956c2aa98e2SPeter Wemm {
1957c2aa98e2SPeter Wemm 	register char *nlp;
1958c2aa98e2SPeter Wemm 	register char *obp;
1959c2aa98e2SPeter Wemm 	int putflags;
1960684b2a5fSGregory Neil Shapiro 	char obuf[MAXLINE + 256];	/* additional length for h_field */
1961c2aa98e2SPeter Wemm 
1962951742c4SGregory Neil Shapiro 	putflags = PXLF_HEADER | PXLF_STRIPMQUOTE;
1963c2aa98e2SPeter Wemm 	if (bitnset(M_7BITHDRS, mci->mci_mailer->m_flags))
1964c2aa98e2SPeter Wemm 		putflags |= PXLF_STRIP8BIT;
1965951742c4SGregory Neil Shapiro 	(void) sm_snprintf(obuf, sizeof(obuf), "%.200s:", h->h_field);
1966c2aa98e2SPeter Wemm 	obp = obuf + strlen(obuf);
1967c2aa98e2SPeter Wemm 	while ((nlp = strchr(v, '\n')) != NULL)
1968c2aa98e2SPeter Wemm 	{
1969c2aa98e2SPeter Wemm 		int l;
1970c2aa98e2SPeter Wemm 
1971c2aa98e2SPeter Wemm 		l = nlp - v;
19727660b554SGregory Neil Shapiro 
19737660b554SGregory Neil Shapiro 		/*
19747660b554SGregory Neil Shapiro 		**  XXX This is broken for SPACELEFT()==0
19757660b554SGregory Neil Shapiro 		**  However, SPACELEFT() is always > 0 unless MAXLINE==1.
19767660b554SGregory Neil Shapiro 		*/
19777660b554SGregory Neil Shapiro 
19783299c2f1SGregory Neil Shapiro 		if (SPACELEFT(obuf, obp) - 1 < (size_t) l)
1979c2aa98e2SPeter Wemm 			l = SPACELEFT(obuf, obp) - 1;
1980c2aa98e2SPeter Wemm 
198112ed1c7cSGregory Neil Shapiro 		(void) sm_snprintf(obp, SPACELEFT(obuf, obp), "%.*s", l, v);
1982567a2fc9SGregory Neil Shapiro 		if (!putxline(obuf, strlen(obuf), mci, putflags))
1983567a2fc9SGregory Neil Shapiro 			goto writeerr;
1984c2aa98e2SPeter Wemm 		v += l + 1;
1985c2aa98e2SPeter Wemm 		obp = obuf;
1986c2aa98e2SPeter Wemm 		if (*v != ' ' && *v != '\t')
1987c2aa98e2SPeter Wemm 			*obp++ = ' ';
1988c2aa98e2SPeter Wemm 	}
19897660b554SGregory Neil Shapiro 
19907660b554SGregory Neil Shapiro 	/* XXX This is broken for SPACELEFT()==0 */
199112ed1c7cSGregory Neil Shapiro 	(void) sm_snprintf(obp, SPACELEFT(obuf, obp), "%.*s",
199212ed1c7cSGregory Neil Shapiro 			   (int) (SPACELEFT(obuf, obp) - 1), v);
1993567a2fc9SGregory Neil Shapiro 	return putxline(obuf, strlen(obuf), mci, putflags);
1994567a2fc9SGregory Neil Shapiro 
1995567a2fc9SGregory Neil Shapiro   writeerr:
1996567a2fc9SGregory Neil Shapiro 	return false;
1997c2aa98e2SPeter Wemm }
1998951742c4SGregory Neil Shapiro 
199912ed1c7cSGregory Neil Shapiro /*
2000c2aa98e2SPeter Wemm **  COMMAIZE -- output a header field, making a comma-translated list.
2001c2aa98e2SPeter Wemm **
2002c2aa98e2SPeter Wemm **	Parameters:
2003c2aa98e2SPeter Wemm **		h -- the header field to output.
2004c2aa98e2SPeter Wemm **		p -- the value to put in it.
200512ed1c7cSGregory Neil Shapiro **		oldstyle -- true if this is an old style header.
2006c2aa98e2SPeter Wemm **		mci -- the connection information.
2007c2aa98e2SPeter Wemm **		e -- the envelope containing the message.
200841f3d2ceSGregory Neil Shapiro **		putflags -- flags for putxline()
2009c2aa98e2SPeter Wemm **
2010c2aa98e2SPeter Wemm **	Returns:
2011355d91e3SGregory Neil Shapiro **		true iff header field was written successfully
2012c2aa98e2SPeter Wemm **
2013c2aa98e2SPeter Wemm **	Side Effects:
2014951742c4SGregory Neil Shapiro **		outputs "p" to "mci".
2015c2aa98e2SPeter Wemm */
2016c2aa98e2SPeter Wemm 
2017567a2fc9SGregory Neil Shapiro bool
201841f3d2ceSGregory Neil Shapiro commaize(h, p, oldstyle, mci, e, putflags)
2019c2aa98e2SPeter Wemm 	register HDR *h;
2020c2aa98e2SPeter Wemm 	register char *p;
2021c2aa98e2SPeter Wemm 	bool oldstyle;
2022c2aa98e2SPeter Wemm 	register MCI *mci;
2023c2aa98e2SPeter Wemm 	register ENVELOPE *e;
202441f3d2ceSGregory Neil Shapiro 	int putflags;
2025c2aa98e2SPeter Wemm {
2026c2aa98e2SPeter Wemm 	register char *obp;
2027951742c4SGregory Neil Shapiro 	int opos, omax, spaces;
202812ed1c7cSGregory Neil Shapiro 	bool firstone = true;
20297660b554SGregory Neil Shapiro 	char **res;
2030c2aa98e2SPeter Wemm 	char obuf[MAXLINE + 3];
2031c2aa98e2SPeter Wemm 
2032c2aa98e2SPeter Wemm 	/*
2033c2aa98e2SPeter Wemm 	**  Output the address list translated by the
2034c2aa98e2SPeter Wemm 	**  mailer and with commas.
2035c2aa98e2SPeter Wemm 	*/
2036c2aa98e2SPeter Wemm 
2037c2aa98e2SPeter Wemm 	if (tTd(14, 2))
203812ed1c7cSGregory Neil Shapiro 		sm_dprintf("commaize(%s:%s)\n", h->h_field, p);
2039c2aa98e2SPeter Wemm 
2040c2aa98e2SPeter Wemm 	if (bitnset(M_7BITHDRS, mci->mci_mailer->m_flags))
2041c2aa98e2SPeter Wemm 		putflags |= PXLF_STRIP8BIT;
2042c2aa98e2SPeter Wemm 
2043c2aa98e2SPeter Wemm 	obp = obuf;
2044951742c4SGregory Neil Shapiro 	(void) sm_snprintf(obp, SPACELEFT(obuf, obp), "%.200s:", h->h_field);
2045951742c4SGregory Neil Shapiro 	/* opos = strlen(obp); instead of the next 3 lines? */
2046951742c4SGregory Neil Shapiro 	opos = strlen(h->h_field) + 1;
2047951742c4SGregory Neil Shapiro 	if (opos > 201)
2048951742c4SGregory Neil Shapiro 		opos = 201;
2049c2aa98e2SPeter Wemm 	obp += opos;
2050951742c4SGregory Neil Shapiro 
2051951742c4SGregory Neil Shapiro 	spaces = 0;
2052951742c4SGregory Neil Shapiro 	while (*p != '\0' && isascii(*p) && isspace(*p))
2053951742c4SGregory Neil Shapiro 	{
2054951742c4SGregory Neil Shapiro 		++spaces;
2055951742c4SGregory Neil Shapiro 		++p;
2056951742c4SGregory Neil Shapiro 	}
2057951742c4SGregory Neil Shapiro 	if (spaces > 0)
2058951742c4SGregory Neil Shapiro 	{
2059951742c4SGregory Neil Shapiro 		SM_ASSERT(sizeof(obuf) > opos  * 2);
2060951742c4SGregory Neil Shapiro 
2061951742c4SGregory Neil Shapiro 		/*
2062951742c4SGregory Neil Shapiro 		**  Restrict number of spaces to half the length of buffer
2063951742c4SGregory Neil Shapiro 		**  so the header field body can be put in here too.
2064951742c4SGregory Neil Shapiro 		**  Note: this is a hack...
2065951742c4SGregory Neil Shapiro 		*/
2066951742c4SGregory Neil Shapiro 
2067951742c4SGregory Neil Shapiro 		if (spaces > sizeof(obuf) / 2)
2068951742c4SGregory Neil Shapiro 			spaces = sizeof(obuf) / 2;
2069951742c4SGregory Neil Shapiro 		(void) sm_snprintf(obp, SPACELEFT(obuf, obp), "%*s", spaces,
2070951742c4SGregory Neil Shapiro 				"");
2071951742c4SGregory Neil Shapiro 		opos += spaces;
2072951742c4SGregory Neil Shapiro 		obp += spaces;
2073951742c4SGregory Neil Shapiro 		SM_ASSERT(obp < &obuf[MAXLINE]);
2074951742c4SGregory Neil Shapiro 	}
2075951742c4SGregory Neil Shapiro 
2076c2aa98e2SPeter Wemm 	omax = mci->mci_mailer->m_linelimit - 2;
2077c2aa98e2SPeter Wemm 	if (omax < 0 || omax > 78)
2078c2aa98e2SPeter Wemm 		omax = 78;
2079c2aa98e2SPeter Wemm 
2080c2aa98e2SPeter Wemm 	/*
2081c2aa98e2SPeter Wemm 	**  Run through the list of values.
2082c2aa98e2SPeter Wemm 	*/
2083c2aa98e2SPeter Wemm 
2084c2aa98e2SPeter Wemm 	while (*p != '\0')
2085c2aa98e2SPeter Wemm 	{
2086c2aa98e2SPeter Wemm 		register char *name;
2087c2aa98e2SPeter Wemm 		register int c;
2088c2aa98e2SPeter Wemm 		char savechar;
2089c2aa98e2SPeter Wemm 		int flags;
20903299c2f1SGregory Neil Shapiro 		auto int status;
2091c2aa98e2SPeter Wemm 
2092c2aa98e2SPeter Wemm 		/*
2093c2aa98e2SPeter Wemm 		**  Find the end of the name.  New style names
2094c2aa98e2SPeter Wemm 		**  end with a comma, old style names end with
2095c2aa98e2SPeter Wemm 		**  a space character.  However, spaces do not
2096c2aa98e2SPeter Wemm 		**  necessarily delimit an old-style name -- at
2097c2aa98e2SPeter Wemm 		**  signs mean keep going.
2098c2aa98e2SPeter Wemm 		*/
2099c2aa98e2SPeter Wemm 
2100c2aa98e2SPeter Wemm 		/* find end of name */
2101c2aa98e2SPeter Wemm 		while ((isascii(*p) && isspace(*p)) || *p == ',')
2102c2aa98e2SPeter Wemm 			p++;
2103c2aa98e2SPeter Wemm 		name = p;
21047660b554SGregory Neil Shapiro 		res = NULL;
2105c2aa98e2SPeter Wemm 		for (;;)
2106c2aa98e2SPeter Wemm 		{
2107c2aa98e2SPeter Wemm 			auto char *oldp;
2108c2aa98e2SPeter Wemm 			char pvpbuf[PSBUFSIZE];
2109c2aa98e2SPeter Wemm 
21107660b554SGregory Neil Shapiro 			res = prescan(p, oldstyle ? ' ' : ',', pvpbuf,
2111951742c4SGregory Neil Shapiro 				      sizeof(pvpbuf), &oldp, ExtTokenTab, false);
2112c2aa98e2SPeter Wemm 			p = oldp;
21137660b554SGregory Neil Shapiro #if _FFR_IGNORE_BOGUS_ADDR
21147660b554SGregory Neil Shapiro 			/* ignore addresses that can't be parsed */
21157660b554SGregory Neil Shapiro 			if (res == NULL)
21167660b554SGregory Neil Shapiro 			{
21177660b554SGregory Neil Shapiro 				name = p;
21187660b554SGregory Neil Shapiro 				continue;
21197660b554SGregory Neil Shapiro 			}
21207660b554SGregory Neil Shapiro #endif /* _FFR_IGNORE_BOGUS_ADDR */
2121c2aa98e2SPeter Wemm 
2122c2aa98e2SPeter Wemm 			/* look to see if we have an at sign */
2123c2aa98e2SPeter Wemm 			while (*p != '\0' && isascii(*p) && isspace(*p))
2124c2aa98e2SPeter Wemm 				p++;
2125c2aa98e2SPeter Wemm 
2126c2aa98e2SPeter Wemm 			if (*p != '@')
2127c2aa98e2SPeter Wemm 			{
2128c2aa98e2SPeter Wemm 				p = oldp;
2129c2aa98e2SPeter Wemm 				break;
2130c2aa98e2SPeter Wemm 			}
213112ed1c7cSGregory Neil Shapiro 			++p;
2132c2aa98e2SPeter Wemm 			while (*p != '\0' && isascii(*p) && isspace(*p))
2133c2aa98e2SPeter Wemm 				p++;
2134c2aa98e2SPeter Wemm 		}
2135c2aa98e2SPeter Wemm 		/* at the end of one complete name */
2136c2aa98e2SPeter Wemm 
2137c2aa98e2SPeter Wemm 		/* strip off trailing white space */
2138c2aa98e2SPeter Wemm 		while (p >= name &&
2139c2aa98e2SPeter Wemm 		       ((isascii(*p) && isspace(*p)) || *p == ',' || *p == '\0'))
2140c2aa98e2SPeter Wemm 			p--;
2141c2aa98e2SPeter Wemm 		if (++p == name)
2142c2aa98e2SPeter Wemm 			continue;
21437660b554SGregory Neil Shapiro 
21447660b554SGregory Neil Shapiro 		/*
21457660b554SGregory Neil Shapiro 		**  if prescan() failed go a bit backwards; this is a hack,
21467660b554SGregory Neil Shapiro 		**  there should be some better error recovery.
21477660b554SGregory Neil Shapiro 		*/
21487660b554SGregory Neil Shapiro 
21497660b554SGregory Neil Shapiro 		if (res == NULL && p > name &&
21507660b554SGregory Neil Shapiro 		    !((isascii(*p) && isspace(*p)) || *p == ',' || *p == '\0'))
21517660b554SGregory Neil Shapiro 			--p;
2152c2aa98e2SPeter Wemm 		savechar = *p;
2153c2aa98e2SPeter Wemm 		*p = '\0';
2154c2aa98e2SPeter Wemm 
2155c2aa98e2SPeter Wemm 		/* translate the name to be relative */
2156c2aa98e2SPeter Wemm 		flags = RF_HEADERADDR|RF_ADDDOMAIN;
2157c2aa98e2SPeter Wemm 		if (bitset(H_FROM, h->h_flags))
2158c2aa98e2SPeter Wemm 			flags |= RF_SENDERADDR;
2159c2aa98e2SPeter Wemm #if USERDB
2160c2aa98e2SPeter Wemm 		else if (e->e_from.q_mailer != NULL &&
2161c2aa98e2SPeter Wemm 			 bitnset(M_UDBRECIPIENT, e->e_from.q_mailer->m_flags))
2162c2aa98e2SPeter Wemm 		{
2163c2aa98e2SPeter Wemm 			char *q;
2164c2aa98e2SPeter Wemm 
216512ed1c7cSGregory Neil Shapiro 			q = udbsender(name, e->e_rpool);
2166c2aa98e2SPeter Wemm 			if (q != NULL)
2167c2aa98e2SPeter Wemm 				name = q;
2168c2aa98e2SPeter Wemm 		}
21693299c2f1SGregory Neil Shapiro #endif /* USERDB */
21703299c2f1SGregory Neil Shapiro 		status = EX_OK;
21713299c2f1SGregory Neil Shapiro 		name = remotename(name, mci->mci_mailer, flags, &status, e);
2172c2aa98e2SPeter Wemm 		if (*name == '\0')
2173c2aa98e2SPeter Wemm 		{
2174c2aa98e2SPeter Wemm 			*p = savechar;
2175c2aa98e2SPeter Wemm 			continue;
2176c2aa98e2SPeter Wemm 		}
217712ed1c7cSGregory Neil Shapiro 		name = denlstring(name, false, true);
2178c2aa98e2SPeter Wemm 
2179c2aa98e2SPeter Wemm 		/* output the name with nice formatting */
2180c2aa98e2SPeter Wemm 		opos += strlen(name);
2181c2aa98e2SPeter Wemm 		if (!firstone)
2182c2aa98e2SPeter Wemm 			opos += 2;
2183c2aa98e2SPeter Wemm 		if (opos > omax && !firstone)
2184c2aa98e2SPeter Wemm 		{
218512ed1c7cSGregory Neil Shapiro 			(void) sm_strlcpy(obp, ",\n", SPACELEFT(obuf, obp));
2186567a2fc9SGregory Neil Shapiro 			if (!putxline(obuf, strlen(obuf), mci, putflags))
2187567a2fc9SGregory Neil Shapiro 				goto writeerr;
2188c2aa98e2SPeter Wemm 			obp = obuf;
2189951742c4SGregory Neil Shapiro 			(void) sm_strlcpy(obp, "        ", sizeof(obuf));
2190c2aa98e2SPeter Wemm 			opos = strlen(obp);
2191c2aa98e2SPeter Wemm 			obp += opos;
2192c2aa98e2SPeter Wemm 			opos += strlen(name);
2193c2aa98e2SPeter Wemm 		}
2194c2aa98e2SPeter Wemm 		else if (!firstone)
2195c2aa98e2SPeter Wemm 		{
219612ed1c7cSGregory Neil Shapiro 			(void) sm_strlcpy(obp, ", ", SPACELEFT(obuf, obp));
2197c2aa98e2SPeter Wemm 			obp += 2;
2198c2aa98e2SPeter Wemm 		}
2199c2aa98e2SPeter Wemm 
2200c2aa98e2SPeter Wemm 		while ((c = *name++) != '\0' && obp < &obuf[MAXLINE])
2201c2aa98e2SPeter Wemm 			*obp++ = c;
220212ed1c7cSGregory Neil Shapiro 		firstone = false;
2203c2aa98e2SPeter Wemm 		*p = savechar;
2204c2aa98e2SPeter Wemm 	}
2205951742c4SGregory Neil Shapiro 	if (obp < &obuf[sizeof(obuf)])
2206c2aa98e2SPeter Wemm 		*obp = '\0';
22077660b554SGregory Neil Shapiro 	else
2208951742c4SGregory Neil Shapiro 		obuf[sizeof(obuf) - 1] = '\0';
2209567a2fc9SGregory Neil Shapiro 	return putxline(obuf, strlen(obuf), mci, putflags);
2210567a2fc9SGregory Neil Shapiro 
2211567a2fc9SGregory Neil Shapiro   writeerr:
2212567a2fc9SGregory Neil Shapiro 	return false;
2213c2aa98e2SPeter Wemm }
2214567a2fc9SGregory Neil Shapiro 
221512ed1c7cSGregory Neil Shapiro /*
2216c2aa98e2SPeter Wemm **  COPYHEADER -- copy header list
2217c2aa98e2SPeter Wemm **
2218c2aa98e2SPeter Wemm **	This routine is the equivalent of newstr for header lists
2219c2aa98e2SPeter Wemm **
2220c2aa98e2SPeter Wemm **	Parameters:
2221c2aa98e2SPeter Wemm **		header -- list of header structures to copy.
222212ed1c7cSGregory Neil Shapiro **		rpool -- resource pool, or NULL
2223c2aa98e2SPeter Wemm **
2224c2aa98e2SPeter Wemm **	Returns:
2225c2aa98e2SPeter Wemm **		a copy of 'header'.
2226c2aa98e2SPeter Wemm **
2227c2aa98e2SPeter Wemm **	Side Effects:
2228c2aa98e2SPeter Wemm **		none.
2229c2aa98e2SPeter Wemm */
2230c2aa98e2SPeter Wemm 
2231c2aa98e2SPeter Wemm HDR *
223212ed1c7cSGregory Neil Shapiro copyheader(header, rpool)
2233c2aa98e2SPeter Wemm 	register HDR *header;
223412ed1c7cSGregory Neil Shapiro 	SM_RPOOL_T *rpool;
2235c2aa98e2SPeter Wemm {
2236c2aa98e2SPeter Wemm 	register HDR *newhdr;
2237c2aa98e2SPeter Wemm 	HDR *ret;
2238c2aa98e2SPeter Wemm 	register HDR **tail = &ret;
2239c2aa98e2SPeter Wemm 
2240c2aa98e2SPeter Wemm 	while (header != NULL)
2241c2aa98e2SPeter Wemm 	{
2242951742c4SGregory Neil Shapiro 		newhdr = (HDR *) sm_rpool_malloc_x(rpool, sizeof(*newhdr));
2243c2aa98e2SPeter Wemm 		STRUCTCOPY(*header, *newhdr);
2244c2aa98e2SPeter Wemm 		*tail = newhdr;
2245c2aa98e2SPeter Wemm 		tail = &newhdr->h_link;
2246c2aa98e2SPeter Wemm 		header = header->h_link;
2247c2aa98e2SPeter Wemm 	}
2248c2aa98e2SPeter Wemm 	*tail = NULL;
2249c2aa98e2SPeter Wemm 
2250c2aa98e2SPeter Wemm 	return ret;
2251c2aa98e2SPeter Wemm }
2252951742c4SGregory Neil Shapiro 
225312ed1c7cSGregory Neil Shapiro /*
225476b7bf71SPeter Wemm **  FIX_MIME_HEADER -- possibly truncate/rebalance parameters in a MIME header
225576b7bf71SPeter Wemm **
225676b7bf71SPeter Wemm **	Run through all of the parameters of a MIME header and
225776b7bf71SPeter Wemm **	possibly truncate and rebalance the parameter according
225876b7bf71SPeter Wemm **	to MaxMimeFieldLength.
225976b7bf71SPeter Wemm **
226076b7bf71SPeter Wemm **	Parameters:
2261f9218d3dSGregory Neil Shapiro **		h -- the header to truncate/rebalance
2262f9218d3dSGregory Neil Shapiro **		e -- the current envelope
226376b7bf71SPeter Wemm **
226476b7bf71SPeter Wemm **	Returns:
2265c46d91b7SGregory Neil Shapiro **		length of last offending field, 0 if all ok.
226676b7bf71SPeter Wemm **
226776b7bf71SPeter Wemm **	Side Effects:
226876b7bf71SPeter Wemm **		string modified in place
226976b7bf71SPeter Wemm */
227076b7bf71SPeter Wemm 
2271c46d91b7SGregory Neil Shapiro static size_t
2272f9218d3dSGregory Neil Shapiro fix_mime_header(h, e)
2273f9218d3dSGregory Neil Shapiro 	HDR *h;
2274f9218d3dSGregory Neil Shapiro 	ENVELOPE *e;
227576b7bf71SPeter Wemm {
2276f9218d3dSGregory Neil Shapiro 	char *begin = h->h_value;
227776b7bf71SPeter Wemm 	char *end;
2278c46d91b7SGregory Neil Shapiro 	size_t len = 0;
2279c46d91b7SGregory Neil Shapiro 	size_t retlen = 0;
228076b7bf71SPeter Wemm 
2281f9218d3dSGregory Neil Shapiro 	if (begin == NULL || *begin == '\0')
2282c46d91b7SGregory Neil Shapiro 		return 0;
228376b7bf71SPeter Wemm 
228476b7bf71SPeter Wemm 	/* Split on each ';' */
22857660b554SGregory Neil Shapiro 	/* find_character() never returns NULL */
228676b7bf71SPeter Wemm 	while ((end = find_character(begin, ';')) != NULL)
228776b7bf71SPeter Wemm 	{
228876b7bf71SPeter Wemm 		char save = *end;
228976b7bf71SPeter Wemm 		char *bp;
229076b7bf71SPeter Wemm 
229176b7bf71SPeter Wemm 		*end = '\0';
229276b7bf71SPeter Wemm 
2293c46d91b7SGregory Neil Shapiro 		len = strlen(begin);
2294c46d91b7SGregory Neil Shapiro 
229576b7bf71SPeter Wemm 		/* Shorten individual parameter */
229676b7bf71SPeter Wemm 		if (shorten_rfc822_string(begin, MaxMimeFieldLength))
2297f9218d3dSGregory Neil Shapiro 		{
2298f9218d3dSGregory Neil Shapiro 			if (len < MaxMimeFieldLength)
2299f9218d3dSGregory Neil Shapiro 			{
2300f9218d3dSGregory Neil Shapiro 				/* we only rebalanced a bogus field */
2301f9218d3dSGregory Neil Shapiro 				sm_syslog(LOG_ALERT, e->e_id,
2302f9218d3dSGregory Neil Shapiro 					  "Fixed MIME %s header field (possible attack)",
2303f9218d3dSGregory Neil Shapiro 					  h->h_field);
2304f9218d3dSGregory Neil Shapiro 				if (tTd(34, 11))
2305f9218d3dSGregory Neil Shapiro 					sm_dprintf("  fixed MIME %s header field (possible attack)\n",
2306f9218d3dSGregory Neil Shapiro 						   h->h_field);
2307f9218d3dSGregory Neil Shapiro 			}
2308f9218d3dSGregory Neil Shapiro 			else
2309f9218d3dSGregory Neil Shapiro 			{
2310f9218d3dSGregory Neil Shapiro 				/* we actually shortened the header */
2311c46d91b7SGregory Neil Shapiro 				retlen = len;
2312f9218d3dSGregory Neil Shapiro 			}
2313f9218d3dSGregory Neil Shapiro 		}
231476b7bf71SPeter Wemm 
231576b7bf71SPeter Wemm 		/* Collapse the possibly shortened string with rest */
231676b7bf71SPeter Wemm 		bp = begin + strlen(begin);
231776b7bf71SPeter Wemm 		if (bp != end)
231876b7bf71SPeter Wemm 		{
231976b7bf71SPeter Wemm 			char *ep = end;
232076b7bf71SPeter Wemm 
232176b7bf71SPeter Wemm 			*end = save;
232276b7bf71SPeter Wemm 			end = bp;
232376b7bf71SPeter Wemm 
232476b7bf71SPeter Wemm 			/* copy character by character due to overlap */
232576b7bf71SPeter Wemm 			while (*ep != '\0')
232676b7bf71SPeter Wemm 				*bp++ = *ep++;
232776b7bf71SPeter Wemm 			*bp = '\0';
232876b7bf71SPeter Wemm 		}
232976b7bf71SPeter Wemm 		else
233076b7bf71SPeter Wemm 			*end = save;
233176b7bf71SPeter Wemm 		if (*end == '\0')
233276b7bf71SPeter Wemm 			break;
233376b7bf71SPeter Wemm 
233476b7bf71SPeter Wemm 		/* Move past ';' */
233576b7bf71SPeter Wemm 		begin = end + 1;
233676b7bf71SPeter Wemm 	}
2337c46d91b7SGregory Neil Shapiro 	return retlen;
233876b7bf71SPeter Wemm }
2339