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