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