xref: /freebsd/contrib/sendmail/src/headers.c (revision c46d91b759c7a461806a7f6e6efccc404d2c21b8)
1c2aa98e2SPeter Wemm /*
23299c2f1SGregory Neil Shapiro  * Copyright (c) 1998-2000 Sendmail, Inc. and its suppliers.
33299c2f1SGregory Neil Shapiro  *	All rights reserved.
4c2aa98e2SPeter Wemm  * Copyright (c) 1983, 1995-1997 Eric P. Allman.  All rights reserved.
5c2aa98e2SPeter Wemm  * Copyright (c) 1988, 1993
6c2aa98e2SPeter Wemm  *	The Regents of the University of California.  All rights reserved.
7c2aa98e2SPeter Wemm  *
8c2aa98e2SPeter Wemm  * By using this file, you agree to the terms and conditions set
9c2aa98e2SPeter Wemm  * forth in the LICENSE file which can be found at the top level of
10c2aa98e2SPeter Wemm  * the sendmail distribution.
11c2aa98e2SPeter Wemm  *
12c2aa98e2SPeter Wemm  */
13c2aa98e2SPeter Wemm 
14c2aa98e2SPeter Wemm #ifndef lint
15c46d91b7SGregory Neil Shapiro static char id[] = "@(#)$Id: headers.c,v 8.203.4.10 2000/10/13 17:54:30 gshapiro Exp $";
163299c2f1SGregory Neil Shapiro #endif /* ! lint */
17c2aa98e2SPeter Wemm 
183299c2f1SGregory Neil Shapiro /* $FreeBSD$ */
193299c2f1SGregory Neil Shapiro 
203299c2f1SGregory Neil Shapiro #include <sendmail.h>
213299c2f1SGregory Neil Shapiro 
22c46d91b7SGregory Neil Shapiro static size_t	fix_mime_header __P((char *));
233299c2f1SGregory Neil Shapiro static int	priencode __P((char *));
243299c2f1SGregory Neil Shapiro static void	put_vanilla_header __P((HDR *, char *, MCI *));
25c2aa98e2SPeter Wemm 
26c2aa98e2SPeter Wemm /*
27c2aa98e2SPeter Wemm **  SETUPHEADERS -- initialize headers in symbol table
28c2aa98e2SPeter Wemm **
29c2aa98e2SPeter Wemm **	Parameters:
30c2aa98e2SPeter Wemm **		none
31c2aa98e2SPeter Wemm **
32c2aa98e2SPeter Wemm **	Returns:
33c2aa98e2SPeter Wemm **		none
34c2aa98e2SPeter Wemm */
35c2aa98e2SPeter Wemm 
36c2aa98e2SPeter Wemm void
37c2aa98e2SPeter Wemm setupheaders()
38c2aa98e2SPeter Wemm {
39c2aa98e2SPeter Wemm 	struct hdrinfo *hi;
40c2aa98e2SPeter Wemm 	STAB *s;
41c2aa98e2SPeter Wemm 
42c2aa98e2SPeter Wemm 	for (hi = HdrInfo; hi->hi_field != NULL; hi++)
43c2aa98e2SPeter Wemm 	{
44c2aa98e2SPeter Wemm 		s = stab(hi->hi_field, ST_HEADER, ST_ENTER);
45c2aa98e2SPeter Wemm 		s->s_header.hi_flags = hi->hi_flags;
46c2aa98e2SPeter Wemm 		s->s_header.hi_ruleset = NULL;
47c2aa98e2SPeter Wemm 	}
48c2aa98e2SPeter Wemm }
49c2aa98e2SPeter Wemm /*
50c2aa98e2SPeter Wemm **  CHOMPHEADER -- process and save a header line.
51c2aa98e2SPeter Wemm **
523299c2f1SGregory Neil Shapiro **	Called by collect, readcf, and readqf to deal with header lines.
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 };
69c2aa98e2SPeter Wemm 
703299c2f1SGregory Neil Shapiro u_long
713299c2f1SGregory Neil Shapiro chompheader(line, pflag, hdrp, e)
72c2aa98e2SPeter Wemm 	char *line;
733299c2f1SGregory Neil Shapiro 	int pflag;
74c2aa98e2SPeter Wemm 	HDR **hdrp;
75c2aa98e2SPeter Wemm 	register ENVELOPE *e;
76c2aa98e2SPeter Wemm {
773299c2f1SGregory Neil Shapiro 	u_char mid = '\0';
78c2aa98e2SPeter Wemm 	register char *p;
79c2aa98e2SPeter Wemm 	register HDR *h;
80c2aa98e2SPeter Wemm 	HDR **hp;
81c2aa98e2SPeter Wemm 	char *fname;
82c2aa98e2SPeter Wemm 	char *fvalue;
83c2aa98e2SPeter Wemm 	bool cond = FALSE;
843299c2f1SGregory Neil Shapiro 	bool dropfrom;
85c2aa98e2SPeter Wemm 	bool headeronly;
86c2aa98e2SPeter Wemm 	STAB *s;
87c2aa98e2SPeter Wemm 	struct hdrinfo *hi;
88e01d6f61SPeter Wemm 	bool nullheader = FALSE;
893299c2f1SGregory Neil Shapiro 	BITMAP256 mopts;
90c2aa98e2SPeter Wemm 
91c2aa98e2SPeter Wemm 	if (tTd(31, 6))
92c2aa98e2SPeter Wemm 	{
933299c2f1SGregory Neil Shapiro 		dprintf("chompheader: ");
94c2aa98e2SPeter Wemm 		xputs(line);
953299c2f1SGregory Neil Shapiro 		dprintf("\n");
96c2aa98e2SPeter Wemm 	}
97c2aa98e2SPeter Wemm 
98c2aa98e2SPeter Wemm 	headeronly = hdrp != NULL;
99c2aa98e2SPeter Wemm 	if (!headeronly)
100c2aa98e2SPeter Wemm 		hdrp = &e->e_header;
101c2aa98e2SPeter Wemm 
102c2aa98e2SPeter Wemm 	/* strip off options */
103c2aa98e2SPeter Wemm 	clrbitmap(mopts);
104c2aa98e2SPeter Wemm 	p = line;
1053299c2f1SGregory Neil Shapiro 	if (!bitset(pflag, CHHDR_USER) && *p == '?')
106c2aa98e2SPeter Wemm 	{
1073299c2f1SGregory Neil Shapiro 		int c;
1083299c2f1SGregory Neil Shapiro 		register char *q;
109c2aa98e2SPeter Wemm 
1103299c2f1SGregory Neil Shapiro 		q = strchr(++p, '?');
1113299c2f1SGregory Neil Shapiro 		if (q == NULL)
1123299c2f1SGregory Neil Shapiro 			goto hse;
1133299c2f1SGregory Neil Shapiro 
1143299c2f1SGregory Neil Shapiro 		*q = '\0';
1153299c2f1SGregory Neil Shapiro 		c = *p & 0377;
1163299c2f1SGregory Neil Shapiro 
1173299c2f1SGregory Neil Shapiro 		/* possibly macro conditional */
1183299c2f1SGregory Neil Shapiro 		if (c == MACROEXPAND)
119c2aa98e2SPeter Wemm 		{
1203299c2f1SGregory Neil Shapiro 			/* catch ?$? */
1213299c2f1SGregory Neil Shapiro 			if (*++p == '\0')
1223299c2f1SGregory Neil Shapiro 			{
1233299c2f1SGregory Neil Shapiro 				*q = '?';
1243299c2f1SGregory Neil Shapiro 				goto hse;
1253299c2f1SGregory Neil Shapiro 			}
1263299c2f1SGregory Neil Shapiro 
1273299c2f1SGregory Neil Shapiro 			mid = (u_char) *p++;
1283299c2f1SGregory Neil Shapiro 
1293299c2f1SGregory Neil Shapiro 			/* catch ?$abc? */
1303299c2f1SGregory Neil Shapiro 			if (*p != '\0')
1313299c2f1SGregory Neil Shapiro 			{
1323299c2f1SGregory Neil Shapiro 				*q = '?';
1333299c2f1SGregory Neil Shapiro 				goto hse;
1343299c2f1SGregory Neil Shapiro 			}
1353299c2f1SGregory Neil Shapiro 		}
1363299c2f1SGregory Neil Shapiro 		else if (*p == '$')
1373299c2f1SGregory Neil Shapiro 		{
1383299c2f1SGregory Neil Shapiro 			/* catch ?$? */
1393299c2f1SGregory Neil Shapiro 			if (*++p == '\0')
1403299c2f1SGregory Neil Shapiro 			{
1413299c2f1SGregory Neil Shapiro 				*q = '?';
1423299c2f1SGregory Neil Shapiro 				goto hse;
1433299c2f1SGregory Neil Shapiro 			}
1443299c2f1SGregory Neil Shapiro 
1453299c2f1SGregory Neil Shapiro 			mid = (u_char)macid(p, NULL);
1463299c2f1SGregory Neil Shapiro 			if (bitset(0200, mid))
1473299c2f1SGregory Neil Shapiro 				p += strlen(macname(mid)) + 2;
1483299c2f1SGregory Neil Shapiro 			else
1493299c2f1SGregory Neil Shapiro 				p++;
1503299c2f1SGregory Neil Shapiro 
1513299c2f1SGregory Neil Shapiro 			/* catch ?$abc? */
1523299c2f1SGregory Neil Shapiro 			if (*p != '\0')
1533299c2f1SGregory Neil Shapiro 			{
1543299c2f1SGregory Neil Shapiro 				*q = '?';
1553299c2f1SGregory Neil Shapiro 				goto hse;
1563299c2f1SGregory Neil Shapiro 			}
1573299c2f1SGregory Neil Shapiro 
158c2aa98e2SPeter Wemm 		}
159c2aa98e2SPeter Wemm 		else
1603299c2f1SGregory Neil Shapiro 		{
1613299c2f1SGregory Neil Shapiro 			while (*p != '\0')
1623299c2f1SGregory Neil Shapiro 			{
1633299c2f1SGregory Neil Shapiro 				if (!isascii(*p))
1643299c2f1SGregory Neil Shapiro 				{
1653299c2f1SGregory Neil Shapiro 					*q = '?';
1663299c2f1SGregory Neil Shapiro 					goto hse;
1673299c2f1SGregory Neil Shapiro 				}
1683299c2f1SGregory Neil Shapiro 
169c46d91b7SGregory Neil Shapiro 				setbitn(bitidx(*p), mopts);
170c2aa98e2SPeter Wemm 				cond = TRUE;
1713299c2f1SGregory Neil Shapiro 				p++;
1723299c2f1SGregory Neil Shapiro 			}
1733299c2f1SGregory Neil Shapiro 		}
1743299c2f1SGregory Neil Shapiro 		p = q + 1;
175c2aa98e2SPeter Wemm 	}
176c2aa98e2SPeter Wemm 
177c2aa98e2SPeter Wemm 	/* find canonical name */
178c2aa98e2SPeter Wemm 	fname = p;
179c2aa98e2SPeter Wemm 	while (isascii(*p) && isgraph(*p) && *p != ':')
180c2aa98e2SPeter Wemm 		p++;
181c2aa98e2SPeter Wemm 	fvalue = p;
182c2aa98e2SPeter Wemm 	while (isascii(*p) && isspace(*p))
183c2aa98e2SPeter Wemm 		p++;
184c2aa98e2SPeter Wemm 	if (*p++ != ':' || fname == fvalue)
185c2aa98e2SPeter Wemm 	{
1863299c2f1SGregory Neil Shapiro hse:
1873299c2f1SGregory Neil Shapiro 		syserr("553 5.3.0 header syntax error, line \"%s\"", line);
188c2aa98e2SPeter Wemm 		return 0;
189c2aa98e2SPeter Wemm 	}
190c2aa98e2SPeter Wemm 	*fvalue = '\0';
191c2aa98e2SPeter Wemm 
192c2aa98e2SPeter Wemm 	/* strip field value on front */
193e01d6f61SPeter Wemm 	if (*p == ' ')
194e01d6f61SPeter Wemm 		p++;
195e01d6f61SPeter Wemm 	fvalue = p;
196e01d6f61SPeter Wemm 
197e01d6f61SPeter Wemm 	/* if the field is null, go ahead and use the default */
198e01d6f61SPeter Wemm 	while (isascii(*p) && isspace(*p))
199e01d6f61SPeter Wemm 		p++;
200e01d6f61SPeter Wemm 	if (*p == '\0')
201e01d6f61SPeter Wemm 		nullheader = TRUE;
202c2aa98e2SPeter Wemm 
203c2aa98e2SPeter Wemm 	/* security scan: long field names are end-of-header */
204c2aa98e2SPeter Wemm 	if (strlen(fname) > 100)
205c2aa98e2SPeter Wemm 		return H_EOH;
206c2aa98e2SPeter Wemm 
207c2aa98e2SPeter Wemm 	/* check to see if it represents a ruleset call */
2083299c2f1SGregory Neil Shapiro 	if (bitset(pflag, CHHDR_DEF))
209c2aa98e2SPeter Wemm 	{
210c2aa98e2SPeter Wemm 		char hbuf[50];
211c2aa98e2SPeter Wemm 
212c2aa98e2SPeter Wemm 		(void) expand(fvalue, hbuf, sizeof hbuf, e);
213c2aa98e2SPeter Wemm 		for (p = hbuf; isascii(*p) && isspace(*p); )
214c2aa98e2SPeter Wemm 			p++;
215c2aa98e2SPeter Wemm 		if ((*p++ & 0377) == CALLSUBR)
216c2aa98e2SPeter Wemm 		{
217c2aa98e2SPeter Wemm 			auto char *endp;
2183299c2f1SGregory Neil Shapiro 			bool strc;
219c2aa98e2SPeter Wemm 
2203299c2f1SGregory Neil Shapiro 			strc = *p == '+';	/* strip comments? */
2213299c2f1SGregory Neil Shapiro 			if (strc)
2223299c2f1SGregory Neil Shapiro 				++p;
223c2aa98e2SPeter Wemm 			if (strtorwset(p, &endp, ST_ENTER) > 0)
224c2aa98e2SPeter Wemm 			{
225c2aa98e2SPeter Wemm 				*endp = '\0';
226c2aa98e2SPeter Wemm 				s = stab(fname, ST_HEADER, ST_ENTER);
227c2aa98e2SPeter Wemm 				s->s_header.hi_ruleset = newstr(p);
2283299c2f1SGregory Neil Shapiro 				if (!strc)
2293299c2f1SGregory Neil Shapiro 					s->s_header.hi_flags |= H_STRIPCOMM;
230c2aa98e2SPeter Wemm 			}
231c2aa98e2SPeter Wemm 			return 0;
232c2aa98e2SPeter Wemm 		}
233c2aa98e2SPeter Wemm 	}
234c2aa98e2SPeter Wemm 
235c2aa98e2SPeter Wemm 	/* see if it is a known type */
236c2aa98e2SPeter Wemm 	s = stab(fname, ST_HEADER, ST_FIND);
237c2aa98e2SPeter Wemm 	if (s != NULL)
238c2aa98e2SPeter Wemm 		hi = &s->s_header;
239c2aa98e2SPeter Wemm 	else
240c2aa98e2SPeter Wemm 		hi = &NormalHeader;
241c2aa98e2SPeter Wemm 
242c2aa98e2SPeter Wemm 	if (tTd(31, 9))
243c2aa98e2SPeter Wemm 	{
244c2aa98e2SPeter Wemm 		if (s == NULL)
2453299c2f1SGregory Neil Shapiro 			dprintf("no header flags match\n");
246c2aa98e2SPeter Wemm 		else
2473299c2f1SGregory Neil Shapiro 			dprintf("header match, flags=%lx, ruleset=%s\n",
248c2aa98e2SPeter Wemm 				hi->hi_flags,
249c2aa98e2SPeter Wemm 				hi->hi_ruleset == NULL ? "<NULL>" : hi->hi_ruleset);
250c2aa98e2SPeter Wemm 	}
251c2aa98e2SPeter Wemm 
252c2aa98e2SPeter Wemm 	/* see if this is a resent message */
2533299c2f1SGregory Neil Shapiro 	if (!bitset(pflag, CHHDR_DEF) && !headeronly &&
2543299c2f1SGregory Neil Shapiro 	    bitset(H_RESENT, hi->hi_flags))
255c2aa98e2SPeter Wemm 		e->e_flags |= EF_RESENT;
256c2aa98e2SPeter Wemm 
257c2aa98e2SPeter Wemm 	/* if this is an Errors-To: header keep track of it now */
2583299c2f1SGregory Neil Shapiro 	if (UseErrorsTo && !bitset(pflag, CHHDR_DEF) && !headeronly &&
259c2aa98e2SPeter Wemm 	    bitset(H_ERRORSTO, hi->hi_flags))
260c2aa98e2SPeter Wemm 		(void) sendtolist(fvalue, NULLADDR, &e->e_errorqueue, 0, e);
261c2aa98e2SPeter Wemm 
262c2aa98e2SPeter Wemm 	/* if this means "end of header" quit now */
263c2aa98e2SPeter Wemm 	if (!headeronly && bitset(H_EOH, hi->hi_flags))
264c2aa98e2SPeter Wemm 		return hi->hi_flags;
265c2aa98e2SPeter Wemm 
266c2aa98e2SPeter Wemm 	/*
267c2aa98e2SPeter Wemm 	**  Horrible hack to work around problem with Lotus Notes SMTP
268c2aa98e2SPeter Wemm 	**  mail gateway, which generates From: headers with newlines in
269c2aa98e2SPeter Wemm 	**  them and the <address> on the second line.  Although this is
270c2aa98e2SPeter Wemm 	**  legal RFC 822, many MUAs don't handle this properly and thus
271c2aa98e2SPeter Wemm 	**  never find the actual address.
272c2aa98e2SPeter Wemm 	*/
273c2aa98e2SPeter Wemm 
274c2aa98e2SPeter Wemm 	if (bitset(H_FROM, hi->hi_flags) && SingleLineFromHeader)
275c2aa98e2SPeter Wemm 	{
276c2aa98e2SPeter Wemm 		while ((p = strchr(fvalue, '\n')) != NULL)
277c2aa98e2SPeter Wemm 			*p = ' ';
278c2aa98e2SPeter Wemm 	}
279c2aa98e2SPeter Wemm 
280c2aa98e2SPeter Wemm 	/*
281c2aa98e2SPeter Wemm 	**  If there is a check ruleset, verify it against the header.
282c2aa98e2SPeter Wemm 	*/
283c2aa98e2SPeter Wemm 
2843299c2f1SGregory Neil Shapiro 	if (bitset(pflag, CHHDR_CHECK))
2853299c2f1SGregory Neil Shapiro 	{
2863299c2f1SGregory Neil Shapiro 		bool stripcom = FALSE;
2873299c2f1SGregory Neil Shapiro 		char *rs;
2883299c2f1SGregory Neil Shapiro 
2893299c2f1SGregory Neil Shapiro 		/* no ruleset? look for default */
2903299c2f1SGregory Neil Shapiro 		rs = hi->hi_ruleset;
2913299c2f1SGregory Neil Shapiro 		if (rs == NULL)
2923299c2f1SGregory Neil Shapiro 		{
2933299c2f1SGregory Neil Shapiro 			s = stab("*", ST_HEADER, ST_FIND);
2943299c2f1SGregory Neil Shapiro 			if (s != NULL)
2953299c2f1SGregory Neil Shapiro 			{
2963299c2f1SGregory Neil Shapiro 				rs = (&s->s_header)->hi_ruleset;
2973299c2f1SGregory Neil Shapiro 				stripcom = bitset((&s->s_header)->hi_flags,
2983299c2f1SGregory Neil Shapiro 						  H_STRIPCOMM);
2993299c2f1SGregory Neil Shapiro 			}
3003299c2f1SGregory Neil Shapiro 		}
3013299c2f1SGregory Neil Shapiro 		else
3023299c2f1SGregory Neil Shapiro 			stripcom = bitset(hi->hi_flags, H_STRIPCOMM);
3033299c2f1SGregory Neil Shapiro 		if (rs != NULL)
3043299c2f1SGregory Neil Shapiro 		{
3053299c2f1SGregory Neil Shapiro 			int l;
3063299c2f1SGregory Neil Shapiro 			char qval[MAXNAME];
3073299c2f1SGregory Neil Shapiro 			char hlen[16];
3083299c2f1SGregory Neil Shapiro 			char *sp, *dp;
3093299c2f1SGregory Neil Shapiro 
3103299c2f1SGregory Neil Shapiro 			dp = qval;
3113299c2f1SGregory Neil Shapiro 			l = 0;
3123299c2f1SGregory Neil Shapiro 			dp[l++] = '"';
3133299c2f1SGregory Neil Shapiro 			for (sp = fvalue; *sp != '\0' && l < MAXNAME - 2; sp++)
3143299c2f1SGregory Neil Shapiro 			{
3153299c2f1SGregory Neil Shapiro 				switch(*sp)
3163299c2f1SGregory Neil Shapiro 				{
3173299c2f1SGregory Neil Shapiro 				  case '\011': /* ht */
3183299c2f1SGregory Neil Shapiro 				  case '\012': /* nl */
3193299c2f1SGregory Neil Shapiro 				  case '\013': /* vt */
3203299c2f1SGregory Neil Shapiro 				  case '\014': /* np */
3213299c2f1SGregory Neil Shapiro 				  case '\015': /* cr */
3223299c2f1SGregory Neil Shapiro 					dp[l++] = ' ';
3233299c2f1SGregory Neil Shapiro 					break;
3243299c2f1SGregory Neil Shapiro 				  case '"':
3253299c2f1SGregory Neil Shapiro 					dp[l++] = '\\';
3263299c2f1SGregory Neil Shapiro 					/* FALLTHROUGH */
3273299c2f1SGregory Neil Shapiro 				  default:
3283299c2f1SGregory Neil Shapiro 					dp[l++] = *sp;
3293299c2f1SGregory Neil Shapiro 					break;
3303299c2f1SGregory Neil Shapiro 				}
3313299c2f1SGregory Neil Shapiro 			}
3323299c2f1SGregory Neil Shapiro 			dp[l++] = '"';
3333299c2f1SGregory Neil Shapiro 			dp[l++] = '\0';
3343299c2f1SGregory Neil Shapiro 			l = strlen(fvalue);
3353299c2f1SGregory Neil Shapiro 			snprintf(hlen, sizeof hlen, "%d", l);
3363299c2f1SGregory Neil Shapiro 			define(macid("{hdrlen}", NULL), newstr(hlen), e);
3373299c2f1SGregory Neil Shapiro 			if (l >= MAXNAME)
3383299c2f1SGregory Neil Shapiro 			{
3393299c2f1SGregory Neil Shapiro 				if (LogLevel > 9)
3403299c2f1SGregory Neil Shapiro 					sm_syslog(LOG_WARNING, e->e_id,
3413299c2f1SGregory Neil Shapiro 						  "Warning: truncated header '%s' before check with '%s' len=%d max=%d",
3423299c2f1SGregory Neil Shapiro 						  fname, rs, l, MAXNAME);
3433299c2f1SGregory Neil Shapiro 			}
3443299c2f1SGregory Neil Shapiro 			if ((sp = macvalue(macid("{currHeader}", NULL), e)) !=
3453299c2f1SGregory Neil Shapiro 			    NULL)
3463299c2f1SGregory Neil Shapiro 				free(sp);
3473299c2f1SGregory Neil Shapiro 			define(macid("{currHeader}", NULL), newstr(qval), e);
3483299c2f1SGregory Neil Shapiro 			define(macid("{hdr_name}", NULL), newstr(fname), e);
349c46d91b7SGregory Neil Shapiro 			(void) rscheck(rs, fvalue, NULL, e, stripcom, TRUE, 4,
350c46d91b7SGregory Neil Shapiro 				       NULL);
3513299c2f1SGregory Neil Shapiro 		}
3523299c2f1SGregory Neil Shapiro 	}
353c2aa98e2SPeter Wemm 
354c2aa98e2SPeter Wemm 	/*
355c2aa98e2SPeter Wemm 	**  Drop explicit From: if same as what we would generate.
356c2aa98e2SPeter Wemm 	**  This is to make MH (which doesn't always give a full name)
357c2aa98e2SPeter Wemm 	**  insert the full name information in all circumstances.
358c2aa98e2SPeter Wemm 	*/
359c2aa98e2SPeter Wemm 
3603299c2f1SGregory Neil Shapiro 	dropfrom = FALSE;
361c2aa98e2SPeter Wemm 	p = "resent-from";
362c2aa98e2SPeter Wemm 	if (!bitset(EF_RESENT, e->e_flags))
363c2aa98e2SPeter Wemm 		p += 7;
3643299c2f1SGregory Neil Shapiro 	if (!bitset(pflag, CHHDR_DEF) && !headeronly &&
3653299c2f1SGregory Neil Shapiro 	    !bitset(EF_QUEUERUN, e->e_flags) && strcasecmp(fname, p) == 0)
366c2aa98e2SPeter Wemm 	{
367c2aa98e2SPeter Wemm 		if (tTd(31, 2))
368c2aa98e2SPeter Wemm 		{
3693299c2f1SGregory Neil Shapiro 			dprintf("comparing header from (%s) against default (%s or %s)\n",
370c2aa98e2SPeter Wemm 				fvalue, e->e_from.q_paddr, e->e_from.q_user);
371c2aa98e2SPeter Wemm 		}
372c2aa98e2SPeter Wemm 		if (e->e_from.q_paddr != NULL &&
3733299c2f1SGregory Neil Shapiro 		    e->e_from.q_mailer != NULL &&
3743299c2f1SGregory Neil Shapiro 		    bitnset(M_LOCALMAILER, e->e_from.q_mailer->m_flags) &&
375c2aa98e2SPeter Wemm 		    (strcmp(fvalue, e->e_from.q_paddr) == 0 ||
376c2aa98e2SPeter Wemm 		     strcmp(fvalue, e->e_from.q_user) == 0))
3773299c2f1SGregory Neil Shapiro 			dropfrom = TRUE;
378c2aa98e2SPeter Wemm 	}
379c2aa98e2SPeter Wemm 
380c2aa98e2SPeter Wemm 	/* delete default value for this header */
381c2aa98e2SPeter Wemm 	for (hp = hdrp; (h = *hp) != NULL; hp = &h->h_link)
382c2aa98e2SPeter Wemm 	{
383c2aa98e2SPeter Wemm 		if (strcasecmp(fname, h->h_field) == 0 &&
3843299c2f1SGregory Neil Shapiro 		    !bitset(H_USER, h->h_flags) &&
385c2aa98e2SPeter Wemm 		    !bitset(H_FORCE, h->h_flags))
386c2aa98e2SPeter Wemm 		{
387e01d6f61SPeter Wemm 			if (nullheader)
388e01d6f61SPeter Wemm 			{
389e01d6f61SPeter Wemm 				/* user-supplied value was null */
390e01d6f61SPeter Wemm 				return 0;
391e01d6f61SPeter Wemm 			}
3923299c2f1SGregory Neil Shapiro 			if (dropfrom)
3933299c2f1SGregory Neil Shapiro 			{
3943299c2f1SGregory Neil Shapiro 				/* make this look like the user entered it */
3953299c2f1SGregory Neil Shapiro 				h->h_flags |= H_USER;
3963299c2f1SGregory Neil Shapiro 				return hi->hi_flags;
3973299c2f1SGregory Neil Shapiro 			}
398c2aa98e2SPeter Wemm 			h->h_value = NULL;
399c2aa98e2SPeter Wemm 			if (!cond)
400c2aa98e2SPeter Wemm 			{
401c2aa98e2SPeter Wemm 				/* copy conditions from default case */
4023299c2f1SGregory Neil Shapiro 				memmove((char *)mopts, (char *)h->h_mflags,
403c2aa98e2SPeter Wemm 					sizeof mopts);
404c2aa98e2SPeter Wemm 			}
4053299c2f1SGregory Neil Shapiro 			h->h_macro = mid;
406c2aa98e2SPeter Wemm 		}
407c2aa98e2SPeter Wemm 	}
408c2aa98e2SPeter Wemm 
409c2aa98e2SPeter Wemm 	/* create a new node */
410c2aa98e2SPeter Wemm 	h = (HDR *) xalloc(sizeof *h);
411c2aa98e2SPeter Wemm 	h->h_field = newstr(fname);
412c2aa98e2SPeter Wemm 	h->h_value = newstr(fvalue);
413c2aa98e2SPeter Wemm 	h->h_link = NULL;
4143299c2f1SGregory Neil Shapiro 	memmove((char *) h->h_mflags, (char *) mopts, sizeof mopts);
4153299c2f1SGregory Neil Shapiro 	h->h_macro = mid;
416c2aa98e2SPeter Wemm 	*hp = h;
417c2aa98e2SPeter Wemm 	h->h_flags = hi->hi_flags;
418d995d2baSGregory Neil Shapiro 	if (bitset(pflag, CHHDR_USER) || bitset(pflag, CHHDR_QUEUE))
4193299c2f1SGregory Neil Shapiro 		h->h_flags |= H_USER;
420c2aa98e2SPeter Wemm 
421c2aa98e2SPeter Wemm 	/* strip EOH flag if parsing MIME headers */
422c2aa98e2SPeter Wemm 	if (headeronly)
423c2aa98e2SPeter Wemm 		h->h_flags &= ~H_EOH;
4243299c2f1SGregory Neil Shapiro 	if (bitset(pflag, CHHDR_DEF))
425c2aa98e2SPeter Wemm 		h->h_flags |= H_DEFAULT;
4263299c2f1SGregory Neil Shapiro 	if (cond || mid != '\0')
427c2aa98e2SPeter Wemm 		h->h_flags |= H_CHECK;
428c2aa98e2SPeter Wemm 
429c2aa98e2SPeter Wemm 	/* hack to see if this is a new format message */
4303299c2f1SGregory Neil Shapiro 	if (!bitset(pflag, CHHDR_DEF) && !headeronly &&
4313299c2f1SGregory Neil Shapiro 	    bitset(H_RCPT|H_FROM, h->h_flags) &&
432c2aa98e2SPeter Wemm 	    (strchr(fvalue, ',') != NULL || strchr(fvalue, '(') != NULL ||
433c2aa98e2SPeter Wemm 	     strchr(fvalue, '<') != NULL || strchr(fvalue, ';') != NULL))
434c2aa98e2SPeter Wemm 	{
435c2aa98e2SPeter Wemm 		e->e_flags &= ~EF_OLDSTYLE;
436c2aa98e2SPeter Wemm 	}
437c2aa98e2SPeter Wemm 
438c2aa98e2SPeter Wemm 	return h->h_flags;
439c2aa98e2SPeter Wemm }
440c2aa98e2SPeter Wemm /*
441c2aa98e2SPeter Wemm **  ADDHEADER -- add a header entry to the end of the queue.
442c2aa98e2SPeter Wemm **
443c2aa98e2SPeter Wemm **	This bypasses the special checking of chompheader.
444c2aa98e2SPeter Wemm **
445c2aa98e2SPeter Wemm **	Parameters:
446c2aa98e2SPeter Wemm **		field -- the name of the header field.
447c2aa98e2SPeter Wemm **		value -- the value of the field.
4483299c2f1SGregory Neil Shapiro **		flags -- flags to add to h_flags.
4493299c2f1SGregory Neil Shapiro **		hdrlist -- an indirect pointer to the header structure list.
450c2aa98e2SPeter Wemm **
451c2aa98e2SPeter Wemm **	Returns:
452c2aa98e2SPeter Wemm **		none.
453c2aa98e2SPeter Wemm **
454c2aa98e2SPeter Wemm **	Side Effects:
455c2aa98e2SPeter Wemm **		adds the field on the list of headers for this envelope.
456c2aa98e2SPeter Wemm */
457c2aa98e2SPeter Wemm 
458c2aa98e2SPeter Wemm void
4593299c2f1SGregory Neil Shapiro addheader(field, value, flags, hdrlist)
460c2aa98e2SPeter Wemm 	char *field;
461c2aa98e2SPeter Wemm 	char *value;
4623299c2f1SGregory Neil Shapiro 	int flags;
463c2aa98e2SPeter Wemm 	HDR **hdrlist;
464c2aa98e2SPeter Wemm {
465c2aa98e2SPeter Wemm 	register HDR *h;
466c2aa98e2SPeter Wemm 	STAB *s;
467c2aa98e2SPeter Wemm 	HDR **hp;
468c2aa98e2SPeter Wemm 
469c2aa98e2SPeter Wemm 	/* find info struct */
470c2aa98e2SPeter Wemm 	s = stab(field, ST_HEADER, ST_FIND);
471c2aa98e2SPeter Wemm 
472c2aa98e2SPeter Wemm 	/* find current place in list -- keep back pointer? */
473c2aa98e2SPeter Wemm 	for (hp = hdrlist; (h = *hp) != NULL; hp = &h->h_link)
474c2aa98e2SPeter Wemm 	{
475c2aa98e2SPeter Wemm 		if (strcasecmp(field, h->h_field) == 0)
476c2aa98e2SPeter Wemm 			break;
477c2aa98e2SPeter Wemm 	}
478c2aa98e2SPeter Wemm 
479c2aa98e2SPeter Wemm 	/* allocate space for new header */
480c2aa98e2SPeter Wemm 	h = (HDR *) xalloc(sizeof *h);
481c2aa98e2SPeter Wemm 	h->h_field = field;
482c2aa98e2SPeter Wemm 	h->h_value = newstr(value);
483c2aa98e2SPeter Wemm 	h->h_link = *hp;
4843299c2f1SGregory Neil Shapiro 	h->h_flags = flags;
485c2aa98e2SPeter Wemm 	if (s != NULL)
486c2aa98e2SPeter Wemm 		h->h_flags |= s->s_header.hi_flags;
487c2aa98e2SPeter Wemm 	clrbitmap(h->h_mflags);
4883299c2f1SGregory Neil Shapiro 	h->h_macro = '\0';
489c2aa98e2SPeter Wemm 	*hp = h;
490c2aa98e2SPeter Wemm }
491c2aa98e2SPeter Wemm /*
492c2aa98e2SPeter Wemm **  HVALUE -- return value of a header.
493c2aa98e2SPeter Wemm **
494c2aa98e2SPeter Wemm **	Only "real" fields (i.e., ones that have not been supplied
495c2aa98e2SPeter Wemm **	as a default) are used.
496c2aa98e2SPeter Wemm **
497c2aa98e2SPeter Wemm **	Parameters:
498c2aa98e2SPeter Wemm **		field -- the field name.
499c2aa98e2SPeter Wemm **		header -- the header list.
500c2aa98e2SPeter Wemm **
501c2aa98e2SPeter Wemm **	Returns:
502c2aa98e2SPeter Wemm **		pointer to the value part.
503c2aa98e2SPeter Wemm **		NULL if not found.
504c2aa98e2SPeter Wemm **
505c2aa98e2SPeter Wemm **	Side Effects:
506c2aa98e2SPeter Wemm **		none.
507c2aa98e2SPeter Wemm */
508c2aa98e2SPeter Wemm 
509c2aa98e2SPeter Wemm char *
510c2aa98e2SPeter Wemm hvalue(field, header)
511c2aa98e2SPeter Wemm 	char *field;
512c2aa98e2SPeter Wemm 	HDR *header;
513c2aa98e2SPeter Wemm {
514c2aa98e2SPeter Wemm 	register HDR *h;
515c2aa98e2SPeter Wemm 
516c2aa98e2SPeter Wemm 	for (h = header; h != NULL; h = h->h_link)
517c2aa98e2SPeter Wemm 	{
518c2aa98e2SPeter Wemm 		if (!bitset(H_DEFAULT, h->h_flags) &&
519c2aa98e2SPeter Wemm 		    strcasecmp(h->h_field, field) == 0)
5203299c2f1SGregory Neil Shapiro 			return h->h_value;
521c2aa98e2SPeter Wemm 	}
5223299c2f1SGregory Neil Shapiro 	return NULL;
523c2aa98e2SPeter Wemm }
524c2aa98e2SPeter Wemm /*
525c2aa98e2SPeter Wemm **  ISHEADER -- predicate telling if argument is a header.
526c2aa98e2SPeter Wemm **
527c2aa98e2SPeter Wemm **	A line is a header if it has a single word followed by
528c2aa98e2SPeter Wemm **	optional white space followed by a colon.
529c2aa98e2SPeter Wemm **
530c2aa98e2SPeter Wemm **	Header fields beginning with two dashes, although technically
531c2aa98e2SPeter Wemm **	permitted by RFC822, are automatically rejected in order
532c2aa98e2SPeter Wemm **	to make MIME work out.  Without this we could have a technically
533c2aa98e2SPeter Wemm **	legal header such as ``--"foo:bar"'' that would also be a legal
534c2aa98e2SPeter Wemm **	MIME separator.
535c2aa98e2SPeter Wemm **
536c2aa98e2SPeter Wemm **	Parameters:
537c2aa98e2SPeter Wemm **		h -- string to check for possible headerness.
538c2aa98e2SPeter Wemm **
539c2aa98e2SPeter Wemm **	Returns:
540c2aa98e2SPeter Wemm **		TRUE if h is a header.
541c2aa98e2SPeter Wemm **		FALSE otherwise.
542c2aa98e2SPeter Wemm **
543c2aa98e2SPeter Wemm **	Side Effects:
544c2aa98e2SPeter Wemm **		none.
545c2aa98e2SPeter Wemm */
546c2aa98e2SPeter Wemm 
547c2aa98e2SPeter Wemm bool
548c2aa98e2SPeter Wemm isheader(h)
549c2aa98e2SPeter Wemm 	char *h;
550c2aa98e2SPeter Wemm {
551c2aa98e2SPeter Wemm 	register char *s = h;
552c2aa98e2SPeter Wemm 
553c2aa98e2SPeter Wemm 	if (s[0] == '-' && s[1] == '-')
554c2aa98e2SPeter Wemm 		return FALSE;
555c2aa98e2SPeter Wemm 
556c2aa98e2SPeter Wemm 	while (*s > ' ' && *s != ':' && *s != '\0')
557c2aa98e2SPeter Wemm 		s++;
558c2aa98e2SPeter Wemm 
559c2aa98e2SPeter Wemm 	if (h == s)
560c2aa98e2SPeter Wemm 		return FALSE;
561c2aa98e2SPeter Wemm 
562c2aa98e2SPeter Wemm 	/* following technically violates RFC822 */
563c2aa98e2SPeter Wemm 	while (isascii(*s) && isspace(*s))
564c2aa98e2SPeter Wemm 		s++;
565c2aa98e2SPeter Wemm 
566c2aa98e2SPeter Wemm 	return (*s == ':');
567c2aa98e2SPeter Wemm }
568c2aa98e2SPeter Wemm /*
569c2aa98e2SPeter Wemm **  EATHEADER -- run through the stored header and extract info.
570c2aa98e2SPeter Wemm **
571c2aa98e2SPeter Wemm **	Parameters:
572c2aa98e2SPeter Wemm **		e -- the envelope to process.
573c2aa98e2SPeter Wemm **		full -- if set, do full processing (e.g., compute
574c2aa98e2SPeter Wemm **			message priority).  This should not be set
575c2aa98e2SPeter Wemm **			when reading a queue file because some info
576c2aa98e2SPeter Wemm **			needed to compute the priority is wrong.
577c2aa98e2SPeter Wemm **
578c2aa98e2SPeter Wemm **	Returns:
579c2aa98e2SPeter Wemm **		none.
580c2aa98e2SPeter Wemm **
581c2aa98e2SPeter Wemm **	Side Effects:
582c2aa98e2SPeter Wemm **		Sets a bunch of global variables from information
583c2aa98e2SPeter Wemm **			in the collected header.
584c2aa98e2SPeter Wemm **		Aborts the message if the hop count is exceeded.
585c2aa98e2SPeter Wemm */
586c2aa98e2SPeter Wemm 
587c2aa98e2SPeter Wemm void
588c2aa98e2SPeter Wemm eatheader(e, full)
589c2aa98e2SPeter Wemm 	register ENVELOPE *e;
590c2aa98e2SPeter Wemm 	bool full;
591c2aa98e2SPeter Wemm {
592c2aa98e2SPeter Wemm 	register HDR *h;
593c2aa98e2SPeter Wemm 	register char *p;
594c2aa98e2SPeter Wemm 	int hopcnt = 0;
595c2aa98e2SPeter Wemm 	char *msgid;
596c2aa98e2SPeter Wemm 	char buf[MAXLINE];
597c2aa98e2SPeter Wemm 
598c2aa98e2SPeter Wemm 	/*
599c2aa98e2SPeter Wemm 	**  Set up macros for possible expansion in headers.
600c2aa98e2SPeter Wemm 	*/
601c2aa98e2SPeter Wemm 
602c2aa98e2SPeter Wemm 	define('f', e->e_sender, e);
603c2aa98e2SPeter Wemm 	define('g', e->e_sender, e);
604c2aa98e2SPeter Wemm 	if (e->e_origrcpt != NULL && *e->e_origrcpt != '\0')
605c2aa98e2SPeter Wemm 		define('u', e->e_origrcpt, e);
606c2aa98e2SPeter Wemm 	else
607c2aa98e2SPeter Wemm 		define('u', NULL, e);
608c2aa98e2SPeter Wemm 
609c2aa98e2SPeter Wemm 	/* full name of from person */
610c2aa98e2SPeter Wemm 	p = hvalue("full-name", e->e_header);
611c2aa98e2SPeter Wemm 	if (p != NULL)
612c2aa98e2SPeter Wemm 	{
613c2aa98e2SPeter Wemm 		if (!rfc822_string(p))
614c2aa98e2SPeter Wemm 		{
615c2aa98e2SPeter Wemm 			/*
616c2aa98e2SPeter Wemm 			**  Quote a full name with special characters
617c2aa98e2SPeter Wemm 			**  as a comment so crackaddr() doesn't destroy
618c2aa98e2SPeter Wemm 			**  the name portion of the address.
619c2aa98e2SPeter Wemm 			*/
620c2aa98e2SPeter Wemm 			p = addquotes(p);
621c2aa98e2SPeter Wemm 		}
622c2aa98e2SPeter Wemm 		define('x', p, e);
623c2aa98e2SPeter Wemm 	}
624c2aa98e2SPeter Wemm 
625c2aa98e2SPeter Wemm 	if (tTd(32, 1))
6263299c2f1SGregory Neil Shapiro 		dprintf("----- collected header -----\n");
627c2aa98e2SPeter Wemm 	msgid = NULL;
628c2aa98e2SPeter Wemm 	for (h = e->e_header; h != NULL; h = h->h_link)
629c2aa98e2SPeter Wemm 	{
630c2aa98e2SPeter Wemm 		if (tTd(32, 1))
6313299c2f1SGregory Neil Shapiro 			dprintf("%s: ", h->h_field);
632c2aa98e2SPeter Wemm 		if (h->h_value == NULL)
633c2aa98e2SPeter Wemm 		{
634c2aa98e2SPeter Wemm 			if (tTd(32, 1))
6353299c2f1SGregory Neil Shapiro 				dprintf("<NULL>\n");
636c2aa98e2SPeter Wemm 			continue;
637c2aa98e2SPeter Wemm 		}
638c2aa98e2SPeter Wemm 
639c2aa98e2SPeter Wemm 		/* do early binding */
6403299c2f1SGregory Neil Shapiro 		if (bitset(H_DEFAULT, h->h_flags) &&
6413299c2f1SGregory Neil Shapiro 		    !bitset(H_BINDLATE, h->h_flags))
642c2aa98e2SPeter Wemm 		{
643c2aa98e2SPeter Wemm 			if (tTd(32, 1))
644c2aa98e2SPeter Wemm 			{
6453299c2f1SGregory Neil Shapiro 				dprintf("(");
646c2aa98e2SPeter Wemm 				xputs(h->h_value);
6473299c2f1SGregory Neil Shapiro 				dprintf(") ");
648c2aa98e2SPeter Wemm 			}
649c2aa98e2SPeter Wemm 			expand(h->h_value, buf, sizeof buf, e);
650c2aa98e2SPeter Wemm 			if (buf[0] != '\0')
651c2aa98e2SPeter Wemm 			{
652c2aa98e2SPeter Wemm 				if (bitset(H_FROM, h->h_flags))
653c2aa98e2SPeter Wemm 					expand(crackaddr(buf), buf, sizeof buf, e);
654c2aa98e2SPeter Wemm 				h->h_value = newstr(buf);
655c2aa98e2SPeter Wemm 				h->h_flags &= ~H_DEFAULT;
656c2aa98e2SPeter Wemm 			}
657c2aa98e2SPeter Wemm 		}
658c2aa98e2SPeter Wemm 
659c2aa98e2SPeter Wemm 		if (tTd(32, 1))
660c2aa98e2SPeter Wemm 		{
661c2aa98e2SPeter Wemm 			xputs(h->h_value);
6623299c2f1SGregory Neil Shapiro 			dprintf("\n");
663c2aa98e2SPeter Wemm 		}
664c2aa98e2SPeter Wemm 
665c2aa98e2SPeter Wemm 		/* count the number of times it has been processed */
666c2aa98e2SPeter Wemm 		if (bitset(H_TRACE, h->h_flags))
667c2aa98e2SPeter Wemm 			hopcnt++;
668c2aa98e2SPeter Wemm 
669c2aa98e2SPeter Wemm 		/* send to this person if we so desire */
670c2aa98e2SPeter Wemm 		if (GrabTo && bitset(H_RCPT, h->h_flags) &&
671c2aa98e2SPeter Wemm 		    !bitset(H_DEFAULT, h->h_flags) &&
672c2aa98e2SPeter Wemm 		    (!bitset(EF_RESENT, e->e_flags) || bitset(H_RESENT, h->h_flags)))
673c2aa98e2SPeter Wemm 		{
674c2aa98e2SPeter Wemm #if 0
675c2aa98e2SPeter Wemm 			int saveflags = e->e_flags;
6763299c2f1SGregory Neil Shapiro #endif /* 0 */
677c2aa98e2SPeter Wemm 
678c2aa98e2SPeter Wemm 			(void) sendtolist(h->h_value, NULLADDR,
679c2aa98e2SPeter Wemm 					  &e->e_sendqueue, 0, e);
680c2aa98e2SPeter Wemm 
681c2aa98e2SPeter Wemm #if 0
682c2aa98e2SPeter Wemm 			/*
683c2aa98e2SPeter Wemm 			**  Change functionality so a fatal error on an
684c2aa98e2SPeter Wemm 			**  address doesn't affect the entire envelope.
685c2aa98e2SPeter Wemm 			*/
686c2aa98e2SPeter Wemm 
687c2aa98e2SPeter Wemm 			/* delete fatal errors generated by this address */
688c2aa98e2SPeter Wemm 			if (!bitset(EF_FATALERRS, saveflags))
689c2aa98e2SPeter Wemm 				e->e_flags &= ~EF_FATALERRS;
6903299c2f1SGregory Neil Shapiro #endif /* 0 */
691c2aa98e2SPeter Wemm 		}
692c2aa98e2SPeter Wemm 
693c2aa98e2SPeter Wemm 		/* save the message-id for logging */
694c2aa98e2SPeter Wemm 		p = "resent-message-id";
695c2aa98e2SPeter Wemm 		if (!bitset(EF_RESENT, e->e_flags))
696c2aa98e2SPeter Wemm 			p += 7;
697c2aa98e2SPeter Wemm 		if (strcasecmp(h->h_field, p) == 0)
698c2aa98e2SPeter Wemm 		{
699c2aa98e2SPeter Wemm 			msgid = h->h_value;
700c2aa98e2SPeter Wemm 			while (isascii(*msgid) && isspace(*msgid))
701c2aa98e2SPeter Wemm 				msgid++;
702c2aa98e2SPeter Wemm 		}
703c2aa98e2SPeter Wemm 	}
704c2aa98e2SPeter Wemm 	if (tTd(32, 1))
7053299c2f1SGregory Neil Shapiro 		dprintf("----------------------------\n");
706c2aa98e2SPeter Wemm 
707c2aa98e2SPeter Wemm 	/* if we are just verifying (that is, sendmail -t -bv), drop out now */
708c2aa98e2SPeter Wemm 	if (OpMode == MD_VERIFY)
709c2aa98e2SPeter Wemm 		return;
710c2aa98e2SPeter Wemm 
711c2aa98e2SPeter Wemm 	/* store hop count */
712c2aa98e2SPeter Wemm 	if (hopcnt > e->e_hopcount)
713c2aa98e2SPeter Wemm 		e->e_hopcount = hopcnt;
714c2aa98e2SPeter Wemm 
715c2aa98e2SPeter Wemm 	/* message priority */
716c2aa98e2SPeter Wemm 	p = hvalue("precedence", e->e_header);
717c2aa98e2SPeter Wemm 	if (p != NULL)
718c2aa98e2SPeter Wemm 		e->e_class = priencode(p);
719c2aa98e2SPeter Wemm 	if (e->e_class < 0)
720c2aa98e2SPeter Wemm 		e->e_timeoutclass = TOC_NONURGENT;
721c2aa98e2SPeter Wemm 	else if (e->e_class > 0)
722c2aa98e2SPeter Wemm 		e->e_timeoutclass = TOC_URGENT;
723c2aa98e2SPeter Wemm 	if (full)
724c2aa98e2SPeter Wemm 	{
725c2aa98e2SPeter Wemm 		e->e_msgpriority = e->e_msgsize
726c2aa98e2SPeter Wemm 				 - e->e_class * WkClassFact
727c2aa98e2SPeter Wemm 				 + e->e_nrcpts * WkRecipFact;
728c2aa98e2SPeter Wemm 	}
729c2aa98e2SPeter Wemm 
730c2aa98e2SPeter Wemm 	/* message timeout priority */
731c2aa98e2SPeter Wemm 	p = hvalue("priority", e->e_header);
732c2aa98e2SPeter Wemm 	if (p != NULL)
733c2aa98e2SPeter Wemm 	{
734c2aa98e2SPeter Wemm 		/* (this should be in the configuration file) */
735c2aa98e2SPeter Wemm 		if (strcasecmp(p, "urgent") == 0)
736c2aa98e2SPeter Wemm 			e->e_timeoutclass = TOC_URGENT;
737c2aa98e2SPeter Wemm 		else if (strcasecmp(p, "normal") == 0)
738c2aa98e2SPeter Wemm 			e->e_timeoutclass = TOC_NORMAL;
739c2aa98e2SPeter Wemm 		else if (strcasecmp(p, "non-urgent") == 0)
740c2aa98e2SPeter Wemm 			e->e_timeoutclass = TOC_NONURGENT;
741c2aa98e2SPeter Wemm 	}
742c2aa98e2SPeter Wemm 
743c2aa98e2SPeter Wemm 	/* date message originated */
744c2aa98e2SPeter Wemm 	p = hvalue("posted-date", e->e_header);
745c2aa98e2SPeter Wemm 	if (p == NULL)
746c2aa98e2SPeter Wemm 		p = hvalue("date", e->e_header);
747c2aa98e2SPeter Wemm 	if (p != NULL)
748c2aa98e2SPeter Wemm 		define('a', p, e);
749c2aa98e2SPeter Wemm 
750c2aa98e2SPeter Wemm 	/* check to see if this is a MIME message */
751c2aa98e2SPeter Wemm 	if ((e->e_bodytype != NULL &&
752c2aa98e2SPeter Wemm 	     strcasecmp(e->e_bodytype, "8BITMIME") == 0) ||
753c2aa98e2SPeter Wemm 	    hvalue("MIME-Version", e->e_header) != NULL)
754c2aa98e2SPeter Wemm 	{
755c2aa98e2SPeter Wemm 		e->e_flags |= EF_IS_MIME;
756c2aa98e2SPeter Wemm 		if (HasEightBits)
757c2aa98e2SPeter Wemm 			e->e_bodytype = "8BITMIME";
758c2aa98e2SPeter Wemm 	}
759c2aa98e2SPeter Wemm 	else if ((p = hvalue("Content-Type", e->e_header)) != NULL)
760c2aa98e2SPeter Wemm 	{
761c2aa98e2SPeter Wemm 		/* this may be an RFC 1049 message */
762c2aa98e2SPeter Wemm 		p = strpbrk(p, ";/");
763c2aa98e2SPeter Wemm 		if (p == NULL || *p == ';')
764c2aa98e2SPeter Wemm 		{
765c2aa98e2SPeter Wemm 			/* yep, it is */
766c2aa98e2SPeter Wemm 			e->e_flags |= EF_DONT_MIME;
767c2aa98e2SPeter Wemm 		}
768c2aa98e2SPeter Wemm 	}
769c2aa98e2SPeter Wemm 
770c2aa98e2SPeter Wemm 	/*
771c2aa98e2SPeter Wemm 	**  From person in antiquated ARPANET mode
772c2aa98e2SPeter Wemm 	**	required by UK Grey Book e-mail gateways (sigh)
773c2aa98e2SPeter Wemm 	*/
774c2aa98e2SPeter Wemm 
775c2aa98e2SPeter Wemm 	if (OpMode == MD_ARPAFTP)
776c2aa98e2SPeter Wemm 	{
777c2aa98e2SPeter Wemm 		register struct hdrinfo *hi;
778c2aa98e2SPeter Wemm 
779c2aa98e2SPeter Wemm 		for (hi = HdrInfo; hi->hi_field != NULL; hi++)
780c2aa98e2SPeter Wemm 		{
781c2aa98e2SPeter Wemm 			if (bitset(H_FROM, hi->hi_flags) &&
782c2aa98e2SPeter Wemm 			    (!bitset(H_RESENT, hi->hi_flags) ||
783c2aa98e2SPeter Wemm 			     bitset(EF_RESENT, e->e_flags)) &&
784c2aa98e2SPeter Wemm 			    (p = hvalue(hi->hi_field, e->e_header)) != NULL)
785c2aa98e2SPeter Wemm 				break;
786c2aa98e2SPeter Wemm 		}
787c2aa98e2SPeter Wemm 		if (hi->hi_field != NULL)
788c2aa98e2SPeter Wemm 		{
789c2aa98e2SPeter Wemm 			if (tTd(32, 2))
7903299c2f1SGregory Neil Shapiro 				dprintf("eatheader: setsender(*%s == %s)\n",
791c2aa98e2SPeter Wemm 					hi->hi_field, p);
792c2aa98e2SPeter Wemm 			setsender(p, e, NULL, '\0', TRUE);
793c2aa98e2SPeter Wemm 		}
794c2aa98e2SPeter Wemm 	}
795c2aa98e2SPeter Wemm 
796c2aa98e2SPeter Wemm 	/*
797c2aa98e2SPeter Wemm 	**  Log collection information.
798c2aa98e2SPeter Wemm 	*/
799c2aa98e2SPeter Wemm 
800c2aa98e2SPeter Wemm 	if (bitset(EF_LOGSENDER, e->e_flags) && LogLevel > 4)
801c2aa98e2SPeter Wemm 		logsender(e, msgid);
802c2aa98e2SPeter Wemm 	e->e_flags &= ~EF_LOGSENDER;
803c2aa98e2SPeter Wemm }
804c2aa98e2SPeter Wemm /*
805c2aa98e2SPeter Wemm **  LOGSENDER -- log sender information
806c2aa98e2SPeter Wemm **
807c2aa98e2SPeter Wemm **	Parameters:
808c2aa98e2SPeter Wemm **		e -- the envelope to log
809c2aa98e2SPeter Wemm **		msgid -- the message id
810c2aa98e2SPeter Wemm **
811c2aa98e2SPeter Wemm **	Returns:
812c2aa98e2SPeter Wemm **		none
813c2aa98e2SPeter Wemm */
814c2aa98e2SPeter Wemm 
815c2aa98e2SPeter Wemm void
816c2aa98e2SPeter Wemm logsender(e, msgid)
817c2aa98e2SPeter Wemm 	register ENVELOPE *e;
818c2aa98e2SPeter Wemm 	char *msgid;
819c2aa98e2SPeter Wemm {
820c2aa98e2SPeter Wemm 	char *name;
821c2aa98e2SPeter Wemm 	register char *sbp;
822c2aa98e2SPeter Wemm 	register char *p;
823c2aa98e2SPeter Wemm 	int l;
824c2aa98e2SPeter Wemm 	char hbuf[MAXNAME + 1];
825c2aa98e2SPeter Wemm 	char sbuf[MAXLINE + 1];
826c2aa98e2SPeter Wemm 	char mbuf[MAXNAME + 1];
827c2aa98e2SPeter Wemm 
828c2aa98e2SPeter Wemm 	/* don't allow newlines in the message-id */
829c2aa98e2SPeter Wemm 	if (msgid != NULL)
830c2aa98e2SPeter Wemm 	{
831c2aa98e2SPeter Wemm 		l = strlen(msgid);
832c2aa98e2SPeter Wemm 		if (l > sizeof mbuf - 1)
833c2aa98e2SPeter Wemm 			l = sizeof mbuf - 1;
8343299c2f1SGregory Neil Shapiro 		memmove(mbuf, msgid, l);
835c2aa98e2SPeter Wemm 		mbuf[l] = '\0';
836c2aa98e2SPeter Wemm 		p = mbuf;
837c2aa98e2SPeter Wemm 		while ((p = strchr(p, '\n')) != NULL)
838c2aa98e2SPeter Wemm 			*p++ = ' ';
839c2aa98e2SPeter Wemm 	}
840c2aa98e2SPeter Wemm 
841c2aa98e2SPeter Wemm 	if (bitset(EF_RESPONSE, e->e_flags))
842c2aa98e2SPeter Wemm 		name = "[RESPONSE]";
843c2aa98e2SPeter Wemm 	else if ((name = macvalue('_', e)) != NULL)
8443299c2f1SGregory Neil Shapiro 		/* EMPTY */
845c2aa98e2SPeter Wemm 		;
846c2aa98e2SPeter Wemm 	else if (RealHostName == NULL)
847c2aa98e2SPeter Wemm 		name = "localhost";
848c2aa98e2SPeter Wemm 	else if (RealHostName[0] == '[')
849c2aa98e2SPeter Wemm 		name = RealHostName;
850c2aa98e2SPeter Wemm 	else
851c2aa98e2SPeter Wemm 	{
852c2aa98e2SPeter Wemm 		name = hbuf;
853c2aa98e2SPeter Wemm 		(void) snprintf(hbuf, sizeof hbuf, "%.80s", RealHostName);
854c2aa98e2SPeter Wemm 		if (RealHostAddr.sa.sa_family != 0)
855c2aa98e2SPeter Wemm 		{
856c2aa98e2SPeter Wemm 			p = &hbuf[strlen(hbuf)];
857c2aa98e2SPeter Wemm 			(void) snprintf(p, SPACELEFT(hbuf, p), " (%.100s)",
858c2aa98e2SPeter Wemm 				anynet_ntoa(&RealHostAddr));
859c2aa98e2SPeter Wemm 		}
860c2aa98e2SPeter Wemm 	}
861c2aa98e2SPeter Wemm 
862c2aa98e2SPeter Wemm 	/* some versions of syslog only take 5 printf args */
863c2aa98e2SPeter Wemm #if (SYSLOG_BUFSIZE) >= 256
864c2aa98e2SPeter Wemm 	sbp = sbuf;
865c2aa98e2SPeter Wemm 	snprintf(sbp, SPACELEFT(sbuf, sbp),
8663299c2f1SGregory Neil Shapiro 	    "from=%.200s, size=%ld, class=%d, nrcpts=%d",
867c2aa98e2SPeter Wemm 	    e->e_from.q_paddr == NULL ? "<NONE>" : e->e_from.q_paddr,
8683299c2f1SGregory Neil Shapiro 	    e->e_msgsize, e->e_class, e->e_nrcpts);
869c2aa98e2SPeter Wemm 	sbp += strlen(sbp);
870c2aa98e2SPeter Wemm 	if (msgid != NULL)
871c2aa98e2SPeter Wemm 	{
872c2aa98e2SPeter Wemm 		snprintf(sbp, SPACELEFT(sbuf, sbp), ", msgid=%.100s", mbuf);
873c2aa98e2SPeter Wemm 		sbp += strlen(sbp);
874c2aa98e2SPeter Wemm 	}
875c2aa98e2SPeter Wemm 	if (e->e_bodytype != NULL)
876c2aa98e2SPeter Wemm 	{
877c2aa98e2SPeter Wemm 		(void) snprintf(sbp, SPACELEFT(sbuf, sbp), ", bodytype=%.20s",
878c2aa98e2SPeter Wemm 			e->e_bodytype);
879c2aa98e2SPeter Wemm 		sbp += strlen(sbp);
880c2aa98e2SPeter Wemm 	}
881c2aa98e2SPeter Wemm 	p = macvalue('r', e);
882c2aa98e2SPeter Wemm 	if (p != NULL)
8833299c2f1SGregory Neil Shapiro 	{
884c2aa98e2SPeter Wemm 		(void) snprintf(sbp, SPACELEFT(sbuf, sbp), ", proto=%.20s", p);
8853299c2f1SGregory Neil Shapiro 		sbp += strlen(sbp);
8863299c2f1SGregory Neil Shapiro 	}
8873299c2f1SGregory Neil Shapiro 	p = macvalue(macid("{daemon_name}", NULL), e);
8883299c2f1SGregory Neil Shapiro 	if (p != NULL)
8893299c2f1SGregory Neil Shapiro 	{
8903299c2f1SGregory Neil Shapiro 		(void) snprintf(sbp, SPACELEFT(sbuf, sbp), ", daemon=%.20s", p);
8913299c2f1SGregory Neil Shapiro 		sbp += strlen(sbp);
8923299c2f1SGregory Neil Shapiro 	}
8933299c2f1SGregory Neil Shapiro # if SASL
8943299c2f1SGregory Neil Shapiro 	p = macvalue(macid("{auth_type}", NULL), e);
8953299c2f1SGregory Neil Shapiro 	if (p != NULL)
8963299c2f1SGregory Neil Shapiro 	{
8973299c2f1SGregory Neil Shapiro 		(void) snprintf(sbp, SPACELEFT(sbuf, sbp), ", mech=%.12s", p);
8983299c2f1SGregory Neil Shapiro 		sbp += strlen(sbp);
8993299c2f1SGregory Neil Shapiro 	}
9003299c2f1SGregory Neil Shapiro 	p = macvalue(macid("{auth_author}", NULL), e);
9013299c2f1SGregory Neil Shapiro 	if (p != NULL)
9023299c2f1SGregory Neil Shapiro 	{
9033299c2f1SGregory Neil Shapiro 		(void) snprintf(sbp, SPACELEFT(sbuf, sbp), ", auth=%.30s", p);
9043299c2f1SGregory Neil Shapiro 		sbp += strlen(sbp);
9053299c2f1SGregory Neil Shapiro 	}
9063299c2f1SGregory Neil Shapiro # endif /* SASL */
907c2aa98e2SPeter Wemm 	sm_syslog(LOG_INFO, e->e_id,
908c2aa98e2SPeter Wemm 		  "%.850s, relay=%.100s",
909c2aa98e2SPeter Wemm 		  sbuf, name);
910c2aa98e2SPeter Wemm 
9113299c2f1SGregory Neil Shapiro #else /* (SYSLOG_BUFSIZE) >= 256 */
912c2aa98e2SPeter Wemm 
913c2aa98e2SPeter Wemm 	sm_syslog(LOG_INFO, e->e_id,
914c2aa98e2SPeter Wemm 		  "from=%s",
915c2aa98e2SPeter Wemm 		  e->e_from.q_paddr == NULL ? "<NONE>"
916c2aa98e2SPeter Wemm 					    : shortenstring(e->e_from.q_paddr, 83));
917c2aa98e2SPeter Wemm 	sm_syslog(LOG_INFO, e->e_id,
9183299c2f1SGregory Neil Shapiro 		  "size=%ld, class=%ld, nrcpts=%d",
9193299c2f1SGregory Neil Shapiro 		  e->e_msgsize, e->e_class, e->e_nrcpts);
920c2aa98e2SPeter Wemm 	if (msgid != NULL)
921c2aa98e2SPeter Wemm 		sm_syslog(LOG_INFO, e->e_id,
922c2aa98e2SPeter Wemm 			  "msgid=%s",
923c2aa98e2SPeter Wemm 			  shortenstring(mbuf, 83));
924c2aa98e2SPeter Wemm 	sbp = sbuf;
925c2aa98e2SPeter Wemm 	*sbp = '\0';
926c2aa98e2SPeter Wemm 	if (e->e_bodytype != NULL)
927c2aa98e2SPeter Wemm 	{
928c2aa98e2SPeter Wemm 		snprintf(sbp, SPACELEFT(sbuf, sbp), "bodytype=%.20s, ", e->e_bodytype);
929c2aa98e2SPeter Wemm 		sbp += strlen(sbp);
930c2aa98e2SPeter Wemm 	}
931c2aa98e2SPeter Wemm 	p = macvalue('r', e);
932c2aa98e2SPeter Wemm 	if (p != NULL)
933c2aa98e2SPeter Wemm 	{
934c2aa98e2SPeter Wemm 		snprintf(sbp, SPACELEFT(sbuf, sbp), "proto=%.20s, ", p);
935c2aa98e2SPeter Wemm 		sbp += strlen(sbp);
936c2aa98e2SPeter Wemm 	}
937c2aa98e2SPeter Wemm 	sm_syslog(LOG_INFO, e->e_id,
938c2aa98e2SPeter Wemm 		  "%.400srelay=%.100s", sbuf, name);
9393299c2f1SGregory Neil Shapiro #endif /* (SYSLOG_BUFSIZE) >= 256 */
940c2aa98e2SPeter Wemm }
941c2aa98e2SPeter Wemm /*
942c2aa98e2SPeter Wemm **  PRIENCODE -- encode external priority names into internal values.
943c2aa98e2SPeter Wemm **
944c2aa98e2SPeter Wemm **	Parameters:
945c2aa98e2SPeter Wemm **		p -- priority in ascii.
946c2aa98e2SPeter Wemm **
947c2aa98e2SPeter Wemm **	Returns:
948c2aa98e2SPeter Wemm **		priority as a numeric level.
949c2aa98e2SPeter Wemm **
950c2aa98e2SPeter Wemm **	Side Effects:
951c2aa98e2SPeter Wemm **		none.
952c2aa98e2SPeter Wemm */
953c2aa98e2SPeter Wemm 
9543299c2f1SGregory Neil Shapiro static int
955c2aa98e2SPeter Wemm priencode(p)
956c2aa98e2SPeter Wemm 	char *p;
957c2aa98e2SPeter Wemm {
958c2aa98e2SPeter Wemm 	register int i;
959c2aa98e2SPeter Wemm 
960c2aa98e2SPeter Wemm 	for (i = 0; i < NumPriorities; i++)
961c2aa98e2SPeter Wemm 	{
9623299c2f1SGregory Neil Shapiro 		if (strcasecmp(p, Priorities[i].pri_name) == 0)
9633299c2f1SGregory Neil Shapiro 			return Priorities[i].pri_val;
964c2aa98e2SPeter Wemm 	}
965c2aa98e2SPeter Wemm 
966c2aa98e2SPeter Wemm 	/* unknown priority */
9673299c2f1SGregory Neil Shapiro 	return 0;
968c2aa98e2SPeter Wemm }
969c2aa98e2SPeter Wemm /*
970c2aa98e2SPeter Wemm **  CRACKADDR -- parse an address and turn it into a macro
971c2aa98e2SPeter Wemm **
972c2aa98e2SPeter Wemm **	This doesn't actually parse the address -- it just extracts
973c2aa98e2SPeter Wemm **	it and replaces it with "$g".  The parse is totally ad hoc
974c2aa98e2SPeter Wemm **	and isn't even guaranteed to leave something syntactically
975c2aa98e2SPeter Wemm **	identical to what it started with.  However, it does leave
976c2aa98e2SPeter Wemm **	something semantically identical.
977c2aa98e2SPeter Wemm **
978c2aa98e2SPeter Wemm **	This algorithm has been cleaned up to handle a wider range
979c2aa98e2SPeter Wemm **	of cases -- notably quoted and backslash escaped strings.
980c2aa98e2SPeter Wemm **	This modification makes it substantially better at preserving
981c2aa98e2SPeter Wemm **	the original syntax.
982c2aa98e2SPeter Wemm **
983c2aa98e2SPeter Wemm **	Parameters:
984c2aa98e2SPeter Wemm **		addr -- the address to be cracked.
985c2aa98e2SPeter Wemm **
986c2aa98e2SPeter Wemm **	Returns:
987c2aa98e2SPeter Wemm **		a pointer to the new version.
988c2aa98e2SPeter Wemm **
989c2aa98e2SPeter Wemm **	Side Effects:
990c2aa98e2SPeter Wemm **		none.
991c2aa98e2SPeter Wemm **
992c2aa98e2SPeter Wemm **	Warning:
993c2aa98e2SPeter Wemm **		The return value is saved in local storage and should
994c2aa98e2SPeter Wemm **		be copied if it is to be reused.
995c2aa98e2SPeter Wemm */
996c2aa98e2SPeter Wemm 
997c2aa98e2SPeter Wemm char *
998c2aa98e2SPeter Wemm crackaddr(addr)
999c2aa98e2SPeter Wemm 	register char *addr;
1000c2aa98e2SPeter Wemm {
1001c2aa98e2SPeter Wemm 	register char *p;
1002c2aa98e2SPeter Wemm 	register char c;
1003c2aa98e2SPeter Wemm 	int cmtlev;
1004c2aa98e2SPeter Wemm 	int realcmtlev;
1005c2aa98e2SPeter Wemm 	int anglelev, realanglelev;
1006c2aa98e2SPeter Wemm 	int copylev;
1007c2aa98e2SPeter Wemm 	int bracklev;
1008c2aa98e2SPeter Wemm 	bool qmode;
1009c2aa98e2SPeter Wemm 	bool realqmode;
1010c2aa98e2SPeter Wemm 	bool skipping;
1011c2aa98e2SPeter Wemm 	bool putgmac = FALSE;
1012c2aa98e2SPeter Wemm 	bool quoteit = FALSE;
1013c2aa98e2SPeter Wemm 	bool gotangle = FALSE;
1014c2aa98e2SPeter Wemm 	bool gotcolon = FALSE;
1015c2aa98e2SPeter Wemm 	register char *bp;
1016c2aa98e2SPeter Wemm 	char *buflim;
1017c2aa98e2SPeter Wemm 	char *bufhead;
1018c2aa98e2SPeter Wemm 	char *addrhead;
1019c2aa98e2SPeter Wemm 	static char buf[MAXNAME + 1];
1020c2aa98e2SPeter Wemm 
1021c2aa98e2SPeter Wemm 	if (tTd(33, 1))
10223299c2f1SGregory Neil Shapiro 		dprintf("crackaddr(%s)\n", addr);
1023c2aa98e2SPeter Wemm 
1024c2aa98e2SPeter Wemm 	/* strip leading spaces */
1025c2aa98e2SPeter Wemm 	while (*addr != '\0' && isascii(*addr) && isspace(*addr))
1026c2aa98e2SPeter Wemm 		addr++;
1027c2aa98e2SPeter Wemm 
1028c2aa98e2SPeter Wemm 	/*
1029c2aa98e2SPeter Wemm 	**  Start by assuming we have no angle brackets.  This will be
1030c2aa98e2SPeter Wemm 	**  adjusted later if we find them.
1031c2aa98e2SPeter Wemm 	*/
1032c2aa98e2SPeter Wemm 
1033c2aa98e2SPeter Wemm 	bp = bufhead = buf;
1034c2aa98e2SPeter Wemm 	buflim = &buf[sizeof buf - 7];
1035c2aa98e2SPeter Wemm 	p = addrhead = addr;
1036c2aa98e2SPeter Wemm 	copylev = anglelev = realanglelev = cmtlev = realcmtlev = 0;
1037c2aa98e2SPeter Wemm 	bracklev = 0;
1038c2aa98e2SPeter Wemm 	qmode = realqmode = FALSE;
1039c2aa98e2SPeter Wemm 
1040c2aa98e2SPeter Wemm 	while ((c = *p++) != '\0')
1041c2aa98e2SPeter Wemm 	{
1042c2aa98e2SPeter Wemm 		/*
1043c2aa98e2SPeter Wemm 		**  If the buffer is overful, go into a special "skipping"
1044c2aa98e2SPeter Wemm 		**  mode that tries to keep legal syntax but doesn't actually
1045c2aa98e2SPeter Wemm 		**  output things.
1046c2aa98e2SPeter Wemm 		*/
1047c2aa98e2SPeter Wemm 
1048c2aa98e2SPeter Wemm 		skipping = bp >= buflim;
1049c2aa98e2SPeter Wemm 
1050c2aa98e2SPeter Wemm 		if (copylev > 0 && !skipping)
1051c2aa98e2SPeter Wemm 			*bp++ = c;
1052c2aa98e2SPeter Wemm 
1053c2aa98e2SPeter Wemm 		/* check for backslash escapes */
1054c2aa98e2SPeter Wemm 		if (c == '\\')
1055c2aa98e2SPeter Wemm 		{
1056c2aa98e2SPeter Wemm 			/* arrange to quote the address */
1057c2aa98e2SPeter Wemm 			if (cmtlev <= 0 && !qmode)
1058c2aa98e2SPeter Wemm 				quoteit = TRUE;
1059c2aa98e2SPeter Wemm 
1060c2aa98e2SPeter Wemm 			if ((c = *p++) == '\0')
1061c2aa98e2SPeter Wemm 			{
1062c2aa98e2SPeter Wemm 				/* too far */
1063c2aa98e2SPeter Wemm 				p--;
1064c2aa98e2SPeter Wemm 				goto putg;
1065c2aa98e2SPeter Wemm 			}
1066c2aa98e2SPeter Wemm 			if (copylev > 0 && !skipping)
1067c2aa98e2SPeter Wemm 				*bp++ = c;
1068c2aa98e2SPeter Wemm 			goto putg;
1069c2aa98e2SPeter Wemm 		}
1070c2aa98e2SPeter Wemm 
1071c2aa98e2SPeter Wemm 		/* check for quoted strings */
1072c2aa98e2SPeter Wemm 		if (c == '"' && cmtlev <= 0)
1073c2aa98e2SPeter Wemm 		{
1074c2aa98e2SPeter Wemm 			qmode = !qmode;
1075c2aa98e2SPeter Wemm 			if (copylev > 0 && !skipping)
1076c2aa98e2SPeter Wemm 				realqmode = !realqmode;
1077c2aa98e2SPeter Wemm 			continue;
1078c2aa98e2SPeter Wemm 		}
1079c2aa98e2SPeter Wemm 		if (qmode)
1080c2aa98e2SPeter Wemm 			goto putg;
1081c2aa98e2SPeter Wemm 
1082c2aa98e2SPeter Wemm 		/* check for comments */
1083c2aa98e2SPeter Wemm 		if (c == '(')
1084c2aa98e2SPeter Wemm 		{
1085c2aa98e2SPeter Wemm 			cmtlev++;
1086c2aa98e2SPeter Wemm 
1087c2aa98e2SPeter Wemm 			/* allow space for closing paren */
1088c2aa98e2SPeter Wemm 			if (!skipping)
1089c2aa98e2SPeter Wemm 			{
1090c2aa98e2SPeter Wemm 				buflim--;
1091c2aa98e2SPeter Wemm 				realcmtlev++;
1092c2aa98e2SPeter Wemm 				if (copylev++ <= 0)
1093c2aa98e2SPeter Wemm 				{
1094c2aa98e2SPeter Wemm 					if (bp != bufhead)
1095c2aa98e2SPeter Wemm 						*bp++ = ' ';
1096c2aa98e2SPeter Wemm 					*bp++ = c;
1097c2aa98e2SPeter Wemm 				}
1098c2aa98e2SPeter Wemm 			}
1099c2aa98e2SPeter Wemm 		}
1100c2aa98e2SPeter Wemm 		if (cmtlev > 0)
1101c2aa98e2SPeter Wemm 		{
1102c2aa98e2SPeter Wemm 			if (c == ')')
1103c2aa98e2SPeter Wemm 			{
1104c2aa98e2SPeter Wemm 				cmtlev--;
1105c2aa98e2SPeter Wemm 				copylev--;
1106c2aa98e2SPeter Wemm 				if (!skipping)
1107c2aa98e2SPeter Wemm 				{
1108c2aa98e2SPeter Wemm 					realcmtlev--;
1109c2aa98e2SPeter Wemm 					buflim++;
1110c2aa98e2SPeter Wemm 				}
1111c2aa98e2SPeter Wemm 			}
1112c2aa98e2SPeter Wemm 			continue;
1113c2aa98e2SPeter Wemm 		}
1114c2aa98e2SPeter Wemm 		else if (c == ')')
1115c2aa98e2SPeter Wemm 		{
1116c2aa98e2SPeter Wemm 			/* syntax error: unmatched ) */
1117c2aa98e2SPeter Wemm 			if (copylev > 0 && !skipping)
1118c2aa98e2SPeter Wemm 				bp--;
1119c2aa98e2SPeter Wemm 		}
1120c2aa98e2SPeter Wemm 
1121c2aa98e2SPeter Wemm 		/* count nesting on [ ... ] (for IPv6 domain literals) */
1122c2aa98e2SPeter Wemm 		if (c == '[')
1123c2aa98e2SPeter Wemm 			bracklev++;
1124c2aa98e2SPeter Wemm 		else if (c == ']')
1125c2aa98e2SPeter Wemm 			bracklev--;
1126c2aa98e2SPeter Wemm 
1127c2aa98e2SPeter Wemm 		/* check for group: list; syntax */
1128c2aa98e2SPeter Wemm 		if (c == ':' && anglelev <= 0 && bracklev <= 0 &&
1129c2aa98e2SPeter Wemm 		    !gotcolon && !ColonOkInAddr)
1130c2aa98e2SPeter Wemm 		{
1131c2aa98e2SPeter Wemm 			register char *q;
1132c2aa98e2SPeter Wemm 
1133c2aa98e2SPeter Wemm 			/*
1134c2aa98e2SPeter Wemm 			**  Check for DECnet phase IV ``::'' (host::user)
1135c2aa98e2SPeter Wemm 			**  or **  DECnet phase V ``:.'' syntaxes.  The latter
1136c2aa98e2SPeter Wemm 			**  covers ``user@DEC:.tay.myhost'' and
1137c2aa98e2SPeter Wemm 			**  ``DEC:.tay.myhost::user'' syntaxes (bletch).
1138c2aa98e2SPeter Wemm 			*/
1139c2aa98e2SPeter Wemm 
1140c2aa98e2SPeter Wemm 			if (*p == ':' || *p == '.')
1141c2aa98e2SPeter Wemm 			{
1142c2aa98e2SPeter Wemm 				if (cmtlev <= 0 && !qmode)
1143c2aa98e2SPeter Wemm 					quoteit = TRUE;
1144c2aa98e2SPeter Wemm 				if (copylev > 0 && !skipping)
1145c2aa98e2SPeter Wemm 				{
1146c2aa98e2SPeter Wemm 					*bp++ = c;
1147c2aa98e2SPeter Wemm 					*bp++ = *p;
1148c2aa98e2SPeter Wemm 				}
1149c2aa98e2SPeter Wemm 				p++;
1150c2aa98e2SPeter Wemm 				goto putg;
1151c2aa98e2SPeter Wemm 			}
1152c2aa98e2SPeter Wemm 
1153c2aa98e2SPeter Wemm 			gotcolon = TRUE;
1154c2aa98e2SPeter Wemm 
1155c2aa98e2SPeter Wemm 			bp = bufhead;
1156c2aa98e2SPeter Wemm 			if (quoteit)
1157c2aa98e2SPeter Wemm 			{
1158c2aa98e2SPeter Wemm 				*bp++ = '"';
1159c2aa98e2SPeter Wemm 
1160c2aa98e2SPeter Wemm 				/* back up over the ':' and any spaces */
1161c2aa98e2SPeter Wemm 				--p;
1162c2aa98e2SPeter Wemm 				while (isascii(*--p) && isspace(*p))
1163c2aa98e2SPeter Wemm 					continue;
1164c2aa98e2SPeter Wemm 				p++;
1165c2aa98e2SPeter Wemm 			}
1166c2aa98e2SPeter Wemm 			for (q = addrhead; q < p; )
1167c2aa98e2SPeter Wemm 			{
1168c2aa98e2SPeter Wemm 				c = *q++;
1169c2aa98e2SPeter Wemm 				if (bp < buflim)
1170c2aa98e2SPeter Wemm 				{
1171c2aa98e2SPeter Wemm 					if (quoteit && c == '"')
1172c2aa98e2SPeter Wemm 						*bp++ = '\\';
1173c2aa98e2SPeter Wemm 					*bp++ = c;
1174c2aa98e2SPeter Wemm 				}
1175c2aa98e2SPeter Wemm 			}
1176c2aa98e2SPeter Wemm 			if (quoteit)
1177c2aa98e2SPeter Wemm 			{
1178c2aa98e2SPeter Wemm 				if (bp == &bufhead[1])
1179c2aa98e2SPeter Wemm 					bp--;
1180c2aa98e2SPeter Wemm 				else
1181c2aa98e2SPeter Wemm 					*bp++ = '"';
1182c2aa98e2SPeter Wemm 				while ((c = *p++) != ':')
1183c2aa98e2SPeter Wemm 				{
1184c2aa98e2SPeter Wemm 					if (bp < buflim)
1185c2aa98e2SPeter Wemm 						*bp++ = c;
1186c2aa98e2SPeter Wemm 				}
1187c2aa98e2SPeter Wemm 				*bp++ = c;
1188c2aa98e2SPeter Wemm 			}
1189c2aa98e2SPeter Wemm 
1190c2aa98e2SPeter Wemm 			/* any trailing white space is part of group: */
1191c2aa98e2SPeter Wemm 			while (isascii(*p) && isspace(*p) && bp < buflim)
1192c2aa98e2SPeter Wemm 				*bp++ = *p++;
1193c2aa98e2SPeter Wemm 			copylev = 0;
1194c2aa98e2SPeter Wemm 			putgmac = quoteit = FALSE;
1195c2aa98e2SPeter Wemm 			bufhead = bp;
1196c2aa98e2SPeter Wemm 			addrhead = p;
1197c2aa98e2SPeter Wemm 			continue;
1198c2aa98e2SPeter Wemm 		}
1199c2aa98e2SPeter Wemm 
1200c2aa98e2SPeter Wemm 		if (c == ';' && copylev <= 0 && !ColonOkInAddr)
1201c2aa98e2SPeter Wemm 		{
1202c2aa98e2SPeter Wemm 			if (bp < buflim)
1203c2aa98e2SPeter Wemm 				*bp++ = c;
1204c2aa98e2SPeter Wemm 		}
1205c2aa98e2SPeter Wemm 
1206c2aa98e2SPeter Wemm 		/* check for characters that may have to be quoted */
1207c2aa98e2SPeter Wemm 		if (strchr(MustQuoteChars, c) != NULL)
1208c2aa98e2SPeter Wemm 		{
1209c2aa98e2SPeter Wemm 			/*
1210c2aa98e2SPeter Wemm 			**  If these occur as the phrase part of a <>
1211c2aa98e2SPeter Wemm 			**  construct, but are not inside of () or already
1212c2aa98e2SPeter Wemm 			**  quoted, they will have to be quoted.  Note that
1213c2aa98e2SPeter Wemm 			**  now (but don't actually do the quoting).
1214c2aa98e2SPeter Wemm 			*/
1215c2aa98e2SPeter Wemm 
1216c2aa98e2SPeter Wemm 			if (cmtlev <= 0 && !qmode)
1217c2aa98e2SPeter Wemm 				quoteit = TRUE;
1218c2aa98e2SPeter Wemm 		}
1219c2aa98e2SPeter Wemm 
1220c2aa98e2SPeter Wemm 		/* check for angle brackets */
1221c2aa98e2SPeter Wemm 		if (c == '<')
1222c2aa98e2SPeter Wemm 		{
1223c2aa98e2SPeter Wemm 			register char *q;
1224c2aa98e2SPeter Wemm 
1225c2aa98e2SPeter Wemm 			/* assume first of two angles is bogus */
1226c2aa98e2SPeter Wemm 			if (gotangle)
1227c2aa98e2SPeter Wemm 				quoteit = TRUE;
1228c2aa98e2SPeter Wemm 			gotangle = TRUE;
1229c2aa98e2SPeter Wemm 
1230c2aa98e2SPeter Wemm 			/* oops -- have to change our mind */
1231c2aa98e2SPeter Wemm 			anglelev = 1;
1232c2aa98e2SPeter Wemm 			if (!skipping)
1233c2aa98e2SPeter Wemm 				realanglelev = 1;
1234c2aa98e2SPeter Wemm 
1235c2aa98e2SPeter Wemm 			bp = bufhead;
1236c2aa98e2SPeter Wemm 			if (quoteit)
1237c2aa98e2SPeter Wemm 			{
1238c2aa98e2SPeter Wemm 				*bp++ = '"';
1239c2aa98e2SPeter Wemm 
1240c2aa98e2SPeter Wemm 				/* back up over the '<' and any spaces */
1241c2aa98e2SPeter Wemm 				--p;
1242c2aa98e2SPeter Wemm 				while (isascii(*--p) && isspace(*p))
1243c2aa98e2SPeter Wemm 					continue;
1244c2aa98e2SPeter Wemm 				p++;
1245c2aa98e2SPeter Wemm 			}
1246c2aa98e2SPeter Wemm 			for (q = addrhead; q < p; )
1247c2aa98e2SPeter Wemm 			{
1248c2aa98e2SPeter Wemm 				c = *q++;
1249c2aa98e2SPeter Wemm 				if (bp < buflim)
1250c2aa98e2SPeter Wemm 				{
1251c2aa98e2SPeter Wemm 					if (quoteit && c == '"')
1252c2aa98e2SPeter Wemm 						*bp++ = '\\';
1253c2aa98e2SPeter Wemm 					*bp++ = c;
1254c2aa98e2SPeter Wemm 				}
1255c2aa98e2SPeter Wemm 			}
1256c2aa98e2SPeter Wemm 			if (quoteit)
1257c2aa98e2SPeter Wemm 			{
1258c2aa98e2SPeter Wemm 				if (bp == &buf[1])
1259c2aa98e2SPeter Wemm 					bp--;
1260c2aa98e2SPeter Wemm 				else
1261c2aa98e2SPeter Wemm 					*bp++ = '"';
1262c2aa98e2SPeter Wemm 				while ((c = *p++) != '<')
1263c2aa98e2SPeter Wemm 				{
1264c2aa98e2SPeter Wemm 					if (bp < buflim)
1265c2aa98e2SPeter Wemm 						*bp++ = c;
1266c2aa98e2SPeter Wemm 				}
1267c2aa98e2SPeter Wemm 				*bp++ = c;
1268c2aa98e2SPeter Wemm 			}
1269c2aa98e2SPeter Wemm 			copylev = 0;
1270c2aa98e2SPeter Wemm 			putgmac = quoteit = FALSE;
1271c2aa98e2SPeter Wemm 			continue;
1272c2aa98e2SPeter Wemm 		}
1273c2aa98e2SPeter Wemm 
1274c2aa98e2SPeter Wemm 		if (c == '>')
1275c2aa98e2SPeter Wemm 		{
1276c2aa98e2SPeter Wemm 			if (anglelev > 0)
1277c2aa98e2SPeter Wemm 			{
1278c2aa98e2SPeter Wemm 				anglelev--;
1279c2aa98e2SPeter Wemm 				if (!skipping)
1280c2aa98e2SPeter Wemm 				{
1281c2aa98e2SPeter Wemm 					realanglelev--;
1282c2aa98e2SPeter Wemm 					buflim++;
1283c2aa98e2SPeter Wemm 				}
1284c2aa98e2SPeter Wemm 			}
1285c2aa98e2SPeter Wemm 			else if (!skipping)
1286c2aa98e2SPeter Wemm 			{
1287c2aa98e2SPeter Wemm 				/* syntax error: unmatched > */
1288c2aa98e2SPeter Wemm 				if (copylev > 0)
1289c2aa98e2SPeter Wemm 					bp--;
1290c2aa98e2SPeter Wemm 				quoteit = TRUE;
1291c2aa98e2SPeter Wemm 				continue;
1292c2aa98e2SPeter Wemm 			}
1293c2aa98e2SPeter Wemm 			if (copylev++ <= 0)
1294c2aa98e2SPeter Wemm 				*bp++ = c;
1295c2aa98e2SPeter Wemm 			continue;
1296c2aa98e2SPeter Wemm 		}
1297c2aa98e2SPeter Wemm 
1298c2aa98e2SPeter Wemm 		/* must be a real address character */
1299c2aa98e2SPeter Wemm 	putg:
1300c2aa98e2SPeter Wemm 		if (copylev <= 0 && !putgmac)
1301c2aa98e2SPeter Wemm 		{
1302c2aa98e2SPeter Wemm 			if (bp > bufhead && bp[-1] == ')')
1303c2aa98e2SPeter Wemm 				*bp++ = ' ';
1304c2aa98e2SPeter Wemm 			*bp++ = MACROEXPAND;
1305c2aa98e2SPeter Wemm 			*bp++ = 'g';
1306c2aa98e2SPeter Wemm 			putgmac = TRUE;
1307c2aa98e2SPeter Wemm 		}
1308c2aa98e2SPeter Wemm 	}
1309c2aa98e2SPeter Wemm 
1310c2aa98e2SPeter Wemm 	/* repair any syntactic damage */
1311c2aa98e2SPeter Wemm 	if (realqmode)
1312c2aa98e2SPeter Wemm 		*bp++ = '"';
1313c2aa98e2SPeter Wemm 	while (realcmtlev-- > 0)
1314c2aa98e2SPeter Wemm 		*bp++ = ')';
1315c2aa98e2SPeter Wemm 	while (realanglelev-- > 0)
1316c2aa98e2SPeter Wemm 		*bp++ = '>';
1317c2aa98e2SPeter Wemm 	*bp++ = '\0';
1318c2aa98e2SPeter Wemm 
1319c2aa98e2SPeter Wemm 	if (tTd(33, 1))
1320c2aa98e2SPeter Wemm 	{
13213299c2f1SGregory Neil Shapiro 		dprintf("crackaddr=>`");
1322c2aa98e2SPeter Wemm 		xputs(buf);
13233299c2f1SGregory Neil Shapiro 		dprintf("'\n");
1324c2aa98e2SPeter Wemm 	}
1325c2aa98e2SPeter Wemm 
13263299c2f1SGregory Neil Shapiro 	return buf;
1327c2aa98e2SPeter Wemm }
1328c2aa98e2SPeter Wemm /*
1329c2aa98e2SPeter Wemm **  PUTHEADER -- put the header part of a message from the in-core copy
1330c2aa98e2SPeter Wemm **
1331c2aa98e2SPeter Wemm **	Parameters:
1332c2aa98e2SPeter Wemm **		mci -- the connection information.
13333299c2f1SGregory Neil Shapiro **		hdr -- the header to put.
1334c2aa98e2SPeter Wemm **		e -- envelope to use.
1335e01d6f61SPeter Wemm **		flags -- MIME conversion flags.
1336c2aa98e2SPeter Wemm **
1337c2aa98e2SPeter Wemm **	Returns:
1338c2aa98e2SPeter Wemm **		none.
1339c2aa98e2SPeter Wemm **
1340c2aa98e2SPeter Wemm **	Side Effects:
1341c2aa98e2SPeter Wemm **		none.
1342c2aa98e2SPeter Wemm */
1343c2aa98e2SPeter Wemm 
1344c2aa98e2SPeter Wemm /*
1345c2aa98e2SPeter Wemm  * Macro for fast max (not available in e.g. DG/UX, 386/ix).
1346c2aa98e2SPeter Wemm  */
1347c2aa98e2SPeter Wemm #ifndef MAX
1348c2aa98e2SPeter Wemm # define MAX(a,b) (((a)>(b))?(a):(b))
13493299c2f1SGregory Neil Shapiro #endif /* ! MAX */
1350c2aa98e2SPeter Wemm 
1351c2aa98e2SPeter Wemm void
1352e01d6f61SPeter Wemm putheader(mci, hdr, e, flags)
1353c2aa98e2SPeter Wemm 	register MCI *mci;
1354c2aa98e2SPeter Wemm 	HDR *hdr;
1355c2aa98e2SPeter Wemm 	register ENVELOPE *e;
1356e01d6f61SPeter Wemm 	int flags;
1357c2aa98e2SPeter Wemm {
1358c2aa98e2SPeter Wemm 	register HDR *h;
1359c2aa98e2SPeter Wemm 	char buf[MAX(MAXLINE,BUFSIZ)];
1360c2aa98e2SPeter Wemm 	char obuf[MAXLINE];
1361c2aa98e2SPeter Wemm 
1362c2aa98e2SPeter Wemm 	if (tTd(34, 1))
13633299c2f1SGregory Neil Shapiro 		dprintf("--- putheader, mailer = %s ---\n",
1364c2aa98e2SPeter Wemm 			mci->mci_mailer->m_name);
1365c2aa98e2SPeter Wemm 
1366c2aa98e2SPeter Wemm 	/*
1367c2aa98e2SPeter Wemm 	**  If we're in MIME mode, we're not really in the header of the
1368c2aa98e2SPeter Wemm 	**  message, just the header of one of the parts of the body of
1369c2aa98e2SPeter Wemm 	**  the message.  Therefore MCIF_INHEADER should not be turned on.
1370c2aa98e2SPeter Wemm 	*/
1371c2aa98e2SPeter Wemm 
1372c2aa98e2SPeter Wemm 	if (!bitset(MCIF_INMIME, mci->mci_flags))
1373c2aa98e2SPeter Wemm 		mci->mci_flags |= MCIF_INHEADER;
1374c2aa98e2SPeter Wemm 
1375c2aa98e2SPeter Wemm 	for (h = hdr; h != NULL; h = h->h_link)
1376c2aa98e2SPeter Wemm 	{
1377c2aa98e2SPeter Wemm 		register char *p = h->h_value;
1378c2aa98e2SPeter Wemm 
1379c2aa98e2SPeter Wemm 		if (tTd(34, 11))
1380c2aa98e2SPeter Wemm 		{
13813299c2f1SGregory Neil Shapiro 			dprintf("  %s: ", h->h_field);
1382c2aa98e2SPeter Wemm 			xputs(p);
1383c2aa98e2SPeter Wemm 		}
1384c2aa98e2SPeter Wemm 
13853299c2f1SGregory Neil Shapiro 		/* Skip empty headers */
13863299c2f1SGregory Neil Shapiro 		if (h->h_value == NULL)
13873299c2f1SGregory Neil Shapiro 			continue;
13883299c2f1SGregory Neil Shapiro 
138976b7bf71SPeter Wemm 		/* heuristic shortening of MIME fields to avoid MUA overflows */
139076b7bf71SPeter Wemm 		if (MaxMimeFieldLength > 0 &&
139176b7bf71SPeter Wemm 		    wordinclass(h->h_field,
139276b7bf71SPeter Wemm 				macid("{checkMIMEFieldHeaders}", NULL)))
139376b7bf71SPeter Wemm 		{
1394c46d91b7SGregory Neil Shapiro 			size_t len;
1395c46d91b7SGregory Neil Shapiro 
1396c46d91b7SGregory Neil Shapiro 			len = fix_mime_header(h->h_value);
1397c46d91b7SGregory Neil Shapiro 			if (len > 0)
139876b7bf71SPeter Wemm 			{
139976b7bf71SPeter Wemm 				sm_syslog(LOG_ALERT, e->e_id,
1400c46d91b7SGregory Neil Shapiro 					  "Truncated MIME %s header due to field size (length = %ld) (possible attack)",
1401c46d91b7SGregory Neil Shapiro 					  h->h_field, (unsigned long) len);
140276b7bf71SPeter Wemm 				if (tTd(34, 11))
1403c46d91b7SGregory Neil Shapiro 					dprintf("  truncated MIME %s header due to field size  (length = %ld) (possible attack)\n",
1404c46d91b7SGregory Neil Shapiro 						h->h_field,
1405c46d91b7SGregory Neil Shapiro 						(unsigned long) len);
140676b7bf71SPeter Wemm 			}
140776b7bf71SPeter Wemm 		}
140876b7bf71SPeter Wemm 
140976b7bf71SPeter Wemm 		if (MaxMimeHeaderLength > 0 &&
141076b7bf71SPeter Wemm 		    wordinclass(h->h_field,
141176b7bf71SPeter Wemm 				macid("{checkMIMETextHeaders}", NULL)))
141276b7bf71SPeter Wemm 		{
1413c46d91b7SGregory Neil Shapiro 			size_t len;
1414c46d91b7SGregory Neil Shapiro 
1415c46d91b7SGregory Neil Shapiro 			len = strlen(h->h_value);
1416c46d91b7SGregory Neil Shapiro 			if (len > (size_t) MaxMimeHeaderLength)
141776b7bf71SPeter Wemm 			{
141876b7bf71SPeter Wemm 				h->h_value[MaxMimeHeaderLength - 1] = '\0';
141976b7bf71SPeter Wemm 				sm_syslog(LOG_ALERT, e->e_id,
1420c46d91b7SGregory Neil Shapiro 					  "Truncated long MIME %s header (length = %ld) (possible attack)",
1421c46d91b7SGregory Neil Shapiro 					  h->h_field, (unsigned long) len);
142276b7bf71SPeter Wemm 				if (tTd(34, 11))
1423c46d91b7SGregory Neil Shapiro 					dprintf("  truncated long MIME %s header (length = %ld) (possible attack)\n",
1424c46d91b7SGregory Neil Shapiro 						h->h_field,
1425c46d91b7SGregory Neil Shapiro 						(unsigned long) len);
142676b7bf71SPeter Wemm 			}
142776b7bf71SPeter Wemm 		}
142876b7bf71SPeter Wemm 
142976b7bf71SPeter Wemm 		if (MaxMimeHeaderLength > 0 &&
143076b7bf71SPeter Wemm 		    wordinclass(h->h_field,
143176b7bf71SPeter Wemm 				macid("{checkMIMEHeaders}", NULL)))
143276b7bf71SPeter Wemm 		{
1433c46d91b7SGregory Neil Shapiro 			size_t len;
1434c46d91b7SGregory Neil Shapiro 
1435c46d91b7SGregory Neil Shapiro 			len = strlen(h->h_value);
1436c46d91b7SGregory Neil Shapiro 			if (shorten_rfc822_string(h->h_value,
1437c46d91b7SGregory Neil Shapiro 						  MaxMimeHeaderLength))
143876b7bf71SPeter Wemm 			{
143976b7bf71SPeter Wemm 				sm_syslog(LOG_ALERT, e->e_id,
1440c46d91b7SGregory Neil Shapiro 					  "Truncated long MIME %s header (length = %ld) (possible attack)",
1441c46d91b7SGregory Neil Shapiro 					  h->h_field, (unsigned long) len);
144276b7bf71SPeter Wemm 				if (tTd(34, 11))
1443c46d91b7SGregory Neil Shapiro 					dprintf("  truncated long MIME %s header (length = %ld) (possible attack)\n",
1444c46d91b7SGregory Neil Shapiro 						h->h_field,
1445c46d91b7SGregory Neil Shapiro 						(unsigned long) len);
144676b7bf71SPeter Wemm 			}
144776b7bf71SPeter Wemm 		}
144876b7bf71SPeter Wemm 
1449e01d6f61SPeter Wemm 		/*
1450e01d6f61SPeter Wemm 		**  Suppress Content-Transfer-Encoding: if we are MIMEing
1451e01d6f61SPeter Wemm 		**  and we are potentially converting from 8 bit to 7 bit
1452e01d6f61SPeter Wemm 		**  MIME.  If converting, add a new CTE header in
1453e01d6f61SPeter Wemm 		**  mime8to7().
1454e01d6f61SPeter Wemm 		*/
1455c2aa98e2SPeter Wemm 		if (bitset(H_CTE, h->h_flags) &&
1456e01d6f61SPeter Wemm 		    bitset(MCIF_CVT8TO7|MCIF_CVT7TO8|MCIF_INMIME,
1457e01d6f61SPeter Wemm 			   mci->mci_flags) &&
1458e01d6f61SPeter Wemm 		    !bitset(M87F_NO8TO7, flags))
1459c2aa98e2SPeter Wemm 		{
1460c2aa98e2SPeter Wemm 			if (tTd(34, 11))
14613299c2f1SGregory Neil Shapiro 				dprintf(" (skipped (content-transfer-encoding))\n");
1462c2aa98e2SPeter Wemm 			continue;
1463c2aa98e2SPeter Wemm 		}
1464c2aa98e2SPeter Wemm 
1465c2aa98e2SPeter Wemm 		if (bitset(MCIF_INMIME, mci->mci_flags))
1466c2aa98e2SPeter Wemm 		{
1467c2aa98e2SPeter Wemm 			if (tTd(34, 11))
14683299c2f1SGregory Neil Shapiro 				dprintf("\n");
1469c2aa98e2SPeter Wemm 			put_vanilla_header(h, p, mci);
1470c2aa98e2SPeter Wemm 			continue;
1471c2aa98e2SPeter Wemm 		}
1472c2aa98e2SPeter Wemm 
1473c2aa98e2SPeter Wemm 		if (bitset(H_CHECK|H_ACHECK, h->h_flags) &&
14743299c2f1SGregory Neil Shapiro 		    !bitintersect(h->h_mflags, mci->mci_mailer->m_flags) &&
14753299c2f1SGregory Neil Shapiro 		    (h->h_macro == '\0' ||
1476c46d91b7SGregory Neil Shapiro 		     macvalue(bitidx(h->h_macro), e) == NULL))
1477c2aa98e2SPeter Wemm 		{
1478c2aa98e2SPeter Wemm 			if (tTd(34, 11))
14793299c2f1SGregory Neil Shapiro 				dprintf(" (skipped)\n");
1480c2aa98e2SPeter Wemm 			continue;
1481c2aa98e2SPeter Wemm 		}
1482c2aa98e2SPeter Wemm 
1483c2aa98e2SPeter Wemm 		/* handle Resent-... headers specially */
1484c2aa98e2SPeter Wemm 		if (bitset(H_RESENT, h->h_flags) && !bitset(EF_RESENT, e->e_flags))
1485c2aa98e2SPeter Wemm 		{
1486c2aa98e2SPeter Wemm 			if (tTd(34, 11))
14873299c2f1SGregory Neil Shapiro 				dprintf(" (skipped (resent))\n");
1488c2aa98e2SPeter Wemm 			continue;
1489c2aa98e2SPeter Wemm 		}
1490c2aa98e2SPeter Wemm 
1491c2aa98e2SPeter Wemm 		/* suppress return receipts if requested */
1492c2aa98e2SPeter Wemm 		if (bitset(H_RECEIPTTO, h->h_flags) &&
1493c2aa98e2SPeter Wemm 		    (RrtImpliesDsn || bitset(EF_NORECEIPT, e->e_flags)))
1494c2aa98e2SPeter Wemm 		{
1495c2aa98e2SPeter Wemm 			if (tTd(34, 11))
14963299c2f1SGregory Neil Shapiro 				dprintf(" (skipped (receipt))\n");
1497c2aa98e2SPeter Wemm 			continue;
1498c2aa98e2SPeter Wemm 		}
1499c2aa98e2SPeter Wemm 
1500c2aa98e2SPeter Wemm 		/* macro expand value if generated internally */
15013299c2f1SGregory Neil Shapiro 		if (bitset(H_DEFAULT, h->h_flags) ||
15023299c2f1SGregory Neil Shapiro 		    bitset(H_BINDLATE, h->h_flags))
1503c2aa98e2SPeter Wemm 		{
1504c2aa98e2SPeter Wemm 			expand(p, buf, sizeof buf, e);
1505c2aa98e2SPeter Wemm 			p = buf;
1506c2aa98e2SPeter Wemm 			if (*p == '\0')
1507c2aa98e2SPeter Wemm 			{
1508c2aa98e2SPeter Wemm 				if (tTd(34, 11))
15093299c2f1SGregory Neil Shapiro 					dprintf(" (skipped -- null value)\n");
1510c2aa98e2SPeter Wemm 				continue;
1511c2aa98e2SPeter Wemm 			}
1512c2aa98e2SPeter Wemm 		}
1513c2aa98e2SPeter Wemm 
1514c2aa98e2SPeter Wemm 		if (bitset(H_BCC, h->h_flags))
1515c2aa98e2SPeter Wemm 		{
1516c2aa98e2SPeter Wemm 			/* Bcc: field -- either truncate or delete */
1517c2aa98e2SPeter Wemm 			if (bitset(EF_DELETE_BCC, e->e_flags))
1518c2aa98e2SPeter Wemm 			{
1519c2aa98e2SPeter Wemm 				if (tTd(34, 11))
15203299c2f1SGregory Neil Shapiro 					dprintf(" (skipped -- bcc)\n");
1521c2aa98e2SPeter Wemm 			}
1522c2aa98e2SPeter Wemm 			else
1523c2aa98e2SPeter Wemm 			{
1524c2aa98e2SPeter Wemm 				/* no other recipient headers: truncate value */
1525c2aa98e2SPeter Wemm 				(void) snprintf(obuf, sizeof obuf, "%s:",
1526c2aa98e2SPeter Wemm 					h->h_field);
1527c2aa98e2SPeter Wemm 				putline(obuf, mci);
1528c2aa98e2SPeter Wemm 			}
1529c2aa98e2SPeter Wemm 			continue;
1530c2aa98e2SPeter Wemm 		}
1531c2aa98e2SPeter Wemm 
1532c2aa98e2SPeter Wemm 		if (tTd(34, 11))
15333299c2f1SGregory Neil Shapiro 			dprintf("\n");
1534c2aa98e2SPeter Wemm 
1535c2aa98e2SPeter Wemm 		if (bitset(H_FROM|H_RCPT, h->h_flags))
1536c2aa98e2SPeter Wemm 		{
1537c2aa98e2SPeter Wemm 			/* address field */
1538c2aa98e2SPeter Wemm 			bool oldstyle = bitset(EF_OLDSTYLE, e->e_flags);
1539c2aa98e2SPeter Wemm 
1540c2aa98e2SPeter Wemm 			if (bitset(H_FROM, h->h_flags))
1541c2aa98e2SPeter Wemm 				oldstyle = FALSE;
1542c2aa98e2SPeter Wemm 			commaize(h, p, oldstyle, mci, e);
1543c2aa98e2SPeter Wemm 		}
1544c2aa98e2SPeter Wemm 		else
1545c2aa98e2SPeter Wemm 		{
1546c2aa98e2SPeter Wemm 			put_vanilla_header(h, p, mci);
1547c2aa98e2SPeter Wemm 		}
1548c2aa98e2SPeter Wemm 	}
1549c2aa98e2SPeter Wemm 
1550c2aa98e2SPeter Wemm 	/*
1551c2aa98e2SPeter Wemm 	**  If we are converting this to a MIME message, add the
15523299c2f1SGregory Neil Shapiro 	**  MIME headers (but not in MIME mode!).
1553c2aa98e2SPeter Wemm 	*/
1554c2aa98e2SPeter Wemm 
1555c2aa98e2SPeter Wemm #if MIME8TO7
1556c2aa98e2SPeter Wemm 	if (bitset(MM_MIME8BIT, MimeMode) &&
1557c2aa98e2SPeter Wemm 	    bitset(EF_HAS8BIT, e->e_flags) &&
1558c2aa98e2SPeter Wemm 	    !bitset(EF_DONT_MIME, e->e_flags) &&
1559c2aa98e2SPeter Wemm 	    !bitnset(M_8BITS, mci->mci_mailer->m_flags) &&
15603299c2f1SGregory Neil Shapiro 	    !bitset(MCIF_CVT8TO7|MCIF_CVT7TO8|MCIF_INMIME, mci->mci_flags) &&
15613299c2f1SGregory Neil Shapiro 	    hvalue("MIME-Version", e->e_header) == NULL)
1562c2aa98e2SPeter Wemm 	{
1563c2aa98e2SPeter Wemm 		putline("MIME-Version: 1.0", mci);
1564c2aa98e2SPeter Wemm 		if (hvalue("Content-Type", e->e_header) == NULL)
1565c2aa98e2SPeter Wemm 		{
1566c2aa98e2SPeter Wemm 			snprintf(obuf, sizeof obuf,
1567c2aa98e2SPeter Wemm 				"Content-Type: text/plain; charset=%s",
1568c2aa98e2SPeter Wemm 				defcharset(e));
1569c2aa98e2SPeter Wemm 			putline(obuf, mci);
1570c2aa98e2SPeter Wemm 		}
1571c2aa98e2SPeter Wemm 		if (hvalue("Content-Transfer-Encoding", e->e_header) == NULL)
1572c2aa98e2SPeter Wemm 			putline("Content-Transfer-Encoding: 8bit", mci);
1573c2aa98e2SPeter Wemm 	}
15743299c2f1SGregory Neil Shapiro #endif /* MIME8TO7 */
1575c2aa98e2SPeter Wemm }
1576c2aa98e2SPeter Wemm /*
1577c2aa98e2SPeter Wemm **  PUT_VANILLA_HEADER -- output a fairly ordinary header
1578c2aa98e2SPeter Wemm **
1579c2aa98e2SPeter Wemm **	Parameters:
1580c2aa98e2SPeter Wemm **		h -- the structure describing this header
1581c2aa98e2SPeter Wemm **		v -- the value of this header
1582c2aa98e2SPeter Wemm **		mci -- the connection info for output
1583c2aa98e2SPeter Wemm **
1584c2aa98e2SPeter Wemm **	Returns:
1585c2aa98e2SPeter Wemm **		none.
1586c2aa98e2SPeter Wemm */
1587c2aa98e2SPeter Wemm 
15883299c2f1SGregory Neil Shapiro static void
1589c2aa98e2SPeter Wemm put_vanilla_header(h, v, mci)
1590c2aa98e2SPeter Wemm 	HDR *h;
1591c2aa98e2SPeter Wemm 	char *v;
1592c2aa98e2SPeter Wemm 	MCI *mci;
1593c2aa98e2SPeter Wemm {
1594c2aa98e2SPeter Wemm 	register char *nlp;
1595c2aa98e2SPeter Wemm 	register char *obp;
1596c2aa98e2SPeter Wemm 	int putflags;
1597c2aa98e2SPeter Wemm 	char obuf[MAXLINE];
1598c2aa98e2SPeter Wemm 
1599c2aa98e2SPeter Wemm 	putflags = PXLF_HEADER;
1600c2aa98e2SPeter Wemm 	if (bitnset(M_7BITHDRS, mci->mci_mailer->m_flags))
1601c2aa98e2SPeter Wemm 		putflags |= PXLF_STRIP8BIT;
1602c2aa98e2SPeter Wemm 	(void) snprintf(obuf, sizeof obuf, "%.200s: ", h->h_field);
1603c2aa98e2SPeter Wemm 	obp = obuf + strlen(obuf);
1604c2aa98e2SPeter Wemm 	while ((nlp = strchr(v, '\n')) != NULL)
1605c2aa98e2SPeter Wemm 	{
1606c2aa98e2SPeter Wemm 		int l;
1607c2aa98e2SPeter Wemm 
1608c2aa98e2SPeter Wemm 		l = nlp - v;
16093299c2f1SGregory Neil Shapiro 		if (SPACELEFT(obuf, obp) - 1 < (size_t)l)
1610c2aa98e2SPeter Wemm 			l = SPACELEFT(obuf, obp) - 1;
1611c2aa98e2SPeter Wemm 
1612c2aa98e2SPeter Wemm 		snprintf(obp, SPACELEFT(obuf, obp), "%.*s", l, v);
1613c2aa98e2SPeter Wemm 		putxline(obuf, strlen(obuf), mci, putflags);
1614c2aa98e2SPeter Wemm 		v += l + 1;
1615c2aa98e2SPeter Wemm 		obp = obuf;
1616c2aa98e2SPeter Wemm 		if (*v != ' ' && *v != '\t')
1617c2aa98e2SPeter Wemm 			*obp++ = ' ';
1618c2aa98e2SPeter Wemm 	}
1619c2aa98e2SPeter Wemm 	snprintf(obp, SPACELEFT(obuf, obp), "%.*s",
16203299c2f1SGregory Neil Shapiro 		(int) sizeof obuf - (obp - obuf) - 1, v);
1621c2aa98e2SPeter Wemm 	putxline(obuf, strlen(obuf), mci, putflags);
1622c2aa98e2SPeter Wemm }
1623c2aa98e2SPeter Wemm /*
1624c2aa98e2SPeter Wemm **  COMMAIZE -- output a header field, making a comma-translated list.
1625c2aa98e2SPeter Wemm **
1626c2aa98e2SPeter Wemm **	Parameters:
1627c2aa98e2SPeter Wemm **		h -- the header field to output.
1628c2aa98e2SPeter Wemm **		p -- the value to put in it.
1629c2aa98e2SPeter Wemm **		oldstyle -- TRUE if this is an old style header.
1630c2aa98e2SPeter Wemm **		mci -- the connection information.
1631c2aa98e2SPeter Wemm **		e -- the envelope containing the message.
1632c2aa98e2SPeter Wemm **
1633c2aa98e2SPeter Wemm **	Returns:
1634c2aa98e2SPeter Wemm **		none.
1635c2aa98e2SPeter Wemm **
1636c2aa98e2SPeter Wemm **	Side Effects:
1637c2aa98e2SPeter Wemm **		outputs "p" to file "fp".
1638c2aa98e2SPeter Wemm */
1639c2aa98e2SPeter Wemm 
1640c2aa98e2SPeter Wemm void
1641c2aa98e2SPeter Wemm commaize(h, p, oldstyle, mci, e)
1642c2aa98e2SPeter Wemm 	register HDR *h;
1643c2aa98e2SPeter Wemm 	register char *p;
1644c2aa98e2SPeter Wemm 	bool oldstyle;
1645c2aa98e2SPeter Wemm 	register MCI *mci;
1646c2aa98e2SPeter Wemm 	register ENVELOPE *e;
1647c2aa98e2SPeter Wemm {
1648c2aa98e2SPeter Wemm 	register char *obp;
1649c2aa98e2SPeter Wemm 	int opos;
1650c2aa98e2SPeter Wemm 	int omax;
1651c2aa98e2SPeter Wemm 	bool firstone = TRUE;
1652c2aa98e2SPeter Wemm 	int putflags = PXLF_HEADER;
1653c2aa98e2SPeter Wemm 	char obuf[MAXLINE + 3];
1654c2aa98e2SPeter Wemm 
1655c2aa98e2SPeter Wemm 	/*
1656c2aa98e2SPeter Wemm 	**  Output the address list translated by the
1657c2aa98e2SPeter Wemm 	**  mailer and with commas.
1658c2aa98e2SPeter Wemm 	*/
1659c2aa98e2SPeter Wemm 
1660c2aa98e2SPeter Wemm 	if (tTd(14, 2))
16613299c2f1SGregory Neil Shapiro 		dprintf("commaize(%s: %s)\n", h->h_field, p);
1662c2aa98e2SPeter Wemm 
1663c2aa98e2SPeter Wemm 	if (bitnset(M_7BITHDRS, mci->mci_mailer->m_flags))
1664c2aa98e2SPeter Wemm 		putflags |= PXLF_STRIP8BIT;
1665c2aa98e2SPeter Wemm 
1666c2aa98e2SPeter Wemm 	obp = obuf;
1667c2aa98e2SPeter Wemm 	(void) snprintf(obp, SPACELEFT(obuf, obp), "%.200s: ", h->h_field);
1668c2aa98e2SPeter Wemm 	opos = strlen(h->h_field) + 2;
1669c2aa98e2SPeter Wemm 	if (opos > 202)
1670c2aa98e2SPeter Wemm 		opos = 202;
1671c2aa98e2SPeter Wemm 	obp += opos;
1672c2aa98e2SPeter Wemm 	omax = mci->mci_mailer->m_linelimit - 2;
1673c2aa98e2SPeter Wemm 	if (omax < 0 || omax > 78)
1674c2aa98e2SPeter Wemm 		omax = 78;
1675c2aa98e2SPeter Wemm 
1676c2aa98e2SPeter Wemm 	/*
1677c2aa98e2SPeter Wemm 	**  Run through the list of values.
1678c2aa98e2SPeter Wemm 	*/
1679c2aa98e2SPeter Wemm 
1680c2aa98e2SPeter Wemm 	while (*p != '\0')
1681c2aa98e2SPeter Wemm 	{
1682c2aa98e2SPeter Wemm 		register char *name;
1683c2aa98e2SPeter Wemm 		register int c;
1684c2aa98e2SPeter Wemm 		char savechar;
1685c2aa98e2SPeter Wemm 		int flags;
16863299c2f1SGregory Neil Shapiro 		auto int status;
1687c2aa98e2SPeter Wemm 
1688c2aa98e2SPeter Wemm 		/*
1689c2aa98e2SPeter Wemm 		**  Find the end of the name.  New style names
1690c2aa98e2SPeter Wemm 		**  end with a comma, old style names end with
1691c2aa98e2SPeter Wemm 		**  a space character.  However, spaces do not
1692c2aa98e2SPeter Wemm 		**  necessarily delimit an old-style name -- at
1693c2aa98e2SPeter Wemm 		**  signs mean keep going.
1694c2aa98e2SPeter Wemm 		*/
1695c2aa98e2SPeter Wemm 
1696c2aa98e2SPeter Wemm 		/* find end of name */
1697c2aa98e2SPeter Wemm 		while ((isascii(*p) && isspace(*p)) || *p == ',')
1698c2aa98e2SPeter Wemm 			p++;
1699c2aa98e2SPeter Wemm 		name = p;
1700c2aa98e2SPeter Wemm 		for (;;)
1701c2aa98e2SPeter Wemm 		{
1702c2aa98e2SPeter Wemm 			auto char *oldp;
1703c2aa98e2SPeter Wemm 			char pvpbuf[PSBUFSIZE];
1704c2aa98e2SPeter Wemm 
1705c2aa98e2SPeter Wemm 			(void) prescan(p, oldstyle ? ' ' : ',', pvpbuf,
1706c2aa98e2SPeter Wemm 				       sizeof pvpbuf, &oldp, NULL);
1707c2aa98e2SPeter Wemm 			p = oldp;
1708c2aa98e2SPeter Wemm 
1709c2aa98e2SPeter Wemm 			/* look to see if we have an at sign */
1710c2aa98e2SPeter Wemm 			while (*p != '\0' && isascii(*p) && isspace(*p))
1711c2aa98e2SPeter Wemm 				p++;
1712c2aa98e2SPeter Wemm 
1713c2aa98e2SPeter Wemm 			if (*p != '@')
1714c2aa98e2SPeter Wemm 			{
1715c2aa98e2SPeter Wemm 				p = oldp;
1716c2aa98e2SPeter Wemm 				break;
1717c2aa98e2SPeter Wemm 			}
1718c2aa98e2SPeter Wemm 			p += *p == '@' ? 1 : 2;
1719c2aa98e2SPeter Wemm 			while (*p != '\0' && isascii(*p) && isspace(*p))
1720c2aa98e2SPeter Wemm 				p++;
1721c2aa98e2SPeter Wemm 		}
1722c2aa98e2SPeter Wemm 		/* at the end of one complete name */
1723c2aa98e2SPeter Wemm 
1724c2aa98e2SPeter Wemm 		/* strip off trailing white space */
1725c2aa98e2SPeter Wemm 		while (p >= name &&
1726c2aa98e2SPeter Wemm 		       ((isascii(*p) && isspace(*p)) || *p == ',' || *p == '\0'))
1727c2aa98e2SPeter Wemm 			p--;
1728c2aa98e2SPeter Wemm 		if (++p == name)
1729c2aa98e2SPeter Wemm 			continue;
1730c2aa98e2SPeter Wemm 		savechar = *p;
1731c2aa98e2SPeter Wemm 		*p = '\0';
1732c2aa98e2SPeter Wemm 
1733c2aa98e2SPeter Wemm 		/* translate the name to be relative */
1734c2aa98e2SPeter Wemm 		flags = RF_HEADERADDR|RF_ADDDOMAIN;
1735c2aa98e2SPeter Wemm 		if (bitset(H_FROM, h->h_flags))
1736c2aa98e2SPeter Wemm 			flags |= RF_SENDERADDR;
1737c2aa98e2SPeter Wemm #if USERDB
1738c2aa98e2SPeter Wemm 		else if (e->e_from.q_mailer != NULL &&
1739c2aa98e2SPeter Wemm 			 bitnset(M_UDBRECIPIENT, e->e_from.q_mailer->m_flags))
1740c2aa98e2SPeter Wemm 		{
1741c2aa98e2SPeter Wemm 			char *q;
1742c2aa98e2SPeter Wemm 
1743c2aa98e2SPeter Wemm 			q = udbsender(name);
1744c2aa98e2SPeter Wemm 			if (q != NULL)
1745c2aa98e2SPeter Wemm 				name = q;
1746c2aa98e2SPeter Wemm 		}
17473299c2f1SGregory Neil Shapiro #endif /* USERDB */
17483299c2f1SGregory Neil Shapiro 		status = EX_OK;
17493299c2f1SGregory Neil Shapiro 		name = remotename(name, mci->mci_mailer, flags, &status, e);
1750c2aa98e2SPeter Wemm 		if (*name == '\0')
1751c2aa98e2SPeter Wemm 		{
1752c2aa98e2SPeter Wemm 			*p = savechar;
1753c2aa98e2SPeter Wemm 			continue;
1754c2aa98e2SPeter Wemm 		}
1755c2aa98e2SPeter Wemm 		name = denlstring(name, FALSE, TRUE);
1756c2aa98e2SPeter Wemm 
17573299c2f1SGregory Neil Shapiro 		/*
17583299c2f1SGregory Neil Shapiro 		**  record data progress so DNS timeouts
17593299c2f1SGregory Neil Shapiro 		**  don't cause DATA timeouts
17603299c2f1SGregory Neil Shapiro 		*/
17613299c2f1SGregory Neil Shapiro 
17623299c2f1SGregory Neil Shapiro 		DataProgress = TRUE;
17633299c2f1SGregory Neil Shapiro 
1764c2aa98e2SPeter Wemm 		/* output the name with nice formatting */
1765c2aa98e2SPeter Wemm 		opos += strlen(name);
1766c2aa98e2SPeter Wemm 		if (!firstone)
1767c2aa98e2SPeter Wemm 			opos += 2;
1768c2aa98e2SPeter Wemm 		if (opos > omax && !firstone)
1769c2aa98e2SPeter Wemm 		{
1770c2aa98e2SPeter Wemm 			snprintf(obp, SPACELEFT(obuf, obp), ",\n");
1771c2aa98e2SPeter Wemm 			putxline(obuf, strlen(obuf), mci, putflags);
1772c2aa98e2SPeter Wemm 			obp = obuf;
17733299c2f1SGregory Neil Shapiro 			(void) strlcpy(obp, "        ", sizeof obp);
1774c2aa98e2SPeter Wemm 			opos = strlen(obp);
1775c2aa98e2SPeter Wemm 			obp += opos;
1776c2aa98e2SPeter Wemm 			opos += strlen(name);
1777c2aa98e2SPeter Wemm 		}
1778c2aa98e2SPeter Wemm 		else if (!firstone)
1779c2aa98e2SPeter Wemm 		{
1780c2aa98e2SPeter Wemm 			snprintf(obp, SPACELEFT(obuf, obp), ", ");
1781c2aa98e2SPeter Wemm 			obp += 2;
1782c2aa98e2SPeter Wemm 		}
1783c2aa98e2SPeter Wemm 
1784c2aa98e2SPeter Wemm 		while ((c = *name++) != '\0' && obp < &obuf[MAXLINE])
1785c2aa98e2SPeter Wemm 			*obp++ = c;
1786c2aa98e2SPeter Wemm 		firstone = FALSE;
1787c2aa98e2SPeter Wemm 		*p = savechar;
1788c2aa98e2SPeter Wemm 	}
1789c2aa98e2SPeter Wemm 	*obp = '\0';
1790c2aa98e2SPeter Wemm 	putxline(obuf, strlen(obuf), mci, putflags);
1791c2aa98e2SPeter Wemm }
1792c2aa98e2SPeter Wemm /*
1793c2aa98e2SPeter Wemm **  COPYHEADER -- copy header list
1794c2aa98e2SPeter Wemm **
1795c2aa98e2SPeter Wemm **	This routine is the equivalent of newstr for header lists
1796c2aa98e2SPeter Wemm **
1797c2aa98e2SPeter Wemm **	Parameters:
1798c2aa98e2SPeter Wemm **		header -- list of header structures to copy.
1799c2aa98e2SPeter Wemm **
1800c2aa98e2SPeter Wemm **	Returns:
1801c2aa98e2SPeter Wemm **		a copy of 'header'.
1802c2aa98e2SPeter Wemm **
1803c2aa98e2SPeter Wemm **	Side Effects:
1804c2aa98e2SPeter Wemm **		none.
1805c2aa98e2SPeter Wemm */
1806c2aa98e2SPeter Wemm 
1807c2aa98e2SPeter Wemm HDR *
1808c2aa98e2SPeter Wemm copyheader(header)
1809c2aa98e2SPeter Wemm 	register HDR *header;
1810c2aa98e2SPeter Wemm {
1811c2aa98e2SPeter Wemm 	register HDR *newhdr;
1812c2aa98e2SPeter Wemm 	HDR *ret;
1813c2aa98e2SPeter Wemm 	register HDR **tail = &ret;
1814c2aa98e2SPeter Wemm 
1815c2aa98e2SPeter Wemm 	while (header != NULL)
1816c2aa98e2SPeter Wemm 	{
18173299c2f1SGregory Neil Shapiro 		newhdr = (HDR *) xalloc(sizeof *newhdr);
1818c2aa98e2SPeter Wemm 		STRUCTCOPY(*header, *newhdr);
1819c2aa98e2SPeter Wemm 		*tail = newhdr;
1820c2aa98e2SPeter Wemm 		tail = &newhdr->h_link;
1821c2aa98e2SPeter Wemm 		header = header->h_link;
1822c2aa98e2SPeter Wemm 	}
1823c2aa98e2SPeter Wemm 	*tail = NULL;
1824c2aa98e2SPeter Wemm 
1825c2aa98e2SPeter Wemm 	return ret;
1826c2aa98e2SPeter Wemm }
182776b7bf71SPeter Wemm /*
182876b7bf71SPeter Wemm **  FIX_MIME_HEADER -- possibly truncate/rebalance parameters in a MIME header
182976b7bf71SPeter Wemm **
183076b7bf71SPeter Wemm **	Run through all of the parameters of a MIME header and
183176b7bf71SPeter Wemm **	possibly truncate and rebalance the parameter according
183276b7bf71SPeter Wemm **	to MaxMimeFieldLength.
183376b7bf71SPeter Wemm **
183476b7bf71SPeter Wemm **	Parameters:
183576b7bf71SPeter Wemm **		string -- the full header
183676b7bf71SPeter Wemm **
183776b7bf71SPeter Wemm **	Returns:
1838c46d91b7SGregory Neil Shapiro **		length of last offending field, 0 if all ok.
183976b7bf71SPeter Wemm **
184076b7bf71SPeter Wemm **	Side Effects:
184176b7bf71SPeter Wemm **		string modified in place
184276b7bf71SPeter Wemm */
184376b7bf71SPeter Wemm 
1844c46d91b7SGregory Neil Shapiro static size_t
184576b7bf71SPeter Wemm fix_mime_header(string)
184676b7bf71SPeter Wemm 	char *string;
184776b7bf71SPeter Wemm {
184876b7bf71SPeter Wemm 	char *begin = string;
184976b7bf71SPeter Wemm 	char *end;
1850c46d91b7SGregory Neil Shapiro 	size_t len = 0;
1851c46d91b7SGregory Neil Shapiro 	size_t retlen = 0;
185276b7bf71SPeter Wemm 
185376b7bf71SPeter Wemm 	if (string == NULL || *string == '\0')
1854c46d91b7SGregory Neil Shapiro 		return 0;
185576b7bf71SPeter Wemm 
185676b7bf71SPeter Wemm 	/* Split on each ';' */
185776b7bf71SPeter Wemm 	while ((end = find_character(begin, ';')) != NULL)
185876b7bf71SPeter Wemm 	{
185976b7bf71SPeter Wemm 		char save = *end;
186076b7bf71SPeter Wemm 		char *bp;
186176b7bf71SPeter Wemm 
186276b7bf71SPeter Wemm 		*end = '\0';
186376b7bf71SPeter Wemm 
1864c46d91b7SGregory Neil Shapiro 		len = strlen(begin);
1865c46d91b7SGregory Neil Shapiro 
186676b7bf71SPeter Wemm 		/* Shorten individual parameter */
186776b7bf71SPeter Wemm 		if (shorten_rfc822_string(begin, MaxMimeFieldLength))
1868c46d91b7SGregory Neil Shapiro 			retlen = len;
186976b7bf71SPeter Wemm 
187076b7bf71SPeter Wemm 		/* Collapse the possibly shortened string with rest */
187176b7bf71SPeter Wemm 		bp = begin + strlen(begin);
187276b7bf71SPeter Wemm 		if (bp != end)
187376b7bf71SPeter Wemm 		{
187476b7bf71SPeter Wemm 			char *ep = end;
187576b7bf71SPeter Wemm 
187676b7bf71SPeter Wemm 			*end = save;
187776b7bf71SPeter Wemm 			end = bp;
187876b7bf71SPeter Wemm 
187976b7bf71SPeter Wemm 			/* copy character by character due to overlap */
188076b7bf71SPeter Wemm 			while (*ep != '\0')
188176b7bf71SPeter Wemm 				*bp++ = *ep++;
188276b7bf71SPeter Wemm 			*bp = '\0';
188376b7bf71SPeter Wemm 		}
188476b7bf71SPeter Wemm 		else
188576b7bf71SPeter Wemm 			*end = save;
188676b7bf71SPeter Wemm 		if (*end == '\0')
188776b7bf71SPeter Wemm 			break;
188876b7bf71SPeter Wemm 
188976b7bf71SPeter Wemm 		/* Move past ';' */
189076b7bf71SPeter Wemm 		begin = end + 1;
189176b7bf71SPeter Wemm 	}
1892c46d91b7SGregory Neil Shapiro 	return retlen;
189376b7bf71SPeter Wemm }
1894