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