xref: /freebsd/contrib/sendmail/src/headers.c (revision 3299c2f12320115fa2829485837e0c3b543c62ba)
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
153299c2f1SGregory Neil Shapiro static char id[] = "@(#)$Id: headers.c,v 8.203.4.6 2000/07/19 02:53:32 ca Exp $";
163299c2f1SGregory Neil Shapiro #endif /* ! lint */
17c2aa98e2SPeter Wemm 
183299c2f1SGregory Neil Shapiro /* $FreeBSD$ */
193299c2f1SGregory Neil Shapiro 
203299c2f1SGregory Neil Shapiro #include <sendmail.h>
213299c2f1SGregory Neil Shapiro 
223299c2f1SGregory Neil Shapiro static bool	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.
563299c2f1SGregory Neil Shapiro **		pflag -- flags:
573299c2f1SGregory Neil Shapiro **			CHHDR_DEF: this is a default value.
583299c2f1SGregory Neil Shapiro **			CHHDR_CHECK: call rulesets.
59c2aa98e2SPeter Wemm **		hdrp -- a pointer to the place to save the header.
60c2aa98e2SPeter Wemm **		e -- the envelope including this header.
61c2aa98e2SPeter Wemm **
62c2aa98e2SPeter Wemm **	Returns:
63c2aa98e2SPeter Wemm **		flags for this header.
64c2aa98e2SPeter Wemm **
65c2aa98e2SPeter Wemm **	Side Effects:
66c2aa98e2SPeter Wemm **		The header is saved on the header list.
67c2aa98e2SPeter Wemm **		Contents of 'line' are destroyed.
68c2aa98e2SPeter Wemm */
69c2aa98e2SPeter Wemm 
703299c2f1SGregory Neil Shapiro static struct hdrinfo	NormalHeader =	{ NULL, 0, NULL };
71c2aa98e2SPeter Wemm 
723299c2f1SGregory Neil Shapiro u_long
733299c2f1SGregory Neil Shapiro chompheader(line, pflag, hdrp, e)
74c2aa98e2SPeter Wemm 	char *line;
753299c2f1SGregory Neil Shapiro 	int pflag;
76c2aa98e2SPeter Wemm 	HDR **hdrp;
77c2aa98e2SPeter Wemm 	register ENVELOPE *e;
78c2aa98e2SPeter Wemm {
793299c2f1SGregory Neil Shapiro 	u_char mid = '\0';
80c2aa98e2SPeter Wemm 	register char *p;
81c2aa98e2SPeter Wemm 	register HDR *h;
82c2aa98e2SPeter Wemm 	HDR **hp;
83c2aa98e2SPeter Wemm 	char *fname;
84c2aa98e2SPeter Wemm 	char *fvalue;
85c2aa98e2SPeter Wemm 	bool cond = FALSE;
863299c2f1SGregory Neil Shapiro 	bool dropfrom;
87c2aa98e2SPeter Wemm 	bool headeronly;
88c2aa98e2SPeter Wemm 	STAB *s;
89c2aa98e2SPeter Wemm 	struct hdrinfo *hi;
90e01d6f61SPeter Wemm 	bool nullheader = FALSE;
913299c2f1SGregory Neil Shapiro 	BITMAP256 mopts;
92c2aa98e2SPeter Wemm 
93c2aa98e2SPeter Wemm 	if (tTd(31, 6))
94c2aa98e2SPeter Wemm 	{
953299c2f1SGregory Neil Shapiro 		dprintf("chompheader: ");
96c2aa98e2SPeter Wemm 		xputs(line);
973299c2f1SGregory Neil Shapiro 		dprintf("\n");
98c2aa98e2SPeter Wemm 	}
99c2aa98e2SPeter Wemm 
100c2aa98e2SPeter Wemm 	headeronly = hdrp != NULL;
101c2aa98e2SPeter Wemm 	if (!headeronly)
102c2aa98e2SPeter Wemm 		hdrp = &e->e_header;
103c2aa98e2SPeter Wemm 
104c2aa98e2SPeter Wemm 	/* strip off options */
105c2aa98e2SPeter Wemm 	clrbitmap(mopts);
106c2aa98e2SPeter Wemm 	p = line;
1073299c2f1SGregory Neil Shapiro 	if (!bitset(pflag, CHHDR_USER) && *p == '?')
108c2aa98e2SPeter Wemm 	{
1093299c2f1SGregory Neil Shapiro 		int c;
1103299c2f1SGregory Neil Shapiro 		register char *q;
111c2aa98e2SPeter Wemm 
1123299c2f1SGregory Neil Shapiro 		q = strchr(++p, '?');
1133299c2f1SGregory Neil Shapiro 		if (q == NULL)
1143299c2f1SGregory Neil Shapiro 			goto hse;
1153299c2f1SGregory Neil Shapiro 
1163299c2f1SGregory Neil Shapiro 		*q = '\0';
1173299c2f1SGregory Neil Shapiro 		c = *p & 0377;
1183299c2f1SGregory Neil Shapiro 
1193299c2f1SGregory Neil Shapiro 		/* possibly macro conditional */
1203299c2f1SGregory Neil Shapiro 		if (c == MACROEXPAND)
121c2aa98e2SPeter Wemm 		{
1223299c2f1SGregory Neil Shapiro 			/* catch ?$? */
1233299c2f1SGregory Neil Shapiro 			if (*++p == '\0')
1243299c2f1SGregory Neil Shapiro 			{
1253299c2f1SGregory Neil Shapiro 				*q = '?';
1263299c2f1SGregory Neil Shapiro 				goto hse;
1273299c2f1SGregory Neil Shapiro 			}
1283299c2f1SGregory Neil Shapiro 
1293299c2f1SGregory Neil Shapiro 			mid = (u_char) *p++;
1303299c2f1SGregory Neil Shapiro 
1313299c2f1SGregory Neil Shapiro 			/* catch ?$abc? */
1323299c2f1SGregory Neil Shapiro 			if (*p != '\0')
1333299c2f1SGregory Neil Shapiro 			{
1343299c2f1SGregory Neil Shapiro 				*q = '?';
1353299c2f1SGregory Neil Shapiro 				goto hse;
1363299c2f1SGregory Neil Shapiro 			}
1373299c2f1SGregory Neil Shapiro 		}
1383299c2f1SGregory Neil Shapiro 		else if (*p == '$')
1393299c2f1SGregory Neil Shapiro 		{
1403299c2f1SGregory Neil Shapiro 			/* catch ?$? */
1413299c2f1SGregory Neil Shapiro 			if (*++p == '\0')
1423299c2f1SGregory Neil Shapiro 			{
1433299c2f1SGregory Neil Shapiro 				*q = '?';
1443299c2f1SGregory Neil Shapiro 				goto hse;
1453299c2f1SGregory Neil Shapiro 			}
1463299c2f1SGregory Neil Shapiro 
1473299c2f1SGregory Neil Shapiro 			mid = (u_char)macid(p, NULL);
1483299c2f1SGregory Neil Shapiro 			if (bitset(0200, mid))
1493299c2f1SGregory Neil Shapiro 				p += strlen(macname(mid)) + 2;
1503299c2f1SGregory Neil Shapiro 			else
1513299c2f1SGregory Neil Shapiro 				p++;
1523299c2f1SGregory Neil Shapiro 
1533299c2f1SGregory Neil Shapiro 			/* catch ?$abc? */
1543299c2f1SGregory Neil Shapiro 			if (*p != '\0')
1553299c2f1SGregory Neil Shapiro 			{
1563299c2f1SGregory Neil Shapiro 				*q = '?';
1573299c2f1SGregory Neil Shapiro 				goto hse;
1583299c2f1SGregory Neil Shapiro 			}
1593299c2f1SGregory Neil Shapiro 
160c2aa98e2SPeter Wemm 		}
161c2aa98e2SPeter Wemm 		else
1623299c2f1SGregory Neil Shapiro 		{
1633299c2f1SGregory Neil Shapiro 			while (*p != '\0')
1643299c2f1SGregory Neil Shapiro 			{
1653299c2f1SGregory Neil Shapiro 				if (!isascii(*p))
1663299c2f1SGregory Neil Shapiro 				{
1673299c2f1SGregory Neil Shapiro 					*q = '?';
1683299c2f1SGregory Neil Shapiro 					goto hse;
1693299c2f1SGregory Neil Shapiro 				}
1703299c2f1SGregory Neil Shapiro 
1713299c2f1SGregory Neil Shapiro 				setbitn(*p, mopts);
172c2aa98e2SPeter Wemm 				cond = TRUE;
1733299c2f1SGregory Neil Shapiro 				p++;
1743299c2f1SGregory Neil Shapiro 			}
1753299c2f1SGregory Neil Shapiro 		}
1763299c2f1SGregory Neil Shapiro 		p = q + 1;
177c2aa98e2SPeter Wemm 	}
178c2aa98e2SPeter Wemm 
179c2aa98e2SPeter Wemm 	/* find canonical name */
180c2aa98e2SPeter Wemm 	fname = p;
181c2aa98e2SPeter Wemm 	while (isascii(*p) && isgraph(*p) && *p != ':')
182c2aa98e2SPeter Wemm 		p++;
183c2aa98e2SPeter Wemm 	fvalue = p;
184c2aa98e2SPeter Wemm 	while (isascii(*p) && isspace(*p))
185c2aa98e2SPeter Wemm 		p++;
186c2aa98e2SPeter Wemm 	if (*p++ != ':' || fname == fvalue)
187c2aa98e2SPeter Wemm 	{
1883299c2f1SGregory Neil Shapiro hse:
1893299c2f1SGregory Neil Shapiro 		syserr("553 5.3.0 header syntax error, line \"%s\"", line);
190c2aa98e2SPeter Wemm 		return 0;
191c2aa98e2SPeter Wemm 	}
192c2aa98e2SPeter Wemm 	*fvalue = '\0';
193c2aa98e2SPeter Wemm 
194c2aa98e2SPeter Wemm 	/* strip field value on front */
195e01d6f61SPeter Wemm 	if (*p == ' ')
196e01d6f61SPeter Wemm 		p++;
197e01d6f61SPeter Wemm 	fvalue = p;
198e01d6f61SPeter Wemm 
199e01d6f61SPeter Wemm 	/* if the field is null, go ahead and use the default */
200e01d6f61SPeter Wemm 	while (isascii(*p) && isspace(*p))
201e01d6f61SPeter Wemm 		p++;
202e01d6f61SPeter Wemm 	if (*p == '\0')
203e01d6f61SPeter Wemm 		nullheader = TRUE;
204c2aa98e2SPeter Wemm 
205c2aa98e2SPeter Wemm 	/* security scan: long field names are end-of-header */
206c2aa98e2SPeter Wemm 	if (strlen(fname) > 100)
207c2aa98e2SPeter Wemm 		return H_EOH;
208c2aa98e2SPeter Wemm 
209c2aa98e2SPeter Wemm 	/* check to see if it represents a ruleset call */
2103299c2f1SGregory Neil Shapiro 	if (bitset(pflag, CHHDR_DEF))
211c2aa98e2SPeter Wemm 	{
212c2aa98e2SPeter Wemm 		char hbuf[50];
213c2aa98e2SPeter Wemm 
214c2aa98e2SPeter Wemm 		(void) expand(fvalue, hbuf, sizeof hbuf, e);
215c2aa98e2SPeter Wemm 		for (p = hbuf; isascii(*p) && isspace(*p); )
216c2aa98e2SPeter Wemm 			p++;
217c2aa98e2SPeter Wemm 		if ((*p++ & 0377) == CALLSUBR)
218c2aa98e2SPeter Wemm 		{
219c2aa98e2SPeter Wemm 			auto char *endp;
2203299c2f1SGregory Neil Shapiro 			bool strc;
221c2aa98e2SPeter Wemm 
2223299c2f1SGregory Neil Shapiro 			strc = *p == '+';	/* strip comments? */
2233299c2f1SGregory Neil Shapiro 			if (strc)
2243299c2f1SGregory Neil Shapiro 				++p;
225c2aa98e2SPeter Wemm 			if (strtorwset(p, &endp, ST_ENTER) > 0)
226c2aa98e2SPeter Wemm 			{
227c2aa98e2SPeter Wemm 				*endp = '\0';
228c2aa98e2SPeter Wemm 				s = stab(fname, ST_HEADER, ST_ENTER);
229c2aa98e2SPeter Wemm 				s->s_header.hi_ruleset = newstr(p);
2303299c2f1SGregory Neil Shapiro 				if (!strc)
2313299c2f1SGregory Neil Shapiro 					s->s_header.hi_flags |= H_STRIPCOMM;
232c2aa98e2SPeter Wemm 			}
233c2aa98e2SPeter Wemm 			return 0;
234c2aa98e2SPeter Wemm 		}
235c2aa98e2SPeter Wemm 	}
236c2aa98e2SPeter Wemm 
237c2aa98e2SPeter Wemm 	/* see if it is a known type */
238c2aa98e2SPeter Wemm 	s = stab(fname, ST_HEADER, ST_FIND);
239c2aa98e2SPeter Wemm 	if (s != NULL)
240c2aa98e2SPeter Wemm 		hi = &s->s_header;
241c2aa98e2SPeter Wemm 	else
242c2aa98e2SPeter Wemm 		hi = &NormalHeader;
243c2aa98e2SPeter Wemm 
244c2aa98e2SPeter Wemm 	if (tTd(31, 9))
245c2aa98e2SPeter Wemm 	{
246c2aa98e2SPeter Wemm 		if (s == NULL)
2473299c2f1SGregory Neil Shapiro 			dprintf("no header flags match\n");
248c2aa98e2SPeter Wemm 		else
2493299c2f1SGregory Neil Shapiro 			dprintf("header match, flags=%lx, ruleset=%s\n",
250c2aa98e2SPeter Wemm 				hi->hi_flags,
251c2aa98e2SPeter Wemm 				hi->hi_ruleset == NULL ? "<NULL>" : hi->hi_ruleset);
252c2aa98e2SPeter Wemm 	}
253c2aa98e2SPeter Wemm 
254c2aa98e2SPeter Wemm 	/* see if this is a resent message */
2553299c2f1SGregory Neil Shapiro 	if (!bitset(pflag, CHHDR_DEF) && !headeronly &&
2563299c2f1SGregory Neil Shapiro 	    bitset(H_RESENT, hi->hi_flags))
257c2aa98e2SPeter Wemm 		e->e_flags |= EF_RESENT;
258c2aa98e2SPeter Wemm 
259c2aa98e2SPeter Wemm 	/* if this is an Errors-To: header keep track of it now */
2603299c2f1SGregory Neil Shapiro 	if (UseErrorsTo && !bitset(pflag, CHHDR_DEF) && !headeronly &&
261c2aa98e2SPeter Wemm 	    bitset(H_ERRORSTO, hi->hi_flags))
262c2aa98e2SPeter Wemm 		(void) sendtolist(fvalue, NULLADDR, &e->e_errorqueue, 0, e);
263c2aa98e2SPeter Wemm 
264c2aa98e2SPeter Wemm 	/* if this means "end of header" quit now */
265c2aa98e2SPeter Wemm 	if (!headeronly && bitset(H_EOH, hi->hi_flags))
266c2aa98e2SPeter Wemm 		return hi->hi_flags;
267c2aa98e2SPeter Wemm 
268c2aa98e2SPeter Wemm 	/*
269c2aa98e2SPeter Wemm 	**  Horrible hack to work around problem with Lotus Notes SMTP
270c2aa98e2SPeter Wemm 	**  mail gateway, which generates From: headers with newlines in
271c2aa98e2SPeter Wemm 	**  them and the <address> on the second line.  Although this is
272c2aa98e2SPeter Wemm 	**  legal RFC 822, many MUAs don't handle this properly and thus
273c2aa98e2SPeter Wemm 	**  never find the actual address.
274c2aa98e2SPeter Wemm 	*/
275c2aa98e2SPeter Wemm 
276c2aa98e2SPeter Wemm 	if (bitset(H_FROM, hi->hi_flags) && SingleLineFromHeader)
277c2aa98e2SPeter Wemm 	{
278c2aa98e2SPeter Wemm 		while ((p = strchr(fvalue, '\n')) != NULL)
279c2aa98e2SPeter Wemm 			*p = ' ';
280c2aa98e2SPeter Wemm 	}
281c2aa98e2SPeter Wemm 
282c2aa98e2SPeter Wemm 	/*
283c2aa98e2SPeter Wemm 	**  If there is a check ruleset, verify it against the header.
284c2aa98e2SPeter Wemm 	*/
285c2aa98e2SPeter Wemm 
2863299c2f1SGregory Neil Shapiro 	if (bitset(pflag, CHHDR_CHECK))
2873299c2f1SGregory Neil Shapiro 	{
2883299c2f1SGregory Neil Shapiro 		bool stripcom = FALSE;
2893299c2f1SGregory Neil Shapiro 		char *rs;
2903299c2f1SGregory Neil Shapiro 
2913299c2f1SGregory Neil Shapiro 		/* no ruleset? look for default */
2923299c2f1SGregory Neil Shapiro 		rs = hi->hi_ruleset;
2933299c2f1SGregory Neil Shapiro 		if (rs == NULL)
2943299c2f1SGregory Neil Shapiro 		{
2953299c2f1SGregory Neil Shapiro 			s = stab("*", ST_HEADER, ST_FIND);
2963299c2f1SGregory Neil Shapiro 			if (s != NULL)
2973299c2f1SGregory Neil Shapiro 			{
2983299c2f1SGregory Neil Shapiro 				rs = (&s->s_header)->hi_ruleset;
2993299c2f1SGregory Neil Shapiro 				stripcom = bitset((&s->s_header)->hi_flags,
3003299c2f1SGregory Neil Shapiro 						  H_STRIPCOMM);
3013299c2f1SGregory Neil Shapiro 			}
3023299c2f1SGregory Neil Shapiro 		}
3033299c2f1SGregory Neil Shapiro 		else
3043299c2f1SGregory Neil Shapiro 			stripcom = bitset(hi->hi_flags, H_STRIPCOMM);
3053299c2f1SGregory Neil Shapiro 		if (rs != NULL)
3063299c2f1SGregory Neil Shapiro 		{
3073299c2f1SGregory Neil Shapiro 			int l;
3083299c2f1SGregory Neil Shapiro 			char qval[MAXNAME];
3093299c2f1SGregory Neil Shapiro 			char hlen[16];
3103299c2f1SGregory Neil Shapiro 			char *sp, *dp;
3113299c2f1SGregory Neil Shapiro 
3123299c2f1SGregory Neil Shapiro 			dp = qval;
3133299c2f1SGregory Neil Shapiro 			l = 0;
3143299c2f1SGregory Neil Shapiro 			dp[l++] = '"';
3153299c2f1SGregory Neil Shapiro 			for (sp = fvalue; *sp != '\0' && l < MAXNAME - 2; sp++)
3163299c2f1SGregory Neil Shapiro 			{
3173299c2f1SGregory Neil Shapiro 				switch(*sp)
3183299c2f1SGregory Neil Shapiro 				{
3193299c2f1SGregory Neil Shapiro 				  case '\011': /* ht */
3203299c2f1SGregory Neil Shapiro 				  case '\012': /* nl */
3213299c2f1SGregory Neil Shapiro 				  case '\013': /* vt */
3223299c2f1SGregory Neil Shapiro 				  case '\014': /* np */
3233299c2f1SGregory Neil Shapiro 				  case '\015': /* cr */
3243299c2f1SGregory Neil Shapiro 					dp[l++] = ' ';
3253299c2f1SGregory Neil Shapiro 					break;
3263299c2f1SGregory Neil Shapiro 				  case '"':
3273299c2f1SGregory Neil Shapiro 					dp[l++] = '\\';
3283299c2f1SGregory Neil Shapiro 					/* FALLTHROUGH */
3293299c2f1SGregory Neil Shapiro 				  default:
3303299c2f1SGregory Neil Shapiro 					dp[l++] = *sp;
3313299c2f1SGregory Neil Shapiro 					break;
3323299c2f1SGregory Neil Shapiro 				}
3333299c2f1SGregory Neil Shapiro 			}
3343299c2f1SGregory Neil Shapiro 			dp[l++] = '"';
3353299c2f1SGregory Neil Shapiro 			dp[l++] = '\0';
3363299c2f1SGregory Neil Shapiro 			l = strlen(fvalue);
3373299c2f1SGregory Neil Shapiro 			snprintf(hlen, sizeof hlen, "%d", l);
3383299c2f1SGregory Neil Shapiro 			define(macid("{hdrlen}", NULL), newstr(hlen), e);
3393299c2f1SGregory Neil Shapiro 			if (l >= MAXNAME)
3403299c2f1SGregory Neil Shapiro 			{
3413299c2f1SGregory Neil Shapiro 				if (LogLevel > 9)
3423299c2f1SGregory Neil Shapiro 					sm_syslog(LOG_WARNING, e->e_id,
3433299c2f1SGregory Neil Shapiro 						  "Warning: truncated header '%s' before check with '%s' len=%d max=%d",
3443299c2f1SGregory Neil Shapiro 						  fname, rs, l, MAXNAME);
3453299c2f1SGregory Neil Shapiro 			}
3463299c2f1SGregory Neil Shapiro 			if ((sp = macvalue(macid("{currHeader}", NULL), e)) !=
3473299c2f1SGregory Neil Shapiro 			    NULL)
3483299c2f1SGregory Neil Shapiro 				free(sp);
3493299c2f1SGregory Neil Shapiro 			define(macid("{currHeader}", NULL), newstr(qval), e);
3503299c2f1SGregory Neil Shapiro 			define(macid("{hdr_name}", NULL), newstr(fname), e);
3513299c2f1SGregory Neil Shapiro 			(void) rscheck(rs, fvalue, NULL, e, stripcom, TRUE, 4);
3523299c2f1SGregory Neil Shapiro 		}
3533299c2f1SGregory Neil Shapiro 	}
354c2aa98e2SPeter Wemm 
355c2aa98e2SPeter Wemm 	/*
356c2aa98e2SPeter Wemm 	**  Drop explicit From: if same as what we would generate.
357c2aa98e2SPeter Wemm 	**  This is to make MH (which doesn't always give a full name)
358c2aa98e2SPeter Wemm 	**  insert the full name information in all circumstances.
359c2aa98e2SPeter Wemm 	*/
360c2aa98e2SPeter Wemm 
3613299c2f1SGregory Neil Shapiro 	dropfrom = FALSE;
362c2aa98e2SPeter Wemm 	p = "resent-from";
363c2aa98e2SPeter Wemm 	if (!bitset(EF_RESENT, e->e_flags))
364c2aa98e2SPeter Wemm 		p += 7;
3653299c2f1SGregory Neil Shapiro 	if (!bitset(pflag, CHHDR_DEF) && !headeronly &&
3663299c2f1SGregory Neil Shapiro 	    !bitset(EF_QUEUERUN, e->e_flags) && strcasecmp(fname, p) == 0)
367c2aa98e2SPeter Wemm 	{
368c2aa98e2SPeter Wemm 		if (tTd(31, 2))
369c2aa98e2SPeter Wemm 		{
3703299c2f1SGregory Neil Shapiro 			dprintf("comparing header from (%s) against default (%s or %s)\n",
371c2aa98e2SPeter Wemm 				fvalue, e->e_from.q_paddr, e->e_from.q_user);
372c2aa98e2SPeter Wemm 		}
373c2aa98e2SPeter Wemm 		if (e->e_from.q_paddr != NULL &&
3743299c2f1SGregory Neil Shapiro 		    e->e_from.q_mailer != NULL &&
3753299c2f1SGregory Neil Shapiro 		    bitnset(M_LOCALMAILER, e->e_from.q_mailer->m_flags) &&
376c2aa98e2SPeter Wemm 		    (strcmp(fvalue, e->e_from.q_paddr) == 0 ||
377c2aa98e2SPeter Wemm 		     strcmp(fvalue, e->e_from.q_user) == 0))
3783299c2f1SGregory Neil Shapiro 			dropfrom = TRUE;
379c2aa98e2SPeter Wemm 	}
380c2aa98e2SPeter Wemm 
381c2aa98e2SPeter Wemm 	/* delete default value for this header */
382c2aa98e2SPeter Wemm 	for (hp = hdrp; (h = *hp) != NULL; hp = &h->h_link)
383c2aa98e2SPeter Wemm 	{
384c2aa98e2SPeter Wemm 		if (strcasecmp(fname, h->h_field) == 0 &&
3853299c2f1SGregory Neil Shapiro 		    !bitset(H_USER, h->h_flags) &&
386c2aa98e2SPeter Wemm 		    !bitset(H_FORCE, h->h_flags))
387c2aa98e2SPeter Wemm 		{
388e01d6f61SPeter Wemm 			if (nullheader)
389e01d6f61SPeter Wemm 			{
390e01d6f61SPeter Wemm 				/* user-supplied value was null */
391e01d6f61SPeter Wemm 				return 0;
392e01d6f61SPeter Wemm 			}
3933299c2f1SGregory Neil Shapiro 			if (dropfrom)
3943299c2f1SGregory Neil Shapiro 			{
3953299c2f1SGregory Neil Shapiro 				/* make this look like the user entered it */
3963299c2f1SGregory Neil Shapiro 				h->h_flags |= H_USER;
3973299c2f1SGregory Neil Shapiro 				return hi->hi_flags;
3983299c2f1SGregory Neil Shapiro 			}
399c2aa98e2SPeter Wemm 			h->h_value = NULL;
400c2aa98e2SPeter Wemm 			if (!cond)
401c2aa98e2SPeter Wemm 			{
402c2aa98e2SPeter Wemm 				/* copy conditions from default case */
4033299c2f1SGregory Neil Shapiro 				memmove((char *)mopts, (char *)h->h_mflags,
404c2aa98e2SPeter Wemm 					sizeof mopts);
405c2aa98e2SPeter Wemm 			}
4063299c2f1SGregory Neil Shapiro 			h->h_macro = mid;
407c2aa98e2SPeter Wemm 		}
408c2aa98e2SPeter Wemm 	}
409c2aa98e2SPeter Wemm 
410c2aa98e2SPeter Wemm 	/* create a new node */
411c2aa98e2SPeter Wemm 	h = (HDR *) xalloc(sizeof *h);
412c2aa98e2SPeter Wemm 	h->h_field = newstr(fname);
413c2aa98e2SPeter Wemm 	h->h_value = newstr(fvalue);
414c2aa98e2SPeter Wemm 	h->h_link = NULL;
4153299c2f1SGregory Neil Shapiro 	memmove((char *) h->h_mflags, (char *) mopts, sizeof mopts);
4163299c2f1SGregory Neil Shapiro 	h->h_macro = mid;
417c2aa98e2SPeter Wemm 	*hp = h;
418c2aa98e2SPeter Wemm 	h->h_flags = hi->hi_flags;
4193299c2f1SGregory Neil Shapiro 	if (bitset(pflag, CHHDR_USER))
4203299c2f1SGregory Neil Shapiro 		h->h_flags |= H_USER;
421c2aa98e2SPeter Wemm 
422c2aa98e2SPeter Wemm 	/* strip EOH flag if parsing MIME headers */
423c2aa98e2SPeter Wemm 	if (headeronly)
424c2aa98e2SPeter Wemm 		h->h_flags &= ~H_EOH;
4253299c2f1SGregory Neil Shapiro 	if (bitset(pflag, CHHDR_DEF))
426c2aa98e2SPeter Wemm 		h->h_flags |= H_DEFAULT;
4273299c2f1SGregory Neil Shapiro 	if (cond || mid != '\0')
428c2aa98e2SPeter Wemm 		h->h_flags |= H_CHECK;
429c2aa98e2SPeter Wemm 
430c2aa98e2SPeter Wemm 	/* hack to see if this is a new format message */
4313299c2f1SGregory Neil Shapiro 	if (!bitset(pflag, CHHDR_DEF) && !headeronly &&
4323299c2f1SGregory Neil Shapiro 	    bitset(H_RCPT|H_FROM, h->h_flags) &&
433c2aa98e2SPeter Wemm 	    (strchr(fvalue, ',') != NULL || strchr(fvalue, '(') != NULL ||
434c2aa98e2SPeter Wemm 	     strchr(fvalue, '<') != NULL || strchr(fvalue, ';') != NULL))
435c2aa98e2SPeter Wemm 	{
436c2aa98e2SPeter Wemm 		e->e_flags &= ~EF_OLDSTYLE;
437c2aa98e2SPeter Wemm 	}
438c2aa98e2SPeter Wemm 
439c2aa98e2SPeter Wemm 	return h->h_flags;
440c2aa98e2SPeter Wemm }
441c2aa98e2SPeter Wemm /*
442c2aa98e2SPeter Wemm **  ADDHEADER -- add a header entry to the end of the queue.
443c2aa98e2SPeter Wemm **
444c2aa98e2SPeter Wemm **	This bypasses the special checking of chompheader.
445c2aa98e2SPeter Wemm **
446c2aa98e2SPeter Wemm **	Parameters:
447c2aa98e2SPeter Wemm **		field -- the name of the header field.
448c2aa98e2SPeter Wemm **		value -- the value of the field.
4493299c2f1SGregory Neil Shapiro **		flags -- flags to add to h_flags.
4503299c2f1SGregory Neil Shapiro **		hdrlist -- an indirect pointer to the header structure list.
451c2aa98e2SPeter Wemm **
452c2aa98e2SPeter Wemm **	Returns:
453c2aa98e2SPeter Wemm **		none.
454c2aa98e2SPeter Wemm **
455c2aa98e2SPeter Wemm **	Side Effects:
456c2aa98e2SPeter Wemm **		adds the field on the list of headers for this envelope.
457c2aa98e2SPeter Wemm */
458c2aa98e2SPeter Wemm 
459c2aa98e2SPeter Wemm void
4603299c2f1SGregory Neil Shapiro addheader(field, value, flags, hdrlist)
461c2aa98e2SPeter Wemm 	char *field;
462c2aa98e2SPeter Wemm 	char *value;
4633299c2f1SGregory Neil Shapiro 	int flags;
464c2aa98e2SPeter Wemm 	HDR **hdrlist;
465c2aa98e2SPeter Wemm {
466c2aa98e2SPeter Wemm 	register HDR *h;
467c2aa98e2SPeter Wemm 	STAB *s;
468c2aa98e2SPeter Wemm 	HDR **hp;
469c2aa98e2SPeter Wemm 
470c2aa98e2SPeter Wemm 	/* find info struct */
471c2aa98e2SPeter Wemm 	s = stab(field, ST_HEADER, ST_FIND);
472c2aa98e2SPeter Wemm 
473c2aa98e2SPeter Wemm 	/* find current place in list -- keep back pointer? */
474c2aa98e2SPeter Wemm 	for (hp = hdrlist; (h = *hp) != NULL; hp = &h->h_link)
475c2aa98e2SPeter Wemm 	{
476c2aa98e2SPeter Wemm 		if (strcasecmp(field, h->h_field) == 0)
477c2aa98e2SPeter Wemm 			break;
478c2aa98e2SPeter Wemm 	}
479c2aa98e2SPeter Wemm 
480c2aa98e2SPeter Wemm 	/* allocate space for new header */
481c2aa98e2SPeter Wemm 	h = (HDR *) xalloc(sizeof *h);
482c2aa98e2SPeter Wemm 	h->h_field = field;
483c2aa98e2SPeter Wemm 	h->h_value = newstr(value);
484c2aa98e2SPeter Wemm 	h->h_link = *hp;
4853299c2f1SGregory Neil Shapiro 	h->h_flags = flags;
486c2aa98e2SPeter Wemm 	if (s != NULL)
487c2aa98e2SPeter Wemm 		h->h_flags |= s->s_header.hi_flags;
488c2aa98e2SPeter Wemm 	clrbitmap(h->h_mflags);
4893299c2f1SGregory Neil Shapiro 	h->h_macro = '\0';
490c2aa98e2SPeter Wemm 	*hp = h;
491c2aa98e2SPeter Wemm }
492c2aa98e2SPeter Wemm /*
493c2aa98e2SPeter Wemm **  HVALUE -- return value of a header.
494c2aa98e2SPeter Wemm **
495c2aa98e2SPeter Wemm **	Only "real" fields (i.e., ones that have not been supplied
496c2aa98e2SPeter Wemm **	as a default) are used.
497c2aa98e2SPeter Wemm **
498c2aa98e2SPeter Wemm **	Parameters:
499c2aa98e2SPeter Wemm **		field -- the field name.
500c2aa98e2SPeter Wemm **		header -- the header list.
501c2aa98e2SPeter Wemm **
502c2aa98e2SPeter Wemm **	Returns:
503c2aa98e2SPeter Wemm **		pointer to the value part.
504c2aa98e2SPeter Wemm **		NULL if not found.
505c2aa98e2SPeter Wemm **
506c2aa98e2SPeter Wemm **	Side Effects:
507c2aa98e2SPeter Wemm **		none.
508c2aa98e2SPeter Wemm */
509c2aa98e2SPeter Wemm 
510c2aa98e2SPeter Wemm char *
511c2aa98e2SPeter Wemm hvalue(field, header)
512c2aa98e2SPeter Wemm 	char *field;
513c2aa98e2SPeter Wemm 	HDR *header;
514c2aa98e2SPeter Wemm {
515c2aa98e2SPeter Wemm 	register HDR *h;
516c2aa98e2SPeter Wemm 
517c2aa98e2SPeter Wemm 	for (h = header; h != NULL; h = h->h_link)
518c2aa98e2SPeter Wemm 	{
519c2aa98e2SPeter Wemm 		if (!bitset(H_DEFAULT, h->h_flags) &&
520c2aa98e2SPeter Wemm 		    strcasecmp(h->h_field, field) == 0)
5213299c2f1SGregory Neil Shapiro 			return h->h_value;
522c2aa98e2SPeter Wemm 	}
5233299c2f1SGregory Neil Shapiro 	return NULL;
524c2aa98e2SPeter Wemm }
525c2aa98e2SPeter Wemm /*
526c2aa98e2SPeter Wemm **  ISHEADER -- predicate telling if argument is a header.
527c2aa98e2SPeter Wemm **
528c2aa98e2SPeter Wemm **	A line is a header if it has a single word followed by
529c2aa98e2SPeter Wemm **	optional white space followed by a colon.
530c2aa98e2SPeter Wemm **
531c2aa98e2SPeter Wemm **	Header fields beginning with two dashes, although technically
532c2aa98e2SPeter Wemm **	permitted by RFC822, are automatically rejected in order
533c2aa98e2SPeter Wemm **	to make MIME work out.  Without this we could have a technically
534c2aa98e2SPeter Wemm **	legal header such as ``--"foo:bar"'' that would also be a legal
535c2aa98e2SPeter Wemm **	MIME separator.
536c2aa98e2SPeter Wemm **
537c2aa98e2SPeter Wemm **	Parameters:
538c2aa98e2SPeter Wemm **		h -- string to check for possible headerness.
539c2aa98e2SPeter Wemm **
540c2aa98e2SPeter Wemm **	Returns:
541c2aa98e2SPeter Wemm **		TRUE if h is a header.
542c2aa98e2SPeter Wemm **		FALSE otherwise.
543c2aa98e2SPeter Wemm **
544c2aa98e2SPeter Wemm **	Side Effects:
545c2aa98e2SPeter Wemm **		none.
546c2aa98e2SPeter Wemm */
547c2aa98e2SPeter Wemm 
548c2aa98e2SPeter Wemm bool
549c2aa98e2SPeter Wemm isheader(h)
550c2aa98e2SPeter Wemm 	char *h;
551c2aa98e2SPeter Wemm {
552c2aa98e2SPeter Wemm 	register char *s = h;
553c2aa98e2SPeter Wemm 
554c2aa98e2SPeter Wemm 	if (s[0] == '-' && s[1] == '-')
555c2aa98e2SPeter Wemm 		return FALSE;
556c2aa98e2SPeter Wemm 
557c2aa98e2SPeter Wemm 	while (*s > ' ' && *s != ':' && *s != '\0')
558c2aa98e2SPeter Wemm 		s++;
559c2aa98e2SPeter Wemm 
560c2aa98e2SPeter Wemm 	if (h == s)
561c2aa98e2SPeter Wemm 		return FALSE;
562c2aa98e2SPeter Wemm 
563c2aa98e2SPeter Wemm 	/* following technically violates RFC822 */
564c2aa98e2SPeter Wemm 	while (isascii(*s) && isspace(*s))
565c2aa98e2SPeter Wemm 		s++;
566c2aa98e2SPeter Wemm 
567c2aa98e2SPeter Wemm 	return (*s == ':');
568c2aa98e2SPeter Wemm }
569c2aa98e2SPeter Wemm /*
570c2aa98e2SPeter Wemm **  EATHEADER -- run through the stored header and extract info.
571c2aa98e2SPeter Wemm **
572c2aa98e2SPeter Wemm **	Parameters:
573c2aa98e2SPeter Wemm **		e -- the envelope to process.
574c2aa98e2SPeter Wemm **		full -- if set, do full processing (e.g., compute
575c2aa98e2SPeter Wemm **			message priority).  This should not be set
576c2aa98e2SPeter Wemm **			when reading a queue file because some info
577c2aa98e2SPeter Wemm **			needed to compute the priority is wrong.
578c2aa98e2SPeter Wemm **
579c2aa98e2SPeter Wemm **	Returns:
580c2aa98e2SPeter Wemm **		none.
581c2aa98e2SPeter Wemm **
582c2aa98e2SPeter Wemm **	Side Effects:
583c2aa98e2SPeter Wemm **		Sets a bunch of global variables from information
584c2aa98e2SPeter Wemm **			in the collected header.
585c2aa98e2SPeter Wemm **		Aborts the message if the hop count is exceeded.
586c2aa98e2SPeter Wemm */
587c2aa98e2SPeter Wemm 
588c2aa98e2SPeter Wemm void
589c2aa98e2SPeter Wemm eatheader(e, full)
590c2aa98e2SPeter Wemm 	register ENVELOPE *e;
591c2aa98e2SPeter Wemm 	bool full;
592c2aa98e2SPeter Wemm {
593c2aa98e2SPeter Wemm 	register HDR *h;
594c2aa98e2SPeter Wemm 	register char *p;
595c2aa98e2SPeter Wemm 	int hopcnt = 0;
596c2aa98e2SPeter Wemm 	char *msgid;
597c2aa98e2SPeter Wemm 	char buf[MAXLINE];
598c2aa98e2SPeter Wemm 
599c2aa98e2SPeter Wemm 	/*
600c2aa98e2SPeter Wemm 	**  Set up macros for possible expansion in headers.
601c2aa98e2SPeter Wemm 	*/
602c2aa98e2SPeter Wemm 
603c2aa98e2SPeter Wemm 	define('f', e->e_sender, e);
604c2aa98e2SPeter Wemm 	define('g', e->e_sender, e);
605c2aa98e2SPeter Wemm 	if (e->e_origrcpt != NULL && *e->e_origrcpt != '\0')
606c2aa98e2SPeter Wemm 		define('u', e->e_origrcpt, e);
607c2aa98e2SPeter Wemm 	else
608c2aa98e2SPeter Wemm 		define('u', NULL, e);
609c2aa98e2SPeter Wemm 
610c2aa98e2SPeter Wemm 	/* full name of from person */
611c2aa98e2SPeter Wemm 	p = hvalue("full-name", e->e_header);
612c2aa98e2SPeter Wemm 	if (p != NULL)
613c2aa98e2SPeter Wemm 	{
614c2aa98e2SPeter Wemm 		if (!rfc822_string(p))
615c2aa98e2SPeter Wemm 		{
616c2aa98e2SPeter Wemm 			/*
617c2aa98e2SPeter Wemm 			**  Quote a full name with special characters
618c2aa98e2SPeter Wemm 			**  as a comment so crackaddr() doesn't destroy
619c2aa98e2SPeter Wemm 			**  the name portion of the address.
620c2aa98e2SPeter Wemm 			*/
621c2aa98e2SPeter Wemm 			p = addquotes(p);
622c2aa98e2SPeter Wemm 		}
623c2aa98e2SPeter Wemm 		define('x', p, e);
624c2aa98e2SPeter Wemm 	}
625c2aa98e2SPeter Wemm 
626c2aa98e2SPeter Wemm 	if (tTd(32, 1))
6273299c2f1SGregory Neil Shapiro 		dprintf("----- collected header -----\n");
628c2aa98e2SPeter Wemm 	msgid = NULL;
629c2aa98e2SPeter Wemm 	for (h = e->e_header; h != NULL; h = h->h_link)
630c2aa98e2SPeter Wemm 	{
631c2aa98e2SPeter Wemm 		if (tTd(32, 1))
6323299c2f1SGregory Neil Shapiro 			dprintf("%s: ", h->h_field);
633c2aa98e2SPeter Wemm 		if (h->h_value == NULL)
634c2aa98e2SPeter Wemm 		{
635c2aa98e2SPeter Wemm 			if (tTd(32, 1))
6363299c2f1SGregory Neil Shapiro 				dprintf("<NULL>\n");
637c2aa98e2SPeter Wemm 			continue;
638c2aa98e2SPeter Wemm 		}
639c2aa98e2SPeter Wemm 
640c2aa98e2SPeter Wemm 		/* do early binding */
6413299c2f1SGregory Neil Shapiro 		if (bitset(H_DEFAULT, h->h_flags) &&
6423299c2f1SGregory Neil Shapiro 		    !bitset(H_BINDLATE, h->h_flags))
643c2aa98e2SPeter Wemm 		{
644c2aa98e2SPeter Wemm 			if (tTd(32, 1))
645c2aa98e2SPeter Wemm 			{
6463299c2f1SGregory Neil Shapiro 				dprintf("(");
647c2aa98e2SPeter Wemm 				xputs(h->h_value);
6483299c2f1SGregory Neil Shapiro 				dprintf(") ");
649c2aa98e2SPeter Wemm 			}
650c2aa98e2SPeter Wemm 			expand(h->h_value, buf, sizeof buf, e);
651c2aa98e2SPeter Wemm 			if (buf[0] != '\0')
652c2aa98e2SPeter Wemm 			{
653c2aa98e2SPeter Wemm 				if (bitset(H_FROM, h->h_flags))
654c2aa98e2SPeter Wemm 					expand(crackaddr(buf), buf, sizeof buf, e);
655c2aa98e2SPeter Wemm 				h->h_value = newstr(buf);
656c2aa98e2SPeter Wemm 				h->h_flags &= ~H_DEFAULT;
657c2aa98e2SPeter Wemm 			}
658c2aa98e2SPeter Wemm 		}
659c2aa98e2SPeter Wemm 
660c2aa98e2SPeter Wemm 		if (tTd(32, 1))
661c2aa98e2SPeter Wemm 		{
662c2aa98e2SPeter Wemm 			xputs(h->h_value);
6633299c2f1SGregory Neil Shapiro 			dprintf("\n");
664c2aa98e2SPeter Wemm 		}
665c2aa98e2SPeter Wemm 
666c2aa98e2SPeter Wemm 		/* count the number of times it has been processed */
667c2aa98e2SPeter Wemm 		if (bitset(H_TRACE, h->h_flags))
668c2aa98e2SPeter Wemm 			hopcnt++;
669c2aa98e2SPeter Wemm 
670c2aa98e2SPeter Wemm 		/* send to this person if we so desire */
671c2aa98e2SPeter Wemm 		if (GrabTo && bitset(H_RCPT, h->h_flags) &&
672c2aa98e2SPeter Wemm 		    !bitset(H_DEFAULT, h->h_flags) &&
673c2aa98e2SPeter Wemm 		    (!bitset(EF_RESENT, e->e_flags) || bitset(H_RESENT, h->h_flags)))
674c2aa98e2SPeter Wemm 		{
675c2aa98e2SPeter Wemm #if 0
676c2aa98e2SPeter Wemm 			int saveflags = e->e_flags;
6773299c2f1SGregory Neil Shapiro #endif /* 0 */
678c2aa98e2SPeter Wemm 
679c2aa98e2SPeter Wemm 			(void) sendtolist(h->h_value, NULLADDR,
680c2aa98e2SPeter Wemm 					  &e->e_sendqueue, 0, e);
681c2aa98e2SPeter Wemm 
682c2aa98e2SPeter Wemm #if 0
683c2aa98e2SPeter Wemm 			/*
684c2aa98e2SPeter Wemm 			**  Change functionality so a fatal error on an
685c2aa98e2SPeter Wemm 			**  address doesn't affect the entire envelope.
686c2aa98e2SPeter Wemm 			*/
687c2aa98e2SPeter Wemm 
688c2aa98e2SPeter Wemm 			/* delete fatal errors generated by this address */
689c2aa98e2SPeter Wemm 			if (!bitset(EF_FATALERRS, saveflags))
690c2aa98e2SPeter Wemm 				e->e_flags &= ~EF_FATALERRS;
6913299c2f1SGregory Neil Shapiro #endif /* 0 */
692c2aa98e2SPeter Wemm 		}
693c2aa98e2SPeter Wemm 
694c2aa98e2SPeter Wemm 		/* save the message-id for logging */
695c2aa98e2SPeter Wemm 		p = "resent-message-id";
696c2aa98e2SPeter Wemm 		if (!bitset(EF_RESENT, e->e_flags))
697c2aa98e2SPeter Wemm 			p += 7;
698c2aa98e2SPeter Wemm 		if (strcasecmp(h->h_field, p) == 0)
699c2aa98e2SPeter Wemm 		{
700c2aa98e2SPeter Wemm 			msgid = h->h_value;
701c2aa98e2SPeter Wemm 			while (isascii(*msgid) && isspace(*msgid))
702c2aa98e2SPeter Wemm 				msgid++;
703c2aa98e2SPeter Wemm 		}
704c2aa98e2SPeter Wemm 	}
705c2aa98e2SPeter Wemm 	if (tTd(32, 1))
7063299c2f1SGregory Neil Shapiro 		dprintf("----------------------------\n");
707c2aa98e2SPeter Wemm 
708c2aa98e2SPeter Wemm 	/* if we are just verifying (that is, sendmail -t -bv), drop out now */
709c2aa98e2SPeter Wemm 	if (OpMode == MD_VERIFY)
710c2aa98e2SPeter Wemm 		return;
711c2aa98e2SPeter Wemm 
712c2aa98e2SPeter Wemm 	/* store hop count */
713c2aa98e2SPeter Wemm 	if (hopcnt > e->e_hopcount)
714c2aa98e2SPeter Wemm 		e->e_hopcount = hopcnt;
715c2aa98e2SPeter Wemm 
716c2aa98e2SPeter Wemm 	/* message priority */
717c2aa98e2SPeter Wemm 	p = hvalue("precedence", e->e_header);
718c2aa98e2SPeter Wemm 	if (p != NULL)
719c2aa98e2SPeter Wemm 		e->e_class = priencode(p);
720c2aa98e2SPeter Wemm 	if (e->e_class < 0)
721c2aa98e2SPeter Wemm 		e->e_timeoutclass = TOC_NONURGENT;
722c2aa98e2SPeter Wemm 	else if (e->e_class > 0)
723c2aa98e2SPeter Wemm 		e->e_timeoutclass = TOC_URGENT;
724c2aa98e2SPeter Wemm 	if (full)
725c2aa98e2SPeter Wemm 	{
726c2aa98e2SPeter Wemm 		e->e_msgpriority = e->e_msgsize
727c2aa98e2SPeter Wemm 				 - e->e_class * WkClassFact
728c2aa98e2SPeter Wemm 				 + e->e_nrcpts * WkRecipFact;
729c2aa98e2SPeter Wemm 	}
730c2aa98e2SPeter Wemm 
731c2aa98e2SPeter Wemm 	/* message timeout priority */
732c2aa98e2SPeter Wemm 	p = hvalue("priority", e->e_header);
733c2aa98e2SPeter Wemm 	if (p != NULL)
734c2aa98e2SPeter Wemm 	{
735c2aa98e2SPeter Wemm 		/* (this should be in the configuration file) */
736c2aa98e2SPeter Wemm 		if (strcasecmp(p, "urgent") == 0)
737c2aa98e2SPeter Wemm 			e->e_timeoutclass = TOC_URGENT;
738c2aa98e2SPeter Wemm 		else if (strcasecmp(p, "normal") == 0)
739c2aa98e2SPeter Wemm 			e->e_timeoutclass = TOC_NORMAL;
740c2aa98e2SPeter Wemm 		else if (strcasecmp(p, "non-urgent") == 0)
741c2aa98e2SPeter Wemm 			e->e_timeoutclass = TOC_NONURGENT;
742c2aa98e2SPeter Wemm 	}
743c2aa98e2SPeter Wemm 
744c2aa98e2SPeter Wemm 	/* date message originated */
745c2aa98e2SPeter Wemm 	p = hvalue("posted-date", e->e_header);
746c2aa98e2SPeter Wemm 	if (p == NULL)
747c2aa98e2SPeter Wemm 		p = hvalue("date", e->e_header);
748c2aa98e2SPeter Wemm 	if (p != NULL)
749c2aa98e2SPeter Wemm 		define('a', p, e);
750c2aa98e2SPeter Wemm 
751c2aa98e2SPeter Wemm 	/* check to see if this is a MIME message */
752c2aa98e2SPeter Wemm 	if ((e->e_bodytype != NULL &&
753c2aa98e2SPeter Wemm 	     strcasecmp(e->e_bodytype, "8BITMIME") == 0) ||
754c2aa98e2SPeter Wemm 	    hvalue("MIME-Version", e->e_header) != NULL)
755c2aa98e2SPeter Wemm 	{
756c2aa98e2SPeter Wemm 		e->e_flags |= EF_IS_MIME;
757c2aa98e2SPeter Wemm 		if (HasEightBits)
758c2aa98e2SPeter Wemm 			e->e_bodytype = "8BITMIME";
759c2aa98e2SPeter Wemm 	}
760c2aa98e2SPeter Wemm 	else if ((p = hvalue("Content-Type", e->e_header)) != NULL)
761c2aa98e2SPeter Wemm 	{
762c2aa98e2SPeter Wemm 		/* this may be an RFC 1049 message */
763c2aa98e2SPeter Wemm 		p = strpbrk(p, ";/");
764c2aa98e2SPeter Wemm 		if (p == NULL || *p == ';')
765c2aa98e2SPeter Wemm 		{
766c2aa98e2SPeter Wemm 			/* yep, it is */
767c2aa98e2SPeter Wemm 			e->e_flags |= EF_DONT_MIME;
768c2aa98e2SPeter Wemm 		}
769c2aa98e2SPeter Wemm 	}
770c2aa98e2SPeter Wemm 
771c2aa98e2SPeter Wemm 	/*
772c2aa98e2SPeter Wemm 	**  From person in antiquated ARPANET mode
773c2aa98e2SPeter Wemm 	**	required by UK Grey Book e-mail gateways (sigh)
774c2aa98e2SPeter Wemm 	*/
775c2aa98e2SPeter Wemm 
776c2aa98e2SPeter Wemm 	if (OpMode == MD_ARPAFTP)
777c2aa98e2SPeter Wemm 	{
778c2aa98e2SPeter Wemm 		register struct hdrinfo *hi;
779c2aa98e2SPeter Wemm 
780c2aa98e2SPeter Wemm 		for (hi = HdrInfo; hi->hi_field != NULL; hi++)
781c2aa98e2SPeter Wemm 		{
782c2aa98e2SPeter Wemm 			if (bitset(H_FROM, hi->hi_flags) &&
783c2aa98e2SPeter Wemm 			    (!bitset(H_RESENT, hi->hi_flags) ||
784c2aa98e2SPeter Wemm 			     bitset(EF_RESENT, e->e_flags)) &&
785c2aa98e2SPeter Wemm 			    (p = hvalue(hi->hi_field, e->e_header)) != NULL)
786c2aa98e2SPeter Wemm 				break;
787c2aa98e2SPeter Wemm 		}
788c2aa98e2SPeter Wemm 		if (hi->hi_field != NULL)
789c2aa98e2SPeter Wemm 		{
790c2aa98e2SPeter Wemm 			if (tTd(32, 2))
7913299c2f1SGregory Neil Shapiro 				dprintf("eatheader: setsender(*%s == %s)\n",
792c2aa98e2SPeter Wemm 					hi->hi_field, p);
793c2aa98e2SPeter Wemm 			setsender(p, e, NULL, '\0', TRUE);
794c2aa98e2SPeter Wemm 		}
795c2aa98e2SPeter Wemm 	}
796c2aa98e2SPeter Wemm 
797c2aa98e2SPeter Wemm 	/*
798c2aa98e2SPeter Wemm 	**  Log collection information.
799c2aa98e2SPeter Wemm 	*/
800c2aa98e2SPeter Wemm 
801c2aa98e2SPeter Wemm 	if (bitset(EF_LOGSENDER, e->e_flags) && LogLevel > 4)
802c2aa98e2SPeter Wemm 		logsender(e, msgid);
803c2aa98e2SPeter Wemm 	e->e_flags &= ~EF_LOGSENDER;
804c2aa98e2SPeter Wemm }
805c2aa98e2SPeter Wemm /*
806c2aa98e2SPeter Wemm **  LOGSENDER -- log sender information
807c2aa98e2SPeter Wemm **
808c2aa98e2SPeter Wemm **	Parameters:
809c2aa98e2SPeter Wemm **		e -- the envelope to log
810c2aa98e2SPeter Wemm **		msgid -- the message id
811c2aa98e2SPeter Wemm **
812c2aa98e2SPeter Wemm **	Returns:
813c2aa98e2SPeter Wemm **		none
814c2aa98e2SPeter Wemm */
815c2aa98e2SPeter Wemm 
816c2aa98e2SPeter Wemm void
817c2aa98e2SPeter Wemm logsender(e, msgid)
818c2aa98e2SPeter Wemm 	register ENVELOPE *e;
819c2aa98e2SPeter Wemm 	char *msgid;
820c2aa98e2SPeter Wemm {
821c2aa98e2SPeter Wemm 	char *name;
822c2aa98e2SPeter Wemm 	register char *sbp;
823c2aa98e2SPeter Wemm 	register char *p;
824c2aa98e2SPeter Wemm 	int l;
825c2aa98e2SPeter Wemm 	char hbuf[MAXNAME + 1];
826c2aa98e2SPeter Wemm 	char sbuf[MAXLINE + 1];
827c2aa98e2SPeter Wemm 	char mbuf[MAXNAME + 1];
828c2aa98e2SPeter Wemm 
829c2aa98e2SPeter Wemm 	/* don't allow newlines in the message-id */
830c2aa98e2SPeter Wemm 	if (msgid != NULL)
831c2aa98e2SPeter Wemm 	{
832c2aa98e2SPeter Wemm 		l = strlen(msgid);
833c2aa98e2SPeter Wemm 		if (l > sizeof mbuf - 1)
834c2aa98e2SPeter Wemm 			l = sizeof mbuf - 1;
8353299c2f1SGregory Neil Shapiro 		memmove(mbuf, msgid, l);
836c2aa98e2SPeter Wemm 		mbuf[l] = '\0';
837c2aa98e2SPeter Wemm 		p = mbuf;
838c2aa98e2SPeter Wemm 		while ((p = strchr(p, '\n')) != NULL)
839c2aa98e2SPeter Wemm 			*p++ = ' ';
840c2aa98e2SPeter Wemm 	}
841c2aa98e2SPeter Wemm 
842c2aa98e2SPeter Wemm 	if (bitset(EF_RESPONSE, e->e_flags))
843c2aa98e2SPeter Wemm 		name = "[RESPONSE]";
844c2aa98e2SPeter Wemm 	else if ((name = macvalue('_', e)) != NULL)
8453299c2f1SGregory Neil Shapiro 		/* EMPTY */
846c2aa98e2SPeter Wemm 		;
847c2aa98e2SPeter Wemm 	else if (RealHostName == NULL)
848c2aa98e2SPeter Wemm 		name = "localhost";
849c2aa98e2SPeter Wemm 	else if (RealHostName[0] == '[')
850c2aa98e2SPeter Wemm 		name = RealHostName;
851c2aa98e2SPeter Wemm 	else
852c2aa98e2SPeter Wemm 	{
853c2aa98e2SPeter Wemm 		name = hbuf;
854c2aa98e2SPeter Wemm 		(void) snprintf(hbuf, sizeof hbuf, "%.80s", RealHostName);
855c2aa98e2SPeter Wemm 		if (RealHostAddr.sa.sa_family != 0)
856c2aa98e2SPeter Wemm 		{
857c2aa98e2SPeter Wemm 			p = &hbuf[strlen(hbuf)];
858c2aa98e2SPeter Wemm 			(void) snprintf(p, SPACELEFT(hbuf, p), " (%.100s)",
859c2aa98e2SPeter Wemm 				anynet_ntoa(&RealHostAddr));
860c2aa98e2SPeter Wemm 		}
861c2aa98e2SPeter Wemm 	}
862c2aa98e2SPeter Wemm 
863c2aa98e2SPeter Wemm 	/* some versions of syslog only take 5 printf args */
864c2aa98e2SPeter Wemm #if (SYSLOG_BUFSIZE) >= 256
865c2aa98e2SPeter Wemm 	sbp = sbuf;
866c2aa98e2SPeter Wemm 	snprintf(sbp, SPACELEFT(sbuf, sbp),
8673299c2f1SGregory Neil Shapiro 	    "from=%.200s, size=%ld, class=%d, nrcpts=%d",
868c2aa98e2SPeter Wemm 	    e->e_from.q_paddr == NULL ? "<NONE>" : e->e_from.q_paddr,
8693299c2f1SGregory Neil Shapiro 	    e->e_msgsize, e->e_class, e->e_nrcpts);
870c2aa98e2SPeter Wemm 	sbp += strlen(sbp);
871c2aa98e2SPeter Wemm 	if (msgid != NULL)
872c2aa98e2SPeter Wemm 	{
873c2aa98e2SPeter Wemm 		snprintf(sbp, SPACELEFT(sbuf, sbp), ", msgid=%.100s", mbuf);
874c2aa98e2SPeter Wemm 		sbp += strlen(sbp);
875c2aa98e2SPeter Wemm 	}
876c2aa98e2SPeter Wemm 	if (e->e_bodytype != NULL)
877c2aa98e2SPeter Wemm 	{
878c2aa98e2SPeter Wemm 		(void) snprintf(sbp, SPACELEFT(sbuf, sbp), ", bodytype=%.20s",
879c2aa98e2SPeter Wemm 			e->e_bodytype);
880c2aa98e2SPeter Wemm 		sbp += strlen(sbp);
881c2aa98e2SPeter Wemm 	}
882c2aa98e2SPeter Wemm 	p = macvalue('r', e);
883c2aa98e2SPeter Wemm 	if (p != NULL)
8843299c2f1SGregory Neil Shapiro 	{
885c2aa98e2SPeter Wemm 		(void) snprintf(sbp, SPACELEFT(sbuf, sbp), ", proto=%.20s", p);
8863299c2f1SGregory Neil Shapiro 		sbp += strlen(sbp);
8873299c2f1SGregory Neil Shapiro 	}
8883299c2f1SGregory Neil Shapiro 	p = macvalue(macid("{daemon_name}", NULL), e);
8893299c2f1SGregory Neil Shapiro 	if (p != NULL)
8903299c2f1SGregory Neil Shapiro 	{
8913299c2f1SGregory Neil Shapiro 		(void) snprintf(sbp, SPACELEFT(sbuf, sbp), ", daemon=%.20s", p);
8923299c2f1SGregory Neil Shapiro 		sbp += strlen(sbp);
8933299c2f1SGregory Neil Shapiro 	}
8943299c2f1SGregory Neil Shapiro # if SASL
8953299c2f1SGregory Neil Shapiro 	p = macvalue(macid("{auth_type}", NULL), e);
8963299c2f1SGregory Neil Shapiro 	if (p != NULL)
8973299c2f1SGregory Neil Shapiro 	{
8983299c2f1SGregory Neil Shapiro 		(void) snprintf(sbp, SPACELEFT(sbuf, sbp), ", mech=%.12s", p);
8993299c2f1SGregory Neil Shapiro 		sbp += strlen(sbp);
9003299c2f1SGregory Neil Shapiro 	}
9013299c2f1SGregory Neil Shapiro 	p = macvalue(macid("{auth_author}", NULL), e);
9023299c2f1SGregory Neil Shapiro 	if (p != NULL)
9033299c2f1SGregory Neil Shapiro 	{
9043299c2f1SGregory Neil Shapiro 		(void) snprintf(sbp, SPACELEFT(sbuf, sbp), ", auth=%.30s", p);
9053299c2f1SGregory Neil Shapiro 		sbp += strlen(sbp);
9063299c2f1SGregory Neil Shapiro 	}
9073299c2f1SGregory Neil Shapiro # endif /* SASL */
908c2aa98e2SPeter Wemm 	sm_syslog(LOG_INFO, e->e_id,
909c2aa98e2SPeter Wemm 		  "%.850s, relay=%.100s",
910c2aa98e2SPeter Wemm 		  sbuf, name);
911c2aa98e2SPeter Wemm 
9123299c2f1SGregory Neil Shapiro #else /* (SYSLOG_BUFSIZE) >= 256 */
913c2aa98e2SPeter Wemm 
914c2aa98e2SPeter Wemm 	sm_syslog(LOG_INFO, e->e_id,
915c2aa98e2SPeter Wemm 		  "from=%s",
916c2aa98e2SPeter Wemm 		  e->e_from.q_paddr == NULL ? "<NONE>"
917c2aa98e2SPeter Wemm 					    : shortenstring(e->e_from.q_paddr, 83));
918c2aa98e2SPeter Wemm 	sm_syslog(LOG_INFO, e->e_id,
9193299c2f1SGregory Neil Shapiro 		  "size=%ld, class=%ld, nrcpts=%d",
9203299c2f1SGregory Neil Shapiro 		  e->e_msgsize, e->e_class, e->e_nrcpts);
921c2aa98e2SPeter Wemm 	if (msgid != NULL)
922c2aa98e2SPeter Wemm 		sm_syslog(LOG_INFO, e->e_id,
923c2aa98e2SPeter Wemm 			  "msgid=%s",
924c2aa98e2SPeter Wemm 			  shortenstring(mbuf, 83));
925c2aa98e2SPeter Wemm 	sbp = sbuf;
926c2aa98e2SPeter Wemm 	*sbp = '\0';
927c2aa98e2SPeter Wemm 	if (e->e_bodytype != NULL)
928c2aa98e2SPeter Wemm 	{
929c2aa98e2SPeter Wemm 		snprintf(sbp, SPACELEFT(sbuf, sbp), "bodytype=%.20s, ", e->e_bodytype);
930c2aa98e2SPeter Wemm 		sbp += strlen(sbp);
931c2aa98e2SPeter Wemm 	}
932c2aa98e2SPeter Wemm 	p = macvalue('r', e);
933c2aa98e2SPeter Wemm 	if (p != NULL)
934c2aa98e2SPeter Wemm 	{
935c2aa98e2SPeter Wemm 		snprintf(sbp, SPACELEFT(sbuf, sbp), "proto=%.20s, ", p);
936c2aa98e2SPeter Wemm 		sbp += strlen(sbp);
937c2aa98e2SPeter Wemm 	}
938c2aa98e2SPeter Wemm 	sm_syslog(LOG_INFO, e->e_id,
939c2aa98e2SPeter Wemm 		  "%.400srelay=%.100s", sbuf, name);
9403299c2f1SGregory Neil Shapiro #endif /* (SYSLOG_BUFSIZE) >= 256 */
941c2aa98e2SPeter Wemm }
942c2aa98e2SPeter Wemm /*
943c2aa98e2SPeter Wemm **  PRIENCODE -- encode external priority names into internal values.
944c2aa98e2SPeter Wemm **
945c2aa98e2SPeter Wemm **	Parameters:
946c2aa98e2SPeter Wemm **		p -- priority in ascii.
947c2aa98e2SPeter Wemm **
948c2aa98e2SPeter Wemm **	Returns:
949c2aa98e2SPeter Wemm **		priority as a numeric level.
950c2aa98e2SPeter Wemm **
951c2aa98e2SPeter Wemm **	Side Effects:
952c2aa98e2SPeter Wemm **		none.
953c2aa98e2SPeter Wemm */
954c2aa98e2SPeter Wemm 
9553299c2f1SGregory Neil Shapiro static int
956c2aa98e2SPeter Wemm priencode(p)
957c2aa98e2SPeter Wemm 	char *p;
958c2aa98e2SPeter Wemm {
959c2aa98e2SPeter Wemm 	register int i;
960c2aa98e2SPeter Wemm 
961c2aa98e2SPeter Wemm 	for (i = 0; i < NumPriorities; i++)
962c2aa98e2SPeter Wemm 	{
9633299c2f1SGregory Neil Shapiro 		if (strcasecmp(p, Priorities[i].pri_name) == 0)
9643299c2f1SGregory Neil Shapiro 			return Priorities[i].pri_val;
965c2aa98e2SPeter Wemm 	}
966c2aa98e2SPeter Wemm 
967c2aa98e2SPeter Wemm 	/* unknown priority */
9683299c2f1SGregory Neil Shapiro 	return 0;
969c2aa98e2SPeter Wemm }
970c2aa98e2SPeter Wemm /*
971c2aa98e2SPeter Wemm **  CRACKADDR -- parse an address and turn it into a macro
972c2aa98e2SPeter Wemm **
973c2aa98e2SPeter Wemm **	This doesn't actually parse the address -- it just extracts
974c2aa98e2SPeter Wemm **	it and replaces it with "$g".  The parse is totally ad hoc
975c2aa98e2SPeter Wemm **	and isn't even guaranteed to leave something syntactically
976c2aa98e2SPeter Wemm **	identical to what it started with.  However, it does leave
977c2aa98e2SPeter Wemm **	something semantically identical.
978c2aa98e2SPeter Wemm **
979c2aa98e2SPeter Wemm **	This algorithm has been cleaned up to handle a wider range
980c2aa98e2SPeter Wemm **	of cases -- notably quoted and backslash escaped strings.
981c2aa98e2SPeter Wemm **	This modification makes it substantially better at preserving
982c2aa98e2SPeter Wemm **	the original syntax.
983c2aa98e2SPeter Wemm **
984c2aa98e2SPeter Wemm **	Parameters:
985c2aa98e2SPeter Wemm **		addr -- the address to be cracked.
986c2aa98e2SPeter Wemm **
987c2aa98e2SPeter Wemm **	Returns:
988c2aa98e2SPeter Wemm **		a pointer to the new version.
989c2aa98e2SPeter Wemm **
990c2aa98e2SPeter Wemm **	Side Effects:
991c2aa98e2SPeter Wemm **		none.
992c2aa98e2SPeter Wemm **
993c2aa98e2SPeter Wemm **	Warning:
994c2aa98e2SPeter Wemm **		The return value is saved in local storage and should
995c2aa98e2SPeter Wemm **		be copied if it is to be reused.
996c2aa98e2SPeter Wemm */
997c2aa98e2SPeter Wemm 
998c2aa98e2SPeter Wemm char *
999c2aa98e2SPeter Wemm crackaddr(addr)
1000c2aa98e2SPeter Wemm 	register char *addr;
1001c2aa98e2SPeter Wemm {
1002c2aa98e2SPeter Wemm 	register char *p;
1003c2aa98e2SPeter Wemm 	register char c;
1004c2aa98e2SPeter Wemm 	int cmtlev;
1005c2aa98e2SPeter Wemm 	int realcmtlev;
1006c2aa98e2SPeter Wemm 	int anglelev, realanglelev;
1007c2aa98e2SPeter Wemm 	int copylev;
1008c2aa98e2SPeter Wemm 	int bracklev;
1009c2aa98e2SPeter Wemm 	bool qmode;
1010c2aa98e2SPeter Wemm 	bool realqmode;
1011c2aa98e2SPeter Wemm 	bool skipping;
1012c2aa98e2SPeter Wemm 	bool putgmac = FALSE;
1013c2aa98e2SPeter Wemm 	bool quoteit = FALSE;
1014c2aa98e2SPeter Wemm 	bool gotangle = FALSE;
1015c2aa98e2SPeter Wemm 	bool gotcolon = FALSE;
1016c2aa98e2SPeter Wemm 	register char *bp;
1017c2aa98e2SPeter Wemm 	char *buflim;
1018c2aa98e2SPeter Wemm 	char *bufhead;
1019c2aa98e2SPeter Wemm 	char *addrhead;
1020c2aa98e2SPeter Wemm 	static char buf[MAXNAME + 1];
1021c2aa98e2SPeter Wemm 
1022c2aa98e2SPeter Wemm 	if (tTd(33, 1))
10233299c2f1SGregory Neil Shapiro 		dprintf("crackaddr(%s)\n", addr);
1024c2aa98e2SPeter Wemm 
1025c2aa98e2SPeter Wemm 	/* strip leading spaces */
1026c2aa98e2SPeter Wemm 	while (*addr != '\0' && isascii(*addr) && isspace(*addr))
1027c2aa98e2SPeter Wemm 		addr++;
1028c2aa98e2SPeter Wemm 
1029c2aa98e2SPeter Wemm 	/*
1030c2aa98e2SPeter Wemm 	**  Start by assuming we have no angle brackets.  This will be
1031c2aa98e2SPeter Wemm 	**  adjusted later if we find them.
1032c2aa98e2SPeter Wemm 	*/
1033c2aa98e2SPeter Wemm 
1034c2aa98e2SPeter Wemm 	bp = bufhead = buf;
1035c2aa98e2SPeter Wemm 	buflim = &buf[sizeof buf - 7];
1036c2aa98e2SPeter Wemm 	p = addrhead = addr;
1037c2aa98e2SPeter Wemm 	copylev = anglelev = realanglelev = cmtlev = realcmtlev = 0;
1038c2aa98e2SPeter Wemm 	bracklev = 0;
1039c2aa98e2SPeter Wemm 	qmode = realqmode = FALSE;
1040c2aa98e2SPeter Wemm 
1041c2aa98e2SPeter Wemm 	while ((c = *p++) != '\0')
1042c2aa98e2SPeter Wemm 	{
1043c2aa98e2SPeter Wemm 		/*
1044c2aa98e2SPeter Wemm 		**  If the buffer is overful, go into a special "skipping"
1045c2aa98e2SPeter Wemm 		**  mode that tries to keep legal syntax but doesn't actually
1046c2aa98e2SPeter Wemm 		**  output things.
1047c2aa98e2SPeter Wemm 		*/
1048c2aa98e2SPeter Wemm 
1049c2aa98e2SPeter Wemm 		skipping = bp >= buflim;
1050c2aa98e2SPeter Wemm 
1051c2aa98e2SPeter Wemm 		if (copylev > 0 && !skipping)
1052c2aa98e2SPeter Wemm 			*bp++ = c;
1053c2aa98e2SPeter Wemm 
1054c2aa98e2SPeter Wemm 		/* check for backslash escapes */
1055c2aa98e2SPeter Wemm 		if (c == '\\')
1056c2aa98e2SPeter Wemm 		{
1057c2aa98e2SPeter Wemm 			/* arrange to quote the address */
1058c2aa98e2SPeter Wemm 			if (cmtlev <= 0 && !qmode)
1059c2aa98e2SPeter Wemm 				quoteit = TRUE;
1060c2aa98e2SPeter Wemm 
1061c2aa98e2SPeter Wemm 			if ((c = *p++) == '\0')
1062c2aa98e2SPeter Wemm 			{
1063c2aa98e2SPeter Wemm 				/* too far */
1064c2aa98e2SPeter Wemm 				p--;
1065c2aa98e2SPeter Wemm 				goto putg;
1066c2aa98e2SPeter Wemm 			}
1067c2aa98e2SPeter Wemm 			if (copylev > 0 && !skipping)
1068c2aa98e2SPeter Wemm 				*bp++ = c;
1069c2aa98e2SPeter Wemm 			goto putg;
1070c2aa98e2SPeter Wemm 		}
1071c2aa98e2SPeter Wemm 
1072c2aa98e2SPeter Wemm 		/* check for quoted strings */
1073c2aa98e2SPeter Wemm 		if (c == '"' && cmtlev <= 0)
1074c2aa98e2SPeter Wemm 		{
1075c2aa98e2SPeter Wemm 			qmode = !qmode;
1076c2aa98e2SPeter Wemm 			if (copylev > 0 && !skipping)
1077c2aa98e2SPeter Wemm 				realqmode = !realqmode;
1078c2aa98e2SPeter Wemm 			continue;
1079c2aa98e2SPeter Wemm 		}
1080c2aa98e2SPeter Wemm 		if (qmode)
1081c2aa98e2SPeter Wemm 			goto putg;
1082c2aa98e2SPeter Wemm 
1083c2aa98e2SPeter Wemm 		/* check for comments */
1084c2aa98e2SPeter Wemm 		if (c == '(')
1085c2aa98e2SPeter Wemm 		{
1086c2aa98e2SPeter Wemm 			cmtlev++;
1087c2aa98e2SPeter Wemm 
1088c2aa98e2SPeter Wemm 			/* allow space for closing paren */
1089c2aa98e2SPeter Wemm 			if (!skipping)
1090c2aa98e2SPeter Wemm 			{
1091c2aa98e2SPeter Wemm 				buflim--;
1092c2aa98e2SPeter Wemm 				realcmtlev++;
1093c2aa98e2SPeter Wemm 				if (copylev++ <= 0)
1094c2aa98e2SPeter Wemm 				{
1095c2aa98e2SPeter Wemm 					if (bp != bufhead)
1096c2aa98e2SPeter Wemm 						*bp++ = ' ';
1097c2aa98e2SPeter Wemm 					*bp++ = c;
1098c2aa98e2SPeter Wemm 				}
1099c2aa98e2SPeter Wemm 			}
1100c2aa98e2SPeter Wemm 		}
1101c2aa98e2SPeter Wemm 		if (cmtlev > 0)
1102c2aa98e2SPeter Wemm 		{
1103c2aa98e2SPeter Wemm 			if (c == ')')
1104c2aa98e2SPeter Wemm 			{
1105c2aa98e2SPeter Wemm 				cmtlev--;
1106c2aa98e2SPeter Wemm 				copylev--;
1107c2aa98e2SPeter Wemm 				if (!skipping)
1108c2aa98e2SPeter Wemm 				{
1109c2aa98e2SPeter Wemm 					realcmtlev--;
1110c2aa98e2SPeter Wemm 					buflim++;
1111c2aa98e2SPeter Wemm 				}
1112c2aa98e2SPeter Wemm 			}
1113c2aa98e2SPeter Wemm 			continue;
1114c2aa98e2SPeter Wemm 		}
1115c2aa98e2SPeter Wemm 		else if (c == ')')
1116c2aa98e2SPeter Wemm 		{
1117c2aa98e2SPeter Wemm 			/* syntax error: unmatched ) */
1118c2aa98e2SPeter Wemm 			if (copylev > 0 && !skipping)
1119c2aa98e2SPeter Wemm 				bp--;
1120c2aa98e2SPeter Wemm 		}
1121c2aa98e2SPeter Wemm 
1122c2aa98e2SPeter Wemm 		/* count nesting on [ ... ] (for IPv6 domain literals) */
1123c2aa98e2SPeter Wemm 		if (c == '[')
1124c2aa98e2SPeter Wemm 			bracklev++;
1125c2aa98e2SPeter Wemm 		else if (c == ']')
1126c2aa98e2SPeter Wemm 			bracklev--;
1127c2aa98e2SPeter Wemm 
1128c2aa98e2SPeter Wemm 		/* check for group: list; syntax */
1129c2aa98e2SPeter Wemm 		if (c == ':' && anglelev <= 0 && bracklev <= 0 &&
1130c2aa98e2SPeter Wemm 		    !gotcolon && !ColonOkInAddr)
1131c2aa98e2SPeter Wemm 		{
1132c2aa98e2SPeter Wemm 			register char *q;
1133c2aa98e2SPeter Wemm 
1134c2aa98e2SPeter Wemm 			/*
1135c2aa98e2SPeter Wemm 			**  Check for DECnet phase IV ``::'' (host::user)
1136c2aa98e2SPeter Wemm 			**  or **  DECnet phase V ``:.'' syntaxes.  The latter
1137c2aa98e2SPeter Wemm 			**  covers ``user@DEC:.tay.myhost'' and
1138c2aa98e2SPeter Wemm 			**  ``DEC:.tay.myhost::user'' syntaxes (bletch).
1139c2aa98e2SPeter Wemm 			*/
1140c2aa98e2SPeter Wemm 
1141c2aa98e2SPeter Wemm 			if (*p == ':' || *p == '.')
1142c2aa98e2SPeter Wemm 			{
1143c2aa98e2SPeter Wemm 				if (cmtlev <= 0 && !qmode)
1144c2aa98e2SPeter Wemm 					quoteit = TRUE;
1145c2aa98e2SPeter Wemm 				if (copylev > 0 && !skipping)
1146c2aa98e2SPeter Wemm 				{
1147c2aa98e2SPeter Wemm 					*bp++ = c;
1148c2aa98e2SPeter Wemm 					*bp++ = *p;
1149c2aa98e2SPeter Wemm 				}
1150c2aa98e2SPeter Wemm 				p++;
1151c2aa98e2SPeter Wemm 				goto putg;
1152c2aa98e2SPeter Wemm 			}
1153c2aa98e2SPeter Wemm 
1154c2aa98e2SPeter Wemm 			gotcolon = TRUE;
1155c2aa98e2SPeter Wemm 
1156c2aa98e2SPeter Wemm 			bp = bufhead;
1157c2aa98e2SPeter Wemm 			if (quoteit)
1158c2aa98e2SPeter Wemm 			{
1159c2aa98e2SPeter Wemm 				*bp++ = '"';
1160c2aa98e2SPeter Wemm 
1161c2aa98e2SPeter Wemm 				/* back up over the ':' and any spaces */
1162c2aa98e2SPeter Wemm 				--p;
1163c2aa98e2SPeter Wemm 				while (isascii(*--p) && isspace(*p))
1164c2aa98e2SPeter Wemm 					continue;
1165c2aa98e2SPeter Wemm 				p++;
1166c2aa98e2SPeter Wemm 			}
1167c2aa98e2SPeter Wemm 			for (q = addrhead; q < p; )
1168c2aa98e2SPeter Wemm 			{
1169c2aa98e2SPeter Wemm 				c = *q++;
1170c2aa98e2SPeter Wemm 				if (bp < buflim)
1171c2aa98e2SPeter Wemm 				{
1172c2aa98e2SPeter Wemm 					if (quoteit && c == '"')
1173c2aa98e2SPeter Wemm 						*bp++ = '\\';
1174c2aa98e2SPeter Wemm 					*bp++ = c;
1175c2aa98e2SPeter Wemm 				}
1176c2aa98e2SPeter Wemm 			}
1177c2aa98e2SPeter Wemm 			if (quoteit)
1178c2aa98e2SPeter Wemm 			{
1179c2aa98e2SPeter Wemm 				if (bp == &bufhead[1])
1180c2aa98e2SPeter Wemm 					bp--;
1181c2aa98e2SPeter Wemm 				else
1182c2aa98e2SPeter Wemm 					*bp++ = '"';
1183c2aa98e2SPeter Wemm 				while ((c = *p++) != ':')
1184c2aa98e2SPeter Wemm 				{
1185c2aa98e2SPeter Wemm 					if (bp < buflim)
1186c2aa98e2SPeter Wemm 						*bp++ = c;
1187c2aa98e2SPeter Wemm 				}
1188c2aa98e2SPeter Wemm 				*bp++ = c;
1189c2aa98e2SPeter Wemm 			}
1190c2aa98e2SPeter Wemm 
1191c2aa98e2SPeter Wemm 			/* any trailing white space is part of group: */
1192c2aa98e2SPeter Wemm 			while (isascii(*p) && isspace(*p) && bp < buflim)
1193c2aa98e2SPeter Wemm 				*bp++ = *p++;
1194c2aa98e2SPeter Wemm 			copylev = 0;
1195c2aa98e2SPeter Wemm 			putgmac = quoteit = FALSE;
1196c2aa98e2SPeter Wemm 			bufhead = bp;
1197c2aa98e2SPeter Wemm 			addrhead = p;
1198c2aa98e2SPeter Wemm 			continue;
1199c2aa98e2SPeter Wemm 		}
1200c2aa98e2SPeter Wemm 
1201c2aa98e2SPeter Wemm 		if (c == ';' && copylev <= 0 && !ColonOkInAddr)
1202c2aa98e2SPeter Wemm 		{
1203c2aa98e2SPeter Wemm 			if (bp < buflim)
1204c2aa98e2SPeter Wemm 				*bp++ = c;
1205c2aa98e2SPeter Wemm 		}
1206c2aa98e2SPeter Wemm 
1207c2aa98e2SPeter Wemm 		/* check for characters that may have to be quoted */
1208c2aa98e2SPeter Wemm 		if (strchr(MustQuoteChars, c) != NULL)
1209c2aa98e2SPeter Wemm 		{
1210c2aa98e2SPeter Wemm 			/*
1211c2aa98e2SPeter Wemm 			**  If these occur as the phrase part of a <>
1212c2aa98e2SPeter Wemm 			**  construct, but are not inside of () or already
1213c2aa98e2SPeter Wemm 			**  quoted, they will have to be quoted.  Note that
1214c2aa98e2SPeter Wemm 			**  now (but don't actually do the quoting).
1215c2aa98e2SPeter Wemm 			*/
1216c2aa98e2SPeter Wemm 
1217c2aa98e2SPeter Wemm 			if (cmtlev <= 0 && !qmode)
1218c2aa98e2SPeter Wemm 				quoteit = TRUE;
1219c2aa98e2SPeter Wemm 		}
1220c2aa98e2SPeter Wemm 
1221c2aa98e2SPeter Wemm 		/* check for angle brackets */
1222c2aa98e2SPeter Wemm 		if (c == '<')
1223c2aa98e2SPeter Wemm 		{
1224c2aa98e2SPeter Wemm 			register char *q;
1225c2aa98e2SPeter Wemm 
1226c2aa98e2SPeter Wemm 			/* assume first of two angles is bogus */
1227c2aa98e2SPeter Wemm 			if (gotangle)
1228c2aa98e2SPeter Wemm 				quoteit = TRUE;
1229c2aa98e2SPeter Wemm 			gotangle = TRUE;
1230c2aa98e2SPeter Wemm 
1231c2aa98e2SPeter Wemm 			/* oops -- have to change our mind */
1232c2aa98e2SPeter Wemm 			anglelev = 1;
1233c2aa98e2SPeter Wemm 			if (!skipping)
1234c2aa98e2SPeter Wemm 				realanglelev = 1;
1235c2aa98e2SPeter Wemm 
1236c2aa98e2SPeter Wemm 			bp = bufhead;
1237c2aa98e2SPeter Wemm 			if (quoteit)
1238c2aa98e2SPeter Wemm 			{
1239c2aa98e2SPeter Wemm 				*bp++ = '"';
1240c2aa98e2SPeter Wemm 
1241c2aa98e2SPeter Wemm 				/* back up over the '<' and any spaces */
1242c2aa98e2SPeter Wemm 				--p;
1243c2aa98e2SPeter Wemm 				while (isascii(*--p) && isspace(*p))
1244c2aa98e2SPeter Wemm 					continue;
1245c2aa98e2SPeter Wemm 				p++;
1246c2aa98e2SPeter Wemm 			}
1247c2aa98e2SPeter Wemm 			for (q = addrhead; q < p; )
1248c2aa98e2SPeter Wemm 			{
1249c2aa98e2SPeter Wemm 				c = *q++;
1250c2aa98e2SPeter Wemm 				if (bp < buflim)
1251c2aa98e2SPeter Wemm 				{
1252c2aa98e2SPeter Wemm 					if (quoteit && c == '"')
1253c2aa98e2SPeter Wemm 						*bp++ = '\\';
1254c2aa98e2SPeter Wemm 					*bp++ = c;
1255c2aa98e2SPeter Wemm 				}
1256c2aa98e2SPeter Wemm 			}
1257c2aa98e2SPeter Wemm 			if (quoteit)
1258c2aa98e2SPeter Wemm 			{
1259c2aa98e2SPeter Wemm 				if (bp == &buf[1])
1260c2aa98e2SPeter Wemm 					bp--;
1261c2aa98e2SPeter Wemm 				else
1262c2aa98e2SPeter Wemm 					*bp++ = '"';
1263c2aa98e2SPeter Wemm 				while ((c = *p++) != '<')
1264c2aa98e2SPeter Wemm 				{
1265c2aa98e2SPeter Wemm 					if (bp < buflim)
1266c2aa98e2SPeter Wemm 						*bp++ = c;
1267c2aa98e2SPeter Wemm 				}
1268c2aa98e2SPeter Wemm 				*bp++ = c;
1269c2aa98e2SPeter Wemm 			}
1270c2aa98e2SPeter Wemm 			copylev = 0;
1271c2aa98e2SPeter Wemm 			putgmac = quoteit = FALSE;
1272c2aa98e2SPeter Wemm 			continue;
1273c2aa98e2SPeter Wemm 		}
1274c2aa98e2SPeter Wemm 
1275c2aa98e2SPeter Wemm 		if (c == '>')
1276c2aa98e2SPeter Wemm 		{
1277c2aa98e2SPeter Wemm 			if (anglelev > 0)
1278c2aa98e2SPeter Wemm 			{
1279c2aa98e2SPeter Wemm 				anglelev--;
1280c2aa98e2SPeter Wemm 				if (!skipping)
1281c2aa98e2SPeter Wemm 				{
1282c2aa98e2SPeter Wemm 					realanglelev--;
1283c2aa98e2SPeter Wemm 					buflim++;
1284c2aa98e2SPeter Wemm 				}
1285c2aa98e2SPeter Wemm 			}
1286c2aa98e2SPeter Wemm 			else if (!skipping)
1287c2aa98e2SPeter Wemm 			{
1288c2aa98e2SPeter Wemm 				/* syntax error: unmatched > */
1289c2aa98e2SPeter Wemm 				if (copylev > 0)
1290c2aa98e2SPeter Wemm 					bp--;
1291c2aa98e2SPeter Wemm 				quoteit = TRUE;
1292c2aa98e2SPeter Wemm 				continue;
1293c2aa98e2SPeter Wemm 			}
1294c2aa98e2SPeter Wemm 			if (copylev++ <= 0)
1295c2aa98e2SPeter Wemm 				*bp++ = c;
1296c2aa98e2SPeter Wemm 			continue;
1297c2aa98e2SPeter Wemm 		}
1298c2aa98e2SPeter Wemm 
1299c2aa98e2SPeter Wemm 		/* must be a real address character */
1300c2aa98e2SPeter Wemm 	putg:
1301c2aa98e2SPeter Wemm 		if (copylev <= 0 && !putgmac)
1302c2aa98e2SPeter Wemm 		{
1303c2aa98e2SPeter Wemm 			if (bp > bufhead && bp[-1] == ')')
1304c2aa98e2SPeter Wemm 				*bp++ = ' ';
1305c2aa98e2SPeter Wemm 			*bp++ = MACROEXPAND;
1306c2aa98e2SPeter Wemm 			*bp++ = 'g';
1307c2aa98e2SPeter Wemm 			putgmac = TRUE;
1308c2aa98e2SPeter Wemm 		}
1309c2aa98e2SPeter Wemm 	}
1310c2aa98e2SPeter Wemm 
1311c2aa98e2SPeter Wemm 	/* repair any syntactic damage */
1312c2aa98e2SPeter Wemm 	if (realqmode)
1313c2aa98e2SPeter Wemm 		*bp++ = '"';
1314c2aa98e2SPeter Wemm 	while (realcmtlev-- > 0)
1315c2aa98e2SPeter Wemm 		*bp++ = ')';
1316c2aa98e2SPeter Wemm 	while (realanglelev-- > 0)
1317c2aa98e2SPeter Wemm 		*bp++ = '>';
1318c2aa98e2SPeter Wemm 	*bp++ = '\0';
1319c2aa98e2SPeter Wemm 
1320c2aa98e2SPeter Wemm 	if (tTd(33, 1))
1321c2aa98e2SPeter Wemm 	{
13223299c2f1SGregory Neil Shapiro 		dprintf("crackaddr=>`");
1323c2aa98e2SPeter Wemm 		xputs(buf);
13243299c2f1SGregory Neil Shapiro 		dprintf("'\n");
1325c2aa98e2SPeter Wemm 	}
1326c2aa98e2SPeter Wemm 
13273299c2f1SGregory Neil Shapiro 	return buf;
1328c2aa98e2SPeter Wemm }
1329c2aa98e2SPeter Wemm /*
1330c2aa98e2SPeter Wemm **  PUTHEADER -- put the header part of a message from the in-core copy
1331c2aa98e2SPeter Wemm **
1332c2aa98e2SPeter Wemm **	Parameters:
1333c2aa98e2SPeter Wemm **		mci -- the connection information.
13343299c2f1SGregory Neil Shapiro **		hdr -- the header to put.
1335c2aa98e2SPeter Wemm **		e -- envelope to use.
1336e01d6f61SPeter Wemm **		flags -- MIME conversion flags.
1337c2aa98e2SPeter Wemm **
1338c2aa98e2SPeter Wemm **	Returns:
1339c2aa98e2SPeter Wemm **		none.
1340c2aa98e2SPeter Wemm **
1341c2aa98e2SPeter Wemm **	Side Effects:
1342c2aa98e2SPeter Wemm **		none.
1343c2aa98e2SPeter Wemm */
1344c2aa98e2SPeter Wemm 
1345c2aa98e2SPeter Wemm /*
1346c2aa98e2SPeter Wemm  * Macro for fast max (not available in e.g. DG/UX, 386/ix).
1347c2aa98e2SPeter Wemm  */
1348c2aa98e2SPeter Wemm #ifndef MAX
1349c2aa98e2SPeter Wemm # define MAX(a,b) (((a)>(b))?(a):(b))
13503299c2f1SGregory Neil Shapiro #endif /* ! MAX */
1351c2aa98e2SPeter Wemm 
1352c2aa98e2SPeter Wemm void
1353e01d6f61SPeter Wemm putheader(mci, hdr, e, flags)
1354c2aa98e2SPeter Wemm 	register MCI *mci;
1355c2aa98e2SPeter Wemm 	HDR *hdr;
1356c2aa98e2SPeter Wemm 	register ENVELOPE *e;
1357e01d6f61SPeter Wemm 	int flags;
1358c2aa98e2SPeter Wemm {
1359c2aa98e2SPeter Wemm 	register HDR *h;
1360c2aa98e2SPeter Wemm 	char buf[MAX(MAXLINE,BUFSIZ)];
1361c2aa98e2SPeter Wemm 	char obuf[MAXLINE];
1362c2aa98e2SPeter Wemm 
1363c2aa98e2SPeter Wemm 	if (tTd(34, 1))
13643299c2f1SGregory Neil Shapiro 		dprintf("--- putheader, mailer = %s ---\n",
1365c2aa98e2SPeter Wemm 			mci->mci_mailer->m_name);
1366c2aa98e2SPeter Wemm 
1367c2aa98e2SPeter Wemm 	/*
1368c2aa98e2SPeter Wemm 	**  If we're in MIME mode, we're not really in the header of the
1369c2aa98e2SPeter Wemm 	**  message, just the header of one of the parts of the body of
1370c2aa98e2SPeter Wemm 	**  the message.  Therefore MCIF_INHEADER should not be turned on.
1371c2aa98e2SPeter Wemm 	*/
1372c2aa98e2SPeter Wemm 
1373c2aa98e2SPeter Wemm 	if (!bitset(MCIF_INMIME, mci->mci_flags))
1374c2aa98e2SPeter Wemm 		mci->mci_flags |= MCIF_INHEADER;
1375c2aa98e2SPeter Wemm 
1376c2aa98e2SPeter Wemm 	for (h = hdr; h != NULL; h = h->h_link)
1377c2aa98e2SPeter Wemm 	{
1378c2aa98e2SPeter Wemm 		register char *p = h->h_value;
1379c2aa98e2SPeter Wemm 
1380c2aa98e2SPeter Wemm 		if (tTd(34, 11))
1381c2aa98e2SPeter Wemm 		{
13823299c2f1SGregory Neil Shapiro 			dprintf("  %s: ", h->h_field);
1383c2aa98e2SPeter Wemm 			xputs(p);
1384c2aa98e2SPeter Wemm 		}
1385c2aa98e2SPeter Wemm 
13863299c2f1SGregory Neil Shapiro 		/* Skip empty headers */
13873299c2f1SGregory Neil Shapiro 		if (h->h_value == NULL)
13883299c2f1SGregory Neil Shapiro 			continue;
13893299c2f1SGregory Neil Shapiro 
139076b7bf71SPeter Wemm 		/* heuristic shortening of MIME fields to avoid MUA overflows */
139176b7bf71SPeter Wemm 		if (MaxMimeFieldLength > 0 &&
139276b7bf71SPeter Wemm 		    wordinclass(h->h_field,
139376b7bf71SPeter Wemm 				macid("{checkMIMEFieldHeaders}", NULL)))
139476b7bf71SPeter Wemm 		{
139576b7bf71SPeter Wemm 			if (fix_mime_header(h->h_value))
139676b7bf71SPeter Wemm 			{
139776b7bf71SPeter Wemm 				sm_syslog(LOG_ALERT, e->e_id,
139876b7bf71SPeter Wemm 					  "Truncated MIME %s header due to field size (possible attack)",
139976b7bf71SPeter Wemm 					  h->h_field);
140076b7bf71SPeter Wemm 				if (tTd(34, 11))
14013299c2f1SGregory Neil Shapiro 					dprintf("  truncated MIME %s header due to field size (possible attack)\n",
140276b7bf71SPeter Wemm 						h->h_field);
140376b7bf71SPeter Wemm 			}
140476b7bf71SPeter Wemm 		}
140576b7bf71SPeter Wemm 
140676b7bf71SPeter Wemm 		if (MaxMimeHeaderLength > 0 &&
140776b7bf71SPeter Wemm 		    wordinclass(h->h_field,
140876b7bf71SPeter Wemm 				macid("{checkMIMETextHeaders}", NULL)))
140976b7bf71SPeter Wemm 		{
14103299c2f1SGregory Neil Shapiro 			if (strlen(h->h_value) > (size_t)MaxMimeHeaderLength)
141176b7bf71SPeter Wemm 			{
141276b7bf71SPeter Wemm 				h->h_value[MaxMimeHeaderLength - 1] = '\0';
141376b7bf71SPeter Wemm 				sm_syslog(LOG_ALERT, e->e_id,
141476b7bf71SPeter Wemm 					  "Truncated long MIME %s header (possible attack)",
141576b7bf71SPeter Wemm 					  h->h_field);
141676b7bf71SPeter Wemm 				if (tTd(34, 11))
14173299c2f1SGregory Neil Shapiro 					dprintf("  truncated long MIME %s header (possible attack)\n",
141876b7bf71SPeter Wemm 						h->h_field);
141976b7bf71SPeter Wemm 			}
142076b7bf71SPeter Wemm 		}
142176b7bf71SPeter Wemm 
142276b7bf71SPeter Wemm 		if (MaxMimeHeaderLength > 0 &&
142376b7bf71SPeter Wemm 		    wordinclass(h->h_field,
142476b7bf71SPeter Wemm 				macid("{checkMIMEHeaders}", NULL)))
142576b7bf71SPeter Wemm 		{
142676b7bf71SPeter Wemm 			if (shorten_rfc822_string(h->h_value, MaxMimeHeaderLength))
142776b7bf71SPeter Wemm 			{
142876b7bf71SPeter Wemm 				sm_syslog(LOG_ALERT, e->e_id,
142976b7bf71SPeter Wemm 					  "Truncated long MIME %s header (possible attack)",
143076b7bf71SPeter Wemm 					  h->h_field);
143176b7bf71SPeter Wemm 				if (tTd(34, 11))
14323299c2f1SGregory Neil Shapiro 					dprintf("  truncated long MIME %s header (possible attack)\n",
143376b7bf71SPeter Wemm 						h->h_field);
143476b7bf71SPeter Wemm 			}
143576b7bf71SPeter Wemm 		}
143676b7bf71SPeter Wemm 
1437e01d6f61SPeter Wemm 		/*
1438e01d6f61SPeter Wemm 		**  Suppress Content-Transfer-Encoding: if we are MIMEing
1439e01d6f61SPeter Wemm 		**  and we are potentially converting from 8 bit to 7 bit
1440e01d6f61SPeter Wemm 		**  MIME.  If converting, add a new CTE header in
1441e01d6f61SPeter Wemm 		**  mime8to7().
1442e01d6f61SPeter Wemm 		*/
1443c2aa98e2SPeter Wemm 		if (bitset(H_CTE, h->h_flags) &&
1444e01d6f61SPeter Wemm 		    bitset(MCIF_CVT8TO7|MCIF_CVT7TO8|MCIF_INMIME,
1445e01d6f61SPeter Wemm 			   mci->mci_flags) &&
1446e01d6f61SPeter Wemm 		    !bitset(M87F_NO8TO7, flags))
1447c2aa98e2SPeter Wemm 		{
1448c2aa98e2SPeter Wemm 			if (tTd(34, 11))
14493299c2f1SGregory Neil Shapiro 				dprintf(" (skipped (content-transfer-encoding))\n");
1450c2aa98e2SPeter Wemm 			continue;
1451c2aa98e2SPeter Wemm 		}
1452c2aa98e2SPeter Wemm 
1453c2aa98e2SPeter Wemm 		if (bitset(MCIF_INMIME, mci->mci_flags))
1454c2aa98e2SPeter Wemm 		{
1455c2aa98e2SPeter Wemm 			if (tTd(34, 11))
14563299c2f1SGregory Neil Shapiro 				dprintf("\n");
1457c2aa98e2SPeter Wemm 			put_vanilla_header(h, p, mci);
1458c2aa98e2SPeter Wemm 			continue;
1459c2aa98e2SPeter Wemm 		}
1460c2aa98e2SPeter Wemm 
1461c2aa98e2SPeter Wemm 		if (bitset(H_CHECK|H_ACHECK, h->h_flags) &&
14623299c2f1SGregory Neil Shapiro 		    !bitintersect(h->h_mflags, mci->mci_mailer->m_flags) &&
14633299c2f1SGregory Neil Shapiro 		    (h->h_macro == '\0' ||
14643299c2f1SGregory Neil Shapiro 		     macvalue(h->h_macro & 0377, e) == NULL))
1465c2aa98e2SPeter Wemm 		{
1466c2aa98e2SPeter Wemm 			if (tTd(34, 11))
14673299c2f1SGregory Neil Shapiro 				dprintf(" (skipped)\n");
1468c2aa98e2SPeter Wemm 			continue;
1469c2aa98e2SPeter Wemm 		}
1470c2aa98e2SPeter Wemm 
1471c2aa98e2SPeter Wemm 		/* handle Resent-... headers specially */
1472c2aa98e2SPeter Wemm 		if (bitset(H_RESENT, h->h_flags) && !bitset(EF_RESENT, e->e_flags))
1473c2aa98e2SPeter Wemm 		{
1474c2aa98e2SPeter Wemm 			if (tTd(34, 11))
14753299c2f1SGregory Neil Shapiro 				dprintf(" (skipped (resent))\n");
1476c2aa98e2SPeter Wemm 			continue;
1477c2aa98e2SPeter Wemm 		}
1478c2aa98e2SPeter Wemm 
1479c2aa98e2SPeter Wemm 		/* suppress return receipts if requested */
1480c2aa98e2SPeter Wemm 		if (bitset(H_RECEIPTTO, h->h_flags) &&
1481c2aa98e2SPeter Wemm 		    (RrtImpliesDsn || bitset(EF_NORECEIPT, e->e_flags)))
1482c2aa98e2SPeter Wemm 		{
1483c2aa98e2SPeter Wemm 			if (tTd(34, 11))
14843299c2f1SGregory Neil Shapiro 				dprintf(" (skipped (receipt))\n");
1485c2aa98e2SPeter Wemm 			continue;
1486c2aa98e2SPeter Wemm 		}
1487c2aa98e2SPeter Wemm 
1488c2aa98e2SPeter Wemm 		/* macro expand value if generated internally */
14893299c2f1SGregory Neil Shapiro 		if (bitset(H_DEFAULT, h->h_flags) ||
14903299c2f1SGregory Neil Shapiro 		    bitset(H_BINDLATE, h->h_flags))
1491c2aa98e2SPeter Wemm 		{
1492c2aa98e2SPeter Wemm 			expand(p, buf, sizeof buf, e);
1493c2aa98e2SPeter Wemm 			p = buf;
1494c2aa98e2SPeter Wemm 			if (*p == '\0')
1495c2aa98e2SPeter Wemm 			{
1496c2aa98e2SPeter Wemm 				if (tTd(34, 11))
14973299c2f1SGregory Neil Shapiro 					dprintf(" (skipped -- null value)\n");
1498c2aa98e2SPeter Wemm 				continue;
1499c2aa98e2SPeter Wemm 			}
1500c2aa98e2SPeter Wemm 		}
1501c2aa98e2SPeter Wemm 
1502c2aa98e2SPeter Wemm 		if (bitset(H_BCC, h->h_flags))
1503c2aa98e2SPeter Wemm 		{
1504c2aa98e2SPeter Wemm 			/* Bcc: field -- either truncate or delete */
1505c2aa98e2SPeter Wemm 			if (bitset(EF_DELETE_BCC, e->e_flags))
1506c2aa98e2SPeter Wemm 			{
1507c2aa98e2SPeter Wemm 				if (tTd(34, 11))
15083299c2f1SGregory Neil Shapiro 					dprintf(" (skipped -- bcc)\n");
1509c2aa98e2SPeter Wemm 			}
1510c2aa98e2SPeter Wemm 			else
1511c2aa98e2SPeter Wemm 			{
1512c2aa98e2SPeter Wemm 				/* no other recipient headers: truncate value */
1513c2aa98e2SPeter Wemm 				(void) snprintf(obuf, sizeof obuf, "%s:",
1514c2aa98e2SPeter Wemm 					h->h_field);
1515c2aa98e2SPeter Wemm 				putline(obuf, mci);
1516c2aa98e2SPeter Wemm 			}
1517c2aa98e2SPeter Wemm 			continue;
1518c2aa98e2SPeter Wemm 		}
1519c2aa98e2SPeter Wemm 
1520c2aa98e2SPeter Wemm 		if (tTd(34, 11))
15213299c2f1SGregory Neil Shapiro 			dprintf("\n");
1522c2aa98e2SPeter Wemm 
1523c2aa98e2SPeter Wemm 		if (bitset(H_FROM|H_RCPT, h->h_flags))
1524c2aa98e2SPeter Wemm 		{
1525c2aa98e2SPeter Wemm 			/* address field */
1526c2aa98e2SPeter Wemm 			bool oldstyle = bitset(EF_OLDSTYLE, e->e_flags);
1527c2aa98e2SPeter Wemm 
1528c2aa98e2SPeter Wemm 			if (bitset(H_FROM, h->h_flags))
1529c2aa98e2SPeter Wemm 				oldstyle = FALSE;
1530c2aa98e2SPeter Wemm 			commaize(h, p, oldstyle, mci, e);
1531c2aa98e2SPeter Wemm 		}
1532c2aa98e2SPeter Wemm 		else
1533c2aa98e2SPeter Wemm 		{
1534c2aa98e2SPeter Wemm 			put_vanilla_header(h, p, mci);
1535c2aa98e2SPeter Wemm 		}
1536c2aa98e2SPeter Wemm 	}
1537c2aa98e2SPeter Wemm 
1538c2aa98e2SPeter Wemm 	/*
1539c2aa98e2SPeter Wemm 	**  If we are converting this to a MIME message, add the
15403299c2f1SGregory Neil Shapiro 	**  MIME headers (but not in MIME mode!).
1541c2aa98e2SPeter Wemm 	*/
1542c2aa98e2SPeter Wemm 
1543c2aa98e2SPeter Wemm #if MIME8TO7
1544c2aa98e2SPeter Wemm 	if (bitset(MM_MIME8BIT, MimeMode) &&
1545c2aa98e2SPeter Wemm 	    bitset(EF_HAS8BIT, e->e_flags) &&
1546c2aa98e2SPeter Wemm 	    !bitset(EF_DONT_MIME, e->e_flags) &&
1547c2aa98e2SPeter Wemm 	    !bitnset(M_8BITS, mci->mci_mailer->m_flags) &&
15483299c2f1SGregory Neil Shapiro 	    !bitset(MCIF_CVT8TO7|MCIF_CVT7TO8|MCIF_INMIME, mci->mci_flags) &&
15493299c2f1SGregory Neil Shapiro 	    hvalue("MIME-Version", e->e_header) == NULL)
1550c2aa98e2SPeter Wemm 	{
1551c2aa98e2SPeter Wemm 		putline("MIME-Version: 1.0", mci);
1552c2aa98e2SPeter Wemm 		if (hvalue("Content-Type", e->e_header) == NULL)
1553c2aa98e2SPeter Wemm 		{
1554c2aa98e2SPeter Wemm 			snprintf(obuf, sizeof obuf,
1555c2aa98e2SPeter Wemm 				"Content-Type: text/plain; charset=%s",
1556c2aa98e2SPeter Wemm 				defcharset(e));
1557c2aa98e2SPeter Wemm 			putline(obuf, mci);
1558c2aa98e2SPeter Wemm 		}
1559c2aa98e2SPeter Wemm 		if (hvalue("Content-Transfer-Encoding", e->e_header) == NULL)
1560c2aa98e2SPeter Wemm 			putline("Content-Transfer-Encoding: 8bit", mci);
1561c2aa98e2SPeter Wemm 	}
15623299c2f1SGregory Neil Shapiro #endif /* MIME8TO7 */
1563c2aa98e2SPeter Wemm }
1564c2aa98e2SPeter Wemm /*
1565c2aa98e2SPeter Wemm **  PUT_VANILLA_HEADER -- output a fairly ordinary header
1566c2aa98e2SPeter Wemm **
1567c2aa98e2SPeter Wemm **	Parameters:
1568c2aa98e2SPeter Wemm **		h -- the structure describing this header
1569c2aa98e2SPeter Wemm **		v -- the value of this header
1570c2aa98e2SPeter Wemm **		mci -- the connection info for output
1571c2aa98e2SPeter Wemm **
1572c2aa98e2SPeter Wemm **	Returns:
1573c2aa98e2SPeter Wemm **		none.
1574c2aa98e2SPeter Wemm */
1575c2aa98e2SPeter Wemm 
15763299c2f1SGregory Neil Shapiro static void
1577c2aa98e2SPeter Wemm put_vanilla_header(h, v, mci)
1578c2aa98e2SPeter Wemm 	HDR *h;
1579c2aa98e2SPeter Wemm 	char *v;
1580c2aa98e2SPeter Wemm 	MCI *mci;
1581c2aa98e2SPeter Wemm {
1582c2aa98e2SPeter Wemm 	register char *nlp;
1583c2aa98e2SPeter Wemm 	register char *obp;
1584c2aa98e2SPeter Wemm 	int putflags;
1585c2aa98e2SPeter Wemm 	char obuf[MAXLINE];
1586c2aa98e2SPeter Wemm 
1587c2aa98e2SPeter Wemm 	putflags = PXLF_HEADER;
1588c2aa98e2SPeter Wemm 	if (bitnset(M_7BITHDRS, mci->mci_mailer->m_flags))
1589c2aa98e2SPeter Wemm 		putflags |= PXLF_STRIP8BIT;
1590c2aa98e2SPeter Wemm 	(void) snprintf(obuf, sizeof obuf, "%.200s: ", h->h_field);
1591c2aa98e2SPeter Wemm 	obp = obuf + strlen(obuf);
1592c2aa98e2SPeter Wemm 	while ((nlp = strchr(v, '\n')) != NULL)
1593c2aa98e2SPeter Wemm 	{
1594c2aa98e2SPeter Wemm 		int l;
1595c2aa98e2SPeter Wemm 
1596c2aa98e2SPeter Wemm 		l = nlp - v;
15973299c2f1SGregory Neil Shapiro 		if (SPACELEFT(obuf, obp) - 1 < (size_t)l)
1598c2aa98e2SPeter Wemm 			l = SPACELEFT(obuf, obp) - 1;
1599c2aa98e2SPeter Wemm 
1600c2aa98e2SPeter Wemm 		snprintf(obp, SPACELEFT(obuf, obp), "%.*s", l, v);
1601c2aa98e2SPeter Wemm 		putxline(obuf, strlen(obuf), mci, putflags);
1602c2aa98e2SPeter Wemm 		v += l + 1;
1603c2aa98e2SPeter Wemm 		obp = obuf;
1604c2aa98e2SPeter Wemm 		if (*v != ' ' && *v != '\t')
1605c2aa98e2SPeter Wemm 			*obp++ = ' ';
1606c2aa98e2SPeter Wemm 	}
1607c2aa98e2SPeter Wemm 	snprintf(obp, SPACELEFT(obuf, obp), "%.*s",
16083299c2f1SGregory Neil Shapiro 		(int) sizeof obuf - (obp - obuf) - 1, v);
1609c2aa98e2SPeter Wemm 	putxline(obuf, strlen(obuf), mci, putflags);
1610c2aa98e2SPeter Wemm }
1611c2aa98e2SPeter Wemm /*
1612c2aa98e2SPeter Wemm **  COMMAIZE -- output a header field, making a comma-translated list.
1613c2aa98e2SPeter Wemm **
1614c2aa98e2SPeter Wemm **	Parameters:
1615c2aa98e2SPeter Wemm **		h -- the header field to output.
1616c2aa98e2SPeter Wemm **		p -- the value to put in it.
1617c2aa98e2SPeter Wemm **		oldstyle -- TRUE if this is an old style header.
1618c2aa98e2SPeter Wemm **		mci -- the connection information.
1619c2aa98e2SPeter Wemm **		e -- the envelope containing the message.
1620c2aa98e2SPeter Wemm **
1621c2aa98e2SPeter Wemm **	Returns:
1622c2aa98e2SPeter Wemm **		none.
1623c2aa98e2SPeter Wemm **
1624c2aa98e2SPeter Wemm **	Side Effects:
1625c2aa98e2SPeter Wemm **		outputs "p" to file "fp".
1626c2aa98e2SPeter Wemm */
1627c2aa98e2SPeter Wemm 
1628c2aa98e2SPeter Wemm void
1629c2aa98e2SPeter Wemm commaize(h, p, oldstyle, mci, e)
1630c2aa98e2SPeter Wemm 	register HDR *h;
1631c2aa98e2SPeter Wemm 	register char *p;
1632c2aa98e2SPeter Wemm 	bool oldstyle;
1633c2aa98e2SPeter Wemm 	register MCI *mci;
1634c2aa98e2SPeter Wemm 	register ENVELOPE *e;
1635c2aa98e2SPeter Wemm {
1636c2aa98e2SPeter Wemm 	register char *obp;
1637c2aa98e2SPeter Wemm 	int opos;
1638c2aa98e2SPeter Wemm 	int omax;
1639c2aa98e2SPeter Wemm 	bool firstone = TRUE;
1640c2aa98e2SPeter Wemm 	int putflags = PXLF_HEADER;
1641c2aa98e2SPeter Wemm 	char obuf[MAXLINE + 3];
1642c2aa98e2SPeter Wemm 
1643c2aa98e2SPeter Wemm 	/*
1644c2aa98e2SPeter Wemm 	**  Output the address list translated by the
1645c2aa98e2SPeter Wemm 	**  mailer and with commas.
1646c2aa98e2SPeter Wemm 	*/
1647c2aa98e2SPeter Wemm 
1648c2aa98e2SPeter Wemm 	if (tTd(14, 2))
16493299c2f1SGregory Neil Shapiro 		dprintf("commaize(%s: %s)\n", h->h_field, p);
1650c2aa98e2SPeter Wemm 
1651c2aa98e2SPeter Wemm 	if (bitnset(M_7BITHDRS, mci->mci_mailer->m_flags))
1652c2aa98e2SPeter Wemm 		putflags |= PXLF_STRIP8BIT;
1653c2aa98e2SPeter Wemm 
1654c2aa98e2SPeter Wemm 	obp = obuf;
1655c2aa98e2SPeter Wemm 	(void) snprintf(obp, SPACELEFT(obuf, obp), "%.200s: ", h->h_field);
1656c2aa98e2SPeter Wemm 	opos = strlen(h->h_field) + 2;
1657c2aa98e2SPeter Wemm 	if (opos > 202)
1658c2aa98e2SPeter Wemm 		opos = 202;
1659c2aa98e2SPeter Wemm 	obp += opos;
1660c2aa98e2SPeter Wemm 	omax = mci->mci_mailer->m_linelimit - 2;
1661c2aa98e2SPeter Wemm 	if (omax < 0 || omax > 78)
1662c2aa98e2SPeter Wemm 		omax = 78;
1663c2aa98e2SPeter Wemm 
1664c2aa98e2SPeter Wemm 	/*
1665c2aa98e2SPeter Wemm 	**  Run through the list of values.
1666c2aa98e2SPeter Wemm 	*/
1667c2aa98e2SPeter Wemm 
1668c2aa98e2SPeter Wemm 	while (*p != '\0')
1669c2aa98e2SPeter Wemm 	{
1670c2aa98e2SPeter Wemm 		register char *name;
1671c2aa98e2SPeter Wemm 		register int c;
1672c2aa98e2SPeter Wemm 		char savechar;
1673c2aa98e2SPeter Wemm 		int flags;
16743299c2f1SGregory Neil Shapiro 		auto int status;
1675c2aa98e2SPeter Wemm 
1676c2aa98e2SPeter Wemm 		/*
1677c2aa98e2SPeter Wemm 		**  Find the end of the name.  New style names
1678c2aa98e2SPeter Wemm 		**  end with a comma, old style names end with
1679c2aa98e2SPeter Wemm 		**  a space character.  However, spaces do not
1680c2aa98e2SPeter Wemm 		**  necessarily delimit an old-style name -- at
1681c2aa98e2SPeter Wemm 		**  signs mean keep going.
1682c2aa98e2SPeter Wemm 		*/
1683c2aa98e2SPeter Wemm 
1684c2aa98e2SPeter Wemm 		/* find end of name */
1685c2aa98e2SPeter Wemm 		while ((isascii(*p) && isspace(*p)) || *p == ',')
1686c2aa98e2SPeter Wemm 			p++;
1687c2aa98e2SPeter Wemm 		name = p;
1688c2aa98e2SPeter Wemm 		for (;;)
1689c2aa98e2SPeter Wemm 		{
1690c2aa98e2SPeter Wemm 			auto char *oldp;
1691c2aa98e2SPeter Wemm 			char pvpbuf[PSBUFSIZE];
1692c2aa98e2SPeter Wemm 
1693c2aa98e2SPeter Wemm 			(void) prescan(p, oldstyle ? ' ' : ',', pvpbuf,
1694c2aa98e2SPeter Wemm 				       sizeof pvpbuf, &oldp, NULL);
1695c2aa98e2SPeter Wemm 			p = oldp;
1696c2aa98e2SPeter Wemm 
1697c2aa98e2SPeter Wemm 			/* look to see if we have an at sign */
1698c2aa98e2SPeter Wemm 			while (*p != '\0' && isascii(*p) && isspace(*p))
1699c2aa98e2SPeter Wemm 				p++;
1700c2aa98e2SPeter Wemm 
1701c2aa98e2SPeter Wemm 			if (*p != '@')
1702c2aa98e2SPeter Wemm 			{
1703c2aa98e2SPeter Wemm 				p = oldp;
1704c2aa98e2SPeter Wemm 				break;
1705c2aa98e2SPeter Wemm 			}
1706c2aa98e2SPeter Wemm 			p += *p == '@' ? 1 : 2;
1707c2aa98e2SPeter Wemm 			while (*p != '\0' && isascii(*p) && isspace(*p))
1708c2aa98e2SPeter Wemm 				p++;
1709c2aa98e2SPeter Wemm 		}
1710c2aa98e2SPeter Wemm 		/* at the end of one complete name */
1711c2aa98e2SPeter Wemm 
1712c2aa98e2SPeter Wemm 		/* strip off trailing white space */
1713c2aa98e2SPeter Wemm 		while (p >= name &&
1714c2aa98e2SPeter Wemm 		       ((isascii(*p) && isspace(*p)) || *p == ',' || *p == '\0'))
1715c2aa98e2SPeter Wemm 			p--;
1716c2aa98e2SPeter Wemm 		if (++p == name)
1717c2aa98e2SPeter Wemm 			continue;
1718c2aa98e2SPeter Wemm 		savechar = *p;
1719c2aa98e2SPeter Wemm 		*p = '\0';
1720c2aa98e2SPeter Wemm 
1721c2aa98e2SPeter Wemm 		/* translate the name to be relative */
1722c2aa98e2SPeter Wemm 		flags = RF_HEADERADDR|RF_ADDDOMAIN;
1723c2aa98e2SPeter Wemm 		if (bitset(H_FROM, h->h_flags))
1724c2aa98e2SPeter Wemm 			flags |= RF_SENDERADDR;
1725c2aa98e2SPeter Wemm #if USERDB
1726c2aa98e2SPeter Wemm 		else if (e->e_from.q_mailer != NULL &&
1727c2aa98e2SPeter Wemm 			 bitnset(M_UDBRECIPIENT, e->e_from.q_mailer->m_flags))
1728c2aa98e2SPeter Wemm 		{
1729c2aa98e2SPeter Wemm 			char *q;
1730c2aa98e2SPeter Wemm 
1731c2aa98e2SPeter Wemm 			q = udbsender(name);
1732c2aa98e2SPeter Wemm 			if (q != NULL)
1733c2aa98e2SPeter Wemm 				name = q;
1734c2aa98e2SPeter Wemm 		}
17353299c2f1SGregory Neil Shapiro #endif /* USERDB */
17363299c2f1SGregory Neil Shapiro 		status = EX_OK;
17373299c2f1SGregory Neil Shapiro 		name = remotename(name, mci->mci_mailer, flags, &status, e);
1738c2aa98e2SPeter Wemm 		if (*name == '\0')
1739c2aa98e2SPeter Wemm 		{
1740c2aa98e2SPeter Wemm 			*p = savechar;
1741c2aa98e2SPeter Wemm 			continue;
1742c2aa98e2SPeter Wemm 		}
1743c2aa98e2SPeter Wemm 		name = denlstring(name, FALSE, TRUE);
1744c2aa98e2SPeter Wemm 
17453299c2f1SGregory Neil Shapiro 		/*
17463299c2f1SGregory Neil Shapiro 		**  record data progress so DNS timeouts
17473299c2f1SGregory Neil Shapiro 		**  don't cause DATA timeouts
17483299c2f1SGregory Neil Shapiro 		*/
17493299c2f1SGregory Neil Shapiro 
17503299c2f1SGregory Neil Shapiro 		DataProgress = TRUE;
17513299c2f1SGregory Neil Shapiro 
1752c2aa98e2SPeter Wemm 		/* output the name with nice formatting */
1753c2aa98e2SPeter Wemm 		opos += strlen(name);
1754c2aa98e2SPeter Wemm 		if (!firstone)
1755c2aa98e2SPeter Wemm 			opos += 2;
1756c2aa98e2SPeter Wemm 		if (opos > omax && !firstone)
1757c2aa98e2SPeter Wemm 		{
1758c2aa98e2SPeter Wemm 			snprintf(obp, SPACELEFT(obuf, obp), ",\n");
1759c2aa98e2SPeter Wemm 			putxline(obuf, strlen(obuf), mci, putflags);
1760c2aa98e2SPeter Wemm 			obp = obuf;
17613299c2f1SGregory Neil Shapiro 			(void) strlcpy(obp, "        ", sizeof obp);
1762c2aa98e2SPeter Wemm 			opos = strlen(obp);
1763c2aa98e2SPeter Wemm 			obp += opos;
1764c2aa98e2SPeter Wemm 			opos += strlen(name);
1765c2aa98e2SPeter Wemm 		}
1766c2aa98e2SPeter Wemm 		else if (!firstone)
1767c2aa98e2SPeter Wemm 		{
1768c2aa98e2SPeter Wemm 			snprintf(obp, SPACELEFT(obuf, obp), ", ");
1769c2aa98e2SPeter Wemm 			obp += 2;
1770c2aa98e2SPeter Wemm 		}
1771c2aa98e2SPeter Wemm 
1772c2aa98e2SPeter Wemm 		while ((c = *name++) != '\0' && obp < &obuf[MAXLINE])
1773c2aa98e2SPeter Wemm 			*obp++ = c;
1774c2aa98e2SPeter Wemm 		firstone = FALSE;
1775c2aa98e2SPeter Wemm 		*p = savechar;
1776c2aa98e2SPeter Wemm 	}
1777c2aa98e2SPeter Wemm 	*obp = '\0';
1778c2aa98e2SPeter Wemm 	putxline(obuf, strlen(obuf), mci, putflags);
1779c2aa98e2SPeter Wemm }
1780c2aa98e2SPeter Wemm /*
1781c2aa98e2SPeter Wemm **  COPYHEADER -- copy header list
1782c2aa98e2SPeter Wemm **
1783c2aa98e2SPeter Wemm **	This routine is the equivalent of newstr for header lists
1784c2aa98e2SPeter Wemm **
1785c2aa98e2SPeter Wemm **	Parameters:
1786c2aa98e2SPeter Wemm **		header -- list of header structures to copy.
1787c2aa98e2SPeter Wemm **
1788c2aa98e2SPeter Wemm **	Returns:
1789c2aa98e2SPeter Wemm **		a copy of 'header'.
1790c2aa98e2SPeter Wemm **
1791c2aa98e2SPeter Wemm **	Side Effects:
1792c2aa98e2SPeter Wemm **		none.
1793c2aa98e2SPeter Wemm */
1794c2aa98e2SPeter Wemm 
1795c2aa98e2SPeter Wemm HDR *
1796c2aa98e2SPeter Wemm copyheader(header)
1797c2aa98e2SPeter Wemm 	register HDR *header;
1798c2aa98e2SPeter Wemm {
1799c2aa98e2SPeter Wemm 	register HDR *newhdr;
1800c2aa98e2SPeter Wemm 	HDR *ret;
1801c2aa98e2SPeter Wemm 	register HDR **tail = &ret;
1802c2aa98e2SPeter Wemm 
1803c2aa98e2SPeter Wemm 	while (header != NULL)
1804c2aa98e2SPeter Wemm 	{
18053299c2f1SGregory Neil Shapiro 		newhdr = (HDR *) xalloc(sizeof *newhdr);
1806c2aa98e2SPeter Wemm 		STRUCTCOPY(*header, *newhdr);
1807c2aa98e2SPeter Wemm 		*tail = newhdr;
1808c2aa98e2SPeter Wemm 		tail = &newhdr->h_link;
1809c2aa98e2SPeter Wemm 		header = header->h_link;
1810c2aa98e2SPeter Wemm 	}
1811c2aa98e2SPeter Wemm 	*tail = NULL;
1812c2aa98e2SPeter Wemm 
1813c2aa98e2SPeter Wemm 	return ret;
1814c2aa98e2SPeter Wemm }
181576b7bf71SPeter Wemm /*
181676b7bf71SPeter Wemm **  FIX_MIME_HEADER -- possibly truncate/rebalance parameters in a MIME header
181776b7bf71SPeter Wemm **
181876b7bf71SPeter Wemm **	Run through all of the parameters of a MIME header and
181976b7bf71SPeter Wemm **	possibly truncate and rebalance the parameter according
182076b7bf71SPeter Wemm **	to MaxMimeFieldLength.
182176b7bf71SPeter Wemm **
182276b7bf71SPeter Wemm **	Parameters:
182376b7bf71SPeter Wemm **		string -- the full header
182476b7bf71SPeter Wemm **
182576b7bf71SPeter Wemm **	Returns:
182676b7bf71SPeter Wemm **		TRUE if the header was modified, FALSE otherwise
182776b7bf71SPeter Wemm **
182876b7bf71SPeter Wemm **	Side Effects:
182976b7bf71SPeter Wemm **		string modified in place
183076b7bf71SPeter Wemm */
183176b7bf71SPeter Wemm 
18323299c2f1SGregory Neil Shapiro static bool
183376b7bf71SPeter Wemm fix_mime_header(string)
183476b7bf71SPeter Wemm 	char *string;
183576b7bf71SPeter Wemm {
183676b7bf71SPeter Wemm 	bool modified = FALSE;
183776b7bf71SPeter Wemm 	char *begin = string;
183876b7bf71SPeter Wemm 	char *end;
183976b7bf71SPeter Wemm 
184076b7bf71SPeter Wemm 	if (string == NULL || *string == '\0')
184176b7bf71SPeter Wemm 		return FALSE;
184276b7bf71SPeter Wemm 
184376b7bf71SPeter Wemm 	/* Split on each ';' */
184476b7bf71SPeter Wemm 	while ((end = find_character(begin, ';')) != NULL)
184576b7bf71SPeter Wemm 	{
184676b7bf71SPeter Wemm 		char save = *end;
184776b7bf71SPeter Wemm 		char *bp;
184876b7bf71SPeter Wemm 
184976b7bf71SPeter Wemm 		*end = '\0';
185076b7bf71SPeter Wemm 
185176b7bf71SPeter Wemm 		/* Shorten individual parameter */
185276b7bf71SPeter Wemm 		if (shorten_rfc822_string(begin, MaxMimeFieldLength))
185376b7bf71SPeter Wemm 			modified = TRUE;
185476b7bf71SPeter Wemm 
185576b7bf71SPeter Wemm 		/* Collapse the possibly shortened string with rest */
185676b7bf71SPeter Wemm 		bp = begin + strlen(begin);
185776b7bf71SPeter Wemm 		if (bp != end)
185876b7bf71SPeter Wemm 		{
185976b7bf71SPeter Wemm 			char *ep = end;
186076b7bf71SPeter Wemm 
186176b7bf71SPeter Wemm 			*end = save;
186276b7bf71SPeter Wemm 			end = bp;
186376b7bf71SPeter Wemm 
186476b7bf71SPeter Wemm 			/* copy character by character due to overlap */
186576b7bf71SPeter Wemm 			while (*ep != '\0')
186676b7bf71SPeter Wemm 				*bp++ = *ep++;
186776b7bf71SPeter Wemm 			*bp = '\0';
186876b7bf71SPeter Wemm 		}
186976b7bf71SPeter Wemm 		else
187076b7bf71SPeter Wemm 			*end = save;
187176b7bf71SPeter Wemm 		if (*end == '\0')
187276b7bf71SPeter Wemm 			break;
187376b7bf71SPeter Wemm 
187476b7bf71SPeter Wemm 		/* Move past ';' */
187576b7bf71SPeter Wemm 		begin = end + 1;
187676b7bf71SPeter Wemm 	}
187776b7bf71SPeter Wemm 	return modified;
187876b7bf71SPeter Wemm }
1879