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