xref: /freebsd/contrib/sendmail/src/headers.c (revision c2aa98e247e56d5266d789dfc9b90b524b0019fe)
1c2aa98e2SPeter Wemm /*
2c2aa98e2SPeter Wemm  * Copyright (c) 1998 Sendmail, Inc.  All rights reserved.
3c2aa98e2SPeter Wemm  * Copyright (c) 1983, 1995-1997 Eric P. Allman.  All rights reserved.
4c2aa98e2SPeter Wemm  * Copyright (c) 1988, 1993
5c2aa98e2SPeter Wemm  *	The Regents of the University of California.  All rights reserved.
6c2aa98e2SPeter Wemm  *
7c2aa98e2SPeter Wemm  * By using this file, you agree to the terms and conditions set
8c2aa98e2SPeter Wemm  * forth in the LICENSE file which can be found at the top level of
9c2aa98e2SPeter Wemm  * the sendmail distribution.
10c2aa98e2SPeter Wemm  *
11c2aa98e2SPeter Wemm  */
12c2aa98e2SPeter Wemm 
13c2aa98e2SPeter Wemm #ifndef lint
14c2aa98e2SPeter Wemm static char sccsid[] = "@(#)headers.c	8.127 (Berkeley) 6/4/98";
15c2aa98e2SPeter Wemm #endif /* not lint */
16c2aa98e2SPeter Wemm 
17c2aa98e2SPeter Wemm # include <errno.h>
18c2aa98e2SPeter Wemm # include "sendmail.h"
19c2aa98e2SPeter Wemm 
20c2aa98e2SPeter Wemm /*
21c2aa98e2SPeter Wemm **  SETUPHEADERS -- initialize headers in symbol table
22c2aa98e2SPeter Wemm **
23c2aa98e2SPeter Wemm **	Parameters:
24c2aa98e2SPeter Wemm **		none
25c2aa98e2SPeter Wemm **
26c2aa98e2SPeter Wemm **	Returns:
27c2aa98e2SPeter Wemm **		none
28c2aa98e2SPeter Wemm */
29c2aa98e2SPeter Wemm 
30c2aa98e2SPeter Wemm void
31c2aa98e2SPeter Wemm setupheaders()
32c2aa98e2SPeter Wemm {
33c2aa98e2SPeter Wemm 	struct hdrinfo *hi;
34c2aa98e2SPeter Wemm 	STAB *s;
35c2aa98e2SPeter Wemm 
36c2aa98e2SPeter Wemm 	for (hi = HdrInfo; hi->hi_field != NULL; hi++)
37c2aa98e2SPeter Wemm 	{
38c2aa98e2SPeter Wemm 		s = stab(hi->hi_field, ST_HEADER, ST_ENTER);
39c2aa98e2SPeter Wemm 		s->s_header.hi_flags = hi->hi_flags;
40c2aa98e2SPeter Wemm 		s->s_header.hi_ruleset = NULL;
41c2aa98e2SPeter Wemm 	}
42c2aa98e2SPeter Wemm }
43c2aa98e2SPeter Wemm /*
44c2aa98e2SPeter Wemm **  CHOMPHEADER -- process and save a header line.
45c2aa98e2SPeter Wemm **
46c2aa98e2SPeter Wemm **	Called by collect and by readcf to deal with header lines.
47c2aa98e2SPeter Wemm **
48c2aa98e2SPeter Wemm **	Parameters:
49c2aa98e2SPeter Wemm **		line -- header as a text line.
50c2aa98e2SPeter Wemm **		def -- if set, this is a default value.
51c2aa98e2SPeter Wemm **		hdrp -- a pointer to the place to save the header.
52c2aa98e2SPeter Wemm **		e -- the envelope including this header.
53c2aa98e2SPeter Wemm **
54c2aa98e2SPeter Wemm **	Returns:
55c2aa98e2SPeter Wemm **		flags for this header.
56c2aa98e2SPeter Wemm **
57c2aa98e2SPeter Wemm **	Side Effects:
58c2aa98e2SPeter Wemm **		The header is saved on the header list.
59c2aa98e2SPeter Wemm **		Contents of 'line' are destroyed.
60c2aa98e2SPeter Wemm */
61c2aa98e2SPeter Wemm 
62c2aa98e2SPeter Wemm struct hdrinfo	NormalHeader =	{ NULL, 0, NULL };
63c2aa98e2SPeter Wemm 
64c2aa98e2SPeter Wemm int
65c2aa98e2SPeter Wemm chompheader(line, def, hdrp, e)
66c2aa98e2SPeter Wemm 	char *line;
67c2aa98e2SPeter Wemm 	bool def;
68c2aa98e2SPeter Wemm 	HDR **hdrp;
69c2aa98e2SPeter Wemm 	register ENVELOPE *e;
70c2aa98e2SPeter Wemm {
71c2aa98e2SPeter Wemm 	register char *p;
72c2aa98e2SPeter Wemm 	register HDR *h;
73c2aa98e2SPeter Wemm 	HDR **hp;
74c2aa98e2SPeter Wemm 	char *fname;
75c2aa98e2SPeter Wemm 	char *fvalue;
76c2aa98e2SPeter Wemm 	bool cond = FALSE;
77c2aa98e2SPeter Wemm 	bool headeronly;
78c2aa98e2SPeter Wemm 	STAB *s;
79c2aa98e2SPeter Wemm 	struct hdrinfo *hi;
80c2aa98e2SPeter Wemm 	BITMAP mopts;
81c2aa98e2SPeter Wemm 
82c2aa98e2SPeter Wemm 	if (tTd(31, 6))
83c2aa98e2SPeter Wemm 	{
84c2aa98e2SPeter Wemm 		printf("chompheader: ");
85c2aa98e2SPeter Wemm 		xputs(line);
86c2aa98e2SPeter Wemm 		printf("\n");
87c2aa98e2SPeter Wemm 	}
88c2aa98e2SPeter Wemm 
89c2aa98e2SPeter Wemm 	headeronly = hdrp != NULL;
90c2aa98e2SPeter Wemm 	if (!headeronly)
91c2aa98e2SPeter Wemm 		hdrp = &e->e_header;
92c2aa98e2SPeter Wemm 
93c2aa98e2SPeter Wemm 	/* strip off options */
94c2aa98e2SPeter Wemm 	clrbitmap(mopts);
95c2aa98e2SPeter Wemm 	p = line;
96c2aa98e2SPeter Wemm 	if (*p == '?')
97c2aa98e2SPeter Wemm 	{
98c2aa98e2SPeter Wemm 		/* have some */
99c2aa98e2SPeter Wemm 		register char *q = strchr(p + 1, *p);
100c2aa98e2SPeter Wemm 
101c2aa98e2SPeter Wemm 		if (q != NULL)
102c2aa98e2SPeter Wemm 		{
103c2aa98e2SPeter Wemm 			*q++ = '\0';
104c2aa98e2SPeter Wemm 			while (*++p != '\0')
105c2aa98e2SPeter Wemm 				setbitn(*p, mopts);
106c2aa98e2SPeter Wemm 			p = q;
107c2aa98e2SPeter Wemm 		}
108c2aa98e2SPeter Wemm 		else
109c2aa98e2SPeter Wemm 			syserr("553 header syntax error, line \"%s\"", line);
110c2aa98e2SPeter Wemm 		cond = TRUE;
111c2aa98e2SPeter Wemm 	}
112c2aa98e2SPeter Wemm 
113c2aa98e2SPeter Wemm 	/* find canonical name */
114c2aa98e2SPeter Wemm 	fname = p;
115c2aa98e2SPeter Wemm 	while (isascii(*p) && isgraph(*p) && *p != ':')
116c2aa98e2SPeter Wemm 		p++;
117c2aa98e2SPeter Wemm 	fvalue = p;
118c2aa98e2SPeter Wemm 	while (isascii(*p) && isspace(*p))
119c2aa98e2SPeter Wemm 		p++;
120c2aa98e2SPeter Wemm 	if (*p++ != ':' || fname == fvalue)
121c2aa98e2SPeter Wemm 	{
122c2aa98e2SPeter Wemm 		syserr("553 header syntax error, line \"%s\"", line);
123c2aa98e2SPeter Wemm 		return 0;
124c2aa98e2SPeter Wemm 	}
125c2aa98e2SPeter Wemm 	*fvalue = '\0';
126c2aa98e2SPeter Wemm 	fvalue = p;
127c2aa98e2SPeter Wemm 
128c2aa98e2SPeter Wemm 	/* strip field value on front */
129c2aa98e2SPeter Wemm 	if (*fvalue == ' ')
130c2aa98e2SPeter Wemm 		fvalue++;
131c2aa98e2SPeter Wemm 
132c2aa98e2SPeter Wemm 	/* security scan: long field names are end-of-header */
133c2aa98e2SPeter Wemm 	if (strlen(fname) > 100)
134c2aa98e2SPeter Wemm 		return H_EOH;
135c2aa98e2SPeter Wemm 
136c2aa98e2SPeter Wemm 	/* check to see if it represents a ruleset call */
137c2aa98e2SPeter Wemm 	if (def)
138c2aa98e2SPeter Wemm 	{
139c2aa98e2SPeter Wemm 		char hbuf[50];
140c2aa98e2SPeter Wemm 
141c2aa98e2SPeter Wemm 		(void) expand(fvalue, hbuf, sizeof hbuf, e);
142c2aa98e2SPeter Wemm 		for (p = hbuf; isascii(*p) && isspace(*p); )
143c2aa98e2SPeter Wemm 			p++;
144c2aa98e2SPeter Wemm 		if ((*p++ & 0377) == CALLSUBR)
145c2aa98e2SPeter Wemm 		{
146c2aa98e2SPeter Wemm 			auto char *endp;
147c2aa98e2SPeter Wemm 
148c2aa98e2SPeter Wemm 			if (strtorwset(p, &endp, ST_ENTER) > 0)
149c2aa98e2SPeter Wemm 			{
150c2aa98e2SPeter Wemm 				*endp = '\0';
151c2aa98e2SPeter Wemm 				s = stab(fname, ST_HEADER, ST_ENTER);
152c2aa98e2SPeter Wemm 				s->s_header.hi_ruleset = newstr(p);
153c2aa98e2SPeter Wemm 			}
154c2aa98e2SPeter Wemm 			return 0;
155c2aa98e2SPeter Wemm 		}
156c2aa98e2SPeter Wemm 	}
157c2aa98e2SPeter Wemm 
158c2aa98e2SPeter Wemm 	/* see if it is a known type */
159c2aa98e2SPeter Wemm 	s = stab(fname, ST_HEADER, ST_FIND);
160c2aa98e2SPeter Wemm 	if (s != NULL)
161c2aa98e2SPeter Wemm 		hi = &s->s_header;
162c2aa98e2SPeter Wemm 	else
163c2aa98e2SPeter Wemm 		hi = &NormalHeader;
164c2aa98e2SPeter Wemm 
165c2aa98e2SPeter Wemm 	if (tTd(31, 9))
166c2aa98e2SPeter Wemm 	{
167c2aa98e2SPeter Wemm 		if (s == NULL)
168c2aa98e2SPeter Wemm 			printf("no header flags match\n");
169c2aa98e2SPeter Wemm 		else
170c2aa98e2SPeter Wemm 			printf("header match, flags=%x, ruleset=%s\n",
171c2aa98e2SPeter Wemm 				hi->hi_flags,
172c2aa98e2SPeter Wemm 				hi->hi_ruleset == NULL ? "<NULL>" : hi->hi_ruleset);
173c2aa98e2SPeter Wemm 	}
174c2aa98e2SPeter Wemm 
175c2aa98e2SPeter Wemm 	/* see if this is a resent message */
176c2aa98e2SPeter Wemm 	if (!def && !headeronly && bitset(H_RESENT, hi->hi_flags))
177c2aa98e2SPeter Wemm 		e->e_flags |= EF_RESENT;
178c2aa98e2SPeter Wemm 
179c2aa98e2SPeter Wemm 	/* if this is an Errors-To: header keep track of it now */
180c2aa98e2SPeter Wemm 	if (UseErrorsTo && !def && !headeronly &&
181c2aa98e2SPeter Wemm 	    bitset(H_ERRORSTO, hi->hi_flags))
182c2aa98e2SPeter Wemm 		(void) sendtolist(fvalue, NULLADDR, &e->e_errorqueue, 0, e);
183c2aa98e2SPeter Wemm 
184c2aa98e2SPeter Wemm 	/* if this means "end of header" quit now */
185c2aa98e2SPeter Wemm 	if (!headeronly && bitset(H_EOH, hi->hi_flags))
186c2aa98e2SPeter Wemm 		return hi->hi_flags;
187c2aa98e2SPeter Wemm 
188c2aa98e2SPeter Wemm 	/*
189c2aa98e2SPeter Wemm 	**  Horrible hack to work around problem with Lotus Notes SMTP
190c2aa98e2SPeter Wemm 	**  mail gateway, which generates From: headers with newlines in
191c2aa98e2SPeter Wemm 	**  them and the <address> on the second line.  Although this is
192c2aa98e2SPeter Wemm 	**  legal RFC 822, many MUAs don't handle this properly and thus
193c2aa98e2SPeter Wemm 	**  never find the actual address.
194c2aa98e2SPeter Wemm 	*/
195c2aa98e2SPeter Wemm 
196c2aa98e2SPeter Wemm 	if (bitset(H_FROM, hi->hi_flags) && SingleLineFromHeader)
197c2aa98e2SPeter Wemm 	{
198c2aa98e2SPeter Wemm 		while ((p = strchr(fvalue, '\n')) != NULL)
199c2aa98e2SPeter Wemm 			*p = ' ';
200c2aa98e2SPeter Wemm 	}
201c2aa98e2SPeter Wemm 
202c2aa98e2SPeter Wemm 	/*
203c2aa98e2SPeter Wemm 	**  If there is a check ruleset, verify it against the header.
204c2aa98e2SPeter Wemm 	*/
205c2aa98e2SPeter Wemm 
206c2aa98e2SPeter Wemm 	if (!def && hi->hi_ruleset != NULL)
207c2aa98e2SPeter Wemm 		(void) rscheck(hi->hi_ruleset, fvalue, NULL, e);
208c2aa98e2SPeter Wemm 
209c2aa98e2SPeter Wemm 	/*
210c2aa98e2SPeter Wemm 	**  Drop explicit From: if same as what we would generate.
211c2aa98e2SPeter Wemm 	**  This is to make MH (which doesn't always give a full name)
212c2aa98e2SPeter Wemm 	**  insert the full name information in all circumstances.
213c2aa98e2SPeter Wemm 	*/
214c2aa98e2SPeter Wemm 
215c2aa98e2SPeter Wemm 	p = "resent-from";
216c2aa98e2SPeter Wemm 	if (!bitset(EF_RESENT, e->e_flags))
217c2aa98e2SPeter Wemm 		p += 7;
218c2aa98e2SPeter Wemm 	if (!def && !headeronly && !bitset(EF_QUEUERUN, e->e_flags) &&
219c2aa98e2SPeter Wemm 	    strcasecmp(fname, p) == 0)
220c2aa98e2SPeter Wemm 	{
221c2aa98e2SPeter Wemm 		if (tTd(31, 2))
222c2aa98e2SPeter Wemm 		{
223c2aa98e2SPeter Wemm 			printf("comparing header from (%s) against default (%s or %s)\n",
224c2aa98e2SPeter Wemm 				fvalue, e->e_from.q_paddr, e->e_from.q_user);
225c2aa98e2SPeter Wemm 		}
226c2aa98e2SPeter Wemm 		if (e->e_from.q_paddr != NULL &&
227c2aa98e2SPeter Wemm 		    (strcmp(fvalue, e->e_from.q_paddr) == 0 ||
228c2aa98e2SPeter Wemm 		     strcmp(fvalue, e->e_from.q_user) == 0))
229c2aa98e2SPeter Wemm 			return hi->hi_flags;
230c2aa98e2SPeter Wemm 	}
231c2aa98e2SPeter Wemm 
232c2aa98e2SPeter Wemm 	/* delete default value for this header */
233c2aa98e2SPeter Wemm 	for (hp = hdrp; (h = *hp) != NULL; hp = &h->h_link)
234c2aa98e2SPeter Wemm 	{
235c2aa98e2SPeter Wemm 		if (strcasecmp(fname, h->h_field) == 0 &&
236c2aa98e2SPeter Wemm 		    bitset(H_DEFAULT, h->h_flags) &&
237c2aa98e2SPeter Wemm 		    !bitset(H_FORCE, h->h_flags))
238c2aa98e2SPeter Wemm 		{
239c2aa98e2SPeter Wemm 			h->h_value = NULL;
240c2aa98e2SPeter Wemm 			if (!cond)
241c2aa98e2SPeter Wemm 			{
242c2aa98e2SPeter Wemm 				/* copy conditions from default case */
243c2aa98e2SPeter Wemm 				bcopy((char *)h->h_mflags, (char *)mopts,
244c2aa98e2SPeter Wemm 						sizeof mopts);
245c2aa98e2SPeter Wemm 			}
246c2aa98e2SPeter Wemm 		}
247c2aa98e2SPeter Wemm 	}
248c2aa98e2SPeter Wemm 
249c2aa98e2SPeter Wemm 	/* create a new node */
250c2aa98e2SPeter Wemm 	h = (HDR *) xalloc(sizeof *h);
251c2aa98e2SPeter Wemm 	h->h_field = newstr(fname);
252c2aa98e2SPeter Wemm 	h->h_value = newstr(fvalue);
253c2aa98e2SPeter Wemm 	h->h_link = NULL;
254c2aa98e2SPeter Wemm 	bcopy((char *) mopts, (char *) h->h_mflags, sizeof mopts);
255c2aa98e2SPeter Wemm 	*hp = h;
256c2aa98e2SPeter Wemm 	h->h_flags = hi->hi_flags;
257c2aa98e2SPeter Wemm 
258c2aa98e2SPeter Wemm 	/* strip EOH flag if parsing MIME headers */
259c2aa98e2SPeter Wemm 	if (headeronly)
260c2aa98e2SPeter Wemm 		h->h_flags &= ~H_EOH;
261c2aa98e2SPeter Wemm 	if (def)
262c2aa98e2SPeter Wemm 		h->h_flags |= H_DEFAULT;
263c2aa98e2SPeter Wemm 	if (cond)
264c2aa98e2SPeter Wemm 		h->h_flags |= H_CHECK;
265c2aa98e2SPeter Wemm 
266c2aa98e2SPeter Wemm 	/* hack to see if this is a new format message */
267c2aa98e2SPeter Wemm 	if (!def && !headeronly && bitset(H_RCPT|H_FROM, h->h_flags) &&
268c2aa98e2SPeter Wemm 	    (strchr(fvalue, ',') != NULL || strchr(fvalue, '(') != NULL ||
269c2aa98e2SPeter Wemm 	     strchr(fvalue, '<') != NULL || strchr(fvalue, ';') != NULL))
270c2aa98e2SPeter Wemm 	{
271c2aa98e2SPeter Wemm 		e->e_flags &= ~EF_OLDSTYLE;
272c2aa98e2SPeter Wemm 	}
273c2aa98e2SPeter Wemm 
274c2aa98e2SPeter Wemm 	return h->h_flags;
275c2aa98e2SPeter Wemm }
276c2aa98e2SPeter Wemm /*
277c2aa98e2SPeter Wemm **  ADDHEADER -- add a header entry to the end of the queue.
278c2aa98e2SPeter Wemm **
279c2aa98e2SPeter Wemm **	This bypasses the special checking of chompheader.
280c2aa98e2SPeter Wemm **
281c2aa98e2SPeter Wemm **	Parameters:
282c2aa98e2SPeter Wemm **		field -- the name of the header field.
283c2aa98e2SPeter Wemm **		value -- the value of the field.
284c2aa98e2SPeter Wemm **		hp -- an indirect pointer to the header structure list.
285c2aa98e2SPeter Wemm **
286c2aa98e2SPeter Wemm **	Returns:
287c2aa98e2SPeter Wemm **		none.
288c2aa98e2SPeter Wemm **
289c2aa98e2SPeter Wemm **	Side Effects:
290c2aa98e2SPeter Wemm **		adds the field on the list of headers for this envelope.
291c2aa98e2SPeter Wemm */
292c2aa98e2SPeter Wemm 
293c2aa98e2SPeter Wemm void
294c2aa98e2SPeter Wemm addheader(field, value, hdrlist)
295c2aa98e2SPeter Wemm 	char *field;
296c2aa98e2SPeter Wemm 	char *value;
297c2aa98e2SPeter Wemm 	HDR **hdrlist;
298c2aa98e2SPeter Wemm {
299c2aa98e2SPeter Wemm 	register HDR *h;
300c2aa98e2SPeter Wemm 	STAB *s;
301c2aa98e2SPeter Wemm 	HDR **hp;
302c2aa98e2SPeter Wemm 
303c2aa98e2SPeter Wemm 	/* find info struct */
304c2aa98e2SPeter Wemm 	s = stab(field, ST_HEADER, ST_FIND);
305c2aa98e2SPeter Wemm 
306c2aa98e2SPeter Wemm 	/* find current place in list -- keep back pointer? */
307c2aa98e2SPeter Wemm 	for (hp = hdrlist; (h = *hp) != NULL; hp = &h->h_link)
308c2aa98e2SPeter Wemm 	{
309c2aa98e2SPeter Wemm 		if (strcasecmp(field, h->h_field) == 0)
310c2aa98e2SPeter Wemm 			break;
311c2aa98e2SPeter Wemm 	}
312c2aa98e2SPeter Wemm 
313c2aa98e2SPeter Wemm 	/* allocate space for new header */
314c2aa98e2SPeter Wemm 	h = (HDR *) xalloc(sizeof *h);
315c2aa98e2SPeter Wemm 	h->h_field = field;
316c2aa98e2SPeter Wemm 	h->h_value = newstr(value);
317c2aa98e2SPeter Wemm 	h->h_link = *hp;
318c2aa98e2SPeter Wemm 	h->h_flags = H_DEFAULT;
319c2aa98e2SPeter Wemm 	if (s != NULL)
320c2aa98e2SPeter Wemm 		h->h_flags |= s->s_header.hi_flags;
321c2aa98e2SPeter Wemm 	clrbitmap(h->h_mflags);
322c2aa98e2SPeter Wemm 	*hp = h;
323c2aa98e2SPeter Wemm }
324c2aa98e2SPeter Wemm /*
325c2aa98e2SPeter Wemm **  HVALUE -- return value of a header.
326c2aa98e2SPeter Wemm **
327c2aa98e2SPeter Wemm **	Only "real" fields (i.e., ones that have not been supplied
328c2aa98e2SPeter Wemm **	as a default) are used.
329c2aa98e2SPeter Wemm **
330c2aa98e2SPeter Wemm **	Parameters:
331c2aa98e2SPeter Wemm **		field -- the field name.
332c2aa98e2SPeter Wemm **		header -- the header list.
333c2aa98e2SPeter Wemm **
334c2aa98e2SPeter Wemm **	Returns:
335c2aa98e2SPeter Wemm **		pointer to the value part.
336c2aa98e2SPeter Wemm **		NULL if not found.
337c2aa98e2SPeter Wemm **
338c2aa98e2SPeter Wemm **	Side Effects:
339c2aa98e2SPeter Wemm **		none.
340c2aa98e2SPeter Wemm */
341c2aa98e2SPeter Wemm 
342c2aa98e2SPeter Wemm char *
343c2aa98e2SPeter Wemm hvalue(field, header)
344c2aa98e2SPeter Wemm 	char *field;
345c2aa98e2SPeter Wemm 	HDR *header;
346c2aa98e2SPeter Wemm {
347c2aa98e2SPeter Wemm 	register HDR *h;
348c2aa98e2SPeter Wemm 
349c2aa98e2SPeter Wemm 	for (h = header; h != NULL; h = h->h_link)
350c2aa98e2SPeter Wemm 	{
351c2aa98e2SPeter Wemm 		if (!bitset(H_DEFAULT, h->h_flags) &&
352c2aa98e2SPeter Wemm 		    strcasecmp(h->h_field, field) == 0)
353c2aa98e2SPeter Wemm 			return (h->h_value);
354c2aa98e2SPeter Wemm 	}
355c2aa98e2SPeter Wemm 	return (NULL);
356c2aa98e2SPeter Wemm }
357c2aa98e2SPeter Wemm /*
358c2aa98e2SPeter Wemm **  ISHEADER -- predicate telling if argument is a header.
359c2aa98e2SPeter Wemm **
360c2aa98e2SPeter Wemm **	A line is a header if it has a single word followed by
361c2aa98e2SPeter Wemm **	optional white space followed by a colon.
362c2aa98e2SPeter Wemm **
363c2aa98e2SPeter Wemm **	Header fields beginning with two dashes, although technically
364c2aa98e2SPeter Wemm **	permitted by RFC822, are automatically rejected in order
365c2aa98e2SPeter Wemm **	to make MIME work out.  Without this we could have a technically
366c2aa98e2SPeter Wemm **	legal header such as ``--"foo:bar"'' that would also be a legal
367c2aa98e2SPeter Wemm **	MIME separator.
368c2aa98e2SPeter Wemm **
369c2aa98e2SPeter Wemm **	Parameters:
370c2aa98e2SPeter Wemm **		h -- string to check for possible headerness.
371c2aa98e2SPeter Wemm **
372c2aa98e2SPeter Wemm **	Returns:
373c2aa98e2SPeter Wemm **		TRUE if h is a header.
374c2aa98e2SPeter Wemm **		FALSE otherwise.
375c2aa98e2SPeter Wemm **
376c2aa98e2SPeter Wemm **	Side Effects:
377c2aa98e2SPeter Wemm **		none.
378c2aa98e2SPeter Wemm */
379c2aa98e2SPeter Wemm 
380c2aa98e2SPeter Wemm bool
381c2aa98e2SPeter Wemm isheader(h)
382c2aa98e2SPeter Wemm 	char *h;
383c2aa98e2SPeter Wemm {
384c2aa98e2SPeter Wemm 	register char *s = h;
385c2aa98e2SPeter Wemm 
386c2aa98e2SPeter Wemm 	if (s[0] == '-' && s[1] == '-')
387c2aa98e2SPeter Wemm 		return FALSE;
388c2aa98e2SPeter Wemm 
389c2aa98e2SPeter Wemm 	while (*s > ' ' && *s != ':' && *s != '\0')
390c2aa98e2SPeter Wemm 		s++;
391c2aa98e2SPeter Wemm 
392c2aa98e2SPeter Wemm 	if (h == s)
393c2aa98e2SPeter Wemm 		return FALSE;
394c2aa98e2SPeter Wemm 
395c2aa98e2SPeter Wemm 	/* following technically violates RFC822 */
396c2aa98e2SPeter Wemm 	while (isascii(*s) && isspace(*s))
397c2aa98e2SPeter Wemm 		s++;
398c2aa98e2SPeter Wemm 
399c2aa98e2SPeter Wemm 	return (*s == ':');
400c2aa98e2SPeter Wemm }
401c2aa98e2SPeter Wemm /*
402c2aa98e2SPeter Wemm **  EATHEADER -- run through the stored header and extract info.
403c2aa98e2SPeter Wemm **
404c2aa98e2SPeter Wemm **	Parameters:
405c2aa98e2SPeter Wemm **		e -- the envelope to process.
406c2aa98e2SPeter Wemm **		full -- if set, do full processing (e.g., compute
407c2aa98e2SPeter Wemm **			message priority).  This should not be set
408c2aa98e2SPeter Wemm **			when reading a queue file because some info
409c2aa98e2SPeter Wemm **			needed to compute the priority is wrong.
410c2aa98e2SPeter Wemm **
411c2aa98e2SPeter Wemm **	Returns:
412c2aa98e2SPeter Wemm **		none.
413c2aa98e2SPeter Wemm **
414c2aa98e2SPeter Wemm **	Side Effects:
415c2aa98e2SPeter Wemm **		Sets a bunch of global variables from information
416c2aa98e2SPeter Wemm **			in the collected header.
417c2aa98e2SPeter Wemm **		Aborts the message if the hop count is exceeded.
418c2aa98e2SPeter Wemm */
419c2aa98e2SPeter Wemm 
420c2aa98e2SPeter Wemm void
421c2aa98e2SPeter Wemm eatheader(e, full)
422c2aa98e2SPeter Wemm 	register ENVELOPE *e;
423c2aa98e2SPeter Wemm 	bool full;
424c2aa98e2SPeter Wemm {
425c2aa98e2SPeter Wemm 	register HDR *h;
426c2aa98e2SPeter Wemm 	register char *p;
427c2aa98e2SPeter Wemm 	int hopcnt = 0;
428c2aa98e2SPeter Wemm 	char *msgid;
429c2aa98e2SPeter Wemm 	char buf[MAXLINE];
430c2aa98e2SPeter Wemm 	extern int priencode __P((char *));
431c2aa98e2SPeter Wemm 
432c2aa98e2SPeter Wemm 	/*
433c2aa98e2SPeter Wemm 	**  Set up macros for possible expansion in headers.
434c2aa98e2SPeter Wemm 	*/
435c2aa98e2SPeter Wemm 
436c2aa98e2SPeter Wemm 	define('f', e->e_sender, e);
437c2aa98e2SPeter Wemm 	define('g', e->e_sender, e);
438c2aa98e2SPeter Wemm 	if (e->e_origrcpt != NULL && *e->e_origrcpt != '\0')
439c2aa98e2SPeter Wemm 		define('u', e->e_origrcpt, e);
440c2aa98e2SPeter Wemm 	else
441c2aa98e2SPeter Wemm 		define('u', NULL, e);
442c2aa98e2SPeter Wemm 
443c2aa98e2SPeter Wemm 	/* full name of from person */
444c2aa98e2SPeter Wemm 	p = hvalue("full-name", e->e_header);
445c2aa98e2SPeter Wemm 	if (p != NULL)
446c2aa98e2SPeter Wemm 	{
447c2aa98e2SPeter Wemm 		extern bool rfc822_string __P((char *));
448c2aa98e2SPeter Wemm 
449c2aa98e2SPeter Wemm 		if (!rfc822_string(p))
450c2aa98e2SPeter Wemm 		{
451c2aa98e2SPeter Wemm 			extern char *addquotes __P((char *));
452c2aa98e2SPeter Wemm 
453c2aa98e2SPeter Wemm 			/*
454c2aa98e2SPeter Wemm 			**  Quote a full name with special characters
455c2aa98e2SPeter Wemm 			**  as a comment so crackaddr() doesn't destroy
456c2aa98e2SPeter Wemm 			**  the name portion of the address.
457c2aa98e2SPeter Wemm 			*/
458c2aa98e2SPeter Wemm 			p = addquotes(p);
459c2aa98e2SPeter Wemm 		}
460c2aa98e2SPeter Wemm 		define('x', p, e);
461c2aa98e2SPeter Wemm 	}
462c2aa98e2SPeter Wemm 
463c2aa98e2SPeter Wemm 	if (tTd(32, 1))
464c2aa98e2SPeter Wemm 		printf("----- collected header -----\n");
465c2aa98e2SPeter Wemm 	msgid = NULL;
466c2aa98e2SPeter Wemm 	for (h = e->e_header; h != NULL; h = h->h_link)
467c2aa98e2SPeter Wemm 	{
468c2aa98e2SPeter Wemm 		if (tTd(32, 1))
469c2aa98e2SPeter Wemm 			printf("%s: ", h->h_field);
470c2aa98e2SPeter Wemm 		if (h->h_value == NULL)
471c2aa98e2SPeter Wemm 		{
472c2aa98e2SPeter Wemm 			if (tTd(32, 1))
473c2aa98e2SPeter Wemm 				printf("<NULL>\n");
474c2aa98e2SPeter Wemm 			continue;
475c2aa98e2SPeter Wemm 		}
476c2aa98e2SPeter Wemm 
477c2aa98e2SPeter Wemm 		/* do early binding */
478c2aa98e2SPeter Wemm 		if (bitset(H_DEFAULT, h->h_flags))
479c2aa98e2SPeter Wemm 		{
480c2aa98e2SPeter Wemm 			if (tTd(32, 1))
481c2aa98e2SPeter Wemm 			{
482c2aa98e2SPeter Wemm 				printf("(");
483c2aa98e2SPeter Wemm 				xputs(h->h_value);
484c2aa98e2SPeter Wemm 				printf(") ");
485c2aa98e2SPeter Wemm 			}
486c2aa98e2SPeter Wemm 			expand(h->h_value, buf, sizeof buf, e);
487c2aa98e2SPeter Wemm 			if (buf[0] != '\0')
488c2aa98e2SPeter Wemm 			{
489c2aa98e2SPeter Wemm 				if (bitset(H_FROM, h->h_flags))
490c2aa98e2SPeter Wemm 				{
491c2aa98e2SPeter Wemm 					extern char *crackaddr __P((char *));
492c2aa98e2SPeter Wemm 
493c2aa98e2SPeter Wemm 					expand(crackaddr(buf), buf, sizeof buf, e);
494c2aa98e2SPeter Wemm 				}
495c2aa98e2SPeter Wemm 				h->h_value = newstr(buf);
496c2aa98e2SPeter Wemm 				h->h_flags &= ~H_DEFAULT;
497c2aa98e2SPeter Wemm 			}
498c2aa98e2SPeter Wemm 		}
499c2aa98e2SPeter Wemm 
500c2aa98e2SPeter Wemm 		if (tTd(32, 1))
501c2aa98e2SPeter Wemm 		{
502c2aa98e2SPeter Wemm 			xputs(h->h_value);
503c2aa98e2SPeter Wemm 			printf("\n");
504c2aa98e2SPeter Wemm 		}
505c2aa98e2SPeter Wemm 
506c2aa98e2SPeter Wemm 		/* count the number of times it has been processed */
507c2aa98e2SPeter Wemm 		if (bitset(H_TRACE, h->h_flags))
508c2aa98e2SPeter Wemm 			hopcnt++;
509c2aa98e2SPeter Wemm 
510c2aa98e2SPeter Wemm 		/* send to this person if we so desire */
511c2aa98e2SPeter Wemm 		if (GrabTo && bitset(H_RCPT, h->h_flags) &&
512c2aa98e2SPeter Wemm 		    !bitset(H_DEFAULT, h->h_flags) &&
513c2aa98e2SPeter Wemm 		    (!bitset(EF_RESENT, e->e_flags) || bitset(H_RESENT, h->h_flags)))
514c2aa98e2SPeter Wemm 		{
515c2aa98e2SPeter Wemm #if 0
516c2aa98e2SPeter Wemm 			int saveflags = e->e_flags;
517c2aa98e2SPeter Wemm #endif
518c2aa98e2SPeter Wemm 
519c2aa98e2SPeter Wemm 			(void) sendtolist(h->h_value, NULLADDR,
520c2aa98e2SPeter Wemm 					  &e->e_sendqueue, 0, e);
521c2aa98e2SPeter Wemm 
522c2aa98e2SPeter Wemm #if 0
523c2aa98e2SPeter Wemm 			/*
524c2aa98e2SPeter Wemm 			** Change functionality so a fatal error on an
525c2aa98e2SPeter Wemm 			** address doesn't affect the entire envelope.
526c2aa98e2SPeter Wemm 			*/
527c2aa98e2SPeter Wemm 
528c2aa98e2SPeter Wemm 			/* delete fatal errors generated by this address */
529c2aa98e2SPeter Wemm 			if (!bitset(EF_FATALERRS, saveflags))
530c2aa98e2SPeter Wemm 				e->e_flags &= ~EF_FATALERRS;
531c2aa98e2SPeter Wemm #endif
532c2aa98e2SPeter Wemm 		}
533c2aa98e2SPeter Wemm 
534c2aa98e2SPeter Wemm 		/* save the message-id for logging */
535c2aa98e2SPeter Wemm 		p = "resent-message-id";
536c2aa98e2SPeter Wemm 		if (!bitset(EF_RESENT, e->e_flags))
537c2aa98e2SPeter Wemm 			p += 7;
538c2aa98e2SPeter Wemm 		if (strcasecmp(h->h_field, p) == 0)
539c2aa98e2SPeter Wemm 		{
540c2aa98e2SPeter Wemm 			msgid = h->h_value;
541c2aa98e2SPeter Wemm 			while (isascii(*msgid) && isspace(*msgid))
542c2aa98e2SPeter Wemm 				msgid++;
543c2aa98e2SPeter Wemm 		}
544c2aa98e2SPeter Wemm 	}
545c2aa98e2SPeter Wemm 	if (tTd(32, 1))
546c2aa98e2SPeter Wemm 		printf("----------------------------\n");
547c2aa98e2SPeter Wemm 
548c2aa98e2SPeter Wemm 	/* if we are just verifying (that is, sendmail -t -bv), drop out now */
549c2aa98e2SPeter Wemm 	if (OpMode == MD_VERIFY)
550c2aa98e2SPeter Wemm 		return;
551c2aa98e2SPeter Wemm 
552c2aa98e2SPeter Wemm 	/* store hop count */
553c2aa98e2SPeter Wemm 	if (hopcnt > e->e_hopcount)
554c2aa98e2SPeter Wemm 		e->e_hopcount = hopcnt;
555c2aa98e2SPeter Wemm 
556c2aa98e2SPeter Wemm 	/* message priority */
557c2aa98e2SPeter Wemm 	p = hvalue("precedence", e->e_header);
558c2aa98e2SPeter Wemm 	if (p != NULL)
559c2aa98e2SPeter Wemm 		e->e_class = priencode(p);
560c2aa98e2SPeter Wemm 	if (e->e_class < 0)
561c2aa98e2SPeter Wemm 		e->e_timeoutclass = TOC_NONURGENT;
562c2aa98e2SPeter Wemm 	else if (e->e_class > 0)
563c2aa98e2SPeter Wemm 		e->e_timeoutclass = TOC_URGENT;
564c2aa98e2SPeter Wemm 	if (full)
565c2aa98e2SPeter Wemm 	{
566c2aa98e2SPeter Wemm 		e->e_msgpriority = e->e_msgsize
567c2aa98e2SPeter Wemm 				 - e->e_class * WkClassFact
568c2aa98e2SPeter Wemm 				 + e->e_nrcpts * WkRecipFact;
569c2aa98e2SPeter Wemm 	}
570c2aa98e2SPeter Wemm 
571c2aa98e2SPeter Wemm 	/* message timeout priority */
572c2aa98e2SPeter Wemm 	p = hvalue("priority", e->e_header);
573c2aa98e2SPeter Wemm 	if (p != NULL)
574c2aa98e2SPeter Wemm 	{
575c2aa98e2SPeter Wemm 		/* (this should be in the configuration file) */
576c2aa98e2SPeter Wemm 		if (strcasecmp(p, "urgent") == 0)
577c2aa98e2SPeter Wemm 			e->e_timeoutclass = TOC_URGENT;
578c2aa98e2SPeter Wemm 		else if (strcasecmp(p, "normal") == 0)
579c2aa98e2SPeter Wemm 			e->e_timeoutclass = TOC_NORMAL;
580c2aa98e2SPeter Wemm 		else if (strcasecmp(p, "non-urgent") == 0)
581c2aa98e2SPeter Wemm 			e->e_timeoutclass = TOC_NONURGENT;
582c2aa98e2SPeter Wemm 	}
583c2aa98e2SPeter Wemm 
584c2aa98e2SPeter Wemm 	/* date message originated */
585c2aa98e2SPeter Wemm 	p = hvalue("posted-date", e->e_header);
586c2aa98e2SPeter Wemm 	if (p == NULL)
587c2aa98e2SPeter Wemm 		p = hvalue("date", e->e_header);
588c2aa98e2SPeter Wemm 	if (p != NULL)
589c2aa98e2SPeter Wemm 		define('a', p, e);
590c2aa98e2SPeter Wemm 
591c2aa98e2SPeter Wemm 	/* check to see if this is a MIME message */
592c2aa98e2SPeter Wemm 	if ((e->e_bodytype != NULL &&
593c2aa98e2SPeter Wemm 	     strcasecmp(e->e_bodytype, "8BITMIME") == 0) ||
594c2aa98e2SPeter Wemm 	    hvalue("MIME-Version", e->e_header) != NULL)
595c2aa98e2SPeter Wemm 	{
596c2aa98e2SPeter Wemm 		e->e_flags |= EF_IS_MIME;
597c2aa98e2SPeter Wemm 		if (HasEightBits)
598c2aa98e2SPeter Wemm 			e->e_bodytype = "8BITMIME";
599c2aa98e2SPeter Wemm 	}
600c2aa98e2SPeter Wemm 	else if ((p = hvalue("Content-Type", e->e_header)) != NULL)
601c2aa98e2SPeter Wemm 	{
602c2aa98e2SPeter Wemm 		/* this may be an RFC 1049 message */
603c2aa98e2SPeter Wemm 		p = strpbrk(p, ";/");
604c2aa98e2SPeter Wemm 		if (p == NULL || *p == ';')
605c2aa98e2SPeter Wemm 		{
606c2aa98e2SPeter Wemm 			/* yep, it is */
607c2aa98e2SPeter Wemm 			e->e_flags |= EF_DONT_MIME;
608c2aa98e2SPeter Wemm 		}
609c2aa98e2SPeter Wemm 	}
610c2aa98e2SPeter Wemm 
611c2aa98e2SPeter Wemm 	/*
612c2aa98e2SPeter Wemm 	**  From person in antiquated ARPANET mode
613c2aa98e2SPeter Wemm 	**	required by UK Grey Book e-mail gateways (sigh)
614c2aa98e2SPeter Wemm 	*/
615c2aa98e2SPeter Wemm 
616c2aa98e2SPeter Wemm 	if (OpMode == MD_ARPAFTP)
617c2aa98e2SPeter Wemm 	{
618c2aa98e2SPeter Wemm 		register struct hdrinfo *hi;
619c2aa98e2SPeter Wemm 
620c2aa98e2SPeter Wemm 		for (hi = HdrInfo; hi->hi_field != NULL; hi++)
621c2aa98e2SPeter Wemm 		{
622c2aa98e2SPeter Wemm 			if (bitset(H_FROM, hi->hi_flags) &&
623c2aa98e2SPeter Wemm 			    (!bitset(H_RESENT, hi->hi_flags) ||
624c2aa98e2SPeter Wemm 			     bitset(EF_RESENT, e->e_flags)) &&
625c2aa98e2SPeter Wemm 			    (p = hvalue(hi->hi_field, e->e_header)) != NULL)
626c2aa98e2SPeter Wemm 				break;
627c2aa98e2SPeter Wemm 		}
628c2aa98e2SPeter Wemm 		if (hi->hi_field != NULL)
629c2aa98e2SPeter Wemm 		{
630c2aa98e2SPeter Wemm 			if (tTd(32, 2))
631c2aa98e2SPeter Wemm 				printf("eatheader: setsender(*%s == %s)\n",
632c2aa98e2SPeter Wemm 					hi->hi_field, p);
633c2aa98e2SPeter Wemm 			setsender(p, e, NULL, '\0', TRUE);
634c2aa98e2SPeter Wemm 		}
635c2aa98e2SPeter Wemm 	}
636c2aa98e2SPeter Wemm 
637c2aa98e2SPeter Wemm 	/*
638c2aa98e2SPeter Wemm 	**  Log collection information.
639c2aa98e2SPeter Wemm 	*/
640c2aa98e2SPeter Wemm 
641c2aa98e2SPeter Wemm 	if (bitset(EF_LOGSENDER, e->e_flags) && LogLevel > 4)
642c2aa98e2SPeter Wemm 		logsender(e, msgid);
643c2aa98e2SPeter Wemm 	e->e_flags &= ~EF_LOGSENDER;
644c2aa98e2SPeter Wemm }
645c2aa98e2SPeter Wemm /*
646c2aa98e2SPeter Wemm **  LOGSENDER -- log sender information
647c2aa98e2SPeter Wemm **
648c2aa98e2SPeter Wemm **	Parameters:
649c2aa98e2SPeter Wemm **		e -- the envelope to log
650c2aa98e2SPeter Wemm **		msgid -- the message id
651c2aa98e2SPeter Wemm **
652c2aa98e2SPeter Wemm **	Returns:
653c2aa98e2SPeter Wemm **		none
654c2aa98e2SPeter Wemm */
655c2aa98e2SPeter Wemm 
656c2aa98e2SPeter Wemm void
657c2aa98e2SPeter Wemm logsender(e, msgid)
658c2aa98e2SPeter Wemm 	register ENVELOPE *e;
659c2aa98e2SPeter Wemm 	char *msgid;
660c2aa98e2SPeter Wemm {
661c2aa98e2SPeter Wemm 	char *name;
662c2aa98e2SPeter Wemm 	register char *sbp;
663c2aa98e2SPeter Wemm 	register char *p;
664c2aa98e2SPeter Wemm 	int l;
665c2aa98e2SPeter Wemm 	char hbuf[MAXNAME + 1];
666c2aa98e2SPeter Wemm 	char sbuf[MAXLINE + 1];
667c2aa98e2SPeter Wemm 	char mbuf[MAXNAME + 1];
668c2aa98e2SPeter Wemm 
669c2aa98e2SPeter Wemm 	/* don't allow newlines in the message-id */
670c2aa98e2SPeter Wemm 	if (msgid != NULL)
671c2aa98e2SPeter Wemm 	{
672c2aa98e2SPeter Wemm 		l = strlen(msgid);
673c2aa98e2SPeter Wemm 		if (l > sizeof mbuf - 1)
674c2aa98e2SPeter Wemm 			l = sizeof mbuf - 1;
675c2aa98e2SPeter Wemm 		bcopy(msgid, mbuf, l);
676c2aa98e2SPeter Wemm 		mbuf[l] = '\0';
677c2aa98e2SPeter Wemm 		p = mbuf;
678c2aa98e2SPeter Wemm 		while ((p = strchr(p, '\n')) != NULL)
679c2aa98e2SPeter Wemm 			*p++ = ' ';
680c2aa98e2SPeter Wemm 	}
681c2aa98e2SPeter Wemm 
682c2aa98e2SPeter Wemm 	if (bitset(EF_RESPONSE, e->e_flags))
683c2aa98e2SPeter Wemm 		name = "[RESPONSE]";
684c2aa98e2SPeter Wemm 	else if ((name = macvalue('_', e)) != NULL)
685c2aa98e2SPeter Wemm 		;
686c2aa98e2SPeter Wemm 	else if (RealHostName == NULL)
687c2aa98e2SPeter Wemm 		name = "localhost";
688c2aa98e2SPeter Wemm 	else if (RealHostName[0] == '[')
689c2aa98e2SPeter Wemm 		name = RealHostName;
690c2aa98e2SPeter Wemm 	else
691c2aa98e2SPeter Wemm 	{
692c2aa98e2SPeter Wemm 		name = hbuf;
693c2aa98e2SPeter Wemm 		(void) snprintf(hbuf, sizeof hbuf, "%.80s", RealHostName);
694c2aa98e2SPeter Wemm 		if (RealHostAddr.sa.sa_family != 0)
695c2aa98e2SPeter Wemm 		{
696c2aa98e2SPeter Wemm 			p = &hbuf[strlen(hbuf)];
697c2aa98e2SPeter Wemm 			(void) snprintf(p, SPACELEFT(hbuf, p), " (%.100s)",
698c2aa98e2SPeter Wemm 				anynet_ntoa(&RealHostAddr));
699c2aa98e2SPeter Wemm 		}
700c2aa98e2SPeter Wemm 	}
701c2aa98e2SPeter Wemm 
702c2aa98e2SPeter Wemm 	/* some versions of syslog only take 5 printf args */
703c2aa98e2SPeter Wemm #  if (SYSLOG_BUFSIZE) >= 256
704c2aa98e2SPeter Wemm 	sbp = sbuf;
705c2aa98e2SPeter Wemm 	snprintf(sbp, SPACELEFT(sbuf, sbp),
706c2aa98e2SPeter Wemm 	    "from=%.200s, size=%ld, class=%d, pri=%ld, nrcpts=%d",
707c2aa98e2SPeter Wemm 	    e->e_from.q_paddr == NULL ? "<NONE>" : e->e_from.q_paddr,
708c2aa98e2SPeter Wemm 	    e->e_msgsize, e->e_class, e->e_msgpriority, e->e_nrcpts);
709c2aa98e2SPeter Wemm 	sbp += strlen(sbp);
710c2aa98e2SPeter Wemm 	if (msgid != NULL)
711c2aa98e2SPeter Wemm 	{
712c2aa98e2SPeter Wemm 		snprintf(sbp, SPACELEFT(sbuf, sbp), ", msgid=%.100s", mbuf);
713c2aa98e2SPeter Wemm 		sbp += strlen(sbp);
714c2aa98e2SPeter Wemm 	}
715c2aa98e2SPeter Wemm 	if (e->e_bodytype != NULL)
716c2aa98e2SPeter Wemm 	{
717c2aa98e2SPeter Wemm 		(void) snprintf(sbp, SPACELEFT(sbuf, sbp), ", bodytype=%.20s",
718c2aa98e2SPeter Wemm 			e->e_bodytype);
719c2aa98e2SPeter Wemm 		sbp += strlen(sbp);
720c2aa98e2SPeter Wemm 	}
721c2aa98e2SPeter Wemm 	p = macvalue('r', e);
722c2aa98e2SPeter Wemm 	if (p != NULL)
723c2aa98e2SPeter Wemm 		(void) snprintf(sbp, SPACELEFT(sbuf, sbp), ", proto=%.20s", p);
724c2aa98e2SPeter Wemm 	sm_syslog(LOG_INFO, e->e_id,
725c2aa98e2SPeter Wemm 		"%.850s, relay=%.100s",
726c2aa98e2SPeter Wemm 		sbuf, name);
727c2aa98e2SPeter Wemm 
728c2aa98e2SPeter Wemm #  else			/* short syslog buffer */
729c2aa98e2SPeter Wemm 
730c2aa98e2SPeter Wemm 	sm_syslog(LOG_INFO, e->e_id,
731c2aa98e2SPeter Wemm 		"from=%s",
732c2aa98e2SPeter Wemm 		e->e_from.q_paddr == NULL ? "<NONE>"
733c2aa98e2SPeter Wemm 					  : shortenstring(e->e_from.q_paddr, 83));
734c2aa98e2SPeter Wemm 	sm_syslog(LOG_INFO, e->e_id,
735c2aa98e2SPeter Wemm 		"size=%ld, class=%ld, pri=%ld, nrcpts=%d",
736c2aa98e2SPeter Wemm 		e->e_msgsize, e->e_class, e->e_msgpriority, e->e_nrcpts);
737c2aa98e2SPeter Wemm 	if (msgid != NULL)
738c2aa98e2SPeter Wemm 		sm_syslog(LOG_INFO, e->e_id,
739c2aa98e2SPeter Wemm 			"msgid=%s",
740c2aa98e2SPeter Wemm 			shortenstring(mbuf, 83));
741c2aa98e2SPeter Wemm 	sbp = sbuf;
742c2aa98e2SPeter Wemm 	*sbp = '\0';
743c2aa98e2SPeter Wemm 	if (e->e_bodytype != NULL)
744c2aa98e2SPeter Wemm 	{
745c2aa98e2SPeter Wemm 		snprintf(sbp, SPACELEFT(sbuf, sbp), "bodytype=%.20s, ", e->e_bodytype);
746c2aa98e2SPeter Wemm 		sbp += strlen(sbp);
747c2aa98e2SPeter Wemm 	}
748c2aa98e2SPeter Wemm 	p = macvalue('r', e);
749c2aa98e2SPeter Wemm 	if (p != NULL)
750c2aa98e2SPeter Wemm 	{
751c2aa98e2SPeter Wemm 		snprintf(sbp, SPACELEFT(sbuf, sbp), "proto=%.20s, ", p);
752c2aa98e2SPeter Wemm 		sbp += strlen(sbp);
753c2aa98e2SPeter Wemm 	}
754c2aa98e2SPeter Wemm 	sm_syslog(LOG_INFO, e->e_id,
755c2aa98e2SPeter Wemm 		"%.400srelay=%.100s", sbuf, name);
756c2aa98e2SPeter Wemm #  endif
757c2aa98e2SPeter Wemm }
758c2aa98e2SPeter Wemm /*
759c2aa98e2SPeter Wemm **  PRIENCODE -- encode external priority names into internal values.
760c2aa98e2SPeter Wemm **
761c2aa98e2SPeter Wemm **	Parameters:
762c2aa98e2SPeter Wemm **		p -- priority in ascii.
763c2aa98e2SPeter Wemm **
764c2aa98e2SPeter Wemm **	Returns:
765c2aa98e2SPeter Wemm **		priority as a numeric level.
766c2aa98e2SPeter Wemm **
767c2aa98e2SPeter Wemm **	Side Effects:
768c2aa98e2SPeter Wemm **		none.
769c2aa98e2SPeter Wemm */
770c2aa98e2SPeter Wemm 
771c2aa98e2SPeter Wemm int
772c2aa98e2SPeter Wemm priencode(p)
773c2aa98e2SPeter Wemm 	char *p;
774c2aa98e2SPeter Wemm {
775c2aa98e2SPeter Wemm 	register int i;
776c2aa98e2SPeter Wemm 
777c2aa98e2SPeter Wemm 	for (i = 0; i < NumPriorities; i++)
778c2aa98e2SPeter Wemm 	{
779c2aa98e2SPeter Wemm 		if (!strcasecmp(p, Priorities[i].pri_name))
780c2aa98e2SPeter Wemm 			return (Priorities[i].pri_val);
781c2aa98e2SPeter Wemm 	}
782c2aa98e2SPeter Wemm 
783c2aa98e2SPeter Wemm 	/* unknown priority */
784c2aa98e2SPeter Wemm 	return (0);
785c2aa98e2SPeter Wemm }
786c2aa98e2SPeter Wemm /*
787c2aa98e2SPeter Wemm **  CRACKADDR -- parse an address and turn it into a macro
788c2aa98e2SPeter Wemm **
789c2aa98e2SPeter Wemm **	This doesn't actually parse the address -- it just extracts
790c2aa98e2SPeter Wemm **	it and replaces it with "$g".  The parse is totally ad hoc
791c2aa98e2SPeter Wemm **	and isn't even guaranteed to leave something syntactically
792c2aa98e2SPeter Wemm **	identical to what it started with.  However, it does leave
793c2aa98e2SPeter Wemm **	something semantically identical.
794c2aa98e2SPeter Wemm **
795c2aa98e2SPeter Wemm **	This algorithm has been cleaned up to handle a wider range
796c2aa98e2SPeter Wemm **	of cases -- notably quoted and backslash escaped strings.
797c2aa98e2SPeter Wemm **	This modification makes it substantially better at preserving
798c2aa98e2SPeter Wemm **	the original syntax.
799c2aa98e2SPeter Wemm **
800c2aa98e2SPeter Wemm **	Parameters:
801c2aa98e2SPeter Wemm **		addr -- the address to be cracked.
802c2aa98e2SPeter Wemm **
803c2aa98e2SPeter Wemm **	Returns:
804c2aa98e2SPeter Wemm **		a pointer to the new version.
805c2aa98e2SPeter Wemm **
806c2aa98e2SPeter Wemm **	Side Effects:
807c2aa98e2SPeter Wemm **		none.
808c2aa98e2SPeter Wemm **
809c2aa98e2SPeter Wemm **	Warning:
810c2aa98e2SPeter Wemm **		The return value is saved in local storage and should
811c2aa98e2SPeter Wemm **		be copied if it is to be reused.
812c2aa98e2SPeter Wemm */
813c2aa98e2SPeter Wemm 
814c2aa98e2SPeter Wemm char *
815c2aa98e2SPeter Wemm crackaddr(addr)
816c2aa98e2SPeter Wemm 	register char *addr;
817c2aa98e2SPeter Wemm {
818c2aa98e2SPeter Wemm 	register char *p;
819c2aa98e2SPeter Wemm 	register char c;
820c2aa98e2SPeter Wemm 	int cmtlev;
821c2aa98e2SPeter Wemm 	int realcmtlev;
822c2aa98e2SPeter Wemm 	int anglelev, realanglelev;
823c2aa98e2SPeter Wemm 	int copylev;
824c2aa98e2SPeter Wemm 	int bracklev;
825c2aa98e2SPeter Wemm 	bool qmode;
826c2aa98e2SPeter Wemm 	bool realqmode;
827c2aa98e2SPeter Wemm 	bool skipping;
828c2aa98e2SPeter Wemm 	bool putgmac = FALSE;
829c2aa98e2SPeter Wemm 	bool quoteit = FALSE;
830c2aa98e2SPeter Wemm 	bool gotangle = FALSE;
831c2aa98e2SPeter Wemm 	bool gotcolon = FALSE;
832c2aa98e2SPeter Wemm 	register char *bp;
833c2aa98e2SPeter Wemm 	char *buflim;
834c2aa98e2SPeter Wemm 	char *bufhead;
835c2aa98e2SPeter Wemm 	char *addrhead;
836c2aa98e2SPeter Wemm 	static char buf[MAXNAME + 1];
837c2aa98e2SPeter Wemm 
838c2aa98e2SPeter Wemm 	if (tTd(33, 1))
839c2aa98e2SPeter Wemm 		printf("crackaddr(%s)\n", addr);
840c2aa98e2SPeter Wemm 
841c2aa98e2SPeter Wemm 	/* strip leading spaces */
842c2aa98e2SPeter Wemm 	while (*addr != '\0' && isascii(*addr) && isspace(*addr))
843c2aa98e2SPeter Wemm 		addr++;
844c2aa98e2SPeter Wemm 
845c2aa98e2SPeter Wemm 	/*
846c2aa98e2SPeter Wemm 	**  Start by assuming we have no angle brackets.  This will be
847c2aa98e2SPeter Wemm 	**  adjusted later if we find them.
848c2aa98e2SPeter Wemm 	*/
849c2aa98e2SPeter Wemm 
850c2aa98e2SPeter Wemm 	bp = bufhead = buf;
851c2aa98e2SPeter Wemm 	buflim = &buf[sizeof buf - 7];
852c2aa98e2SPeter Wemm 	p = addrhead = addr;
853c2aa98e2SPeter Wemm 	copylev = anglelev = realanglelev = cmtlev = realcmtlev = 0;
854c2aa98e2SPeter Wemm 	bracklev = 0;
855c2aa98e2SPeter Wemm 	qmode = realqmode = FALSE;
856c2aa98e2SPeter Wemm 
857c2aa98e2SPeter Wemm 	while ((c = *p++) != '\0')
858c2aa98e2SPeter Wemm 	{
859c2aa98e2SPeter Wemm 		/*
860c2aa98e2SPeter Wemm 		**  If the buffer is overful, go into a special "skipping"
861c2aa98e2SPeter Wemm 		**  mode that tries to keep legal syntax but doesn't actually
862c2aa98e2SPeter Wemm 		**  output things.
863c2aa98e2SPeter Wemm 		*/
864c2aa98e2SPeter Wemm 
865c2aa98e2SPeter Wemm 		skipping = bp >= buflim;
866c2aa98e2SPeter Wemm 
867c2aa98e2SPeter Wemm 		if (copylev > 0 && !skipping)
868c2aa98e2SPeter Wemm 			*bp++ = c;
869c2aa98e2SPeter Wemm 
870c2aa98e2SPeter Wemm 		/* check for backslash escapes */
871c2aa98e2SPeter Wemm 		if (c == '\\')
872c2aa98e2SPeter Wemm 		{
873c2aa98e2SPeter Wemm 			/* arrange to quote the address */
874c2aa98e2SPeter Wemm 			if (cmtlev <= 0 && !qmode)
875c2aa98e2SPeter Wemm 				quoteit = TRUE;
876c2aa98e2SPeter Wemm 
877c2aa98e2SPeter Wemm 			if ((c = *p++) == '\0')
878c2aa98e2SPeter Wemm 			{
879c2aa98e2SPeter Wemm 				/* too far */
880c2aa98e2SPeter Wemm 				p--;
881c2aa98e2SPeter Wemm 				goto putg;
882c2aa98e2SPeter Wemm 			}
883c2aa98e2SPeter Wemm 			if (copylev > 0 && !skipping)
884c2aa98e2SPeter Wemm 				*bp++ = c;
885c2aa98e2SPeter Wemm 			goto putg;
886c2aa98e2SPeter Wemm 		}
887c2aa98e2SPeter Wemm 
888c2aa98e2SPeter Wemm 		/* check for quoted strings */
889c2aa98e2SPeter Wemm 		if (c == '"' && cmtlev <= 0)
890c2aa98e2SPeter Wemm 		{
891c2aa98e2SPeter Wemm 			qmode = !qmode;
892c2aa98e2SPeter Wemm 			if (copylev > 0 && !skipping)
893c2aa98e2SPeter Wemm 				realqmode = !realqmode;
894c2aa98e2SPeter Wemm 			continue;
895c2aa98e2SPeter Wemm 		}
896c2aa98e2SPeter Wemm 		if (qmode)
897c2aa98e2SPeter Wemm 			goto putg;
898c2aa98e2SPeter Wemm 
899c2aa98e2SPeter Wemm 		/* check for comments */
900c2aa98e2SPeter Wemm 		if (c == '(')
901c2aa98e2SPeter Wemm 		{
902c2aa98e2SPeter Wemm 			cmtlev++;
903c2aa98e2SPeter Wemm 
904c2aa98e2SPeter Wemm 			/* allow space for closing paren */
905c2aa98e2SPeter Wemm 			if (!skipping)
906c2aa98e2SPeter Wemm 			{
907c2aa98e2SPeter Wemm 				buflim--;
908c2aa98e2SPeter Wemm 				realcmtlev++;
909c2aa98e2SPeter Wemm 				if (copylev++ <= 0)
910c2aa98e2SPeter Wemm 				{
911c2aa98e2SPeter Wemm 					if (bp != bufhead)
912c2aa98e2SPeter Wemm 						*bp++ = ' ';
913c2aa98e2SPeter Wemm 					*bp++ = c;
914c2aa98e2SPeter Wemm 				}
915c2aa98e2SPeter Wemm 			}
916c2aa98e2SPeter Wemm 		}
917c2aa98e2SPeter Wemm 		if (cmtlev > 0)
918c2aa98e2SPeter Wemm 		{
919c2aa98e2SPeter Wemm 			if (c == ')')
920c2aa98e2SPeter Wemm 			{
921c2aa98e2SPeter Wemm 				cmtlev--;
922c2aa98e2SPeter Wemm 				copylev--;
923c2aa98e2SPeter Wemm 				if (!skipping)
924c2aa98e2SPeter Wemm 				{
925c2aa98e2SPeter Wemm 					realcmtlev--;
926c2aa98e2SPeter Wemm 					buflim++;
927c2aa98e2SPeter Wemm 				}
928c2aa98e2SPeter Wemm 			}
929c2aa98e2SPeter Wemm 			continue;
930c2aa98e2SPeter Wemm 		}
931c2aa98e2SPeter Wemm 		else if (c == ')')
932c2aa98e2SPeter Wemm 		{
933c2aa98e2SPeter Wemm 			/* syntax error: unmatched ) */
934c2aa98e2SPeter Wemm 			if (copylev > 0 && !skipping)
935c2aa98e2SPeter Wemm 				bp--;
936c2aa98e2SPeter Wemm 		}
937c2aa98e2SPeter Wemm 
938c2aa98e2SPeter Wemm 		/* count nesting on [ ... ] (for IPv6 domain literals) */
939c2aa98e2SPeter Wemm 		if (c == '[')
940c2aa98e2SPeter Wemm 			bracklev++;
941c2aa98e2SPeter Wemm 		else if (c == ']')
942c2aa98e2SPeter Wemm 			bracklev--;
943c2aa98e2SPeter Wemm 
944c2aa98e2SPeter Wemm 		/* check for group: list; syntax */
945c2aa98e2SPeter Wemm 		if (c == ':' && anglelev <= 0 && bracklev <= 0 &&
946c2aa98e2SPeter Wemm 		    !gotcolon && !ColonOkInAddr)
947c2aa98e2SPeter Wemm 		{
948c2aa98e2SPeter Wemm 			register char *q;
949c2aa98e2SPeter Wemm 
950c2aa98e2SPeter Wemm 			/*
951c2aa98e2SPeter Wemm 			**  Check for DECnet phase IV ``::'' (host::user)
952c2aa98e2SPeter Wemm 			**  or **  DECnet phase V ``:.'' syntaxes.  The latter
953c2aa98e2SPeter Wemm 			**  covers ``user@DEC:.tay.myhost'' and
954c2aa98e2SPeter Wemm 			**  ``DEC:.tay.myhost::user'' syntaxes (bletch).
955c2aa98e2SPeter Wemm 			*/
956c2aa98e2SPeter Wemm 
957c2aa98e2SPeter Wemm 			if (*p == ':' || *p == '.')
958c2aa98e2SPeter Wemm 			{
959c2aa98e2SPeter Wemm 				if (cmtlev <= 0 && !qmode)
960c2aa98e2SPeter Wemm 					quoteit = TRUE;
961c2aa98e2SPeter Wemm 				if (copylev > 0 && !skipping)
962c2aa98e2SPeter Wemm 				{
963c2aa98e2SPeter Wemm 					*bp++ = c;
964c2aa98e2SPeter Wemm 					*bp++ = *p;
965c2aa98e2SPeter Wemm 				}
966c2aa98e2SPeter Wemm 				p++;
967c2aa98e2SPeter Wemm 				goto putg;
968c2aa98e2SPeter Wemm 			}
969c2aa98e2SPeter Wemm 
970c2aa98e2SPeter Wemm 			gotcolon = TRUE;
971c2aa98e2SPeter Wemm 
972c2aa98e2SPeter Wemm 			bp = bufhead;
973c2aa98e2SPeter Wemm 			if (quoteit)
974c2aa98e2SPeter Wemm 			{
975c2aa98e2SPeter Wemm 				*bp++ = '"';
976c2aa98e2SPeter Wemm 
977c2aa98e2SPeter Wemm 				/* back up over the ':' and any spaces */
978c2aa98e2SPeter Wemm 				--p;
979c2aa98e2SPeter Wemm 				while (isascii(*--p) && isspace(*p))
980c2aa98e2SPeter Wemm 					continue;
981c2aa98e2SPeter Wemm 				p++;
982c2aa98e2SPeter Wemm 			}
983c2aa98e2SPeter Wemm 			for (q = addrhead; q < p; )
984c2aa98e2SPeter Wemm 			{
985c2aa98e2SPeter Wemm 				c = *q++;
986c2aa98e2SPeter Wemm 				if (bp < buflim)
987c2aa98e2SPeter Wemm 				{
988c2aa98e2SPeter Wemm 					if (quoteit && c == '"')
989c2aa98e2SPeter Wemm 						*bp++ = '\\';
990c2aa98e2SPeter Wemm 					*bp++ = c;
991c2aa98e2SPeter Wemm 				}
992c2aa98e2SPeter Wemm 			}
993c2aa98e2SPeter Wemm 			if (quoteit)
994c2aa98e2SPeter Wemm 			{
995c2aa98e2SPeter Wemm 				if (bp == &bufhead[1])
996c2aa98e2SPeter Wemm 					bp--;
997c2aa98e2SPeter Wemm 				else
998c2aa98e2SPeter Wemm 					*bp++ = '"';
999c2aa98e2SPeter Wemm 				while ((c = *p++) != ':')
1000c2aa98e2SPeter Wemm 				{
1001c2aa98e2SPeter Wemm 					if (bp < buflim)
1002c2aa98e2SPeter Wemm 						*bp++ = c;
1003c2aa98e2SPeter Wemm 				}
1004c2aa98e2SPeter Wemm 				*bp++ = c;
1005c2aa98e2SPeter Wemm 			}
1006c2aa98e2SPeter Wemm 
1007c2aa98e2SPeter Wemm 			/* any trailing white space is part of group: */
1008c2aa98e2SPeter Wemm 			while (isascii(*p) && isspace(*p) && bp < buflim)
1009c2aa98e2SPeter Wemm 				*bp++ = *p++;
1010c2aa98e2SPeter Wemm 			copylev = 0;
1011c2aa98e2SPeter Wemm 			putgmac = quoteit = FALSE;
1012c2aa98e2SPeter Wemm 			bufhead = bp;
1013c2aa98e2SPeter Wemm 			addrhead = p;
1014c2aa98e2SPeter Wemm 			continue;
1015c2aa98e2SPeter Wemm 		}
1016c2aa98e2SPeter Wemm 
1017c2aa98e2SPeter Wemm 		if (c == ';' && copylev <= 0 && !ColonOkInAddr)
1018c2aa98e2SPeter Wemm 		{
1019c2aa98e2SPeter Wemm 			if (bp < buflim)
1020c2aa98e2SPeter Wemm 				*bp++ = c;
1021c2aa98e2SPeter Wemm 		}
1022c2aa98e2SPeter Wemm 
1023c2aa98e2SPeter Wemm 		/* check for characters that may have to be quoted */
1024c2aa98e2SPeter Wemm 		if (strchr(MustQuoteChars, c) != NULL)
1025c2aa98e2SPeter Wemm 		{
1026c2aa98e2SPeter Wemm 			/*
1027c2aa98e2SPeter Wemm 			**  If these occur as the phrase part of a <>
1028c2aa98e2SPeter Wemm 			**  construct, but are not inside of () or already
1029c2aa98e2SPeter Wemm 			**  quoted, they will have to be quoted.  Note that
1030c2aa98e2SPeter Wemm 			**  now (but don't actually do the quoting).
1031c2aa98e2SPeter Wemm 			*/
1032c2aa98e2SPeter Wemm 
1033c2aa98e2SPeter Wemm 			if (cmtlev <= 0 && !qmode)
1034c2aa98e2SPeter Wemm 				quoteit = TRUE;
1035c2aa98e2SPeter Wemm 		}
1036c2aa98e2SPeter Wemm 
1037c2aa98e2SPeter Wemm 		/* check for angle brackets */
1038c2aa98e2SPeter Wemm 		if (c == '<')
1039c2aa98e2SPeter Wemm 		{
1040c2aa98e2SPeter Wemm 			register char *q;
1041c2aa98e2SPeter Wemm 
1042c2aa98e2SPeter Wemm 			/* assume first of two angles is bogus */
1043c2aa98e2SPeter Wemm 			if (gotangle)
1044c2aa98e2SPeter Wemm 				quoteit = TRUE;
1045c2aa98e2SPeter Wemm 			gotangle = TRUE;
1046c2aa98e2SPeter Wemm 
1047c2aa98e2SPeter Wemm 			/* oops -- have to change our mind */
1048c2aa98e2SPeter Wemm 			anglelev = 1;
1049c2aa98e2SPeter Wemm 			if (!skipping)
1050c2aa98e2SPeter Wemm 				realanglelev = 1;
1051c2aa98e2SPeter Wemm 
1052c2aa98e2SPeter Wemm 			bp = bufhead;
1053c2aa98e2SPeter Wemm 			if (quoteit)
1054c2aa98e2SPeter Wemm 			{
1055c2aa98e2SPeter Wemm 				*bp++ = '"';
1056c2aa98e2SPeter Wemm 
1057c2aa98e2SPeter Wemm 				/* back up over the '<' and any spaces */
1058c2aa98e2SPeter Wemm 				--p;
1059c2aa98e2SPeter Wemm 				while (isascii(*--p) && isspace(*p))
1060c2aa98e2SPeter Wemm 					continue;
1061c2aa98e2SPeter Wemm 				p++;
1062c2aa98e2SPeter Wemm 			}
1063c2aa98e2SPeter Wemm 			for (q = addrhead; q < p; )
1064c2aa98e2SPeter Wemm 			{
1065c2aa98e2SPeter Wemm 				c = *q++;
1066c2aa98e2SPeter Wemm 				if (bp < buflim)
1067c2aa98e2SPeter Wemm 				{
1068c2aa98e2SPeter Wemm 					if (quoteit && c == '"')
1069c2aa98e2SPeter Wemm 						*bp++ = '\\';
1070c2aa98e2SPeter Wemm 					*bp++ = c;
1071c2aa98e2SPeter Wemm 				}
1072c2aa98e2SPeter Wemm 			}
1073c2aa98e2SPeter Wemm 			if (quoteit)
1074c2aa98e2SPeter Wemm 			{
1075c2aa98e2SPeter Wemm 				if (bp == &buf[1])
1076c2aa98e2SPeter Wemm 					bp--;
1077c2aa98e2SPeter Wemm 				else
1078c2aa98e2SPeter Wemm 					*bp++ = '"';
1079c2aa98e2SPeter Wemm 				while ((c = *p++) != '<')
1080c2aa98e2SPeter Wemm 				{
1081c2aa98e2SPeter Wemm 					if (bp < buflim)
1082c2aa98e2SPeter Wemm 						*bp++ = c;
1083c2aa98e2SPeter Wemm 				}
1084c2aa98e2SPeter Wemm 				*bp++ = c;
1085c2aa98e2SPeter Wemm 			}
1086c2aa98e2SPeter Wemm 			copylev = 0;
1087c2aa98e2SPeter Wemm 			putgmac = quoteit = FALSE;
1088c2aa98e2SPeter Wemm 			continue;
1089c2aa98e2SPeter Wemm 		}
1090c2aa98e2SPeter Wemm 
1091c2aa98e2SPeter Wemm 		if (c == '>')
1092c2aa98e2SPeter Wemm 		{
1093c2aa98e2SPeter Wemm 			if (anglelev > 0)
1094c2aa98e2SPeter Wemm 			{
1095c2aa98e2SPeter Wemm 				anglelev--;
1096c2aa98e2SPeter Wemm 				if (!skipping)
1097c2aa98e2SPeter Wemm 				{
1098c2aa98e2SPeter Wemm 					realanglelev--;
1099c2aa98e2SPeter Wemm 					buflim++;
1100c2aa98e2SPeter Wemm 				}
1101c2aa98e2SPeter Wemm 			}
1102c2aa98e2SPeter Wemm 			else if (!skipping)
1103c2aa98e2SPeter Wemm 			{
1104c2aa98e2SPeter Wemm 				/* syntax error: unmatched > */
1105c2aa98e2SPeter Wemm 				if (copylev > 0)
1106c2aa98e2SPeter Wemm 					bp--;
1107c2aa98e2SPeter Wemm 				quoteit = TRUE;
1108c2aa98e2SPeter Wemm 				continue;
1109c2aa98e2SPeter Wemm 			}
1110c2aa98e2SPeter Wemm 			if (copylev++ <= 0)
1111c2aa98e2SPeter Wemm 				*bp++ = c;
1112c2aa98e2SPeter Wemm 			continue;
1113c2aa98e2SPeter Wemm 		}
1114c2aa98e2SPeter Wemm 
1115c2aa98e2SPeter Wemm 		/* must be a real address character */
1116c2aa98e2SPeter Wemm 	putg:
1117c2aa98e2SPeter Wemm 		if (copylev <= 0 && !putgmac)
1118c2aa98e2SPeter Wemm 		{
1119c2aa98e2SPeter Wemm 			if (bp > bufhead && bp[-1] == ')')
1120c2aa98e2SPeter Wemm 				*bp++ = ' ';
1121c2aa98e2SPeter Wemm 			*bp++ = MACROEXPAND;
1122c2aa98e2SPeter Wemm 			*bp++ = 'g';
1123c2aa98e2SPeter Wemm 			putgmac = TRUE;
1124c2aa98e2SPeter Wemm 		}
1125c2aa98e2SPeter Wemm 	}
1126c2aa98e2SPeter Wemm 
1127c2aa98e2SPeter Wemm 	/* repair any syntactic damage */
1128c2aa98e2SPeter Wemm 	if (realqmode)
1129c2aa98e2SPeter Wemm 		*bp++ = '"';
1130c2aa98e2SPeter Wemm 	while (realcmtlev-- > 0)
1131c2aa98e2SPeter Wemm 		*bp++ = ')';
1132c2aa98e2SPeter Wemm 	while (realanglelev-- > 0)
1133c2aa98e2SPeter Wemm 		*bp++ = '>';
1134c2aa98e2SPeter Wemm 	*bp++ = '\0';
1135c2aa98e2SPeter Wemm 
1136c2aa98e2SPeter Wemm 	if (tTd(33, 1))
1137c2aa98e2SPeter Wemm 	{
1138c2aa98e2SPeter Wemm 		printf("crackaddr=>`");
1139c2aa98e2SPeter Wemm 		xputs(buf);
1140c2aa98e2SPeter Wemm 		printf("'\n");
1141c2aa98e2SPeter Wemm 	}
1142c2aa98e2SPeter Wemm 
1143c2aa98e2SPeter Wemm 	return (buf);
1144c2aa98e2SPeter Wemm }
1145c2aa98e2SPeter Wemm /*
1146c2aa98e2SPeter Wemm **  PUTHEADER -- put the header part of a message from the in-core copy
1147c2aa98e2SPeter Wemm **
1148c2aa98e2SPeter Wemm **	Parameters:
1149c2aa98e2SPeter Wemm **		mci -- the connection information.
1150c2aa98e2SPeter Wemm **		h -- the header to put.
1151c2aa98e2SPeter Wemm **		e -- envelope to use.
1152c2aa98e2SPeter Wemm **
1153c2aa98e2SPeter Wemm **	Returns:
1154c2aa98e2SPeter Wemm **		none.
1155c2aa98e2SPeter Wemm **
1156c2aa98e2SPeter Wemm **	Side Effects:
1157c2aa98e2SPeter Wemm **		none.
1158c2aa98e2SPeter Wemm */
1159c2aa98e2SPeter Wemm 
1160c2aa98e2SPeter Wemm /*
1161c2aa98e2SPeter Wemm  * Macro for fast max (not available in e.g. DG/UX, 386/ix).
1162c2aa98e2SPeter Wemm  */
1163c2aa98e2SPeter Wemm #ifndef MAX
1164c2aa98e2SPeter Wemm # define MAX(a,b) (((a)>(b))?(a):(b))
1165c2aa98e2SPeter Wemm #endif
1166c2aa98e2SPeter Wemm 
1167c2aa98e2SPeter Wemm void
1168c2aa98e2SPeter Wemm putheader(mci, hdr, e)
1169c2aa98e2SPeter Wemm 	register MCI *mci;
1170c2aa98e2SPeter Wemm 	HDR *hdr;
1171c2aa98e2SPeter Wemm 	register ENVELOPE *e;
1172c2aa98e2SPeter Wemm {
1173c2aa98e2SPeter Wemm 	register HDR *h;
1174c2aa98e2SPeter Wemm 	char buf[MAX(MAXLINE,BUFSIZ)];
1175c2aa98e2SPeter Wemm 	char obuf[MAXLINE];
1176c2aa98e2SPeter Wemm 
1177c2aa98e2SPeter Wemm 	if (tTd(34, 1))
1178c2aa98e2SPeter Wemm 		printf("--- putheader, mailer = %s ---\n",
1179c2aa98e2SPeter Wemm 			mci->mci_mailer->m_name);
1180c2aa98e2SPeter Wemm 
1181c2aa98e2SPeter Wemm 	/*
1182c2aa98e2SPeter Wemm 	**  If we're in MIME mode, we're not really in the header of the
1183c2aa98e2SPeter Wemm 	**  message, just the header of one of the parts of the body of
1184c2aa98e2SPeter Wemm 	**  the message.  Therefore MCIF_INHEADER should not be turned on.
1185c2aa98e2SPeter Wemm 	*/
1186c2aa98e2SPeter Wemm 
1187c2aa98e2SPeter Wemm 	if (!bitset(MCIF_INMIME, mci->mci_flags))
1188c2aa98e2SPeter Wemm 		mci->mci_flags |= MCIF_INHEADER;
1189c2aa98e2SPeter Wemm 
1190c2aa98e2SPeter Wemm 	for (h = hdr; h != NULL; h = h->h_link)
1191c2aa98e2SPeter Wemm 	{
1192c2aa98e2SPeter Wemm 		register char *p = h->h_value;
1193c2aa98e2SPeter Wemm 		extern bool bitintersect __P((BITMAP, BITMAP));
1194c2aa98e2SPeter Wemm 
1195c2aa98e2SPeter Wemm 		if (tTd(34, 11))
1196c2aa98e2SPeter Wemm 		{
1197c2aa98e2SPeter Wemm 			printf("  %s: ", h->h_field);
1198c2aa98e2SPeter Wemm 			xputs(p);
1199c2aa98e2SPeter Wemm 		}
1200c2aa98e2SPeter Wemm 
1201c2aa98e2SPeter Wemm 		/* suppress Content-Transfer-Encoding: if we are MIMEing */
1202c2aa98e2SPeter Wemm 		if (bitset(H_CTE, h->h_flags) &&
1203c2aa98e2SPeter Wemm 		    bitset(MCIF_CVT8TO7|MCIF_CVT7TO8|MCIF_INMIME, mci->mci_flags))
1204c2aa98e2SPeter Wemm 		{
1205c2aa98e2SPeter Wemm 			if (tTd(34, 11))
1206c2aa98e2SPeter Wemm 				printf(" (skipped (content-transfer-encoding))\n");
1207c2aa98e2SPeter Wemm 			continue;
1208c2aa98e2SPeter Wemm 		}
1209c2aa98e2SPeter Wemm 
1210c2aa98e2SPeter Wemm 		if (bitset(MCIF_INMIME, mci->mci_flags))
1211c2aa98e2SPeter Wemm 		{
1212c2aa98e2SPeter Wemm 			if (tTd(34, 11))
1213c2aa98e2SPeter Wemm 				printf("\n");
1214c2aa98e2SPeter Wemm 			put_vanilla_header(h, p, mci);
1215c2aa98e2SPeter Wemm 			continue;
1216c2aa98e2SPeter Wemm 		}
1217c2aa98e2SPeter Wemm 
1218c2aa98e2SPeter Wemm 		if (bitset(H_CHECK|H_ACHECK, h->h_flags) &&
1219c2aa98e2SPeter Wemm 		    !bitintersect(h->h_mflags, mci->mci_mailer->m_flags))
1220c2aa98e2SPeter Wemm 		{
1221c2aa98e2SPeter Wemm 			if (tTd(34, 11))
1222c2aa98e2SPeter Wemm 				printf(" (skipped)\n");
1223c2aa98e2SPeter Wemm 			continue;
1224c2aa98e2SPeter Wemm 		}
1225c2aa98e2SPeter Wemm 
1226c2aa98e2SPeter Wemm 		/* handle Resent-... headers specially */
1227c2aa98e2SPeter Wemm 		if (bitset(H_RESENT, h->h_flags) && !bitset(EF_RESENT, e->e_flags))
1228c2aa98e2SPeter Wemm 		{
1229c2aa98e2SPeter Wemm 			if (tTd(34, 11))
1230c2aa98e2SPeter Wemm 				printf(" (skipped (resent))\n");
1231c2aa98e2SPeter Wemm 			continue;
1232c2aa98e2SPeter Wemm 		}
1233c2aa98e2SPeter Wemm 
1234c2aa98e2SPeter Wemm 		/* suppress return receipts if requested */
1235c2aa98e2SPeter Wemm 		if (bitset(H_RECEIPTTO, h->h_flags) &&
1236c2aa98e2SPeter Wemm #if _FFR_DSN_RRT_OPTION
1237c2aa98e2SPeter Wemm 		    (RrtImpliesDsn || bitset(EF_NORECEIPT, e->e_flags)))
1238c2aa98e2SPeter Wemm #else
1239c2aa98e2SPeter Wemm 		    bitset(EF_NORECEIPT, e->e_flags))
1240c2aa98e2SPeter Wemm #endif
1241c2aa98e2SPeter Wemm 		{
1242c2aa98e2SPeter Wemm 			if (tTd(34, 11))
1243c2aa98e2SPeter Wemm 				printf(" (skipped (receipt))\n");
1244c2aa98e2SPeter Wemm 			continue;
1245c2aa98e2SPeter Wemm 		}
1246c2aa98e2SPeter Wemm 
1247c2aa98e2SPeter Wemm 		/* macro expand value if generated internally */
1248c2aa98e2SPeter Wemm 		if (bitset(H_DEFAULT, h->h_flags))
1249c2aa98e2SPeter Wemm 		{
1250c2aa98e2SPeter Wemm 			expand(p, buf, sizeof buf, e);
1251c2aa98e2SPeter Wemm 			p = buf;
1252c2aa98e2SPeter Wemm 			if (*p == '\0')
1253c2aa98e2SPeter Wemm 			{
1254c2aa98e2SPeter Wemm 				if (tTd(34, 11))
1255c2aa98e2SPeter Wemm 					printf(" (skipped -- null value)\n");
1256c2aa98e2SPeter Wemm 				continue;
1257c2aa98e2SPeter Wemm 			}
1258c2aa98e2SPeter Wemm 		}
1259c2aa98e2SPeter Wemm 
1260c2aa98e2SPeter Wemm 		if (bitset(H_BCC, h->h_flags))
1261c2aa98e2SPeter Wemm 		{
1262c2aa98e2SPeter Wemm 			/* Bcc: field -- either truncate or delete */
1263c2aa98e2SPeter Wemm 			if (bitset(EF_DELETE_BCC, e->e_flags))
1264c2aa98e2SPeter Wemm 			{
1265c2aa98e2SPeter Wemm 				if (tTd(34, 11))
1266c2aa98e2SPeter Wemm 					printf(" (skipped -- bcc)\n");
1267c2aa98e2SPeter Wemm 			}
1268c2aa98e2SPeter Wemm 			else
1269c2aa98e2SPeter Wemm 			{
1270c2aa98e2SPeter Wemm 				/* no other recipient headers: truncate value */
1271c2aa98e2SPeter Wemm 				(void) snprintf(obuf, sizeof obuf, "%s:",
1272c2aa98e2SPeter Wemm 					h->h_field);
1273c2aa98e2SPeter Wemm 				putline(obuf, mci);
1274c2aa98e2SPeter Wemm 			}
1275c2aa98e2SPeter Wemm 			continue;
1276c2aa98e2SPeter Wemm 		}
1277c2aa98e2SPeter Wemm 
1278c2aa98e2SPeter Wemm 		if (tTd(34, 11))
1279c2aa98e2SPeter Wemm 			printf("\n");
1280c2aa98e2SPeter Wemm 
1281c2aa98e2SPeter Wemm 		if (bitset(H_FROM|H_RCPT, h->h_flags))
1282c2aa98e2SPeter Wemm 		{
1283c2aa98e2SPeter Wemm 			/* address field */
1284c2aa98e2SPeter Wemm 			bool oldstyle = bitset(EF_OLDSTYLE, e->e_flags);
1285c2aa98e2SPeter Wemm 
1286c2aa98e2SPeter Wemm 			if (bitset(H_FROM, h->h_flags))
1287c2aa98e2SPeter Wemm 				oldstyle = FALSE;
1288c2aa98e2SPeter Wemm 			commaize(h, p, oldstyle, mci, e);
1289c2aa98e2SPeter Wemm 		}
1290c2aa98e2SPeter Wemm 		else
1291c2aa98e2SPeter Wemm 		{
1292c2aa98e2SPeter Wemm 			put_vanilla_header(h, p, mci);
1293c2aa98e2SPeter Wemm 		}
1294c2aa98e2SPeter Wemm 	}
1295c2aa98e2SPeter Wemm 
1296c2aa98e2SPeter Wemm 	/*
1297c2aa98e2SPeter Wemm 	**  If we are converting this to a MIME message, add the
1298c2aa98e2SPeter Wemm 	**  MIME headers.
1299c2aa98e2SPeter Wemm 	*/
1300c2aa98e2SPeter Wemm 
1301c2aa98e2SPeter Wemm #if MIME8TO7
1302c2aa98e2SPeter Wemm 	if (bitset(MM_MIME8BIT, MimeMode) &&
1303c2aa98e2SPeter Wemm 	    bitset(EF_HAS8BIT, e->e_flags) &&
1304c2aa98e2SPeter Wemm 	    !bitset(EF_DONT_MIME, e->e_flags) &&
1305c2aa98e2SPeter Wemm 	    !bitnset(M_8BITS, mci->mci_mailer->m_flags) &&
1306c2aa98e2SPeter Wemm 	    !bitset(MCIF_CVT8TO7|MCIF_CVT7TO8, mci->mci_flags))
1307c2aa98e2SPeter Wemm 	{
1308c2aa98e2SPeter Wemm 		if (hvalue("MIME-Version", e->e_header) == NULL)
1309c2aa98e2SPeter Wemm 			putline("MIME-Version: 1.0", mci);
1310c2aa98e2SPeter Wemm 		if (hvalue("Content-Type", e->e_header) == NULL)
1311c2aa98e2SPeter Wemm 		{
1312c2aa98e2SPeter Wemm 			snprintf(obuf, sizeof obuf,
1313c2aa98e2SPeter Wemm 				"Content-Type: text/plain; charset=%s",
1314c2aa98e2SPeter Wemm 				defcharset(e));
1315c2aa98e2SPeter Wemm 			putline(obuf, mci);
1316c2aa98e2SPeter Wemm 		}
1317c2aa98e2SPeter Wemm 		if (hvalue("Content-Transfer-Encoding", e->e_header) == NULL)
1318c2aa98e2SPeter Wemm 			putline("Content-Transfer-Encoding: 8bit", mci);
1319c2aa98e2SPeter Wemm 	}
1320c2aa98e2SPeter Wemm #endif
1321c2aa98e2SPeter Wemm }
1322c2aa98e2SPeter Wemm /*
1323c2aa98e2SPeter Wemm **  PUT_VANILLA_HEADER -- output a fairly ordinary header
1324c2aa98e2SPeter Wemm **
1325c2aa98e2SPeter Wemm **	Parameters:
1326c2aa98e2SPeter Wemm **		h -- the structure describing this header
1327c2aa98e2SPeter Wemm **		v -- the value of this header
1328c2aa98e2SPeter Wemm **		mci -- the connection info for output
1329c2aa98e2SPeter Wemm **
1330c2aa98e2SPeter Wemm **	Returns:
1331c2aa98e2SPeter Wemm **		none.
1332c2aa98e2SPeter Wemm */
1333c2aa98e2SPeter Wemm 
1334c2aa98e2SPeter Wemm void
1335c2aa98e2SPeter Wemm put_vanilla_header(h, v, mci)
1336c2aa98e2SPeter Wemm 	HDR *h;
1337c2aa98e2SPeter Wemm 	char *v;
1338c2aa98e2SPeter Wemm 	MCI *mci;
1339c2aa98e2SPeter Wemm {
1340c2aa98e2SPeter Wemm 	register char *nlp;
1341c2aa98e2SPeter Wemm 	register char *obp;
1342c2aa98e2SPeter Wemm 	int putflags;
1343c2aa98e2SPeter Wemm 	char obuf[MAXLINE];
1344c2aa98e2SPeter Wemm 
1345c2aa98e2SPeter Wemm 	putflags = PXLF_HEADER;
1346c2aa98e2SPeter Wemm #if _FFR_7BITHDRS
1347c2aa98e2SPeter Wemm 	if (bitnset(M_7BITHDRS, mci->mci_mailer->m_flags))
1348c2aa98e2SPeter Wemm 		putflags |= PXLF_STRIP8BIT;
1349c2aa98e2SPeter Wemm #endif
1350c2aa98e2SPeter Wemm 	(void) snprintf(obuf, sizeof obuf, "%.200s: ", h->h_field);
1351c2aa98e2SPeter Wemm 	obp = obuf + strlen(obuf);
1352c2aa98e2SPeter Wemm 	while ((nlp = strchr(v, '\n')) != NULL)
1353c2aa98e2SPeter Wemm 	{
1354c2aa98e2SPeter Wemm 		int l;
1355c2aa98e2SPeter Wemm 
1356c2aa98e2SPeter Wemm 		l = nlp - v;
1357c2aa98e2SPeter Wemm 		if (SPACELEFT(obuf, obp) - 1 < l)
1358c2aa98e2SPeter Wemm 			l = SPACELEFT(obuf, obp) - 1;
1359c2aa98e2SPeter Wemm 
1360c2aa98e2SPeter Wemm 		snprintf(obp, SPACELEFT(obuf, obp), "%.*s", l, v);
1361c2aa98e2SPeter Wemm 		putxline(obuf, strlen(obuf), mci, putflags);
1362c2aa98e2SPeter Wemm 		v += l + 1;
1363c2aa98e2SPeter Wemm 		obp = obuf;
1364c2aa98e2SPeter Wemm 		if (*v != ' ' && *v != '\t')
1365c2aa98e2SPeter Wemm 			*obp++ = ' ';
1366c2aa98e2SPeter Wemm 	}
1367c2aa98e2SPeter Wemm 	snprintf(obp, SPACELEFT(obuf, obp), "%.*s",
1368c2aa98e2SPeter Wemm 		sizeof obuf - (obp - obuf) - 1, v);
1369c2aa98e2SPeter Wemm 	putxline(obuf, strlen(obuf), mci, putflags);
1370c2aa98e2SPeter Wemm }
1371c2aa98e2SPeter Wemm /*
1372c2aa98e2SPeter Wemm **  COMMAIZE -- output a header field, making a comma-translated list.
1373c2aa98e2SPeter Wemm **
1374c2aa98e2SPeter Wemm **	Parameters:
1375c2aa98e2SPeter Wemm **		h -- the header field to output.
1376c2aa98e2SPeter Wemm **		p -- the value to put in it.
1377c2aa98e2SPeter Wemm **		oldstyle -- TRUE if this is an old style header.
1378c2aa98e2SPeter Wemm **		mci -- the connection information.
1379c2aa98e2SPeter Wemm **		e -- the envelope containing the message.
1380c2aa98e2SPeter Wemm **
1381c2aa98e2SPeter Wemm **	Returns:
1382c2aa98e2SPeter Wemm **		none.
1383c2aa98e2SPeter Wemm **
1384c2aa98e2SPeter Wemm **	Side Effects:
1385c2aa98e2SPeter Wemm **		outputs "p" to file "fp".
1386c2aa98e2SPeter Wemm */
1387c2aa98e2SPeter Wemm 
1388c2aa98e2SPeter Wemm void
1389c2aa98e2SPeter Wemm commaize(h, p, oldstyle, mci, e)
1390c2aa98e2SPeter Wemm 	register HDR *h;
1391c2aa98e2SPeter Wemm 	register char *p;
1392c2aa98e2SPeter Wemm 	bool oldstyle;
1393c2aa98e2SPeter Wemm 	register MCI *mci;
1394c2aa98e2SPeter Wemm 	register ENVELOPE *e;
1395c2aa98e2SPeter Wemm {
1396c2aa98e2SPeter Wemm 	register char *obp;
1397c2aa98e2SPeter Wemm 	int opos;
1398c2aa98e2SPeter Wemm 	int omax;
1399c2aa98e2SPeter Wemm 	bool firstone = TRUE;
1400c2aa98e2SPeter Wemm 	int putflags = PXLF_HEADER;
1401c2aa98e2SPeter Wemm 	char obuf[MAXLINE + 3];
1402c2aa98e2SPeter Wemm 
1403c2aa98e2SPeter Wemm 	/*
1404c2aa98e2SPeter Wemm 	**  Output the address list translated by the
1405c2aa98e2SPeter Wemm 	**  mailer and with commas.
1406c2aa98e2SPeter Wemm 	*/
1407c2aa98e2SPeter Wemm 
1408c2aa98e2SPeter Wemm 	if (tTd(14, 2))
1409c2aa98e2SPeter Wemm 		printf("commaize(%s: %s)\n", h->h_field, p);
1410c2aa98e2SPeter Wemm 
1411c2aa98e2SPeter Wemm #if _FFR_7BITHDRS
1412c2aa98e2SPeter Wemm 	if (bitnset(M_7BITHDRS, mci->mci_mailer->m_flags))
1413c2aa98e2SPeter Wemm 		putflags |= PXLF_STRIP8BIT;
1414c2aa98e2SPeter Wemm #endif
1415c2aa98e2SPeter Wemm 
1416c2aa98e2SPeter Wemm 	obp = obuf;
1417c2aa98e2SPeter Wemm 	(void) snprintf(obp, SPACELEFT(obuf, obp), "%.200s: ", h->h_field);
1418c2aa98e2SPeter Wemm 	opos = strlen(h->h_field) + 2;
1419c2aa98e2SPeter Wemm 	if (opos > 202)
1420c2aa98e2SPeter Wemm 		opos = 202;
1421c2aa98e2SPeter Wemm 	obp += opos;
1422c2aa98e2SPeter Wemm 	omax = mci->mci_mailer->m_linelimit - 2;
1423c2aa98e2SPeter Wemm 	if (omax < 0 || omax > 78)
1424c2aa98e2SPeter Wemm 		omax = 78;
1425c2aa98e2SPeter Wemm 
1426c2aa98e2SPeter Wemm 	/*
1427c2aa98e2SPeter Wemm 	**  Run through the list of values.
1428c2aa98e2SPeter Wemm 	*/
1429c2aa98e2SPeter Wemm 
1430c2aa98e2SPeter Wemm 	while (*p != '\0')
1431c2aa98e2SPeter Wemm 	{
1432c2aa98e2SPeter Wemm 		register char *name;
1433c2aa98e2SPeter Wemm 		register int c;
1434c2aa98e2SPeter Wemm 		char savechar;
1435c2aa98e2SPeter Wemm 		int flags;
1436c2aa98e2SPeter Wemm 		auto int stat;
1437c2aa98e2SPeter Wemm 
1438c2aa98e2SPeter Wemm 		/*
1439c2aa98e2SPeter Wemm 		**  Find the end of the name.  New style names
1440c2aa98e2SPeter Wemm 		**  end with a comma, old style names end with
1441c2aa98e2SPeter Wemm 		**  a space character.  However, spaces do not
1442c2aa98e2SPeter Wemm 		**  necessarily delimit an old-style name -- at
1443c2aa98e2SPeter Wemm 		**  signs mean keep going.
1444c2aa98e2SPeter Wemm 		*/
1445c2aa98e2SPeter Wemm 
1446c2aa98e2SPeter Wemm 		/* find end of name */
1447c2aa98e2SPeter Wemm 		while ((isascii(*p) && isspace(*p)) || *p == ',')
1448c2aa98e2SPeter Wemm 			p++;
1449c2aa98e2SPeter Wemm 		name = p;
1450c2aa98e2SPeter Wemm 		for (;;)
1451c2aa98e2SPeter Wemm 		{
1452c2aa98e2SPeter Wemm 			auto char *oldp;
1453c2aa98e2SPeter Wemm 			char pvpbuf[PSBUFSIZE];
1454c2aa98e2SPeter Wemm 
1455c2aa98e2SPeter Wemm 			(void) prescan(p, oldstyle ? ' ' : ',', pvpbuf,
1456c2aa98e2SPeter Wemm 				       sizeof pvpbuf, &oldp, NULL);
1457c2aa98e2SPeter Wemm 			p = oldp;
1458c2aa98e2SPeter Wemm 
1459c2aa98e2SPeter Wemm 			/* look to see if we have an at sign */
1460c2aa98e2SPeter Wemm 			while (*p != '\0' && isascii(*p) && isspace(*p))
1461c2aa98e2SPeter Wemm 				p++;
1462c2aa98e2SPeter Wemm 
1463c2aa98e2SPeter Wemm 			if (*p != '@')
1464c2aa98e2SPeter Wemm 			{
1465c2aa98e2SPeter Wemm 				p = oldp;
1466c2aa98e2SPeter Wemm 				break;
1467c2aa98e2SPeter Wemm 			}
1468c2aa98e2SPeter Wemm 			p += *p == '@' ? 1 : 2;
1469c2aa98e2SPeter Wemm 			while (*p != '\0' && isascii(*p) && isspace(*p))
1470c2aa98e2SPeter Wemm 				p++;
1471c2aa98e2SPeter Wemm 		}
1472c2aa98e2SPeter Wemm 		/* at the end of one complete name */
1473c2aa98e2SPeter Wemm 
1474c2aa98e2SPeter Wemm 		/* strip off trailing white space */
1475c2aa98e2SPeter Wemm 		while (p >= name &&
1476c2aa98e2SPeter Wemm 		       ((isascii(*p) && isspace(*p)) || *p == ',' || *p == '\0'))
1477c2aa98e2SPeter Wemm 			p--;
1478c2aa98e2SPeter Wemm 		if (++p == name)
1479c2aa98e2SPeter Wemm 			continue;
1480c2aa98e2SPeter Wemm 		savechar = *p;
1481c2aa98e2SPeter Wemm 		*p = '\0';
1482c2aa98e2SPeter Wemm 
1483c2aa98e2SPeter Wemm 		/* translate the name to be relative */
1484c2aa98e2SPeter Wemm 		flags = RF_HEADERADDR|RF_ADDDOMAIN;
1485c2aa98e2SPeter Wemm 		if (bitset(H_FROM, h->h_flags))
1486c2aa98e2SPeter Wemm 			flags |= RF_SENDERADDR;
1487c2aa98e2SPeter Wemm #if USERDB
1488c2aa98e2SPeter Wemm 		else if (e->e_from.q_mailer != NULL &&
1489c2aa98e2SPeter Wemm 			 bitnset(M_UDBRECIPIENT, e->e_from.q_mailer->m_flags))
1490c2aa98e2SPeter Wemm 		{
1491c2aa98e2SPeter Wemm 			extern char *udbsender __P((char *));
1492c2aa98e2SPeter Wemm 			char *q;
1493c2aa98e2SPeter Wemm 
1494c2aa98e2SPeter Wemm 			q = udbsender(name);
1495c2aa98e2SPeter Wemm 			if (q != NULL)
1496c2aa98e2SPeter Wemm 				name = q;
1497c2aa98e2SPeter Wemm 		}
1498c2aa98e2SPeter Wemm #endif
1499c2aa98e2SPeter Wemm 		stat = EX_OK;
1500c2aa98e2SPeter Wemm 		name = remotename(name, mci->mci_mailer, flags, &stat, e);
1501c2aa98e2SPeter Wemm 		if (*name == '\0')
1502c2aa98e2SPeter Wemm 		{
1503c2aa98e2SPeter Wemm 			*p = savechar;
1504c2aa98e2SPeter Wemm 			continue;
1505c2aa98e2SPeter Wemm 		}
1506c2aa98e2SPeter Wemm 		name = denlstring(name, FALSE, TRUE);
1507c2aa98e2SPeter Wemm 
1508c2aa98e2SPeter Wemm 		/* output the name with nice formatting */
1509c2aa98e2SPeter Wemm 		opos += strlen(name);
1510c2aa98e2SPeter Wemm 		if (!firstone)
1511c2aa98e2SPeter Wemm 			opos += 2;
1512c2aa98e2SPeter Wemm 		if (opos > omax && !firstone)
1513c2aa98e2SPeter Wemm 		{
1514c2aa98e2SPeter Wemm 			snprintf(obp, SPACELEFT(obuf, obp), ",\n");
1515c2aa98e2SPeter Wemm 			putxline(obuf, strlen(obuf), mci, putflags);
1516c2aa98e2SPeter Wemm 			obp = obuf;
1517c2aa98e2SPeter Wemm 			(void) strcpy(obp, "        ");
1518c2aa98e2SPeter Wemm 			opos = strlen(obp);
1519c2aa98e2SPeter Wemm 			obp += opos;
1520c2aa98e2SPeter Wemm 			opos += strlen(name);
1521c2aa98e2SPeter Wemm 		}
1522c2aa98e2SPeter Wemm 		else if (!firstone)
1523c2aa98e2SPeter Wemm 		{
1524c2aa98e2SPeter Wemm 			snprintf(obp, SPACELEFT(obuf, obp), ", ");
1525c2aa98e2SPeter Wemm 			obp += 2;
1526c2aa98e2SPeter Wemm 		}
1527c2aa98e2SPeter Wemm 
1528c2aa98e2SPeter Wemm 		while ((c = *name++) != '\0' && obp < &obuf[MAXLINE])
1529c2aa98e2SPeter Wemm 			*obp++ = c;
1530c2aa98e2SPeter Wemm 		firstone = FALSE;
1531c2aa98e2SPeter Wemm 		*p = savechar;
1532c2aa98e2SPeter Wemm 	}
1533c2aa98e2SPeter Wemm 	*obp = '\0';
1534c2aa98e2SPeter Wemm 	putxline(obuf, strlen(obuf), mci, putflags);
1535c2aa98e2SPeter Wemm }
1536c2aa98e2SPeter Wemm /*
1537c2aa98e2SPeter Wemm **  COPYHEADER -- copy header list
1538c2aa98e2SPeter Wemm **
1539c2aa98e2SPeter Wemm **	This routine is the equivalent of newstr for header lists
1540c2aa98e2SPeter Wemm **
1541c2aa98e2SPeter Wemm **	Parameters:
1542c2aa98e2SPeter Wemm **		header -- list of header structures to copy.
1543c2aa98e2SPeter Wemm **
1544c2aa98e2SPeter Wemm **	Returns:
1545c2aa98e2SPeter Wemm **		a copy of 'header'.
1546c2aa98e2SPeter Wemm **
1547c2aa98e2SPeter Wemm **	Side Effects:
1548c2aa98e2SPeter Wemm **		none.
1549c2aa98e2SPeter Wemm */
1550c2aa98e2SPeter Wemm 
1551c2aa98e2SPeter Wemm HDR *
1552c2aa98e2SPeter Wemm copyheader(header)
1553c2aa98e2SPeter Wemm 	register HDR *header;
1554c2aa98e2SPeter Wemm {
1555c2aa98e2SPeter Wemm 	register HDR *newhdr;
1556c2aa98e2SPeter Wemm 	HDR *ret;
1557c2aa98e2SPeter Wemm 	register HDR **tail = &ret;
1558c2aa98e2SPeter Wemm 
1559c2aa98e2SPeter Wemm 	while (header != NULL)
1560c2aa98e2SPeter Wemm 	{
1561c2aa98e2SPeter Wemm 		newhdr = (HDR *) xalloc(sizeof(HDR));
1562c2aa98e2SPeter Wemm 		STRUCTCOPY(*header, *newhdr);
1563c2aa98e2SPeter Wemm 		*tail = newhdr;
1564c2aa98e2SPeter Wemm 		tail = &newhdr->h_link;
1565c2aa98e2SPeter Wemm 		header = header->h_link;
1566c2aa98e2SPeter Wemm 	}
1567c2aa98e2SPeter Wemm 	*tail = NULL;
1568c2aa98e2SPeter Wemm 
1569c2aa98e2SPeter Wemm 	return ret;
1570c2aa98e2SPeter Wemm }
1571