xref: /freebsd/contrib/sendmail/src/headers.c (revision 2fb4f839f3fc72ce2bab12f9ba4760f97f73e97f)
1c2aa98e2SPeter Wemm /*
25dd76dd0SGregory Neil Shapiro  * Copyright (c) 1998-2004, 2006, 2007 Proofpoint, Inc. and its suppliers.
33299c2f1SGregory Neil Shapiro  *	All rights reserved.
4c2aa98e2SPeter Wemm  * Copyright (c) 1983, 1995-1997 Eric P. Allman.  All rights reserved.
5c2aa98e2SPeter Wemm  * Copyright (c) 1988, 1993
6c2aa98e2SPeter Wemm  *	The Regents of the University of California.  All rights reserved.
7c2aa98e2SPeter Wemm  *
8c2aa98e2SPeter Wemm  * By using this file, you agree to the terms and conditions set
9c2aa98e2SPeter Wemm  * forth in the LICENSE file which can be found at the top level of
10c2aa98e2SPeter Wemm  * the sendmail distribution.
11c2aa98e2SPeter Wemm  *
12c2aa98e2SPeter Wemm  */
13c2aa98e2SPeter Wemm 
1412ed1c7cSGregory Neil Shapiro #include <sendmail.h>
15951742c4SGregory Neil Shapiro #include <sm/sendmail.h>
16*2fb4f839SGregory Neil Shapiro #include <sm/ixlen.h>
17c2aa98e2SPeter Wemm 
184313cc83SGregory Neil Shapiro SM_RCSID("@(#)$Id: headers.c,v 8.320 2013-11-22 20:51:55 ca Exp $")
193299c2f1SGregory Neil Shapiro 
20951742c4SGregory Neil Shapiro static HDR	*allocheader __P((char *, char *, int, SM_RPOOL_T *, bool));
21f9218d3dSGregory Neil Shapiro static size_t	fix_mime_header __P((HDR *, ENVELOPE *));
223299c2f1SGregory Neil Shapiro static int	priencode __P((char *));
23567a2fc9SGregory Neil Shapiro static bool	put_vanilla_header __P((HDR *, char *, MCI *));
24c2aa98e2SPeter Wemm 
25c2aa98e2SPeter Wemm /*
26c2aa98e2SPeter Wemm **  SETUPHEADERS -- initialize headers in symbol table
27c2aa98e2SPeter Wemm **
28c2aa98e2SPeter Wemm **	Parameters:
29c2aa98e2SPeter Wemm **		none
30c2aa98e2SPeter Wemm **
31c2aa98e2SPeter Wemm **	Returns:
32c2aa98e2SPeter Wemm **		none
33c2aa98e2SPeter Wemm */
34c2aa98e2SPeter Wemm 
35c2aa98e2SPeter Wemm void
36c2aa98e2SPeter Wemm setupheaders()
37c2aa98e2SPeter Wemm {
38c2aa98e2SPeter Wemm 	struct hdrinfo *hi;
39c2aa98e2SPeter Wemm 	STAB *s;
40c2aa98e2SPeter Wemm 
41c2aa98e2SPeter Wemm 	for (hi = HdrInfo; hi->hi_field != NULL; hi++)
42c2aa98e2SPeter Wemm 	{
43c2aa98e2SPeter Wemm 		s = stab(hi->hi_field, ST_HEADER, ST_ENTER);
44c2aa98e2SPeter Wemm 		s->s_header.hi_flags = hi->hi_flags;
45c2aa98e2SPeter Wemm 		s->s_header.hi_ruleset = NULL;
46c2aa98e2SPeter Wemm 	}
47c2aa98e2SPeter Wemm }
48951742c4SGregory Neil Shapiro 
4912ed1c7cSGregory Neil Shapiro /*
50951742c4SGregory Neil Shapiro **  DOCHOMPHEADER -- process and save a header line.
51c2aa98e2SPeter Wemm **
52951742c4SGregory Neil Shapiro **	Called by chompheader.
53c2aa98e2SPeter Wemm **
54c2aa98e2SPeter Wemm **	Parameters:
55c2aa98e2SPeter Wemm **		line -- header as a text line.
56d995d2baSGregory Neil Shapiro **		pflag -- flags for chompheader() (from sendmail.h)
57c2aa98e2SPeter Wemm **		hdrp -- a pointer to the place to save the header.
58c2aa98e2SPeter Wemm **		e -- the envelope including this header.
59c2aa98e2SPeter Wemm **
60c2aa98e2SPeter Wemm **	Returns:
61c2aa98e2SPeter Wemm **		flags for this header.
62c2aa98e2SPeter Wemm **
63c2aa98e2SPeter Wemm **	Side Effects:
64c2aa98e2SPeter Wemm **		The header is saved on the header list.
65c2aa98e2SPeter Wemm **		Contents of 'line' are destroyed.
66c2aa98e2SPeter Wemm */
67c2aa98e2SPeter Wemm 
683299c2f1SGregory Neil Shapiro static struct hdrinfo	NormalHeader =	{ NULL, 0, NULL };
69951742c4SGregory Neil Shapiro static unsigned long	dochompheader __P((char *, int, HDR **, ENVELOPE *));
70c2aa98e2SPeter Wemm 
71951742c4SGregory Neil Shapiro static unsigned long
72951742c4SGregory Neil Shapiro dochompheader(line, pflag, hdrp, e)
73c2aa98e2SPeter Wemm 	char *line;
743299c2f1SGregory Neil Shapiro 	int pflag;
75c2aa98e2SPeter Wemm 	HDR **hdrp;
76951742c4SGregory Neil Shapiro 	ENVELOPE *e;
77c2aa98e2SPeter Wemm {
7812ed1c7cSGregory Neil Shapiro 	unsigned char mid = '\0';
79c2aa98e2SPeter Wemm 	register char *p;
80c2aa98e2SPeter Wemm 	register HDR *h;
81c2aa98e2SPeter Wemm 	HDR **hp;
82c2aa98e2SPeter Wemm 	char *fname;
83c2aa98e2SPeter Wemm 	char *fvalue;
8412ed1c7cSGregory Neil Shapiro 	bool cond = false;
853299c2f1SGregory Neil Shapiro 	bool dropfrom;
86c2aa98e2SPeter Wemm 	bool headeronly;
87c2aa98e2SPeter Wemm 	STAB *s;
88c2aa98e2SPeter Wemm 	struct hdrinfo *hi;
8912ed1c7cSGregory Neil Shapiro 	bool nullheader = false;
903299c2f1SGregory Neil Shapiro 	BITMAP256 mopts;
91c2aa98e2SPeter Wemm 
92c2aa98e2SPeter Wemm 	headeronly = hdrp != NULL;
93c2aa98e2SPeter Wemm 	if (!headeronly)
94c2aa98e2SPeter Wemm 		hdrp = &e->e_header;
95c2aa98e2SPeter Wemm 
96c2aa98e2SPeter Wemm 	/* strip off options */
97c2aa98e2SPeter Wemm 	clrbitmap(mopts);
98c2aa98e2SPeter Wemm 	p = line;
993299c2f1SGregory Neil Shapiro 	if (!bitset(pflag, CHHDR_USER) && *p == '?')
100c2aa98e2SPeter Wemm 	{
1013299c2f1SGregory Neil Shapiro 		int c;
1023299c2f1SGregory Neil Shapiro 		register char *q;
103c2aa98e2SPeter Wemm 
1043299c2f1SGregory Neil Shapiro 		q = strchr(++p, '?');
1053299c2f1SGregory Neil Shapiro 		if (q == NULL)
1063299c2f1SGregory Neil Shapiro 			goto hse;
1073299c2f1SGregory Neil Shapiro 
1083299c2f1SGregory Neil Shapiro 		*q = '\0';
1093299c2f1SGregory Neil Shapiro 		c = *p & 0377;
1103299c2f1SGregory Neil Shapiro 
1113299c2f1SGregory Neil Shapiro 		/* possibly macro conditional */
1123299c2f1SGregory Neil Shapiro 		if (c == MACROEXPAND)
113c2aa98e2SPeter Wemm 		{
1143299c2f1SGregory Neil Shapiro 			/* catch ?$? */
1153299c2f1SGregory Neil Shapiro 			if (*++p == '\0')
1163299c2f1SGregory Neil Shapiro 			{
1173299c2f1SGregory Neil Shapiro 				*q = '?';
1183299c2f1SGregory Neil Shapiro 				goto hse;
1193299c2f1SGregory Neil Shapiro 			}
1203299c2f1SGregory Neil Shapiro 
12112ed1c7cSGregory Neil Shapiro 			mid = (unsigned char) *p++;
1223299c2f1SGregory Neil Shapiro 
1233299c2f1SGregory Neil Shapiro 			/* catch ?$abc? */
1243299c2f1SGregory Neil Shapiro 			if (*p != '\0')
1253299c2f1SGregory Neil Shapiro 			{
1263299c2f1SGregory Neil Shapiro 				*q = '?';
1273299c2f1SGregory Neil Shapiro 				goto hse;
1283299c2f1SGregory Neil Shapiro 			}
1293299c2f1SGregory Neil Shapiro 		}
1303299c2f1SGregory Neil Shapiro 		else if (*p == '$')
1313299c2f1SGregory Neil Shapiro 		{
1323299c2f1SGregory Neil Shapiro 			/* catch ?$? */
1333299c2f1SGregory Neil Shapiro 			if (*++p == '\0')
1343299c2f1SGregory Neil Shapiro 			{
1353299c2f1SGregory Neil Shapiro 				*q = '?';
1363299c2f1SGregory Neil Shapiro 				goto hse;
1373299c2f1SGregory Neil Shapiro 			}
1383299c2f1SGregory Neil Shapiro 
13912ed1c7cSGregory Neil Shapiro 			mid = (unsigned char) macid(p);
1403299c2f1SGregory Neil Shapiro 			if (bitset(0200, mid))
1417660b554SGregory Neil Shapiro 			{
1423299c2f1SGregory Neil Shapiro 				p += strlen(macname(mid)) + 2;
1437660b554SGregory Neil Shapiro 				SM_ASSERT(p <= q);
1447660b554SGregory Neil Shapiro 			}
1453299c2f1SGregory Neil Shapiro 			else
1463299c2f1SGregory Neil Shapiro 				p++;
1473299c2f1SGregory Neil Shapiro 
1483299c2f1SGregory Neil Shapiro 			/* catch ?$abc? */
1493299c2f1SGregory Neil Shapiro 			if (*p != '\0')
1503299c2f1SGregory Neil Shapiro 			{
1513299c2f1SGregory Neil Shapiro 				*q = '?';
1523299c2f1SGregory Neil Shapiro 				goto hse;
1533299c2f1SGregory Neil Shapiro 			}
154c2aa98e2SPeter Wemm 		}
155c2aa98e2SPeter Wemm 		else
1563299c2f1SGregory Neil Shapiro 		{
1573299c2f1SGregory Neil Shapiro 			while (*p != '\0')
1583299c2f1SGregory Neil Shapiro 			{
1593299c2f1SGregory Neil Shapiro 				if (!isascii(*p))
1603299c2f1SGregory Neil Shapiro 				{
1613299c2f1SGregory Neil Shapiro 					*q = '?';
1623299c2f1SGregory Neil Shapiro 					goto hse;
1633299c2f1SGregory Neil Shapiro 				}
1643299c2f1SGregory Neil Shapiro 
165c46d91b7SGregory Neil Shapiro 				setbitn(bitidx(*p), mopts);
16612ed1c7cSGregory Neil Shapiro 				cond = true;
1673299c2f1SGregory Neil Shapiro 				p++;
1683299c2f1SGregory Neil Shapiro 			}
1693299c2f1SGregory Neil Shapiro 		}
1703299c2f1SGregory Neil Shapiro 		p = q + 1;
171c2aa98e2SPeter Wemm 	}
172c2aa98e2SPeter Wemm 
173c2aa98e2SPeter Wemm 	/* find canonical name */
174c2aa98e2SPeter Wemm 	fname = p;
175c2aa98e2SPeter Wemm 	while (isascii(*p) && isgraph(*p) && *p != ':')
176c2aa98e2SPeter Wemm 		p++;
177c2aa98e2SPeter Wemm 	fvalue = p;
1785b0945b5SGregory Neil Shapiro 	while (SM_ISSPACE(*p))
179c2aa98e2SPeter Wemm 		p++;
180c2aa98e2SPeter Wemm 	if (*p++ != ':' || fname == fvalue)
181c2aa98e2SPeter Wemm 	{
1823299c2f1SGregory Neil Shapiro hse:
1833299c2f1SGregory Neil Shapiro 		syserr("553 5.3.0 header syntax error, line \"%s\"", line);
184c2aa98e2SPeter Wemm 		return 0;
185c2aa98e2SPeter Wemm 	}
186c2aa98e2SPeter Wemm 	*fvalue = '\0';
187e01d6f61SPeter Wemm 	fvalue = p;
188e01d6f61SPeter Wemm 
189e01d6f61SPeter Wemm 	/* if the field is null, go ahead and use the default */
1905b0945b5SGregory Neil Shapiro 	while (SM_ISSPACE(*p))
191e01d6f61SPeter Wemm 		p++;
192e01d6f61SPeter Wemm 	if (*p == '\0')
19312ed1c7cSGregory Neil Shapiro 		nullheader = true;
194c2aa98e2SPeter Wemm 
195c2aa98e2SPeter Wemm 	/* security scan: long field names are end-of-header */
196c2aa98e2SPeter Wemm 	if (strlen(fname) > 100)
197c2aa98e2SPeter Wemm 		return H_EOH;
198c2aa98e2SPeter Wemm 
199c2aa98e2SPeter Wemm 	/* check to see if it represents a ruleset call */
2003299c2f1SGregory Neil Shapiro 	if (bitset(pflag, CHHDR_DEF))
201c2aa98e2SPeter Wemm 	{
202c2aa98e2SPeter Wemm 		char hbuf[50];
203c2aa98e2SPeter Wemm 
204951742c4SGregory Neil Shapiro 		(void) expand(fvalue, hbuf, sizeof(hbuf), e);
2055b0945b5SGregory Neil Shapiro 		for (p = hbuf; SM_ISSPACE(*p); )
206c2aa98e2SPeter Wemm 			p++;
207c2aa98e2SPeter Wemm 		if ((*p++ & 0377) == CALLSUBR)
208c2aa98e2SPeter Wemm 		{
209c2aa98e2SPeter Wemm 			auto char *endp;
2103299c2f1SGregory Neil Shapiro 			bool strc;
211c2aa98e2SPeter Wemm 
2123299c2f1SGregory Neil Shapiro 			strc = *p == '+';	/* strip comments? */
2133299c2f1SGregory Neil Shapiro 			if (strc)
2143299c2f1SGregory Neil Shapiro 				++p;
215c2aa98e2SPeter Wemm 			if (strtorwset(p, &endp, ST_ENTER) > 0)
216c2aa98e2SPeter Wemm 			{
217c2aa98e2SPeter Wemm 				*endp = '\0';
218c2aa98e2SPeter Wemm 				s = stab(fname, ST_HEADER, ST_ENTER);
21912ed1c7cSGregory Neil Shapiro 				if (LogLevel > 9 &&
22012ed1c7cSGregory Neil Shapiro 				    s->s_header.hi_ruleset != NULL)
22112ed1c7cSGregory Neil Shapiro 					sm_syslog(LOG_WARNING, NOQID,
22212ed1c7cSGregory Neil Shapiro 						  "Warning: redefined ruleset for header=%s, old=%s, new=%s",
22312ed1c7cSGregory Neil Shapiro 						  fname,
22412ed1c7cSGregory Neil Shapiro 						  s->s_header.hi_ruleset, p);
225c2aa98e2SPeter Wemm 				s->s_header.hi_ruleset = newstr(p);
2263299c2f1SGregory Neil Shapiro 				if (!strc)
2273299c2f1SGregory Neil Shapiro 					s->s_header.hi_flags |= H_STRIPCOMM;
228c2aa98e2SPeter Wemm 			}
229c2aa98e2SPeter Wemm 			return 0;
230c2aa98e2SPeter Wemm 		}
231c2aa98e2SPeter Wemm 	}
232c2aa98e2SPeter Wemm 
233c2aa98e2SPeter Wemm 	/* see if it is a known type */
234c2aa98e2SPeter Wemm 	s = stab(fname, ST_HEADER, ST_FIND);
235c2aa98e2SPeter Wemm 	if (s != NULL)
236c2aa98e2SPeter Wemm 		hi = &s->s_header;
237c2aa98e2SPeter Wemm 	else
238c2aa98e2SPeter Wemm 		hi = &NormalHeader;
239c2aa98e2SPeter Wemm 
240c2aa98e2SPeter Wemm 	if (tTd(31, 9))
241c2aa98e2SPeter Wemm 	{
242c2aa98e2SPeter Wemm 		if (s == NULL)
24312ed1c7cSGregory Neil Shapiro 			sm_dprintf("no header flags match\n");
244c2aa98e2SPeter Wemm 		else
24512ed1c7cSGregory Neil Shapiro 			sm_dprintf("header match, flags=%lx, ruleset=%s\n",
246c2aa98e2SPeter Wemm 				   hi->hi_flags,
24712ed1c7cSGregory Neil Shapiro 				   hi->hi_ruleset == NULL ? "<NULL>"
24812ed1c7cSGregory Neil Shapiro 							  : hi->hi_ruleset);
249c2aa98e2SPeter Wemm 	}
250c2aa98e2SPeter Wemm 
251c2aa98e2SPeter Wemm 	/* see if this is a resent message */
2523299c2f1SGregory Neil Shapiro 	if (!bitset(pflag, CHHDR_DEF) && !headeronly &&
2533299c2f1SGregory Neil Shapiro 	    bitset(H_RESENT, hi->hi_flags))
254c2aa98e2SPeter Wemm 		e->e_flags |= EF_RESENT;
255c2aa98e2SPeter Wemm 
256c2aa98e2SPeter Wemm 	/* if this is an Errors-To: header keep track of it now */
2573299c2f1SGregory Neil Shapiro 	if (UseErrorsTo && !bitset(pflag, CHHDR_DEF) && !headeronly &&
258c2aa98e2SPeter Wemm 	    bitset(H_ERRORSTO, hi->hi_flags))
259c2aa98e2SPeter Wemm 		(void) sendtolist(fvalue, NULLADDR, &e->e_errorqueue, 0, e);
260c2aa98e2SPeter Wemm 
261c2aa98e2SPeter Wemm 	/* if this means "end of header" quit now */
262c2aa98e2SPeter Wemm 	if (!headeronly && bitset(H_EOH, hi->hi_flags))
263c2aa98e2SPeter Wemm 		return hi->hi_flags;
264c2aa98e2SPeter Wemm 
265c2aa98e2SPeter Wemm 	/*
266c2aa98e2SPeter Wemm 	**  Horrible hack to work around problem with Lotus Notes SMTP
267c2aa98e2SPeter Wemm 	**  mail gateway, which generates From: headers with newlines in
268c2aa98e2SPeter Wemm 	**  them and the <address> on the second line.  Although this is
269c2aa98e2SPeter Wemm 	**  legal RFC 822, many MUAs don't handle this properly and thus
270c2aa98e2SPeter Wemm 	**  never find the actual address.
271c2aa98e2SPeter Wemm 	*/
272c2aa98e2SPeter Wemm 
273c2aa98e2SPeter Wemm 	if (bitset(H_FROM, hi->hi_flags) && SingleLineFromHeader)
274c2aa98e2SPeter Wemm 	{
275c2aa98e2SPeter Wemm 		while ((p = strchr(fvalue, '\n')) != NULL)
276c2aa98e2SPeter Wemm 			*p = ' ';
277c2aa98e2SPeter Wemm 	}
278c2aa98e2SPeter Wemm 
279c2aa98e2SPeter Wemm 	/*
280c2aa98e2SPeter Wemm 	**  If there is a check ruleset, verify it against the header.
281c2aa98e2SPeter Wemm 	*/
282c2aa98e2SPeter Wemm 
2833299c2f1SGregory Neil Shapiro 	if (bitset(pflag, CHHDR_CHECK))
2843299c2f1SGregory Neil Shapiro 	{
2859d8fddc1SGregory Neil Shapiro 		int rscheckflags;
2863299c2f1SGregory Neil Shapiro 		char *rs;
2873299c2f1SGregory Neil Shapiro 
2889d8fddc1SGregory Neil Shapiro 		rscheckflags = RSF_COUNT;
2899d8fddc1SGregory Neil Shapiro 		if (!bitset(hi->hi_flags, H_FROM|H_RCPT))
2909d8fddc1SGregory Neil Shapiro 			rscheckflags |= RSF_UNSTRUCTURED;
291bfb62e91SGregory Neil Shapiro 
292bfb62e91SGregory Neil Shapiro 		/* no ruleset? look for default */
293bfb62e91SGregory Neil Shapiro 		rs = hi->hi_ruleset;
2943299c2f1SGregory Neil Shapiro 		if (rs == NULL)
2953299c2f1SGregory Neil Shapiro 		{
2963299c2f1SGregory Neil Shapiro 			s = stab("*", ST_HEADER, ST_FIND);
2973299c2f1SGregory Neil Shapiro 			if (s != NULL)
2983299c2f1SGregory Neil Shapiro 			{
2993299c2f1SGregory Neil Shapiro 				rs = (&s->s_header)->hi_ruleset;
3009d8fddc1SGregory Neil Shapiro 				if (bitset((&s->s_header)->hi_flags,
3019d8fddc1SGregory Neil Shapiro 					   H_STRIPCOMM))
3029d8fddc1SGregory Neil Shapiro 					rscheckflags |= RSF_RMCOMM;
3033299c2f1SGregory Neil Shapiro 			}
3043299c2f1SGregory Neil Shapiro 		}
3059d8fddc1SGregory Neil Shapiro 		else if (bitset(hi->hi_flags, H_STRIPCOMM))
3069d8fddc1SGregory Neil Shapiro 			rscheckflags |= RSF_RMCOMM;
3073299c2f1SGregory Neil Shapiro 		if (rs != NULL)
3083299c2f1SGregory Neil Shapiro 		{
30912ed1c7cSGregory Neil Shapiro 			int l, k;
310*2fb4f839SGregory Neil Shapiro 			char qval[MAXNAME_I];
311*2fb4f839SGregory Neil Shapiro 			XLENDECL
3123299c2f1SGregory Neil Shapiro 
3133299c2f1SGregory Neil Shapiro 			l = 0;
314*2fb4f839SGregory Neil Shapiro 			XLEN('"');
31512ed1c7cSGregory Neil Shapiro 			qval[l++] = '"';
31612ed1c7cSGregory Neil Shapiro 
31712ed1c7cSGregory Neil Shapiro 			/* - 3 to avoid problems with " at the end */
318*2fb4f839SGregory Neil Shapiro 			for (k = 0;
319*2fb4f839SGregory Neil Shapiro 			     fvalue[k] != '\0' && l < sizeof(qval) - 3
320*2fb4f839SGregory Neil Shapiro 			     && xlen < MAXNAME - 3;
321*2fb4f839SGregory Neil Shapiro 			     k++)
3223299c2f1SGregory Neil Shapiro 			{
323*2fb4f839SGregory Neil Shapiro 				XLEN(fvalue[k]);
32412ed1c7cSGregory Neil Shapiro 				switch (fvalue[k])
3253299c2f1SGregory Neil Shapiro 				{
32612ed1c7cSGregory Neil Shapiro 				  /* XXX other control chars? */
3273299c2f1SGregory Neil Shapiro 				  case '\011': /* ht */
3283299c2f1SGregory Neil Shapiro 				  case '\012': /* nl */
3293299c2f1SGregory Neil Shapiro 				  case '\013': /* vt */
3303299c2f1SGregory Neil Shapiro 				  case '\014': /* np */
3313299c2f1SGregory Neil Shapiro 				  case '\015': /* cr */
33212ed1c7cSGregory Neil Shapiro 					qval[l++] = ' ';
3333299c2f1SGregory Neil Shapiro 					break;
3343299c2f1SGregory Neil Shapiro 				  case '"':
335*2fb4f839SGregory Neil Shapiro 					XLEN('\\');
33612ed1c7cSGregory Neil Shapiro 					qval[l++] = '\\';
3373299c2f1SGregory Neil Shapiro 					/* FALLTHROUGH */
3383299c2f1SGregory Neil Shapiro 				  default:
33912ed1c7cSGregory Neil Shapiro 					qval[l++] = fvalue[k];
3403299c2f1SGregory Neil Shapiro 					break;
3413299c2f1SGregory Neil Shapiro 				}
3423299c2f1SGregory Neil Shapiro 			}
343*2fb4f839SGregory Neil Shapiro 			/* just for "completeness": xlen not used afterwards */
344*2fb4f839SGregory Neil Shapiro 			XLEN('"');
34512ed1c7cSGregory Neil Shapiro 			qval[l++] = '"';
34612ed1c7cSGregory Neil Shapiro 			qval[l] = '\0';
34712ed1c7cSGregory Neil Shapiro 			k += strlen(fvalue + k);
348*2fb4f839SGregory Neil Shapiro 			if (k >= sizeof(qval))
3493299c2f1SGregory Neil Shapiro 			{
3503299c2f1SGregory Neil Shapiro 				if (LogLevel > 9)
3513299c2f1SGregory Neil Shapiro 					sm_syslog(LOG_WARNING, e->e_id,
3523299c2f1SGregory Neil Shapiro 						  "Warning: truncated header '%s' before check with '%s' len=%d max=%d",
353*2fb4f839SGregory Neil Shapiro 						  fname, rs, k,
354*2fb4f839SGregory Neil Shapiro 						  (int) (sizeof(qval) - 1));
3553299c2f1SGregory Neil Shapiro 			}
35612ed1c7cSGregory Neil Shapiro 			macdefine(&e->e_macro, A_TEMP,
35712ed1c7cSGregory Neil Shapiro 				macid("{currHeader}"), qval);
35812ed1c7cSGregory Neil Shapiro 			macdefine(&e->e_macro, A_TEMP,
35912ed1c7cSGregory Neil Shapiro 				macid("{hdr_name}"), fname);
36012ed1c7cSGregory Neil Shapiro 
361951742c4SGregory Neil Shapiro 			(void) sm_snprintf(qval, sizeof(qval), "%d", k);
36212ed1c7cSGregory Neil Shapiro 			macdefine(&e->e_macro, A_TEMP, macid("{hdrlen}"), qval);
363bfb62e91SGregory Neil Shapiro 			if (bitset(H_FROM, hi->hi_flags))
36412ed1c7cSGregory Neil Shapiro 				macdefine(&e->e_macro, A_PERM,
36512ed1c7cSGregory Neil Shapiro 					macid("{addr_type}"), "h s");
366bfb62e91SGregory Neil Shapiro 			else if (bitset(H_RCPT, hi->hi_flags))
36712ed1c7cSGregory Neil Shapiro 				macdefine(&e->e_macro, A_PERM,
36812ed1c7cSGregory Neil Shapiro 					macid("{addr_type}"), "h r");
36912ed1c7cSGregory Neil Shapiro 			else
37012ed1c7cSGregory Neil Shapiro 				macdefine(&e->e_macro, A_PERM,
37112ed1c7cSGregory Neil Shapiro 					macid("{addr_type}"), "h");
3729d8fddc1SGregory Neil Shapiro 			(void) rscheck(rs, fvalue, NULL, e, rscheckflags, 3,
373da7d7b9cSGregory Neil Shapiro 				       NULL, e->e_id, NULL, NULL);
3743299c2f1SGregory Neil Shapiro 		}
3753299c2f1SGregory Neil Shapiro 	}
376c2aa98e2SPeter Wemm 
377c2aa98e2SPeter Wemm 	/*
378c2aa98e2SPeter Wemm 	**  Drop explicit From: if same as what we would generate.
379c2aa98e2SPeter Wemm 	**  This is to make MH (which doesn't always give a full name)
380c2aa98e2SPeter Wemm 	**  insert the full name information in all circumstances.
381c2aa98e2SPeter Wemm 	*/
382c2aa98e2SPeter Wemm 
38312ed1c7cSGregory Neil Shapiro 	dropfrom = false;
384c2aa98e2SPeter Wemm 	p = "resent-from";
385c2aa98e2SPeter Wemm 	if (!bitset(EF_RESENT, e->e_flags))
386c2aa98e2SPeter Wemm 		p += 7;
3873299c2f1SGregory Neil Shapiro 	if (!bitset(pflag, CHHDR_DEF) && !headeronly &&
388*2fb4f839SGregory Neil Shapiro 	    !bitset(EF_QUEUERUN, e->e_flags) && SM_STRCASEEQ(fname, p))
389c2aa98e2SPeter Wemm 	{
390c2aa98e2SPeter Wemm 		if (e->e_from.q_paddr != NULL &&
3913299c2f1SGregory Neil Shapiro 		    e->e_from.q_mailer != NULL &&
3923299c2f1SGregory Neil Shapiro 		    bitnset(M_LOCALMAILER, e->e_from.q_mailer->m_flags) &&
393c2aa98e2SPeter Wemm 		    (strcmp(fvalue, e->e_from.q_paddr) == 0 ||
394c2aa98e2SPeter Wemm 		     strcmp(fvalue, e->e_from.q_user) == 0))
39512ed1c7cSGregory Neil Shapiro 			dropfrom = true;
3965dd76dd0SGregory Neil Shapiro 		if (tTd(31, 2))
3975dd76dd0SGregory Neil Shapiro 		{
3985dd76dd0SGregory Neil Shapiro 			sm_dprintf("comparing header from (%s) against default (%s or %s), drop=%d\n",
3995dd76dd0SGregory Neil Shapiro 				fvalue, e->e_from.q_paddr, e->e_from.q_user,
4005dd76dd0SGregory Neil Shapiro 				dropfrom);
4015dd76dd0SGregory Neil Shapiro 		}
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 	{
407*2fb4f839SGregory Neil Shapiro 		if (SM_STRCASEEQ(fname, h->h_field) &&
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;
4205dd76dd0SGregory Neil Shapiro 
4215dd76dd0SGregory Neil Shapiro 				/*
4225dd76dd0SGregory Neil Shapiro 				**  If the MH hack is selected, allow to turn
4235dd76dd0SGregory Neil Shapiro 				**  it off via a mailer flag to avoid problems
4245dd76dd0SGregory Neil Shapiro 				**  with setups that remove the F flag from
4255dd76dd0SGregory Neil Shapiro 				**  the RCPT mailer.
4265dd76dd0SGregory Neil Shapiro 				*/
4275dd76dd0SGregory Neil Shapiro 
4285dd76dd0SGregory Neil Shapiro 				if (bitnset(M_NOMHHACK,
4295dd76dd0SGregory Neil Shapiro 					    e->e_from.q_mailer->m_flags))
4305dd76dd0SGregory Neil Shapiro 				{
4315dd76dd0SGregory Neil Shapiro 					h->h_flags &= ~H_CHECK;
4325dd76dd0SGregory Neil Shapiro 				}
4333299c2f1SGregory Neil Shapiro 				return hi->hi_flags;
4343299c2f1SGregory Neil Shapiro 			}
435c2aa98e2SPeter Wemm 			h->h_value = NULL;
436c2aa98e2SPeter Wemm 			if (!cond)
437c2aa98e2SPeter Wemm 			{
438c2aa98e2SPeter Wemm 				/* copy conditions from default case */
4393299c2f1SGregory Neil Shapiro 				memmove((char *) mopts, (char *) h->h_mflags,
440951742c4SGregory Neil Shapiro 					sizeof(mopts));
441c2aa98e2SPeter Wemm 			}
4423299c2f1SGregory Neil Shapiro 			h->h_macro = mid;
443c2aa98e2SPeter Wemm 		}
444c2aa98e2SPeter Wemm 	}
445c2aa98e2SPeter Wemm 
446c2aa98e2SPeter Wemm 	/* create a new node */
447*2fb4f839SGregory Neil Shapiro 	h = (HDR *) sm_rpool_malloc_tagged_x(e->e_rpool, sizeof(*h), "header",
448*2fb4f839SGregory Neil Shapiro 			pflag, bitset(pflag, CHHDR_DEF) ? 0 : 1);
449*2fb4f839SGregory Neil Shapiro 	h->h_field = sm_rpool_strdup_tagged_x(e->e_rpool, fname, "h_field",
450*2fb4f839SGregory Neil Shapiro 			pflag, bitset(pflag, CHHDR_DEF) ? 0 : 1);
451*2fb4f839SGregory Neil Shapiro 	h->h_value = sm_rpool_strdup_tagged_x(e->e_rpool, fvalue, "h_value",
452*2fb4f839SGregory Neil Shapiro 			pflag, bitset(pflag, CHHDR_DEF) ? 0 : 1);
453c2aa98e2SPeter Wemm 	h->h_link = NULL;
454951742c4SGregory Neil Shapiro 	memmove((char *) h->h_mflags, (char *) mopts, sizeof(mopts));
4553299c2f1SGregory Neil Shapiro 	h->h_macro = mid;
456c2aa98e2SPeter Wemm 	*hp = h;
457c2aa98e2SPeter Wemm 	h->h_flags = hi->hi_flags;
458d995d2baSGregory Neil Shapiro 	if (bitset(pflag, CHHDR_USER) || bitset(pflag, CHHDR_QUEUE))
4593299c2f1SGregory Neil Shapiro 		h->h_flags |= H_USER;
460c2aa98e2SPeter Wemm 
461c2aa98e2SPeter Wemm 	/* strip EOH flag if parsing MIME headers */
462c2aa98e2SPeter Wemm 	if (headeronly)
463c2aa98e2SPeter Wemm 		h->h_flags &= ~H_EOH;
4643299c2f1SGregory Neil Shapiro 	if (bitset(pflag, CHHDR_DEF))
465c2aa98e2SPeter Wemm 		h->h_flags |= H_DEFAULT;
4663299c2f1SGregory Neil Shapiro 	if (cond || mid != '\0')
467c2aa98e2SPeter Wemm 		h->h_flags |= H_CHECK;
468c2aa98e2SPeter Wemm 
469c2aa98e2SPeter Wemm 	/* hack to see if this is a new format message */
4703299c2f1SGregory Neil Shapiro 	if (!bitset(pflag, CHHDR_DEF) && !headeronly &&
4713299c2f1SGregory Neil Shapiro 	    bitset(H_RCPT|H_FROM, h->h_flags) &&
472c2aa98e2SPeter Wemm 	    (strchr(fvalue, ',') != NULL || strchr(fvalue, '(') != NULL ||
473c2aa98e2SPeter Wemm 	     strchr(fvalue, '<') != NULL || strchr(fvalue, ';') != NULL))
474c2aa98e2SPeter Wemm 	{
475c2aa98e2SPeter Wemm 		e->e_flags &= ~EF_OLDSTYLE;
476c2aa98e2SPeter Wemm 	}
477c2aa98e2SPeter Wemm 
478c2aa98e2SPeter Wemm 	return h->h_flags;
479c2aa98e2SPeter Wemm }
480951742c4SGregory Neil Shapiro 
481951742c4SGregory Neil Shapiro /*
482951742c4SGregory Neil Shapiro **  CHOMPHEADER -- process and save a header line.
483951742c4SGregory Neil Shapiro **
484951742c4SGregory Neil Shapiro **	Called by collect, readcf, and readqf to deal with header lines.
485951742c4SGregory Neil Shapiro **	This is just a wrapper for dochompheader().
486951742c4SGregory Neil Shapiro **
487951742c4SGregory Neil Shapiro **	Parameters:
488951742c4SGregory Neil Shapiro **		line -- header as a text line.
489951742c4SGregory Neil Shapiro **		pflag -- flags for chompheader() (from sendmail.h)
490951742c4SGregory Neil Shapiro **		hdrp -- a pointer to the place to save the header.
491951742c4SGregory Neil Shapiro **		e -- the envelope including this header.
492951742c4SGregory Neil Shapiro **
493951742c4SGregory Neil Shapiro **	Returns:
494951742c4SGregory Neil Shapiro **		flags for this header.
495951742c4SGregory Neil Shapiro **
496951742c4SGregory Neil Shapiro **	Side Effects:
497951742c4SGregory Neil Shapiro **		The header is saved on the header list.
498951742c4SGregory Neil Shapiro **		Contents of 'line' are destroyed.
499951742c4SGregory Neil Shapiro */
500951742c4SGregory Neil Shapiro 
501951742c4SGregory Neil Shapiro 
502951742c4SGregory Neil Shapiro unsigned long
503951742c4SGregory Neil Shapiro chompheader(line, pflag, hdrp, e)
504951742c4SGregory Neil Shapiro 	char *line;
505951742c4SGregory Neil Shapiro 	int pflag;
506951742c4SGregory Neil Shapiro 	HDR **hdrp;
507951742c4SGregory Neil Shapiro 	register ENVELOPE *e;
508951742c4SGregory Neil Shapiro {
509951742c4SGregory Neil Shapiro 	unsigned long rval;
510951742c4SGregory Neil Shapiro 
511951742c4SGregory Neil Shapiro 	if (tTd(31, 6))
512951742c4SGregory Neil Shapiro 	{
513951742c4SGregory Neil Shapiro 		sm_dprintf("chompheader: ");
514951742c4SGregory Neil Shapiro 		xputs(sm_debug_file(), line);
515951742c4SGregory Neil Shapiro 		sm_dprintf("\n");
516951742c4SGregory Neil Shapiro 	}
517951742c4SGregory Neil Shapiro 
518951742c4SGregory Neil Shapiro 	/* quote this if user (not config file) input */
519951742c4SGregory Neil Shapiro 	if (bitset(pflag, CHHDR_USER))
520951742c4SGregory Neil Shapiro 	{
521*2fb4f839SGregory Neil Shapiro 		char xbuf[MAXLINE]; /* EAI:ok; actual buffer might be greater */
522951742c4SGregory Neil Shapiro 		char *xbp = NULL;
523951742c4SGregory Neil Shapiro 		int xbufs;
524951742c4SGregory Neil Shapiro 
525951742c4SGregory Neil Shapiro 		xbufs = sizeof(xbuf);
526*2fb4f839SGregory Neil Shapiro 		xbp = quote_internal_chars(line, xbuf, &xbufs, NULL);
527951742c4SGregory Neil Shapiro 		if (tTd(31, 7))
528951742c4SGregory Neil Shapiro 		{
529951742c4SGregory Neil Shapiro 			sm_dprintf("chompheader: quoted: ");
530951742c4SGregory Neil Shapiro 			xputs(sm_debug_file(), xbp);
531951742c4SGregory Neil Shapiro 			sm_dprintf("\n");
532951742c4SGregory Neil Shapiro 		}
533951742c4SGregory Neil Shapiro 		rval = dochompheader(xbp, pflag, hdrp, e);
534951742c4SGregory Neil Shapiro 		if (xbp != xbuf)
535951742c4SGregory Neil Shapiro 			sm_free(xbp);
536951742c4SGregory Neil Shapiro 	}
537951742c4SGregory Neil Shapiro 	else
538951742c4SGregory Neil Shapiro 		rval = dochompheader(line, pflag, hdrp, e);
539951742c4SGregory Neil Shapiro 
540951742c4SGregory Neil Shapiro 	return rval;
541951742c4SGregory Neil Shapiro }
542951742c4SGregory Neil Shapiro 
54312ed1c7cSGregory Neil Shapiro /*
544bfb62e91SGregory Neil Shapiro **  ALLOCHEADER -- allocate a header entry
545bfb62e91SGregory Neil Shapiro **
546bfb62e91SGregory Neil Shapiro **	Parameters:
547951742c4SGregory Neil Shapiro **		field -- the name of the header field (will not be copied).
548951742c4SGregory Neil Shapiro **		value -- the value of the field (will be copied).
549bfb62e91SGregory Neil Shapiro **		flags -- flags to add to h_flags.
550bfb62e91SGregory Neil Shapiro **		rp -- resource pool for allocations
551951742c4SGregory Neil Shapiro **		space -- add leading space?
552bfb62e91SGregory Neil Shapiro **
553bfb62e91SGregory Neil Shapiro **	Returns:
554bfb62e91SGregory Neil Shapiro **		Pointer to a newly allocated and populated HDR.
555951742c4SGregory Neil Shapiro **
556951742c4SGregory Neil Shapiro **	Notes:
557951742c4SGregory Neil Shapiro **		o field and value must be in internal format, i.e.,
558951742c4SGregory Neil Shapiro **		metacharacters must be "quoted", see quote_internal_chars().
559951742c4SGregory Neil Shapiro **		o maybe add more flags to decide:
560951742c4SGregory Neil Shapiro **		  - what to copy (field/value)
561951742c4SGregory Neil Shapiro **		  - whether to convert value to an internal format
562bfb62e91SGregory Neil Shapiro */
563bfb62e91SGregory Neil Shapiro 
564bfb62e91SGregory Neil Shapiro static HDR *
565951742c4SGregory Neil Shapiro allocheader(field, value, flags, rp, space)
566bfb62e91SGregory Neil Shapiro 	char *field;
567bfb62e91SGregory Neil Shapiro 	char *value;
568bfb62e91SGregory Neil Shapiro 	int flags;
569bfb62e91SGregory Neil Shapiro 	SM_RPOOL_T *rp;
570951742c4SGregory Neil Shapiro 	bool space;
571bfb62e91SGregory Neil Shapiro {
572bfb62e91SGregory Neil Shapiro 	HDR *h;
573bfb62e91SGregory Neil Shapiro 	STAB *s;
574bfb62e91SGregory Neil Shapiro 
575bfb62e91SGregory Neil Shapiro 	/* find info struct */
576bfb62e91SGregory Neil Shapiro 	s = stab(field, ST_HEADER, ST_FIND);
577bfb62e91SGregory Neil Shapiro 
578bfb62e91SGregory Neil Shapiro 	/* allocate space for new header */
579951742c4SGregory Neil Shapiro 	h = (HDR *) sm_rpool_malloc_x(rp, sizeof(*h));
580bfb62e91SGregory Neil Shapiro 	h->h_field = field;
581951742c4SGregory Neil Shapiro 	if (space)
582951742c4SGregory Neil Shapiro 	{
583951742c4SGregory Neil Shapiro 		size_t l;
584951742c4SGregory Neil Shapiro 		char *n;
585951742c4SGregory Neil Shapiro 
586951742c4SGregory Neil Shapiro 		l = strlen(value);
587951742c4SGregory Neil Shapiro 		SM_ASSERT(l + 2 > l);
588951742c4SGregory Neil Shapiro 		n = sm_rpool_malloc_x(rp, l + 2);
589951742c4SGregory Neil Shapiro 		n[0] = ' ';
590951742c4SGregory Neil Shapiro 		n[1] = '\0';
591951742c4SGregory Neil Shapiro 		sm_strlcpy(n + 1, value, l + 1);
592951742c4SGregory Neil Shapiro 		h->h_value = n;
593951742c4SGregory Neil Shapiro 	}
594951742c4SGregory Neil Shapiro 	else
595bfb62e91SGregory Neil Shapiro 		h->h_value = sm_rpool_strdup_x(rp, value);
596bfb62e91SGregory Neil Shapiro 	h->h_flags = flags;
597bfb62e91SGregory Neil Shapiro 	if (s != NULL)
598bfb62e91SGregory Neil Shapiro 		h->h_flags |= s->s_header.hi_flags;
599bfb62e91SGregory Neil Shapiro 	clrbitmap(h->h_mflags);
600bfb62e91SGregory Neil Shapiro 	h->h_macro = '\0';
601bfb62e91SGregory Neil Shapiro 
602bfb62e91SGregory Neil Shapiro 	return h;
603bfb62e91SGregory Neil Shapiro }
604951742c4SGregory Neil Shapiro 
605bfb62e91SGregory Neil Shapiro /*
606c2aa98e2SPeter Wemm **  ADDHEADER -- add a header entry to the end of the queue.
607c2aa98e2SPeter Wemm **
608c2aa98e2SPeter Wemm **	This bypasses the special checking of chompheader.
609c2aa98e2SPeter Wemm **
610c2aa98e2SPeter Wemm **	Parameters:
611951742c4SGregory Neil Shapiro **		field -- the name of the header field (will not be copied).
612951742c4SGregory Neil Shapiro **		value -- the value of the field (will be copied).
6133299c2f1SGregory Neil Shapiro **		flags -- flags to add to h_flags.
61412ed1c7cSGregory Neil Shapiro **		e -- envelope.
615951742c4SGregory Neil Shapiro **		space -- add leading space?
616c2aa98e2SPeter Wemm **
617c2aa98e2SPeter Wemm **	Returns:
618c2aa98e2SPeter Wemm **		none.
619c2aa98e2SPeter Wemm **
620c2aa98e2SPeter Wemm **	Side Effects:
621c2aa98e2SPeter Wemm **		adds the field on the list of headers for this envelope.
622951742c4SGregory Neil Shapiro **
623951742c4SGregory Neil Shapiro **	Notes: field and value must be in internal format, i.e.,
624951742c4SGregory Neil Shapiro **		metacharacters must be "quoted", see quote_internal_chars().
625c2aa98e2SPeter Wemm */
626c2aa98e2SPeter Wemm 
627c2aa98e2SPeter Wemm void
628951742c4SGregory Neil Shapiro addheader(field, value, flags, e, space)
629c2aa98e2SPeter Wemm 	char *field;
630c2aa98e2SPeter Wemm 	char *value;
6313299c2f1SGregory Neil Shapiro 	int flags;
63212ed1c7cSGregory Neil Shapiro 	ENVELOPE *e;
633951742c4SGregory Neil Shapiro 	bool space;
634c2aa98e2SPeter Wemm {
635c2aa98e2SPeter Wemm 	register HDR *h;
636c2aa98e2SPeter Wemm 	HDR **hp;
63712ed1c7cSGregory Neil Shapiro 	HDR **hdrlist = &e->e_header;
638c2aa98e2SPeter Wemm 
639c2aa98e2SPeter Wemm 	/* find current place in list -- keep back pointer? */
640c2aa98e2SPeter Wemm 	for (hp = hdrlist; (h = *hp) != NULL; hp = &h->h_link)
641c2aa98e2SPeter Wemm 	{
642*2fb4f839SGregory Neil Shapiro 		if (SM_STRCASEEQ(field, h->h_field))
643c2aa98e2SPeter Wemm 			break;
644c2aa98e2SPeter Wemm 	}
645c2aa98e2SPeter Wemm 
646c2aa98e2SPeter Wemm 	/* allocate space for new header */
647951742c4SGregory Neil Shapiro 	h = allocheader(field, value, flags, e->e_rpool, space);
648c2aa98e2SPeter Wemm 	h->h_link = *hp;
649c2aa98e2SPeter Wemm 	*hp = h;
650c2aa98e2SPeter Wemm }
651951742c4SGregory Neil Shapiro 
65212ed1c7cSGregory Neil Shapiro /*
653bfb62e91SGregory Neil Shapiro **  INSHEADER -- insert a header entry at the specified index
654bfb62e91SGregory Neil Shapiro **	This bypasses the special checking of chompheader.
655bfb62e91SGregory Neil Shapiro **
656bfb62e91SGregory Neil Shapiro **	Parameters:
657bfb62e91SGregory Neil Shapiro **		idx -- index into the header list at which to insert
658951742c4SGregory Neil Shapiro **		field -- the name of the header field (will be copied).
659951742c4SGregory Neil Shapiro **		value -- the value of the field (will be copied).
660bfb62e91SGregory Neil Shapiro **		flags -- flags to add to h_flags.
661bfb62e91SGregory Neil Shapiro **		e -- envelope.
662951742c4SGregory Neil Shapiro **		space -- add leading space?
663bfb62e91SGregory Neil Shapiro **
664bfb62e91SGregory Neil Shapiro **	Returns:
665bfb62e91SGregory Neil Shapiro **		none.
666bfb62e91SGregory Neil Shapiro **
667bfb62e91SGregory Neil Shapiro **	Side Effects:
668bfb62e91SGregory Neil Shapiro **		inserts the field on the list of headers for this envelope.
669951742c4SGregory Neil Shapiro **
670951742c4SGregory Neil Shapiro **	Notes:
671951742c4SGregory Neil Shapiro **		- field and value must be in internal format, i.e.,
672951742c4SGregory Neil Shapiro **		metacharacters must be "quoted", see quote_internal_chars().
673951742c4SGregory Neil Shapiro **		- the header list contains headers that might not be
674951742c4SGregory Neil Shapiro **		sent "out" (see putheader(): "skip"), hence there is no
675951742c4SGregory Neil Shapiro **		reliable way to insert a header at an exact position
676951742c4SGregory Neil Shapiro **		(except at the front or end).
677bfb62e91SGregory Neil Shapiro */
678bfb62e91SGregory Neil Shapiro 
679bfb62e91SGregory Neil Shapiro void
680951742c4SGregory Neil Shapiro insheader(idx, field, value, flags, e, space)
681bfb62e91SGregory Neil Shapiro 	int idx;
682bfb62e91SGregory Neil Shapiro 	char *field;
683bfb62e91SGregory Neil Shapiro 	char *value;
684bfb62e91SGregory Neil Shapiro 	int flags;
685bfb62e91SGregory Neil Shapiro 	ENVELOPE *e;
686951742c4SGregory Neil Shapiro 	bool space;
687bfb62e91SGregory Neil Shapiro {
688bfb62e91SGregory Neil Shapiro 	HDR *h, *srch, *last = NULL;
689bfb62e91SGregory Neil Shapiro 
690bfb62e91SGregory Neil Shapiro 	/* allocate space for new header */
691951742c4SGregory Neil Shapiro 	h = allocheader(field, value, flags, e->e_rpool, space);
692bfb62e91SGregory Neil Shapiro 
693bfb62e91SGregory Neil Shapiro 	/* find insertion position */
694bfb62e91SGregory Neil Shapiro 	for (srch = e->e_header; srch != NULL && idx > 0;
695bfb62e91SGregory Neil Shapiro 	     srch = srch->h_link, idx--)
696bfb62e91SGregory Neil Shapiro 		last = srch;
697bfb62e91SGregory Neil Shapiro 
698bfb62e91SGregory Neil Shapiro 	if (e->e_header == NULL)
699bfb62e91SGregory Neil Shapiro 	{
700bfb62e91SGregory Neil Shapiro 		e->e_header = h;
701bfb62e91SGregory Neil Shapiro 		h->h_link = NULL;
702bfb62e91SGregory Neil Shapiro 	}
703bfb62e91SGregory Neil Shapiro 	else if (srch == NULL)
704bfb62e91SGregory Neil Shapiro 	{
705bfb62e91SGregory Neil Shapiro 		SM_ASSERT(last != NULL);
706bfb62e91SGregory Neil Shapiro 		last->h_link = h;
707bfb62e91SGregory Neil Shapiro 		h->h_link = NULL;
708bfb62e91SGregory Neil Shapiro 	}
709bfb62e91SGregory Neil Shapiro 	else
710bfb62e91SGregory Neil Shapiro 	{
711bfb62e91SGregory Neil Shapiro 		h->h_link = srch->h_link;
712bfb62e91SGregory Neil Shapiro 		srch->h_link = h;
713bfb62e91SGregory Neil Shapiro 	}
714bfb62e91SGregory Neil Shapiro }
715951742c4SGregory Neil Shapiro 
716bfb62e91SGregory Neil Shapiro /*
717c2aa98e2SPeter Wemm **  HVALUE -- return value of a header.
718c2aa98e2SPeter Wemm **
719c2aa98e2SPeter Wemm **	Only "real" fields (i.e., ones that have not been supplied
720c2aa98e2SPeter Wemm **	as a default) are used.
721c2aa98e2SPeter Wemm **
722c2aa98e2SPeter Wemm **	Parameters:
723c2aa98e2SPeter Wemm **		field -- the field name.
724c2aa98e2SPeter Wemm **		header -- the header list.
725c2aa98e2SPeter Wemm **
726c2aa98e2SPeter Wemm **	Returns:
727951742c4SGregory Neil Shapiro **		pointer to the value part (internal format).
728c2aa98e2SPeter Wemm **		NULL if not found.
729c2aa98e2SPeter Wemm **
730c2aa98e2SPeter Wemm **	Side Effects:
731c2aa98e2SPeter Wemm **		none.
732c2aa98e2SPeter Wemm */
733c2aa98e2SPeter Wemm 
734c2aa98e2SPeter Wemm char *
735c2aa98e2SPeter Wemm hvalue(field, header)
736c2aa98e2SPeter Wemm 	char *field;
737c2aa98e2SPeter Wemm 	HDR *header;
738c2aa98e2SPeter Wemm {
739c2aa98e2SPeter Wemm 	register HDR *h;
740c2aa98e2SPeter Wemm 
741c2aa98e2SPeter Wemm 	for (h = header; h != NULL; h = h->h_link)
742c2aa98e2SPeter Wemm 	{
743c2aa98e2SPeter Wemm 		if (!bitset(H_DEFAULT, h->h_flags) &&
744*2fb4f839SGregory Neil Shapiro 		    SM_STRCASEEQ(h->h_field, field))
7459bd497b8SGregory Neil Shapiro 		{
7469bd497b8SGregory Neil Shapiro 			char *s;
7479bd497b8SGregory Neil Shapiro 
7489bd497b8SGregory Neil Shapiro 			s = h->h_value;
7499bd497b8SGregory Neil Shapiro 			if (s == NULL)
7509bd497b8SGregory Neil Shapiro 				return NULL;
7515b0945b5SGregory Neil Shapiro 			while (SM_ISSPACE(*s))
7529bd497b8SGregory Neil Shapiro 				s++;
7539bd497b8SGregory Neil Shapiro 			return s;
7549bd497b8SGregory Neil Shapiro 		}
755c2aa98e2SPeter Wemm 	}
7563299c2f1SGregory Neil Shapiro 	return NULL;
757c2aa98e2SPeter Wemm }
758951742c4SGregory Neil Shapiro 
75912ed1c7cSGregory Neil Shapiro /*
760c2aa98e2SPeter Wemm **  ISHEADER -- predicate telling if argument is a header.
761c2aa98e2SPeter Wemm **
762c2aa98e2SPeter Wemm **	A line is a header if it has a single word followed by
763c2aa98e2SPeter Wemm **	optional white space followed by a colon.
764c2aa98e2SPeter Wemm **
765c2aa98e2SPeter Wemm **	Header fields beginning with two dashes, although technically
766c2aa98e2SPeter Wemm **	permitted by RFC822, are automatically rejected in order
767c2aa98e2SPeter Wemm **	to make MIME work out.  Without this we could have a technically
768c2aa98e2SPeter Wemm **	legal header such as ``--"foo:bar"'' that would also be a legal
769c2aa98e2SPeter Wemm **	MIME separator.
770c2aa98e2SPeter Wemm **
771c2aa98e2SPeter Wemm **	Parameters:
772c2aa98e2SPeter Wemm **		h -- string to check for possible headerness.
773c2aa98e2SPeter Wemm **
774c2aa98e2SPeter Wemm **	Returns:
77512ed1c7cSGregory Neil Shapiro **		true if h is a header.
77612ed1c7cSGregory Neil Shapiro **		false otherwise.
777c2aa98e2SPeter Wemm **
778c2aa98e2SPeter Wemm **	Side Effects:
779c2aa98e2SPeter Wemm **		none.
780c2aa98e2SPeter Wemm */
781c2aa98e2SPeter Wemm 
782c2aa98e2SPeter Wemm bool
783c2aa98e2SPeter Wemm isheader(h)
784c2aa98e2SPeter Wemm 	char *h;
785c2aa98e2SPeter Wemm {
786951742c4SGregory Neil Shapiro 	char *s;
787c2aa98e2SPeter Wemm 
788951742c4SGregory Neil Shapiro 	s = h;
789c2aa98e2SPeter Wemm 	if (s[0] == '-' && s[1] == '-')
79012ed1c7cSGregory Neil Shapiro 		return false;
791c2aa98e2SPeter Wemm 
792c2aa98e2SPeter Wemm 	while (*s > ' ' && *s != ':' && *s != '\0')
793c2aa98e2SPeter Wemm 		s++;
794c2aa98e2SPeter Wemm 
795c2aa98e2SPeter Wemm 	if (h == s)
79612ed1c7cSGregory Neil Shapiro 		return false;
797c2aa98e2SPeter Wemm 
798c2aa98e2SPeter Wemm 	/* following technically violates RFC822 */
7995b0945b5SGregory Neil Shapiro 	while (SM_ISSPACE(*s))
800c2aa98e2SPeter Wemm 		s++;
801c2aa98e2SPeter Wemm 
802c2aa98e2SPeter Wemm 	return (*s == ':');
803c2aa98e2SPeter Wemm }
804951742c4SGregory Neil Shapiro 
80512ed1c7cSGregory Neil Shapiro /*
806c2aa98e2SPeter Wemm **  EATHEADER -- run through the stored header and extract info.
807c2aa98e2SPeter Wemm **
808c2aa98e2SPeter Wemm **	Parameters:
809c2aa98e2SPeter Wemm **		e -- the envelope to process.
810c2aa98e2SPeter Wemm **		full -- if set, do full processing (e.g., compute
811c2aa98e2SPeter Wemm **			message priority).  This should not be set
812c2aa98e2SPeter Wemm **			when reading a queue file because some info
813c2aa98e2SPeter Wemm **			needed to compute the priority is wrong.
81412ed1c7cSGregory Neil Shapiro **		log -- call logsender()?
815c2aa98e2SPeter Wemm **
816c2aa98e2SPeter Wemm **	Returns:
817c2aa98e2SPeter Wemm **		none.
818c2aa98e2SPeter Wemm **
819c2aa98e2SPeter Wemm **	Side Effects:
820c2aa98e2SPeter Wemm **		Sets a bunch of global variables from information
821c2aa98e2SPeter Wemm **			in the collected header.
822c2aa98e2SPeter Wemm */
823c2aa98e2SPeter Wemm 
824c2aa98e2SPeter Wemm void
82512ed1c7cSGregory Neil Shapiro eatheader(e, full, log)
826c2aa98e2SPeter Wemm 	register ENVELOPE *e;
827c2aa98e2SPeter Wemm 	bool full;
82812ed1c7cSGregory Neil Shapiro 	bool log;
829c2aa98e2SPeter Wemm {
830c2aa98e2SPeter Wemm 	register HDR *h;
831c2aa98e2SPeter Wemm 	register char *p;
832c2aa98e2SPeter Wemm 	int hopcnt = 0;
833c2aa98e2SPeter Wemm 	char buf[MAXLINE];
834c2aa98e2SPeter Wemm 
835c2aa98e2SPeter Wemm 	/*
836c2aa98e2SPeter Wemm 	**  Set up macros for possible expansion in headers.
837c2aa98e2SPeter Wemm 	*/
838c2aa98e2SPeter Wemm 
83912ed1c7cSGregory Neil Shapiro 	macdefine(&e->e_macro, A_PERM, 'f', e->e_sender);
84012ed1c7cSGregory Neil Shapiro 	macdefine(&e->e_macro, A_PERM, 'g', e->e_sender);
841c2aa98e2SPeter Wemm 	if (e->e_origrcpt != NULL && *e->e_origrcpt != '\0')
84212ed1c7cSGregory Neil Shapiro 		macdefine(&e->e_macro, A_PERM, 'u', e->e_origrcpt);
843c2aa98e2SPeter Wemm 	else
84412ed1c7cSGregory Neil Shapiro 		macdefine(&e->e_macro, A_PERM, 'u', NULL);
845c2aa98e2SPeter Wemm 
846c2aa98e2SPeter Wemm 	/* full name of from person */
847c2aa98e2SPeter Wemm 	p = hvalue("full-name", e->e_header);
848c2aa98e2SPeter Wemm 	if (p != NULL)
849c2aa98e2SPeter Wemm 	{
850c2aa98e2SPeter Wemm 		if (!rfc822_string(p))
851c2aa98e2SPeter Wemm 		{
852c2aa98e2SPeter Wemm 			/*
853c2aa98e2SPeter Wemm 			**  Quote a full name with special characters
854c2aa98e2SPeter Wemm 			**  as a comment so crackaddr() doesn't destroy
855c2aa98e2SPeter Wemm 			**  the name portion of the address.
856c2aa98e2SPeter Wemm 			*/
85712ed1c7cSGregory Neil Shapiro 
85812ed1c7cSGregory Neil Shapiro 			p = addquotes(p, e->e_rpool);
859c2aa98e2SPeter Wemm 		}
86012ed1c7cSGregory Neil Shapiro 		macdefine(&e->e_macro, A_PERM, 'x', p);
861c2aa98e2SPeter Wemm 	}
862c2aa98e2SPeter Wemm 
863c2aa98e2SPeter Wemm 	if (tTd(32, 1))
86412ed1c7cSGregory Neil Shapiro 		sm_dprintf("----- collected header -----\n");
86512ed1c7cSGregory Neil Shapiro 	e->e_msgid = NULL;
866c2aa98e2SPeter Wemm 	for (h = e->e_header; h != NULL; h = h->h_link)
867c2aa98e2SPeter Wemm 	{
868c2aa98e2SPeter Wemm 		if (tTd(32, 1))
86912ed1c7cSGregory Neil Shapiro 			sm_dprintf("%s:", h->h_field);
870c2aa98e2SPeter Wemm 		if (h->h_value == NULL)
871c2aa98e2SPeter Wemm 		{
872c2aa98e2SPeter Wemm 			if (tTd(32, 1))
87312ed1c7cSGregory Neil Shapiro 				sm_dprintf("<NULL>\n");
874c2aa98e2SPeter Wemm 			continue;
875c2aa98e2SPeter Wemm 		}
876c2aa98e2SPeter Wemm 
877c2aa98e2SPeter Wemm 		/* do early binding */
8783299c2f1SGregory Neil Shapiro 		if (bitset(H_DEFAULT, h->h_flags) &&
8793299c2f1SGregory Neil Shapiro 		    !bitset(H_BINDLATE, h->h_flags))
880c2aa98e2SPeter Wemm 		{
881c2aa98e2SPeter Wemm 			if (tTd(32, 1))
882c2aa98e2SPeter Wemm 			{
88312ed1c7cSGregory Neil Shapiro 				sm_dprintf("(");
884bfb62e91SGregory Neil Shapiro 				xputs(sm_debug_file(), h->h_value);
88512ed1c7cSGregory Neil Shapiro 				sm_dprintf(") ");
886c2aa98e2SPeter Wemm 			}
887951742c4SGregory Neil Shapiro 			expand(h->h_value, buf, sizeof(buf), e);
888951742c4SGregory Neil Shapiro 			if (buf[0] != '\0' &&
889951742c4SGregory Neil Shapiro 			    (buf[0] != ' ' || buf[1] != '\0'))
890c2aa98e2SPeter Wemm 			{
891c2aa98e2SPeter Wemm 				if (bitset(H_FROM, h->h_flags))
892f9218d3dSGregory Neil Shapiro 					expand(crackaddr(buf, e),
893951742c4SGregory Neil Shapiro 					       buf, sizeof(buf), e);
89412ed1c7cSGregory Neil Shapiro 				h->h_value = sm_rpool_strdup_x(e->e_rpool, buf);
895c2aa98e2SPeter Wemm 				h->h_flags &= ~H_DEFAULT;
896c2aa98e2SPeter Wemm 			}
897c2aa98e2SPeter Wemm 		}
898c2aa98e2SPeter Wemm 		if (tTd(32, 1))
899c2aa98e2SPeter Wemm 		{
900bfb62e91SGregory Neil Shapiro 			xputs(sm_debug_file(), h->h_value);
90112ed1c7cSGregory Neil Shapiro 			sm_dprintf("\n");
902c2aa98e2SPeter Wemm 		}
903c2aa98e2SPeter Wemm 
904c2aa98e2SPeter Wemm 		/* count the number of times it has been processed */
905c2aa98e2SPeter Wemm 		if (bitset(H_TRACE, h->h_flags))
906c2aa98e2SPeter Wemm 			hopcnt++;
907c2aa98e2SPeter Wemm 
908c2aa98e2SPeter Wemm 		/* send to this person if we so desire */
909c2aa98e2SPeter Wemm 		if (GrabTo && bitset(H_RCPT, h->h_flags) &&
910c2aa98e2SPeter Wemm 		    !bitset(H_DEFAULT, h->h_flags) &&
91112ed1c7cSGregory Neil Shapiro 		    (!bitset(EF_RESENT, e->e_flags) ||
91212ed1c7cSGregory Neil Shapiro 		     bitset(H_RESENT, h->h_flags)))
913c2aa98e2SPeter Wemm 		{
914c2aa98e2SPeter Wemm #if 0
915c2aa98e2SPeter Wemm 			int saveflags = e->e_flags;
9165b0945b5SGregory Neil Shapiro #endif
917c2aa98e2SPeter Wemm 
91812ed1c7cSGregory Neil Shapiro 			(void) sendtolist(denlstring(h->h_value, true, false),
91912ed1c7cSGregory Neil Shapiro 					  NULLADDR, &e->e_sendqueue, 0, e);
920c2aa98e2SPeter Wemm 
921c2aa98e2SPeter Wemm #if 0
922c2aa98e2SPeter Wemm 			/*
923c2aa98e2SPeter Wemm 			**  Change functionality so a fatal error on an
924c2aa98e2SPeter Wemm 			**  address doesn't affect the entire envelope.
925c2aa98e2SPeter Wemm 			*/
926c2aa98e2SPeter Wemm 
927c2aa98e2SPeter Wemm 			/* delete fatal errors generated by this address */
928c2aa98e2SPeter Wemm 			if (!bitset(EF_FATALERRS, saveflags))
929c2aa98e2SPeter Wemm 				e->e_flags &= ~EF_FATALERRS;
9303299c2f1SGregory Neil Shapiro #endif /* 0 */
931c2aa98e2SPeter Wemm 		}
932c2aa98e2SPeter Wemm 
933c2aa98e2SPeter Wemm 		/* save the message-id for logging */
934c2aa98e2SPeter Wemm 		p = "resent-message-id";
935c2aa98e2SPeter Wemm 		if (!bitset(EF_RESENT, e->e_flags))
936c2aa98e2SPeter Wemm 			p += 7;
937*2fb4f839SGregory Neil Shapiro 		if (SM_STRCASEEQ(h->h_field, p))
938c2aa98e2SPeter Wemm 		{
93912ed1c7cSGregory Neil Shapiro 			e->e_msgid = h->h_value;
940*2fb4f839SGregory Neil Shapiro 			while (SM_ISSPACE(*e->e_msgid))
94112ed1c7cSGregory Neil Shapiro 				e->e_msgid++;
9421ae5b8d4SGregory Neil Shapiro 			macdefine(&e->e_macro, A_PERM, macid("{msg_id}"),
9431ae5b8d4SGregory Neil Shapiro 				  e->e_msgid);
944c2aa98e2SPeter Wemm 		}
945c2aa98e2SPeter Wemm 	}
946c2aa98e2SPeter Wemm 	if (tTd(32, 1))
94712ed1c7cSGregory Neil Shapiro 		sm_dprintf("----------------------------\n");
948c2aa98e2SPeter Wemm 
949c2aa98e2SPeter Wemm 	/* if we are just verifying (that is, sendmail -t -bv), drop out now */
950c2aa98e2SPeter Wemm 	if (OpMode == MD_VERIFY)
951c2aa98e2SPeter Wemm 		return;
952c2aa98e2SPeter Wemm 
953c2aa98e2SPeter Wemm 	/* store hop count */
954c2aa98e2SPeter Wemm 	if (hopcnt > e->e_hopcount)
95512ed1c7cSGregory Neil Shapiro 	{
956c2aa98e2SPeter Wemm 		e->e_hopcount = hopcnt;
957951742c4SGregory Neil Shapiro 		(void) sm_snprintf(buf, sizeof(buf), "%d", e->e_hopcount);
95812ed1c7cSGregory Neil Shapiro 		macdefine(&e->e_macro, A_TEMP, 'c', buf);
95912ed1c7cSGregory Neil Shapiro 	}
960c2aa98e2SPeter Wemm 
961c2aa98e2SPeter Wemm 	/* message priority */
962c2aa98e2SPeter Wemm 	p = hvalue("precedence", e->e_header);
963c2aa98e2SPeter Wemm 	if (p != NULL)
964c2aa98e2SPeter Wemm 		e->e_class = priencode(p);
965c2aa98e2SPeter Wemm 	if (e->e_class < 0)
966c2aa98e2SPeter Wemm 		e->e_timeoutclass = TOC_NONURGENT;
967c2aa98e2SPeter Wemm 	else if (e->e_class > 0)
968c2aa98e2SPeter Wemm 		e->e_timeoutclass = TOC_URGENT;
969c2aa98e2SPeter Wemm 	if (full)
970c2aa98e2SPeter Wemm 	{
971c2aa98e2SPeter Wemm 		e->e_msgpriority = e->e_msgsize
972c2aa98e2SPeter Wemm 				 - e->e_class * WkClassFact
973c2aa98e2SPeter Wemm 				 + e->e_nrcpts * WkRecipFact;
974c2aa98e2SPeter Wemm 	}
975c2aa98e2SPeter Wemm 
976bfb62e91SGregory Neil Shapiro 	/* check for DSN to properly set e_timeoutclass */
977bfb62e91SGregory Neil Shapiro 	p = hvalue("content-type", e->e_header);
978bfb62e91SGregory Neil Shapiro 	if (p != NULL)
979bfb62e91SGregory Neil Shapiro 	{
980bfb62e91SGregory Neil Shapiro 		bool oldsupr;
981bfb62e91SGregory Neil Shapiro 		char **pvp;
982bfb62e91SGregory Neil Shapiro 		char pvpbuf[MAXLINE];
983bfb62e91SGregory Neil Shapiro 		extern unsigned char MimeTokenTab[256];
984bfb62e91SGregory Neil Shapiro 
985bfb62e91SGregory Neil Shapiro 		/* tokenize header */
986bfb62e91SGregory Neil Shapiro 		oldsupr = SuprErrs;
987bfb62e91SGregory Neil Shapiro 		SuprErrs = true;
988951742c4SGregory Neil Shapiro 		pvp = prescan(p, '\0', pvpbuf, sizeof(pvpbuf), NULL,
989bfb62e91SGregory Neil Shapiro 			      MimeTokenTab, false);
990bfb62e91SGregory Neil Shapiro 		SuprErrs = oldsupr;
991bfb62e91SGregory Neil Shapiro 
992bfb62e91SGregory Neil Shapiro 		/* Check if multipart/report */
993bfb62e91SGregory Neil Shapiro 		if (pvp != NULL && pvp[0] != NULL &&
994bfb62e91SGregory Neil Shapiro 		    pvp[1] != NULL && pvp[2] != NULL &&
995*2fb4f839SGregory Neil Shapiro 		    SM_STRCASEEQ(*pvp++, "multipart") &&
996bfb62e91SGregory Neil Shapiro 		    strcmp(*pvp++, "/") == 0 &&
997*2fb4f839SGregory Neil Shapiro 		    SM_STRCASEEQ(*pvp++, "report"))
998bfb62e91SGregory Neil Shapiro 		{
999bfb62e91SGregory Neil Shapiro 			/* Look for report-type=delivery-status */
1000bfb62e91SGregory Neil Shapiro 			while (*pvp != NULL)
1001bfb62e91SGregory Neil Shapiro 			{
1002bfb62e91SGregory Neil Shapiro 				/* skip to semicolon separator */
1003bfb62e91SGregory Neil Shapiro 				while (*pvp != NULL && strcmp(*pvp, ";") != 0)
1004bfb62e91SGregory Neil Shapiro 					pvp++;
1005bfb62e91SGregory Neil Shapiro 
1006bfb62e91SGregory Neil Shapiro 				/* skip semicolon */
1007bfb62e91SGregory Neil Shapiro 				if (*pvp++ == NULL || *pvp == NULL)
1008bfb62e91SGregory Neil Shapiro 					break;
1009bfb62e91SGregory Neil Shapiro 
1010bfb62e91SGregory Neil Shapiro 				/* look for report-type */
1011*2fb4f839SGregory Neil Shapiro 				if (!SM_STRCASEEQ(*pvp++, "report-type"))
1012bfb62e91SGregory Neil Shapiro 					continue;
1013bfb62e91SGregory Neil Shapiro 
1014bfb62e91SGregory Neil Shapiro 				/* skip equal */
1015bfb62e91SGregory Neil Shapiro 				if (*pvp == NULL || strcmp(*pvp, "=") != 0)
1016bfb62e91SGregory Neil Shapiro 					continue;
1017bfb62e91SGregory Neil Shapiro 
1018bfb62e91SGregory Neil Shapiro 				/* check value */
1019bfb62e91SGregory Neil Shapiro 				if (*++pvp != NULL &&
1020*2fb4f839SGregory Neil Shapiro 				    SM_STRCASEEQ(*pvp, "delivery-status"))
1021bfb62e91SGregory Neil Shapiro 					e->e_timeoutclass = TOC_DSN;
1022bfb62e91SGregory Neil Shapiro 
1023bfb62e91SGregory Neil Shapiro 				/* found report-type, no need to continue */
1024bfb62e91SGregory Neil Shapiro 				break;
1025bfb62e91SGregory Neil Shapiro 			}
1026bfb62e91SGregory Neil Shapiro 		}
1027bfb62e91SGregory Neil Shapiro 	}
1028bfb62e91SGregory Neil Shapiro 
1029c2aa98e2SPeter Wemm 	/* message timeout priority */
1030c2aa98e2SPeter Wemm 	p = hvalue("priority", e->e_header);
1031c2aa98e2SPeter Wemm 	if (p != NULL)
1032c2aa98e2SPeter Wemm 	{
1033c2aa98e2SPeter Wemm 		/* (this should be in the configuration file) */
1034*2fb4f839SGregory Neil Shapiro 		if (SM_STRCASEEQ(p, "urgent"))
1035c2aa98e2SPeter Wemm 			e->e_timeoutclass = TOC_URGENT;
1036*2fb4f839SGregory Neil Shapiro 		else if (SM_STRCASEEQ(p, "normal"))
1037c2aa98e2SPeter Wemm 			e->e_timeoutclass = TOC_NORMAL;
1038*2fb4f839SGregory Neil Shapiro 		else if (SM_STRCASEEQ(p, "non-urgent"))
1039c2aa98e2SPeter Wemm 			e->e_timeoutclass = TOC_NONURGENT;
10401ae5b8d4SGregory Neil Shapiro 		else if (bitset(EF_RESPONSE, e->e_flags))
10411ae5b8d4SGregory Neil Shapiro 			e->e_timeoutclass = TOC_DSN;
10421ae5b8d4SGregory Neil Shapiro 	}
10431ae5b8d4SGregory Neil Shapiro 	else if (bitset(EF_RESPONSE, e->e_flags))
104472936242SGregory Neil Shapiro 		e->e_timeoutclass = TOC_DSN;
104572936242SGregory Neil Shapiro 
1046c2aa98e2SPeter Wemm 	/* date message originated */
1047c2aa98e2SPeter Wemm 	p = hvalue("posted-date", e->e_header);
1048c2aa98e2SPeter Wemm 	if (p == NULL)
1049c2aa98e2SPeter Wemm 		p = hvalue("date", e->e_header);
1050c2aa98e2SPeter Wemm 	if (p != NULL)
105112ed1c7cSGregory Neil Shapiro 		macdefine(&e->e_macro, A_PERM, 'a', p);
1052c2aa98e2SPeter Wemm 
1053c2aa98e2SPeter Wemm 	/* check to see if this is a MIME message */
1054c2aa98e2SPeter Wemm 	if ((e->e_bodytype != NULL &&
1055*2fb4f839SGregory Neil Shapiro 	     SM_STRCASEEQ(e->e_bodytype, "8bitmime")) ||
1056c2aa98e2SPeter Wemm 	    hvalue("MIME-Version", e->e_header) != NULL)
1057c2aa98e2SPeter Wemm 	{
1058c2aa98e2SPeter Wemm 		e->e_flags |= EF_IS_MIME;
1059c2aa98e2SPeter Wemm 		if (HasEightBits)
1060c2aa98e2SPeter Wemm 			e->e_bodytype = "8BITMIME";
1061c2aa98e2SPeter Wemm 	}
1062c2aa98e2SPeter Wemm 	else if ((p = hvalue("Content-Type", e->e_header)) != NULL)
1063c2aa98e2SPeter Wemm 	{
1064c2aa98e2SPeter Wemm 		/* this may be an RFC 1049 message */
1065c2aa98e2SPeter Wemm 		p = strpbrk(p, ";/");
1066c2aa98e2SPeter Wemm 		if (p == NULL || *p == ';')
1067c2aa98e2SPeter Wemm 		{
1068c2aa98e2SPeter Wemm 			/* yep, it is */
1069c2aa98e2SPeter Wemm 			e->e_flags |= EF_DONT_MIME;
1070c2aa98e2SPeter Wemm 		}
1071c2aa98e2SPeter Wemm 	}
1072c2aa98e2SPeter Wemm 
1073c2aa98e2SPeter Wemm 	/*
1074c2aa98e2SPeter Wemm 	**  From person in antiquated ARPANET mode
1075c2aa98e2SPeter Wemm 	**	required by UK Grey Book e-mail gateways (sigh)
1076c2aa98e2SPeter Wemm 	*/
1077c2aa98e2SPeter Wemm 
1078c2aa98e2SPeter Wemm 	if (OpMode == MD_ARPAFTP)
1079c2aa98e2SPeter Wemm 	{
1080c2aa98e2SPeter Wemm 		register struct hdrinfo *hi;
1081c2aa98e2SPeter Wemm 
1082c2aa98e2SPeter Wemm 		for (hi = HdrInfo; hi->hi_field != NULL; hi++)
1083c2aa98e2SPeter Wemm 		{
1084c2aa98e2SPeter Wemm 			if (bitset(H_FROM, hi->hi_flags) &&
1085c2aa98e2SPeter Wemm 			    (!bitset(H_RESENT, hi->hi_flags) ||
1086c2aa98e2SPeter Wemm 			     bitset(EF_RESENT, e->e_flags)) &&
1087c2aa98e2SPeter Wemm 			    (p = hvalue(hi->hi_field, e->e_header)) != NULL)
1088c2aa98e2SPeter Wemm 				break;
1089c2aa98e2SPeter Wemm 		}
1090c2aa98e2SPeter Wemm 		if (hi->hi_field != NULL)
1091c2aa98e2SPeter Wemm 		{
1092c2aa98e2SPeter Wemm 			if (tTd(32, 2))
109312ed1c7cSGregory Neil Shapiro 				sm_dprintf("eatheader: setsender(*%s == %s)\n",
1094c2aa98e2SPeter Wemm 					hi->hi_field, p);
109512ed1c7cSGregory Neil Shapiro 			setsender(p, e, NULL, '\0', true);
1096c2aa98e2SPeter Wemm 		}
1097c2aa98e2SPeter Wemm 	}
1098c2aa98e2SPeter Wemm 
1099c2aa98e2SPeter Wemm 	/*
1100c2aa98e2SPeter Wemm 	**  Log collection information.
1101c2aa98e2SPeter Wemm 	*/
1102c2aa98e2SPeter Wemm 
11039bd497b8SGregory Neil Shapiro 	if (tTd(92, 2))
11049bd497b8SGregory Neil Shapiro 		sm_dprintf("eatheader: e_id=%s, EF_LOGSENDER=%d, LogLevel=%d, log=%d\n",
11059bd497b8SGregory Neil Shapiro 			e->e_id, bitset(EF_LOGSENDER, e->e_flags), LogLevel,
11069bd497b8SGregory Neil Shapiro 			log);
110712ed1c7cSGregory Neil Shapiro 	if (log && bitset(EF_LOGSENDER, e->e_flags) && LogLevel > 4)
110812ed1c7cSGregory Neil Shapiro 	{
110912ed1c7cSGregory Neil Shapiro 		logsender(e, e->e_msgid);
1110c2aa98e2SPeter Wemm 		e->e_flags &= ~EF_LOGSENDER;
1111c2aa98e2SPeter Wemm 	}
111212ed1c7cSGregory Neil Shapiro }
1113951742c4SGregory Neil Shapiro 
111412ed1c7cSGregory Neil Shapiro /*
1115c2aa98e2SPeter Wemm **  LOGSENDER -- log sender information
1116c2aa98e2SPeter Wemm **
1117c2aa98e2SPeter Wemm **	Parameters:
1118c2aa98e2SPeter Wemm **		e -- the envelope to log
1119c2aa98e2SPeter Wemm **		msgid -- the message id
1120c2aa98e2SPeter Wemm **
1121c2aa98e2SPeter Wemm **	Returns:
1122c2aa98e2SPeter Wemm **		none
1123c2aa98e2SPeter Wemm */
1124c2aa98e2SPeter Wemm 
1125*2fb4f839SGregory Neil Shapiro 
1126*2fb4f839SGregory Neil Shapiro #define XBUFLEN MAXNAME
1127*2fb4f839SGregory Neil Shapiro #if (SYSLOG_BUFSIZE) >= 256
1128*2fb4f839SGregory Neil Shapiro # ifndef MSGIDLOGLEN
1129*2fb4f839SGregory Neil Shapiro #  define MSGIDLOGLEN 100
1130*2fb4f839SGregory Neil Shapiro #  define FIRSTLOGLEN 850
1131*2fb4f839SGregory Neil Shapiro # else
1132*2fb4f839SGregory Neil Shapiro #  if MSGIDLOGLEN < 100
1133*2fb4f839SGregory Neil Shapiro #    ERROR "MSGIDLOGLEN too short"
1134*2fb4f839SGregory Neil Shapiro #  endif
1135*2fb4f839SGregory Neil Shapiro /* XREF: this is "sizeof(sbuf)", see above */
1136*2fb4f839SGregory Neil Shapiro #  if MSGIDLOGLEN >= MAXLINE / 2
1137*2fb4f839SGregory Neil Shapiro #    ERROR "MSGIDLOGLEN too long"
1138*2fb4f839SGregory Neil Shapiro #  endif
1139*2fb4f839SGregory Neil Shapiro 
1140*2fb4f839SGregory Neil Shapiro /* 850 - 100 for original MSGIDLOGLEN */
1141*2fb4f839SGregory Neil Shapiro #  define FIRSTLOGLEN (750 + MSGIDLOGLEN)
1142*2fb4f839SGregory Neil Shapiro 
1143*2fb4f839SGregory Neil Shapiro /* check that total length is ok */
1144*2fb4f839SGregory Neil Shapiro #  if FIRSTLOGLEN + 200 >= MAXLINE
1145*2fb4f839SGregory Neil Shapiro #    ERROR "MSGIDLOGLEN too long"
1146*2fb4f839SGregory Neil Shapiro #  endif
1147*2fb4f839SGregory Neil Shapiro #  if MSGIDLOGLEN > MAXNAME
1148*2fb4f839SGregory Neil Shapiro #    undef XBUFLEN
1149*2fb4f839SGregory Neil Shapiro #    define XBUFLEN MSGIDLOGLEN
1150*2fb4f839SGregory Neil Shapiro #  endif
1151*2fb4f839SGregory Neil Shapiro # endif
1152*2fb4f839SGregory Neil Shapiro #endif /* (SYSLOG_BUFSIZE) >= 256 */
1153*2fb4f839SGregory Neil Shapiro 
1154c2aa98e2SPeter Wemm void
1155c2aa98e2SPeter Wemm logsender(e, msgid)
1156c2aa98e2SPeter Wemm 	register ENVELOPE *e;
1157c2aa98e2SPeter Wemm 	char *msgid;
1158c2aa98e2SPeter Wemm {
1159c2aa98e2SPeter Wemm 	char *name;
1160c2aa98e2SPeter Wemm 	register char *sbp;
1161c2aa98e2SPeter Wemm 	register char *p;
1162*2fb4f839SGregory Neil Shapiro 	char hbuf[MAXNAME + 1];	/* EAI:ok; restricted to short size */
1163*2fb4f839SGregory Neil Shapiro 	char sbuf[MAXLINE + 1]; /* EAI:ok; XREF: see also MSGIDLOGLEN */
1164*2fb4f839SGregory Neil Shapiro #if _FFR_8BITENVADDR
1165*2fb4f839SGregory Neil Shapiro 	char xbuf[XBUFLEN + 1];	/* EAI:ok */
1166*2fb4f839SGregory Neil Shapiro #endif
1167*2fb4f839SGregory Neil Shapiro 	char *xstr;
1168c2aa98e2SPeter Wemm 
1169c2aa98e2SPeter Wemm 	if (bitset(EF_RESPONSE, e->e_flags))
1170c2aa98e2SPeter Wemm 		name = "[RESPONSE]";
1171c2aa98e2SPeter Wemm 	else if ((name = macvalue('_', e)) != NULL)
11723299c2f1SGregory Neil Shapiro 		/* EMPTY */
1173c2aa98e2SPeter Wemm 		;
1174c2aa98e2SPeter Wemm 	else if (RealHostName == NULL)
1175c2aa98e2SPeter Wemm 		name = "localhost";
1176c2aa98e2SPeter Wemm 	else if (RealHostName[0] == '[')
1177c2aa98e2SPeter Wemm 		name = RealHostName;
1178c2aa98e2SPeter Wemm 	else
1179c2aa98e2SPeter Wemm 	{
1180c2aa98e2SPeter Wemm 		name = hbuf;
1181951742c4SGregory Neil Shapiro 		(void) sm_snprintf(hbuf, sizeof(hbuf), "%.80s", RealHostName);
1182c2aa98e2SPeter Wemm 		if (RealHostAddr.sa.sa_family != 0)
1183c2aa98e2SPeter Wemm 		{
1184c2aa98e2SPeter Wemm 			p = &hbuf[strlen(hbuf)];
118512ed1c7cSGregory Neil Shapiro 			(void) sm_snprintf(p, SPACELEFT(hbuf, p),
118612ed1c7cSGregory Neil Shapiro 					   " (%.100s)",
1187c2aa98e2SPeter Wemm 					   anynet_ntoa(&RealHostAddr));
1188c2aa98e2SPeter Wemm 		}
1189c2aa98e2SPeter Wemm 	}
1190c2aa98e2SPeter Wemm 
1191c2aa98e2SPeter Wemm #if (SYSLOG_BUFSIZE) >= 256
1192c2aa98e2SPeter Wemm 	sbp = sbuf;
1193*2fb4f839SGregory Neil Shapiro 	if (NULL != e->e_from.q_paddr)
1194*2fb4f839SGregory Neil Shapiro 	{
1195*2fb4f839SGregory Neil Shapiro 		xstr = e->e_from.q_paddr;
1196*2fb4f839SGregory Neil Shapiro # if _FFR_8BITENVADDR
1197*2fb4f839SGregory Neil Shapiro 		(void) dequote_internal_chars(e->e_from.q_paddr, xbuf, sizeof(xbuf));
1198*2fb4f839SGregory Neil Shapiro 		xstr = xbuf;
1199*2fb4f839SGregory Neil Shapiro # endif
1200*2fb4f839SGregory Neil Shapiro 	}
1201*2fb4f839SGregory Neil Shapiro 	else
1202*2fb4f839SGregory Neil Shapiro 		xstr = "<NONE>";
120312ed1c7cSGregory Neil Shapiro 	(void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp),
1204*2fb4f839SGregory Neil Shapiro 		"from=%.200s, size=%ld, class=%d, nrcpts=%d", xstr,
1205ba00ec3dSGregory Neil Shapiro 		PRT_NONNEGL(e->e_msgsize), e->e_class, e->e_nrcpts);
1206c2aa98e2SPeter Wemm 	sbp += strlen(sbp);
1207c2aa98e2SPeter Wemm 	if (msgid != NULL)
1208c2aa98e2SPeter Wemm 	{
1209*2fb4f839SGregory Neil Shapiro # if _FFR_8BITENVADDR
1210*2fb4f839SGregory Neil Shapiro 		(void) dequote_internal_chars(msgid, xbuf, sizeof(xbuf));
1211*2fb4f839SGregory Neil Shapiro 		msgid = xbuf;
12125b0945b5SGregory Neil Shapiro # endif
121312ed1c7cSGregory Neil Shapiro 		(void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp),
12145b0945b5SGregory Neil Shapiro 				", msgid=%.*s", MSGIDLOGLEN, msgid);
1215c2aa98e2SPeter Wemm 		sbp += strlen(sbp);
1216c2aa98e2SPeter Wemm 	}
1217c2aa98e2SPeter Wemm 	if (e->e_bodytype != NULL)
1218c2aa98e2SPeter Wemm 	{
121912ed1c7cSGregory Neil Shapiro 		(void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp),
122012ed1c7cSGregory Neil Shapiro 				", bodytype=%.20s", e->e_bodytype);
1221c2aa98e2SPeter Wemm 		sbp += strlen(sbp);
1222c2aa98e2SPeter Wemm 	}
1223c2aa98e2SPeter Wemm 	p = macvalue('r', e);
1224c2aa98e2SPeter Wemm 	if (p != NULL)
12253299c2f1SGregory Neil Shapiro 	{
122612ed1c7cSGregory Neil Shapiro 		(void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp),
122712ed1c7cSGregory Neil Shapiro 				", proto=%.20s", p);
12283299c2f1SGregory Neil Shapiro 		sbp += strlen(sbp);
12293299c2f1SGregory Neil Shapiro 	}
123012ed1c7cSGregory Neil Shapiro 	p = macvalue(macid("{daemon_name}"), e);
12313299c2f1SGregory Neil Shapiro 	if (p != NULL)
12323299c2f1SGregory Neil Shapiro 	{
123312ed1c7cSGregory Neil Shapiro 		(void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp),
123412ed1c7cSGregory Neil Shapiro 				", daemon=%.20s", p);
12353299c2f1SGregory Neil Shapiro 		sbp += strlen(sbp);
12363299c2f1SGregory Neil Shapiro 	}
1237da7d7b9cSGregory Neil Shapiro # if _FFR_LOG_MORE1
12385b0945b5SGregory Neil Shapiro 	LOG_MORE(sbuf, sbp);
1239da7d7b9cSGregory Neil Shapiro #  if SASL
1240da7d7b9cSGregory Neil Shapiro 	p = macvalue(macid("{auth_type}"), e);
1241*2fb4f839SGregory Neil Shapiro 	if (SM_IS_EMPTY(p))
1242da7d7b9cSGregory Neil Shapiro 		p = "NONE";
1243da7d7b9cSGregory Neil Shapiro 	(void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp), ", auth=%.20s", p);
1244da7d7b9cSGregory Neil Shapiro 	sbp += strlen(sbp);
1245da7d7b9cSGregory Neil Shapiro #  endif /* SASL */
1246da7d7b9cSGregory Neil Shapiro # endif /* _FFR_LOG_MORE1 */
12475b0945b5SGregory Neil Shapiro 	sm_syslog(LOG_INFO, e->e_id, "%.*s, relay=%s", FIRSTLOGLEN, sbuf, name);
1248c2aa98e2SPeter Wemm 
12493299c2f1SGregory Neil Shapiro #else /* (SYSLOG_BUFSIZE) >= 256 */
1250c2aa98e2SPeter Wemm 
1251c2aa98e2SPeter Wemm 	sm_syslog(LOG_INFO, e->e_id,
1252c2aa98e2SPeter Wemm 		  "from=%s",
1253c2aa98e2SPeter Wemm 		  e->e_from.q_paddr == NULL ? "<NONE>"
125412ed1c7cSGregory Neil Shapiro 					    : shortenstring(e->e_from.q_paddr,
125512ed1c7cSGregory Neil Shapiro 							    83));
1256c2aa98e2SPeter Wemm 	sm_syslog(LOG_INFO, e->e_id,
12573299c2f1SGregory Neil Shapiro 		  "size=%ld, class=%ld, nrcpts=%d",
1258ba00ec3dSGregory Neil Shapiro 		  PRT_NONNEGL(e->e_msgsize), e->e_class, e->e_nrcpts);
1259c2aa98e2SPeter Wemm 	if (msgid != NULL)
1260*2fb4f839SGregory Neil Shapiro 	{
1261*2fb4f839SGregory Neil Shapiro # if _FFR_8BITENVADDR
1262*2fb4f839SGregory Neil Shapiro 		(void) dequote_internal_chars(msgid, xbuf, sizeof(xbuf));
1263*2fb4f839SGregory Neil Shapiro 		msgid = xbuf;
1264*2fb4f839SGregory Neil Shapiro # endif
1265c2aa98e2SPeter Wemm 		sm_syslog(LOG_INFO, e->e_id,
1266c2aa98e2SPeter Wemm 			  "msgid=%s",
12675b0945b5SGregory Neil Shapiro 			  shortenstring(msgid, 83));
1268*2fb4f839SGregory Neil Shapiro 	}
1269c2aa98e2SPeter Wemm 	sbp = sbuf;
1270c2aa98e2SPeter Wemm 	*sbp = '\0';
1271c2aa98e2SPeter Wemm 	if (e->e_bodytype != NULL)
1272c2aa98e2SPeter Wemm 	{
127312ed1c7cSGregory Neil Shapiro 		(void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp),
127412ed1c7cSGregory Neil Shapiro 				"bodytype=%.20s, ", e->e_bodytype);
1275c2aa98e2SPeter Wemm 		sbp += strlen(sbp);
1276c2aa98e2SPeter Wemm 	}
1277c2aa98e2SPeter Wemm 	p = macvalue('r', e);
1278c2aa98e2SPeter Wemm 	if (p != NULL)
1279c2aa98e2SPeter Wemm 	{
128012ed1c7cSGregory Neil Shapiro 		(void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp),
128112ed1c7cSGregory Neil Shapiro 				"proto=%.20s, ", p);
1282c2aa98e2SPeter Wemm 		sbp += strlen(sbp);
1283c2aa98e2SPeter Wemm 	}
1284c2aa98e2SPeter Wemm 	sm_syslog(LOG_INFO, e->e_id,
12852ef40764SGregory Neil Shapiro 		  "%.400srelay=%s", sbuf, name);
12863299c2f1SGregory Neil Shapiro #endif /* (SYSLOG_BUFSIZE) >= 256 */
1287c2aa98e2SPeter Wemm }
1288951742c4SGregory Neil Shapiro 
128912ed1c7cSGregory Neil Shapiro /*
1290c2aa98e2SPeter Wemm **  PRIENCODE -- encode external priority names into internal values.
1291c2aa98e2SPeter Wemm **
1292c2aa98e2SPeter Wemm **	Parameters:
1293c2aa98e2SPeter Wemm **		p -- priority in ascii.
1294c2aa98e2SPeter Wemm **
1295c2aa98e2SPeter Wemm **	Returns:
1296c2aa98e2SPeter Wemm **		priority as a numeric level.
1297c2aa98e2SPeter Wemm **
1298c2aa98e2SPeter Wemm **	Side Effects:
1299c2aa98e2SPeter Wemm **		none.
1300c2aa98e2SPeter Wemm */
1301c2aa98e2SPeter Wemm 
13023299c2f1SGregory Neil Shapiro static int
1303c2aa98e2SPeter Wemm priencode(p)
1304c2aa98e2SPeter Wemm 	char *p;
1305c2aa98e2SPeter Wemm {
1306c2aa98e2SPeter Wemm 	register int i;
1307c2aa98e2SPeter Wemm 
1308c2aa98e2SPeter Wemm 	for (i = 0; i < NumPriorities; i++)
1309c2aa98e2SPeter Wemm 	{
1310*2fb4f839SGregory Neil Shapiro 		if (SM_STRCASEEQ(p, Priorities[i].pri_name))
13113299c2f1SGregory Neil Shapiro 			return Priorities[i].pri_val;
1312c2aa98e2SPeter Wemm 	}
1313c2aa98e2SPeter Wemm 
1314c2aa98e2SPeter Wemm 	/* unknown priority */
13153299c2f1SGregory Neil Shapiro 	return 0;
1316c2aa98e2SPeter Wemm }
1317951742c4SGregory Neil Shapiro 
131812ed1c7cSGregory Neil Shapiro /*
1319c2aa98e2SPeter Wemm **  CRACKADDR -- parse an address and turn it into a macro
1320c2aa98e2SPeter Wemm **
1321c2aa98e2SPeter Wemm **	This doesn't actually parse the address -- it just extracts
1322c2aa98e2SPeter Wemm **	it and replaces it with "$g".  The parse is totally ad hoc
1323c2aa98e2SPeter Wemm **	and isn't even guaranteed to leave something syntactically
1324c2aa98e2SPeter Wemm **	identical to what it started with.  However, it does leave
1325f9218d3dSGregory Neil Shapiro **	something semantically identical if possible, else at least
1326f9218d3dSGregory Neil Shapiro **	syntactically correct.
1327f9218d3dSGregory Neil Shapiro **
1328f9218d3dSGregory Neil Shapiro **	For example, it changes "Real Name <real@example.com> (Comment)"
1329f9218d3dSGregory Neil Shapiro **	to "Real Name <$g> (Comment)".
1330c2aa98e2SPeter Wemm **
1331c2aa98e2SPeter Wemm **	This algorithm has been cleaned up to handle a wider range
1332c2aa98e2SPeter Wemm **	of cases -- notably quoted and backslash escaped strings.
1333c2aa98e2SPeter Wemm **	This modification makes it substantially better at preserving
1334c2aa98e2SPeter Wemm **	the original syntax.
1335c2aa98e2SPeter Wemm **
1336c2aa98e2SPeter Wemm **	Parameters:
1337*2fb4f839SGregory Neil Shapiro **		addr -- the address to be cracked. [A]
1338f9218d3dSGregory Neil Shapiro **		e -- the current envelope.
1339c2aa98e2SPeter Wemm **
1340c2aa98e2SPeter Wemm **	Returns:
1341c2aa98e2SPeter Wemm **		a pointer to the new version.
1342c2aa98e2SPeter Wemm **
1343c2aa98e2SPeter Wemm **	Side Effects:
1344c2aa98e2SPeter Wemm **		none.
1345c2aa98e2SPeter Wemm **
1346c2aa98e2SPeter Wemm **	Warning:
1347*2fb4f839SGregory Neil Shapiro **		The return value is saved in static storage and should
1348c2aa98e2SPeter Wemm **		be copied if it is to be reused.
1349c2aa98e2SPeter Wemm */
1350c2aa98e2SPeter Wemm 
1351*2fb4f839SGregory Neil Shapiro #define SM_HAVE_ROOMB		((bp < buflim) && (buflim <= bufend))
1352*2fb4f839SGregory Neil Shapiro #if USE_EAI
1353*2fb4f839SGregory Neil Shapiro # define SM_HAVE_ROOM		((xlen < MAXNAME) && SM_HAVE_ROOMB)
1354*2fb4f839SGregory Neil Shapiro #else
1355*2fb4f839SGregory Neil Shapiro # define SM_HAVE_ROOM		SM_HAVE_ROOMB
1356*2fb4f839SGregory Neil Shapiro #endif
1357f9218d3dSGregory Neil Shapiro 
1358f9218d3dSGregory Neil Shapiro /*
1359f9218d3dSGregory Neil Shapiro **  Append a character to bp if we have room.
1360f9218d3dSGregory Neil Shapiro **  If not, punt and return $g.
1361f9218d3dSGregory Neil Shapiro */
1362f9218d3dSGregory Neil Shapiro 
1363f9218d3dSGregory Neil Shapiro #define SM_APPEND_CHAR(c)					\
1364f9218d3dSGregory Neil Shapiro 	do							\
1365f9218d3dSGregory Neil Shapiro 	{							\
1366*2fb4f839SGregory Neil Shapiro 		XLEN(c);					\
1367f9218d3dSGregory Neil Shapiro 		if (SM_HAVE_ROOM)				\
1368f9218d3dSGregory Neil Shapiro 			*bp++ = (c);				\
1369f9218d3dSGregory Neil Shapiro 		else						\
1370f9218d3dSGregory Neil Shapiro 			goto returng;				\
1371f9218d3dSGregory Neil Shapiro 	} while (0)
1372f9218d3dSGregory Neil Shapiro 
1373f9218d3dSGregory Neil Shapiro #if MAXNAME < 10
1374*2fb4f839SGregory Neil Shapiro # ERROR "MAXNAME must be at least 10"
13755b0945b5SGregory Neil Shapiro #endif
1376f9218d3dSGregory Neil Shapiro 
1377c2aa98e2SPeter Wemm char *
1378f9218d3dSGregory Neil Shapiro crackaddr(addr, e)
1379c2aa98e2SPeter Wemm 	register char *addr;
1380f9218d3dSGregory Neil Shapiro 	ENVELOPE *e;
1381c2aa98e2SPeter Wemm {
1382c2aa98e2SPeter Wemm 	register char *p;
1383c2aa98e2SPeter Wemm 	register char c;
1384f9218d3dSGregory Neil Shapiro 	int cmtlev;			/* comment level in input string */
1385f9218d3dSGregory Neil Shapiro 	int realcmtlev;			/* comment level in output string */
1386f9218d3dSGregory Neil Shapiro 	int anglelev;			/* angle level in input string */
1387f9218d3dSGregory Neil Shapiro 	int copylev;			/* 0 == in address, >0 copying */
1388f9218d3dSGregory Neil Shapiro 	int bracklev;			/* bracket level for IPv6 addr check */
1389f9218d3dSGregory Neil Shapiro 	bool addangle;			/* put closing angle in output */
1390f9218d3dSGregory Neil Shapiro 	bool qmode;			/* quoting in original string? */
1391f9218d3dSGregory Neil Shapiro 	bool realqmode;			/* quoting in output string? */
1392f9218d3dSGregory Neil Shapiro 	bool putgmac = false;		/* already wrote $g */
1393f9218d3dSGregory Neil Shapiro 	bool quoteit = false;		/* need to quote next character */
1394f9218d3dSGregory Neil Shapiro 	bool gotangle = false;		/* found first '<' */
1395f9218d3dSGregory Neil Shapiro 	bool gotcolon = false;		/* found a ':' */
1396c2aa98e2SPeter Wemm 	register char *bp;
1397c2aa98e2SPeter Wemm 	char *buflim;
1398c2aa98e2SPeter Wemm 	char *bufhead;
1399c2aa98e2SPeter Wemm 	char *addrhead;
1400f9218d3dSGregory Neil Shapiro 	char *bufend;
1401*2fb4f839SGregory Neil Shapiro 	static char buf[MAXNAME_I + 1];	/* XXX: EAI? */
1402*2fb4f839SGregory Neil Shapiro 	XLENDECL
1403c2aa98e2SPeter Wemm 
1404c2aa98e2SPeter Wemm 	if (tTd(33, 1))
140512ed1c7cSGregory Neil Shapiro 		sm_dprintf("crackaddr(%s)\n", addr);
1406c2aa98e2SPeter Wemm 
1407951742c4SGregory Neil Shapiro 	buflim = bufend = &buf[sizeof(buf) - 1];
1408951742c4SGregory Neil Shapiro 	bp = bufhead = buf;
1409951742c4SGregory Neil Shapiro 
1410951742c4SGregory Neil Shapiro 	/* skip over leading spaces but preserve them */
14115b0945b5SGregory Neil Shapiro 	while (*addr != '\0' && SM_ISSPACE(*addr))
1412951742c4SGregory Neil Shapiro 	{
1413951742c4SGregory Neil Shapiro 		SM_APPEND_CHAR(*addr);
1414c2aa98e2SPeter Wemm 		addr++;
1415951742c4SGregory Neil Shapiro 	}
1416951742c4SGregory Neil Shapiro 	bufhead = bp;
1417c2aa98e2SPeter Wemm 
1418c2aa98e2SPeter Wemm 	/*
1419c2aa98e2SPeter Wemm 	**  Start by assuming we have no angle brackets.  This will be
1420c2aa98e2SPeter Wemm 	**  adjusted later if we find them.
1421c2aa98e2SPeter Wemm 	*/
1422c2aa98e2SPeter Wemm 
1423c2aa98e2SPeter Wemm 	p = addrhead = addr;
1424f9218d3dSGregory Neil Shapiro 	copylev = anglelev = cmtlev = realcmtlev = 0;
1425c2aa98e2SPeter Wemm 	bracklev = 0;
1426f9218d3dSGregory Neil Shapiro 	qmode = realqmode = addangle = false;
1427c2aa98e2SPeter Wemm 
1428c2aa98e2SPeter Wemm 	while ((c = *p++) != '\0')
1429c2aa98e2SPeter Wemm 	{
1430c2aa98e2SPeter Wemm 		/*
1431f9218d3dSGregory Neil Shapiro 		**  Try to keep legal syntax using spare buffer space
1432f9218d3dSGregory Neil Shapiro 		**  (maintained by buflim).
1433c2aa98e2SPeter Wemm 		*/
1434c2aa98e2SPeter Wemm 
1435f9218d3dSGregory Neil Shapiro 		if (copylev > 0)
1436f9218d3dSGregory Neil Shapiro 			SM_APPEND_CHAR(c);
1437c2aa98e2SPeter Wemm 
1438c2aa98e2SPeter Wemm 		/* check for backslash escapes */
1439c2aa98e2SPeter Wemm 		if (c == '\\')
1440c2aa98e2SPeter Wemm 		{
1441c2aa98e2SPeter Wemm 			/* arrange to quote the address */
1442c2aa98e2SPeter Wemm 			if (cmtlev <= 0 && !qmode)
144312ed1c7cSGregory Neil Shapiro 				quoteit = true;
1444c2aa98e2SPeter Wemm 
1445c2aa98e2SPeter Wemm 			if ((c = *p++) == '\0')
1446c2aa98e2SPeter Wemm 			{
1447c2aa98e2SPeter Wemm 				/* too far */
1448c2aa98e2SPeter Wemm 				p--;
1449c2aa98e2SPeter Wemm 				goto putg;
1450c2aa98e2SPeter Wemm 			}
1451f9218d3dSGregory Neil Shapiro 			if (copylev > 0)
1452f9218d3dSGregory Neil Shapiro 				SM_APPEND_CHAR(c);
1453c2aa98e2SPeter Wemm 			goto putg;
1454c2aa98e2SPeter Wemm 		}
1455c2aa98e2SPeter Wemm 
1456c2aa98e2SPeter Wemm 		/* check for quoted strings */
1457c2aa98e2SPeter Wemm 		if (c == '"' && cmtlev <= 0)
1458c2aa98e2SPeter Wemm 		{
1459c2aa98e2SPeter Wemm 			qmode = !qmode;
1460f9218d3dSGregory Neil Shapiro 			if (copylev > 0 && SM_HAVE_ROOM)
1461f9218d3dSGregory Neil Shapiro 			{
1462f9218d3dSGregory Neil Shapiro 				if (realqmode)
1463f9218d3dSGregory Neil Shapiro 					buflim--;
1464f9218d3dSGregory Neil Shapiro 				else
1465f9218d3dSGregory Neil Shapiro 					buflim++;
1466c2aa98e2SPeter Wemm 				realqmode = !realqmode;
1467f9218d3dSGregory Neil Shapiro 			}
1468c2aa98e2SPeter Wemm 			continue;
1469c2aa98e2SPeter Wemm 		}
1470c2aa98e2SPeter Wemm 		if (qmode)
1471c2aa98e2SPeter Wemm 			goto putg;
1472c2aa98e2SPeter Wemm 
1473c2aa98e2SPeter Wemm 		/* check for comments */
1474c2aa98e2SPeter Wemm 		if (c == '(')
1475c2aa98e2SPeter Wemm 		{
1476c2aa98e2SPeter Wemm 			cmtlev++;
1477c2aa98e2SPeter Wemm 
1478c2aa98e2SPeter Wemm 			/* allow space for closing paren */
1479f9218d3dSGregory Neil Shapiro 			if (SM_HAVE_ROOM)
1480c2aa98e2SPeter Wemm 			{
1481c2aa98e2SPeter Wemm 				buflim--;
1482c2aa98e2SPeter Wemm 				realcmtlev++;
1483c2aa98e2SPeter Wemm 				if (copylev++ <= 0)
1484c2aa98e2SPeter Wemm 				{
1485c2aa98e2SPeter Wemm 					if (bp != bufhead)
1486f9218d3dSGregory Neil Shapiro 						SM_APPEND_CHAR(' ');
1487f9218d3dSGregory Neil Shapiro 					SM_APPEND_CHAR(c);
1488c2aa98e2SPeter Wemm 				}
1489c2aa98e2SPeter Wemm 			}
1490c2aa98e2SPeter Wemm 		}
1491c2aa98e2SPeter Wemm 		if (cmtlev > 0)
1492c2aa98e2SPeter Wemm 		{
1493c2aa98e2SPeter Wemm 			if (c == ')')
1494c2aa98e2SPeter Wemm 			{
1495c2aa98e2SPeter Wemm 				cmtlev--;
1496c2aa98e2SPeter Wemm 				copylev--;
1497f9218d3dSGregory Neil Shapiro 				if (SM_HAVE_ROOM)
1498c2aa98e2SPeter Wemm 				{
1499c2aa98e2SPeter Wemm 					realcmtlev--;
1500c2aa98e2SPeter Wemm 					buflim++;
1501c2aa98e2SPeter Wemm 				}
1502c2aa98e2SPeter Wemm 			}
1503c2aa98e2SPeter Wemm 			continue;
1504c2aa98e2SPeter Wemm 		}
1505c2aa98e2SPeter Wemm 		else if (c == ')')
1506c2aa98e2SPeter Wemm 		{
1507c2aa98e2SPeter Wemm 			/* syntax error: unmatched ) */
15087660b554SGregory Neil Shapiro 			if (copylev > 0 && SM_HAVE_ROOM && bp > bufhead)
1509c2aa98e2SPeter Wemm 				bp--;
1510c2aa98e2SPeter Wemm 		}
1511c2aa98e2SPeter Wemm 
1512c2aa98e2SPeter Wemm 		/* count nesting on [ ... ] (for IPv6 domain literals) */
1513c2aa98e2SPeter Wemm 		if (c == '[')
1514c2aa98e2SPeter Wemm 			bracklev++;
1515c2aa98e2SPeter Wemm 		else if (c == ']')
1516c2aa98e2SPeter Wemm 			bracklev--;
1517c2aa98e2SPeter Wemm 
1518c2aa98e2SPeter Wemm 		/* check for group: list; syntax */
1519c2aa98e2SPeter Wemm 		if (c == ':' && anglelev <= 0 && bracklev <= 0 &&
1520c2aa98e2SPeter Wemm 		    !gotcolon && !ColonOkInAddr)
1521c2aa98e2SPeter Wemm 		{
1522c2aa98e2SPeter Wemm 			register char *q;
1523c2aa98e2SPeter Wemm 
1524c2aa98e2SPeter Wemm 			/*
1525c2aa98e2SPeter Wemm 			**  Check for DECnet phase IV ``::'' (host::user)
1526f9218d3dSGregory Neil Shapiro 			**  or DECnet phase V ``:.'' syntaxes.  The latter
1527c2aa98e2SPeter Wemm 			**  covers ``user@DEC:.tay.myhost'' and
1528c2aa98e2SPeter Wemm 			**  ``DEC:.tay.myhost::user'' syntaxes (bletch).
1529c2aa98e2SPeter Wemm 			*/
1530c2aa98e2SPeter Wemm 
1531c2aa98e2SPeter Wemm 			if (*p == ':' || *p == '.')
1532c2aa98e2SPeter Wemm 			{
1533c2aa98e2SPeter Wemm 				if (cmtlev <= 0 && !qmode)
153412ed1c7cSGregory Neil Shapiro 					quoteit = true;
1535f9218d3dSGregory Neil Shapiro 				if (copylev > 0)
1536c2aa98e2SPeter Wemm 				{
1537f9218d3dSGregory Neil Shapiro 					SM_APPEND_CHAR(c);
1538f9218d3dSGregory Neil Shapiro 					SM_APPEND_CHAR(*p);
1539c2aa98e2SPeter Wemm 				}
1540c2aa98e2SPeter Wemm 				p++;
1541c2aa98e2SPeter Wemm 				goto putg;
1542c2aa98e2SPeter Wemm 			}
1543c2aa98e2SPeter Wemm 
154412ed1c7cSGregory Neil Shapiro 			gotcolon = true;
1545c2aa98e2SPeter Wemm 
1546c2aa98e2SPeter Wemm 			bp = bufhead;
1547c2aa98e2SPeter Wemm 			if (quoteit)
1548c2aa98e2SPeter Wemm 			{
1549f9218d3dSGregory Neil Shapiro 				SM_APPEND_CHAR('"');
1550c2aa98e2SPeter Wemm 
1551c2aa98e2SPeter Wemm 				/* back up over the ':' and any spaces */
1552c2aa98e2SPeter Wemm 				--p;
1553f9218d3dSGregory Neil Shapiro 				while (p > addr &&
1554f9218d3dSGregory Neil Shapiro 				       isascii(*--p) && isspace(*p))
1555c2aa98e2SPeter Wemm 					continue;
1556c2aa98e2SPeter Wemm 				p++;
1557c2aa98e2SPeter Wemm 			}
1558c2aa98e2SPeter Wemm 			for (q = addrhead; q < p; )
1559c2aa98e2SPeter Wemm 			{
1560c2aa98e2SPeter Wemm 				c = *q++;
1561c2aa98e2SPeter Wemm 				if (quoteit && c == '"')
1562f9218d3dSGregory Neil Shapiro 					SM_APPEND_CHAR('\\');
1563f9218d3dSGregory Neil Shapiro 				SM_APPEND_CHAR(c);
1564c2aa98e2SPeter Wemm 			}
1565c2aa98e2SPeter Wemm 			if (quoteit)
1566c2aa98e2SPeter Wemm 			{
1567c2aa98e2SPeter Wemm 				if (bp == &bufhead[1])
1568c2aa98e2SPeter Wemm 					bp--;
1569c2aa98e2SPeter Wemm 				else
1570f9218d3dSGregory Neil Shapiro 					SM_APPEND_CHAR('"');
1571c2aa98e2SPeter Wemm 				while ((c = *p++) != ':')
1572f9218d3dSGregory Neil Shapiro 					SM_APPEND_CHAR(c);
1573f9218d3dSGregory Neil Shapiro 				SM_APPEND_CHAR(c);
1574c2aa98e2SPeter Wemm 			}
1575c2aa98e2SPeter Wemm 
1576c2aa98e2SPeter Wemm 			/* any trailing white space is part of group: */
15775b0945b5SGregory Neil Shapiro 			while (SM_ISSPACE(*p))
1578f9218d3dSGregory Neil Shapiro 			{
1579f9218d3dSGregory Neil Shapiro 				SM_APPEND_CHAR(*p);
1580f9218d3dSGregory Neil Shapiro 				p++;
1581f9218d3dSGregory Neil Shapiro 			}
1582c2aa98e2SPeter Wemm 			copylev = 0;
158312ed1c7cSGregory Neil Shapiro 			putgmac = quoteit = false;
1584c2aa98e2SPeter Wemm 			bufhead = bp;
1585c2aa98e2SPeter Wemm 			addrhead = p;
1586c2aa98e2SPeter Wemm 			continue;
1587c2aa98e2SPeter Wemm 		}
1588c2aa98e2SPeter Wemm 
1589c2aa98e2SPeter Wemm 		if (c == ';' && copylev <= 0 && !ColonOkInAddr)
1590f9218d3dSGregory Neil Shapiro 			SM_APPEND_CHAR(c);
1591c2aa98e2SPeter Wemm 
1592c2aa98e2SPeter Wemm 		/* check for characters that may have to be quoted */
1593c2aa98e2SPeter Wemm 		if (strchr(MustQuoteChars, c) != NULL)
1594c2aa98e2SPeter Wemm 		{
1595c2aa98e2SPeter Wemm 			/*
1596c2aa98e2SPeter Wemm 			**  If these occur as the phrase part of a <>
1597c2aa98e2SPeter Wemm 			**  construct, but are not inside of () or already
1598c2aa98e2SPeter Wemm 			**  quoted, they will have to be quoted.  Note that
1599c2aa98e2SPeter Wemm 			**  now (but don't actually do the quoting).
1600c2aa98e2SPeter Wemm 			*/
1601c2aa98e2SPeter Wemm 
1602c2aa98e2SPeter Wemm 			if (cmtlev <= 0 && !qmode)
160312ed1c7cSGregory Neil Shapiro 				quoteit = true;
1604c2aa98e2SPeter Wemm 		}
1605c2aa98e2SPeter Wemm 
1606c2aa98e2SPeter Wemm 		/* check for angle brackets */
1607c2aa98e2SPeter Wemm 		if (c == '<')
1608c2aa98e2SPeter Wemm 		{
1609c2aa98e2SPeter Wemm 			register char *q;
1610c2aa98e2SPeter Wemm 
1611c2aa98e2SPeter Wemm 			/* assume first of two angles is bogus */
1612c2aa98e2SPeter Wemm 			if (gotangle)
161312ed1c7cSGregory Neil Shapiro 				quoteit = true;
161412ed1c7cSGregory Neil Shapiro 			gotangle = true;
1615c2aa98e2SPeter Wemm 
1616c2aa98e2SPeter Wemm 			/* oops -- have to change our mind */
1617c2aa98e2SPeter Wemm 			anglelev = 1;
1618f9218d3dSGregory Neil Shapiro 			if (SM_HAVE_ROOM)
1619f9218d3dSGregory Neil Shapiro 			{
1620f9218d3dSGregory Neil Shapiro 				if (!addangle)
1621f9218d3dSGregory Neil Shapiro 					buflim--;
1622f9218d3dSGregory Neil Shapiro 				addangle = true;
1623f9218d3dSGregory Neil Shapiro 			}
1624c2aa98e2SPeter Wemm 
1625c2aa98e2SPeter Wemm 			bp = bufhead;
1626c2aa98e2SPeter Wemm 			if (quoteit)
1627c2aa98e2SPeter Wemm 			{
1628f9218d3dSGregory Neil Shapiro 				SM_APPEND_CHAR('"');
1629c2aa98e2SPeter Wemm 
1630c2aa98e2SPeter Wemm 				/* back up over the '<' and any spaces */
1631c2aa98e2SPeter Wemm 				--p;
1632f9218d3dSGregory Neil Shapiro 				while (p > addr &&
1633f9218d3dSGregory Neil Shapiro 				       isascii(*--p) && isspace(*p))
1634c2aa98e2SPeter Wemm 					continue;
1635c2aa98e2SPeter Wemm 				p++;
1636c2aa98e2SPeter Wemm 			}
1637c2aa98e2SPeter Wemm 			for (q = addrhead; q < p; )
1638c2aa98e2SPeter Wemm 			{
1639c2aa98e2SPeter Wemm 				c = *q++;
1640c2aa98e2SPeter Wemm 				if (quoteit && c == '"')
1641f9218d3dSGregory Neil Shapiro 				{
1642f9218d3dSGregory Neil Shapiro 					SM_APPEND_CHAR('\\');
1643f9218d3dSGregory Neil Shapiro 					SM_APPEND_CHAR(c);
1644c2aa98e2SPeter Wemm 				}
1645f9218d3dSGregory Neil Shapiro 				else
1646f9218d3dSGregory Neil Shapiro 					SM_APPEND_CHAR(c);
1647c2aa98e2SPeter Wemm 			}
1648c2aa98e2SPeter Wemm 			if (quoteit)
1649c2aa98e2SPeter Wemm 			{
1650c2aa98e2SPeter Wemm 				if (bp == &buf[1])
1651c2aa98e2SPeter Wemm 					bp--;
1652c2aa98e2SPeter Wemm 				else
1653f9218d3dSGregory Neil Shapiro 					SM_APPEND_CHAR('"');
1654c2aa98e2SPeter Wemm 				while ((c = *p++) != '<')
1655f9218d3dSGregory Neil Shapiro 					SM_APPEND_CHAR(c);
1656f9218d3dSGregory Neil Shapiro 				SM_APPEND_CHAR(c);
1657c2aa98e2SPeter Wemm 			}
1658c2aa98e2SPeter Wemm 			copylev = 0;
165912ed1c7cSGregory Neil Shapiro 			putgmac = quoteit = false;
1660c2aa98e2SPeter Wemm 			continue;
1661c2aa98e2SPeter Wemm 		}
1662c2aa98e2SPeter Wemm 
1663c2aa98e2SPeter Wemm 		if (c == '>')
1664c2aa98e2SPeter Wemm 		{
1665c2aa98e2SPeter Wemm 			if (anglelev > 0)
1666c2aa98e2SPeter Wemm 			{
1667c2aa98e2SPeter Wemm 				anglelev--;
1668f9218d3dSGregory Neil Shapiro 				if (SM_HAVE_ROOM)
1669c2aa98e2SPeter Wemm 				{
1670f9218d3dSGregory Neil Shapiro 					if (addangle)
1671c2aa98e2SPeter Wemm 						buflim++;
1672f9218d3dSGregory Neil Shapiro 					addangle = false;
1673c2aa98e2SPeter Wemm 				}
1674c2aa98e2SPeter Wemm 			}
1675f9218d3dSGregory Neil Shapiro 			else if (SM_HAVE_ROOM)
1676c2aa98e2SPeter Wemm 			{
1677c2aa98e2SPeter Wemm 				/* syntax error: unmatched > */
16787660b554SGregory Neil Shapiro 				if (copylev > 0 && bp > bufhead)
1679c2aa98e2SPeter Wemm 					bp--;
168012ed1c7cSGregory Neil Shapiro 				quoteit = true;
1681c2aa98e2SPeter Wemm 				continue;
1682c2aa98e2SPeter Wemm 			}
1683c2aa98e2SPeter Wemm 			if (copylev++ <= 0)
1684f9218d3dSGregory Neil Shapiro 				SM_APPEND_CHAR(c);
1685c2aa98e2SPeter Wemm 			continue;
1686c2aa98e2SPeter Wemm 		}
1687c2aa98e2SPeter Wemm 
1688c2aa98e2SPeter Wemm 		/* must be a real address character */
1689c2aa98e2SPeter Wemm 	putg:
1690c2aa98e2SPeter Wemm 		if (copylev <= 0 && !putgmac)
1691c2aa98e2SPeter Wemm 		{
1692f9218d3dSGregory Neil Shapiro 			if (bp > buf && bp[-1] == ')')
1693f9218d3dSGregory Neil Shapiro 				SM_APPEND_CHAR(' ');
1694f9218d3dSGregory Neil Shapiro 			SM_APPEND_CHAR(MACROEXPAND);
1695f9218d3dSGregory Neil Shapiro 			SM_APPEND_CHAR('g');
169612ed1c7cSGregory Neil Shapiro 			putgmac = true;
1697c2aa98e2SPeter Wemm 		}
1698c2aa98e2SPeter Wemm 	}
1699c2aa98e2SPeter Wemm 
1700c2aa98e2SPeter Wemm 	/* repair any syntactic damage */
1701f9218d3dSGregory Neil Shapiro 	if (realqmode && bp < bufend)
1702c2aa98e2SPeter Wemm 		*bp++ = '"';
1703f9218d3dSGregory Neil Shapiro 	while (realcmtlev-- > 0 && bp < bufend)
1704c2aa98e2SPeter Wemm 		*bp++ = ')';
1705f9218d3dSGregory Neil Shapiro 	if (addangle && bp < bufend)
1706c2aa98e2SPeter Wemm 		*bp++ = '>';
1707f9218d3dSGregory Neil Shapiro 	*bp = '\0';
1708f9218d3dSGregory Neil Shapiro 	if (bp < bufend)
1709f9218d3dSGregory Neil Shapiro 		goto success;
1710c2aa98e2SPeter Wemm 
1711f9218d3dSGregory Neil Shapiro  returng:
1712f9218d3dSGregory Neil Shapiro 	/* String too long, punt */
1713f9218d3dSGregory Neil Shapiro 	buf[0] = '<';
1714f9218d3dSGregory Neil Shapiro 	buf[1] = MACROEXPAND;
1715f9218d3dSGregory Neil Shapiro 	buf[2]= 'g';
1716f9218d3dSGregory Neil Shapiro 	buf[3] = '>';
1717f9218d3dSGregory Neil Shapiro 	buf[4]= '\0';
1718f9218d3dSGregory Neil Shapiro 	sm_syslog(LOG_ALERT, e->e_id,
1719f9218d3dSGregory Neil Shapiro 		  "Dropped invalid comments from header address");
1720f9218d3dSGregory Neil Shapiro 
1721f9218d3dSGregory Neil Shapiro  success:
1722c2aa98e2SPeter Wemm 	if (tTd(33, 1))
1723c2aa98e2SPeter Wemm 	{
172412ed1c7cSGregory Neil Shapiro 		sm_dprintf("crackaddr=>`");
1725bfb62e91SGregory Neil Shapiro 		xputs(sm_debug_file(), buf);
172612ed1c7cSGregory Neil Shapiro 		sm_dprintf("'\n");
1727c2aa98e2SPeter Wemm 	}
17283299c2f1SGregory Neil Shapiro 	return buf;
1729c2aa98e2SPeter Wemm }
1730951742c4SGregory Neil Shapiro 
173112ed1c7cSGregory Neil Shapiro /*
1732c2aa98e2SPeter Wemm **  PUTHEADER -- put the header part of a message from the in-core copy
1733c2aa98e2SPeter Wemm **
1734c2aa98e2SPeter Wemm **	Parameters:
1735c2aa98e2SPeter Wemm **		mci -- the connection information.
17363299c2f1SGregory Neil Shapiro **		hdr -- the header to put.
1737c2aa98e2SPeter Wemm **		e -- envelope to use.
1738e01d6f61SPeter Wemm **		flags -- MIME conversion flags.
1739c2aa98e2SPeter Wemm **
1740c2aa98e2SPeter Wemm **	Returns:
1741355d91e3SGregory Neil Shapiro **		true iff header part was written successfully
1742c2aa98e2SPeter Wemm **
1743c2aa98e2SPeter Wemm **	Side Effects:
1744c2aa98e2SPeter Wemm **		none.
1745c2aa98e2SPeter Wemm */
1746c2aa98e2SPeter Wemm 
1747567a2fc9SGregory Neil Shapiro bool
1748e01d6f61SPeter Wemm putheader(mci, hdr, e, flags)
1749c2aa98e2SPeter Wemm 	register MCI *mci;
1750c2aa98e2SPeter Wemm 	HDR *hdr;
1751c2aa98e2SPeter Wemm 	register ENVELOPE *e;
1752e01d6f61SPeter Wemm 	int flags;
1753c2aa98e2SPeter Wemm {
1754c2aa98e2SPeter Wemm 	register HDR *h;
175512ed1c7cSGregory Neil Shapiro 	char buf[SM_MAX(MAXLINE,BUFSIZ)];
1756c2aa98e2SPeter Wemm 	char obuf[MAXLINE];
1757c2aa98e2SPeter Wemm 
1758c2aa98e2SPeter Wemm 	if (tTd(34, 1))
175912ed1c7cSGregory Neil Shapiro 		sm_dprintf("--- putheader, mailer = %s ---\n",
1760c2aa98e2SPeter Wemm 			mci->mci_mailer->m_name);
1761c2aa98e2SPeter Wemm 
1762c2aa98e2SPeter Wemm 	/*
1763c2aa98e2SPeter Wemm 	**  If we're in MIME mode, we're not really in the header of the
1764c2aa98e2SPeter Wemm 	**  message, just the header of one of the parts of the body of
1765c2aa98e2SPeter Wemm 	**  the message.  Therefore MCIF_INHEADER should not be turned on.
1766c2aa98e2SPeter Wemm 	*/
1767c2aa98e2SPeter Wemm 
1768c2aa98e2SPeter Wemm 	if (!bitset(MCIF_INMIME, mci->mci_flags))
1769c2aa98e2SPeter Wemm 		mci->mci_flags |= MCIF_INHEADER;
1770c2aa98e2SPeter Wemm 
1771c2aa98e2SPeter Wemm 	for (h = hdr; h != NULL; h = h->h_link)
1772c2aa98e2SPeter Wemm 	{
1773c2aa98e2SPeter Wemm 		register char *p = h->h_value;
177412ed1c7cSGregory Neil Shapiro 		char *q;
1775c2aa98e2SPeter Wemm 
1776c2aa98e2SPeter Wemm 		if (tTd(34, 11))
1777c2aa98e2SPeter Wemm 		{
177812ed1c7cSGregory Neil Shapiro 			sm_dprintf("  %s:", h->h_field);
1779bfb62e91SGregory Neil Shapiro 			xputs(sm_debug_file(), p);
1780c2aa98e2SPeter Wemm 		}
1781c2aa98e2SPeter Wemm 
17823299c2f1SGregory Neil Shapiro 		/* Skip empty headers */
1783*2fb4f839SGregory Neil Shapiro 		if (p == NULL)
17843299c2f1SGregory Neil Shapiro 			continue;
1785*2fb4f839SGregory Neil Shapiro #if _FFR_8BITENVADDR
1786*2fb4f839SGregory Neil Shapiro 		(void) dequote_internal_chars(p, buf, sizeof(buf));
1787*2fb4f839SGregory Neil Shapiro #endif
17883299c2f1SGregory Neil Shapiro 
178976b7bf71SPeter Wemm 		/* heuristic shortening of MIME fields to avoid MUA overflows */
179076b7bf71SPeter Wemm 		if (MaxMimeFieldLength > 0 &&
179176b7bf71SPeter Wemm 		    wordinclass(h->h_field,
179212ed1c7cSGregory Neil Shapiro 				macid("{checkMIMEFieldHeaders}")))
179376b7bf71SPeter Wemm 		{
1794c46d91b7SGregory Neil Shapiro 			size_t len;
1795c46d91b7SGregory Neil Shapiro 
1796f9218d3dSGregory Neil Shapiro 			len = fix_mime_header(h, e);
1797c46d91b7SGregory Neil Shapiro 			if (len > 0)
179876b7bf71SPeter Wemm 			{
179976b7bf71SPeter Wemm 				sm_syslog(LOG_ALERT, e->e_id,
1800c46d91b7SGregory Neil Shapiro 					  "Truncated MIME %s header due to field size (length = %ld) (possible attack)",
1801c46d91b7SGregory Neil Shapiro 					  h->h_field, (unsigned long) len);
180276b7bf71SPeter Wemm 				if (tTd(34, 11))
180312ed1c7cSGregory Neil Shapiro 					sm_dprintf("  truncated MIME %s header due to field size  (length = %ld) (possible attack)\n",
1804c46d91b7SGregory Neil Shapiro 						   h->h_field,
1805c46d91b7SGregory Neil Shapiro 						   (unsigned long) len);
180676b7bf71SPeter Wemm 			}
180776b7bf71SPeter Wemm 		}
180876b7bf71SPeter Wemm 
180976b7bf71SPeter Wemm 		if (MaxMimeHeaderLength > 0 &&
181076b7bf71SPeter Wemm 		    wordinclass(h->h_field,
181112ed1c7cSGregory Neil Shapiro 				macid("{checkMIMETextHeaders}")))
181276b7bf71SPeter Wemm 		{
1813c46d91b7SGregory Neil Shapiro 			size_t len;
1814c46d91b7SGregory Neil Shapiro 
1815*2fb4f839SGregory Neil Shapiro 			len = strlen(p);
1816c46d91b7SGregory Neil Shapiro 			if (len > (size_t) MaxMimeHeaderLength)
181776b7bf71SPeter Wemm 			{
181876b7bf71SPeter Wemm 				h->h_value[MaxMimeHeaderLength - 1] = '\0';
181976b7bf71SPeter Wemm 				sm_syslog(LOG_ALERT, e->e_id,
1820c46d91b7SGregory Neil Shapiro 					  "Truncated long MIME %s header (length = %ld) (possible attack)",
1821c46d91b7SGregory Neil Shapiro 					  h->h_field, (unsigned long) len);
182276b7bf71SPeter Wemm 				if (tTd(34, 11))
182312ed1c7cSGregory Neil Shapiro 					sm_dprintf("  truncated long MIME %s header (length = %ld) (possible attack)\n",
1824c46d91b7SGregory Neil Shapiro 						   h->h_field,
1825c46d91b7SGregory Neil Shapiro 						   (unsigned long) len);
182676b7bf71SPeter Wemm 			}
182776b7bf71SPeter Wemm 		}
182876b7bf71SPeter Wemm 
182976b7bf71SPeter Wemm 		if (MaxMimeHeaderLength > 0 &&
183076b7bf71SPeter Wemm 		    wordinclass(h->h_field,
183112ed1c7cSGregory Neil Shapiro 				macid("{checkMIMEHeaders}")))
183276b7bf71SPeter Wemm 		{
1833c46d91b7SGregory Neil Shapiro 			size_t len;
1834c46d91b7SGregory Neil Shapiro 
1835c46d91b7SGregory Neil Shapiro 			len = strlen(h->h_value);
1836c46d91b7SGregory Neil Shapiro 			if (shorten_rfc822_string(h->h_value,
1837c46d91b7SGregory Neil Shapiro 						  MaxMimeHeaderLength))
183876b7bf71SPeter Wemm 			{
1839f9218d3dSGregory Neil Shapiro 				if (len < MaxMimeHeaderLength)
1840f9218d3dSGregory Neil Shapiro 				{
1841f9218d3dSGregory Neil Shapiro 					/* we only rebalanced a bogus header */
1842f9218d3dSGregory Neil Shapiro 					sm_syslog(LOG_ALERT, e->e_id,
1843f9218d3dSGregory Neil Shapiro 						  "Fixed MIME %s header (possible attack)",
1844f9218d3dSGregory Neil Shapiro 						  h->h_field);
1845f9218d3dSGregory Neil Shapiro 					if (tTd(34, 11))
1846f9218d3dSGregory Neil Shapiro 						sm_dprintf("  fixed MIME %s header (possible attack)\n",
1847f9218d3dSGregory Neil Shapiro 							   h->h_field);
1848f9218d3dSGregory Neil Shapiro 				}
1849f9218d3dSGregory Neil Shapiro 				else
1850f9218d3dSGregory Neil Shapiro 				{
1851f9218d3dSGregory Neil Shapiro 					/* we actually shortened header */
185276b7bf71SPeter Wemm 					sm_syslog(LOG_ALERT, e->e_id,
1853c46d91b7SGregory Neil Shapiro 						  "Truncated long MIME %s header (length = %ld) (possible attack)",
1854f9218d3dSGregory Neil Shapiro 						  h->h_field,
1855f9218d3dSGregory Neil Shapiro 						  (unsigned long) len);
185676b7bf71SPeter Wemm 					if (tTd(34, 11))
185712ed1c7cSGregory Neil Shapiro 						sm_dprintf("  truncated long MIME %s header (length = %ld) (possible attack)\n",
1858c46d91b7SGregory Neil Shapiro 							   h->h_field,
1859c46d91b7SGregory Neil Shapiro 							   (unsigned long) len);
186076b7bf71SPeter Wemm 				}
186176b7bf71SPeter Wemm 			}
1862f9218d3dSGregory Neil Shapiro 		}
186376b7bf71SPeter Wemm 
1864e01d6f61SPeter Wemm 		/*
1865e01d6f61SPeter Wemm 		**  Suppress Content-Transfer-Encoding: if we are MIMEing
1866e01d6f61SPeter Wemm 		**  and we are potentially converting from 8 bit to 7 bit
1867e01d6f61SPeter Wemm 		**  MIME.  If converting, add a new CTE header in
1868e01d6f61SPeter Wemm 		**  mime8to7().
1869e01d6f61SPeter Wemm 		*/
187012ed1c7cSGregory Neil Shapiro 
1871c2aa98e2SPeter Wemm 		if (bitset(H_CTE, h->h_flags) &&
1872e01d6f61SPeter Wemm 		    bitset(MCIF_CVT8TO7|MCIF_CVT7TO8|MCIF_INMIME,
1873e01d6f61SPeter Wemm 			   mci->mci_flags) &&
1874e01d6f61SPeter Wemm 		    !bitset(M87F_NO8TO7, flags))
1875c2aa98e2SPeter Wemm 		{
1876c2aa98e2SPeter Wemm 			if (tTd(34, 11))
187712ed1c7cSGregory Neil Shapiro 				sm_dprintf(" (skipped (content-transfer-encoding))\n");
1878c2aa98e2SPeter Wemm 			continue;
1879c2aa98e2SPeter Wemm 		}
1880c2aa98e2SPeter Wemm 
1881c2aa98e2SPeter Wemm 		if (bitset(MCIF_INMIME, mci->mci_flags))
1882c2aa98e2SPeter Wemm 		{
1883c2aa98e2SPeter Wemm 			if (tTd(34, 11))
188412ed1c7cSGregory Neil Shapiro 				sm_dprintf("\n");
1885567a2fc9SGregory Neil Shapiro 			if (!put_vanilla_header(h, p, mci))
1886567a2fc9SGregory Neil Shapiro 				goto writeerr;
1887c2aa98e2SPeter Wemm 			continue;
1888c2aa98e2SPeter Wemm 		}
1889c2aa98e2SPeter Wemm 
1890c2aa98e2SPeter Wemm 		if (bitset(H_CHECK|H_ACHECK, h->h_flags) &&
18913299c2f1SGregory Neil Shapiro 		    !bitintersect(h->h_mflags, mci->mci_mailer->m_flags) &&
18923299c2f1SGregory Neil Shapiro 		    (h->h_macro == '\0' ||
189312ed1c7cSGregory Neil Shapiro 		     (q = macvalue(bitidx(h->h_macro), e)) == NULL ||
189412ed1c7cSGregory Neil Shapiro 		     *q == '\0'))
1895c2aa98e2SPeter Wemm 		{
1896c2aa98e2SPeter Wemm 			if (tTd(34, 11))
189712ed1c7cSGregory Neil Shapiro 				sm_dprintf(" (skipped)\n");
1898c2aa98e2SPeter Wemm 			continue;
1899c2aa98e2SPeter Wemm 		}
1900c2aa98e2SPeter Wemm 
1901c2aa98e2SPeter Wemm 		/* handle Resent-... headers specially */
1902c2aa98e2SPeter Wemm 		if (bitset(H_RESENT, h->h_flags) && !bitset(EF_RESENT, e->e_flags))
1903c2aa98e2SPeter Wemm 		{
1904c2aa98e2SPeter Wemm 			if (tTd(34, 11))
190512ed1c7cSGregory Neil Shapiro 				sm_dprintf(" (skipped (resent))\n");
1906c2aa98e2SPeter Wemm 			continue;
1907c2aa98e2SPeter Wemm 		}
1908c2aa98e2SPeter Wemm 
1909c2aa98e2SPeter Wemm 		/* suppress return receipts if requested */
1910c2aa98e2SPeter Wemm 		if (bitset(H_RECEIPTTO, h->h_flags) &&
1911c2aa98e2SPeter Wemm 		    (RrtImpliesDsn || bitset(EF_NORECEIPT, e->e_flags)))
1912c2aa98e2SPeter Wemm 		{
1913c2aa98e2SPeter Wemm 			if (tTd(34, 11))
191412ed1c7cSGregory Neil Shapiro 				sm_dprintf(" (skipped (receipt))\n");
1915c2aa98e2SPeter Wemm 			continue;
1916c2aa98e2SPeter Wemm 		}
1917c2aa98e2SPeter Wemm 
1918c2aa98e2SPeter Wemm 		/* macro expand value if generated internally */
19193299c2f1SGregory Neil Shapiro 		if (bitset(H_DEFAULT, h->h_flags) ||
19203299c2f1SGregory Neil Shapiro 		    bitset(H_BINDLATE, h->h_flags))
1921c2aa98e2SPeter Wemm 		{
1922951742c4SGregory Neil Shapiro 			expand(p, buf, sizeof(buf), e);
1923c2aa98e2SPeter Wemm 			p = buf;
1924c2aa98e2SPeter Wemm 			if (*p == '\0')
1925c2aa98e2SPeter Wemm 			{
1926c2aa98e2SPeter Wemm 				if (tTd(34, 11))
192712ed1c7cSGregory Neil Shapiro 					sm_dprintf(" (skipped -- null value)\n");
1928c2aa98e2SPeter Wemm 				continue;
1929c2aa98e2SPeter Wemm 			}
1930c2aa98e2SPeter Wemm 		}
1931c2aa98e2SPeter Wemm 
19325b0945b5SGregory Neil Shapiro 		if (bitset(H_BCC, h->h_flags) && !KeepBcc)
1933c2aa98e2SPeter Wemm 		{
1934c2aa98e2SPeter Wemm 			/* Bcc: field -- either truncate or delete */
1935c2aa98e2SPeter Wemm 			if (bitset(EF_DELETE_BCC, e->e_flags))
1936c2aa98e2SPeter Wemm 			{
1937c2aa98e2SPeter Wemm 				if (tTd(34, 11))
193812ed1c7cSGregory Neil Shapiro 					sm_dprintf(" (skipped -- bcc)\n");
1939c2aa98e2SPeter Wemm 			}
1940c2aa98e2SPeter Wemm 			else
1941c2aa98e2SPeter Wemm 			{
1942c2aa98e2SPeter Wemm 				/* no other recipient headers: truncate value */
1943951742c4SGregory Neil Shapiro 				(void) sm_strlcpyn(obuf, sizeof(obuf), 2,
194412ed1c7cSGregory Neil Shapiro 						   h->h_field, ":");
1945567a2fc9SGregory Neil Shapiro 				if (!putline(obuf, mci))
1946567a2fc9SGregory Neil Shapiro 					goto writeerr;
1947c2aa98e2SPeter Wemm 			}
1948c2aa98e2SPeter Wemm 			continue;
1949c2aa98e2SPeter Wemm 		}
1950c2aa98e2SPeter Wemm 
1951c2aa98e2SPeter Wemm 		if (tTd(34, 11))
195212ed1c7cSGregory Neil Shapiro 			sm_dprintf("\n");
1953c2aa98e2SPeter Wemm 
1954c2aa98e2SPeter Wemm 		if (bitset(H_FROM|H_RCPT, h->h_flags))
1955c2aa98e2SPeter Wemm 		{
1956c2aa98e2SPeter Wemm 			/* address field */
1957c2aa98e2SPeter Wemm 			bool oldstyle = bitset(EF_OLDSTYLE, e->e_flags);
1958c2aa98e2SPeter Wemm 
1959c2aa98e2SPeter Wemm 			if (bitset(H_FROM, h->h_flags))
196012ed1c7cSGregory Neil Shapiro 				oldstyle = false;
1961da7d7b9cSGregory Neil Shapiro 			if (!commaize(h, p, oldstyle, mci, e,
1962da7d7b9cSGregory Neil Shapiro 				      PXLF_HEADER | PXLF_STRIPMQUOTE)
1963da7d7b9cSGregory Neil Shapiro 			    && bitnset(M_xSMTP, mci->mci_mailer->m_flags))
1964da7d7b9cSGregory Neil Shapiro 				goto writeerr;
1965c2aa98e2SPeter Wemm 		}
1966c2aa98e2SPeter Wemm 		else
1967c2aa98e2SPeter Wemm 		{
1968567a2fc9SGregory Neil Shapiro 			if (!put_vanilla_header(h, p, mci))
1969567a2fc9SGregory Neil Shapiro 				goto writeerr;
1970c2aa98e2SPeter Wemm 		}
1971c2aa98e2SPeter Wemm 	}
1972c2aa98e2SPeter Wemm 
1973c2aa98e2SPeter Wemm 	/*
1974c2aa98e2SPeter Wemm 	**  If we are converting this to a MIME message, add the
19753299c2f1SGregory Neil Shapiro 	**  MIME headers (but not in MIME mode!).
1976c2aa98e2SPeter Wemm 	*/
1977c2aa98e2SPeter Wemm 
1978c2aa98e2SPeter Wemm #if MIME8TO7
1979c2aa98e2SPeter Wemm 	if (bitset(MM_MIME8BIT, MimeMode) &&
1980c2aa98e2SPeter Wemm 	    bitset(EF_HAS8BIT, e->e_flags) &&
1981c2aa98e2SPeter Wemm 	    !bitset(EF_DONT_MIME, e->e_flags) &&
1982c2aa98e2SPeter Wemm 	    !bitnset(M_8BITS, mci->mci_mailer->m_flags) &&
19833299c2f1SGregory Neil Shapiro 	    !bitset(MCIF_CVT8TO7|MCIF_CVT7TO8|MCIF_INMIME, mci->mci_flags) &&
19843299c2f1SGregory Neil Shapiro 	    hvalue("MIME-Version", e->e_header) == NULL)
1985c2aa98e2SPeter Wemm 	{
1986567a2fc9SGregory Neil Shapiro 		if (!putline("MIME-Version: 1.0", mci))
1987567a2fc9SGregory Neil Shapiro 			goto writeerr;
1988c2aa98e2SPeter Wemm 		if (hvalue("Content-Type", e->e_header) == NULL)
1989c2aa98e2SPeter Wemm 		{
1990951742c4SGregory Neil Shapiro 			(void) sm_snprintf(obuf, sizeof(obuf),
1991c2aa98e2SPeter Wemm 					"Content-Type: text/plain; charset=%s",
1992c2aa98e2SPeter Wemm 					defcharset(e));
1993567a2fc9SGregory Neil Shapiro 			if (!putline(obuf, mci))
1994567a2fc9SGregory Neil Shapiro 				goto writeerr;
1995c2aa98e2SPeter Wemm 		}
1996567a2fc9SGregory Neil Shapiro 		if (hvalue("Content-Transfer-Encoding", e->e_header) == NULL
1997567a2fc9SGregory Neil Shapiro 		    && !putline("Content-Transfer-Encoding: 8bit", mci))
1998567a2fc9SGregory Neil Shapiro 			goto writeerr;
1999c2aa98e2SPeter Wemm 	}
20003299c2f1SGregory Neil Shapiro #endif /* MIME8TO7 */
2001567a2fc9SGregory Neil Shapiro 	return true;
2002567a2fc9SGregory Neil Shapiro 
2003567a2fc9SGregory Neil Shapiro   writeerr:
2004567a2fc9SGregory Neil Shapiro 	return false;
2005c2aa98e2SPeter Wemm }
2006951742c4SGregory Neil Shapiro 
200712ed1c7cSGregory Neil Shapiro /*
2008c2aa98e2SPeter Wemm **  PUT_VANILLA_HEADER -- output a fairly ordinary header
2009c2aa98e2SPeter Wemm **
2010c2aa98e2SPeter Wemm **	Parameters:
2011c2aa98e2SPeter Wemm **		h -- the structure describing this header
2012c2aa98e2SPeter Wemm **		v -- the value of this header
2013c2aa98e2SPeter Wemm **		mci -- the connection info for output
2014c2aa98e2SPeter Wemm **
2015c2aa98e2SPeter Wemm **	Returns:
2016355d91e3SGregory Neil Shapiro **		true iff header was written successfully
2017c2aa98e2SPeter Wemm */
2018c2aa98e2SPeter Wemm 
2019567a2fc9SGregory Neil Shapiro static bool
2020c2aa98e2SPeter Wemm put_vanilla_header(h, v, mci)
2021c2aa98e2SPeter Wemm 	HDR *h;
2022c2aa98e2SPeter Wemm 	char *v;
2023c2aa98e2SPeter Wemm 	MCI *mci;
2024c2aa98e2SPeter Wemm {
2025c2aa98e2SPeter Wemm 	register char *nlp;
2026c2aa98e2SPeter Wemm 	register char *obp;
2027c2aa98e2SPeter Wemm 	int putflags;
2028684b2a5fSGregory Neil Shapiro 	char obuf[MAXLINE + 256];	/* additional length for h_field */
2029c2aa98e2SPeter Wemm 
2030951742c4SGregory Neil Shapiro 	putflags = PXLF_HEADER | PXLF_STRIPMQUOTE;
2031c2aa98e2SPeter Wemm 	if (bitnset(M_7BITHDRS, mci->mci_mailer->m_flags))
2032c2aa98e2SPeter Wemm 		putflags |= PXLF_STRIP8BIT;
2033951742c4SGregory Neil Shapiro 	(void) sm_snprintf(obuf, sizeof(obuf), "%.200s:", h->h_field);
2034c2aa98e2SPeter Wemm 	obp = obuf + strlen(obuf);
2035c2aa98e2SPeter Wemm 	while ((nlp = strchr(v, '\n')) != NULL)
2036c2aa98e2SPeter Wemm 	{
2037c2aa98e2SPeter Wemm 		int l;
2038c2aa98e2SPeter Wemm 
2039c2aa98e2SPeter Wemm 		l = nlp - v;
20407660b554SGregory Neil Shapiro 
20417660b554SGregory Neil Shapiro 		/*
20427660b554SGregory Neil Shapiro 		**  XXX This is broken for SPACELEFT()==0
20437660b554SGregory Neil Shapiro 		**  However, SPACELEFT() is always > 0 unless MAXLINE==1.
20447660b554SGregory Neil Shapiro 		*/
20457660b554SGregory Neil Shapiro 
20463299c2f1SGregory Neil Shapiro 		if (SPACELEFT(obuf, obp) - 1 < (size_t) l)
2047c2aa98e2SPeter Wemm 			l = SPACELEFT(obuf, obp) - 1;
2048c2aa98e2SPeter Wemm 
204912ed1c7cSGregory Neil Shapiro 		(void) sm_snprintf(obp, SPACELEFT(obuf, obp), "%.*s", l, v);
2050567a2fc9SGregory Neil Shapiro 		if (!putxline(obuf, strlen(obuf), mci, putflags))
2051567a2fc9SGregory Neil Shapiro 			goto writeerr;
2052c2aa98e2SPeter Wemm 		v += l + 1;
2053c2aa98e2SPeter Wemm 		obp = obuf;
2054c2aa98e2SPeter Wemm 		if (*v != ' ' && *v != '\t')
2055c2aa98e2SPeter Wemm 			*obp++ = ' ';
2056c2aa98e2SPeter Wemm 	}
20577660b554SGregory Neil Shapiro 
20587660b554SGregory Neil Shapiro 	/* XXX This is broken for SPACELEFT()==0 */
205912ed1c7cSGregory Neil Shapiro 	(void) sm_snprintf(obp, SPACELEFT(obuf, obp), "%.*s",
206012ed1c7cSGregory Neil Shapiro 			   (int) (SPACELEFT(obuf, obp) - 1), v);
2061567a2fc9SGregory Neil Shapiro 	return putxline(obuf, strlen(obuf), mci, putflags);
2062567a2fc9SGregory Neil Shapiro 
2063567a2fc9SGregory Neil Shapiro   writeerr:
2064567a2fc9SGregory Neil Shapiro 	return false;
2065c2aa98e2SPeter Wemm }
2066951742c4SGregory Neil Shapiro 
206712ed1c7cSGregory Neil Shapiro /*
2068c2aa98e2SPeter Wemm **  COMMAIZE -- output a header field, making a comma-translated list.
2069c2aa98e2SPeter Wemm **
2070c2aa98e2SPeter Wemm **	Parameters:
2071c2aa98e2SPeter Wemm **		h -- the header field to output.
2072c2aa98e2SPeter Wemm **		p -- the value to put in it.
207312ed1c7cSGregory Neil Shapiro **		oldstyle -- true if this is an old style header.
2074c2aa98e2SPeter Wemm **		mci -- the connection information.
2075c2aa98e2SPeter Wemm **		e -- the envelope containing the message.
207641f3d2ceSGregory Neil Shapiro **		putflags -- flags for putxline()
2077c2aa98e2SPeter Wemm **
2078c2aa98e2SPeter Wemm **	Returns:
2079355d91e3SGregory Neil Shapiro **		true iff header field was written successfully
2080c2aa98e2SPeter Wemm **
2081c2aa98e2SPeter Wemm **	Side Effects:
2082951742c4SGregory Neil Shapiro **		outputs "p" to "mci".
2083c2aa98e2SPeter Wemm */
2084c2aa98e2SPeter Wemm 
2085567a2fc9SGregory Neil Shapiro bool
208641f3d2ceSGregory Neil Shapiro commaize(h, p, oldstyle, mci, e, putflags)
2087c2aa98e2SPeter Wemm 	register HDR *h;
2088c2aa98e2SPeter Wemm 	register char *p;
2089c2aa98e2SPeter Wemm 	bool oldstyle;
2090c2aa98e2SPeter Wemm 	register MCI *mci;
2091c2aa98e2SPeter Wemm 	register ENVELOPE *e;
209241f3d2ceSGregory Neil Shapiro 	int putflags;
2093c2aa98e2SPeter Wemm {
2094c2aa98e2SPeter Wemm 	register char *obp;
2095951742c4SGregory Neil Shapiro 	int opos, omax, spaces;
209612ed1c7cSGregory Neil Shapiro 	bool firstone = true;
20977660b554SGregory Neil Shapiro 	char **res;
2098c2aa98e2SPeter Wemm 	char obuf[MAXLINE + 3];
2099c2aa98e2SPeter Wemm 
2100c2aa98e2SPeter Wemm 	/*
2101c2aa98e2SPeter Wemm 	**  Output the address list translated by the
2102c2aa98e2SPeter Wemm 	**  mailer and with commas.
2103c2aa98e2SPeter Wemm 	*/
2104c2aa98e2SPeter Wemm 
2105c2aa98e2SPeter Wemm 	if (tTd(14, 2))
210612ed1c7cSGregory Neil Shapiro 		sm_dprintf("commaize(%s:%s)\n", h->h_field, p);
2107c2aa98e2SPeter Wemm 
2108c2aa98e2SPeter Wemm 	if (bitnset(M_7BITHDRS, mci->mci_mailer->m_flags))
2109c2aa98e2SPeter Wemm 		putflags |= PXLF_STRIP8BIT;
2110c2aa98e2SPeter Wemm 
2111*2fb4f839SGregory Neil Shapiro #if _FFR_MTA_MODE
2112*2fb4f839SGregory Neil Shapiro 	/* activate this per mailer? */
2113*2fb4f839SGregory Neil Shapiro 	if (bitset(H_FROM, h->h_flags) && bitset(H_ASIS, h->h_flags))
2114*2fb4f839SGregory Neil Shapiro 	{
2115*2fb4f839SGregory Neil Shapiro 		(void) sm_snprintf(obuf, sizeof(obuf), "%.200s:%s", h->h_field,
2116*2fb4f839SGregory Neil Shapiro 				h->h_value);
2117*2fb4f839SGregory Neil Shapiro 		return putxline(obuf, strlen(obuf), mci, putflags);
2118*2fb4f839SGregory Neil Shapiro 	}
2119*2fb4f839SGregory Neil Shapiro #endif
2120*2fb4f839SGregory Neil Shapiro 
2121c2aa98e2SPeter Wemm 	obp = obuf;
2122951742c4SGregory Neil Shapiro 	(void) sm_snprintf(obp, SPACELEFT(obuf, obp), "%.200s:", h->h_field);
2123951742c4SGregory Neil Shapiro 	/* opos = strlen(obp); instead of the next 3 lines? */
2124951742c4SGregory Neil Shapiro 	opos = strlen(h->h_field) + 1;
2125951742c4SGregory Neil Shapiro 	if (opos > 201)
2126951742c4SGregory Neil Shapiro 		opos = 201;
2127c2aa98e2SPeter Wemm 	obp += opos;
2128951742c4SGregory Neil Shapiro 
2129951742c4SGregory Neil Shapiro 	spaces = 0;
21305b0945b5SGregory Neil Shapiro 	while (*p != '\0' && SM_ISSPACE(*p))
2131951742c4SGregory Neil Shapiro 	{
2132951742c4SGregory Neil Shapiro 		++spaces;
2133951742c4SGregory Neil Shapiro 		++p;
2134951742c4SGregory Neil Shapiro 	}
2135951742c4SGregory Neil Shapiro 	if (spaces > 0)
2136951742c4SGregory Neil Shapiro 	{
2137951742c4SGregory Neil Shapiro 		SM_ASSERT(sizeof(obuf) > opos  * 2);
2138951742c4SGregory Neil Shapiro 
2139951742c4SGregory Neil Shapiro 		/*
2140951742c4SGregory Neil Shapiro 		**  Restrict number of spaces to half the length of buffer
2141951742c4SGregory Neil Shapiro 		**  so the header field body can be put in here too.
2142951742c4SGregory Neil Shapiro 		**  Note: this is a hack...
2143951742c4SGregory Neil Shapiro 		*/
2144951742c4SGregory Neil Shapiro 
2145951742c4SGregory Neil Shapiro 		if (spaces > sizeof(obuf) / 2)
2146951742c4SGregory Neil Shapiro 			spaces = sizeof(obuf) / 2;
2147951742c4SGregory Neil Shapiro 		(void) sm_snprintf(obp, SPACELEFT(obuf, obp), "%*s", spaces,
2148951742c4SGregory Neil Shapiro 				"");
2149951742c4SGregory Neil Shapiro 		opos += spaces;
2150951742c4SGregory Neil Shapiro 		obp += spaces;
2151951742c4SGregory Neil Shapiro 		SM_ASSERT(obp < &obuf[MAXLINE]);
2152951742c4SGregory Neil Shapiro 	}
2153951742c4SGregory Neil Shapiro 
2154c2aa98e2SPeter Wemm 	omax = mci->mci_mailer->m_linelimit - 2;
2155c2aa98e2SPeter Wemm 	if (omax < 0 || omax > 78)
2156c2aa98e2SPeter Wemm 		omax = 78;
2157c2aa98e2SPeter Wemm 
2158c2aa98e2SPeter Wemm 	/*
2159c2aa98e2SPeter Wemm 	**  Run through the list of values.
2160c2aa98e2SPeter Wemm 	*/
2161c2aa98e2SPeter Wemm 
2162c2aa98e2SPeter Wemm 	while (*p != '\0')
2163c2aa98e2SPeter Wemm 	{
2164c2aa98e2SPeter Wemm 		register char *name;
2165c2aa98e2SPeter Wemm 		register int c;
2166c2aa98e2SPeter Wemm 		char savechar;
2167c2aa98e2SPeter Wemm 		int flags;
21683299c2f1SGregory Neil Shapiro 		auto int status;
2169c2aa98e2SPeter Wemm 
2170c2aa98e2SPeter Wemm 		/*
2171c2aa98e2SPeter Wemm 		**  Find the end of the name.  New style names
2172c2aa98e2SPeter Wemm 		**  end with a comma, old style names end with
2173c2aa98e2SPeter Wemm 		**  a space character.  However, spaces do not
2174c2aa98e2SPeter Wemm 		**  necessarily delimit an old-style name -- at
2175c2aa98e2SPeter Wemm 		**  signs mean keep going.
2176c2aa98e2SPeter Wemm 		*/
2177c2aa98e2SPeter Wemm 
2178c2aa98e2SPeter Wemm 		/* find end of name */
21795b0945b5SGregory Neil Shapiro 		while ((SM_ISSPACE(*p)) || *p == ',')
2180c2aa98e2SPeter Wemm 			p++;
2181c2aa98e2SPeter Wemm 		name = p;
21827660b554SGregory Neil Shapiro 		res = NULL;
2183c2aa98e2SPeter Wemm 		for (;;)
2184c2aa98e2SPeter Wemm 		{
2185c2aa98e2SPeter Wemm 			auto char *oldp;
2186c2aa98e2SPeter Wemm 			char pvpbuf[PSBUFSIZE];
2187c2aa98e2SPeter Wemm 
21887660b554SGregory Neil Shapiro 			res = prescan(p, oldstyle ? ' ' : ',', pvpbuf,
2189951742c4SGregory Neil Shapiro 				      sizeof(pvpbuf), &oldp, ExtTokenTab, false);
2190c2aa98e2SPeter Wemm 			p = oldp;
21917660b554SGregory Neil Shapiro #if _FFR_IGNORE_BOGUS_ADDR
21927660b554SGregory Neil Shapiro 			/* ignore addresses that can't be parsed */
21937660b554SGregory Neil Shapiro 			if (res == NULL)
21947660b554SGregory Neil Shapiro 			{
21957660b554SGregory Neil Shapiro 				name = p;
21967660b554SGregory Neil Shapiro 				continue;
21977660b554SGregory Neil Shapiro 			}
21987660b554SGregory Neil Shapiro #endif /* _FFR_IGNORE_BOGUS_ADDR */
2199c2aa98e2SPeter Wemm 
2200c2aa98e2SPeter Wemm 			/* look to see if we have an at sign */
22015b0945b5SGregory Neil Shapiro 			while (*p != '\0' && SM_ISSPACE(*p))
2202c2aa98e2SPeter Wemm 				p++;
2203c2aa98e2SPeter Wemm 
2204c2aa98e2SPeter Wemm 			if (*p != '@')
2205c2aa98e2SPeter Wemm 			{
2206c2aa98e2SPeter Wemm 				p = oldp;
2207c2aa98e2SPeter Wemm 				break;
2208c2aa98e2SPeter Wemm 			}
220912ed1c7cSGregory Neil Shapiro 			++p;
22105b0945b5SGregory Neil Shapiro 			while (*p != '\0' && SM_ISSPACE(*p))
2211c2aa98e2SPeter Wemm 				p++;
2212c2aa98e2SPeter Wemm 		}
2213c2aa98e2SPeter Wemm 		/* at the end of one complete name */
2214c2aa98e2SPeter Wemm 
2215c2aa98e2SPeter Wemm 		/* strip off trailing white space */
2216c2aa98e2SPeter Wemm 		while (p >= name &&
22175b0945b5SGregory Neil Shapiro 		       ((SM_ISSPACE(*p)) || *p == ',' || *p == '\0'))
2218c2aa98e2SPeter Wemm 			p--;
2219c2aa98e2SPeter Wemm 		if (++p == name)
2220c2aa98e2SPeter Wemm 			continue;
22217660b554SGregory Neil Shapiro 
22227660b554SGregory Neil Shapiro 		/*
22237660b554SGregory Neil Shapiro 		**  if prescan() failed go a bit backwards; this is a hack,
22247660b554SGregory Neil Shapiro 		**  there should be some better error recovery.
22257660b554SGregory Neil Shapiro 		*/
22267660b554SGregory Neil Shapiro 
22277660b554SGregory Neil Shapiro 		if (res == NULL && p > name &&
22285b0945b5SGregory Neil Shapiro 		    !((SM_ISSPACE(*p)) || *p == ',' || *p == '\0'))
22297660b554SGregory Neil Shapiro 			--p;
2230c2aa98e2SPeter Wemm 		savechar = *p;
2231c2aa98e2SPeter Wemm 		*p = '\0';
2232c2aa98e2SPeter Wemm 
2233c2aa98e2SPeter Wemm 		/* translate the name to be relative */
2234c2aa98e2SPeter Wemm 		flags = RF_HEADERADDR|RF_ADDDOMAIN;
2235c2aa98e2SPeter Wemm 		if (bitset(H_FROM, h->h_flags))
2236c2aa98e2SPeter Wemm 			flags |= RF_SENDERADDR;
2237c2aa98e2SPeter Wemm #if USERDB
2238c2aa98e2SPeter Wemm 		else if (e->e_from.q_mailer != NULL &&
2239c2aa98e2SPeter Wemm 			 bitnset(M_UDBRECIPIENT, e->e_from.q_mailer->m_flags))
2240c2aa98e2SPeter Wemm 		{
2241c2aa98e2SPeter Wemm 			char *q;
2242c2aa98e2SPeter Wemm 
224312ed1c7cSGregory Neil Shapiro 			q = udbsender(name, e->e_rpool);
2244c2aa98e2SPeter Wemm 			if (q != NULL)
2245c2aa98e2SPeter Wemm 				name = q;
2246c2aa98e2SPeter Wemm 		}
22473299c2f1SGregory Neil Shapiro #endif /* USERDB */
22483299c2f1SGregory Neil Shapiro 		status = EX_OK;
22493299c2f1SGregory Neil Shapiro 		name = remotename(name, mci->mci_mailer, flags, &status, e);
2250da7d7b9cSGregory Neil Shapiro 		if (status != EX_OK && bitnset(M_xSMTP, mci->mci_mailer->m_flags))
2251da7d7b9cSGregory Neil Shapiro 		{
2252da7d7b9cSGregory Neil Shapiro 			if (status == EX_TEMPFAIL)
2253da7d7b9cSGregory Neil Shapiro 				mci->mci_flags |= MCIF_NOTSTICKY;
2254da7d7b9cSGregory Neil Shapiro 			goto writeerr;
2255da7d7b9cSGregory Neil Shapiro 		}
2256c2aa98e2SPeter Wemm 		if (*name == '\0')
2257c2aa98e2SPeter Wemm 		{
2258c2aa98e2SPeter Wemm 			*p = savechar;
2259c2aa98e2SPeter Wemm 			continue;
2260c2aa98e2SPeter Wemm 		}
226112ed1c7cSGregory Neil Shapiro 		name = denlstring(name, false, true);
2262c2aa98e2SPeter Wemm 
2263c2aa98e2SPeter Wemm 		/* output the name with nice formatting */
2264c2aa98e2SPeter Wemm 		opos += strlen(name);
2265c2aa98e2SPeter Wemm 		if (!firstone)
2266c2aa98e2SPeter Wemm 			opos += 2;
2267c2aa98e2SPeter Wemm 		if (opos > omax && !firstone)
2268c2aa98e2SPeter Wemm 		{
226912ed1c7cSGregory Neil Shapiro 			(void) sm_strlcpy(obp, ",\n", SPACELEFT(obuf, obp));
2270567a2fc9SGregory Neil Shapiro 			if (!putxline(obuf, strlen(obuf), mci, putflags))
2271567a2fc9SGregory Neil Shapiro 				goto writeerr;
2272c2aa98e2SPeter Wemm 			obp = obuf;
2273951742c4SGregory Neil Shapiro 			(void) sm_strlcpy(obp, "        ", sizeof(obuf));
2274c2aa98e2SPeter Wemm 			opos = strlen(obp);
2275c2aa98e2SPeter Wemm 			obp += opos;
2276c2aa98e2SPeter Wemm 			opos += strlen(name);
2277c2aa98e2SPeter Wemm 		}
2278c2aa98e2SPeter Wemm 		else if (!firstone)
2279c2aa98e2SPeter Wemm 		{
228012ed1c7cSGregory Neil Shapiro 			(void) sm_strlcpy(obp, ", ", SPACELEFT(obuf, obp));
2281c2aa98e2SPeter Wemm 			obp += 2;
2282c2aa98e2SPeter Wemm 		}
2283c2aa98e2SPeter Wemm 
2284c2aa98e2SPeter Wemm 		while ((c = *name++) != '\0' && obp < &obuf[MAXLINE])
2285c2aa98e2SPeter Wemm 			*obp++ = c;
228612ed1c7cSGregory Neil Shapiro 		firstone = false;
2287c2aa98e2SPeter Wemm 		*p = savechar;
2288c2aa98e2SPeter Wemm 	}
2289951742c4SGregory Neil Shapiro 	if (obp < &obuf[sizeof(obuf)])
2290c2aa98e2SPeter Wemm 		*obp = '\0';
22917660b554SGregory Neil Shapiro 	else
2292951742c4SGregory Neil Shapiro 		obuf[sizeof(obuf) - 1] = '\0';
2293567a2fc9SGregory Neil Shapiro 	return putxline(obuf, strlen(obuf), mci, putflags);
2294567a2fc9SGregory Neil Shapiro 
2295567a2fc9SGregory Neil Shapiro   writeerr:
2296567a2fc9SGregory Neil Shapiro 	return false;
2297c2aa98e2SPeter Wemm }
2298567a2fc9SGregory Neil Shapiro 
229912ed1c7cSGregory Neil Shapiro /*
2300c2aa98e2SPeter Wemm **  COPYHEADER -- copy header list
2301c2aa98e2SPeter Wemm **
2302c2aa98e2SPeter Wemm **	This routine is the equivalent of newstr for header lists
2303c2aa98e2SPeter Wemm **
2304c2aa98e2SPeter Wemm **	Parameters:
2305c2aa98e2SPeter Wemm **		header -- list of header structures to copy.
230612ed1c7cSGregory Neil Shapiro **		rpool -- resource pool, or NULL
2307c2aa98e2SPeter Wemm **
2308c2aa98e2SPeter Wemm **	Returns:
2309c2aa98e2SPeter Wemm **		a copy of 'header'.
2310c2aa98e2SPeter Wemm **
2311c2aa98e2SPeter Wemm **	Side Effects:
2312c2aa98e2SPeter Wemm **		none.
2313c2aa98e2SPeter Wemm */
2314c2aa98e2SPeter Wemm 
2315c2aa98e2SPeter Wemm HDR *
231612ed1c7cSGregory Neil Shapiro copyheader(header, rpool)
2317c2aa98e2SPeter Wemm 	register HDR *header;
231812ed1c7cSGregory Neil Shapiro 	SM_RPOOL_T *rpool;
2319c2aa98e2SPeter Wemm {
2320c2aa98e2SPeter Wemm 	register HDR *newhdr;
2321c2aa98e2SPeter Wemm 	HDR *ret;
2322c2aa98e2SPeter Wemm 	register HDR **tail = &ret;
2323c2aa98e2SPeter Wemm 
2324c2aa98e2SPeter Wemm 	while (header != NULL)
2325c2aa98e2SPeter Wemm 	{
2326951742c4SGregory Neil Shapiro 		newhdr = (HDR *) sm_rpool_malloc_x(rpool, sizeof(*newhdr));
2327c2aa98e2SPeter Wemm 		STRUCTCOPY(*header, *newhdr);
2328c2aa98e2SPeter Wemm 		*tail = newhdr;
2329c2aa98e2SPeter Wemm 		tail = &newhdr->h_link;
2330c2aa98e2SPeter Wemm 		header = header->h_link;
2331c2aa98e2SPeter Wemm 	}
2332c2aa98e2SPeter Wemm 	*tail = NULL;
2333c2aa98e2SPeter Wemm 
2334c2aa98e2SPeter Wemm 	return ret;
2335c2aa98e2SPeter Wemm }
2336951742c4SGregory Neil Shapiro 
233712ed1c7cSGregory Neil Shapiro /*
233876b7bf71SPeter Wemm **  FIX_MIME_HEADER -- possibly truncate/rebalance parameters in a MIME header
233976b7bf71SPeter Wemm **
234076b7bf71SPeter Wemm **	Run through all of the parameters of a MIME header and
234176b7bf71SPeter Wemm **	possibly truncate and rebalance the parameter according
234276b7bf71SPeter Wemm **	to MaxMimeFieldLength.
234376b7bf71SPeter Wemm **
234476b7bf71SPeter Wemm **	Parameters:
2345f9218d3dSGregory Neil Shapiro **		h -- the header to truncate/rebalance
2346f9218d3dSGregory Neil Shapiro **		e -- the current envelope
234776b7bf71SPeter Wemm **
234876b7bf71SPeter Wemm **	Returns:
2349c46d91b7SGregory Neil Shapiro **		length of last offending field, 0 if all ok.
235076b7bf71SPeter Wemm **
235176b7bf71SPeter Wemm **	Side Effects:
235276b7bf71SPeter Wemm **		string modified in place
235376b7bf71SPeter Wemm */
235476b7bf71SPeter Wemm 
2355c46d91b7SGregory Neil Shapiro static size_t
2356f9218d3dSGregory Neil Shapiro fix_mime_header(h, e)
2357f9218d3dSGregory Neil Shapiro 	HDR *h;
2358f9218d3dSGregory Neil Shapiro 	ENVELOPE *e;
235976b7bf71SPeter Wemm {
2360f9218d3dSGregory Neil Shapiro 	char *begin = h->h_value;
236176b7bf71SPeter Wemm 	char *end;
2362c46d91b7SGregory Neil Shapiro 	size_t len = 0;
2363c46d91b7SGregory Neil Shapiro 	size_t retlen = 0;
236476b7bf71SPeter Wemm 
2365*2fb4f839SGregory Neil Shapiro 	if (SM_IS_EMPTY(begin))
2366c46d91b7SGregory Neil Shapiro 		return 0;
236776b7bf71SPeter Wemm 
236876b7bf71SPeter Wemm 	/* Split on each ';' */
23697660b554SGregory Neil Shapiro 	/* find_character() never returns NULL */
237076b7bf71SPeter Wemm 	while ((end = find_character(begin, ';')) != NULL)
237176b7bf71SPeter Wemm 	{
237276b7bf71SPeter Wemm 		char save = *end;
237376b7bf71SPeter Wemm 		char *bp;
237476b7bf71SPeter Wemm 
237576b7bf71SPeter Wemm 		*end = '\0';
237676b7bf71SPeter Wemm 
2377c46d91b7SGregory Neil Shapiro 		len = strlen(begin);
2378c46d91b7SGregory Neil Shapiro 
237976b7bf71SPeter Wemm 		/* Shorten individual parameter */
238076b7bf71SPeter Wemm 		if (shorten_rfc822_string(begin, MaxMimeFieldLength))
2381f9218d3dSGregory Neil Shapiro 		{
2382f9218d3dSGregory Neil Shapiro 			if (len < MaxMimeFieldLength)
2383f9218d3dSGregory Neil Shapiro 			{
2384f9218d3dSGregory Neil Shapiro 				/* we only rebalanced a bogus field */
2385f9218d3dSGregory Neil Shapiro 				sm_syslog(LOG_ALERT, e->e_id,
2386f9218d3dSGregory Neil Shapiro 					  "Fixed MIME %s header field (possible attack)",
2387f9218d3dSGregory Neil Shapiro 					  h->h_field);
2388f9218d3dSGregory Neil Shapiro 				if (tTd(34, 11))
2389f9218d3dSGregory Neil Shapiro 					sm_dprintf("  fixed MIME %s header field (possible attack)\n",
2390f9218d3dSGregory Neil Shapiro 						   h->h_field);
2391f9218d3dSGregory Neil Shapiro 			}
2392f9218d3dSGregory Neil Shapiro 			else
2393f9218d3dSGregory Neil Shapiro 			{
2394f9218d3dSGregory Neil Shapiro 				/* we actually shortened the header */
2395c46d91b7SGregory Neil Shapiro 				retlen = len;
2396f9218d3dSGregory Neil Shapiro 			}
2397f9218d3dSGregory Neil Shapiro 		}
239876b7bf71SPeter Wemm 
239976b7bf71SPeter Wemm 		/* Collapse the possibly shortened string with rest */
240076b7bf71SPeter Wemm 		bp = begin + strlen(begin);
240176b7bf71SPeter Wemm 		if (bp != end)
240276b7bf71SPeter Wemm 		{
240376b7bf71SPeter Wemm 			char *ep = end;
240476b7bf71SPeter Wemm 
240576b7bf71SPeter Wemm 			*end = save;
240676b7bf71SPeter Wemm 			end = bp;
240776b7bf71SPeter Wemm 
240876b7bf71SPeter Wemm 			/* copy character by character due to overlap */
240976b7bf71SPeter Wemm 			while (*ep != '\0')
241076b7bf71SPeter Wemm 				*bp++ = *ep++;
241176b7bf71SPeter Wemm 			*bp = '\0';
241276b7bf71SPeter Wemm 		}
241376b7bf71SPeter Wemm 		else
241476b7bf71SPeter Wemm 			*end = save;
241576b7bf71SPeter Wemm 		if (*end == '\0')
241676b7bf71SPeter Wemm 			break;
241776b7bf71SPeter Wemm 
241876b7bf71SPeter Wemm 		/* Move past ';' */
241976b7bf71SPeter Wemm 		begin = end + 1;
242076b7bf71SPeter Wemm 	}
2421c46d91b7SGregory Neil Shapiro 	return retlen;
242276b7bf71SPeter Wemm }
2423