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