xref: /freebsd/contrib/sendmail/src/headers.c (revision f9218d3d4fd34f082473b3a021c6d4d109fb47cf)
1c2aa98e2SPeter Wemm /*
2f9218d3dSGregory Neil Shapiro  * Copyright (c) 1998-2003 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  *
12c2aa98e2SPeter Wemm  */
13c2aa98e2SPeter Wemm 
1412ed1c7cSGregory Neil Shapiro #include <sendmail.h>
15c2aa98e2SPeter Wemm 
16f9218d3dSGregory Neil Shapiro SM_RCSID("@(#)$Id: headers.c,v 8.266.4.4 2003/01/18 00:41:48 gshapiro Exp $")
173299c2f1SGregory Neil Shapiro 
18f9218d3dSGregory Neil Shapiro static size_t	fix_mime_header __P((HDR *, ENVELOPE *));
193299c2f1SGregory Neil Shapiro static int	priencode __P((char *));
203299c2f1SGregory Neil Shapiro static void	put_vanilla_header __P((HDR *, char *, MCI *));
21c2aa98e2SPeter Wemm 
22c2aa98e2SPeter Wemm /*
23c2aa98e2SPeter Wemm **  SETUPHEADERS -- initialize headers in symbol table
24c2aa98e2SPeter Wemm **
25c2aa98e2SPeter Wemm **	Parameters:
26c2aa98e2SPeter Wemm **		none
27c2aa98e2SPeter Wemm **
28c2aa98e2SPeter Wemm **	Returns:
29c2aa98e2SPeter Wemm **		none
30c2aa98e2SPeter Wemm */
31c2aa98e2SPeter Wemm 
32c2aa98e2SPeter Wemm void
33c2aa98e2SPeter Wemm setupheaders()
34c2aa98e2SPeter Wemm {
35c2aa98e2SPeter Wemm 	struct hdrinfo *hi;
36c2aa98e2SPeter Wemm 	STAB *s;
37c2aa98e2SPeter Wemm 
38c2aa98e2SPeter Wemm 	for (hi = HdrInfo; hi->hi_field != NULL; hi++)
39c2aa98e2SPeter Wemm 	{
40c2aa98e2SPeter Wemm 		s = stab(hi->hi_field, ST_HEADER, ST_ENTER);
41c2aa98e2SPeter Wemm 		s->s_header.hi_flags = hi->hi_flags;
42c2aa98e2SPeter Wemm 		s->s_header.hi_ruleset = NULL;
43c2aa98e2SPeter Wemm 	}
44c2aa98e2SPeter Wemm }
4512ed1c7cSGregory Neil Shapiro /*
46c2aa98e2SPeter Wemm **  CHOMPHEADER -- process and save a header line.
47c2aa98e2SPeter Wemm **
483299c2f1SGregory Neil Shapiro **	Called by collect, readcf, and readqf to deal with header lines.
49c2aa98e2SPeter Wemm **
50c2aa98e2SPeter Wemm **	Parameters:
51c2aa98e2SPeter Wemm **		line -- header as a text line.
52d995d2baSGregory Neil Shapiro **		pflag -- flags for chompheader() (from sendmail.h)
53c2aa98e2SPeter Wemm **		hdrp -- a pointer to the place to save the header.
54c2aa98e2SPeter Wemm **		e -- the envelope including this header.
55c2aa98e2SPeter Wemm **
56c2aa98e2SPeter Wemm **	Returns:
57c2aa98e2SPeter Wemm **		flags for this header.
58c2aa98e2SPeter Wemm **
59c2aa98e2SPeter Wemm **	Side Effects:
60c2aa98e2SPeter Wemm **		The header is saved on the header list.
61c2aa98e2SPeter Wemm **		Contents of 'line' are destroyed.
62c2aa98e2SPeter Wemm */
63c2aa98e2SPeter Wemm 
643299c2f1SGregory Neil Shapiro static struct hdrinfo	NormalHeader =	{ NULL, 0, NULL };
65c2aa98e2SPeter Wemm 
6612ed1c7cSGregory Neil Shapiro unsigned long
673299c2f1SGregory Neil Shapiro chompheader(line, pflag, hdrp, e)
68c2aa98e2SPeter Wemm 	char *line;
693299c2f1SGregory Neil Shapiro 	int pflag;
70c2aa98e2SPeter Wemm 	HDR **hdrp;
71c2aa98e2SPeter Wemm 	register ENVELOPE *e;
72c2aa98e2SPeter Wemm {
7312ed1c7cSGregory Neil Shapiro 	unsigned char mid = '\0';
74c2aa98e2SPeter Wemm 	register char *p;
75c2aa98e2SPeter Wemm 	register HDR *h;
76c2aa98e2SPeter Wemm 	HDR **hp;
77c2aa98e2SPeter Wemm 	char *fname;
78c2aa98e2SPeter Wemm 	char *fvalue;
7912ed1c7cSGregory Neil Shapiro 	bool cond = false;
803299c2f1SGregory Neil Shapiro 	bool dropfrom;
81c2aa98e2SPeter Wemm 	bool headeronly;
82c2aa98e2SPeter Wemm 	STAB *s;
83c2aa98e2SPeter Wemm 	struct hdrinfo *hi;
8412ed1c7cSGregory Neil Shapiro 	bool nullheader = false;
853299c2f1SGregory Neil Shapiro 	BITMAP256 mopts;
86c2aa98e2SPeter Wemm 
87c2aa98e2SPeter Wemm 	if (tTd(31, 6))
88c2aa98e2SPeter Wemm 	{
8912ed1c7cSGregory Neil Shapiro 		sm_dprintf("chompheader: ");
90c2aa98e2SPeter Wemm 		xputs(line);
9112ed1c7cSGregory Neil Shapiro 		sm_dprintf("\n");
92c2aa98e2SPeter Wemm 	}
93c2aa98e2SPeter Wemm 
94c2aa98e2SPeter Wemm 	headeronly = hdrp != NULL;
95c2aa98e2SPeter Wemm 	if (!headeronly)
96c2aa98e2SPeter Wemm 		hdrp = &e->e_header;
97c2aa98e2SPeter Wemm 
98c2aa98e2SPeter Wemm 	/* strip off options */
99c2aa98e2SPeter Wemm 	clrbitmap(mopts);
100c2aa98e2SPeter Wemm 	p = line;
1013299c2f1SGregory Neil Shapiro 	if (!bitset(pflag, CHHDR_USER) && *p == '?')
102c2aa98e2SPeter Wemm 	{
1033299c2f1SGregory Neil Shapiro 		int c;
1043299c2f1SGregory Neil Shapiro 		register char *q;
105c2aa98e2SPeter Wemm 
1063299c2f1SGregory Neil Shapiro 		q = strchr(++p, '?');
1073299c2f1SGregory Neil Shapiro 		if (q == NULL)
1083299c2f1SGregory Neil Shapiro 			goto hse;
1093299c2f1SGregory Neil Shapiro 
1103299c2f1SGregory Neil Shapiro 		*q = '\0';
1113299c2f1SGregory Neil Shapiro 		c = *p & 0377;
1123299c2f1SGregory Neil Shapiro 
1133299c2f1SGregory Neil Shapiro 		/* possibly macro conditional */
1143299c2f1SGregory Neil Shapiro 		if (c == MACROEXPAND)
115c2aa98e2SPeter Wemm 		{
1163299c2f1SGregory Neil Shapiro 			/* catch ?$? */
1173299c2f1SGregory Neil Shapiro 			if (*++p == '\0')
1183299c2f1SGregory Neil Shapiro 			{
1193299c2f1SGregory Neil Shapiro 				*q = '?';
1203299c2f1SGregory Neil Shapiro 				goto hse;
1213299c2f1SGregory Neil Shapiro 			}
1223299c2f1SGregory Neil Shapiro 
12312ed1c7cSGregory Neil Shapiro 			mid = (unsigned char) *p++;
1243299c2f1SGregory Neil Shapiro 
1253299c2f1SGregory Neil Shapiro 			/* catch ?$abc? */
1263299c2f1SGregory Neil Shapiro 			if (*p != '\0')
1273299c2f1SGregory Neil Shapiro 			{
1283299c2f1SGregory Neil Shapiro 				*q = '?';
1293299c2f1SGregory Neil Shapiro 				goto hse;
1303299c2f1SGregory Neil Shapiro 			}
1313299c2f1SGregory Neil Shapiro 		}
1323299c2f1SGregory Neil Shapiro 		else if (*p == '$')
1333299c2f1SGregory Neil Shapiro 		{
1343299c2f1SGregory Neil Shapiro 			/* catch ?$? */
1353299c2f1SGregory Neil Shapiro 			if (*++p == '\0')
1363299c2f1SGregory Neil Shapiro 			{
1373299c2f1SGregory Neil Shapiro 				*q = '?';
1383299c2f1SGregory Neil Shapiro 				goto hse;
1393299c2f1SGregory Neil Shapiro 			}
1403299c2f1SGregory Neil Shapiro 
14112ed1c7cSGregory Neil Shapiro 			mid = (unsigned char) macid(p);
1423299c2f1SGregory Neil Shapiro 			if (bitset(0200, mid))
1433299c2f1SGregory Neil Shapiro 				p += strlen(macname(mid)) + 2;
1443299c2f1SGregory Neil Shapiro 			else
1453299c2f1SGregory Neil Shapiro 				p++;
1463299c2f1SGregory Neil Shapiro 
1473299c2f1SGregory Neil Shapiro 			/* catch ?$abc? */
1483299c2f1SGregory Neil Shapiro 			if (*p != '\0')
1493299c2f1SGregory Neil Shapiro 			{
1503299c2f1SGregory Neil Shapiro 				*q = '?';
1513299c2f1SGregory Neil Shapiro 				goto hse;
1523299c2f1SGregory Neil Shapiro 			}
153c2aa98e2SPeter Wemm 		}
154c2aa98e2SPeter Wemm 		else
1553299c2f1SGregory Neil Shapiro 		{
1563299c2f1SGregory Neil Shapiro 			while (*p != '\0')
1573299c2f1SGregory Neil Shapiro 			{
1583299c2f1SGregory Neil Shapiro 				if (!isascii(*p))
1593299c2f1SGregory Neil Shapiro 				{
1603299c2f1SGregory Neil Shapiro 					*q = '?';
1613299c2f1SGregory Neil Shapiro 					goto hse;
1623299c2f1SGregory Neil Shapiro 				}
1633299c2f1SGregory Neil Shapiro 
164c46d91b7SGregory Neil Shapiro 				setbitn(bitidx(*p), mopts);
16512ed1c7cSGregory Neil Shapiro 				cond = true;
1663299c2f1SGregory Neil Shapiro 				p++;
1673299c2f1SGregory Neil Shapiro 			}
1683299c2f1SGregory Neil Shapiro 		}
1693299c2f1SGregory Neil Shapiro 		p = q + 1;
170c2aa98e2SPeter Wemm 	}
171c2aa98e2SPeter Wemm 
172c2aa98e2SPeter Wemm 	/* find canonical name */
173c2aa98e2SPeter Wemm 	fname = p;
174c2aa98e2SPeter Wemm 	while (isascii(*p) && isgraph(*p) && *p != ':')
175c2aa98e2SPeter Wemm 		p++;
176c2aa98e2SPeter Wemm 	fvalue = p;
177c2aa98e2SPeter Wemm 	while (isascii(*p) && isspace(*p))
178c2aa98e2SPeter Wemm 		p++;
179c2aa98e2SPeter Wemm 	if (*p++ != ':' || fname == fvalue)
180c2aa98e2SPeter Wemm 	{
1813299c2f1SGregory Neil Shapiro hse:
1823299c2f1SGregory Neil Shapiro 		syserr("553 5.3.0 header syntax error, line \"%s\"", line);
183c2aa98e2SPeter Wemm 		return 0;
184c2aa98e2SPeter Wemm 	}
185c2aa98e2SPeter Wemm 	*fvalue = '\0';
186c2aa98e2SPeter Wemm 
187c2aa98e2SPeter Wemm 	/* strip field value on front */
188e01d6f61SPeter Wemm 	if (*p == ' ')
189e01d6f61SPeter Wemm 		p++;
190e01d6f61SPeter Wemm 	fvalue = p;
191e01d6f61SPeter Wemm 
192e01d6f61SPeter Wemm 	/* if the field is null, go ahead and use the default */
193e01d6f61SPeter Wemm 	while (isascii(*p) && isspace(*p))
194e01d6f61SPeter Wemm 		p++;
195e01d6f61SPeter Wemm 	if (*p == '\0')
19612ed1c7cSGregory Neil Shapiro 		nullheader = true;
197c2aa98e2SPeter Wemm 
198c2aa98e2SPeter Wemm 	/* security scan: long field names are end-of-header */
199c2aa98e2SPeter Wemm 	if (strlen(fname) > 100)
200c2aa98e2SPeter Wemm 		return H_EOH;
201c2aa98e2SPeter Wemm 
202c2aa98e2SPeter Wemm 	/* check to see if it represents a ruleset call */
2033299c2f1SGregory Neil Shapiro 	if (bitset(pflag, CHHDR_DEF))
204c2aa98e2SPeter Wemm 	{
205c2aa98e2SPeter Wemm 		char hbuf[50];
206c2aa98e2SPeter Wemm 
207c2aa98e2SPeter Wemm 		(void) expand(fvalue, hbuf, sizeof hbuf, e);
208c2aa98e2SPeter Wemm 		for (p = hbuf; isascii(*p) && isspace(*p); )
209c2aa98e2SPeter Wemm 			p++;
210c2aa98e2SPeter Wemm 		if ((*p++ & 0377) == CALLSUBR)
211c2aa98e2SPeter Wemm 		{
212c2aa98e2SPeter Wemm 			auto char *endp;
2133299c2f1SGregory Neil Shapiro 			bool strc;
214c2aa98e2SPeter Wemm 
2153299c2f1SGregory Neil Shapiro 			strc = *p == '+';	/* strip comments? */
2163299c2f1SGregory Neil Shapiro 			if (strc)
2173299c2f1SGregory Neil Shapiro 				++p;
218c2aa98e2SPeter Wemm 			if (strtorwset(p, &endp, ST_ENTER) > 0)
219c2aa98e2SPeter Wemm 			{
220c2aa98e2SPeter Wemm 				*endp = '\0';
221c2aa98e2SPeter Wemm 				s = stab(fname, ST_HEADER, ST_ENTER);
22212ed1c7cSGregory Neil Shapiro 				if (LogLevel > 9 &&
22312ed1c7cSGregory Neil Shapiro 				    s->s_header.hi_ruleset != NULL)
22412ed1c7cSGregory Neil Shapiro 					sm_syslog(LOG_WARNING, NOQID,
22512ed1c7cSGregory Neil Shapiro 						  "Warning: redefined ruleset for header=%s, old=%s, new=%s",
22612ed1c7cSGregory Neil Shapiro 						  fname,
22712ed1c7cSGregory Neil Shapiro 						  s->s_header.hi_ruleset, p);
228c2aa98e2SPeter Wemm 				s->s_header.hi_ruleset = newstr(p);
2293299c2f1SGregory Neil Shapiro 				if (!strc)
2303299c2f1SGregory Neil Shapiro 					s->s_header.hi_flags |= H_STRIPCOMM;
231c2aa98e2SPeter Wemm 			}
232c2aa98e2SPeter Wemm 			return 0;
233c2aa98e2SPeter Wemm 		}
234c2aa98e2SPeter Wemm 	}
235c2aa98e2SPeter Wemm 
236c2aa98e2SPeter Wemm 	/* see if it is a known type */
237c2aa98e2SPeter Wemm 	s = stab(fname, ST_HEADER, ST_FIND);
238c2aa98e2SPeter Wemm 	if (s != NULL)
239c2aa98e2SPeter Wemm 		hi = &s->s_header;
240c2aa98e2SPeter Wemm 	else
241c2aa98e2SPeter Wemm 		hi = &NormalHeader;
242c2aa98e2SPeter Wemm 
243c2aa98e2SPeter Wemm 	if (tTd(31, 9))
244c2aa98e2SPeter Wemm 	{
245c2aa98e2SPeter Wemm 		if (s == NULL)
24612ed1c7cSGregory Neil Shapiro 			sm_dprintf("no header flags match\n");
247c2aa98e2SPeter Wemm 		else
24812ed1c7cSGregory Neil Shapiro 			sm_dprintf("header match, flags=%lx, ruleset=%s\n",
249c2aa98e2SPeter Wemm 				   hi->hi_flags,
25012ed1c7cSGregory Neil Shapiro 				   hi->hi_ruleset == NULL ? "<NULL>"
25112ed1c7cSGregory Neil Shapiro 							  : hi->hi_ruleset);
252c2aa98e2SPeter Wemm 	}
253c2aa98e2SPeter Wemm 
254c2aa98e2SPeter Wemm 	/* see if this is a resent message */
2553299c2f1SGregory Neil Shapiro 	if (!bitset(pflag, CHHDR_DEF) && !headeronly &&
2563299c2f1SGregory Neil Shapiro 	    bitset(H_RESENT, hi->hi_flags))
257c2aa98e2SPeter Wemm 		e->e_flags |= EF_RESENT;
258c2aa98e2SPeter Wemm 
259c2aa98e2SPeter Wemm 	/* if this is an Errors-To: header keep track of it now */
2603299c2f1SGregory Neil Shapiro 	if (UseErrorsTo && !bitset(pflag, CHHDR_DEF) && !headeronly &&
261c2aa98e2SPeter Wemm 	    bitset(H_ERRORSTO, hi->hi_flags))
262c2aa98e2SPeter Wemm 		(void) sendtolist(fvalue, NULLADDR, &e->e_errorqueue, 0, e);
263c2aa98e2SPeter Wemm 
264c2aa98e2SPeter Wemm 	/* if this means "end of header" quit now */
265c2aa98e2SPeter Wemm 	if (!headeronly && bitset(H_EOH, hi->hi_flags))
266c2aa98e2SPeter Wemm 		return hi->hi_flags;
267c2aa98e2SPeter Wemm 
268c2aa98e2SPeter Wemm 	/*
269c2aa98e2SPeter Wemm 	**  Horrible hack to work around problem with Lotus Notes SMTP
270c2aa98e2SPeter Wemm 	**  mail gateway, which generates From: headers with newlines in
271c2aa98e2SPeter Wemm 	**  them and the <address> on the second line.  Although this is
272c2aa98e2SPeter Wemm 	**  legal RFC 822, many MUAs don't handle this properly and thus
273c2aa98e2SPeter Wemm 	**  never find the actual address.
274c2aa98e2SPeter Wemm 	*/
275c2aa98e2SPeter Wemm 
276c2aa98e2SPeter Wemm 	if (bitset(H_FROM, hi->hi_flags) && SingleLineFromHeader)
277c2aa98e2SPeter Wemm 	{
278c2aa98e2SPeter Wemm 		while ((p = strchr(fvalue, '\n')) != NULL)
279c2aa98e2SPeter Wemm 			*p = ' ';
280c2aa98e2SPeter Wemm 	}
281c2aa98e2SPeter Wemm 
282c2aa98e2SPeter Wemm 	/*
283c2aa98e2SPeter Wemm 	**  If there is a check ruleset, verify it against the header.
284c2aa98e2SPeter Wemm 	*/
285c2aa98e2SPeter Wemm 
2863299c2f1SGregory Neil Shapiro 	if (bitset(pflag, CHHDR_CHECK))
2873299c2f1SGregory Neil Shapiro 	{
2889d8fddc1SGregory Neil Shapiro 		int rscheckflags;
2893299c2f1SGregory Neil Shapiro 		char *rs;
2903299c2f1SGregory Neil Shapiro 
2913299c2f1SGregory Neil Shapiro 		/* no ruleset? look for default */
2923299c2f1SGregory Neil Shapiro 		rs = hi->hi_ruleset;
2939d8fddc1SGregory Neil Shapiro 		rscheckflags = RSF_COUNT;
2949d8fddc1SGregory Neil Shapiro 		if (!bitset(hi->hi_flags, H_FROM|H_RCPT))
2959d8fddc1SGregory Neil Shapiro 			rscheckflags |= RSF_UNSTRUCTURED;
2963299c2f1SGregory Neil Shapiro 		if (rs == NULL)
2973299c2f1SGregory Neil Shapiro 		{
2983299c2f1SGregory Neil Shapiro 			s = stab("*", ST_HEADER, ST_FIND);
2993299c2f1SGregory Neil Shapiro 			if (s != NULL)
3003299c2f1SGregory Neil Shapiro 			{
3013299c2f1SGregory Neil Shapiro 				rs = (&s->s_header)->hi_ruleset;
3029d8fddc1SGregory Neil Shapiro 				if (bitset((&s->s_header)->hi_flags,
3039d8fddc1SGregory Neil Shapiro 					   H_STRIPCOMM))
3049d8fddc1SGregory Neil Shapiro 					rscheckflags |= RSF_RMCOMM;
3053299c2f1SGregory Neil Shapiro 			}
3063299c2f1SGregory Neil Shapiro 		}
3079d8fddc1SGregory Neil Shapiro 		else if (bitset(hi->hi_flags, H_STRIPCOMM))
3089d8fddc1SGregory Neil Shapiro 			rscheckflags |= RSF_RMCOMM;
3093299c2f1SGregory Neil Shapiro 		if (rs != NULL)
3103299c2f1SGregory Neil Shapiro 		{
31112ed1c7cSGregory Neil Shapiro 			int l, k;
3123299c2f1SGregory Neil Shapiro 			char qval[MAXNAME];
3133299c2f1SGregory Neil Shapiro 
3143299c2f1SGregory Neil Shapiro 			l = 0;
31512ed1c7cSGregory Neil Shapiro 			qval[l++] = '"';
31612ed1c7cSGregory Neil Shapiro 
31712ed1c7cSGregory Neil Shapiro 			/* - 3 to avoid problems with " at the end */
31812ed1c7cSGregory Neil Shapiro 			for (k = 0; fvalue[k] != '\0' && l < MAXNAME - 3; k++)
3193299c2f1SGregory Neil Shapiro 			{
32012ed1c7cSGregory Neil Shapiro 				switch (fvalue[k])
3213299c2f1SGregory Neil Shapiro 				{
32212ed1c7cSGregory Neil Shapiro 				  /* XXX other control chars? */
3233299c2f1SGregory Neil Shapiro 				  case '\011': /* ht */
3243299c2f1SGregory Neil Shapiro 				  case '\012': /* nl */
3253299c2f1SGregory Neil Shapiro 				  case '\013': /* vt */
3263299c2f1SGregory Neil Shapiro 				  case '\014': /* np */
3273299c2f1SGregory Neil Shapiro 				  case '\015': /* cr */
32812ed1c7cSGregory Neil Shapiro 					qval[l++] = ' ';
3293299c2f1SGregory Neil Shapiro 					break;
3303299c2f1SGregory Neil Shapiro 				  case '"':
33112ed1c7cSGregory Neil Shapiro 					qval[l++] = '\\';
3323299c2f1SGregory Neil Shapiro 					/* FALLTHROUGH */
3333299c2f1SGregory Neil Shapiro 				  default:
33412ed1c7cSGregory Neil Shapiro 					qval[l++] = fvalue[k];
3353299c2f1SGregory Neil Shapiro 					break;
3363299c2f1SGregory Neil Shapiro 				}
3373299c2f1SGregory Neil Shapiro 			}
33812ed1c7cSGregory Neil Shapiro 			qval[l++] = '"';
33912ed1c7cSGregory Neil Shapiro 			qval[l] = '\0';
34012ed1c7cSGregory Neil Shapiro 			k += strlen(fvalue + k);
34112ed1c7cSGregory Neil Shapiro 			if (k >= MAXNAME)
3423299c2f1SGregory Neil Shapiro 			{
3433299c2f1SGregory Neil Shapiro 				if (LogLevel > 9)
3443299c2f1SGregory Neil Shapiro 					sm_syslog(LOG_WARNING, e->e_id,
3453299c2f1SGregory Neil Shapiro 						  "Warning: truncated header '%s' before check with '%s' len=%d max=%d",
34612ed1c7cSGregory Neil Shapiro 						  fname, rs, k, MAXNAME - 1);
3473299c2f1SGregory Neil Shapiro 			}
34812ed1c7cSGregory Neil Shapiro 			macdefine(&e->e_macro, A_TEMP,
34912ed1c7cSGregory Neil Shapiro 				macid("{currHeader}"), qval);
35012ed1c7cSGregory Neil Shapiro 			macdefine(&e->e_macro, A_TEMP,
35112ed1c7cSGregory Neil Shapiro 				macid("{hdr_name}"), fname);
35212ed1c7cSGregory Neil Shapiro 
35312ed1c7cSGregory Neil Shapiro 			(void) sm_snprintf(qval, sizeof qval, "%d", k);
35412ed1c7cSGregory Neil Shapiro 			macdefine(&e->e_macro, A_TEMP, macid("{hdrlen}"), qval);
35512ed1c7cSGregory Neil Shapiro #if _FFR_HDR_TYPE
35612ed1c7cSGregory Neil Shapiro 			/*
35712ed1c7cSGregory Neil Shapiro 			**  XXX: h isn't set yet
35812ed1c7cSGregory Neil Shapiro 			**  If we really want to be precise then we have
35912ed1c7cSGregory Neil Shapiro 			**  to lookup the header (see below).
36012ed1c7cSGregory Neil Shapiro 			**  It's probably not worth the effort.
36112ed1c7cSGregory Neil Shapiro 			*/
36212ed1c7cSGregory Neil Shapiro 
36312ed1c7cSGregory Neil Shapiro 			if (bitset(H_FROM, h->h_flags))
36412ed1c7cSGregory Neil Shapiro 				macdefine(&e->e_macro, A_PERM,
36512ed1c7cSGregory Neil Shapiro 					macid("{addr_type}"), "h s");
36612ed1c7cSGregory Neil Shapiro 			else if (bitset(H_RCPT, h->h_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 /*
465c2aa98e2SPeter Wemm **  ADDHEADER -- add a header entry to the end of the queue.
466c2aa98e2SPeter Wemm **
467c2aa98e2SPeter Wemm **	This bypasses the special checking of chompheader.
468c2aa98e2SPeter Wemm **
469c2aa98e2SPeter Wemm **	Parameters:
470c2aa98e2SPeter Wemm **		field -- the name of the header field.
471c2aa98e2SPeter Wemm **		value -- the value of the field.
4723299c2f1SGregory Neil Shapiro **		flags -- flags to add to h_flags.
47312ed1c7cSGregory Neil Shapiro **		e -- envelope.
474c2aa98e2SPeter Wemm **
475c2aa98e2SPeter Wemm **	Returns:
476c2aa98e2SPeter Wemm **		none.
477c2aa98e2SPeter Wemm **
478c2aa98e2SPeter Wemm **	Side Effects:
479c2aa98e2SPeter Wemm **		adds the field on the list of headers for this envelope.
480c2aa98e2SPeter Wemm */
481c2aa98e2SPeter Wemm 
482c2aa98e2SPeter Wemm void
48312ed1c7cSGregory Neil Shapiro addheader(field, value, flags, e)
484c2aa98e2SPeter Wemm 	char *field;
485c2aa98e2SPeter Wemm 	char *value;
4863299c2f1SGregory Neil Shapiro 	int flags;
48712ed1c7cSGregory Neil Shapiro 	ENVELOPE *e;
488c2aa98e2SPeter Wemm {
489c2aa98e2SPeter Wemm 	register HDR *h;
490c2aa98e2SPeter Wemm 	STAB *s;
491c2aa98e2SPeter Wemm 	HDR **hp;
49212ed1c7cSGregory Neil Shapiro 	HDR **hdrlist = &e->e_header;
493c2aa98e2SPeter Wemm 
494c2aa98e2SPeter Wemm 	/* find info struct */
495c2aa98e2SPeter Wemm 	s = stab(field, ST_HEADER, ST_FIND);
496c2aa98e2SPeter Wemm 
497c2aa98e2SPeter Wemm 	/* find current place in list -- keep back pointer? */
498c2aa98e2SPeter Wemm 	for (hp = hdrlist; (h = *hp) != NULL; hp = &h->h_link)
499c2aa98e2SPeter Wemm 	{
50012ed1c7cSGregory Neil Shapiro 		if (sm_strcasecmp(field, h->h_field) == 0)
501c2aa98e2SPeter Wemm 			break;
502c2aa98e2SPeter Wemm 	}
503c2aa98e2SPeter Wemm 
504c2aa98e2SPeter Wemm 	/* allocate space for new header */
50512ed1c7cSGregory Neil Shapiro 	h = (HDR *) sm_rpool_malloc_x(e->e_rpool, sizeof *h);
506c2aa98e2SPeter Wemm 	h->h_field = field;
50712ed1c7cSGregory Neil Shapiro 	h->h_value = sm_rpool_strdup_x(e->e_rpool, value);
508c2aa98e2SPeter Wemm 	h->h_link = *hp;
5093299c2f1SGregory Neil Shapiro 	h->h_flags = flags;
510c2aa98e2SPeter Wemm 	if (s != NULL)
511c2aa98e2SPeter Wemm 		h->h_flags |= s->s_header.hi_flags;
512c2aa98e2SPeter Wemm 	clrbitmap(h->h_mflags);
5133299c2f1SGregory Neil Shapiro 	h->h_macro = '\0';
514c2aa98e2SPeter Wemm 	*hp = h;
515c2aa98e2SPeter Wemm }
51612ed1c7cSGregory Neil Shapiro /*
517c2aa98e2SPeter Wemm **  HVALUE -- return value of a header.
518c2aa98e2SPeter Wemm **
519c2aa98e2SPeter Wemm **	Only "real" fields (i.e., ones that have not been supplied
520c2aa98e2SPeter Wemm **	as a default) are used.
521c2aa98e2SPeter Wemm **
522c2aa98e2SPeter Wemm **	Parameters:
523c2aa98e2SPeter Wemm **		field -- the field name.
524c2aa98e2SPeter Wemm **		header -- the header list.
525c2aa98e2SPeter Wemm **
526c2aa98e2SPeter Wemm **	Returns:
527c2aa98e2SPeter Wemm **		pointer to the value part.
528c2aa98e2SPeter Wemm **		NULL if not found.
529c2aa98e2SPeter Wemm **
530c2aa98e2SPeter Wemm **	Side Effects:
531c2aa98e2SPeter Wemm **		none.
532c2aa98e2SPeter Wemm */
533c2aa98e2SPeter Wemm 
534c2aa98e2SPeter Wemm char *
535c2aa98e2SPeter Wemm hvalue(field, header)
536c2aa98e2SPeter Wemm 	char *field;
537c2aa98e2SPeter Wemm 	HDR *header;
538c2aa98e2SPeter Wemm {
539c2aa98e2SPeter Wemm 	register HDR *h;
540c2aa98e2SPeter Wemm 
541c2aa98e2SPeter Wemm 	for (h = header; h != NULL; h = h->h_link)
542c2aa98e2SPeter Wemm 	{
543c2aa98e2SPeter Wemm 		if (!bitset(H_DEFAULT, h->h_flags) &&
54412ed1c7cSGregory Neil Shapiro 		    sm_strcasecmp(h->h_field, field) == 0)
5453299c2f1SGregory Neil Shapiro 			return h->h_value;
546c2aa98e2SPeter Wemm 	}
5473299c2f1SGregory Neil Shapiro 	return NULL;
548c2aa98e2SPeter Wemm }
54912ed1c7cSGregory Neil Shapiro /*
550c2aa98e2SPeter Wemm **  ISHEADER -- predicate telling if argument is a header.
551c2aa98e2SPeter Wemm **
552c2aa98e2SPeter Wemm **	A line is a header if it has a single word followed by
553c2aa98e2SPeter Wemm **	optional white space followed by a colon.
554c2aa98e2SPeter Wemm **
555c2aa98e2SPeter Wemm **	Header fields beginning with two dashes, although technically
556c2aa98e2SPeter Wemm **	permitted by RFC822, are automatically rejected in order
557c2aa98e2SPeter Wemm **	to make MIME work out.  Without this we could have a technically
558c2aa98e2SPeter Wemm **	legal header such as ``--"foo:bar"'' that would also be a legal
559c2aa98e2SPeter Wemm **	MIME separator.
560c2aa98e2SPeter Wemm **
561c2aa98e2SPeter Wemm **	Parameters:
562c2aa98e2SPeter Wemm **		h -- string to check for possible headerness.
563c2aa98e2SPeter Wemm **
564c2aa98e2SPeter Wemm **	Returns:
56512ed1c7cSGregory Neil Shapiro **		true if h is a header.
56612ed1c7cSGregory Neil Shapiro **		false otherwise.
567c2aa98e2SPeter Wemm **
568c2aa98e2SPeter Wemm **	Side Effects:
569c2aa98e2SPeter Wemm **		none.
570c2aa98e2SPeter Wemm */
571c2aa98e2SPeter Wemm 
572c2aa98e2SPeter Wemm bool
573c2aa98e2SPeter Wemm isheader(h)
574c2aa98e2SPeter Wemm 	char *h;
575c2aa98e2SPeter Wemm {
576c2aa98e2SPeter Wemm 	register char *s = h;
577c2aa98e2SPeter Wemm 
578c2aa98e2SPeter Wemm 	if (s[0] == '-' && s[1] == '-')
57912ed1c7cSGregory Neil Shapiro 		return false;
580c2aa98e2SPeter Wemm 
581c2aa98e2SPeter Wemm 	while (*s > ' ' && *s != ':' && *s != '\0')
582c2aa98e2SPeter Wemm 		s++;
583c2aa98e2SPeter Wemm 
584c2aa98e2SPeter Wemm 	if (h == s)
58512ed1c7cSGregory Neil Shapiro 		return false;
586c2aa98e2SPeter Wemm 
587c2aa98e2SPeter Wemm 	/* following technically violates RFC822 */
588c2aa98e2SPeter Wemm 	while (isascii(*s) && isspace(*s))
589c2aa98e2SPeter Wemm 		s++;
590c2aa98e2SPeter Wemm 
591c2aa98e2SPeter Wemm 	return (*s == ':');
592c2aa98e2SPeter Wemm }
59312ed1c7cSGregory Neil Shapiro /*
594c2aa98e2SPeter Wemm **  EATHEADER -- run through the stored header and extract info.
595c2aa98e2SPeter Wemm **
596c2aa98e2SPeter Wemm **	Parameters:
597c2aa98e2SPeter Wemm **		e -- the envelope to process.
598c2aa98e2SPeter Wemm **		full -- if set, do full processing (e.g., compute
599c2aa98e2SPeter Wemm **			message priority).  This should not be set
600c2aa98e2SPeter Wemm **			when reading a queue file because some info
601c2aa98e2SPeter Wemm **			needed to compute the priority is wrong.
60212ed1c7cSGregory Neil Shapiro **		log -- call logsender()?
603c2aa98e2SPeter Wemm **
604c2aa98e2SPeter Wemm **	Returns:
605c2aa98e2SPeter Wemm **		none.
606c2aa98e2SPeter Wemm **
607c2aa98e2SPeter Wemm **	Side Effects:
608c2aa98e2SPeter Wemm **		Sets a bunch of global variables from information
609c2aa98e2SPeter Wemm **			in the collected header.
610c2aa98e2SPeter Wemm */
611c2aa98e2SPeter Wemm 
612c2aa98e2SPeter Wemm void
61312ed1c7cSGregory Neil Shapiro eatheader(e, full, log)
614c2aa98e2SPeter Wemm 	register ENVELOPE *e;
615c2aa98e2SPeter Wemm 	bool full;
61612ed1c7cSGregory Neil Shapiro 	bool log;
617c2aa98e2SPeter Wemm {
618c2aa98e2SPeter Wemm 	register HDR *h;
619c2aa98e2SPeter Wemm 	register char *p;
620c2aa98e2SPeter Wemm 	int hopcnt = 0;
621c2aa98e2SPeter Wemm 	char buf[MAXLINE];
622c2aa98e2SPeter Wemm 
623c2aa98e2SPeter Wemm 	/*
624c2aa98e2SPeter Wemm 	**  Set up macros for possible expansion in headers.
625c2aa98e2SPeter Wemm 	*/
626c2aa98e2SPeter Wemm 
62712ed1c7cSGregory Neil Shapiro 	macdefine(&e->e_macro, A_PERM, 'f', e->e_sender);
62812ed1c7cSGregory Neil Shapiro 	macdefine(&e->e_macro, A_PERM, 'g', e->e_sender);
629c2aa98e2SPeter Wemm 	if (e->e_origrcpt != NULL && *e->e_origrcpt != '\0')
63012ed1c7cSGregory Neil Shapiro 		macdefine(&e->e_macro, A_PERM, 'u', e->e_origrcpt);
631c2aa98e2SPeter Wemm 	else
63212ed1c7cSGregory Neil Shapiro 		macdefine(&e->e_macro, A_PERM, 'u', NULL);
633c2aa98e2SPeter Wemm 
634c2aa98e2SPeter Wemm 	/* full name of from person */
635c2aa98e2SPeter Wemm 	p = hvalue("full-name", e->e_header);
636c2aa98e2SPeter Wemm 	if (p != NULL)
637c2aa98e2SPeter Wemm 	{
638c2aa98e2SPeter Wemm 		if (!rfc822_string(p))
639c2aa98e2SPeter Wemm 		{
640c2aa98e2SPeter Wemm 			/*
641c2aa98e2SPeter Wemm 			**  Quote a full name with special characters
642c2aa98e2SPeter Wemm 			**  as a comment so crackaddr() doesn't destroy
643c2aa98e2SPeter Wemm 			**  the name portion of the address.
644c2aa98e2SPeter Wemm 			*/
64512ed1c7cSGregory Neil Shapiro 
64612ed1c7cSGregory Neil Shapiro 			p = addquotes(p, e->e_rpool);
647c2aa98e2SPeter Wemm 		}
64812ed1c7cSGregory Neil Shapiro 		macdefine(&e->e_macro, A_PERM, 'x', p);
649c2aa98e2SPeter Wemm 	}
650c2aa98e2SPeter Wemm 
651c2aa98e2SPeter Wemm 	if (tTd(32, 1))
65212ed1c7cSGregory Neil Shapiro 		sm_dprintf("----- collected header -----\n");
65312ed1c7cSGregory Neil Shapiro 	e->e_msgid = NULL;
654c2aa98e2SPeter Wemm 	for (h = e->e_header; h != NULL; h = h->h_link)
655c2aa98e2SPeter Wemm 	{
656c2aa98e2SPeter Wemm 		if (tTd(32, 1))
65712ed1c7cSGregory Neil Shapiro 			sm_dprintf("%s: ", h->h_field);
658c2aa98e2SPeter Wemm 		if (h->h_value == NULL)
659c2aa98e2SPeter Wemm 		{
660c2aa98e2SPeter Wemm 			if (tTd(32, 1))
66112ed1c7cSGregory Neil Shapiro 				sm_dprintf("<NULL>\n");
662c2aa98e2SPeter Wemm 			continue;
663c2aa98e2SPeter Wemm 		}
664c2aa98e2SPeter Wemm 
665c2aa98e2SPeter Wemm 		/* do early binding */
6663299c2f1SGregory Neil Shapiro 		if (bitset(H_DEFAULT, h->h_flags) &&
6673299c2f1SGregory Neil Shapiro 		    !bitset(H_BINDLATE, h->h_flags))
668c2aa98e2SPeter Wemm 		{
669c2aa98e2SPeter Wemm 			if (tTd(32, 1))
670c2aa98e2SPeter Wemm 			{
67112ed1c7cSGregory Neil Shapiro 				sm_dprintf("(");
672c2aa98e2SPeter Wemm 				xputs(h->h_value);
67312ed1c7cSGregory Neil Shapiro 				sm_dprintf(") ");
674c2aa98e2SPeter Wemm 			}
675c2aa98e2SPeter Wemm 			expand(h->h_value, buf, sizeof buf, e);
676c2aa98e2SPeter Wemm 			if (buf[0] != '\0')
677c2aa98e2SPeter Wemm 			{
678c2aa98e2SPeter Wemm 				if (bitset(H_FROM, h->h_flags))
679f9218d3dSGregory Neil Shapiro 					expand(crackaddr(buf, e),
680f9218d3dSGregory Neil Shapiro 					       buf, sizeof buf, e);
68112ed1c7cSGregory Neil Shapiro 				h->h_value = sm_rpool_strdup_x(e->e_rpool, buf);
682c2aa98e2SPeter Wemm 				h->h_flags &= ~H_DEFAULT;
683c2aa98e2SPeter Wemm 			}
684c2aa98e2SPeter Wemm 		}
685c2aa98e2SPeter Wemm 		if (tTd(32, 1))
686c2aa98e2SPeter Wemm 		{
687c2aa98e2SPeter Wemm 			xputs(h->h_value);
68812ed1c7cSGregory Neil Shapiro 			sm_dprintf("\n");
689c2aa98e2SPeter Wemm 		}
690c2aa98e2SPeter Wemm 
691c2aa98e2SPeter Wemm 		/* count the number of times it has been processed */
692c2aa98e2SPeter Wemm 		if (bitset(H_TRACE, h->h_flags))
693c2aa98e2SPeter Wemm 			hopcnt++;
694c2aa98e2SPeter Wemm 
695c2aa98e2SPeter Wemm 		/* send to this person if we so desire */
696c2aa98e2SPeter Wemm 		if (GrabTo && bitset(H_RCPT, h->h_flags) &&
697c2aa98e2SPeter Wemm 		    !bitset(H_DEFAULT, h->h_flags) &&
69812ed1c7cSGregory Neil Shapiro 		    (!bitset(EF_RESENT, e->e_flags) ||
69912ed1c7cSGregory Neil Shapiro 		     bitset(H_RESENT, h->h_flags)))
700c2aa98e2SPeter Wemm 		{
701c2aa98e2SPeter Wemm #if 0
702c2aa98e2SPeter Wemm 			int saveflags = e->e_flags;
7033299c2f1SGregory Neil Shapiro #endif /* 0 */
704c2aa98e2SPeter Wemm 
70512ed1c7cSGregory Neil Shapiro 			(void) sendtolist(denlstring(h->h_value, true, false),
70612ed1c7cSGregory Neil Shapiro 					  NULLADDR, &e->e_sendqueue, 0, e);
707c2aa98e2SPeter Wemm 
708c2aa98e2SPeter Wemm #if 0
709c2aa98e2SPeter Wemm 			/*
710c2aa98e2SPeter Wemm 			**  Change functionality so a fatal error on an
711c2aa98e2SPeter Wemm 			**  address doesn't affect the entire envelope.
712c2aa98e2SPeter Wemm 			*/
713c2aa98e2SPeter Wemm 
714c2aa98e2SPeter Wemm 			/* delete fatal errors generated by this address */
715c2aa98e2SPeter Wemm 			if (!bitset(EF_FATALERRS, saveflags))
716c2aa98e2SPeter Wemm 				e->e_flags &= ~EF_FATALERRS;
7173299c2f1SGregory Neil Shapiro #endif /* 0 */
718c2aa98e2SPeter Wemm 		}
719c2aa98e2SPeter Wemm 
720c2aa98e2SPeter Wemm 		/* save the message-id for logging */
721c2aa98e2SPeter Wemm 		p = "resent-message-id";
722c2aa98e2SPeter Wemm 		if (!bitset(EF_RESENT, e->e_flags))
723c2aa98e2SPeter Wemm 			p += 7;
72412ed1c7cSGregory Neil Shapiro 		if (sm_strcasecmp(h->h_field, p) == 0)
725c2aa98e2SPeter Wemm 		{
72612ed1c7cSGregory Neil Shapiro 			e->e_msgid = h->h_value;
72712ed1c7cSGregory Neil Shapiro 			while (isascii(*e->e_msgid) && isspace(*e->e_msgid))
72812ed1c7cSGregory Neil Shapiro 				e->e_msgid++;
729c2aa98e2SPeter Wemm 		}
730c2aa98e2SPeter Wemm 	}
731c2aa98e2SPeter Wemm 	if (tTd(32, 1))
73212ed1c7cSGregory Neil Shapiro 		sm_dprintf("----------------------------\n");
733c2aa98e2SPeter Wemm 
734c2aa98e2SPeter Wemm 	/* if we are just verifying (that is, sendmail -t -bv), drop out now */
735c2aa98e2SPeter Wemm 	if (OpMode == MD_VERIFY)
736c2aa98e2SPeter Wemm 		return;
737c2aa98e2SPeter Wemm 
738c2aa98e2SPeter Wemm 	/* store hop count */
739c2aa98e2SPeter Wemm 	if (hopcnt > e->e_hopcount)
74012ed1c7cSGregory Neil Shapiro 	{
741c2aa98e2SPeter Wemm 		e->e_hopcount = hopcnt;
74212ed1c7cSGregory Neil Shapiro 		(void) sm_snprintf(buf, sizeof buf, "%d", e->e_hopcount);
74312ed1c7cSGregory Neil Shapiro 		macdefine(&e->e_macro, A_TEMP, 'c', buf);
74412ed1c7cSGregory Neil Shapiro 	}
745c2aa98e2SPeter Wemm 
746c2aa98e2SPeter Wemm 	/* message priority */
747c2aa98e2SPeter Wemm 	p = hvalue("precedence", e->e_header);
748c2aa98e2SPeter Wemm 	if (p != NULL)
749c2aa98e2SPeter Wemm 		e->e_class = priencode(p);
750c2aa98e2SPeter Wemm 	if (e->e_class < 0)
751c2aa98e2SPeter Wemm 		e->e_timeoutclass = TOC_NONURGENT;
752c2aa98e2SPeter Wemm 	else if (e->e_class > 0)
753c2aa98e2SPeter Wemm 		e->e_timeoutclass = TOC_URGENT;
754c2aa98e2SPeter Wemm 	if (full)
755c2aa98e2SPeter Wemm 	{
756c2aa98e2SPeter Wemm 		e->e_msgpriority = e->e_msgsize
757c2aa98e2SPeter Wemm 				 - e->e_class * WkClassFact
758c2aa98e2SPeter Wemm 				 + e->e_nrcpts * WkRecipFact;
759c2aa98e2SPeter Wemm 	}
760c2aa98e2SPeter Wemm 
761c2aa98e2SPeter Wemm 	/* message timeout priority */
762c2aa98e2SPeter Wemm 	p = hvalue("priority", e->e_header);
763c2aa98e2SPeter Wemm 	if (p != NULL)
764c2aa98e2SPeter Wemm 	{
765c2aa98e2SPeter Wemm 		/* (this should be in the configuration file) */
76612ed1c7cSGregory Neil Shapiro 		if (sm_strcasecmp(p, "urgent") == 0)
767c2aa98e2SPeter Wemm 			e->e_timeoutclass = TOC_URGENT;
76812ed1c7cSGregory Neil Shapiro 		else if (sm_strcasecmp(p, "normal") == 0)
769c2aa98e2SPeter Wemm 			e->e_timeoutclass = TOC_NORMAL;
77012ed1c7cSGregory Neil Shapiro 		else if (sm_strcasecmp(p, "non-urgent") == 0)
771c2aa98e2SPeter Wemm 			e->e_timeoutclass = TOC_NONURGENT;
772c2aa98e2SPeter Wemm 	}
773c2aa98e2SPeter Wemm 
774c2aa98e2SPeter Wemm 	/* date message originated */
775c2aa98e2SPeter Wemm 	p = hvalue("posted-date", e->e_header);
776c2aa98e2SPeter Wemm 	if (p == NULL)
777c2aa98e2SPeter Wemm 		p = hvalue("date", e->e_header);
778c2aa98e2SPeter Wemm 	if (p != NULL)
77912ed1c7cSGregory Neil Shapiro 		macdefine(&e->e_macro, A_PERM, 'a', p);
780c2aa98e2SPeter Wemm 
781c2aa98e2SPeter Wemm 	/* check to see if this is a MIME message */
782c2aa98e2SPeter Wemm 	if ((e->e_bodytype != NULL &&
78312ed1c7cSGregory Neil Shapiro 	     sm_strcasecmp(e->e_bodytype, "8BITMIME") == 0) ||
784c2aa98e2SPeter Wemm 	    hvalue("MIME-Version", e->e_header) != NULL)
785c2aa98e2SPeter Wemm 	{
786c2aa98e2SPeter Wemm 		e->e_flags |= EF_IS_MIME;
787c2aa98e2SPeter Wemm 		if (HasEightBits)
788c2aa98e2SPeter Wemm 			e->e_bodytype = "8BITMIME";
789c2aa98e2SPeter Wemm 	}
790c2aa98e2SPeter Wemm 	else if ((p = hvalue("Content-Type", e->e_header)) != NULL)
791c2aa98e2SPeter Wemm 	{
792c2aa98e2SPeter Wemm 		/* this may be an RFC 1049 message */
793c2aa98e2SPeter Wemm 		p = strpbrk(p, ";/");
794c2aa98e2SPeter Wemm 		if (p == NULL || *p == ';')
795c2aa98e2SPeter Wemm 		{
796c2aa98e2SPeter Wemm 			/* yep, it is */
797c2aa98e2SPeter Wemm 			e->e_flags |= EF_DONT_MIME;
798c2aa98e2SPeter Wemm 		}
799c2aa98e2SPeter Wemm 	}
800c2aa98e2SPeter Wemm 
801c2aa98e2SPeter Wemm 	/*
802c2aa98e2SPeter Wemm 	**  From person in antiquated ARPANET mode
803c2aa98e2SPeter Wemm 	**	required by UK Grey Book e-mail gateways (sigh)
804c2aa98e2SPeter Wemm 	*/
805c2aa98e2SPeter Wemm 
806c2aa98e2SPeter Wemm 	if (OpMode == MD_ARPAFTP)
807c2aa98e2SPeter Wemm 	{
808c2aa98e2SPeter Wemm 		register struct hdrinfo *hi;
809c2aa98e2SPeter Wemm 
810c2aa98e2SPeter Wemm 		for (hi = HdrInfo; hi->hi_field != NULL; hi++)
811c2aa98e2SPeter Wemm 		{
812c2aa98e2SPeter Wemm 			if (bitset(H_FROM, hi->hi_flags) &&
813c2aa98e2SPeter Wemm 			    (!bitset(H_RESENT, hi->hi_flags) ||
814c2aa98e2SPeter Wemm 			     bitset(EF_RESENT, e->e_flags)) &&
815c2aa98e2SPeter Wemm 			    (p = hvalue(hi->hi_field, e->e_header)) != NULL)
816c2aa98e2SPeter Wemm 				break;
817c2aa98e2SPeter Wemm 		}
818c2aa98e2SPeter Wemm 		if (hi->hi_field != NULL)
819c2aa98e2SPeter Wemm 		{
820c2aa98e2SPeter Wemm 			if (tTd(32, 2))
82112ed1c7cSGregory Neil Shapiro 				sm_dprintf("eatheader: setsender(*%s == %s)\n",
822c2aa98e2SPeter Wemm 					hi->hi_field, p);
82312ed1c7cSGregory Neil Shapiro 			setsender(p, e, NULL, '\0', true);
824c2aa98e2SPeter Wemm 		}
825c2aa98e2SPeter Wemm 	}
826c2aa98e2SPeter Wemm 
827c2aa98e2SPeter Wemm 	/*
828c2aa98e2SPeter Wemm 	**  Log collection information.
829c2aa98e2SPeter Wemm 	*/
830c2aa98e2SPeter Wemm 
83112ed1c7cSGregory Neil Shapiro 	if (log && bitset(EF_LOGSENDER, e->e_flags) && LogLevel > 4)
83212ed1c7cSGregory Neil Shapiro 	{
83312ed1c7cSGregory Neil Shapiro 		logsender(e, e->e_msgid);
834c2aa98e2SPeter Wemm 		e->e_flags &= ~EF_LOGSENDER;
835c2aa98e2SPeter Wemm 	}
83612ed1c7cSGregory Neil Shapiro }
83712ed1c7cSGregory Neil Shapiro /*
838c2aa98e2SPeter Wemm **  LOGSENDER -- log sender information
839c2aa98e2SPeter Wemm **
840c2aa98e2SPeter Wemm **	Parameters:
841c2aa98e2SPeter Wemm **		e -- the envelope to log
842c2aa98e2SPeter Wemm **		msgid -- the message id
843c2aa98e2SPeter Wemm **
844c2aa98e2SPeter Wemm **	Returns:
845c2aa98e2SPeter Wemm **		none
846c2aa98e2SPeter Wemm */
847c2aa98e2SPeter Wemm 
848c2aa98e2SPeter Wemm void
849c2aa98e2SPeter Wemm logsender(e, msgid)
850c2aa98e2SPeter Wemm 	register ENVELOPE *e;
851c2aa98e2SPeter Wemm 	char *msgid;
852c2aa98e2SPeter Wemm {
853c2aa98e2SPeter Wemm 	char *name;
854c2aa98e2SPeter Wemm 	register char *sbp;
855c2aa98e2SPeter Wemm 	register char *p;
856c2aa98e2SPeter Wemm 	int l;
857c2aa98e2SPeter Wemm 	char hbuf[MAXNAME + 1];
858c2aa98e2SPeter Wemm 	char sbuf[MAXLINE + 1];
859c2aa98e2SPeter Wemm 	char mbuf[MAXNAME + 1];
860c2aa98e2SPeter Wemm 
861c2aa98e2SPeter Wemm 	/* don't allow newlines in the message-id */
86212ed1c7cSGregory Neil Shapiro 	/* XXX do we still need this? sm_syslog() replaces control chars */
863c2aa98e2SPeter Wemm 	if (msgid != NULL)
864c2aa98e2SPeter Wemm 	{
865c2aa98e2SPeter Wemm 		l = strlen(msgid);
866c2aa98e2SPeter Wemm 		if (l > sizeof mbuf - 1)
867c2aa98e2SPeter Wemm 			l = sizeof mbuf - 1;
8683299c2f1SGregory Neil Shapiro 		memmove(mbuf, msgid, l);
869c2aa98e2SPeter Wemm 		mbuf[l] = '\0';
870c2aa98e2SPeter Wemm 		p = mbuf;
871c2aa98e2SPeter Wemm 		while ((p = strchr(p, '\n')) != NULL)
872c2aa98e2SPeter Wemm 			*p++ = ' ';
873c2aa98e2SPeter Wemm 	}
874c2aa98e2SPeter Wemm 
875c2aa98e2SPeter Wemm 	if (bitset(EF_RESPONSE, e->e_flags))
876c2aa98e2SPeter Wemm 		name = "[RESPONSE]";
877c2aa98e2SPeter Wemm 	else if ((name = macvalue('_', e)) != NULL)
8783299c2f1SGregory Neil Shapiro 		/* EMPTY */
879c2aa98e2SPeter Wemm 		;
880c2aa98e2SPeter Wemm 	else if (RealHostName == NULL)
881c2aa98e2SPeter Wemm 		name = "localhost";
882c2aa98e2SPeter Wemm 	else if (RealHostName[0] == '[')
883c2aa98e2SPeter Wemm 		name = RealHostName;
884c2aa98e2SPeter Wemm 	else
885c2aa98e2SPeter Wemm 	{
886c2aa98e2SPeter Wemm 		name = hbuf;
88712ed1c7cSGregory Neil Shapiro 		(void) sm_snprintf(hbuf, sizeof hbuf, "%.80s", RealHostName);
888c2aa98e2SPeter Wemm 		if (RealHostAddr.sa.sa_family != 0)
889c2aa98e2SPeter Wemm 		{
890c2aa98e2SPeter Wemm 			p = &hbuf[strlen(hbuf)];
89112ed1c7cSGregory Neil Shapiro 			(void) sm_snprintf(p, SPACELEFT(hbuf, p),
89212ed1c7cSGregory Neil Shapiro 					   " (%.100s)",
893c2aa98e2SPeter Wemm 					   anynet_ntoa(&RealHostAddr));
894c2aa98e2SPeter Wemm 		}
895c2aa98e2SPeter Wemm 	}
896c2aa98e2SPeter Wemm 
897c2aa98e2SPeter Wemm 	/* some versions of syslog only take 5 printf args */
898c2aa98e2SPeter Wemm #if (SYSLOG_BUFSIZE) >= 256
899c2aa98e2SPeter Wemm 	sbp = sbuf;
90012ed1c7cSGregory Neil Shapiro 	(void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp),
9013299c2f1SGregory Neil Shapiro 		"from=%.200s, size=%ld, class=%d, nrcpts=%d",
902c2aa98e2SPeter Wemm 		e->e_from.q_paddr == NULL ? "<NONE>" : e->e_from.q_paddr,
9033299c2f1SGregory Neil Shapiro 		e->e_msgsize, e->e_class, e->e_nrcpts);
904c2aa98e2SPeter Wemm 	sbp += strlen(sbp);
905c2aa98e2SPeter Wemm 	if (msgid != NULL)
906c2aa98e2SPeter Wemm 	{
90712ed1c7cSGregory Neil Shapiro 		(void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp),
90812ed1c7cSGregory Neil Shapiro 				", msgid=%.100s", mbuf);
909c2aa98e2SPeter Wemm 		sbp += strlen(sbp);
910c2aa98e2SPeter Wemm 	}
911c2aa98e2SPeter Wemm 	if (e->e_bodytype != NULL)
912c2aa98e2SPeter Wemm 	{
91312ed1c7cSGregory Neil Shapiro 		(void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp),
91412ed1c7cSGregory Neil Shapiro 				", bodytype=%.20s", e->e_bodytype);
915c2aa98e2SPeter Wemm 		sbp += strlen(sbp);
916c2aa98e2SPeter Wemm 	}
917c2aa98e2SPeter Wemm 	p = macvalue('r', e);
918c2aa98e2SPeter Wemm 	if (p != NULL)
9193299c2f1SGregory Neil Shapiro 	{
92012ed1c7cSGregory Neil Shapiro 		(void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp),
92112ed1c7cSGregory Neil Shapiro 				", proto=%.20s", p);
9223299c2f1SGregory Neil Shapiro 		sbp += strlen(sbp);
9233299c2f1SGregory Neil Shapiro 	}
92412ed1c7cSGregory Neil Shapiro 	p = macvalue(macid("{daemon_name}"), e);
9253299c2f1SGregory Neil Shapiro 	if (p != NULL)
9263299c2f1SGregory Neil Shapiro 	{
92712ed1c7cSGregory Neil Shapiro 		(void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp),
92812ed1c7cSGregory Neil Shapiro 				", daemon=%.20s", p);
9293299c2f1SGregory Neil Shapiro 		sbp += strlen(sbp);
9303299c2f1SGregory Neil Shapiro 	}
9312ef40764SGregory Neil Shapiro 	sm_syslog(LOG_INFO, e->e_id, "%.850s, relay=%s", sbuf, name);
932c2aa98e2SPeter Wemm 
9333299c2f1SGregory Neil Shapiro #else /* (SYSLOG_BUFSIZE) >= 256 */
934c2aa98e2SPeter Wemm 
935c2aa98e2SPeter Wemm 	sm_syslog(LOG_INFO, e->e_id,
936c2aa98e2SPeter Wemm 		  "from=%s",
937c2aa98e2SPeter Wemm 		  e->e_from.q_paddr == NULL ? "<NONE>"
93812ed1c7cSGregory Neil Shapiro 					    : shortenstring(e->e_from.q_paddr,
93912ed1c7cSGregory Neil Shapiro 							    83));
940c2aa98e2SPeter Wemm 	sm_syslog(LOG_INFO, e->e_id,
9413299c2f1SGregory Neil Shapiro 		  "size=%ld, class=%ld, nrcpts=%d",
9423299c2f1SGregory Neil Shapiro 		  e->e_msgsize, e->e_class, e->e_nrcpts);
943c2aa98e2SPeter Wemm 	if (msgid != NULL)
944c2aa98e2SPeter Wemm 		sm_syslog(LOG_INFO, e->e_id,
945c2aa98e2SPeter Wemm 			  "msgid=%s",
946c2aa98e2SPeter Wemm 			  shortenstring(mbuf, 83));
947c2aa98e2SPeter Wemm 	sbp = sbuf;
948c2aa98e2SPeter Wemm 	*sbp = '\0';
949c2aa98e2SPeter Wemm 	if (e->e_bodytype != NULL)
950c2aa98e2SPeter Wemm 	{
95112ed1c7cSGregory Neil Shapiro 		(void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp),
95212ed1c7cSGregory Neil Shapiro 				"bodytype=%.20s, ", e->e_bodytype);
953c2aa98e2SPeter Wemm 		sbp += strlen(sbp);
954c2aa98e2SPeter Wemm 	}
955c2aa98e2SPeter Wemm 	p = macvalue('r', e);
956c2aa98e2SPeter Wemm 	if (p != NULL)
957c2aa98e2SPeter Wemm 	{
95812ed1c7cSGregory Neil Shapiro 		(void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp),
95912ed1c7cSGregory Neil Shapiro 				"proto=%.20s, ", p);
960c2aa98e2SPeter Wemm 		sbp += strlen(sbp);
961c2aa98e2SPeter Wemm 	}
962c2aa98e2SPeter Wemm 	sm_syslog(LOG_INFO, e->e_id,
9632ef40764SGregory Neil Shapiro 		  "%.400srelay=%s", sbuf, name);
9643299c2f1SGregory Neil Shapiro #endif /* (SYSLOG_BUFSIZE) >= 256 */
965c2aa98e2SPeter Wemm }
96612ed1c7cSGregory Neil Shapiro /*
967c2aa98e2SPeter Wemm **  PRIENCODE -- encode external priority names into internal values.
968c2aa98e2SPeter Wemm **
969c2aa98e2SPeter Wemm **	Parameters:
970c2aa98e2SPeter Wemm **		p -- priority in ascii.
971c2aa98e2SPeter Wemm **
972c2aa98e2SPeter Wemm **	Returns:
973c2aa98e2SPeter Wemm **		priority as a numeric level.
974c2aa98e2SPeter Wemm **
975c2aa98e2SPeter Wemm **	Side Effects:
976c2aa98e2SPeter Wemm **		none.
977c2aa98e2SPeter Wemm */
978c2aa98e2SPeter Wemm 
9793299c2f1SGregory Neil Shapiro static int
980c2aa98e2SPeter Wemm priencode(p)
981c2aa98e2SPeter Wemm 	char *p;
982c2aa98e2SPeter Wemm {
983c2aa98e2SPeter Wemm 	register int i;
984c2aa98e2SPeter Wemm 
985c2aa98e2SPeter Wemm 	for (i = 0; i < NumPriorities; i++)
986c2aa98e2SPeter Wemm 	{
98712ed1c7cSGregory Neil Shapiro 		if (sm_strcasecmp(p, Priorities[i].pri_name) == 0)
9883299c2f1SGregory Neil Shapiro 			return Priorities[i].pri_val;
989c2aa98e2SPeter Wemm 	}
990c2aa98e2SPeter Wemm 
991c2aa98e2SPeter Wemm 	/* unknown priority */
9923299c2f1SGregory Neil Shapiro 	return 0;
993c2aa98e2SPeter Wemm }
99412ed1c7cSGregory Neil Shapiro /*
995c2aa98e2SPeter Wemm **  CRACKADDR -- parse an address and turn it into a macro
996c2aa98e2SPeter Wemm **
997c2aa98e2SPeter Wemm **	This doesn't actually parse the address -- it just extracts
998c2aa98e2SPeter Wemm **	it and replaces it with "$g".  The parse is totally ad hoc
999c2aa98e2SPeter Wemm **	and isn't even guaranteed to leave something syntactically
1000c2aa98e2SPeter Wemm **	identical to what it started with.  However, it does leave
1001f9218d3dSGregory Neil Shapiro **	something semantically identical if possible, else at least
1002f9218d3dSGregory Neil Shapiro **	syntactically correct.
1003f9218d3dSGregory Neil Shapiro **
1004f9218d3dSGregory Neil Shapiro **	For example, it changes "Real Name <real@example.com> (Comment)"
1005f9218d3dSGregory Neil Shapiro **	to "Real Name <$g> (Comment)".
1006c2aa98e2SPeter Wemm **
1007c2aa98e2SPeter Wemm **	This algorithm has been cleaned up to handle a wider range
1008c2aa98e2SPeter Wemm **	of cases -- notably quoted and backslash escaped strings.
1009c2aa98e2SPeter Wemm **	This modification makes it substantially better at preserving
1010c2aa98e2SPeter Wemm **	the original syntax.
1011c2aa98e2SPeter Wemm **
1012c2aa98e2SPeter Wemm **	Parameters:
1013c2aa98e2SPeter Wemm **		addr -- the address to be cracked.
1014f9218d3dSGregory Neil Shapiro **		e -- the current envelope.
1015c2aa98e2SPeter Wemm **
1016c2aa98e2SPeter Wemm **	Returns:
1017c2aa98e2SPeter Wemm **		a pointer to the new version.
1018c2aa98e2SPeter Wemm **
1019c2aa98e2SPeter Wemm **	Side Effects:
1020c2aa98e2SPeter Wemm **		none.
1021c2aa98e2SPeter Wemm **
1022c2aa98e2SPeter Wemm **	Warning:
1023c2aa98e2SPeter Wemm **		The return value is saved in local storage and should
1024c2aa98e2SPeter Wemm **		be copied if it is to be reused.
1025c2aa98e2SPeter Wemm */
1026c2aa98e2SPeter Wemm 
1027f9218d3dSGregory Neil Shapiro #define SM_HAVE_ROOM		((bp < buflim) && (buflim <= bufend))
1028f9218d3dSGregory Neil Shapiro 
1029f9218d3dSGregory Neil Shapiro /*
1030f9218d3dSGregory Neil Shapiro **  Append a character to bp if we have room.
1031f9218d3dSGregory Neil Shapiro **  If not, punt and return $g.
1032f9218d3dSGregory Neil Shapiro */
1033f9218d3dSGregory Neil Shapiro 
1034f9218d3dSGregory Neil Shapiro #define SM_APPEND_CHAR(c)					\
1035f9218d3dSGregory Neil Shapiro 	do							\
1036f9218d3dSGregory Neil Shapiro 	{							\
1037f9218d3dSGregory Neil Shapiro 		if (SM_HAVE_ROOM)				\
1038f9218d3dSGregory Neil Shapiro 			*bp++ = (c);				\
1039f9218d3dSGregory Neil Shapiro 		else						\
1040f9218d3dSGregory Neil Shapiro 			goto returng;				\
1041f9218d3dSGregory Neil Shapiro 	} while (0)
1042f9218d3dSGregory Neil Shapiro 
1043f9218d3dSGregory Neil Shapiro #if MAXNAME < 10
1044f9218d3dSGregory Neil Shapiro ERROR MAXNAME must be at least 10
1045f9218d3dSGregory Neil Shapiro #endif /* MAXNAME < 10 */
1046f9218d3dSGregory Neil Shapiro 
1047c2aa98e2SPeter Wemm char *
1048f9218d3dSGregory Neil Shapiro crackaddr(addr, e)
1049c2aa98e2SPeter Wemm 	register char *addr;
1050f9218d3dSGregory Neil Shapiro 	ENVELOPE *e;
1051c2aa98e2SPeter Wemm {
1052c2aa98e2SPeter Wemm 	register char *p;
1053c2aa98e2SPeter Wemm 	register char c;
1054f9218d3dSGregory Neil Shapiro 	int cmtlev;			/* comment level in input string */
1055f9218d3dSGregory Neil Shapiro 	int realcmtlev;			/* comment level in output string */
1056f9218d3dSGregory Neil Shapiro 	int anglelev;			/* angle level in input string */
1057f9218d3dSGregory Neil Shapiro 	int copylev;			/* 0 == in address, >0 copying */
1058f9218d3dSGregory Neil Shapiro 	int bracklev;			/* bracket level for IPv6 addr check */
1059f9218d3dSGregory Neil Shapiro 	bool addangle;			/* put closing angle in output */
1060f9218d3dSGregory Neil Shapiro 	bool qmode;			/* quoting in original string? */
1061f9218d3dSGregory Neil Shapiro 	bool realqmode;			/* quoting in output string? */
1062f9218d3dSGregory Neil Shapiro 	bool putgmac = false;		/* already wrote $g */
1063f9218d3dSGregory Neil Shapiro 	bool quoteit = false;		/* need to quote next character */
1064f9218d3dSGregory Neil Shapiro 	bool gotangle = false;		/* found first '<' */
1065f9218d3dSGregory Neil Shapiro 	bool gotcolon = false;		/* found a ':' */
1066c2aa98e2SPeter Wemm 	register char *bp;
1067c2aa98e2SPeter Wemm 	char *buflim;
1068c2aa98e2SPeter Wemm 	char *bufhead;
1069c2aa98e2SPeter Wemm 	char *addrhead;
1070f9218d3dSGregory Neil Shapiro 	char *bufend;
1071c2aa98e2SPeter Wemm 	static char buf[MAXNAME + 1];
1072c2aa98e2SPeter Wemm 
1073c2aa98e2SPeter Wemm 	if (tTd(33, 1))
107412ed1c7cSGregory Neil Shapiro 		sm_dprintf("crackaddr(%s)\n", addr);
1075c2aa98e2SPeter Wemm 
1076c2aa98e2SPeter Wemm 	/* strip leading spaces */
1077c2aa98e2SPeter Wemm 	while (*addr != '\0' && isascii(*addr) && isspace(*addr))
1078c2aa98e2SPeter Wemm 		addr++;
1079c2aa98e2SPeter Wemm 
1080c2aa98e2SPeter Wemm 	/*
1081c2aa98e2SPeter Wemm 	**  Start by assuming we have no angle brackets.  This will be
1082c2aa98e2SPeter Wemm 	**  adjusted later if we find them.
1083c2aa98e2SPeter Wemm 	*/
1084c2aa98e2SPeter Wemm 
1085f9218d3dSGregory Neil Shapiro 	buflim = bufend = &buf[sizeof(buf) - 1];
1086c2aa98e2SPeter Wemm 	bp = bufhead = buf;
1087c2aa98e2SPeter Wemm 	p = addrhead = addr;
1088f9218d3dSGregory Neil Shapiro 	copylev = anglelev = cmtlev = realcmtlev = 0;
1089c2aa98e2SPeter Wemm 	bracklev = 0;
1090f9218d3dSGregory Neil Shapiro 	qmode = realqmode = addangle = false;
1091c2aa98e2SPeter Wemm 
1092c2aa98e2SPeter Wemm 	while ((c = *p++) != '\0')
1093c2aa98e2SPeter Wemm 	{
1094c2aa98e2SPeter Wemm 		/*
1095f9218d3dSGregory Neil Shapiro 		**  Try to keep legal syntax using spare buffer space
1096f9218d3dSGregory Neil Shapiro 		**  (maintained by buflim).
1097c2aa98e2SPeter Wemm 		*/
1098c2aa98e2SPeter Wemm 
1099f9218d3dSGregory Neil Shapiro 		if (copylev > 0)
1100f9218d3dSGregory Neil Shapiro 			SM_APPEND_CHAR(c);
1101c2aa98e2SPeter Wemm 
1102c2aa98e2SPeter Wemm 		/* check for backslash escapes */
1103c2aa98e2SPeter Wemm 		if (c == '\\')
1104c2aa98e2SPeter Wemm 		{
1105c2aa98e2SPeter Wemm 			/* arrange to quote the address */
1106c2aa98e2SPeter Wemm 			if (cmtlev <= 0 && !qmode)
110712ed1c7cSGregory Neil Shapiro 				quoteit = true;
1108c2aa98e2SPeter Wemm 
1109c2aa98e2SPeter Wemm 			if ((c = *p++) == '\0')
1110c2aa98e2SPeter Wemm 			{
1111c2aa98e2SPeter Wemm 				/* too far */
1112c2aa98e2SPeter Wemm 				p--;
1113c2aa98e2SPeter Wemm 				goto putg;
1114c2aa98e2SPeter Wemm 			}
1115f9218d3dSGregory Neil Shapiro 			if (copylev > 0)
1116f9218d3dSGregory Neil Shapiro 				SM_APPEND_CHAR(c);
1117c2aa98e2SPeter Wemm 			goto putg;
1118c2aa98e2SPeter Wemm 		}
1119c2aa98e2SPeter Wemm 
1120c2aa98e2SPeter Wemm 		/* check for quoted strings */
1121c2aa98e2SPeter Wemm 		if (c == '"' && cmtlev <= 0)
1122c2aa98e2SPeter Wemm 		{
1123c2aa98e2SPeter Wemm 			qmode = !qmode;
1124f9218d3dSGregory Neil Shapiro 			if (copylev > 0 && SM_HAVE_ROOM)
1125f9218d3dSGregory Neil Shapiro 			{
1126f9218d3dSGregory Neil Shapiro 				if (realqmode)
1127f9218d3dSGregory Neil Shapiro 					buflim--;
1128f9218d3dSGregory Neil Shapiro 				else
1129f9218d3dSGregory Neil Shapiro 					buflim++;
1130c2aa98e2SPeter Wemm 				realqmode = !realqmode;
1131f9218d3dSGregory Neil Shapiro 			}
1132c2aa98e2SPeter Wemm 			continue;
1133c2aa98e2SPeter Wemm 		}
1134c2aa98e2SPeter Wemm 		if (qmode)
1135c2aa98e2SPeter Wemm 			goto putg;
1136c2aa98e2SPeter Wemm 
1137c2aa98e2SPeter Wemm 		/* check for comments */
1138c2aa98e2SPeter Wemm 		if (c == '(')
1139c2aa98e2SPeter Wemm 		{
1140c2aa98e2SPeter Wemm 			cmtlev++;
1141c2aa98e2SPeter Wemm 
1142c2aa98e2SPeter Wemm 			/* allow space for closing paren */
1143f9218d3dSGregory Neil Shapiro 			if (SM_HAVE_ROOM)
1144c2aa98e2SPeter Wemm 			{
1145c2aa98e2SPeter Wemm 				buflim--;
1146c2aa98e2SPeter Wemm 				realcmtlev++;
1147c2aa98e2SPeter Wemm 				if (copylev++ <= 0)
1148c2aa98e2SPeter Wemm 				{
1149c2aa98e2SPeter Wemm 					if (bp != bufhead)
1150f9218d3dSGregory Neil Shapiro 						SM_APPEND_CHAR(' ');
1151f9218d3dSGregory Neil Shapiro 					SM_APPEND_CHAR(c);
1152c2aa98e2SPeter Wemm 				}
1153c2aa98e2SPeter Wemm 			}
1154c2aa98e2SPeter Wemm 		}
1155c2aa98e2SPeter Wemm 		if (cmtlev > 0)
1156c2aa98e2SPeter Wemm 		{
1157c2aa98e2SPeter Wemm 			if (c == ')')
1158c2aa98e2SPeter Wemm 			{
1159c2aa98e2SPeter Wemm 				cmtlev--;
1160c2aa98e2SPeter Wemm 				copylev--;
1161f9218d3dSGregory Neil Shapiro 				if (SM_HAVE_ROOM)
1162c2aa98e2SPeter Wemm 				{
1163c2aa98e2SPeter Wemm 					realcmtlev--;
1164c2aa98e2SPeter Wemm 					buflim++;
1165c2aa98e2SPeter Wemm 				}
1166c2aa98e2SPeter Wemm 			}
1167c2aa98e2SPeter Wemm 			continue;
1168c2aa98e2SPeter Wemm 		}
1169c2aa98e2SPeter Wemm 		else if (c == ')')
1170c2aa98e2SPeter Wemm 		{
1171c2aa98e2SPeter Wemm 			/* syntax error: unmatched ) */
1172f9218d3dSGregory Neil Shapiro 			if (copylev > 0 && SM_HAVE_ROOM)
1173c2aa98e2SPeter Wemm 				bp--;
1174c2aa98e2SPeter Wemm 		}
1175c2aa98e2SPeter Wemm 
1176c2aa98e2SPeter Wemm 		/* count nesting on [ ... ] (for IPv6 domain literals) */
1177c2aa98e2SPeter Wemm 		if (c == '[')
1178c2aa98e2SPeter Wemm 			bracklev++;
1179c2aa98e2SPeter Wemm 		else if (c == ']')
1180c2aa98e2SPeter Wemm 			bracklev--;
1181c2aa98e2SPeter Wemm 
1182c2aa98e2SPeter Wemm 		/* check for group: list; syntax */
1183c2aa98e2SPeter Wemm 		if (c == ':' && anglelev <= 0 && bracklev <= 0 &&
1184c2aa98e2SPeter Wemm 		    !gotcolon && !ColonOkInAddr)
1185c2aa98e2SPeter Wemm 		{
1186c2aa98e2SPeter Wemm 			register char *q;
1187c2aa98e2SPeter Wemm 
1188c2aa98e2SPeter Wemm 			/*
1189c2aa98e2SPeter Wemm 			**  Check for DECnet phase IV ``::'' (host::user)
1190f9218d3dSGregory Neil Shapiro 			**  or DECnet phase V ``:.'' syntaxes.  The latter
1191c2aa98e2SPeter Wemm 			**  covers ``user@DEC:.tay.myhost'' and
1192c2aa98e2SPeter Wemm 			**  ``DEC:.tay.myhost::user'' syntaxes (bletch).
1193c2aa98e2SPeter Wemm 			*/
1194c2aa98e2SPeter Wemm 
1195c2aa98e2SPeter Wemm 			if (*p == ':' || *p == '.')
1196c2aa98e2SPeter Wemm 			{
1197c2aa98e2SPeter Wemm 				if (cmtlev <= 0 && !qmode)
119812ed1c7cSGregory Neil Shapiro 					quoteit = true;
1199f9218d3dSGregory Neil Shapiro 				if (copylev > 0)
1200c2aa98e2SPeter Wemm 				{
1201f9218d3dSGregory Neil Shapiro 					SM_APPEND_CHAR(c);
1202f9218d3dSGregory Neil Shapiro 					SM_APPEND_CHAR(*p);
1203c2aa98e2SPeter Wemm 				}
1204c2aa98e2SPeter Wemm 				p++;
1205c2aa98e2SPeter Wemm 				goto putg;
1206c2aa98e2SPeter Wemm 			}
1207c2aa98e2SPeter Wemm 
120812ed1c7cSGregory Neil Shapiro 			gotcolon = true;
1209c2aa98e2SPeter Wemm 
1210c2aa98e2SPeter Wemm 			bp = bufhead;
1211c2aa98e2SPeter Wemm 			if (quoteit)
1212c2aa98e2SPeter Wemm 			{
1213f9218d3dSGregory Neil Shapiro 				SM_APPEND_CHAR('"');
1214c2aa98e2SPeter Wemm 
1215c2aa98e2SPeter Wemm 				/* back up over the ':' and any spaces */
1216c2aa98e2SPeter Wemm 				--p;
1217f9218d3dSGregory Neil Shapiro 				while (p > addr &&
1218f9218d3dSGregory Neil Shapiro 				       isascii(*--p) && isspace(*p))
1219c2aa98e2SPeter Wemm 					continue;
1220c2aa98e2SPeter Wemm 				p++;
1221c2aa98e2SPeter Wemm 			}
1222c2aa98e2SPeter Wemm 			for (q = addrhead; q < p; )
1223c2aa98e2SPeter Wemm 			{
1224c2aa98e2SPeter Wemm 				c = *q++;
1225c2aa98e2SPeter Wemm 				if (quoteit && c == '"')
1226f9218d3dSGregory Neil Shapiro 				{
1227f9218d3dSGregory Neil Shapiro 					SM_APPEND_CHAR('\\');
1228f9218d3dSGregory Neil Shapiro 					SM_APPEND_CHAR(c);
1229c2aa98e2SPeter Wemm 				}
1230f9218d3dSGregory Neil Shapiro 				else
1231f9218d3dSGregory Neil Shapiro 					SM_APPEND_CHAR(c);
1232c2aa98e2SPeter Wemm 			}
1233c2aa98e2SPeter Wemm 			if (quoteit)
1234c2aa98e2SPeter Wemm 			{
1235c2aa98e2SPeter Wemm 				if (bp == &bufhead[1])
1236c2aa98e2SPeter Wemm 					bp--;
1237c2aa98e2SPeter Wemm 				else
1238f9218d3dSGregory Neil Shapiro 					SM_APPEND_CHAR('"');
1239c2aa98e2SPeter Wemm 				while ((c = *p++) != ':')
1240f9218d3dSGregory Neil Shapiro 					SM_APPEND_CHAR(c);
1241f9218d3dSGregory Neil Shapiro 				SM_APPEND_CHAR(c);
1242c2aa98e2SPeter Wemm 			}
1243c2aa98e2SPeter Wemm 
1244c2aa98e2SPeter Wemm 			/* any trailing white space is part of group: */
1245f9218d3dSGregory Neil Shapiro 			while (isascii(*p) && isspace(*p))
1246f9218d3dSGregory Neil Shapiro 			{
1247f9218d3dSGregory Neil Shapiro 				SM_APPEND_CHAR(*p);
1248f9218d3dSGregory Neil Shapiro 				p++;
1249f9218d3dSGregory Neil Shapiro 			}
1250c2aa98e2SPeter Wemm 			copylev = 0;
125112ed1c7cSGregory Neil Shapiro 			putgmac = quoteit = false;
1252c2aa98e2SPeter Wemm 			bufhead = bp;
1253c2aa98e2SPeter Wemm 			addrhead = p;
1254c2aa98e2SPeter Wemm 			continue;
1255c2aa98e2SPeter Wemm 		}
1256c2aa98e2SPeter Wemm 
1257c2aa98e2SPeter Wemm 		if (c == ';' && copylev <= 0 && !ColonOkInAddr)
1258f9218d3dSGregory Neil Shapiro 			SM_APPEND_CHAR(c);
1259c2aa98e2SPeter Wemm 
1260c2aa98e2SPeter Wemm 		/* check for characters that may have to be quoted */
1261c2aa98e2SPeter Wemm 		if (strchr(MustQuoteChars, c) != NULL)
1262c2aa98e2SPeter Wemm 		{
1263c2aa98e2SPeter Wemm 			/*
1264c2aa98e2SPeter Wemm 			**  If these occur as the phrase part of a <>
1265c2aa98e2SPeter Wemm 			**  construct, but are not inside of () or already
1266c2aa98e2SPeter Wemm 			**  quoted, they will have to be quoted.  Note that
1267c2aa98e2SPeter Wemm 			**  now (but don't actually do the quoting).
1268c2aa98e2SPeter Wemm 			*/
1269c2aa98e2SPeter Wemm 
1270c2aa98e2SPeter Wemm 			if (cmtlev <= 0 && !qmode)
127112ed1c7cSGregory Neil Shapiro 				quoteit = true;
1272c2aa98e2SPeter Wemm 		}
1273c2aa98e2SPeter Wemm 
1274c2aa98e2SPeter Wemm 		/* check for angle brackets */
1275c2aa98e2SPeter Wemm 		if (c == '<')
1276c2aa98e2SPeter Wemm 		{
1277c2aa98e2SPeter Wemm 			register char *q;
1278c2aa98e2SPeter Wemm 
1279c2aa98e2SPeter Wemm 			/* assume first of two angles is bogus */
1280c2aa98e2SPeter Wemm 			if (gotangle)
128112ed1c7cSGregory Neil Shapiro 				quoteit = true;
128212ed1c7cSGregory Neil Shapiro 			gotangle = true;
1283c2aa98e2SPeter Wemm 
1284c2aa98e2SPeter Wemm 			/* oops -- have to change our mind */
1285c2aa98e2SPeter Wemm 			anglelev = 1;
1286f9218d3dSGregory Neil Shapiro 			if (SM_HAVE_ROOM)
1287f9218d3dSGregory Neil Shapiro 			{
1288f9218d3dSGregory Neil Shapiro 				if (!addangle)
1289f9218d3dSGregory Neil Shapiro 					buflim--;
1290f9218d3dSGregory Neil Shapiro 				addangle = true;
1291f9218d3dSGregory Neil Shapiro 			}
1292c2aa98e2SPeter Wemm 
1293c2aa98e2SPeter Wemm 			bp = bufhead;
1294c2aa98e2SPeter Wemm 			if (quoteit)
1295c2aa98e2SPeter Wemm 			{
1296f9218d3dSGregory Neil Shapiro 				SM_APPEND_CHAR('"');
1297c2aa98e2SPeter Wemm 
1298c2aa98e2SPeter Wemm 				/* back up over the '<' and any spaces */
1299c2aa98e2SPeter Wemm 				--p;
1300f9218d3dSGregory Neil Shapiro 				while (p > addr &&
1301f9218d3dSGregory Neil Shapiro 				       isascii(*--p) && isspace(*p))
1302c2aa98e2SPeter Wemm 					continue;
1303c2aa98e2SPeter Wemm 				p++;
1304c2aa98e2SPeter Wemm 			}
1305c2aa98e2SPeter Wemm 			for (q = addrhead; q < p; )
1306c2aa98e2SPeter Wemm 			{
1307c2aa98e2SPeter Wemm 				c = *q++;
1308c2aa98e2SPeter Wemm 				if (quoteit && c == '"')
1309f9218d3dSGregory Neil Shapiro 				{
1310f9218d3dSGregory Neil Shapiro 					SM_APPEND_CHAR('\\');
1311f9218d3dSGregory Neil Shapiro 					SM_APPEND_CHAR(c);
1312c2aa98e2SPeter Wemm 				}
1313f9218d3dSGregory Neil Shapiro 				else
1314f9218d3dSGregory Neil Shapiro 					SM_APPEND_CHAR(c);
1315c2aa98e2SPeter Wemm 			}
1316c2aa98e2SPeter Wemm 			if (quoteit)
1317c2aa98e2SPeter Wemm 			{
1318c2aa98e2SPeter Wemm 				if (bp == &buf[1])
1319c2aa98e2SPeter Wemm 					bp--;
1320c2aa98e2SPeter Wemm 				else
1321f9218d3dSGregory Neil Shapiro 					SM_APPEND_CHAR('"');
1322c2aa98e2SPeter Wemm 				while ((c = *p++) != '<')
1323f9218d3dSGregory Neil Shapiro 					SM_APPEND_CHAR(c);
1324f9218d3dSGregory Neil Shapiro 				SM_APPEND_CHAR(c);
1325c2aa98e2SPeter Wemm 			}
1326c2aa98e2SPeter Wemm 			copylev = 0;
132712ed1c7cSGregory Neil Shapiro 			putgmac = quoteit = false;
1328c2aa98e2SPeter Wemm 			continue;
1329c2aa98e2SPeter Wemm 		}
1330c2aa98e2SPeter Wemm 
1331c2aa98e2SPeter Wemm 		if (c == '>')
1332c2aa98e2SPeter Wemm 		{
1333c2aa98e2SPeter Wemm 			if (anglelev > 0)
1334c2aa98e2SPeter Wemm 			{
1335c2aa98e2SPeter Wemm 				anglelev--;
1336f9218d3dSGregory Neil Shapiro 				if (SM_HAVE_ROOM)
1337c2aa98e2SPeter Wemm 				{
1338f9218d3dSGregory Neil Shapiro 					if (addangle)
1339c2aa98e2SPeter Wemm 						buflim++;
1340f9218d3dSGregory Neil Shapiro 					addangle = false;
1341c2aa98e2SPeter Wemm 				}
1342c2aa98e2SPeter Wemm 			}
1343f9218d3dSGregory Neil Shapiro 			else if (SM_HAVE_ROOM)
1344c2aa98e2SPeter Wemm 			{
1345c2aa98e2SPeter Wemm 				/* syntax error: unmatched > */
1346c2aa98e2SPeter Wemm 				if (copylev > 0)
1347c2aa98e2SPeter Wemm 					bp--;
134812ed1c7cSGregory Neil Shapiro 				quoteit = true;
1349c2aa98e2SPeter Wemm 				continue;
1350c2aa98e2SPeter Wemm 			}
1351c2aa98e2SPeter Wemm 			if (copylev++ <= 0)
1352f9218d3dSGregory Neil Shapiro 				SM_APPEND_CHAR(c);
1353c2aa98e2SPeter Wemm 			continue;
1354c2aa98e2SPeter Wemm 		}
1355c2aa98e2SPeter Wemm 
1356c2aa98e2SPeter Wemm 		/* must be a real address character */
1357c2aa98e2SPeter Wemm 	putg:
1358c2aa98e2SPeter Wemm 		if (copylev <= 0 && !putgmac)
1359c2aa98e2SPeter Wemm 		{
1360f9218d3dSGregory Neil Shapiro 			if (bp > buf && bp[-1] == ')')
1361f9218d3dSGregory Neil Shapiro 				SM_APPEND_CHAR(' ');
1362f9218d3dSGregory Neil Shapiro 			SM_APPEND_CHAR(MACROEXPAND);
1363f9218d3dSGregory Neil Shapiro 			SM_APPEND_CHAR('g');
136412ed1c7cSGregory Neil Shapiro 			putgmac = true;
1365c2aa98e2SPeter Wemm 		}
1366c2aa98e2SPeter Wemm 	}
1367c2aa98e2SPeter Wemm 
1368c2aa98e2SPeter Wemm 	/* repair any syntactic damage */
1369f9218d3dSGregory Neil Shapiro 	if (realqmode && bp < bufend)
1370c2aa98e2SPeter Wemm 		*bp++ = '"';
1371f9218d3dSGregory Neil Shapiro 	while (realcmtlev-- > 0 && bp < bufend)
1372c2aa98e2SPeter Wemm 		*bp++ = ')';
1373f9218d3dSGregory Neil Shapiro 	if (addangle && bp < bufend)
1374c2aa98e2SPeter Wemm 		*bp++ = '>';
1375f9218d3dSGregory Neil Shapiro 	*bp = '\0';
1376f9218d3dSGregory Neil Shapiro 	if (bp < bufend)
1377f9218d3dSGregory Neil Shapiro 		goto success;
1378c2aa98e2SPeter Wemm 
1379f9218d3dSGregory Neil Shapiro  returng:
1380f9218d3dSGregory Neil Shapiro 	/* String too long, punt */
1381f9218d3dSGregory Neil Shapiro 	buf[0] = '<';
1382f9218d3dSGregory Neil Shapiro 	buf[1] = MACROEXPAND;
1383f9218d3dSGregory Neil Shapiro 	buf[2]= 'g';
1384f9218d3dSGregory Neil Shapiro 	buf[3] = '>';
1385f9218d3dSGregory Neil Shapiro 	buf[4]= '\0';
1386f9218d3dSGregory Neil Shapiro 	sm_syslog(LOG_ALERT, e->e_id,
1387f9218d3dSGregory Neil Shapiro 		  "Dropped invalid comments from header address");
1388f9218d3dSGregory Neil Shapiro 
1389f9218d3dSGregory Neil Shapiro  success:
1390c2aa98e2SPeter Wemm 	if (tTd(33, 1))
1391c2aa98e2SPeter Wemm 	{
139212ed1c7cSGregory Neil Shapiro 		sm_dprintf("crackaddr=>`");
1393c2aa98e2SPeter Wemm 		xputs(buf);
139412ed1c7cSGregory Neil Shapiro 		sm_dprintf("'\n");
1395c2aa98e2SPeter Wemm 	}
13963299c2f1SGregory Neil Shapiro 	return buf;
1397c2aa98e2SPeter Wemm }
139812ed1c7cSGregory Neil Shapiro /*
1399c2aa98e2SPeter Wemm **  PUTHEADER -- put the header part of a message from the in-core copy
1400c2aa98e2SPeter Wemm **
1401c2aa98e2SPeter Wemm **	Parameters:
1402c2aa98e2SPeter Wemm **		mci -- the connection information.
14033299c2f1SGregory Neil Shapiro **		hdr -- the header to put.
1404c2aa98e2SPeter Wemm **		e -- envelope to use.
1405e01d6f61SPeter Wemm **		flags -- MIME conversion flags.
1406c2aa98e2SPeter Wemm **
1407c2aa98e2SPeter Wemm **	Returns:
1408c2aa98e2SPeter Wemm **		none.
1409c2aa98e2SPeter Wemm **
1410c2aa98e2SPeter Wemm **	Side Effects:
1411c2aa98e2SPeter Wemm **		none.
1412c2aa98e2SPeter Wemm */
1413c2aa98e2SPeter Wemm 
1414c2aa98e2SPeter Wemm void
1415e01d6f61SPeter Wemm putheader(mci, hdr, e, flags)
1416c2aa98e2SPeter Wemm 	register MCI *mci;
1417c2aa98e2SPeter Wemm 	HDR *hdr;
1418c2aa98e2SPeter Wemm 	register ENVELOPE *e;
1419e01d6f61SPeter Wemm 	int flags;
1420c2aa98e2SPeter Wemm {
1421c2aa98e2SPeter Wemm 	register HDR *h;
142212ed1c7cSGregory Neil Shapiro 	char buf[SM_MAX(MAXLINE,BUFSIZ)];
1423c2aa98e2SPeter Wemm 	char obuf[MAXLINE];
1424c2aa98e2SPeter Wemm 
1425c2aa98e2SPeter Wemm 	if (tTd(34, 1))
142612ed1c7cSGregory Neil Shapiro 		sm_dprintf("--- putheader, mailer = %s ---\n",
1427c2aa98e2SPeter Wemm 			mci->mci_mailer->m_name);
1428c2aa98e2SPeter Wemm 
1429c2aa98e2SPeter Wemm 	/*
1430c2aa98e2SPeter Wemm 	**  If we're in MIME mode, we're not really in the header of the
1431c2aa98e2SPeter Wemm 	**  message, just the header of one of the parts of the body of
1432c2aa98e2SPeter Wemm 	**  the message.  Therefore MCIF_INHEADER should not be turned on.
1433c2aa98e2SPeter Wemm 	*/
1434c2aa98e2SPeter Wemm 
1435c2aa98e2SPeter Wemm 	if (!bitset(MCIF_INMIME, mci->mci_flags))
1436c2aa98e2SPeter Wemm 		mci->mci_flags |= MCIF_INHEADER;
1437c2aa98e2SPeter Wemm 
1438c2aa98e2SPeter Wemm 	for (h = hdr; h != NULL; h = h->h_link)
1439c2aa98e2SPeter Wemm 	{
1440c2aa98e2SPeter Wemm 		register char *p = h->h_value;
144112ed1c7cSGregory Neil Shapiro 		char *q;
1442c2aa98e2SPeter Wemm 
1443c2aa98e2SPeter Wemm 		if (tTd(34, 11))
1444c2aa98e2SPeter Wemm 		{
144512ed1c7cSGregory Neil Shapiro 			sm_dprintf("  %s: ", h->h_field);
1446c2aa98e2SPeter Wemm 			xputs(p);
1447c2aa98e2SPeter Wemm 		}
1448c2aa98e2SPeter Wemm 
14493299c2f1SGregory Neil Shapiro 		/* Skip empty headers */
14503299c2f1SGregory Neil Shapiro 		if (h->h_value == NULL)
14513299c2f1SGregory Neil Shapiro 			continue;
14523299c2f1SGregory Neil Shapiro 
145376b7bf71SPeter Wemm 		/* heuristic shortening of MIME fields to avoid MUA overflows */
145476b7bf71SPeter Wemm 		if (MaxMimeFieldLength > 0 &&
145576b7bf71SPeter Wemm 		    wordinclass(h->h_field,
145612ed1c7cSGregory Neil Shapiro 				macid("{checkMIMEFieldHeaders}")))
145776b7bf71SPeter Wemm 		{
1458c46d91b7SGregory Neil Shapiro 			size_t len;
1459c46d91b7SGregory Neil Shapiro 
1460f9218d3dSGregory Neil Shapiro 			len = fix_mime_header(h, e);
1461c46d91b7SGregory Neil Shapiro 			if (len > 0)
146276b7bf71SPeter Wemm 			{
146376b7bf71SPeter Wemm 				sm_syslog(LOG_ALERT, e->e_id,
1464c46d91b7SGregory Neil Shapiro 					  "Truncated MIME %s header due to field size (length = %ld) (possible attack)",
1465c46d91b7SGregory Neil Shapiro 					  h->h_field, (unsigned long) len);
146676b7bf71SPeter Wemm 				if (tTd(34, 11))
146712ed1c7cSGregory Neil Shapiro 					sm_dprintf("  truncated MIME %s header due to field size  (length = %ld) (possible attack)\n",
1468c46d91b7SGregory Neil Shapiro 						   h->h_field,
1469c46d91b7SGregory Neil Shapiro 						   (unsigned long) len);
147076b7bf71SPeter Wemm 			}
147176b7bf71SPeter Wemm 		}
147276b7bf71SPeter Wemm 
147376b7bf71SPeter Wemm 		if (MaxMimeHeaderLength > 0 &&
147476b7bf71SPeter Wemm 		    wordinclass(h->h_field,
147512ed1c7cSGregory Neil Shapiro 				macid("{checkMIMETextHeaders}")))
147676b7bf71SPeter Wemm 		{
1477c46d91b7SGregory Neil Shapiro 			size_t len;
1478c46d91b7SGregory Neil Shapiro 
1479c46d91b7SGregory Neil Shapiro 			len = strlen(h->h_value);
1480c46d91b7SGregory Neil Shapiro 			if (len > (size_t) MaxMimeHeaderLength)
148176b7bf71SPeter Wemm 			{
148276b7bf71SPeter Wemm 				h->h_value[MaxMimeHeaderLength - 1] = '\0';
148376b7bf71SPeter Wemm 				sm_syslog(LOG_ALERT, e->e_id,
1484c46d91b7SGregory Neil Shapiro 					  "Truncated long MIME %s header (length = %ld) (possible attack)",
1485c46d91b7SGregory Neil Shapiro 					  h->h_field, (unsigned long) len);
148676b7bf71SPeter Wemm 				if (tTd(34, 11))
148712ed1c7cSGregory Neil Shapiro 					sm_dprintf("  truncated long MIME %s header (length = %ld) (possible attack)\n",
1488c46d91b7SGregory Neil Shapiro 						   h->h_field,
1489c46d91b7SGregory Neil Shapiro 						   (unsigned long) len);
149076b7bf71SPeter Wemm 			}
149176b7bf71SPeter Wemm 		}
149276b7bf71SPeter Wemm 
149376b7bf71SPeter Wemm 		if (MaxMimeHeaderLength > 0 &&
149476b7bf71SPeter Wemm 		    wordinclass(h->h_field,
149512ed1c7cSGregory Neil Shapiro 				macid("{checkMIMEHeaders}")))
149676b7bf71SPeter Wemm 		{
1497c46d91b7SGregory Neil Shapiro 			size_t len;
1498c46d91b7SGregory Neil Shapiro 
1499c46d91b7SGregory Neil Shapiro 			len = strlen(h->h_value);
1500c46d91b7SGregory Neil Shapiro 			if (shorten_rfc822_string(h->h_value,
1501c46d91b7SGregory Neil Shapiro 						  MaxMimeHeaderLength))
150276b7bf71SPeter Wemm 			{
1503f9218d3dSGregory Neil Shapiro 				if (len < MaxMimeHeaderLength)
1504f9218d3dSGregory Neil Shapiro 				{
1505f9218d3dSGregory Neil Shapiro 					/* we only rebalanced a bogus header */
1506f9218d3dSGregory Neil Shapiro 					sm_syslog(LOG_ALERT, e->e_id,
1507f9218d3dSGregory Neil Shapiro 						  "Fixed MIME %s header (possible attack)",
1508f9218d3dSGregory Neil Shapiro 						  h->h_field);
1509f9218d3dSGregory Neil Shapiro 					if (tTd(34, 11))
1510f9218d3dSGregory Neil Shapiro 						sm_dprintf("  fixed MIME %s header (possible attack)\n",
1511f9218d3dSGregory Neil Shapiro 							   h->h_field);
1512f9218d3dSGregory Neil Shapiro 				}
1513f9218d3dSGregory Neil Shapiro 				else
1514f9218d3dSGregory Neil Shapiro 				{
1515f9218d3dSGregory Neil Shapiro 					/* we actually shortened header */
151676b7bf71SPeter Wemm 					sm_syslog(LOG_ALERT, e->e_id,
1517c46d91b7SGregory Neil Shapiro 						  "Truncated long MIME %s header (length = %ld) (possible attack)",
1518f9218d3dSGregory Neil Shapiro 						  h->h_field,
1519f9218d3dSGregory Neil Shapiro 						  (unsigned long) len);
152076b7bf71SPeter Wemm 					if (tTd(34, 11))
152112ed1c7cSGregory Neil Shapiro 						sm_dprintf("  truncated long MIME %s header (length = %ld) (possible attack)\n",
1522c46d91b7SGregory Neil Shapiro 							   h->h_field,
1523c46d91b7SGregory Neil Shapiro 							   (unsigned long) len);
152476b7bf71SPeter Wemm 				}
152576b7bf71SPeter Wemm 			}
1526f9218d3dSGregory Neil Shapiro 		}
152776b7bf71SPeter Wemm 
1528e01d6f61SPeter Wemm 		/*
1529e01d6f61SPeter Wemm 		**  Suppress Content-Transfer-Encoding: if we are MIMEing
1530e01d6f61SPeter Wemm 		**  and we are potentially converting from 8 bit to 7 bit
1531e01d6f61SPeter Wemm 		**  MIME.  If converting, add a new CTE header in
1532e01d6f61SPeter Wemm 		**  mime8to7().
1533e01d6f61SPeter Wemm 		*/
153412ed1c7cSGregory Neil Shapiro 
1535c2aa98e2SPeter Wemm 		if (bitset(H_CTE, h->h_flags) &&
1536e01d6f61SPeter Wemm 		    bitset(MCIF_CVT8TO7|MCIF_CVT7TO8|MCIF_INMIME,
1537e01d6f61SPeter Wemm 			   mci->mci_flags) &&
1538e01d6f61SPeter Wemm 		    !bitset(M87F_NO8TO7, flags))
1539c2aa98e2SPeter Wemm 		{
1540c2aa98e2SPeter Wemm 			if (tTd(34, 11))
154112ed1c7cSGregory Neil Shapiro 				sm_dprintf(" (skipped (content-transfer-encoding))\n");
1542c2aa98e2SPeter Wemm 			continue;
1543c2aa98e2SPeter Wemm 		}
1544c2aa98e2SPeter Wemm 
1545c2aa98e2SPeter Wemm 		if (bitset(MCIF_INMIME, mci->mci_flags))
1546c2aa98e2SPeter Wemm 		{
1547c2aa98e2SPeter Wemm 			if (tTd(34, 11))
154812ed1c7cSGregory Neil Shapiro 				sm_dprintf("\n");
1549c2aa98e2SPeter Wemm 			put_vanilla_header(h, p, mci);
1550c2aa98e2SPeter Wemm 			continue;
1551c2aa98e2SPeter Wemm 		}
1552c2aa98e2SPeter Wemm 
1553c2aa98e2SPeter Wemm 		if (bitset(H_CHECK|H_ACHECK, h->h_flags) &&
15543299c2f1SGregory Neil Shapiro 		    !bitintersect(h->h_mflags, mci->mci_mailer->m_flags) &&
15553299c2f1SGregory Neil Shapiro 		    (h->h_macro == '\0' ||
155612ed1c7cSGregory Neil Shapiro 		     (q = macvalue(bitidx(h->h_macro), e)) == NULL ||
155712ed1c7cSGregory Neil Shapiro 		     *q == '\0'))
1558c2aa98e2SPeter Wemm 		{
1559c2aa98e2SPeter Wemm 			if (tTd(34, 11))
156012ed1c7cSGregory Neil Shapiro 				sm_dprintf(" (skipped)\n");
1561c2aa98e2SPeter Wemm 			continue;
1562c2aa98e2SPeter Wemm 		}
1563c2aa98e2SPeter Wemm 
1564c2aa98e2SPeter Wemm 		/* handle Resent-... headers specially */
1565c2aa98e2SPeter Wemm 		if (bitset(H_RESENT, h->h_flags) && !bitset(EF_RESENT, e->e_flags))
1566c2aa98e2SPeter Wemm 		{
1567c2aa98e2SPeter Wemm 			if (tTd(34, 11))
156812ed1c7cSGregory Neil Shapiro 				sm_dprintf(" (skipped (resent))\n");
1569c2aa98e2SPeter Wemm 			continue;
1570c2aa98e2SPeter Wemm 		}
1571c2aa98e2SPeter Wemm 
1572c2aa98e2SPeter Wemm 		/* suppress return receipts if requested */
1573c2aa98e2SPeter Wemm 		if (bitset(H_RECEIPTTO, h->h_flags) &&
1574c2aa98e2SPeter Wemm 		    (RrtImpliesDsn || bitset(EF_NORECEIPT, e->e_flags)))
1575c2aa98e2SPeter Wemm 		{
1576c2aa98e2SPeter Wemm 			if (tTd(34, 11))
157712ed1c7cSGregory Neil Shapiro 				sm_dprintf(" (skipped (receipt))\n");
1578c2aa98e2SPeter Wemm 			continue;
1579c2aa98e2SPeter Wemm 		}
1580c2aa98e2SPeter Wemm 
1581c2aa98e2SPeter Wemm 		/* macro expand value if generated internally */
15823299c2f1SGregory Neil Shapiro 		if (bitset(H_DEFAULT, h->h_flags) ||
15833299c2f1SGregory Neil Shapiro 		    bitset(H_BINDLATE, h->h_flags))
1584c2aa98e2SPeter Wemm 		{
1585c2aa98e2SPeter Wemm 			expand(p, buf, sizeof buf, e);
1586c2aa98e2SPeter Wemm 			p = buf;
1587c2aa98e2SPeter Wemm 			if (*p == '\0')
1588c2aa98e2SPeter Wemm 			{
1589c2aa98e2SPeter Wemm 				if (tTd(34, 11))
159012ed1c7cSGregory Neil Shapiro 					sm_dprintf(" (skipped -- null value)\n");
1591c2aa98e2SPeter Wemm 				continue;
1592c2aa98e2SPeter Wemm 			}
1593c2aa98e2SPeter Wemm 		}
1594c2aa98e2SPeter Wemm 
1595c2aa98e2SPeter Wemm 		if (bitset(H_BCC, h->h_flags))
1596c2aa98e2SPeter Wemm 		{
1597c2aa98e2SPeter Wemm 			/* Bcc: field -- either truncate or delete */
1598c2aa98e2SPeter Wemm 			if (bitset(EF_DELETE_BCC, e->e_flags))
1599c2aa98e2SPeter Wemm 			{
1600c2aa98e2SPeter Wemm 				if (tTd(34, 11))
160112ed1c7cSGregory Neil Shapiro 					sm_dprintf(" (skipped -- bcc)\n");
1602c2aa98e2SPeter Wemm 			}
1603c2aa98e2SPeter Wemm 			else
1604c2aa98e2SPeter Wemm 			{
1605c2aa98e2SPeter Wemm 				/* no other recipient headers: truncate value */
160612ed1c7cSGregory Neil Shapiro 				(void) sm_strlcpyn(obuf, sizeof obuf, 2,
160712ed1c7cSGregory Neil Shapiro 						   h->h_field, ":");
1608c2aa98e2SPeter Wemm 				putline(obuf, mci);
1609c2aa98e2SPeter Wemm 			}
1610c2aa98e2SPeter Wemm 			continue;
1611c2aa98e2SPeter Wemm 		}
1612c2aa98e2SPeter Wemm 
1613c2aa98e2SPeter Wemm 		if (tTd(34, 11))
161412ed1c7cSGregory Neil Shapiro 			sm_dprintf("\n");
1615c2aa98e2SPeter Wemm 
1616c2aa98e2SPeter Wemm 		if (bitset(H_FROM|H_RCPT, h->h_flags))
1617c2aa98e2SPeter Wemm 		{
1618c2aa98e2SPeter Wemm 			/* address field */
1619c2aa98e2SPeter Wemm 			bool oldstyle = bitset(EF_OLDSTYLE, e->e_flags);
1620c2aa98e2SPeter Wemm 
1621c2aa98e2SPeter Wemm 			if (bitset(H_FROM, h->h_flags))
162212ed1c7cSGregory Neil Shapiro 				oldstyle = false;
1623c2aa98e2SPeter Wemm 			commaize(h, p, oldstyle, mci, e);
1624c2aa98e2SPeter Wemm 		}
1625c2aa98e2SPeter Wemm 		else
1626c2aa98e2SPeter Wemm 		{
1627c2aa98e2SPeter Wemm 			put_vanilla_header(h, p, mci);
1628c2aa98e2SPeter Wemm 		}
1629c2aa98e2SPeter Wemm 	}
1630c2aa98e2SPeter Wemm 
1631c2aa98e2SPeter Wemm 	/*
1632c2aa98e2SPeter Wemm 	**  If we are converting this to a MIME message, add the
16333299c2f1SGregory Neil Shapiro 	**  MIME headers (but not in MIME mode!).
1634c2aa98e2SPeter Wemm 	*/
1635c2aa98e2SPeter Wemm 
1636c2aa98e2SPeter Wemm #if MIME8TO7
1637c2aa98e2SPeter Wemm 	if (bitset(MM_MIME8BIT, MimeMode) &&
1638c2aa98e2SPeter Wemm 	    bitset(EF_HAS8BIT, e->e_flags) &&
1639c2aa98e2SPeter Wemm 	    !bitset(EF_DONT_MIME, e->e_flags) &&
1640c2aa98e2SPeter Wemm 	    !bitnset(M_8BITS, mci->mci_mailer->m_flags) &&
16413299c2f1SGregory Neil Shapiro 	    !bitset(MCIF_CVT8TO7|MCIF_CVT7TO8|MCIF_INMIME, mci->mci_flags) &&
16423299c2f1SGregory Neil Shapiro 	    hvalue("MIME-Version", e->e_header) == NULL)
1643c2aa98e2SPeter Wemm 	{
1644c2aa98e2SPeter Wemm 		putline("MIME-Version: 1.0", mci);
1645c2aa98e2SPeter Wemm 		if (hvalue("Content-Type", e->e_header) == NULL)
1646c2aa98e2SPeter Wemm 		{
164712ed1c7cSGregory Neil Shapiro 			(void) sm_snprintf(obuf, sizeof obuf,
1648c2aa98e2SPeter Wemm 					"Content-Type: text/plain; charset=%s",
1649c2aa98e2SPeter Wemm 					defcharset(e));
1650c2aa98e2SPeter Wemm 			putline(obuf, mci);
1651c2aa98e2SPeter Wemm 		}
1652c2aa98e2SPeter Wemm 		if (hvalue("Content-Transfer-Encoding", e->e_header) == NULL)
1653c2aa98e2SPeter Wemm 			putline("Content-Transfer-Encoding: 8bit", mci);
1654c2aa98e2SPeter Wemm 	}
16553299c2f1SGregory Neil Shapiro #endif /* MIME8TO7 */
1656c2aa98e2SPeter Wemm }
165712ed1c7cSGregory Neil Shapiro /*
1658c2aa98e2SPeter Wemm **  PUT_VANILLA_HEADER -- output a fairly ordinary header
1659c2aa98e2SPeter Wemm **
1660c2aa98e2SPeter Wemm **	Parameters:
1661c2aa98e2SPeter Wemm **		h -- the structure describing this header
1662c2aa98e2SPeter Wemm **		v -- the value of this header
1663c2aa98e2SPeter Wemm **		mci -- the connection info for output
1664c2aa98e2SPeter Wemm **
1665c2aa98e2SPeter Wemm **	Returns:
1666c2aa98e2SPeter Wemm **		none.
1667c2aa98e2SPeter Wemm */
1668c2aa98e2SPeter Wemm 
16693299c2f1SGregory Neil Shapiro static void
1670c2aa98e2SPeter Wemm put_vanilla_header(h, v, mci)
1671c2aa98e2SPeter Wemm 	HDR *h;
1672c2aa98e2SPeter Wemm 	char *v;
1673c2aa98e2SPeter Wemm 	MCI *mci;
1674c2aa98e2SPeter Wemm {
1675c2aa98e2SPeter Wemm 	register char *nlp;
1676c2aa98e2SPeter Wemm 	register char *obp;
1677c2aa98e2SPeter Wemm 	int putflags;
1678c2aa98e2SPeter Wemm 	char obuf[MAXLINE];
1679c2aa98e2SPeter Wemm 
1680c2aa98e2SPeter Wemm 	putflags = PXLF_HEADER;
1681c2aa98e2SPeter Wemm 	if (bitnset(M_7BITHDRS, mci->mci_mailer->m_flags))
1682c2aa98e2SPeter Wemm 		putflags |= PXLF_STRIP8BIT;
168312ed1c7cSGregory Neil Shapiro 	(void) sm_snprintf(obuf, sizeof obuf, "%.200s: ", h->h_field);
1684c2aa98e2SPeter Wemm 	obp = obuf + strlen(obuf);
1685c2aa98e2SPeter Wemm 	while ((nlp = strchr(v, '\n')) != NULL)
1686c2aa98e2SPeter Wemm 	{
1687c2aa98e2SPeter Wemm 		int l;
1688c2aa98e2SPeter Wemm 
1689c2aa98e2SPeter Wemm 		l = nlp - v;
16903299c2f1SGregory Neil Shapiro 		if (SPACELEFT(obuf, obp) - 1 < (size_t) l)
1691c2aa98e2SPeter Wemm 			l = SPACELEFT(obuf, obp) - 1;
1692c2aa98e2SPeter Wemm 
169312ed1c7cSGregory Neil Shapiro 		(void) sm_snprintf(obp, SPACELEFT(obuf, obp), "%.*s", l, v);
1694c2aa98e2SPeter Wemm 		putxline(obuf, strlen(obuf), mci, putflags);
1695c2aa98e2SPeter Wemm 		v += l + 1;
1696c2aa98e2SPeter Wemm 		obp = obuf;
1697c2aa98e2SPeter Wemm 		if (*v != ' ' && *v != '\t')
1698c2aa98e2SPeter Wemm 			*obp++ = ' ';
1699c2aa98e2SPeter Wemm 	}
170012ed1c7cSGregory Neil Shapiro 	(void) sm_snprintf(obp, SPACELEFT(obuf, obp), "%.*s",
170112ed1c7cSGregory Neil Shapiro 			   (int) (SPACELEFT(obuf, obp) - 1), v);
1702c2aa98e2SPeter Wemm 	putxline(obuf, strlen(obuf), mci, putflags);
1703c2aa98e2SPeter Wemm }
170412ed1c7cSGregory Neil Shapiro /*
1705c2aa98e2SPeter Wemm **  COMMAIZE -- output a header field, making a comma-translated list.
1706c2aa98e2SPeter Wemm **
1707c2aa98e2SPeter Wemm **	Parameters:
1708c2aa98e2SPeter Wemm **		h -- the header field to output.
1709c2aa98e2SPeter Wemm **		p -- the value to put in it.
171012ed1c7cSGregory Neil Shapiro **		oldstyle -- true if this is an old style header.
1711c2aa98e2SPeter Wemm **		mci -- the connection information.
1712c2aa98e2SPeter Wemm **		e -- the envelope containing the message.
1713c2aa98e2SPeter Wemm **
1714c2aa98e2SPeter Wemm **	Returns:
1715c2aa98e2SPeter Wemm **		none.
1716c2aa98e2SPeter Wemm **
1717c2aa98e2SPeter Wemm **	Side Effects:
1718c2aa98e2SPeter Wemm **		outputs "p" to file "fp".
1719c2aa98e2SPeter Wemm */
1720c2aa98e2SPeter Wemm 
1721c2aa98e2SPeter Wemm void
1722c2aa98e2SPeter Wemm commaize(h, p, oldstyle, mci, e)
1723c2aa98e2SPeter Wemm 	register HDR *h;
1724c2aa98e2SPeter Wemm 	register char *p;
1725c2aa98e2SPeter Wemm 	bool oldstyle;
1726c2aa98e2SPeter Wemm 	register MCI *mci;
1727c2aa98e2SPeter Wemm 	register ENVELOPE *e;
1728c2aa98e2SPeter Wemm {
1729c2aa98e2SPeter Wemm 	register char *obp;
1730c2aa98e2SPeter Wemm 	int opos;
1731c2aa98e2SPeter Wemm 	int omax;
173212ed1c7cSGregory Neil Shapiro 	bool firstone = true;
1733c2aa98e2SPeter Wemm 	int putflags = PXLF_HEADER;
1734c2aa98e2SPeter Wemm 	char obuf[MAXLINE + 3];
1735c2aa98e2SPeter Wemm 
1736c2aa98e2SPeter Wemm 	/*
1737c2aa98e2SPeter Wemm 	**  Output the address list translated by the
1738c2aa98e2SPeter Wemm 	**  mailer and with commas.
1739c2aa98e2SPeter Wemm 	*/
1740c2aa98e2SPeter Wemm 
1741c2aa98e2SPeter Wemm 	if (tTd(14, 2))
174212ed1c7cSGregory Neil Shapiro 		sm_dprintf("commaize(%s: %s)\n", h->h_field, p);
1743c2aa98e2SPeter Wemm 
1744c2aa98e2SPeter Wemm 	if (bitnset(M_7BITHDRS, mci->mci_mailer->m_flags))
1745c2aa98e2SPeter Wemm 		putflags |= PXLF_STRIP8BIT;
1746c2aa98e2SPeter Wemm 
1747c2aa98e2SPeter Wemm 	obp = obuf;
174812ed1c7cSGregory Neil Shapiro 	(void) sm_snprintf(obp, SPACELEFT(obuf, obp), "%.200s: ",
174912ed1c7cSGregory Neil Shapiro 			h->h_field);
1750c2aa98e2SPeter Wemm 	opos = strlen(h->h_field) + 2;
1751c2aa98e2SPeter Wemm 	if (opos > 202)
1752c2aa98e2SPeter Wemm 		opos = 202;
1753c2aa98e2SPeter Wemm 	obp += opos;
1754c2aa98e2SPeter Wemm 	omax = mci->mci_mailer->m_linelimit - 2;
1755c2aa98e2SPeter Wemm 	if (omax < 0 || omax > 78)
1756c2aa98e2SPeter Wemm 		omax = 78;
1757c2aa98e2SPeter Wemm 
1758c2aa98e2SPeter Wemm 	/*
1759c2aa98e2SPeter Wemm 	**  Run through the list of values.
1760c2aa98e2SPeter Wemm 	*/
1761c2aa98e2SPeter Wemm 
1762c2aa98e2SPeter Wemm 	while (*p != '\0')
1763c2aa98e2SPeter Wemm 	{
1764c2aa98e2SPeter Wemm 		register char *name;
1765c2aa98e2SPeter Wemm 		register int c;
1766c2aa98e2SPeter Wemm 		char savechar;
1767c2aa98e2SPeter Wemm 		int flags;
17683299c2f1SGregory Neil Shapiro 		auto int status;
1769c2aa98e2SPeter Wemm 
1770c2aa98e2SPeter Wemm 		/*
1771c2aa98e2SPeter Wemm 		**  Find the end of the name.  New style names
1772c2aa98e2SPeter Wemm 		**  end with a comma, old style names end with
1773c2aa98e2SPeter Wemm 		**  a space character.  However, spaces do not
1774c2aa98e2SPeter Wemm 		**  necessarily delimit an old-style name -- at
1775c2aa98e2SPeter Wemm 		**  signs mean keep going.
1776c2aa98e2SPeter Wemm 		*/
1777c2aa98e2SPeter Wemm 
1778c2aa98e2SPeter Wemm 		/* find end of name */
1779c2aa98e2SPeter Wemm 		while ((isascii(*p) && isspace(*p)) || *p == ',')
1780c2aa98e2SPeter Wemm 			p++;
1781c2aa98e2SPeter Wemm 		name = p;
1782c2aa98e2SPeter Wemm 		for (;;)
1783c2aa98e2SPeter Wemm 		{
1784c2aa98e2SPeter Wemm 			auto char *oldp;
1785c2aa98e2SPeter Wemm 			char pvpbuf[PSBUFSIZE];
1786c2aa98e2SPeter Wemm 
1787c2aa98e2SPeter Wemm 			(void) prescan(p, oldstyle ? ' ' : ',', pvpbuf,
1788c2aa98e2SPeter Wemm 				       sizeof pvpbuf, &oldp, NULL);
1789c2aa98e2SPeter Wemm 			p = oldp;
1790c2aa98e2SPeter Wemm 
1791c2aa98e2SPeter Wemm 			/* look to see if we have an at sign */
1792c2aa98e2SPeter Wemm 			while (*p != '\0' && isascii(*p) && isspace(*p))
1793c2aa98e2SPeter Wemm 				p++;
1794c2aa98e2SPeter Wemm 
1795c2aa98e2SPeter Wemm 			if (*p != '@')
1796c2aa98e2SPeter Wemm 			{
1797c2aa98e2SPeter Wemm 				p = oldp;
1798c2aa98e2SPeter Wemm 				break;
1799c2aa98e2SPeter Wemm 			}
180012ed1c7cSGregory Neil Shapiro 			++p;
1801c2aa98e2SPeter Wemm 			while (*p != '\0' && isascii(*p) && isspace(*p))
1802c2aa98e2SPeter Wemm 				p++;
1803c2aa98e2SPeter Wemm 		}
1804c2aa98e2SPeter Wemm 		/* at the end of one complete name */
1805c2aa98e2SPeter Wemm 
1806c2aa98e2SPeter Wemm 		/* strip off trailing white space */
1807c2aa98e2SPeter Wemm 		while (p >= name &&
1808c2aa98e2SPeter Wemm 		       ((isascii(*p) && isspace(*p)) || *p == ',' || *p == '\0'))
1809c2aa98e2SPeter Wemm 			p--;
1810c2aa98e2SPeter Wemm 		if (++p == name)
1811c2aa98e2SPeter Wemm 			continue;
1812c2aa98e2SPeter Wemm 		savechar = *p;
1813c2aa98e2SPeter Wemm 		*p = '\0';
1814c2aa98e2SPeter Wemm 
1815c2aa98e2SPeter Wemm 		/* translate the name to be relative */
1816c2aa98e2SPeter Wemm 		flags = RF_HEADERADDR|RF_ADDDOMAIN;
1817c2aa98e2SPeter Wemm 		if (bitset(H_FROM, h->h_flags))
1818c2aa98e2SPeter Wemm 			flags |= RF_SENDERADDR;
1819c2aa98e2SPeter Wemm #if USERDB
1820c2aa98e2SPeter Wemm 		else if (e->e_from.q_mailer != NULL &&
1821c2aa98e2SPeter Wemm 			 bitnset(M_UDBRECIPIENT, e->e_from.q_mailer->m_flags))
1822c2aa98e2SPeter Wemm 		{
1823c2aa98e2SPeter Wemm 			char *q;
1824c2aa98e2SPeter Wemm 
182512ed1c7cSGregory Neil Shapiro 			q = udbsender(name, e->e_rpool);
1826c2aa98e2SPeter Wemm 			if (q != NULL)
1827c2aa98e2SPeter Wemm 				name = q;
1828c2aa98e2SPeter Wemm 		}
18293299c2f1SGregory Neil Shapiro #endif /* USERDB */
18303299c2f1SGregory Neil Shapiro 		status = EX_OK;
18313299c2f1SGregory Neil Shapiro 		name = remotename(name, mci->mci_mailer, flags, &status, e);
1832c2aa98e2SPeter Wemm 		if (*name == '\0')
1833c2aa98e2SPeter Wemm 		{
1834c2aa98e2SPeter Wemm 			*p = savechar;
1835c2aa98e2SPeter Wemm 			continue;
1836c2aa98e2SPeter Wemm 		}
183712ed1c7cSGregory Neil Shapiro 		name = denlstring(name, false, true);
1838c2aa98e2SPeter Wemm 
18393299c2f1SGregory Neil Shapiro 		/*
18403299c2f1SGregory Neil Shapiro 		**  record data progress so DNS timeouts
18413299c2f1SGregory Neil Shapiro 		**  don't cause DATA timeouts
18423299c2f1SGregory Neil Shapiro 		*/
18433299c2f1SGregory Neil Shapiro 
184412ed1c7cSGregory Neil Shapiro 		DataProgress = true;
18453299c2f1SGregory Neil Shapiro 
1846c2aa98e2SPeter Wemm 		/* output the name with nice formatting */
1847c2aa98e2SPeter Wemm 		opos += strlen(name);
1848c2aa98e2SPeter Wemm 		if (!firstone)
1849c2aa98e2SPeter Wemm 			opos += 2;
1850c2aa98e2SPeter Wemm 		if (opos > omax && !firstone)
1851c2aa98e2SPeter Wemm 		{
185212ed1c7cSGregory Neil Shapiro 			(void) sm_strlcpy(obp, ",\n", SPACELEFT(obuf, obp));
1853c2aa98e2SPeter Wemm 			putxline(obuf, strlen(obuf), mci, putflags);
1854c2aa98e2SPeter Wemm 			obp = obuf;
185512ed1c7cSGregory Neil Shapiro 			(void) sm_strlcpy(obp, "        ", sizeof obp);
1856c2aa98e2SPeter Wemm 			opos = strlen(obp);
1857c2aa98e2SPeter Wemm 			obp += opos;
1858c2aa98e2SPeter Wemm 			opos += strlen(name);
1859c2aa98e2SPeter Wemm 		}
1860c2aa98e2SPeter Wemm 		else if (!firstone)
1861c2aa98e2SPeter Wemm 		{
186212ed1c7cSGregory Neil Shapiro 			(void) sm_strlcpy(obp, ", ", SPACELEFT(obuf, obp));
1863c2aa98e2SPeter Wemm 			obp += 2;
1864c2aa98e2SPeter Wemm 		}
1865c2aa98e2SPeter Wemm 
1866c2aa98e2SPeter Wemm 		while ((c = *name++) != '\0' && obp < &obuf[MAXLINE])
1867c2aa98e2SPeter Wemm 			*obp++ = c;
186812ed1c7cSGregory Neil Shapiro 		firstone = false;
1869c2aa98e2SPeter Wemm 		*p = savechar;
1870c2aa98e2SPeter Wemm 	}
1871c2aa98e2SPeter Wemm 	*obp = '\0';
1872c2aa98e2SPeter Wemm 	putxline(obuf, strlen(obuf), mci, putflags);
1873c2aa98e2SPeter Wemm }
187412ed1c7cSGregory Neil Shapiro /*
1875c2aa98e2SPeter Wemm **  COPYHEADER -- copy header list
1876c2aa98e2SPeter Wemm **
1877c2aa98e2SPeter Wemm **	This routine is the equivalent of newstr for header lists
1878c2aa98e2SPeter Wemm **
1879c2aa98e2SPeter Wemm **	Parameters:
1880c2aa98e2SPeter Wemm **		header -- list of header structures to copy.
188112ed1c7cSGregory Neil Shapiro **		rpool -- resource pool, or NULL
1882c2aa98e2SPeter Wemm **
1883c2aa98e2SPeter Wemm **	Returns:
1884c2aa98e2SPeter Wemm **		a copy of 'header'.
1885c2aa98e2SPeter Wemm **
1886c2aa98e2SPeter Wemm **	Side Effects:
1887c2aa98e2SPeter Wemm **		none.
1888c2aa98e2SPeter Wemm */
1889c2aa98e2SPeter Wemm 
1890c2aa98e2SPeter Wemm HDR *
189112ed1c7cSGregory Neil Shapiro copyheader(header, rpool)
1892c2aa98e2SPeter Wemm 	register HDR *header;
189312ed1c7cSGregory Neil Shapiro 	SM_RPOOL_T *rpool;
1894c2aa98e2SPeter Wemm {
1895c2aa98e2SPeter Wemm 	register HDR *newhdr;
1896c2aa98e2SPeter Wemm 	HDR *ret;
1897c2aa98e2SPeter Wemm 	register HDR **tail = &ret;
1898c2aa98e2SPeter Wemm 
1899c2aa98e2SPeter Wemm 	while (header != NULL)
1900c2aa98e2SPeter Wemm 	{
190112ed1c7cSGregory Neil Shapiro 		newhdr = (HDR *) sm_rpool_malloc_x(rpool, sizeof *newhdr);
1902c2aa98e2SPeter Wemm 		STRUCTCOPY(*header, *newhdr);
1903c2aa98e2SPeter Wemm 		*tail = newhdr;
1904c2aa98e2SPeter Wemm 		tail = &newhdr->h_link;
1905c2aa98e2SPeter Wemm 		header = header->h_link;
1906c2aa98e2SPeter Wemm 	}
1907c2aa98e2SPeter Wemm 	*tail = NULL;
1908c2aa98e2SPeter Wemm 
1909c2aa98e2SPeter Wemm 	return ret;
1910c2aa98e2SPeter Wemm }
191112ed1c7cSGregory Neil Shapiro /*
191276b7bf71SPeter Wemm **  FIX_MIME_HEADER -- possibly truncate/rebalance parameters in a MIME header
191376b7bf71SPeter Wemm **
191476b7bf71SPeter Wemm **	Run through all of the parameters of a MIME header and
191576b7bf71SPeter Wemm **	possibly truncate and rebalance the parameter according
191676b7bf71SPeter Wemm **	to MaxMimeFieldLength.
191776b7bf71SPeter Wemm **
191876b7bf71SPeter Wemm **	Parameters:
1919f9218d3dSGregory Neil Shapiro **		h -- the header to truncate/rebalance
1920f9218d3dSGregory Neil Shapiro **		e -- the current envelope
192176b7bf71SPeter Wemm **
192276b7bf71SPeter Wemm **	Returns:
1923c46d91b7SGregory Neil Shapiro **		length of last offending field, 0 if all ok.
192476b7bf71SPeter Wemm **
192576b7bf71SPeter Wemm **	Side Effects:
192676b7bf71SPeter Wemm **		string modified in place
192776b7bf71SPeter Wemm */
192876b7bf71SPeter Wemm 
1929c46d91b7SGregory Neil Shapiro static size_t
1930f9218d3dSGregory Neil Shapiro fix_mime_header(h, e)
1931f9218d3dSGregory Neil Shapiro 	HDR *h;
1932f9218d3dSGregory Neil Shapiro 	ENVELOPE *e;
193376b7bf71SPeter Wemm {
1934f9218d3dSGregory Neil Shapiro 	char *begin = h->h_value;
193576b7bf71SPeter Wemm 	char *end;
1936c46d91b7SGregory Neil Shapiro 	size_t len = 0;
1937c46d91b7SGregory Neil Shapiro 	size_t retlen = 0;
193876b7bf71SPeter Wemm 
1939f9218d3dSGregory Neil Shapiro 	if (begin == NULL || *begin == '\0')
1940c46d91b7SGregory Neil Shapiro 		return 0;
194176b7bf71SPeter Wemm 
194276b7bf71SPeter Wemm 	/* Split on each ';' */
194376b7bf71SPeter Wemm 	while ((end = find_character(begin, ';')) != NULL)
194476b7bf71SPeter Wemm 	{
194576b7bf71SPeter Wemm 		char save = *end;
194676b7bf71SPeter Wemm 		char *bp;
194776b7bf71SPeter Wemm 
194876b7bf71SPeter Wemm 		*end = '\0';
194976b7bf71SPeter Wemm 
1950c46d91b7SGregory Neil Shapiro 		len = strlen(begin);
1951c46d91b7SGregory Neil Shapiro 
195276b7bf71SPeter Wemm 		/* Shorten individual parameter */
195376b7bf71SPeter Wemm 		if (shorten_rfc822_string(begin, MaxMimeFieldLength))
1954f9218d3dSGregory Neil Shapiro 		{
1955f9218d3dSGregory Neil Shapiro 			if (len < MaxMimeFieldLength)
1956f9218d3dSGregory Neil Shapiro 			{
1957f9218d3dSGregory Neil Shapiro 				/* we only rebalanced a bogus field */
1958f9218d3dSGregory Neil Shapiro 				sm_syslog(LOG_ALERT, e->e_id,
1959f9218d3dSGregory Neil Shapiro 					  "Fixed MIME %s header field (possible attack)",
1960f9218d3dSGregory Neil Shapiro 					  h->h_field);
1961f9218d3dSGregory Neil Shapiro 				if (tTd(34, 11))
1962f9218d3dSGregory Neil Shapiro 					sm_dprintf("  fixed MIME %s header field (possible attack)\n",
1963f9218d3dSGregory Neil Shapiro 						   h->h_field);
1964f9218d3dSGregory Neil Shapiro 			}
1965f9218d3dSGregory Neil Shapiro 			else
1966f9218d3dSGregory Neil Shapiro 			{
1967f9218d3dSGregory Neil Shapiro 				/* we actually shortened the header */
1968c46d91b7SGregory Neil Shapiro 				retlen = len;
1969f9218d3dSGregory Neil Shapiro 			}
1970f9218d3dSGregory Neil Shapiro 		}
197176b7bf71SPeter Wemm 
197276b7bf71SPeter Wemm 		/* Collapse the possibly shortened string with rest */
197376b7bf71SPeter Wemm 		bp = begin + strlen(begin);
197476b7bf71SPeter Wemm 		if (bp != end)
197576b7bf71SPeter Wemm 		{
197676b7bf71SPeter Wemm 			char *ep = end;
197776b7bf71SPeter Wemm 
197876b7bf71SPeter Wemm 			*end = save;
197976b7bf71SPeter Wemm 			end = bp;
198076b7bf71SPeter Wemm 
198176b7bf71SPeter Wemm 			/* copy character by character due to overlap */
198276b7bf71SPeter Wemm 			while (*ep != '\0')
198376b7bf71SPeter Wemm 				*bp++ = *ep++;
198476b7bf71SPeter Wemm 			*bp = '\0';
198576b7bf71SPeter Wemm 		}
198676b7bf71SPeter Wemm 		else
198776b7bf71SPeter Wemm 			*end = save;
198876b7bf71SPeter Wemm 		if (*end == '\0')
198976b7bf71SPeter Wemm 			break;
199076b7bf71SPeter Wemm 
199176b7bf71SPeter Wemm 		/* Move past ';' */
199276b7bf71SPeter Wemm 		begin = end + 1;
199376b7bf71SPeter Wemm 	}
1994c46d91b7SGregory Neil Shapiro 	return retlen;
199576b7bf71SPeter Wemm }
1996