xref: /freebsd/contrib/sendmail/src/headers.c (revision 355d91e30e0f9d2d767b7cb557ba3d83a1a74b1c)
1c2aa98e2SPeter Wemm /*
2567a2fc9SGregory Neil Shapiro  * Copyright (c) 1998-2004, 2006 Sendmail, 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  *
127660b554SGregory Neil Shapiro  * $FreeBSD$
13c2aa98e2SPeter Wemm  */
14c2aa98e2SPeter Wemm 
1512ed1c7cSGregory Neil Shapiro #include <sendmail.h>
16c2aa98e2SPeter Wemm 
17355d91e3SGregory Neil Shapiro SM_RCSID("@(#)$Id: headers.c,v 8.291 2006/03/24 01:01:56 ca Exp $")
183299c2f1SGregory Neil Shapiro 
19bfb62e91SGregory Neil Shapiro static HDR	*allocheader __P((char *, char *, int, SM_RPOOL_T *));
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 }
4712ed1c7cSGregory Neil Shapiro /*
48c2aa98e2SPeter Wemm **  CHOMPHEADER -- process and save a header line.
49c2aa98e2SPeter Wemm **
503299c2f1SGregory Neil Shapiro **	Called by collect, readcf, and readqf to deal with header lines.
51c2aa98e2SPeter Wemm **
52c2aa98e2SPeter Wemm **	Parameters:
53c2aa98e2SPeter Wemm **		line -- header as a text line.
54d995d2baSGregory Neil Shapiro **		pflag -- flags for chompheader() (from sendmail.h)
55c2aa98e2SPeter Wemm **		hdrp -- a pointer to the place to save the header.
56c2aa98e2SPeter Wemm **		e -- the envelope including this header.
57c2aa98e2SPeter Wemm **
58c2aa98e2SPeter Wemm **	Returns:
59c2aa98e2SPeter Wemm **		flags for this header.
60c2aa98e2SPeter Wemm **
61c2aa98e2SPeter Wemm **	Side Effects:
62c2aa98e2SPeter Wemm **		The header is saved on the header list.
63c2aa98e2SPeter Wemm **		Contents of 'line' are destroyed.
64c2aa98e2SPeter Wemm */
65c2aa98e2SPeter Wemm 
663299c2f1SGregory Neil Shapiro static struct hdrinfo	NormalHeader =	{ NULL, 0, NULL };
67c2aa98e2SPeter Wemm 
6812ed1c7cSGregory Neil Shapiro unsigned long
693299c2f1SGregory Neil Shapiro chompheader(line, pflag, hdrp, e)
70c2aa98e2SPeter Wemm 	char *line;
713299c2f1SGregory Neil Shapiro 	int pflag;
72c2aa98e2SPeter Wemm 	HDR **hdrp;
73c2aa98e2SPeter Wemm 	register ENVELOPE *e;
74c2aa98e2SPeter Wemm {
7512ed1c7cSGregory Neil Shapiro 	unsigned char mid = '\0';
76c2aa98e2SPeter Wemm 	register char *p;
77c2aa98e2SPeter Wemm 	register HDR *h;
78c2aa98e2SPeter Wemm 	HDR **hp;
79c2aa98e2SPeter Wemm 	char *fname;
80c2aa98e2SPeter Wemm 	char *fvalue;
8112ed1c7cSGregory Neil Shapiro 	bool cond = false;
823299c2f1SGregory Neil Shapiro 	bool dropfrom;
83c2aa98e2SPeter Wemm 	bool headeronly;
84c2aa98e2SPeter Wemm 	STAB *s;
85c2aa98e2SPeter Wemm 	struct hdrinfo *hi;
8612ed1c7cSGregory Neil Shapiro 	bool nullheader = false;
873299c2f1SGregory Neil Shapiro 	BITMAP256 mopts;
88c2aa98e2SPeter Wemm 
89c2aa98e2SPeter Wemm 	if (tTd(31, 6))
90c2aa98e2SPeter Wemm 	{
9112ed1c7cSGregory Neil Shapiro 		sm_dprintf("chompheader: ");
92bfb62e91SGregory Neil Shapiro 		xputs(sm_debug_file(), line);
9312ed1c7cSGregory Neil Shapiro 		sm_dprintf("\n");
94c2aa98e2SPeter Wemm 	}
95c2aa98e2SPeter Wemm 
96c2aa98e2SPeter Wemm 	headeronly = hdrp != NULL;
97c2aa98e2SPeter Wemm 	if (!headeronly)
98c2aa98e2SPeter Wemm 		hdrp = &e->e_header;
99c2aa98e2SPeter Wemm 
100c2aa98e2SPeter Wemm 	/* strip off options */
101c2aa98e2SPeter Wemm 	clrbitmap(mopts);
102c2aa98e2SPeter Wemm 	p = line;
1033299c2f1SGregory Neil Shapiro 	if (!bitset(pflag, CHHDR_USER) && *p == '?')
104c2aa98e2SPeter Wemm 	{
1053299c2f1SGregory Neil Shapiro 		int c;
1063299c2f1SGregory Neil Shapiro 		register char *q;
107c2aa98e2SPeter Wemm 
1083299c2f1SGregory Neil Shapiro 		q = strchr(++p, '?');
1093299c2f1SGregory Neil Shapiro 		if (q == NULL)
1103299c2f1SGregory Neil Shapiro 			goto hse;
1113299c2f1SGregory Neil Shapiro 
1123299c2f1SGregory Neil Shapiro 		*q = '\0';
1133299c2f1SGregory Neil Shapiro 		c = *p & 0377;
1143299c2f1SGregory Neil Shapiro 
1153299c2f1SGregory Neil Shapiro 		/* possibly macro conditional */
1163299c2f1SGregory Neil Shapiro 		if (c == MACROEXPAND)
117c2aa98e2SPeter Wemm 		{
1183299c2f1SGregory Neil Shapiro 			/* catch ?$? */
1193299c2f1SGregory Neil Shapiro 			if (*++p == '\0')
1203299c2f1SGregory Neil Shapiro 			{
1213299c2f1SGregory Neil Shapiro 				*q = '?';
1223299c2f1SGregory Neil Shapiro 				goto hse;
1233299c2f1SGregory Neil Shapiro 			}
1243299c2f1SGregory Neil Shapiro 
12512ed1c7cSGregory Neil Shapiro 			mid = (unsigned char) *p++;
1263299c2f1SGregory Neil Shapiro 
1273299c2f1SGregory Neil Shapiro 			/* catch ?$abc? */
1283299c2f1SGregory Neil Shapiro 			if (*p != '\0')
1293299c2f1SGregory Neil Shapiro 			{
1303299c2f1SGregory Neil Shapiro 				*q = '?';
1313299c2f1SGregory Neil Shapiro 				goto hse;
1323299c2f1SGregory Neil Shapiro 			}
1333299c2f1SGregory Neil Shapiro 		}
1343299c2f1SGregory Neil Shapiro 		else if (*p == '$')
1353299c2f1SGregory Neil Shapiro 		{
1363299c2f1SGregory Neil Shapiro 			/* catch ?$? */
1373299c2f1SGregory Neil Shapiro 			if (*++p == '\0')
1383299c2f1SGregory Neil Shapiro 			{
1393299c2f1SGregory Neil Shapiro 				*q = '?';
1403299c2f1SGregory Neil Shapiro 				goto hse;
1413299c2f1SGregory Neil Shapiro 			}
1423299c2f1SGregory Neil Shapiro 
14312ed1c7cSGregory Neil Shapiro 			mid = (unsigned char) macid(p);
1443299c2f1SGregory Neil Shapiro 			if (bitset(0200, mid))
1457660b554SGregory Neil Shapiro 			{
1463299c2f1SGregory Neil Shapiro 				p += strlen(macname(mid)) + 2;
1477660b554SGregory Neil Shapiro 				SM_ASSERT(p <= q);
1487660b554SGregory Neil Shapiro 			}
1493299c2f1SGregory Neil Shapiro 			else
1503299c2f1SGregory Neil Shapiro 				p++;
1513299c2f1SGregory Neil Shapiro 
1523299c2f1SGregory Neil Shapiro 			/* catch ?$abc? */
1533299c2f1SGregory Neil Shapiro 			if (*p != '\0')
1543299c2f1SGregory Neil Shapiro 			{
1553299c2f1SGregory Neil Shapiro 				*q = '?';
1563299c2f1SGregory Neil Shapiro 				goto hse;
1573299c2f1SGregory Neil Shapiro 			}
158c2aa98e2SPeter Wemm 		}
159c2aa98e2SPeter Wemm 		else
1603299c2f1SGregory Neil Shapiro 		{
1613299c2f1SGregory Neil Shapiro 			while (*p != '\0')
1623299c2f1SGregory Neil Shapiro 			{
1633299c2f1SGregory Neil Shapiro 				if (!isascii(*p))
1643299c2f1SGregory Neil Shapiro 				{
1653299c2f1SGregory Neil Shapiro 					*q = '?';
1663299c2f1SGregory Neil Shapiro 					goto hse;
1673299c2f1SGregory Neil Shapiro 				}
1683299c2f1SGregory Neil Shapiro 
169c46d91b7SGregory Neil Shapiro 				setbitn(bitidx(*p), mopts);
17012ed1c7cSGregory Neil Shapiro 				cond = true;
1713299c2f1SGregory Neil Shapiro 				p++;
1723299c2f1SGregory Neil Shapiro 			}
1733299c2f1SGregory Neil Shapiro 		}
1743299c2f1SGregory Neil Shapiro 		p = q + 1;
175c2aa98e2SPeter Wemm 	}
176c2aa98e2SPeter Wemm 
177c2aa98e2SPeter Wemm 	/* find canonical name */
178c2aa98e2SPeter Wemm 	fname = p;
179c2aa98e2SPeter Wemm 	while (isascii(*p) && isgraph(*p) && *p != ':')
180c2aa98e2SPeter Wemm 		p++;
181c2aa98e2SPeter Wemm 	fvalue = p;
182c2aa98e2SPeter Wemm 	while (isascii(*p) && isspace(*p))
183c2aa98e2SPeter Wemm 		p++;
184c2aa98e2SPeter Wemm 	if (*p++ != ':' || fname == fvalue)
185c2aa98e2SPeter Wemm 	{
1863299c2f1SGregory Neil Shapiro hse:
1873299c2f1SGregory Neil Shapiro 		syserr("553 5.3.0 header syntax error, line \"%s\"", line);
188c2aa98e2SPeter Wemm 		return 0;
189c2aa98e2SPeter Wemm 	}
190c2aa98e2SPeter Wemm 	*fvalue = '\0';
191c2aa98e2SPeter Wemm 
192c2aa98e2SPeter Wemm 	/* strip field value on front */
193e01d6f61SPeter Wemm 	if (*p == ' ')
194e01d6f61SPeter Wemm 		p++;
195e01d6f61SPeter Wemm 	fvalue = p;
196e01d6f61SPeter Wemm 
197e01d6f61SPeter Wemm 	/* if the field is null, go ahead and use the default */
198e01d6f61SPeter Wemm 	while (isascii(*p) && isspace(*p))
199e01d6f61SPeter Wemm 		p++;
200e01d6f61SPeter Wemm 	if (*p == '\0')
20112ed1c7cSGregory Neil Shapiro 		nullheader = true;
202c2aa98e2SPeter Wemm 
203c2aa98e2SPeter Wemm 	/* security scan: long field names are end-of-header */
204c2aa98e2SPeter Wemm 	if (strlen(fname) > 100)
205c2aa98e2SPeter Wemm 		return H_EOH;
206c2aa98e2SPeter Wemm 
207c2aa98e2SPeter Wemm 	/* check to see if it represents a ruleset call */
2083299c2f1SGregory Neil Shapiro 	if (bitset(pflag, CHHDR_DEF))
209c2aa98e2SPeter Wemm 	{
210c2aa98e2SPeter Wemm 		char hbuf[50];
211c2aa98e2SPeter Wemm 
212c2aa98e2SPeter Wemm 		(void) expand(fvalue, hbuf, sizeof hbuf, e);
213c2aa98e2SPeter Wemm 		for (p = hbuf; isascii(*p) && isspace(*p); )
214c2aa98e2SPeter Wemm 			p++;
215c2aa98e2SPeter Wemm 		if ((*p++ & 0377) == CALLSUBR)
216c2aa98e2SPeter Wemm 		{
217c2aa98e2SPeter Wemm 			auto char *endp;
2183299c2f1SGregory Neil Shapiro 			bool strc;
219c2aa98e2SPeter Wemm 
2203299c2f1SGregory Neil Shapiro 			strc = *p == '+';	/* strip comments? */
2213299c2f1SGregory Neil Shapiro 			if (strc)
2223299c2f1SGregory Neil Shapiro 				++p;
223c2aa98e2SPeter Wemm 			if (strtorwset(p, &endp, ST_ENTER) > 0)
224c2aa98e2SPeter Wemm 			{
225c2aa98e2SPeter Wemm 				*endp = '\0';
226c2aa98e2SPeter Wemm 				s = stab(fname, ST_HEADER, ST_ENTER);
22712ed1c7cSGregory Neil Shapiro 				if (LogLevel > 9 &&
22812ed1c7cSGregory Neil Shapiro 				    s->s_header.hi_ruleset != NULL)
22912ed1c7cSGregory Neil Shapiro 					sm_syslog(LOG_WARNING, NOQID,
23012ed1c7cSGregory Neil Shapiro 						  "Warning: redefined ruleset for header=%s, old=%s, new=%s",
23112ed1c7cSGregory Neil Shapiro 						  fname,
23212ed1c7cSGregory Neil Shapiro 						  s->s_header.hi_ruleset, p);
233c2aa98e2SPeter Wemm 				s->s_header.hi_ruleset = newstr(p);
2343299c2f1SGregory Neil Shapiro 				if (!strc)
2353299c2f1SGregory Neil Shapiro 					s->s_header.hi_flags |= H_STRIPCOMM;
236c2aa98e2SPeter Wemm 			}
237c2aa98e2SPeter Wemm 			return 0;
238c2aa98e2SPeter Wemm 		}
239c2aa98e2SPeter Wemm 	}
240c2aa98e2SPeter Wemm 
241c2aa98e2SPeter Wemm 	/* see if it is a known type */
242c2aa98e2SPeter Wemm 	s = stab(fname, ST_HEADER, ST_FIND);
243c2aa98e2SPeter Wemm 	if (s != NULL)
244c2aa98e2SPeter Wemm 		hi = &s->s_header;
245c2aa98e2SPeter Wemm 	else
246c2aa98e2SPeter Wemm 		hi = &NormalHeader;
247c2aa98e2SPeter Wemm 
248c2aa98e2SPeter Wemm 	if (tTd(31, 9))
249c2aa98e2SPeter Wemm 	{
250c2aa98e2SPeter Wemm 		if (s == NULL)
25112ed1c7cSGregory Neil Shapiro 			sm_dprintf("no header flags match\n");
252c2aa98e2SPeter Wemm 		else
25312ed1c7cSGregory Neil Shapiro 			sm_dprintf("header match, flags=%lx, ruleset=%s\n",
254c2aa98e2SPeter Wemm 				   hi->hi_flags,
25512ed1c7cSGregory Neil Shapiro 				   hi->hi_ruleset == NULL ? "<NULL>"
25612ed1c7cSGregory Neil Shapiro 							  : hi->hi_ruleset);
257c2aa98e2SPeter Wemm 	}
258c2aa98e2SPeter Wemm 
259c2aa98e2SPeter Wemm 	/* see if this is a resent message */
2603299c2f1SGregory Neil Shapiro 	if (!bitset(pflag, CHHDR_DEF) && !headeronly &&
2613299c2f1SGregory Neil Shapiro 	    bitset(H_RESENT, hi->hi_flags))
262c2aa98e2SPeter Wemm 		e->e_flags |= EF_RESENT;
263c2aa98e2SPeter Wemm 
264c2aa98e2SPeter Wemm 	/* if this is an Errors-To: header keep track of it now */
2653299c2f1SGregory Neil Shapiro 	if (UseErrorsTo && !bitset(pflag, CHHDR_DEF) && !headeronly &&
266c2aa98e2SPeter Wemm 	    bitset(H_ERRORSTO, hi->hi_flags))
267c2aa98e2SPeter Wemm 		(void) sendtolist(fvalue, NULLADDR, &e->e_errorqueue, 0, e);
268c2aa98e2SPeter Wemm 
269c2aa98e2SPeter Wemm 	/* if this means "end of header" quit now */
270c2aa98e2SPeter Wemm 	if (!headeronly && bitset(H_EOH, hi->hi_flags))
271c2aa98e2SPeter Wemm 		return hi->hi_flags;
272c2aa98e2SPeter Wemm 
273c2aa98e2SPeter Wemm 	/*
274c2aa98e2SPeter Wemm 	**  Horrible hack to work around problem with Lotus Notes SMTP
275c2aa98e2SPeter Wemm 	**  mail gateway, which generates From: headers with newlines in
276c2aa98e2SPeter Wemm 	**  them and the <address> on the second line.  Although this is
277c2aa98e2SPeter Wemm 	**  legal RFC 822, many MUAs don't handle this properly and thus
278c2aa98e2SPeter Wemm 	**  never find the actual address.
279c2aa98e2SPeter Wemm 	*/
280c2aa98e2SPeter Wemm 
281c2aa98e2SPeter Wemm 	if (bitset(H_FROM, hi->hi_flags) && SingleLineFromHeader)
282c2aa98e2SPeter Wemm 	{
283c2aa98e2SPeter Wemm 		while ((p = strchr(fvalue, '\n')) != NULL)
284c2aa98e2SPeter Wemm 			*p = ' ';
285c2aa98e2SPeter Wemm 	}
286c2aa98e2SPeter Wemm 
287c2aa98e2SPeter Wemm 	/*
288c2aa98e2SPeter Wemm 	**  If there is a check ruleset, verify it against the header.
289c2aa98e2SPeter Wemm 	*/
290c2aa98e2SPeter Wemm 
2913299c2f1SGregory Neil Shapiro 	if (bitset(pflag, CHHDR_CHECK))
2923299c2f1SGregory Neil Shapiro 	{
2939d8fddc1SGregory Neil Shapiro 		int rscheckflags;
2943299c2f1SGregory Neil Shapiro 		char *rs;
2953299c2f1SGregory Neil Shapiro 
2969d8fddc1SGregory Neil Shapiro 		rscheckflags = RSF_COUNT;
2979d8fddc1SGregory Neil Shapiro 		if (!bitset(hi->hi_flags, H_FROM|H_RCPT))
2989d8fddc1SGregory Neil Shapiro 			rscheckflags |= RSF_UNSTRUCTURED;
299bfb62e91SGregory Neil Shapiro 
300bfb62e91SGregory Neil Shapiro 		/* no ruleset? look for default */
301bfb62e91SGregory Neil Shapiro 		rs = hi->hi_ruleset;
3023299c2f1SGregory Neil Shapiro 		if (rs == NULL)
3033299c2f1SGregory Neil Shapiro 		{
3043299c2f1SGregory Neil Shapiro 			s = stab("*", ST_HEADER, ST_FIND);
3053299c2f1SGregory Neil Shapiro 			if (s != NULL)
3063299c2f1SGregory Neil Shapiro 			{
3073299c2f1SGregory Neil Shapiro 				rs = (&s->s_header)->hi_ruleset;
3089d8fddc1SGregory Neil Shapiro 				if (bitset((&s->s_header)->hi_flags,
3099d8fddc1SGregory Neil Shapiro 					   H_STRIPCOMM))
3109d8fddc1SGregory Neil Shapiro 					rscheckflags |= RSF_RMCOMM;
3113299c2f1SGregory Neil Shapiro 			}
3123299c2f1SGregory Neil Shapiro 		}
3139d8fddc1SGregory Neil Shapiro 		else if (bitset(hi->hi_flags, H_STRIPCOMM))
3149d8fddc1SGregory Neil Shapiro 			rscheckflags |= RSF_RMCOMM;
3153299c2f1SGregory Neil Shapiro 		if (rs != NULL)
3163299c2f1SGregory Neil Shapiro 		{
31712ed1c7cSGregory Neil Shapiro 			int l, k;
3183299c2f1SGregory Neil Shapiro 			char qval[MAXNAME];
3193299c2f1SGregory Neil Shapiro 
3203299c2f1SGregory Neil Shapiro 			l = 0;
32112ed1c7cSGregory Neil Shapiro 			qval[l++] = '"';
32212ed1c7cSGregory Neil Shapiro 
32312ed1c7cSGregory Neil Shapiro 			/* - 3 to avoid problems with " at the end */
3247660b554SGregory Neil Shapiro 			/* should be sizeof(qval), not MAXNAME */
32512ed1c7cSGregory Neil Shapiro 			for (k = 0; fvalue[k] != '\0' && l < MAXNAME - 3; k++)
3263299c2f1SGregory Neil Shapiro 			{
32712ed1c7cSGregory Neil Shapiro 				switch (fvalue[k])
3283299c2f1SGregory Neil Shapiro 				{
32912ed1c7cSGregory Neil Shapiro 				  /* XXX other control chars? */
3303299c2f1SGregory Neil Shapiro 				  case '\011': /* ht */
3313299c2f1SGregory Neil Shapiro 				  case '\012': /* nl */
3323299c2f1SGregory Neil Shapiro 				  case '\013': /* vt */
3333299c2f1SGregory Neil Shapiro 				  case '\014': /* np */
3343299c2f1SGregory Neil Shapiro 				  case '\015': /* cr */
33512ed1c7cSGregory Neil Shapiro 					qval[l++] = ' ';
3363299c2f1SGregory Neil Shapiro 					break;
3373299c2f1SGregory Neil Shapiro 				  case '"':
33812ed1c7cSGregory Neil Shapiro 					qval[l++] = '\\';
3393299c2f1SGregory Neil Shapiro 					/* FALLTHROUGH */
3403299c2f1SGregory Neil Shapiro 				  default:
34112ed1c7cSGregory Neil Shapiro 					qval[l++] = fvalue[k];
3423299c2f1SGregory Neil Shapiro 					break;
3433299c2f1SGregory Neil Shapiro 				}
3443299c2f1SGregory Neil Shapiro 			}
34512ed1c7cSGregory Neil Shapiro 			qval[l++] = '"';
34612ed1c7cSGregory Neil Shapiro 			qval[l] = '\0';
34712ed1c7cSGregory Neil Shapiro 			k += strlen(fvalue + k);
34812ed1c7cSGregory Neil Shapiro 			if (k >= MAXNAME)
3493299c2f1SGregory Neil Shapiro 			{
3503299c2f1SGregory Neil Shapiro 				if (LogLevel > 9)
3513299c2f1SGregory Neil Shapiro 					sm_syslog(LOG_WARNING, e->e_id,
3523299c2f1SGregory Neil Shapiro 						  "Warning: truncated header '%s' before check with '%s' len=%d max=%d",
35312ed1c7cSGregory Neil Shapiro 						  fname, rs, k, MAXNAME - 1);
3543299c2f1SGregory Neil Shapiro 			}
35512ed1c7cSGregory Neil Shapiro 			macdefine(&e->e_macro, A_TEMP,
35612ed1c7cSGregory Neil Shapiro 				macid("{currHeader}"), qval);
35712ed1c7cSGregory Neil Shapiro 			macdefine(&e->e_macro, A_TEMP,
35812ed1c7cSGregory Neil Shapiro 				macid("{hdr_name}"), fname);
35912ed1c7cSGregory Neil Shapiro 
36012ed1c7cSGregory Neil Shapiro 			(void) sm_snprintf(qval, sizeof qval, "%d", k);
36112ed1c7cSGregory Neil Shapiro 			macdefine(&e->e_macro, A_TEMP, macid("{hdrlen}"), qval);
36212ed1c7cSGregory Neil Shapiro #if _FFR_HDR_TYPE
363bfb62e91SGregory Neil Shapiro 			if (bitset(H_FROM, hi->hi_flags))
36412ed1c7cSGregory Neil Shapiro 				macdefine(&e->e_macro, A_PERM,
36512ed1c7cSGregory Neil Shapiro 					macid("{addr_type}"), "h s");
366bfb62e91SGregory Neil Shapiro 			else if (bitset(H_RCPT, hi->hi_flags))
36712ed1c7cSGregory Neil Shapiro 				macdefine(&e->e_macro, A_PERM,
36812ed1c7cSGregory Neil Shapiro 					macid("{addr_type}"), "h r");
36912ed1c7cSGregory Neil Shapiro 			else
37012ed1c7cSGregory Neil Shapiro #endif /* _FFR_HDR_TYPE */
37112ed1c7cSGregory Neil Shapiro 				macdefine(&e->e_macro, A_PERM,
37212ed1c7cSGregory Neil Shapiro 					macid("{addr_type}"), "h");
3739d8fddc1SGregory Neil Shapiro 			(void) rscheck(rs, fvalue, NULL, e, rscheckflags, 3,
37412ed1c7cSGregory Neil Shapiro 				       NULL, e->e_id);
3753299c2f1SGregory Neil Shapiro 		}
3763299c2f1SGregory Neil Shapiro 	}
377c2aa98e2SPeter Wemm 
378c2aa98e2SPeter Wemm 	/*
379c2aa98e2SPeter Wemm 	**  Drop explicit From: if same as what we would generate.
380c2aa98e2SPeter Wemm 	**  This is to make MH (which doesn't always give a full name)
381c2aa98e2SPeter Wemm 	**  insert the full name information in all circumstances.
382c2aa98e2SPeter Wemm 	*/
383c2aa98e2SPeter Wemm 
38412ed1c7cSGregory Neil Shapiro 	dropfrom = false;
385c2aa98e2SPeter Wemm 	p = "resent-from";
386c2aa98e2SPeter Wemm 	if (!bitset(EF_RESENT, e->e_flags))
387c2aa98e2SPeter Wemm 		p += 7;
3883299c2f1SGregory Neil Shapiro 	if (!bitset(pflag, CHHDR_DEF) && !headeronly &&
38912ed1c7cSGregory Neil Shapiro 	    !bitset(EF_QUEUERUN, e->e_flags) && sm_strcasecmp(fname, p) == 0)
390c2aa98e2SPeter Wemm 	{
391c2aa98e2SPeter Wemm 		if (tTd(31, 2))
392c2aa98e2SPeter Wemm 		{
39312ed1c7cSGregory Neil Shapiro 			sm_dprintf("comparing header from (%s) against default (%s or %s)\n",
394c2aa98e2SPeter Wemm 				fvalue, e->e_from.q_paddr, e->e_from.q_user);
395c2aa98e2SPeter Wemm 		}
396c2aa98e2SPeter Wemm 		if (e->e_from.q_paddr != NULL &&
3973299c2f1SGregory Neil Shapiro 		    e->e_from.q_mailer != NULL &&
3983299c2f1SGregory Neil Shapiro 		    bitnset(M_LOCALMAILER, e->e_from.q_mailer->m_flags) &&
399c2aa98e2SPeter Wemm 		    (strcmp(fvalue, e->e_from.q_paddr) == 0 ||
400c2aa98e2SPeter Wemm 		     strcmp(fvalue, e->e_from.q_user) == 0))
40112ed1c7cSGregory Neil Shapiro 			dropfrom = true;
402c2aa98e2SPeter Wemm 	}
403c2aa98e2SPeter Wemm 
404c2aa98e2SPeter Wemm 	/* delete default value for this header */
405c2aa98e2SPeter Wemm 	for (hp = hdrp; (h = *hp) != NULL; hp = &h->h_link)
406c2aa98e2SPeter Wemm 	{
40712ed1c7cSGregory Neil Shapiro 		if (sm_strcasecmp(fname, h->h_field) == 0 &&
4083299c2f1SGregory Neil Shapiro 		    !bitset(H_USER, h->h_flags) &&
409c2aa98e2SPeter Wemm 		    !bitset(H_FORCE, h->h_flags))
410c2aa98e2SPeter Wemm 		{
411e01d6f61SPeter Wemm 			if (nullheader)
412e01d6f61SPeter Wemm 			{
413e01d6f61SPeter Wemm 				/* user-supplied value was null */
414e01d6f61SPeter Wemm 				return 0;
415e01d6f61SPeter Wemm 			}
4163299c2f1SGregory Neil Shapiro 			if (dropfrom)
4173299c2f1SGregory Neil Shapiro 			{
4183299c2f1SGregory Neil Shapiro 				/* make this look like the user entered it */
4193299c2f1SGregory Neil Shapiro 				h->h_flags |= H_USER;
4203299c2f1SGregory Neil Shapiro 				return hi->hi_flags;
4213299c2f1SGregory Neil Shapiro 			}
422c2aa98e2SPeter Wemm 			h->h_value = NULL;
423c2aa98e2SPeter Wemm 			if (!cond)
424c2aa98e2SPeter Wemm 			{
425c2aa98e2SPeter Wemm 				/* copy conditions from default case */
4263299c2f1SGregory Neil Shapiro 				memmove((char *) mopts, (char *) h->h_mflags,
427c2aa98e2SPeter Wemm 					sizeof mopts);
428c2aa98e2SPeter Wemm 			}
4293299c2f1SGregory Neil Shapiro 			h->h_macro = mid;
430c2aa98e2SPeter Wemm 		}
431c2aa98e2SPeter Wemm 	}
432c2aa98e2SPeter Wemm 
433c2aa98e2SPeter Wemm 	/* create a new node */
43412ed1c7cSGregory Neil Shapiro 	h = (HDR *) sm_rpool_malloc_x(e->e_rpool, sizeof *h);
43512ed1c7cSGregory Neil Shapiro 	h->h_field = sm_rpool_strdup_x(e->e_rpool, fname);
43612ed1c7cSGregory Neil Shapiro 	h->h_value = sm_rpool_strdup_x(e->e_rpool, fvalue);
437c2aa98e2SPeter Wemm 	h->h_link = NULL;
4383299c2f1SGregory Neil Shapiro 	memmove((char *) h->h_mflags, (char *) mopts, sizeof mopts);
4393299c2f1SGregory Neil Shapiro 	h->h_macro = mid;
440c2aa98e2SPeter Wemm 	*hp = h;
441c2aa98e2SPeter Wemm 	h->h_flags = hi->hi_flags;
442d995d2baSGregory Neil Shapiro 	if (bitset(pflag, CHHDR_USER) || bitset(pflag, CHHDR_QUEUE))
4433299c2f1SGregory Neil Shapiro 		h->h_flags |= H_USER;
444c2aa98e2SPeter Wemm 
445c2aa98e2SPeter Wemm 	/* strip EOH flag if parsing MIME headers */
446c2aa98e2SPeter Wemm 	if (headeronly)
447c2aa98e2SPeter Wemm 		h->h_flags &= ~H_EOH;
4483299c2f1SGregory Neil Shapiro 	if (bitset(pflag, CHHDR_DEF))
449c2aa98e2SPeter Wemm 		h->h_flags |= H_DEFAULT;
4503299c2f1SGregory Neil Shapiro 	if (cond || mid != '\0')
451c2aa98e2SPeter Wemm 		h->h_flags |= H_CHECK;
452c2aa98e2SPeter Wemm 
453c2aa98e2SPeter Wemm 	/* hack to see if this is a new format message */
4543299c2f1SGregory Neil Shapiro 	if (!bitset(pflag, CHHDR_DEF) && !headeronly &&
4553299c2f1SGregory Neil Shapiro 	    bitset(H_RCPT|H_FROM, h->h_flags) &&
456c2aa98e2SPeter Wemm 	    (strchr(fvalue, ',') != NULL || strchr(fvalue, '(') != NULL ||
457c2aa98e2SPeter Wemm 	     strchr(fvalue, '<') != NULL || strchr(fvalue, ';') != NULL))
458c2aa98e2SPeter Wemm 	{
459c2aa98e2SPeter Wemm 		e->e_flags &= ~EF_OLDSTYLE;
460c2aa98e2SPeter Wemm 	}
461c2aa98e2SPeter Wemm 
462c2aa98e2SPeter Wemm 	return h->h_flags;
463c2aa98e2SPeter Wemm }
46412ed1c7cSGregory Neil Shapiro /*
465bfb62e91SGregory Neil Shapiro **  ALLOCHEADER -- allocate a header entry
466bfb62e91SGregory Neil Shapiro **
467bfb62e91SGregory Neil Shapiro **	Parameters:
468bfb62e91SGregory Neil Shapiro **		field -- the name of the header field.
469bfb62e91SGregory Neil Shapiro **		value -- the value of the field.
470bfb62e91SGregory Neil Shapiro **		flags -- flags to add to h_flags.
471bfb62e91SGregory Neil Shapiro **		rp -- resource pool for allocations
472bfb62e91SGregory Neil Shapiro **
473bfb62e91SGregory Neil Shapiro **	Returns:
474bfb62e91SGregory Neil Shapiro **		Pointer to a newly allocated and populated HDR.
475bfb62e91SGregory Neil Shapiro */
476bfb62e91SGregory Neil Shapiro 
477bfb62e91SGregory Neil Shapiro static HDR *
478bfb62e91SGregory Neil Shapiro allocheader(field, value, flags, rp)
479bfb62e91SGregory Neil Shapiro 	char *field;
480bfb62e91SGregory Neil Shapiro 	char *value;
481bfb62e91SGregory Neil Shapiro 	int flags;
482bfb62e91SGregory Neil Shapiro 	SM_RPOOL_T *rp;
483bfb62e91SGregory Neil Shapiro {
484bfb62e91SGregory Neil Shapiro 	HDR *h;
485bfb62e91SGregory Neil Shapiro 	STAB *s;
486bfb62e91SGregory Neil Shapiro 
487bfb62e91SGregory Neil Shapiro 	/* find info struct */
488bfb62e91SGregory Neil Shapiro 	s = stab(field, ST_HEADER, ST_FIND);
489bfb62e91SGregory Neil Shapiro 
490bfb62e91SGregory Neil Shapiro 	/* allocate space for new header */
491bfb62e91SGregory Neil Shapiro 	h = (HDR *) sm_rpool_malloc_x(rp, sizeof *h);
492bfb62e91SGregory Neil Shapiro 	h->h_field = field;
493bfb62e91SGregory Neil Shapiro 	h->h_value = sm_rpool_strdup_x(rp, value);
494bfb62e91SGregory Neil Shapiro 	h->h_flags = flags;
495bfb62e91SGregory Neil Shapiro 	if (s != NULL)
496bfb62e91SGregory Neil Shapiro 		h->h_flags |= s->s_header.hi_flags;
497bfb62e91SGregory Neil Shapiro 	clrbitmap(h->h_mflags);
498bfb62e91SGregory Neil Shapiro 	h->h_macro = '\0';
499bfb62e91SGregory Neil Shapiro 
500bfb62e91SGregory Neil Shapiro 	return h;
501bfb62e91SGregory Neil Shapiro }
502bfb62e91SGregory Neil Shapiro /*
503c2aa98e2SPeter Wemm **  ADDHEADER -- add a header entry to the end of the queue.
504c2aa98e2SPeter Wemm **
505c2aa98e2SPeter Wemm **	This bypasses the special checking of chompheader.
506c2aa98e2SPeter Wemm **
507c2aa98e2SPeter Wemm **	Parameters:
508c2aa98e2SPeter Wemm **		field -- the name of the header field.
509c2aa98e2SPeter Wemm **		value -- the value of the field.
5103299c2f1SGregory Neil Shapiro **		flags -- flags to add to h_flags.
51112ed1c7cSGregory Neil Shapiro **		e -- envelope.
512c2aa98e2SPeter Wemm **
513c2aa98e2SPeter Wemm **	Returns:
514c2aa98e2SPeter Wemm **		none.
515c2aa98e2SPeter Wemm **
516c2aa98e2SPeter Wemm **	Side Effects:
517c2aa98e2SPeter Wemm **		adds the field on the list of headers for this envelope.
518c2aa98e2SPeter Wemm */
519c2aa98e2SPeter Wemm 
520c2aa98e2SPeter Wemm void
52112ed1c7cSGregory Neil Shapiro addheader(field, value, flags, e)
522c2aa98e2SPeter Wemm 	char *field;
523c2aa98e2SPeter Wemm 	char *value;
5243299c2f1SGregory Neil Shapiro 	int flags;
52512ed1c7cSGregory Neil Shapiro 	ENVELOPE *e;
526c2aa98e2SPeter Wemm {
527c2aa98e2SPeter Wemm 	register HDR *h;
528c2aa98e2SPeter Wemm 	HDR **hp;
52912ed1c7cSGregory Neil Shapiro 	HDR **hdrlist = &e->e_header;
530c2aa98e2SPeter Wemm 
531c2aa98e2SPeter Wemm 	/* find current place in list -- keep back pointer? */
532c2aa98e2SPeter Wemm 	for (hp = hdrlist; (h = *hp) != NULL; hp = &h->h_link)
533c2aa98e2SPeter Wemm 	{
53412ed1c7cSGregory Neil Shapiro 		if (sm_strcasecmp(field, h->h_field) == 0)
535c2aa98e2SPeter Wemm 			break;
536c2aa98e2SPeter Wemm 	}
537c2aa98e2SPeter Wemm 
538c2aa98e2SPeter Wemm 	/* allocate space for new header */
539bfb62e91SGregory Neil Shapiro 	h = allocheader(field, value, flags, e->e_rpool);
540c2aa98e2SPeter Wemm 	h->h_link = *hp;
541c2aa98e2SPeter Wemm 	*hp = h;
542c2aa98e2SPeter Wemm }
54312ed1c7cSGregory Neil Shapiro /*
544bfb62e91SGregory Neil Shapiro **  INSHEADER -- insert a header entry at the specified index
545bfb62e91SGregory Neil Shapiro **
546bfb62e91SGregory Neil Shapiro **	This bypasses the special checking of chompheader.
547bfb62e91SGregory Neil Shapiro **
548bfb62e91SGregory Neil Shapiro **	Parameters:
549bfb62e91SGregory Neil Shapiro **		idx -- index into the header list at which to insert
550bfb62e91SGregory Neil Shapiro **		field -- the name of the header field.
551bfb62e91SGregory Neil Shapiro **		value -- the value of the field.
552bfb62e91SGregory Neil Shapiro **		flags -- flags to add to h_flags.
553bfb62e91SGregory Neil Shapiro **		e -- envelope.
554bfb62e91SGregory Neil Shapiro **
555bfb62e91SGregory Neil Shapiro **	Returns:
556bfb62e91SGregory Neil Shapiro **		none.
557bfb62e91SGregory Neil Shapiro **
558bfb62e91SGregory Neil Shapiro **	Side Effects:
559bfb62e91SGregory Neil Shapiro **		inserts the field on the list of headers for this envelope.
560bfb62e91SGregory Neil Shapiro */
561bfb62e91SGregory Neil Shapiro 
562bfb62e91SGregory Neil Shapiro void
563bfb62e91SGregory Neil Shapiro insheader(idx, field, value, flags, e)
564bfb62e91SGregory Neil Shapiro 	int idx;
565bfb62e91SGregory Neil Shapiro 	char *field;
566bfb62e91SGregory Neil Shapiro 	char *value;
567bfb62e91SGregory Neil Shapiro 	int flags;
568bfb62e91SGregory Neil Shapiro 	ENVELOPE *e;
569bfb62e91SGregory Neil Shapiro {
570bfb62e91SGregory Neil Shapiro 	HDR *h, *srch, *last = NULL;
571bfb62e91SGregory Neil Shapiro 
572bfb62e91SGregory Neil Shapiro 	/* allocate space for new header */
573bfb62e91SGregory Neil Shapiro 	h = allocheader(field, value, flags, e->e_rpool);
574bfb62e91SGregory Neil Shapiro 
575bfb62e91SGregory Neil Shapiro 	/* find insertion position */
576bfb62e91SGregory Neil Shapiro 	for (srch = e->e_header; srch != NULL && idx > 0;
577bfb62e91SGregory Neil Shapiro 	     srch = srch->h_link, idx--)
578bfb62e91SGregory Neil Shapiro 		last = srch;
579bfb62e91SGregory Neil Shapiro 
580bfb62e91SGregory Neil Shapiro 	if (e->e_header == NULL)
581bfb62e91SGregory Neil Shapiro 	{
582bfb62e91SGregory Neil Shapiro 		e->e_header = h;
583bfb62e91SGregory Neil Shapiro 		h->h_link = NULL;
584bfb62e91SGregory Neil Shapiro 	}
585bfb62e91SGregory Neil Shapiro 	else if (srch == NULL)
586bfb62e91SGregory Neil Shapiro 	{
587bfb62e91SGregory Neil Shapiro 		SM_ASSERT(last != NULL);
588bfb62e91SGregory Neil Shapiro 		last->h_link = h;
589bfb62e91SGregory Neil Shapiro 		h->h_link = NULL;
590bfb62e91SGregory Neil Shapiro 	}
591bfb62e91SGregory Neil Shapiro 	else
592bfb62e91SGregory Neil Shapiro 	{
593bfb62e91SGregory Neil Shapiro 		h->h_link = srch->h_link;
594bfb62e91SGregory Neil Shapiro 		srch->h_link = h;
595bfb62e91SGregory Neil Shapiro 	}
596bfb62e91SGregory Neil Shapiro }
597bfb62e91SGregory Neil Shapiro /*
598c2aa98e2SPeter Wemm **  HVALUE -- return value of a header.
599c2aa98e2SPeter Wemm **
600c2aa98e2SPeter Wemm **	Only "real" fields (i.e., ones that have not been supplied
601c2aa98e2SPeter Wemm **	as a default) are used.
602c2aa98e2SPeter Wemm **
603c2aa98e2SPeter Wemm **	Parameters:
604c2aa98e2SPeter Wemm **		field -- the field name.
605c2aa98e2SPeter Wemm **		header -- the header list.
606c2aa98e2SPeter Wemm **
607c2aa98e2SPeter Wemm **	Returns:
608c2aa98e2SPeter Wemm **		pointer to the value part.
609c2aa98e2SPeter Wemm **		NULL if not found.
610c2aa98e2SPeter Wemm **
611c2aa98e2SPeter Wemm **	Side Effects:
612c2aa98e2SPeter Wemm **		none.
613c2aa98e2SPeter Wemm */
614c2aa98e2SPeter Wemm 
615c2aa98e2SPeter Wemm char *
616c2aa98e2SPeter Wemm hvalue(field, header)
617c2aa98e2SPeter Wemm 	char *field;
618c2aa98e2SPeter Wemm 	HDR *header;
619c2aa98e2SPeter Wemm {
620c2aa98e2SPeter Wemm 	register HDR *h;
621c2aa98e2SPeter Wemm 
622c2aa98e2SPeter Wemm 	for (h = header; h != NULL; h = h->h_link)
623c2aa98e2SPeter Wemm 	{
624c2aa98e2SPeter Wemm 		if (!bitset(H_DEFAULT, h->h_flags) &&
62512ed1c7cSGregory Neil Shapiro 		    sm_strcasecmp(h->h_field, field) == 0)
6263299c2f1SGregory Neil Shapiro 			return h->h_value;
627c2aa98e2SPeter Wemm 	}
6283299c2f1SGregory Neil Shapiro 	return NULL;
629c2aa98e2SPeter Wemm }
63012ed1c7cSGregory Neil Shapiro /*
631c2aa98e2SPeter Wemm **  ISHEADER -- predicate telling if argument is a header.
632c2aa98e2SPeter Wemm **
633c2aa98e2SPeter Wemm **	A line is a header if it has a single word followed by
634c2aa98e2SPeter Wemm **	optional white space followed by a colon.
635c2aa98e2SPeter Wemm **
636c2aa98e2SPeter Wemm **	Header fields beginning with two dashes, although technically
637c2aa98e2SPeter Wemm **	permitted by RFC822, are automatically rejected in order
638c2aa98e2SPeter Wemm **	to make MIME work out.  Without this we could have a technically
639c2aa98e2SPeter Wemm **	legal header such as ``--"foo:bar"'' that would also be a legal
640c2aa98e2SPeter Wemm **	MIME separator.
641c2aa98e2SPeter Wemm **
642c2aa98e2SPeter Wemm **	Parameters:
643c2aa98e2SPeter Wemm **		h -- string to check for possible headerness.
644c2aa98e2SPeter Wemm **
645c2aa98e2SPeter Wemm **	Returns:
64612ed1c7cSGregory Neil Shapiro **		true if h is a header.
64712ed1c7cSGregory Neil Shapiro **		false otherwise.
648c2aa98e2SPeter Wemm **
649c2aa98e2SPeter Wemm **	Side Effects:
650c2aa98e2SPeter Wemm **		none.
651c2aa98e2SPeter Wemm */
652c2aa98e2SPeter Wemm 
653c2aa98e2SPeter Wemm bool
654c2aa98e2SPeter Wemm isheader(h)
655c2aa98e2SPeter Wemm 	char *h;
656c2aa98e2SPeter Wemm {
657c2aa98e2SPeter Wemm 	register char *s = h;
658c2aa98e2SPeter Wemm 
659c2aa98e2SPeter Wemm 	if (s[0] == '-' && s[1] == '-')
66012ed1c7cSGregory Neil Shapiro 		return false;
661c2aa98e2SPeter Wemm 
662c2aa98e2SPeter Wemm 	while (*s > ' ' && *s != ':' && *s != '\0')
663c2aa98e2SPeter Wemm 		s++;
664c2aa98e2SPeter Wemm 
665c2aa98e2SPeter Wemm 	if (h == s)
66612ed1c7cSGregory Neil Shapiro 		return false;
667c2aa98e2SPeter Wemm 
668c2aa98e2SPeter Wemm 	/* following technically violates RFC822 */
669c2aa98e2SPeter Wemm 	while (isascii(*s) && isspace(*s))
670c2aa98e2SPeter Wemm 		s++;
671c2aa98e2SPeter Wemm 
672c2aa98e2SPeter Wemm 	return (*s == ':');
673c2aa98e2SPeter Wemm }
67412ed1c7cSGregory Neil Shapiro /*
675c2aa98e2SPeter Wemm **  EATHEADER -- run through the stored header and extract info.
676c2aa98e2SPeter Wemm **
677c2aa98e2SPeter Wemm **	Parameters:
678c2aa98e2SPeter Wemm **		e -- the envelope to process.
679c2aa98e2SPeter Wemm **		full -- if set, do full processing (e.g., compute
680c2aa98e2SPeter Wemm **			message priority).  This should not be set
681c2aa98e2SPeter Wemm **			when reading a queue file because some info
682c2aa98e2SPeter Wemm **			needed to compute the priority is wrong.
68312ed1c7cSGregory Neil Shapiro **		log -- call logsender()?
684c2aa98e2SPeter Wemm **
685c2aa98e2SPeter Wemm **	Returns:
686c2aa98e2SPeter Wemm **		none.
687c2aa98e2SPeter Wemm **
688c2aa98e2SPeter Wemm **	Side Effects:
689c2aa98e2SPeter Wemm **		Sets a bunch of global variables from information
690c2aa98e2SPeter Wemm **			in the collected header.
691c2aa98e2SPeter Wemm */
692c2aa98e2SPeter Wemm 
693c2aa98e2SPeter Wemm void
69412ed1c7cSGregory Neil Shapiro eatheader(e, full, log)
695c2aa98e2SPeter Wemm 	register ENVELOPE *e;
696c2aa98e2SPeter Wemm 	bool full;
69712ed1c7cSGregory Neil Shapiro 	bool log;
698c2aa98e2SPeter Wemm {
699c2aa98e2SPeter Wemm 	register HDR *h;
700c2aa98e2SPeter Wemm 	register char *p;
701c2aa98e2SPeter Wemm 	int hopcnt = 0;
702c2aa98e2SPeter Wemm 	char buf[MAXLINE];
703c2aa98e2SPeter Wemm 
704c2aa98e2SPeter Wemm 	/*
705c2aa98e2SPeter Wemm 	**  Set up macros for possible expansion in headers.
706c2aa98e2SPeter Wemm 	*/
707c2aa98e2SPeter Wemm 
70812ed1c7cSGregory Neil Shapiro 	macdefine(&e->e_macro, A_PERM, 'f', e->e_sender);
70912ed1c7cSGregory Neil Shapiro 	macdefine(&e->e_macro, A_PERM, 'g', e->e_sender);
710c2aa98e2SPeter Wemm 	if (e->e_origrcpt != NULL && *e->e_origrcpt != '\0')
71112ed1c7cSGregory Neil Shapiro 		macdefine(&e->e_macro, A_PERM, 'u', e->e_origrcpt);
712c2aa98e2SPeter Wemm 	else
71312ed1c7cSGregory Neil Shapiro 		macdefine(&e->e_macro, A_PERM, 'u', NULL);
714c2aa98e2SPeter Wemm 
715c2aa98e2SPeter Wemm 	/* full name of from person */
716c2aa98e2SPeter Wemm 	p = hvalue("full-name", e->e_header);
717c2aa98e2SPeter Wemm 	if (p != NULL)
718c2aa98e2SPeter Wemm 	{
719c2aa98e2SPeter Wemm 		if (!rfc822_string(p))
720c2aa98e2SPeter Wemm 		{
721c2aa98e2SPeter Wemm 			/*
722c2aa98e2SPeter Wemm 			**  Quote a full name with special characters
723c2aa98e2SPeter Wemm 			**  as a comment so crackaddr() doesn't destroy
724c2aa98e2SPeter Wemm 			**  the name portion of the address.
725c2aa98e2SPeter Wemm 			*/
72612ed1c7cSGregory Neil Shapiro 
72712ed1c7cSGregory Neil Shapiro 			p = addquotes(p, e->e_rpool);
728c2aa98e2SPeter Wemm 		}
72912ed1c7cSGregory Neil Shapiro 		macdefine(&e->e_macro, A_PERM, 'x', p);
730c2aa98e2SPeter Wemm 	}
731c2aa98e2SPeter Wemm 
732c2aa98e2SPeter Wemm 	if (tTd(32, 1))
73312ed1c7cSGregory Neil Shapiro 		sm_dprintf("----- collected header -----\n");
73412ed1c7cSGregory Neil Shapiro 	e->e_msgid = NULL;
735c2aa98e2SPeter Wemm 	for (h = e->e_header; h != NULL; h = h->h_link)
736c2aa98e2SPeter Wemm 	{
737c2aa98e2SPeter Wemm 		if (tTd(32, 1))
73812ed1c7cSGregory Neil Shapiro 			sm_dprintf("%s: ", h->h_field);
739c2aa98e2SPeter Wemm 		if (h->h_value == NULL)
740c2aa98e2SPeter Wemm 		{
741c2aa98e2SPeter Wemm 			if (tTd(32, 1))
74212ed1c7cSGregory Neil Shapiro 				sm_dprintf("<NULL>\n");
743c2aa98e2SPeter Wemm 			continue;
744c2aa98e2SPeter Wemm 		}
745c2aa98e2SPeter Wemm 
746c2aa98e2SPeter Wemm 		/* do early binding */
7473299c2f1SGregory Neil Shapiro 		if (bitset(H_DEFAULT, h->h_flags) &&
7483299c2f1SGregory Neil Shapiro 		    !bitset(H_BINDLATE, h->h_flags))
749c2aa98e2SPeter Wemm 		{
750c2aa98e2SPeter Wemm 			if (tTd(32, 1))
751c2aa98e2SPeter Wemm 			{
75212ed1c7cSGregory Neil Shapiro 				sm_dprintf("(");
753bfb62e91SGregory Neil Shapiro 				xputs(sm_debug_file(), h->h_value);
75412ed1c7cSGregory Neil Shapiro 				sm_dprintf(") ");
755c2aa98e2SPeter Wemm 			}
756c2aa98e2SPeter Wemm 			expand(h->h_value, buf, sizeof buf, e);
757c2aa98e2SPeter Wemm 			if (buf[0] != '\0')
758c2aa98e2SPeter Wemm 			{
759c2aa98e2SPeter Wemm 				if (bitset(H_FROM, h->h_flags))
760f9218d3dSGregory Neil Shapiro 					expand(crackaddr(buf, e),
761f9218d3dSGregory Neil Shapiro 					       buf, sizeof buf, e);
76212ed1c7cSGregory Neil Shapiro 				h->h_value = sm_rpool_strdup_x(e->e_rpool, buf);
763c2aa98e2SPeter Wemm 				h->h_flags &= ~H_DEFAULT;
764c2aa98e2SPeter Wemm 			}
765c2aa98e2SPeter Wemm 		}
766c2aa98e2SPeter Wemm 		if (tTd(32, 1))
767c2aa98e2SPeter Wemm 		{
768bfb62e91SGregory Neil Shapiro 			xputs(sm_debug_file(), h->h_value);
76912ed1c7cSGregory Neil Shapiro 			sm_dprintf("\n");
770c2aa98e2SPeter Wemm 		}
771c2aa98e2SPeter Wemm 
772c2aa98e2SPeter Wemm 		/* count the number of times it has been processed */
773c2aa98e2SPeter Wemm 		if (bitset(H_TRACE, h->h_flags))
774c2aa98e2SPeter Wemm 			hopcnt++;
775c2aa98e2SPeter Wemm 
776c2aa98e2SPeter Wemm 		/* send to this person if we so desire */
777c2aa98e2SPeter Wemm 		if (GrabTo && bitset(H_RCPT, h->h_flags) &&
778c2aa98e2SPeter Wemm 		    !bitset(H_DEFAULT, h->h_flags) &&
77912ed1c7cSGregory Neil Shapiro 		    (!bitset(EF_RESENT, e->e_flags) ||
78012ed1c7cSGregory Neil Shapiro 		     bitset(H_RESENT, h->h_flags)))
781c2aa98e2SPeter Wemm 		{
782c2aa98e2SPeter Wemm #if 0
783c2aa98e2SPeter Wemm 			int saveflags = e->e_flags;
7843299c2f1SGregory Neil Shapiro #endif /* 0 */
785c2aa98e2SPeter Wemm 
78612ed1c7cSGregory Neil Shapiro 			(void) sendtolist(denlstring(h->h_value, true, false),
78712ed1c7cSGregory Neil Shapiro 					  NULLADDR, &e->e_sendqueue, 0, e);
788c2aa98e2SPeter Wemm 
789c2aa98e2SPeter Wemm #if 0
790c2aa98e2SPeter Wemm 			/*
791c2aa98e2SPeter Wemm 			**  Change functionality so a fatal error on an
792c2aa98e2SPeter Wemm 			**  address doesn't affect the entire envelope.
793c2aa98e2SPeter Wemm 			*/
794c2aa98e2SPeter Wemm 
795c2aa98e2SPeter Wemm 			/* delete fatal errors generated by this address */
796c2aa98e2SPeter Wemm 			if (!bitset(EF_FATALERRS, saveflags))
797c2aa98e2SPeter Wemm 				e->e_flags &= ~EF_FATALERRS;
7983299c2f1SGregory Neil Shapiro #endif /* 0 */
799c2aa98e2SPeter Wemm 		}
800c2aa98e2SPeter Wemm 
801c2aa98e2SPeter Wemm 		/* save the message-id for logging */
802c2aa98e2SPeter Wemm 		p = "resent-message-id";
803c2aa98e2SPeter Wemm 		if (!bitset(EF_RESENT, e->e_flags))
804c2aa98e2SPeter Wemm 			p += 7;
80512ed1c7cSGregory Neil Shapiro 		if (sm_strcasecmp(h->h_field, p) == 0)
806c2aa98e2SPeter Wemm 		{
80712ed1c7cSGregory Neil Shapiro 			e->e_msgid = h->h_value;
80812ed1c7cSGregory Neil Shapiro 			while (isascii(*e->e_msgid) && isspace(*e->e_msgid))
80912ed1c7cSGregory Neil Shapiro 				e->e_msgid++;
8101ae5b8d4SGregory Neil Shapiro 			macdefine(&e->e_macro, A_PERM, macid("{msg_id}"),
8111ae5b8d4SGregory Neil Shapiro 				  e->e_msgid);
812c2aa98e2SPeter Wemm 		}
813c2aa98e2SPeter Wemm 	}
814c2aa98e2SPeter Wemm 	if (tTd(32, 1))
81512ed1c7cSGregory Neil Shapiro 		sm_dprintf("----------------------------\n");
816c2aa98e2SPeter Wemm 
817c2aa98e2SPeter Wemm 	/* if we are just verifying (that is, sendmail -t -bv), drop out now */
818c2aa98e2SPeter Wemm 	if (OpMode == MD_VERIFY)
819c2aa98e2SPeter Wemm 		return;
820c2aa98e2SPeter Wemm 
821c2aa98e2SPeter Wemm 	/* store hop count */
822c2aa98e2SPeter Wemm 	if (hopcnt > e->e_hopcount)
82312ed1c7cSGregory Neil Shapiro 	{
824c2aa98e2SPeter Wemm 		e->e_hopcount = hopcnt;
82512ed1c7cSGregory Neil Shapiro 		(void) sm_snprintf(buf, sizeof buf, "%d", e->e_hopcount);
82612ed1c7cSGregory Neil Shapiro 		macdefine(&e->e_macro, A_TEMP, 'c', buf);
82712ed1c7cSGregory Neil Shapiro 	}
828c2aa98e2SPeter Wemm 
829c2aa98e2SPeter Wemm 	/* message priority */
830c2aa98e2SPeter Wemm 	p = hvalue("precedence", e->e_header);
831c2aa98e2SPeter Wemm 	if (p != NULL)
832c2aa98e2SPeter Wemm 		e->e_class = priencode(p);
833c2aa98e2SPeter Wemm 	if (e->e_class < 0)
834c2aa98e2SPeter Wemm 		e->e_timeoutclass = TOC_NONURGENT;
835c2aa98e2SPeter Wemm 	else if (e->e_class > 0)
836c2aa98e2SPeter Wemm 		e->e_timeoutclass = TOC_URGENT;
837c2aa98e2SPeter Wemm 	if (full)
838c2aa98e2SPeter Wemm 	{
839c2aa98e2SPeter Wemm 		e->e_msgpriority = e->e_msgsize
840c2aa98e2SPeter Wemm 				 - e->e_class * WkClassFact
841c2aa98e2SPeter Wemm 				 + e->e_nrcpts * WkRecipFact;
842c2aa98e2SPeter Wemm 	}
843c2aa98e2SPeter Wemm 
844bfb62e91SGregory Neil Shapiro 	/* check for DSN to properly set e_timeoutclass */
845bfb62e91SGregory Neil Shapiro 	p = hvalue("content-type", e->e_header);
846bfb62e91SGregory Neil Shapiro 	if (p != NULL)
847bfb62e91SGregory Neil Shapiro 	{
848bfb62e91SGregory Neil Shapiro 		bool oldsupr;
849bfb62e91SGregory Neil Shapiro 		char **pvp;
850bfb62e91SGregory Neil Shapiro 		char pvpbuf[MAXLINE];
851bfb62e91SGregory Neil Shapiro 		extern unsigned char MimeTokenTab[256];
852bfb62e91SGregory Neil Shapiro 
853bfb62e91SGregory Neil Shapiro 		/* tokenize header */
854bfb62e91SGregory Neil Shapiro 		oldsupr = SuprErrs;
855bfb62e91SGregory Neil Shapiro 		SuprErrs = true;
856bfb62e91SGregory Neil Shapiro 		pvp = prescan(p, '\0', pvpbuf, sizeof pvpbuf, NULL,
857bfb62e91SGregory Neil Shapiro 			      MimeTokenTab, false);
858bfb62e91SGregory Neil Shapiro 		SuprErrs = oldsupr;
859bfb62e91SGregory Neil Shapiro 
860bfb62e91SGregory Neil Shapiro 		/* Check if multipart/report */
861bfb62e91SGregory Neil Shapiro 		if (pvp != NULL && pvp[0] != NULL &&
862bfb62e91SGregory Neil Shapiro 		    pvp[1] != NULL && pvp[2] != NULL &&
863bfb62e91SGregory Neil Shapiro 		    sm_strcasecmp(*pvp++, "multipart") == 0 &&
864bfb62e91SGregory Neil Shapiro 		    strcmp(*pvp++, "/") == 0 &&
865bfb62e91SGregory Neil Shapiro 		    sm_strcasecmp(*pvp++, "report") == 0)
866bfb62e91SGregory Neil Shapiro 		{
867bfb62e91SGregory Neil Shapiro 			/* Look for report-type=delivery-status */
868bfb62e91SGregory Neil Shapiro 			while (*pvp != NULL)
869bfb62e91SGregory Neil Shapiro 			{
870bfb62e91SGregory Neil Shapiro 				/* skip to semicolon separator */
871bfb62e91SGregory Neil Shapiro 				while (*pvp != NULL && strcmp(*pvp, ";") != 0)
872bfb62e91SGregory Neil Shapiro 					pvp++;
873bfb62e91SGregory Neil Shapiro 
874bfb62e91SGregory Neil Shapiro 				/* skip semicolon */
875bfb62e91SGregory Neil Shapiro 				if (*pvp++ == NULL || *pvp == NULL)
876bfb62e91SGregory Neil Shapiro 					break;
877bfb62e91SGregory Neil Shapiro 
878bfb62e91SGregory Neil Shapiro 				/* look for report-type */
879bfb62e91SGregory Neil Shapiro 				if (sm_strcasecmp(*pvp++, "report-type") != 0)
880bfb62e91SGregory Neil Shapiro 					continue;
881bfb62e91SGregory Neil Shapiro 
882bfb62e91SGregory Neil Shapiro 				/* skip equal */
883bfb62e91SGregory Neil Shapiro 				if (*pvp == NULL || strcmp(*pvp, "=") != 0)
884bfb62e91SGregory Neil Shapiro 					continue;
885bfb62e91SGregory Neil Shapiro 
886bfb62e91SGregory Neil Shapiro 				/* check value */
887bfb62e91SGregory Neil Shapiro 				if (*++pvp != NULL &&
888bfb62e91SGregory Neil Shapiro 				    sm_strcasecmp(*pvp,
889bfb62e91SGregory Neil Shapiro 						  "delivery-status") == 0)
890bfb62e91SGregory Neil Shapiro 					e->e_timeoutclass = TOC_DSN;
891bfb62e91SGregory Neil Shapiro 
892bfb62e91SGregory Neil Shapiro 				/* found report-type, no need to continue */
893bfb62e91SGregory Neil Shapiro 				break;
894bfb62e91SGregory Neil Shapiro 			}
895bfb62e91SGregory Neil Shapiro 		}
896bfb62e91SGregory Neil Shapiro 	}
897bfb62e91SGregory Neil Shapiro 
898c2aa98e2SPeter Wemm 	/* message timeout priority */
899c2aa98e2SPeter Wemm 	p = hvalue("priority", e->e_header);
900c2aa98e2SPeter Wemm 	if (p != NULL)
901c2aa98e2SPeter Wemm 	{
902c2aa98e2SPeter Wemm 		/* (this should be in the configuration file) */
90312ed1c7cSGregory Neil Shapiro 		if (sm_strcasecmp(p, "urgent") == 0)
904c2aa98e2SPeter Wemm 			e->e_timeoutclass = TOC_URGENT;
90512ed1c7cSGregory Neil Shapiro 		else if (sm_strcasecmp(p, "normal") == 0)
906c2aa98e2SPeter Wemm 			e->e_timeoutclass = TOC_NORMAL;
90712ed1c7cSGregory Neil Shapiro 		else if (sm_strcasecmp(p, "non-urgent") == 0)
908c2aa98e2SPeter Wemm 			e->e_timeoutclass = TOC_NONURGENT;
9091ae5b8d4SGregory Neil Shapiro 		else if (bitset(EF_RESPONSE, e->e_flags))
9101ae5b8d4SGregory Neil Shapiro 			e->e_timeoutclass = TOC_DSN;
9111ae5b8d4SGregory Neil Shapiro 	}
9121ae5b8d4SGregory Neil Shapiro 	else if (bitset(EF_RESPONSE, e->e_flags))
91372936242SGregory Neil Shapiro 		e->e_timeoutclass = TOC_DSN;
91472936242SGregory Neil Shapiro 
915c2aa98e2SPeter Wemm 	/* date message originated */
916c2aa98e2SPeter Wemm 	p = hvalue("posted-date", e->e_header);
917c2aa98e2SPeter Wemm 	if (p == NULL)
918c2aa98e2SPeter Wemm 		p = hvalue("date", e->e_header);
919c2aa98e2SPeter Wemm 	if (p != NULL)
92012ed1c7cSGregory Neil Shapiro 		macdefine(&e->e_macro, A_PERM, 'a', p);
921c2aa98e2SPeter Wemm 
922c2aa98e2SPeter Wemm 	/* check to see if this is a MIME message */
923c2aa98e2SPeter Wemm 	if ((e->e_bodytype != NULL &&
92412ed1c7cSGregory Neil Shapiro 	     sm_strcasecmp(e->e_bodytype, "8BITMIME") == 0) ||
925c2aa98e2SPeter Wemm 	    hvalue("MIME-Version", e->e_header) != NULL)
926c2aa98e2SPeter Wemm 	{
927c2aa98e2SPeter Wemm 		e->e_flags |= EF_IS_MIME;
928c2aa98e2SPeter Wemm 		if (HasEightBits)
929c2aa98e2SPeter Wemm 			e->e_bodytype = "8BITMIME";
930c2aa98e2SPeter Wemm 	}
931c2aa98e2SPeter Wemm 	else if ((p = hvalue("Content-Type", e->e_header)) != NULL)
932c2aa98e2SPeter Wemm 	{
933c2aa98e2SPeter Wemm 		/* this may be an RFC 1049 message */
934c2aa98e2SPeter Wemm 		p = strpbrk(p, ";/");
935c2aa98e2SPeter Wemm 		if (p == NULL || *p == ';')
936c2aa98e2SPeter Wemm 		{
937c2aa98e2SPeter Wemm 			/* yep, it is */
938c2aa98e2SPeter Wemm 			e->e_flags |= EF_DONT_MIME;
939c2aa98e2SPeter Wemm 		}
940c2aa98e2SPeter Wemm 	}
941c2aa98e2SPeter Wemm 
942c2aa98e2SPeter Wemm 	/*
943c2aa98e2SPeter Wemm 	**  From person in antiquated ARPANET mode
944c2aa98e2SPeter Wemm 	**	required by UK Grey Book e-mail gateways (sigh)
945c2aa98e2SPeter Wemm 	*/
946c2aa98e2SPeter Wemm 
947c2aa98e2SPeter Wemm 	if (OpMode == MD_ARPAFTP)
948c2aa98e2SPeter Wemm 	{
949c2aa98e2SPeter Wemm 		register struct hdrinfo *hi;
950c2aa98e2SPeter Wemm 
951c2aa98e2SPeter Wemm 		for (hi = HdrInfo; hi->hi_field != NULL; hi++)
952c2aa98e2SPeter Wemm 		{
953c2aa98e2SPeter Wemm 			if (bitset(H_FROM, hi->hi_flags) &&
954c2aa98e2SPeter Wemm 			    (!bitset(H_RESENT, hi->hi_flags) ||
955c2aa98e2SPeter Wemm 			     bitset(EF_RESENT, e->e_flags)) &&
956c2aa98e2SPeter Wemm 			    (p = hvalue(hi->hi_field, e->e_header)) != NULL)
957c2aa98e2SPeter Wemm 				break;
958c2aa98e2SPeter Wemm 		}
959c2aa98e2SPeter Wemm 		if (hi->hi_field != NULL)
960c2aa98e2SPeter Wemm 		{
961c2aa98e2SPeter Wemm 			if (tTd(32, 2))
96212ed1c7cSGregory Neil Shapiro 				sm_dprintf("eatheader: setsender(*%s == %s)\n",
963c2aa98e2SPeter Wemm 					hi->hi_field, p);
96412ed1c7cSGregory Neil Shapiro 			setsender(p, e, NULL, '\0', true);
965c2aa98e2SPeter Wemm 		}
966c2aa98e2SPeter Wemm 	}
967c2aa98e2SPeter Wemm 
968c2aa98e2SPeter Wemm 	/*
969c2aa98e2SPeter Wemm 	**  Log collection information.
970c2aa98e2SPeter Wemm 	*/
971c2aa98e2SPeter Wemm 
97212ed1c7cSGregory Neil Shapiro 	if (log && bitset(EF_LOGSENDER, e->e_flags) && LogLevel > 4)
97312ed1c7cSGregory Neil Shapiro 	{
97412ed1c7cSGregory Neil Shapiro 		logsender(e, e->e_msgid);
975c2aa98e2SPeter Wemm 		e->e_flags &= ~EF_LOGSENDER;
976c2aa98e2SPeter Wemm 	}
97712ed1c7cSGregory Neil Shapiro }
97812ed1c7cSGregory Neil Shapiro /*
979c2aa98e2SPeter Wemm **  LOGSENDER -- log sender information
980c2aa98e2SPeter Wemm **
981c2aa98e2SPeter Wemm **	Parameters:
982c2aa98e2SPeter Wemm **		e -- the envelope to log
983c2aa98e2SPeter Wemm **		msgid -- the message id
984c2aa98e2SPeter Wemm **
985c2aa98e2SPeter Wemm **	Returns:
986c2aa98e2SPeter Wemm **		none
987c2aa98e2SPeter Wemm */
988c2aa98e2SPeter Wemm 
989c2aa98e2SPeter Wemm void
990c2aa98e2SPeter Wemm logsender(e, msgid)
991c2aa98e2SPeter Wemm 	register ENVELOPE *e;
992c2aa98e2SPeter Wemm 	char *msgid;
993c2aa98e2SPeter Wemm {
994c2aa98e2SPeter Wemm 	char *name;
995c2aa98e2SPeter Wemm 	register char *sbp;
996c2aa98e2SPeter Wemm 	register char *p;
997c2aa98e2SPeter Wemm 	char hbuf[MAXNAME + 1];
998c2aa98e2SPeter Wemm 	char sbuf[MAXLINE + 1];
999c2aa98e2SPeter Wemm 	char mbuf[MAXNAME + 1];
1000c2aa98e2SPeter Wemm 
1001c2aa98e2SPeter Wemm 	/* don't allow newlines in the message-id */
100212ed1c7cSGregory Neil Shapiro 	/* XXX do we still need this? sm_syslog() replaces control chars */
1003c2aa98e2SPeter Wemm 	if (msgid != NULL)
1004c2aa98e2SPeter Wemm 	{
1005567a2fc9SGregory Neil Shapiro 		size_t l;
1006567a2fc9SGregory Neil Shapiro 
1007c2aa98e2SPeter Wemm 		l = strlen(msgid);
1008c2aa98e2SPeter Wemm 		if (l > sizeof mbuf - 1)
1009c2aa98e2SPeter Wemm 			l = sizeof mbuf - 1;
10103299c2f1SGregory Neil Shapiro 		memmove(mbuf, msgid, l);
1011c2aa98e2SPeter Wemm 		mbuf[l] = '\0';
1012c2aa98e2SPeter Wemm 		p = mbuf;
1013c2aa98e2SPeter Wemm 		while ((p = strchr(p, '\n')) != NULL)
1014c2aa98e2SPeter Wemm 			*p++ = ' ';
1015c2aa98e2SPeter Wemm 	}
1016c2aa98e2SPeter Wemm 
1017c2aa98e2SPeter Wemm 	if (bitset(EF_RESPONSE, e->e_flags))
1018c2aa98e2SPeter Wemm 		name = "[RESPONSE]";
1019c2aa98e2SPeter Wemm 	else if ((name = macvalue('_', e)) != NULL)
10203299c2f1SGregory Neil Shapiro 		/* EMPTY */
1021c2aa98e2SPeter Wemm 		;
1022c2aa98e2SPeter Wemm 	else if (RealHostName == NULL)
1023c2aa98e2SPeter Wemm 		name = "localhost";
1024c2aa98e2SPeter Wemm 	else if (RealHostName[0] == '[')
1025c2aa98e2SPeter Wemm 		name = RealHostName;
1026c2aa98e2SPeter Wemm 	else
1027c2aa98e2SPeter Wemm 	{
1028c2aa98e2SPeter Wemm 		name = hbuf;
102912ed1c7cSGregory Neil Shapiro 		(void) sm_snprintf(hbuf, sizeof hbuf, "%.80s", RealHostName);
1030c2aa98e2SPeter Wemm 		if (RealHostAddr.sa.sa_family != 0)
1031c2aa98e2SPeter Wemm 		{
1032c2aa98e2SPeter Wemm 			p = &hbuf[strlen(hbuf)];
103312ed1c7cSGregory Neil Shapiro 			(void) sm_snprintf(p, SPACELEFT(hbuf, p),
103412ed1c7cSGregory Neil Shapiro 					   " (%.100s)",
1035c2aa98e2SPeter Wemm 					   anynet_ntoa(&RealHostAddr));
1036c2aa98e2SPeter Wemm 		}
1037c2aa98e2SPeter Wemm 	}
1038c2aa98e2SPeter Wemm 
1039c2aa98e2SPeter Wemm 	/* some versions of syslog only take 5 printf args */
1040c2aa98e2SPeter Wemm #if (SYSLOG_BUFSIZE) >= 256
1041c2aa98e2SPeter Wemm 	sbp = sbuf;
104212ed1c7cSGregory Neil Shapiro 	(void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp),
10433299c2f1SGregory Neil Shapiro 		"from=%.200s, size=%ld, class=%d, nrcpts=%d",
1044c2aa98e2SPeter Wemm 		e->e_from.q_paddr == NULL ? "<NONE>" : e->e_from.q_paddr,
10453299c2f1SGregory Neil Shapiro 		e->e_msgsize, e->e_class, e->e_nrcpts);
1046c2aa98e2SPeter Wemm 	sbp += strlen(sbp);
1047c2aa98e2SPeter Wemm 	if (msgid != NULL)
1048c2aa98e2SPeter Wemm 	{
104912ed1c7cSGregory Neil Shapiro 		(void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp),
105012ed1c7cSGregory Neil Shapiro 				", msgid=%.100s", mbuf);
1051c2aa98e2SPeter Wemm 		sbp += strlen(sbp);
1052c2aa98e2SPeter Wemm 	}
1053c2aa98e2SPeter Wemm 	if (e->e_bodytype != NULL)
1054c2aa98e2SPeter Wemm 	{
105512ed1c7cSGregory Neil Shapiro 		(void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp),
105612ed1c7cSGregory Neil Shapiro 				", bodytype=%.20s", e->e_bodytype);
1057c2aa98e2SPeter Wemm 		sbp += strlen(sbp);
1058c2aa98e2SPeter Wemm 	}
1059c2aa98e2SPeter Wemm 	p = macvalue('r', e);
1060c2aa98e2SPeter Wemm 	if (p != NULL)
10613299c2f1SGregory Neil Shapiro 	{
106212ed1c7cSGregory Neil Shapiro 		(void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp),
106312ed1c7cSGregory Neil Shapiro 				", proto=%.20s", p);
10643299c2f1SGregory Neil Shapiro 		sbp += strlen(sbp);
10653299c2f1SGregory Neil Shapiro 	}
106612ed1c7cSGregory Neil Shapiro 	p = macvalue(macid("{daemon_name}"), e);
10673299c2f1SGregory Neil Shapiro 	if (p != NULL)
10683299c2f1SGregory Neil Shapiro 	{
106912ed1c7cSGregory Neil Shapiro 		(void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp),
107012ed1c7cSGregory Neil Shapiro 				", daemon=%.20s", p);
10713299c2f1SGregory Neil Shapiro 		sbp += strlen(sbp);
10723299c2f1SGregory Neil Shapiro 	}
10732ef40764SGregory Neil Shapiro 	sm_syslog(LOG_INFO, e->e_id, "%.850s, relay=%s", sbuf, name);
1074c2aa98e2SPeter Wemm 
10753299c2f1SGregory Neil Shapiro #else /* (SYSLOG_BUFSIZE) >= 256 */
1076c2aa98e2SPeter Wemm 
1077c2aa98e2SPeter Wemm 	sm_syslog(LOG_INFO, e->e_id,
1078c2aa98e2SPeter Wemm 		  "from=%s",
1079c2aa98e2SPeter Wemm 		  e->e_from.q_paddr == NULL ? "<NONE>"
108012ed1c7cSGregory Neil Shapiro 					    : shortenstring(e->e_from.q_paddr,
108112ed1c7cSGregory Neil Shapiro 							    83));
1082c2aa98e2SPeter Wemm 	sm_syslog(LOG_INFO, e->e_id,
10833299c2f1SGregory Neil Shapiro 		  "size=%ld, class=%ld, nrcpts=%d",
10843299c2f1SGregory Neil Shapiro 		  e->e_msgsize, e->e_class, e->e_nrcpts);
1085c2aa98e2SPeter Wemm 	if (msgid != NULL)
1086c2aa98e2SPeter Wemm 		sm_syslog(LOG_INFO, e->e_id,
1087c2aa98e2SPeter Wemm 			  "msgid=%s",
1088c2aa98e2SPeter Wemm 			  shortenstring(mbuf, 83));
1089c2aa98e2SPeter Wemm 	sbp = sbuf;
1090c2aa98e2SPeter Wemm 	*sbp = '\0';
1091c2aa98e2SPeter Wemm 	if (e->e_bodytype != NULL)
1092c2aa98e2SPeter Wemm 	{
109312ed1c7cSGregory Neil Shapiro 		(void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp),
109412ed1c7cSGregory Neil Shapiro 				"bodytype=%.20s, ", e->e_bodytype);
1095c2aa98e2SPeter Wemm 		sbp += strlen(sbp);
1096c2aa98e2SPeter Wemm 	}
1097c2aa98e2SPeter Wemm 	p = macvalue('r', e);
1098c2aa98e2SPeter Wemm 	if (p != NULL)
1099c2aa98e2SPeter Wemm 	{
110012ed1c7cSGregory Neil Shapiro 		(void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp),
110112ed1c7cSGregory Neil Shapiro 				"proto=%.20s, ", p);
1102c2aa98e2SPeter Wemm 		sbp += strlen(sbp);
1103c2aa98e2SPeter Wemm 	}
1104c2aa98e2SPeter Wemm 	sm_syslog(LOG_INFO, e->e_id,
11052ef40764SGregory Neil Shapiro 		  "%.400srelay=%s", sbuf, name);
11063299c2f1SGregory Neil Shapiro #endif /* (SYSLOG_BUFSIZE) >= 256 */
1107c2aa98e2SPeter Wemm }
110812ed1c7cSGregory Neil Shapiro /*
1109c2aa98e2SPeter Wemm **  PRIENCODE -- encode external priority names into internal values.
1110c2aa98e2SPeter Wemm **
1111c2aa98e2SPeter Wemm **	Parameters:
1112c2aa98e2SPeter Wemm **		p -- priority in ascii.
1113c2aa98e2SPeter Wemm **
1114c2aa98e2SPeter Wemm **	Returns:
1115c2aa98e2SPeter Wemm **		priority as a numeric level.
1116c2aa98e2SPeter Wemm **
1117c2aa98e2SPeter Wemm **	Side Effects:
1118c2aa98e2SPeter Wemm **		none.
1119c2aa98e2SPeter Wemm */
1120c2aa98e2SPeter Wemm 
11213299c2f1SGregory Neil Shapiro static int
1122c2aa98e2SPeter Wemm priencode(p)
1123c2aa98e2SPeter Wemm 	char *p;
1124c2aa98e2SPeter Wemm {
1125c2aa98e2SPeter Wemm 	register int i;
1126c2aa98e2SPeter Wemm 
1127c2aa98e2SPeter Wemm 	for (i = 0; i < NumPriorities; i++)
1128c2aa98e2SPeter Wemm 	{
112912ed1c7cSGregory Neil Shapiro 		if (sm_strcasecmp(p, Priorities[i].pri_name) == 0)
11303299c2f1SGregory Neil Shapiro 			return Priorities[i].pri_val;
1131c2aa98e2SPeter Wemm 	}
1132c2aa98e2SPeter Wemm 
1133c2aa98e2SPeter Wemm 	/* unknown priority */
11343299c2f1SGregory Neil Shapiro 	return 0;
1135c2aa98e2SPeter Wemm }
113612ed1c7cSGregory Neil Shapiro /*
1137c2aa98e2SPeter Wemm **  CRACKADDR -- parse an address and turn it into a macro
1138c2aa98e2SPeter Wemm **
1139c2aa98e2SPeter Wemm **	This doesn't actually parse the address -- it just extracts
1140c2aa98e2SPeter Wemm **	it and replaces it with "$g".  The parse is totally ad hoc
1141c2aa98e2SPeter Wemm **	and isn't even guaranteed to leave something syntactically
1142c2aa98e2SPeter Wemm **	identical to what it started with.  However, it does leave
1143f9218d3dSGregory Neil Shapiro **	something semantically identical if possible, else at least
1144f9218d3dSGregory Neil Shapiro **	syntactically correct.
1145f9218d3dSGregory Neil Shapiro **
1146f9218d3dSGregory Neil Shapiro **	For example, it changes "Real Name <real@example.com> (Comment)"
1147f9218d3dSGregory Neil Shapiro **	to "Real Name <$g> (Comment)".
1148c2aa98e2SPeter Wemm **
1149c2aa98e2SPeter Wemm **	This algorithm has been cleaned up to handle a wider range
1150c2aa98e2SPeter Wemm **	of cases -- notably quoted and backslash escaped strings.
1151c2aa98e2SPeter Wemm **	This modification makes it substantially better at preserving
1152c2aa98e2SPeter Wemm **	the original syntax.
1153c2aa98e2SPeter Wemm **
1154c2aa98e2SPeter Wemm **	Parameters:
1155c2aa98e2SPeter Wemm **		addr -- the address to be cracked.
1156f9218d3dSGregory Neil Shapiro **		e -- the current envelope.
1157c2aa98e2SPeter Wemm **
1158c2aa98e2SPeter Wemm **	Returns:
1159c2aa98e2SPeter Wemm **		a pointer to the new version.
1160c2aa98e2SPeter Wemm **
1161c2aa98e2SPeter Wemm **	Side Effects:
1162c2aa98e2SPeter Wemm **		none.
1163c2aa98e2SPeter Wemm **
1164c2aa98e2SPeter Wemm **	Warning:
1165c2aa98e2SPeter Wemm **		The return value is saved in local storage and should
1166c2aa98e2SPeter Wemm **		be copied if it is to be reused.
1167c2aa98e2SPeter Wemm */
1168c2aa98e2SPeter Wemm 
1169f9218d3dSGregory Neil Shapiro #define SM_HAVE_ROOM		((bp < buflim) && (buflim <= bufend))
1170f9218d3dSGregory Neil Shapiro 
1171f9218d3dSGregory Neil Shapiro /*
1172f9218d3dSGregory Neil Shapiro **  Append a character to bp if we have room.
1173f9218d3dSGregory Neil Shapiro **  If not, punt and return $g.
1174f9218d3dSGregory Neil Shapiro */
1175f9218d3dSGregory Neil Shapiro 
1176f9218d3dSGregory Neil Shapiro #define SM_APPEND_CHAR(c)					\
1177f9218d3dSGregory Neil Shapiro 	do							\
1178f9218d3dSGregory Neil Shapiro 	{							\
1179f9218d3dSGregory Neil Shapiro 		if (SM_HAVE_ROOM)				\
1180f9218d3dSGregory Neil Shapiro 			*bp++ = (c);				\
1181f9218d3dSGregory Neil Shapiro 		else						\
1182f9218d3dSGregory Neil Shapiro 			goto returng;				\
1183f9218d3dSGregory Neil Shapiro 	} while (0)
1184f9218d3dSGregory Neil Shapiro 
1185f9218d3dSGregory Neil Shapiro #if MAXNAME < 10
1186f9218d3dSGregory Neil Shapiro ERROR MAXNAME must be at least 10
1187f9218d3dSGregory Neil Shapiro #endif /* MAXNAME < 10 */
1188f9218d3dSGregory Neil Shapiro 
1189c2aa98e2SPeter Wemm char *
1190f9218d3dSGregory Neil Shapiro crackaddr(addr, e)
1191c2aa98e2SPeter Wemm 	register char *addr;
1192f9218d3dSGregory Neil Shapiro 	ENVELOPE *e;
1193c2aa98e2SPeter Wemm {
1194c2aa98e2SPeter Wemm 	register char *p;
1195c2aa98e2SPeter Wemm 	register char c;
1196f9218d3dSGregory Neil Shapiro 	int cmtlev;			/* comment level in input string */
1197f9218d3dSGregory Neil Shapiro 	int realcmtlev;			/* comment level in output string */
1198f9218d3dSGregory Neil Shapiro 	int anglelev;			/* angle level in input string */
1199f9218d3dSGregory Neil Shapiro 	int copylev;			/* 0 == in address, >0 copying */
1200f9218d3dSGregory Neil Shapiro 	int bracklev;			/* bracket level for IPv6 addr check */
1201f9218d3dSGregory Neil Shapiro 	bool addangle;			/* put closing angle in output */
1202f9218d3dSGregory Neil Shapiro 	bool qmode;			/* quoting in original string? */
1203f9218d3dSGregory Neil Shapiro 	bool realqmode;			/* quoting in output string? */
1204f9218d3dSGregory Neil Shapiro 	bool putgmac = false;		/* already wrote $g */
1205f9218d3dSGregory Neil Shapiro 	bool quoteit = false;		/* need to quote next character */
1206f9218d3dSGregory Neil Shapiro 	bool gotangle = false;		/* found first '<' */
1207f9218d3dSGregory Neil Shapiro 	bool gotcolon = false;		/* found a ':' */
1208c2aa98e2SPeter Wemm 	register char *bp;
1209c2aa98e2SPeter Wemm 	char *buflim;
1210c2aa98e2SPeter Wemm 	char *bufhead;
1211c2aa98e2SPeter Wemm 	char *addrhead;
1212f9218d3dSGregory Neil Shapiro 	char *bufend;
1213c2aa98e2SPeter Wemm 	static char buf[MAXNAME + 1];
1214c2aa98e2SPeter Wemm 
1215c2aa98e2SPeter Wemm 	if (tTd(33, 1))
121612ed1c7cSGregory Neil Shapiro 		sm_dprintf("crackaddr(%s)\n", addr);
1217c2aa98e2SPeter Wemm 
1218c2aa98e2SPeter Wemm 	/* strip leading spaces */
1219c2aa98e2SPeter Wemm 	while (*addr != '\0' && isascii(*addr) && isspace(*addr))
1220c2aa98e2SPeter Wemm 		addr++;
1221c2aa98e2SPeter Wemm 
1222c2aa98e2SPeter Wemm 	/*
1223c2aa98e2SPeter Wemm 	**  Start by assuming we have no angle brackets.  This will be
1224c2aa98e2SPeter Wemm 	**  adjusted later if we find them.
1225c2aa98e2SPeter Wemm 	*/
1226c2aa98e2SPeter Wemm 
1227f9218d3dSGregory Neil Shapiro 	buflim = bufend = &buf[sizeof(buf) - 1];
1228c2aa98e2SPeter Wemm 	bp = bufhead = buf;
1229c2aa98e2SPeter Wemm 	p = addrhead = addr;
1230f9218d3dSGregory Neil Shapiro 	copylev = anglelev = cmtlev = realcmtlev = 0;
1231c2aa98e2SPeter Wemm 	bracklev = 0;
1232f9218d3dSGregory Neil Shapiro 	qmode = realqmode = addangle = false;
1233c2aa98e2SPeter Wemm 
1234c2aa98e2SPeter Wemm 	while ((c = *p++) != '\0')
1235c2aa98e2SPeter Wemm 	{
1236c2aa98e2SPeter Wemm 		/*
1237f9218d3dSGregory Neil Shapiro 		**  Try to keep legal syntax using spare buffer space
1238f9218d3dSGregory Neil Shapiro 		**  (maintained by buflim).
1239c2aa98e2SPeter Wemm 		*/
1240c2aa98e2SPeter Wemm 
1241f9218d3dSGregory Neil Shapiro 		if (copylev > 0)
1242f9218d3dSGregory Neil Shapiro 			SM_APPEND_CHAR(c);
1243c2aa98e2SPeter Wemm 
1244c2aa98e2SPeter Wemm 		/* check for backslash escapes */
1245c2aa98e2SPeter Wemm 		if (c == '\\')
1246c2aa98e2SPeter Wemm 		{
1247c2aa98e2SPeter Wemm 			/* arrange to quote the address */
1248c2aa98e2SPeter Wemm 			if (cmtlev <= 0 && !qmode)
124912ed1c7cSGregory Neil Shapiro 				quoteit = true;
1250c2aa98e2SPeter Wemm 
1251c2aa98e2SPeter Wemm 			if ((c = *p++) == '\0')
1252c2aa98e2SPeter Wemm 			{
1253c2aa98e2SPeter Wemm 				/* too far */
1254c2aa98e2SPeter Wemm 				p--;
1255c2aa98e2SPeter Wemm 				goto putg;
1256c2aa98e2SPeter Wemm 			}
1257f9218d3dSGregory Neil Shapiro 			if (copylev > 0)
1258f9218d3dSGregory Neil Shapiro 				SM_APPEND_CHAR(c);
1259c2aa98e2SPeter Wemm 			goto putg;
1260c2aa98e2SPeter Wemm 		}
1261c2aa98e2SPeter Wemm 
1262c2aa98e2SPeter Wemm 		/* check for quoted strings */
1263c2aa98e2SPeter Wemm 		if (c == '"' && cmtlev <= 0)
1264c2aa98e2SPeter Wemm 		{
1265c2aa98e2SPeter Wemm 			qmode = !qmode;
1266f9218d3dSGregory Neil Shapiro 			if (copylev > 0 && SM_HAVE_ROOM)
1267f9218d3dSGregory Neil Shapiro 			{
1268f9218d3dSGregory Neil Shapiro 				if (realqmode)
1269f9218d3dSGregory Neil Shapiro 					buflim--;
1270f9218d3dSGregory Neil Shapiro 				else
1271f9218d3dSGregory Neil Shapiro 					buflim++;
1272c2aa98e2SPeter Wemm 				realqmode = !realqmode;
1273f9218d3dSGregory Neil Shapiro 			}
1274c2aa98e2SPeter Wemm 			continue;
1275c2aa98e2SPeter Wemm 		}
1276c2aa98e2SPeter Wemm 		if (qmode)
1277c2aa98e2SPeter Wemm 			goto putg;
1278c2aa98e2SPeter Wemm 
1279c2aa98e2SPeter Wemm 		/* check for comments */
1280c2aa98e2SPeter Wemm 		if (c == '(')
1281c2aa98e2SPeter Wemm 		{
1282c2aa98e2SPeter Wemm 			cmtlev++;
1283c2aa98e2SPeter Wemm 
1284c2aa98e2SPeter Wemm 			/* allow space for closing paren */
1285f9218d3dSGregory Neil Shapiro 			if (SM_HAVE_ROOM)
1286c2aa98e2SPeter Wemm 			{
1287c2aa98e2SPeter Wemm 				buflim--;
1288c2aa98e2SPeter Wemm 				realcmtlev++;
1289c2aa98e2SPeter Wemm 				if (copylev++ <= 0)
1290c2aa98e2SPeter Wemm 				{
1291c2aa98e2SPeter Wemm 					if (bp != bufhead)
1292f9218d3dSGregory Neil Shapiro 						SM_APPEND_CHAR(' ');
1293f9218d3dSGregory Neil Shapiro 					SM_APPEND_CHAR(c);
1294c2aa98e2SPeter Wemm 				}
1295c2aa98e2SPeter Wemm 			}
1296c2aa98e2SPeter Wemm 		}
1297c2aa98e2SPeter Wemm 		if (cmtlev > 0)
1298c2aa98e2SPeter Wemm 		{
1299c2aa98e2SPeter Wemm 			if (c == ')')
1300c2aa98e2SPeter Wemm 			{
1301c2aa98e2SPeter Wemm 				cmtlev--;
1302c2aa98e2SPeter Wemm 				copylev--;
1303f9218d3dSGregory Neil Shapiro 				if (SM_HAVE_ROOM)
1304c2aa98e2SPeter Wemm 				{
1305c2aa98e2SPeter Wemm 					realcmtlev--;
1306c2aa98e2SPeter Wemm 					buflim++;
1307c2aa98e2SPeter Wemm 				}
1308c2aa98e2SPeter Wemm 			}
1309c2aa98e2SPeter Wemm 			continue;
1310c2aa98e2SPeter Wemm 		}
1311c2aa98e2SPeter Wemm 		else if (c == ')')
1312c2aa98e2SPeter Wemm 		{
1313c2aa98e2SPeter Wemm 			/* syntax error: unmatched ) */
13147660b554SGregory Neil Shapiro 			if (copylev > 0 && SM_HAVE_ROOM && bp > bufhead)
1315c2aa98e2SPeter Wemm 				bp--;
1316c2aa98e2SPeter Wemm 		}
1317c2aa98e2SPeter Wemm 
1318c2aa98e2SPeter Wemm 		/* count nesting on [ ... ] (for IPv6 domain literals) */
1319c2aa98e2SPeter Wemm 		if (c == '[')
1320c2aa98e2SPeter Wemm 			bracklev++;
1321c2aa98e2SPeter Wemm 		else if (c == ']')
1322c2aa98e2SPeter Wemm 			bracklev--;
1323c2aa98e2SPeter Wemm 
1324c2aa98e2SPeter Wemm 		/* check for group: list; syntax */
1325c2aa98e2SPeter Wemm 		if (c == ':' && anglelev <= 0 && bracklev <= 0 &&
1326c2aa98e2SPeter Wemm 		    !gotcolon && !ColonOkInAddr)
1327c2aa98e2SPeter Wemm 		{
1328c2aa98e2SPeter Wemm 			register char *q;
1329c2aa98e2SPeter Wemm 
1330c2aa98e2SPeter Wemm 			/*
1331c2aa98e2SPeter Wemm 			**  Check for DECnet phase IV ``::'' (host::user)
1332f9218d3dSGregory Neil Shapiro 			**  or DECnet phase V ``:.'' syntaxes.  The latter
1333c2aa98e2SPeter Wemm 			**  covers ``user@DEC:.tay.myhost'' and
1334c2aa98e2SPeter Wemm 			**  ``DEC:.tay.myhost::user'' syntaxes (bletch).
1335c2aa98e2SPeter Wemm 			*/
1336c2aa98e2SPeter Wemm 
1337c2aa98e2SPeter Wemm 			if (*p == ':' || *p == '.')
1338c2aa98e2SPeter Wemm 			{
1339c2aa98e2SPeter Wemm 				if (cmtlev <= 0 && !qmode)
134012ed1c7cSGregory Neil Shapiro 					quoteit = true;
1341f9218d3dSGregory Neil Shapiro 				if (copylev > 0)
1342c2aa98e2SPeter Wemm 				{
1343f9218d3dSGregory Neil Shapiro 					SM_APPEND_CHAR(c);
1344f9218d3dSGregory Neil Shapiro 					SM_APPEND_CHAR(*p);
1345c2aa98e2SPeter Wemm 				}
1346c2aa98e2SPeter Wemm 				p++;
1347c2aa98e2SPeter Wemm 				goto putg;
1348c2aa98e2SPeter Wemm 			}
1349c2aa98e2SPeter Wemm 
135012ed1c7cSGregory Neil Shapiro 			gotcolon = true;
1351c2aa98e2SPeter Wemm 
1352c2aa98e2SPeter Wemm 			bp = bufhead;
1353c2aa98e2SPeter Wemm 			if (quoteit)
1354c2aa98e2SPeter Wemm 			{
1355f9218d3dSGregory Neil Shapiro 				SM_APPEND_CHAR('"');
1356c2aa98e2SPeter Wemm 
1357c2aa98e2SPeter Wemm 				/* back up over the ':' and any spaces */
1358c2aa98e2SPeter Wemm 				--p;
1359f9218d3dSGregory Neil Shapiro 				while (p > addr &&
1360f9218d3dSGregory Neil Shapiro 				       isascii(*--p) && isspace(*p))
1361c2aa98e2SPeter Wemm 					continue;
1362c2aa98e2SPeter Wemm 				p++;
1363c2aa98e2SPeter Wemm 			}
1364c2aa98e2SPeter Wemm 			for (q = addrhead; q < p; )
1365c2aa98e2SPeter Wemm 			{
1366c2aa98e2SPeter Wemm 				c = *q++;
1367c2aa98e2SPeter Wemm 				if (quoteit && c == '"')
1368f9218d3dSGregory Neil Shapiro 					SM_APPEND_CHAR('\\');
1369f9218d3dSGregory Neil Shapiro 				SM_APPEND_CHAR(c);
1370c2aa98e2SPeter Wemm 			}
1371c2aa98e2SPeter Wemm 			if (quoteit)
1372c2aa98e2SPeter Wemm 			{
1373c2aa98e2SPeter Wemm 				if (bp == &bufhead[1])
1374c2aa98e2SPeter Wemm 					bp--;
1375c2aa98e2SPeter Wemm 				else
1376f9218d3dSGregory Neil Shapiro 					SM_APPEND_CHAR('"');
1377c2aa98e2SPeter Wemm 				while ((c = *p++) != ':')
1378f9218d3dSGregory Neil Shapiro 					SM_APPEND_CHAR(c);
1379f9218d3dSGregory Neil Shapiro 				SM_APPEND_CHAR(c);
1380c2aa98e2SPeter Wemm 			}
1381c2aa98e2SPeter Wemm 
1382c2aa98e2SPeter Wemm 			/* any trailing white space is part of group: */
1383f9218d3dSGregory Neil Shapiro 			while (isascii(*p) && isspace(*p))
1384f9218d3dSGregory Neil Shapiro 			{
1385f9218d3dSGregory Neil Shapiro 				SM_APPEND_CHAR(*p);
1386f9218d3dSGregory Neil Shapiro 				p++;
1387f9218d3dSGregory Neil Shapiro 			}
1388c2aa98e2SPeter Wemm 			copylev = 0;
138912ed1c7cSGregory Neil Shapiro 			putgmac = quoteit = false;
1390c2aa98e2SPeter Wemm 			bufhead = bp;
1391c2aa98e2SPeter Wemm 			addrhead = p;
1392c2aa98e2SPeter Wemm 			continue;
1393c2aa98e2SPeter Wemm 		}
1394c2aa98e2SPeter Wemm 
1395c2aa98e2SPeter Wemm 		if (c == ';' && copylev <= 0 && !ColonOkInAddr)
1396f9218d3dSGregory Neil Shapiro 			SM_APPEND_CHAR(c);
1397c2aa98e2SPeter Wemm 
1398c2aa98e2SPeter Wemm 		/* check for characters that may have to be quoted */
1399c2aa98e2SPeter Wemm 		if (strchr(MustQuoteChars, c) != NULL)
1400c2aa98e2SPeter Wemm 		{
1401c2aa98e2SPeter Wemm 			/*
1402c2aa98e2SPeter Wemm 			**  If these occur as the phrase part of a <>
1403c2aa98e2SPeter Wemm 			**  construct, but are not inside of () or already
1404c2aa98e2SPeter Wemm 			**  quoted, they will have to be quoted.  Note that
1405c2aa98e2SPeter Wemm 			**  now (but don't actually do the quoting).
1406c2aa98e2SPeter Wemm 			*/
1407c2aa98e2SPeter Wemm 
1408c2aa98e2SPeter Wemm 			if (cmtlev <= 0 && !qmode)
140912ed1c7cSGregory Neil Shapiro 				quoteit = true;
1410c2aa98e2SPeter Wemm 		}
1411c2aa98e2SPeter Wemm 
1412c2aa98e2SPeter Wemm 		/* check for angle brackets */
1413c2aa98e2SPeter Wemm 		if (c == '<')
1414c2aa98e2SPeter Wemm 		{
1415c2aa98e2SPeter Wemm 			register char *q;
1416c2aa98e2SPeter Wemm 
1417c2aa98e2SPeter Wemm 			/* assume first of two angles is bogus */
1418c2aa98e2SPeter Wemm 			if (gotangle)
141912ed1c7cSGregory Neil Shapiro 				quoteit = true;
142012ed1c7cSGregory Neil Shapiro 			gotangle = true;
1421c2aa98e2SPeter Wemm 
1422c2aa98e2SPeter Wemm 			/* oops -- have to change our mind */
1423c2aa98e2SPeter Wemm 			anglelev = 1;
1424f9218d3dSGregory Neil Shapiro 			if (SM_HAVE_ROOM)
1425f9218d3dSGregory Neil Shapiro 			{
1426f9218d3dSGregory Neil Shapiro 				if (!addangle)
1427f9218d3dSGregory Neil Shapiro 					buflim--;
1428f9218d3dSGregory Neil Shapiro 				addangle = true;
1429f9218d3dSGregory Neil Shapiro 			}
1430c2aa98e2SPeter Wemm 
1431c2aa98e2SPeter Wemm 			bp = bufhead;
1432c2aa98e2SPeter Wemm 			if (quoteit)
1433c2aa98e2SPeter Wemm 			{
1434f9218d3dSGregory Neil Shapiro 				SM_APPEND_CHAR('"');
1435c2aa98e2SPeter Wemm 
1436c2aa98e2SPeter Wemm 				/* back up over the '<' and any spaces */
1437c2aa98e2SPeter Wemm 				--p;
1438f9218d3dSGregory Neil Shapiro 				while (p > addr &&
1439f9218d3dSGregory Neil Shapiro 				       isascii(*--p) && isspace(*p))
1440c2aa98e2SPeter Wemm 					continue;
1441c2aa98e2SPeter Wemm 				p++;
1442c2aa98e2SPeter Wemm 			}
1443c2aa98e2SPeter Wemm 			for (q = addrhead; q < p; )
1444c2aa98e2SPeter Wemm 			{
1445c2aa98e2SPeter Wemm 				c = *q++;
1446c2aa98e2SPeter Wemm 				if (quoteit && c == '"')
1447f9218d3dSGregory Neil Shapiro 				{
1448f9218d3dSGregory Neil Shapiro 					SM_APPEND_CHAR('\\');
1449f9218d3dSGregory Neil Shapiro 					SM_APPEND_CHAR(c);
1450c2aa98e2SPeter Wemm 				}
1451f9218d3dSGregory Neil Shapiro 				else
1452f9218d3dSGregory Neil Shapiro 					SM_APPEND_CHAR(c);
1453c2aa98e2SPeter Wemm 			}
1454c2aa98e2SPeter Wemm 			if (quoteit)
1455c2aa98e2SPeter Wemm 			{
1456c2aa98e2SPeter Wemm 				if (bp == &buf[1])
1457c2aa98e2SPeter Wemm 					bp--;
1458c2aa98e2SPeter Wemm 				else
1459f9218d3dSGregory Neil Shapiro 					SM_APPEND_CHAR('"');
1460c2aa98e2SPeter Wemm 				while ((c = *p++) != '<')
1461f9218d3dSGregory Neil Shapiro 					SM_APPEND_CHAR(c);
1462f9218d3dSGregory Neil Shapiro 				SM_APPEND_CHAR(c);
1463c2aa98e2SPeter Wemm 			}
1464c2aa98e2SPeter Wemm 			copylev = 0;
146512ed1c7cSGregory Neil Shapiro 			putgmac = quoteit = false;
1466c2aa98e2SPeter Wemm 			continue;
1467c2aa98e2SPeter Wemm 		}
1468c2aa98e2SPeter Wemm 
1469c2aa98e2SPeter Wemm 		if (c == '>')
1470c2aa98e2SPeter Wemm 		{
1471c2aa98e2SPeter Wemm 			if (anglelev > 0)
1472c2aa98e2SPeter Wemm 			{
1473c2aa98e2SPeter Wemm 				anglelev--;
1474f9218d3dSGregory Neil Shapiro 				if (SM_HAVE_ROOM)
1475c2aa98e2SPeter Wemm 				{
1476f9218d3dSGregory Neil Shapiro 					if (addangle)
1477c2aa98e2SPeter Wemm 						buflim++;
1478f9218d3dSGregory Neil Shapiro 					addangle = false;
1479c2aa98e2SPeter Wemm 				}
1480c2aa98e2SPeter Wemm 			}
1481f9218d3dSGregory Neil Shapiro 			else if (SM_HAVE_ROOM)
1482c2aa98e2SPeter Wemm 			{
1483c2aa98e2SPeter Wemm 				/* syntax error: unmatched > */
14847660b554SGregory Neil Shapiro 				if (copylev > 0 && bp > bufhead)
1485c2aa98e2SPeter Wemm 					bp--;
148612ed1c7cSGregory Neil Shapiro 				quoteit = true;
1487c2aa98e2SPeter Wemm 				continue;
1488c2aa98e2SPeter Wemm 			}
1489c2aa98e2SPeter Wemm 			if (copylev++ <= 0)
1490f9218d3dSGregory Neil Shapiro 				SM_APPEND_CHAR(c);
1491c2aa98e2SPeter Wemm 			continue;
1492c2aa98e2SPeter Wemm 		}
1493c2aa98e2SPeter Wemm 
1494c2aa98e2SPeter Wemm 		/* must be a real address character */
1495c2aa98e2SPeter Wemm 	putg:
1496c2aa98e2SPeter Wemm 		if (copylev <= 0 && !putgmac)
1497c2aa98e2SPeter Wemm 		{
1498f9218d3dSGregory Neil Shapiro 			if (bp > buf && bp[-1] == ')')
1499f9218d3dSGregory Neil Shapiro 				SM_APPEND_CHAR(' ');
1500f9218d3dSGregory Neil Shapiro 			SM_APPEND_CHAR(MACROEXPAND);
1501f9218d3dSGregory Neil Shapiro 			SM_APPEND_CHAR('g');
150212ed1c7cSGregory Neil Shapiro 			putgmac = true;
1503c2aa98e2SPeter Wemm 		}
1504c2aa98e2SPeter Wemm 	}
1505c2aa98e2SPeter Wemm 
1506c2aa98e2SPeter Wemm 	/* repair any syntactic damage */
1507f9218d3dSGregory Neil Shapiro 	if (realqmode && bp < bufend)
1508c2aa98e2SPeter Wemm 		*bp++ = '"';
1509f9218d3dSGregory Neil Shapiro 	while (realcmtlev-- > 0 && bp < bufend)
1510c2aa98e2SPeter Wemm 		*bp++ = ')';
1511f9218d3dSGregory Neil Shapiro 	if (addangle && bp < bufend)
1512c2aa98e2SPeter Wemm 		*bp++ = '>';
1513f9218d3dSGregory Neil Shapiro 	*bp = '\0';
1514f9218d3dSGregory Neil Shapiro 	if (bp < bufend)
1515f9218d3dSGregory Neil Shapiro 		goto success;
1516c2aa98e2SPeter Wemm 
1517f9218d3dSGregory Neil Shapiro  returng:
1518f9218d3dSGregory Neil Shapiro 	/* String too long, punt */
1519f9218d3dSGregory Neil Shapiro 	buf[0] = '<';
1520f9218d3dSGregory Neil Shapiro 	buf[1] = MACROEXPAND;
1521f9218d3dSGregory Neil Shapiro 	buf[2]= 'g';
1522f9218d3dSGregory Neil Shapiro 	buf[3] = '>';
1523f9218d3dSGregory Neil Shapiro 	buf[4]= '\0';
1524f9218d3dSGregory Neil Shapiro 	sm_syslog(LOG_ALERT, e->e_id,
1525f9218d3dSGregory Neil Shapiro 		  "Dropped invalid comments from header address");
1526f9218d3dSGregory Neil Shapiro 
1527f9218d3dSGregory Neil Shapiro  success:
1528c2aa98e2SPeter Wemm 	if (tTd(33, 1))
1529c2aa98e2SPeter Wemm 	{
153012ed1c7cSGregory Neil Shapiro 		sm_dprintf("crackaddr=>`");
1531bfb62e91SGregory Neil Shapiro 		xputs(sm_debug_file(), buf);
153212ed1c7cSGregory Neil Shapiro 		sm_dprintf("'\n");
1533c2aa98e2SPeter Wemm 	}
15343299c2f1SGregory Neil Shapiro 	return buf;
1535c2aa98e2SPeter Wemm }
153612ed1c7cSGregory Neil Shapiro /*
1537c2aa98e2SPeter Wemm **  PUTHEADER -- put the header part of a message from the in-core copy
1538c2aa98e2SPeter Wemm **
1539c2aa98e2SPeter Wemm **	Parameters:
1540c2aa98e2SPeter Wemm **		mci -- the connection information.
15413299c2f1SGregory Neil Shapiro **		hdr -- the header to put.
1542c2aa98e2SPeter Wemm **		e -- envelope to use.
1543e01d6f61SPeter Wemm **		flags -- MIME conversion flags.
1544c2aa98e2SPeter Wemm **
1545c2aa98e2SPeter Wemm **	Returns:
1546355d91e3SGregory Neil Shapiro **		true iff header part was written successfully
1547c2aa98e2SPeter Wemm **
1548c2aa98e2SPeter Wemm **	Side Effects:
1549c2aa98e2SPeter Wemm **		none.
1550c2aa98e2SPeter Wemm */
1551c2aa98e2SPeter Wemm 
1552567a2fc9SGregory Neil Shapiro bool
1553e01d6f61SPeter Wemm putheader(mci, hdr, e, flags)
1554c2aa98e2SPeter Wemm 	register MCI *mci;
1555c2aa98e2SPeter Wemm 	HDR *hdr;
1556c2aa98e2SPeter Wemm 	register ENVELOPE *e;
1557e01d6f61SPeter Wemm 	int flags;
1558c2aa98e2SPeter Wemm {
1559c2aa98e2SPeter Wemm 	register HDR *h;
156012ed1c7cSGregory Neil Shapiro 	char buf[SM_MAX(MAXLINE,BUFSIZ)];
1561c2aa98e2SPeter Wemm 	char obuf[MAXLINE];
1562c2aa98e2SPeter Wemm 
1563c2aa98e2SPeter Wemm 	if (tTd(34, 1))
156412ed1c7cSGregory Neil Shapiro 		sm_dprintf("--- putheader, mailer = %s ---\n",
1565c2aa98e2SPeter Wemm 			mci->mci_mailer->m_name);
1566c2aa98e2SPeter Wemm 
1567c2aa98e2SPeter Wemm 	/*
1568c2aa98e2SPeter Wemm 	**  If we're in MIME mode, we're not really in the header of the
1569c2aa98e2SPeter Wemm 	**  message, just the header of one of the parts of the body of
1570c2aa98e2SPeter Wemm 	**  the message.  Therefore MCIF_INHEADER should not be turned on.
1571c2aa98e2SPeter Wemm 	*/
1572c2aa98e2SPeter Wemm 
1573c2aa98e2SPeter Wemm 	if (!bitset(MCIF_INMIME, mci->mci_flags))
1574c2aa98e2SPeter Wemm 		mci->mci_flags |= MCIF_INHEADER;
1575c2aa98e2SPeter Wemm 
1576c2aa98e2SPeter Wemm 	for (h = hdr; h != NULL; h = h->h_link)
1577c2aa98e2SPeter Wemm 	{
1578c2aa98e2SPeter Wemm 		register char *p = h->h_value;
157912ed1c7cSGregory Neil Shapiro 		char *q;
1580c2aa98e2SPeter Wemm 
1581c2aa98e2SPeter Wemm 		if (tTd(34, 11))
1582c2aa98e2SPeter Wemm 		{
158312ed1c7cSGregory Neil Shapiro 			sm_dprintf("  %s: ", h->h_field);
1584bfb62e91SGregory Neil Shapiro 			xputs(sm_debug_file(), p);
1585c2aa98e2SPeter Wemm 		}
1586c2aa98e2SPeter Wemm 
15873299c2f1SGregory Neil Shapiro 		/* Skip empty headers */
15883299c2f1SGregory Neil Shapiro 		if (h->h_value == NULL)
15893299c2f1SGregory Neil Shapiro 			continue;
15903299c2f1SGregory Neil Shapiro 
159176b7bf71SPeter Wemm 		/* heuristic shortening of MIME fields to avoid MUA overflows */
159276b7bf71SPeter Wemm 		if (MaxMimeFieldLength > 0 &&
159376b7bf71SPeter Wemm 		    wordinclass(h->h_field,
159412ed1c7cSGregory Neil Shapiro 				macid("{checkMIMEFieldHeaders}")))
159576b7bf71SPeter Wemm 		{
1596c46d91b7SGregory Neil Shapiro 			size_t len;
1597c46d91b7SGregory Neil Shapiro 
1598f9218d3dSGregory Neil Shapiro 			len = fix_mime_header(h, e);
1599c46d91b7SGregory Neil Shapiro 			if (len > 0)
160076b7bf71SPeter Wemm 			{
160176b7bf71SPeter Wemm 				sm_syslog(LOG_ALERT, e->e_id,
1602c46d91b7SGregory Neil Shapiro 					  "Truncated MIME %s header due to field size (length = %ld) (possible attack)",
1603c46d91b7SGregory Neil Shapiro 					  h->h_field, (unsigned long) len);
160476b7bf71SPeter Wemm 				if (tTd(34, 11))
160512ed1c7cSGregory Neil Shapiro 					sm_dprintf("  truncated MIME %s header due to field size  (length = %ld) (possible attack)\n",
1606c46d91b7SGregory Neil Shapiro 						   h->h_field,
1607c46d91b7SGregory Neil Shapiro 						   (unsigned long) len);
160876b7bf71SPeter Wemm 			}
160976b7bf71SPeter Wemm 		}
161076b7bf71SPeter Wemm 
161176b7bf71SPeter Wemm 		if (MaxMimeHeaderLength > 0 &&
161276b7bf71SPeter Wemm 		    wordinclass(h->h_field,
161312ed1c7cSGregory Neil Shapiro 				macid("{checkMIMETextHeaders}")))
161476b7bf71SPeter Wemm 		{
1615c46d91b7SGregory Neil Shapiro 			size_t len;
1616c46d91b7SGregory Neil Shapiro 
1617c46d91b7SGregory Neil Shapiro 			len = strlen(h->h_value);
1618c46d91b7SGregory Neil Shapiro 			if (len > (size_t) MaxMimeHeaderLength)
161976b7bf71SPeter Wemm 			{
162076b7bf71SPeter Wemm 				h->h_value[MaxMimeHeaderLength - 1] = '\0';
162176b7bf71SPeter Wemm 				sm_syslog(LOG_ALERT, e->e_id,
1622c46d91b7SGregory Neil Shapiro 					  "Truncated long MIME %s header (length = %ld) (possible attack)",
1623c46d91b7SGregory Neil Shapiro 					  h->h_field, (unsigned long) len);
162476b7bf71SPeter Wemm 				if (tTd(34, 11))
162512ed1c7cSGregory Neil Shapiro 					sm_dprintf("  truncated long MIME %s header (length = %ld) (possible attack)\n",
1626c46d91b7SGregory Neil Shapiro 						   h->h_field,
1627c46d91b7SGregory Neil Shapiro 						   (unsigned long) len);
162876b7bf71SPeter Wemm 			}
162976b7bf71SPeter Wemm 		}
163076b7bf71SPeter Wemm 
163176b7bf71SPeter Wemm 		if (MaxMimeHeaderLength > 0 &&
163276b7bf71SPeter Wemm 		    wordinclass(h->h_field,
163312ed1c7cSGregory Neil Shapiro 				macid("{checkMIMEHeaders}")))
163476b7bf71SPeter Wemm 		{
1635c46d91b7SGregory Neil Shapiro 			size_t len;
1636c46d91b7SGregory Neil Shapiro 
1637c46d91b7SGregory Neil Shapiro 			len = strlen(h->h_value);
1638c46d91b7SGregory Neil Shapiro 			if (shorten_rfc822_string(h->h_value,
1639c46d91b7SGregory Neil Shapiro 						  MaxMimeHeaderLength))
164076b7bf71SPeter Wemm 			{
1641f9218d3dSGregory Neil Shapiro 				if (len < MaxMimeHeaderLength)
1642f9218d3dSGregory Neil Shapiro 				{
1643f9218d3dSGregory Neil Shapiro 					/* we only rebalanced a bogus header */
1644f9218d3dSGregory Neil Shapiro 					sm_syslog(LOG_ALERT, e->e_id,
1645f9218d3dSGregory Neil Shapiro 						  "Fixed MIME %s header (possible attack)",
1646f9218d3dSGregory Neil Shapiro 						  h->h_field);
1647f9218d3dSGregory Neil Shapiro 					if (tTd(34, 11))
1648f9218d3dSGregory Neil Shapiro 						sm_dprintf("  fixed MIME %s header (possible attack)\n",
1649f9218d3dSGregory Neil Shapiro 							   h->h_field);
1650f9218d3dSGregory Neil Shapiro 				}
1651f9218d3dSGregory Neil Shapiro 				else
1652f9218d3dSGregory Neil Shapiro 				{
1653f9218d3dSGregory Neil Shapiro 					/* we actually shortened header */
165476b7bf71SPeter Wemm 					sm_syslog(LOG_ALERT, e->e_id,
1655c46d91b7SGregory Neil Shapiro 						  "Truncated long MIME %s header (length = %ld) (possible attack)",
1656f9218d3dSGregory Neil Shapiro 						  h->h_field,
1657f9218d3dSGregory Neil Shapiro 						  (unsigned long) len);
165876b7bf71SPeter Wemm 					if (tTd(34, 11))
165912ed1c7cSGregory Neil Shapiro 						sm_dprintf("  truncated long MIME %s header (length = %ld) (possible attack)\n",
1660c46d91b7SGregory Neil Shapiro 							   h->h_field,
1661c46d91b7SGregory Neil Shapiro 							   (unsigned long) len);
166276b7bf71SPeter Wemm 				}
166376b7bf71SPeter Wemm 			}
1664f9218d3dSGregory Neil Shapiro 		}
166576b7bf71SPeter Wemm 
1666e01d6f61SPeter Wemm 		/*
1667e01d6f61SPeter Wemm 		**  Suppress Content-Transfer-Encoding: if we are MIMEing
1668e01d6f61SPeter Wemm 		**  and we are potentially converting from 8 bit to 7 bit
1669e01d6f61SPeter Wemm 		**  MIME.  If converting, add a new CTE header in
1670e01d6f61SPeter Wemm 		**  mime8to7().
1671e01d6f61SPeter Wemm 		*/
167212ed1c7cSGregory Neil Shapiro 
1673c2aa98e2SPeter Wemm 		if (bitset(H_CTE, h->h_flags) &&
1674e01d6f61SPeter Wemm 		    bitset(MCIF_CVT8TO7|MCIF_CVT7TO8|MCIF_INMIME,
1675e01d6f61SPeter Wemm 			   mci->mci_flags) &&
1676e01d6f61SPeter Wemm 		    !bitset(M87F_NO8TO7, flags))
1677c2aa98e2SPeter Wemm 		{
1678c2aa98e2SPeter Wemm 			if (tTd(34, 11))
167912ed1c7cSGregory Neil Shapiro 				sm_dprintf(" (skipped (content-transfer-encoding))\n");
1680c2aa98e2SPeter Wemm 			continue;
1681c2aa98e2SPeter Wemm 		}
1682c2aa98e2SPeter Wemm 
1683c2aa98e2SPeter Wemm 		if (bitset(MCIF_INMIME, mci->mci_flags))
1684c2aa98e2SPeter Wemm 		{
1685c2aa98e2SPeter Wemm 			if (tTd(34, 11))
168612ed1c7cSGregory Neil Shapiro 				sm_dprintf("\n");
1687567a2fc9SGregory Neil Shapiro 			if (!put_vanilla_header(h, p, mci))
1688567a2fc9SGregory Neil Shapiro 				goto writeerr;
1689c2aa98e2SPeter Wemm 			continue;
1690c2aa98e2SPeter Wemm 		}
1691c2aa98e2SPeter Wemm 
1692c2aa98e2SPeter Wemm 		if (bitset(H_CHECK|H_ACHECK, h->h_flags) &&
16933299c2f1SGregory Neil Shapiro 		    !bitintersect(h->h_mflags, mci->mci_mailer->m_flags) &&
16943299c2f1SGregory Neil Shapiro 		    (h->h_macro == '\0' ||
169512ed1c7cSGregory Neil Shapiro 		     (q = macvalue(bitidx(h->h_macro), e)) == NULL ||
169612ed1c7cSGregory Neil Shapiro 		     *q == '\0'))
1697c2aa98e2SPeter Wemm 		{
1698c2aa98e2SPeter Wemm 			if (tTd(34, 11))
169912ed1c7cSGregory Neil Shapiro 				sm_dprintf(" (skipped)\n");
1700c2aa98e2SPeter Wemm 			continue;
1701c2aa98e2SPeter Wemm 		}
1702c2aa98e2SPeter Wemm 
1703c2aa98e2SPeter Wemm 		/* handle Resent-... headers specially */
1704c2aa98e2SPeter Wemm 		if (bitset(H_RESENT, h->h_flags) && !bitset(EF_RESENT, e->e_flags))
1705c2aa98e2SPeter Wemm 		{
1706c2aa98e2SPeter Wemm 			if (tTd(34, 11))
170712ed1c7cSGregory Neil Shapiro 				sm_dprintf(" (skipped (resent))\n");
1708c2aa98e2SPeter Wemm 			continue;
1709c2aa98e2SPeter Wemm 		}
1710c2aa98e2SPeter Wemm 
1711c2aa98e2SPeter Wemm 		/* suppress return receipts if requested */
1712c2aa98e2SPeter Wemm 		if (bitset(H_RECEIPTTO, h->h_flags) &&
1713c2aa98e2SPeter Wemm 		    (RrtImpliesDsn || bitset(EF_NORECEIPT, e->e_flags)))
1714c2aa98e2SPeter Wemm 		{
1715c2aa98e2SPeter Wemm 			if (tTd(34, 11))
171612ed1c7cSGregory Neil Shapiro 				sm_dprintf(" (skipped (receipt))\n");
1717c2aa98e2SPeter Wemm 			continue;
1718c2aa98e2SPeter Wemm 		}
1719c2aa98e2SPeter Wemm 
1720c2aa98e2SPeter Wemm 		/* macro expand value if generated internally */
17213299c2f1SGregory Neil Shapiro 		if (bitset(H_DEFAULT, h->h_flags) ||
17223299c2f1SGregory Neil Shapiro 		    bitset(H_BINDLATE, h->h_flags))
1723c2aa98e2SPeter Wemm 		{
1724c2aa98e2SPeter Wemm 			expand(p, buf, sizeof buf, e);
1725c2aa98e2SPeter Wemm 			p = buf;
1726c2aa98e2SPeter Wemm 			if (*p == '\0')
1727c2aa98e2SPeter Wemm 			{
1728c2aa98e2SPeter Wemm 				if (tTd(34, 11))
172912ed1c7cSGregory Neil Shapiro 					sm_dprintf(" (skipped -- null value)\n");
1730c2aa98e2SPeter Wemm 				continue;
1731c2aa98e2SPeter Wemm 			}
1732c2aa98e2SPeter Wemm 		}
1733c2aa98e2SPeter Wemm 
1734c2aa98e2SPeter Wemm 		if (bitset(H_BCC, h->h_flags))
1735c2aa98e2SPeter Wemm 		{
1736c2aa98e2SPeter Wemm 			/* Bcc: field -- either truncate or delete */
1737c2aa98e2SPeter Wemm 			if (bitset(EF_DELETE_BCC, e->e_flags))
1738c2aa98e2SPeter Wemm 			{
1739c2aa98e2SPeter Wemm 				if (tTd(34, 11))
174012ed1c7cSGregory Neil Shapiro 					sm_dprintf(" (skipped -- bcc)\n");
1741c2aa98e2SPeter Wemm 			}
1742c2aa98e2SPeter Wemm 			else
1743c2aa98e2SPeter Wemm 			{
1744c2aa98e2SPeter Wemm 				/* no other recipient headers: truncate value */
174512ed1c7cSGregory Neil Shapiro 				(void) sm_strlcpyn(obuf, sizeof obuf, 2,
174612ed1c7cSGregory Neil Shapiro 						   h->h_field, ":");
1747567a2fc9SGregory Neil Shapiro 				if (!putline(obuf, mci))
1748567a2fc9SGregory Neil Shapiro 					goto writeerr;
1749c2aa98e2SPeter Wemm 			}
1750c2aa98e2SPeter Wemm 			continue;
1751c2aa98e2SPeter Wemm 		}
1752c2aa98e2SPeter Wemm 
1753c2aa98e2SPeter Wemm 		if (tTd(34, 11))
175412ed1c7cSGregory Neil Shapiro 			sm_dprintf("\n");
1755c2aa98e2SPeter Wemm 
1756c2aa98e2SPeter Wemm 		if (bitset(H_FROM|H_RCPT, h->h_flags))
1757c2aa98e2SPeter Wemm 		{
1758c2aa98e2SPeter Wemm 			/* address field */
1759c2aa98e2SPeter Wemm 			bool oldstyle = bitset(EF_OLDSTYLE, e->e_flags);
1760c2aa98e2SPeter Wemm 
1761c2aa98e2SPeter Wemm 			if (bitset(H_FROM, h->h_flags))
176212ed1c7cSGregory Neil Shapiro 				oldstyle = false;
1763c2aa98e2SPeter Wemm 			commaize(h, p, oldstyle, mci, e);
1764c2aa98e2SPeter Wemm 		}
1765c2aa98e2SPeter Wemm 		else
1766c2aa98e2SPeter Wemm 		{
1767567a2fc9SGregory Neil Shapiro 			if (!put_vanilla_header(h, p, mci))
1768567a2fc9SGregory Neil Shapiro 				goto writeerr;
1769c2aa98e2SPeter Wemm 		}
1770c2aa98e2SPeter Wemm 	}
1771c2aa98e2SPeter Wemm 
1772c2aa98e2SPeter Wemm 	/*
1773c2aa98e2SPeter Wemm 	**  If we are converting this to a MIME message, add the
17743299c2f1SGregory Neil Shapiro 	**  MIME headers (but not in MIME mode!).
1775c2aa98e2SPeter Wemm 	*/
1776c2aa98e2SPeter Wemm 
1777c2aa98e2SPeter Wemm #if MIME8TO7
1778c2aa98e2SPeter Wemm 	if (bitset(MM_MIME8BIT, MimeMode) &&
1779c2aa98e2SPeter Wemm 	    bitset(EF_HAS8BIT, e->e_flags) &&
1780c2aa98e2SPeter Wemm 	    !bitset(EF_DONT_MIME, e->e_flags) &&
1781c2aa98e2SPeter Wemm 	    !bitnset(M_8BITS, mci->mci_mailer->m_flags) &&
17823299c2f1SGregory Neil Shapiro 	    !bitset(MCIF_CVT8TO7|MCIF_CVT7TO8|MCIF_INMIME, mci->mci_flags) &&
17833299c2f1SGregory Neil Shapiro 	    hvalue("MIME-Version", e->e_header) == NULL)
1784c2aa98e2SPeter Wemm 	{
1785567a2fc9SGregory Neil Shapiro 		if (!putline("MIME-Version: 1.0", mci))
1786567a2fc9SGregory Neil Shapiro 			goto writeerr;
1787c2aa98e2SPeter Wemm 		if (hvalue("Content-Type", e->e_header) == NULL)
1788c2aa98e2SPeter Wemm 		{
178912ed1c7cSGregory Neil Shapiro 			(void) sm_snprintf(obuf, sizeof obuf,
1790c2aa98e2SPeter Wemm 					"Content-Type: text/plain; charset=%s",
1791c2aa98e2SPeter Wemm 					defcharset(e));
1792567a2fc9SGregory Neil Shapiro 			if (!putline(obuf, mci))
1793567a2fc9SGregory Neil Shapiro 				goto writeerr;
1794c2aa98e2SPeter Wemm 		}
1795567a2fc9SGregory Neil Shapiro 		if (hvalue("Content-Transfer-Encoding", e->e_header) == NULL
1796567a2fc9SGregory Neil Shapiro 		    && !putline("Content-Transfer-Encoding: 8bit", mci))
1797567a2fc9SGregory Neil Shapiro 			goto writeerr;
1798c2aa98e2SPeter Wemm 	}
17993299c2f1SGregory Neil Shapiro #endif /* MIME8TO7 */
1800567a2fc9SGregory Neil Shapiro 	return true;
1801567a2fc9SGregory Neil Shapiro 
1802567a2fc9SGregory Neil Shapiro   writeerr:
1803567a2fc9SGregory Neil Shapiro 	return false;
1804c2aa98e2SPeter Wemm }
180512ed1c7cSGregory Neil Shapiro /*
1806c2aa98e2SPeter Wemm **  PUT_VANILLA_HEADER -- output a fairly ordinary header
1807c2aa98e2SPeter Wemm **
1808c2aa98e2SPeter Wemm **	Parameters:
1809c2aa98e2SPeter Wemm **		h -- the structure describing this header
1810c2aa98e2SPeter Wemm **		v -- the value of this header
1811c2aa98e2SPeter Wemm **		mci -- the connection info for output
1812c2aa98e2SPeter Wemm **
1813c2aa98e2SPeter Wemm **	Returns:
1814355d91e3SGregory Neil Shapiro **		true iff header was written successfully
1815c2aa98e2SPeter Wemm */
1816c2aa98e2SPeter Wemm 
1817567a2fc9SGregory Neil Shapiro static bool
1818c2aa98e2SPeter Wemm put_vanilla_header(h, v, mci)
1819c2aa98e2SPeter Wemm 	HDR *h;
1820c2aa98e2SPeter Wemm 	char *v;
1821c2aa98e2SPeter Wemm 	MCI *mci;
1822c2aa98e2SPeter Wemm {
1823c2aa98e2SPeter Wemm 	register char *nlp;
1824c2aa98e2SPeter Wemm 	register char *obp;
1825c2aa98e2SPeter Wemm 	int putflags;
1826684b2a5fSGregory Neil Shapiro 	char obuf[MAXLINE + 256];	/* additional length for h_field */
1827c2aa98e2SPeter Wemm 
1828c2aa98e2SPeter Wemm 	putflags = PXLF_HEADER;
1829c2aa98e2SPeter Wemm 	if (bitnset(M_7BITHDRS, mci->mci_mailer->m_flags))
1830c2aa98e2SPeter Wemm 		putflags |= PXLF_STRIP8BIT;
183112ed1c7cSGregory Neil Shapiro 	(void) sm_snprintf(obuf, sizeof obuf, "%.200s: ", h->h_field);
1832c2aa98e2SPeter Wemm 	obp = obuf + strlen(obuf);
1833c2aa98e2SPeter Wemm 	while ((nlp = strchr(v, '\n')) != NULL)
1834c2aa98e2SPeter Wemm 	{
1835c2aa98e2SPeter Wemm 		int l;
1836c2aa98e2SPeter Wemm 
1837c2aa98e2SPeter Wemm 		l = nlp - v;
18387660b554SGregory Neil Shapiro 
18397660b554SGregory Neil Shapiro 		/*
18407660b554SGregory Neil Shapiro 		**  XXX This is broken for SPACELEFT()==0
18417660b554SGregory Neil Shapiro 		**  However, SPACELEFT() is always > 0 unless MAXLINE==1.
18427660b554SGregory Neil Shapiro 		*/
18437660b554SGregory Neil Shapiro 
18443299c2f1SGregory Neil Shapiro 		if (SPACELEFT(obuf, obp) - 1 < (size_t) l)
1845c2aa98e2SPeter Wemm 			l = SPACELEFT(obuf, obp) - 1;
1846c2aa98e2SPeter Wemm 
184712ed1c7cSGregory Neil Shapiro 		(void) sm_snprintf(obp, SPACELEFT(obuf, obp), "%.*s", l, v);
1848567a2fc9SGregory Neil Shapiro 		if (!putxline(obuf, strlen(obuf), mci, putflags))
1849567a2fc9SGregory Neil Shapiro 			goto writeerr;
1850c2aa98e2SPeter Wemm 		v += l + 1;
1851c2aa98e2SPeter Wemm 		obp = obuf;
1852c2aa98e2SPeter Wemm 		if (*v != ' ' && *v != '\t')
1853c2aa98e2SPeter Wemm 			*obp++ = ' ';
1854c2aa98e2SPeter Wemm 	}
18557660b554SGregory Neil Shapiro 
18567660b554SGregory Neil Shapiro 	/* XXX This is broken for SPACELEFT()==0 */
185712ed1c7cSGregory Neil Shapiro 	(void) sm_snprintf(obp, SPACELEFT(obuf, obp), "%.*s",
185812ed1c7cSGregory Neil Shapiro 			   (int) (SPACELEFT(obuf, obp) - 1), v);
1859567a2fc9SGregory Neil Shapiro 	return putxline(obuf, strlen(obuf), mci, putflags);
1860567a2fc9SGregory Neil Shapiro 
1861567a2fc9SGregory Neil Shapiro   writeerr:
1862567a2fc9SGregory Neil Shapiro 	return false;
1863c2aa98e2SPeter Wemm }
186412ed1c7cSGregory Neil Shapiro /*
1865c2aa98e2SPeter Wemm **  COMMAIZE -- output a header field, making a comma-translated list.
1866c2aa98e2SPeter Wemm **
1867c2aa98e2SPeter Wemm **	Parameters:
1868c2aa98e2SPeter Wemm **		h -- the header field to output.
1869c2aa98e2SPeter Wemm **		p -- the value to put in it.
187012ed1c7cSGregory Neil Shapiro **		oldstyle -- true if this is an old style header.
1871c2aa98e2SPeter Wemm **		mci -- the connection information.
1872c2aa98e2SPeter Wemm **		e -- the envelope containing the message.
1873c2aa98e2SPeter Wemm **
1874c2aa98e2SPeter Wemm **	Returns:
1875355d91e3SGregory Neil Shapiro **		true iff header field was written successfully
1876c2aa98e2SPeter Wemm **
1877c2aa98e2SPeter Wemm **	Side Effects:
1878c2aa98e2SPeter Wemm **		outputs "p" to file "fp".
1879c2aa98e2SPeter Wemm */
1880c2aa98e2SPeter Wemm 
1881567a2fc9SGregory Neil Shapiro bool
1882c2aa98e2SPeter Wemm commaize(h, p, oldstyle, mci, e)
1883c2aa98e2SPeter Wemm 	register HDR *h;
1884c2aa98e2SPeter Wemm 	register char *p;
1885c2aa98e2SPeter Wemm 	bool oldstyle;
1886c2aa98e2SPeter Wemm 	register MCI *mci;
1887c2aa98e2SPeter Wemm 	register ENVELOPE *e;
1888c2aa98e2SPeter Wemm {
1889c2aa98e2SPeter Wemm 	register char *obp;
1890c2aa98e2SPeter Wemm 	int opos;
1891c2aa98e2SPeter Wemm 	int omax;
189212ed1c7cSGregory Neil Shapiro 	bool firstone = true;
1893c2aa98e2SPeter Wemm 	int putflags = PXLF_HEADER;
18947660b554SGregory Neil Shapiro 	char **res;
1895c2aa98e2SPeter Wemm 	char obuf[MAXLINE + 3];
1896c2aa98e2SPeter Wemm 
1897c2aa98e2SPeter Wemm 	/*
1898c2aa98e2SPeter Wemm 	**  Output the address list translated by the
1899c2aa98e2SPeter Wemm 	**  mailer and with commas.
1900c2aa98e2SPeter Wemm 	*/
1901c2aa98e2SPeter Wemm 
1902c2aa98e2SPeter Wemm 	if (tTd(14, 2))
190312ed1c7cSGregory Neil Shapiro 		sm_dprintf("commaize(%s: %s)\n", h->h_field, p);
1904c2aa98e2SPeter Wemm 
1905c2aa98e2SPeter Wemm 	if (bitnset(M_7BITHDRS, mci->mci_mailer->m_flags))
1906c2aa98e2SPeter Wemm 		putflags |= PXLF_STRIP8BIT;
1907c2aa98e2SPeter Wemm 
1908c2aa98e2SPeter Wemm 	obp = obuf;
190912ed1c7cSGregory Neil Shapiro 	(void) sm_snprintf(obp, SPACELEFT(obuf, obp), "%.200s: ",
191012ed1c7cSGregory Neil Shapiro 			h->h_field);
19117660b554SGregory Neil Shapiro 
19127660b554SGregory Neil Shapiro 	/* opos = strlen(obp); */
1913c2aa98e2SPeter Wemm 	opos = strlen(h->h_field) + 2;
1914c2aa98e2SPeter Wemm 	if (opos > 202)
1915c2aa98e2SPeter Wemm 		opos = 202;
1916c2aa98e2SPeter Wemm 	obp += opos;
1917c2aa98e2SPeter Wemm 	omax = mci->mci_mailer->m_linelimit - 2;
1918c2aa98e2SPeter Wemm 	if (omax < 0 || omax > 78)
1919c2aa98e2SPeter Wemm 		omax = 78;
1920c2aa98e2SPeter Wemm 
1921c2aa98e2SPeter Wemm 	/*
1922c2aa98e2SPeter Wemm 	**  Run through the list of values.
1923c2aa98e2SPeter Wemm 	*/
1924c2aa98e2SPeter Wemm 
1925c2aa98e2SPeter Wemm 	while (*p != '\0')
1926c2aa98e2SPeter Wemm 	{
1927c2aa98e2SPeter Wemm 		register char *name;
1928c2aa98e2SPeter Wemm 		register int c;
1929c2aa98e2SPeter Wemm 		char savechar;
1930c2aa98e2SPeter Wemm 		int flags;
19313299c2f1SGregory Neil Shapiro 		auto int status;
1932c2aa98e2SPeter Wemm 
1933c2aa98e2SPeter Wemm 		/*
1934c2aa98e2SPeter Wemm 		**  Find the end of the name.  New style names
1935c2aa98e2SPeter Wemm 		**  end with a comma, old style names end with
1936c2aa98e2SPeter Wemm 		**  a space character.  However, spaces do not
1937c2aa98e2SPeter Wemm 		**  necessarily delimit an old-style name -- at
1938c2aa98e2SPeter Wemm 		**  signs mean keep going.
1939c2aa98e2SPeter Wemm 		*/
1940c2aa98e2SPeter Wemm 
1941c2aa98e2SPeter Wemm 		/* find end of name */
1942c2aa98e2SPeter Wemm 		while ((isascii(*p) && isspace(*p)) || *p == ',')
1943c2aa98e2SPeter Wemm 			p++;
1944c2aa98e2SPeter Wemm 		name = p;
19457660b554SGregory Neil Shapiro 		res = NULL;
1946c2aa98e2SPeter Wemm 		for (;;)
1947c2aa98e2SPeter Wemm 		{
1948c2aa98e2SPeter Wemm 			auto char *oldp;
1949c2aa98e2SPeter Wemm 			char pvpbuf[PSBUFSIZE];
1950c2aa98e2SPeter Wemm 
19517660b554SGregory Neil Shapiro 			res = prescan(p, oldstyle ? ' ' : ',', pvpbuf,
1952bfb62e91SGregory Neil Shapiro 				      sizeof pvpbuf, &oldp, NULL, false);
1953c2aa98e2SPeter Wemm 			p = oldp;
19547660b554SGregory Neil Shapiro #if _FFR_IGNORE_BOGUS_ADDR
19557660b554SGregory Neil Shapiro 			/* ignore addresses that can't be parsed */
19567660b554SGregory Neil Shapiro 			if (res == NULL)
19577660b554SGregory Neil Shapiro 			{
19587660b554SGregory Neil Shapiro 				name = p;
19597660b554SGregory Neil Shapiro 				continue;
19607660b554SGregory Neil Shapiro 			}
19617660b554SGregory Neil Shapiro #endif /* _FFR_IGNORE_BOGUS_ADDR */
1962c2aa98e2SPeter Wemm 
1963c2aa98e2SPeter Wemm 			/* look to see if we have an at sign */
1964c2aa98e2SPeter Wemm 			while (*p != '\0' && isascii(*p) && isspace(*p))
1965c2aa98e2SPeter Wemm 				p++;
1966c2aa98e2SPeter Wemm 
1967c2aa98e2SPeter Wemm 			if (*p != '@')
1968c2aa98e2SPeter Wemm 			{
1969c2aa98e2SPeter Wemm 				p = oldp;
1970c2aa98e2SPeter Wemm 				break;
1971c2aa98e2SPeter Wemm 			}
197212ed1c7cSGregory Neil Shapiro 			++p;
1973c2aa98e2SPeter Wemm 			while (*p != '\0' && isascii(*p) && isspace(*p))
1974c2aa98e2SPeter Wemm 				p++;
1975c2aa98e2SPeter Wemm 		}
1976c2aa98e2SPeter Wemm 		/* at the end of one complete name */
1977c2aa98e2SPeter Wemm 
1978c2aa98e2SPeter Wemm 		/* strip off trailing white space */
1979c2aa98e2SPeter Wemm 		while (p >= name &&
1980c2aa98e2SPeter Wemm 		       ((isascii(*p) && isspace(*p)) || *p == ',' || *p == '\0'))
1981c2aa98e2SPeter Wemm 			p--;
1982c2aa98e2SPeter Wemm 		if (++p == name)
1983c2aa98e2SPeter Wemm 			continue;
19847660b554SGregory Neil Shapiro 
19857660b554SGregory Neil Shapiro 		/*
19867660b554SGregory Neil Shapiro 		**  if prescan() failed go a bit backwards; this is a hack,
19877660b554SGregory Neil Shapiro 		**  there should be some better error recovery.
19887660b554SGregory Neil Shapiro 		*/
19897660b554SGregory Neil Shapiro 
19907660b554SGregory Neil Shapiro 		if (res == NULL && p > name &&
19917660b554SGregory Neil Shapiro 		    !((isascii(*p) && isspace(*p)) || *p == ',' || *p == '\0'))
19927660b554SGregory Neil Shapiro 			--p;
1993c2aa98e2SPeter Wemm 		savechar = *p;
1994c2aa98e2SPeter Wemm 		*p = '\0';
1995c2aa98e2SPeter Wemm 
1996c2aa98e2SPeter Wemm 		/* translate the name to be relative */
1997c2aa98e2SPeter Wemm 		flags = RF_HEADERADDR|RF_ADDDOMAIN;
1998c2aa98e2SPeter Wemm 		if (bitset(H_FROM, h->h_flags))
1999c2aa98e2SPeter Wemm 			flags |= RF_SENDERADDR;
2000c2aa98e2SPeter Wemm #if USERDB
2001c2aa98e2SPeter Wemm 		else if (e->e_from.q_mailer != NULL &&
2002c2aa98e2SPeter Wemm 			 bitnset(M_UDBRECIPIENT, e->e_from.q_mailer->m_flags))
2003c2aa98e2SPeter Wemm 		{
2004c2aa98e2SPeter Wemm 			char *q;
2005c2aa98e2SPeter Wemm 
200612ed1c7cSGregory Neil Shapiro 			q = udbsender(name, e->e_rpool);
2007c2aa98e2SPeter Wemm 			if (q != NULL)
2008c2aa98e2SPeter Wemm 				name = q;
2009c2aa98e2SPeter Wemm 		}
20103299c2f1SGregory Neil Shapiro #endif /* USERDB */
20113299c2f1SGregory Neil Shapiro 		status = EX_OK;
20123299c2f1SGregory Neil Shapiro 		name = remotename(name, mci->mci_mailer, flags, &status, e);
2013c2aa98e2SPeter Wemm 		if (*name == '\0')
2014c2aa98e2SPeter Wemm 		{
2015c2aa98e2SPeter Wemm 			*p = savechar;
2016c2aa98e2SPeter Wemm 			continue;
2017c2aa98e2SPeter Wemm 		}
201812ed1c7cSGregory Neil Shapiro 		name = denlstring(name, false, true);
2019c2aa98e2SPeter Wemm 
2020c2aa98e2SPeter Wemm 		/* output the name with nice formatting */
2021c2aa98e2SPeter Wemm 		opos += strlen(name);
2022c2aa98e2SPeter Wemm 		if (!firstone)
2023c2aa98e2SPeter Wemm 			opos += 2;
2024c2aa98e2SPeter Wemm 		if (opos > omax && !firstone)
2025c2aa98e2SPeter Wemm 		{
202612ed1c7cSGregory Neil Shapiro 			(void) sm_strlcpy(obp, ",\n", SPACELEFT(obuf, obp));
2027567a2fc9SGregory Neil Shapiro 			if (!putxline(obuf, strlen(obuf), mci, putflags))
2028567a2fc9SGregory Neil Shapiro 				goto writeerr;
2029c2aa98e2SPeter Wemm 			obp = obuf;
20307660b554SGregory Neil Shapiro 			(void) sm_strlcpy(obp, "        ", sizeof obuf);
2031c2aa98e2SPeter Wemm 			opos = strlen(obp);
2032c2aa98e2SPeter Wemm 			obp += opos;
2033c2aa98e2SPeter Wemm 			opos += strlen(name);
2034c2aa98e2SPeter Wemm 		}
2035c2aa98e2SPeter Wemm 		else if (!firstone)
2036c2aa98e2SPeter Wemm 		{
203712ed1c7cSGregory Neil Shapiro 			(void) sm_strlcpy(obp, ", ", SPACELEFT(obuf, obp));
2038c2aa98e2SPeter Wemm 			obp += 2;
2039c2aa98e2SPeter Wemm 		}
2040c2aa98e2SPeter Wemm 
2041c2aa98e2SPeter Wemm 		while ((c = *name++) != '\0' && obp < &obuf[MAXLINE])
2042c2aa98e2SPeter Wemm 			*obp++ = c;
204312ed1c7cSGregory Neil Shapiro 		firstone = false;
2044c2aa98e2SPeter Wemm 		*p = savechar;
2045c2aa98e2SPeter Wemm 	}
20467660b554SGregory Neil Shapiro 	if (obp < &obuf[sizeof obuf])
2047c2aa98e2SPeter Wemm 		*obp = '\0';
20487660b554SGregory Neil Shapiro 	else
20497660b554SGregory Neil Shapiro 		obuf[sizeof obuf - 1] = '\0';
2050567a2fc9SGregory Neil Shapiro 	return putxline(obuf, strlen(obuf), mci, putflags);
2051567a2fc9SGregory Neil Shapiro 
2052567a2fc9SGregory Neil Shapiro   writeerr:
2053567a2fc9SGregory Neil Shapiro 	return false;
2054c2aa98e2SPeter Wemm }
2055567a2fc9SGregory Neil Shapiro 
205612ed1c7cSGregory Neil Shapiro /*
2057c2aa98e2SPeter Wemm **  COPYHEADER -- copy header list
2058c2aa98e2SPeter Wemm **
2059c2aa98e2SPeter Wemm **	This routine is the equivalent of newstr for header lists
2060c2aa98e2SPeter Wemm **
2061c2aa98e2SPeter Wemm **	Parameters:
2062c2aa98e2SPeter Wemm **		header -- list of header structures to copy.
206312ed1c7cSGregory Neil Shapiro **		rpool -- resource pool, or NULL
2064c2aa98e2SPeter Wemm **
2065c2aa98e2SPeter Wemm **	Returns:
2066c2aa98e2SPeter Wemm **		a copy of 'header'.
2067c2aa98e2SPeter Wemm **
2068c2aa98e2SPeter Wemm **	Side Effects:
2069c2aa98e2SPeter Wemm **		none.
2070c2aa98e2SPeter Wemm */
2071c2aa98e2SPeter Wemm 
2072c2aa98e2SPeter Wemm HDR *
207312ed1c7cSGregory Neil Shapiro copyheader(header, rpool)
2074c2aa98e2SPeter Wemm 	register HDR *header;
207512ed1c7cSGregory Neil Shapiro 	SM_RPOOL_T *rpool;
2076c2aa98e2SPeter Wemm {
2077c2aa98e2SPeter Wemm 	register HDR *newhdr;
2078c2aa98e2SPeter Wemm 	HDR *ret;
2079c2aa98e2SPeter Wemm 	register HDR **tail = &ret;
2080c2aa98e2SPeter Wemm 
2081c2aa98e2SPeter Wemm 	while (header != NULL)
2082c2aa98e2SPeter Wemm 	{
208312ed1c7cSGregory Neil Shapiro 		newhdr = (HDR *) sm_rpool_malloc_x(rpool, sizeof *newhdr);
2084c2aa98e2SPeter Wemm 		STRUCTCOPY(*header, *newhdr);
2085c2aa98e2SPeter Wemm 		*tail = newhdr;
2086c2aa98e2SPeter Wemm 		tail = &newhdr->h_link;
2087c2aa98e2SPeter Wemm 		header = header->h_link;
2088c2aa98e2SPeter Wemm 	}
2089c2aa98e2SPeter Wemm 	*tail = NULL;
2090c2aa98e2SPeter Wemm 
2091c2aa98e2SPeter Wemm 	return ret;
2092c2aa98e2SPeter Wemm }
209312ed1c7cSGregory Neil Shapiro /*
209476b7bf71SPeter Wemm **  FIX_MIME_HEADER -- possibly truncate/rebalance parameters in a MIME header
209576b7bf71SPeter Wemm **
209676b7bf71SPeter Wemm **	Run through all of the parameters of a MIME header and
209776b7bf71SPeter Wemm **	possibly truncate and rebalance the parameter according
209876b7bf71SPeter Wemm **	to MaxMimeFieldLength.
209976b7bf71SPeter Wemm **
210076b7bf71SPeter Wemm **	Parameters:
2101f9218d3dSGregory Neil Shapiro **		h -- the header to truncate/rebalance
2102f9218d3dSGregory Neil Shapiro **		e -- the current envelope
210376b7bf71SPeter Wemm **
210476b7bf71SPeter Wemm **	Returns:
2105c46d91b7SGregory Neil Shapiro **		length of last offending field, 0 if all ok.
210676b7bf71SPeter Wemm **
210776b7bf71SPeter Wemm **	Side Effects:
210876b7bf71SPeter Wemm **		string modified in place
210976b7bf71SPeter Wemm */
211076b7bf71SPeter Wemm 
2111c46d91b7SGregory Neil Shapiro static size_t
2112f9218d3dSGregory Neil Shapiro fix_mime_header(h, e)
2113f9218d3dSGregory Neil Shapiro 	HDR *h;
2114f9218d3dSGregory Neil Shapiro 	ENVELOPE *e;
211576b7bf71SPeter Wemm {
2116f9218d3dSGregory Neil Shapiro 	char *begin = h->h_value;
211776b7bf71SPeter Wemm 	char *end;
2118c46d91b7SGregory Neil Shapiro 	size_t len = 0;
2119c46d91b7SGregory Neil Shapiro 	size_t retlen = 0;
212076b7bf71SPeter Wemm 
2121f9218d3dSGregory Neil Shapiro 	if (begin == NULL || *begin == '\0')
2122c46d91b7SGregory Neil Shapiro 		return 0;
212376b7bf71SPeter Wemm 
212476b7bf71SPeter Wemm 	/* Split on each ';' */
21257660b554SGregory Neil Shapiro 	/* find_character() never returns NULL */
212676b7bf71SPeter Wemm 	while ((end = find_character(begin, ';')) != NULL)
212776b7bf71SPeter Wemm 	{
212876b7bf71SPeter Wemm 		char save = *end;
212976b7bf71SPeter Wemm 		char *bp;
213076b7bf71SPeter Wemm 
213176b7bf71SPeter Wemm 		*end = '\0';
213276b7bf71SPeter Wemm 
2133c46d91b7SGregory Neil Shapiro 		len = strlen(begin);
2134c46d91b7SGregory Neil Shapiro 
213576b7bf71SPeter Wemm 		/* Shorten individual parameter */
213676b7bf71SPeter Wemm 		if (shorten_rfc822_string(begin, MaxMimeFieldLength))
2137f9218d3dSGregory Neil Shapiro 		{
2138f9218d3dSGregory Neil Shapiro 			if (len < MaxMimeFieldLength)
2139f9218d3dSGregory Neil Shapiro 			{
2140f9218d3dSGregory Neil Shapiro 				/* we only rebalanced a bogus field */
2141f9218d3dSGregory Neil Shapiro 				sm_syslog(LOG_ALERT, e->e_id,
2142f9218d3dSGregory Neil Shapiro 					  "Fixed MIME %s header field (possible attack)",
2143f9218d3dSGregory Neil Shapiro 					  h->h_field);
2144f9218d3dSGregory Neil Shapiro 				if (tTd(34, 11))
2145f9218d3dSGregory Neil Shapiro 					sm_dprintf("  fixed MIME %s header field (possible attack)\n",
2146f9218d3dSGregory Neil Shapiro 						   h->h_field);
2147f9218d3dSGregory Neil Shapiro 			}
2148f9218d3dSGregory Neil Shapiro 			else
2149f9218d3dSGregory Neil Shapiro 			{
2150f9218d3dSGregory Neil Shapiro 				/* we actually shortened the header */
2151c46d91b7SGregory Neil Shapiro 				retlen = len;
2152f9218d3dSGregory Neil Shapiro 			}
2153f9218d3dSGregory Neil Shapiro 		}
215476b7bf71SPeter Wemm 
215576b7bf71SPeter Wemm 		/* Collapse the possibly shortened string with rest */
215676b7bf71SPeter Wemm 		bp = begin + strlen(begin);
215776b7bf71SPeter Wemm 		if (bp != end)
215876b7bf71SPeter Wemm 		{
215976b7bf71SPeter Wemm 			char *ep = end;
216076b7bf71SPeter Wemm 
216176b7bf71SPeter Wemm 			*end = save;
216276b7bf71SPeter Wemm 			end = bp;
216376b7bf71SPeter Wemm 
216476b7bf71SPeter Wemm 			/* copy character by character due to overlap */
216576b7bf71SPeter Wemm 			while (*ep != '\0')
216676b7bf71SPeter Wemm 				*bp++ = *ep++;
216776b7bf71SPeter Wemm 			*bp = '\0';
216876b7bf71SPeter Wemm 		}
216976b7bf71SPeter Wemm 		else
217076b7bf71SPeter Wemm 			*end = save;
217176b7bf71SPeter Wemm 		if (*end == '\0')
217276b7bf71SPeter Wemm 			break;
217376b7bf71SPeter Wemm 
217476b7bf71SPeter Wemm 		/* Move past ';' */
217576b7bf71SPeter Wemm 		begin = end + 1;
217676b7bf71SPeter Wemm 	}
2177c46d91b7SGregory Neil Shapiro 	return retlen;
217876b7bf71SPeter Wemm }
2179