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