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