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