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