1 /*
2  * Copyright (c) 1983 Eric P. Allman
3  * Copyright (c) 1988, 1993
4  *	The Regents of the University of California.  All rights reserved.
5  *
6  * %sccs.include.redist.c%
7  */
8 
9 #ifndef lint
10 static char sccsid[] = "@(#)headers.c	8.1 (Berkeley) 06/07/93";
11 #endif /* not lint */
12 
13 # include <errno.h>
14 # include "sendmail.h"
15 
16 /*
17 **  CHOMPHEADER -- process and save a header line.
18 **
19 **	Called by collect and by readcf to deal with header lines.
20 **
21 **	Parameters:
22 **		line -- header as a text line.
23 **		def -- if set, this is a default value.
24 **		e -- the envelope including this header.
25 **
26 **	Returns:
27 **		flags for this header.
28 **
29 **	Side Effects:
30 **		The header is saved on the header list.
31 **		Contents of 'line' are destroyed.
32 */
33 
34 chompheader(line, def, e)
35 	char *line;
36 	bool def;
37 	register ENVELOPE *e;
38 {
39 	register char *p;
40 	register HDR *h;
41 	HDR **hp;
42 	char *fname;
43 	char *fvalue;
44 	struct hdrinfo *hi;
45 	bool cond = FALSE;
46 	BITMAP mopts;
47 
48 	if (tTd(31, 6))
49 		printf("chompheader: %s\n", line);
50 
51 	/* strip off options */
52 	clrbitmap(mopts);
53 	p = line;
54 	if (*p == '?')
55 	{
56 		/* have some */
57 		register char *q = strchr(p + 1, *p);
58 
59 		if (q != NULL)
60 		{
61 			*q++ = '\0';
62 			while (*++p != '\0')
63 				setbitn(*p, mopts);
64 			p = q;
65 		}
66 		else
67 			usrerr("553 header syntax error, line \"%s\"", line);
68 		cond = TRUE;
69 	}
70 
71 	/* find canonical name */
72 	fname = p;
73 	p = strchr(p, ':');
74 	if (p == NULL)
75 	{
76 		syserr("553 header syntax error, line \"%s\"", line);
77 		return (0);
78 	}
79 	fvalue = &p[1];
80 	while (isascii(*--p) && isspace(*p))
81 		continue;
82 	*++p = '\0';
83 
84 	/* strip field value on front */
85 	if (*fvalue == ' ')
86 		fvalue++;
87 
88 	/* see if it is a known type */
89 	for (hi = HdrInfo; hi->hi_field != NULL; hi++)
90 	{
91 		if (strcasecmp(hi->hi_field, fname) == 0)
92 			break;
93 	}
94 
95 	/* see if this is a resent message */
96 	if (!def && bitset(H_RESENT, hi->hi_flags))
97 		e->e_flags |= EF_RESENT;
98 
99 	/* if this means "end of header" quit now */
100 	if (bitset(H_EOH, hi->hi_flags))
101 		return (hi->hi_flags);
102 
103 	/* drop explicit From: if same as what we would generate -- for MH */
104 	p = "resent-from";
105 	if (!bitset(EF_RESENT, e->e_flags))
106 		p += 7;
107 	if (!def && !bitset(EF_QUEUERUN, e->e_flags) && strcasecmp(fname, p) == 0)
108 	{
109 		if (e->e_from.q_paddr != NULL &&
110 		    strcmp(fvalue, e->e_from.q_paddr) == 0)
111 			return (hi->hi_flags);
112 	}
113 
114 	/* delete default value for this header */
115 	for (hp = &e->e_header; (h = *hp) != NULL; hp = &h->h_link)
116 	{
117 		if (strcasecmp(fname, h->h_field) == 0 &&
118 		    bitset(H_DEFAULT, h->h_flags) &&
119 		    !bitset(H_FORCE, h->h_flags))
120 			h->h_value = NULL;
121 	}
122 
123 	/* create a new node */
124 	h = (HDR *) xalloc(sizeof *h);
125 	h->h_field = newstr(fname);
126 	h->h_value = NULL;
127 	h->h_link = NULL;
128 	bcopy((char *) mopts, (char *) h->h_mflags, sizeof mopts);
129 	*hp = h;
130 	h->h_flags = hi->hi_flags;
131 	if (def)
132 		h->h_flags |= H_DEFAULT;
133 	if (cond)
134 		h->h_flags |= H_CHECK;
135 	if (h->h_value != NULL)
136 		free((char *) h->h_value);
137 	h->h_value = newstr(fvalue);
138 
139 	/* hack to see if this is a new format message */
140 	if (!def && bitset(H_RCPT|H_FROM, h->h_flags) &&
141 	    (strchr(fvalue, ',') != NULL || strchr(fvalue, '(') != NULL ||
142 	     strchr(fvalue, '<') != NULL || strchr(fvalue, ';') != NULL))
143 	{
144 		e->e_flags &= ~EF_OLDSTYLE;
145 	}
146 
147 	return (h->h_flags);
148 }
149 /*
150 **  ADDHEADER -- add a header entry to the end of the queue.
151 **
152 **	This bypasses the special checking of chompheader.
153 **
154 **	Parameters:
155 **		field -- the name of the header field.
156 **		value -- the value of the field.
157 **		e -- the envelope to add them to.
158 **
159 **	Returns:
160 **		none.
161 **
162 **	Side Effects:
163 **		adds the field on the list of headers for this envelope.
164 */
165 
166 addheader(field, value, e)
167 	char *field;
168 	char *value;
169 	ENVELOPE *e;
170 {
171 	register HDR *h;
172 	register struct hdrinfo *hi;
173 	HDR **hp;
174 
175 	/* find info struct */
176 	for (hi = HdrInfo; hi->hi_field != NULL; hi++)
177 	{
178 		if (strcasecmp(field, hi->hi_field) == 0)
179 			break;
180 	}
181 
182 	/* find current place in list -- keep back pointer? */
183 	for (hp = &e->e_header; (h = *hp) != NULL; hp = &h->h_link)
184 	{
185 		if (strcasecmp(field, h->h_field) == 0)
186 			break;
187 	}
188 
189 	/* allocate space for new header */
190 	h = (HDR *) xalloc(sizeof *h);
191 	h->h_field = field;
192 	h->h_value = newstr(value);
193 	h->h_link = *hp;
194 	h->h_flags = hi->hi_flags | H_DEFAULT;
195 	clrbitmap(h->h_mflags);
196 	*hp = h;
197 }
198 /*
199 **  HVALUE -- return value of a header.
200 **
201 **	Only "real" fields (i.e., ones that have not been supplied
202 **	as a default) are used.
203 **
204 **	Parameters:
205 **		field -- the field name.
206 **		e -- the envelope containing the header.
207 **
208 **	Returns:
209 **		pointer to the value part.
210 **		NULL if not found.
211 **
212 **	Side Effects:
213 **		none.
214 */
215 
216 char *
217 hvalue(field, e)
218 	char *field;
219 	register ENVELOPE *e;
220 {
221 	register HDR *h;
222 
223 	for (h = e->e_header; h != NULL; h = h->h_link)
224 	{
225 		if (!bitset(H_DEFAULT, h->h_flags) &&
226 		    strcasecmp(h->h_field, field) == 0)
227 			return (h->h_value);
228 	}
229 	return (NULL);
230 }
231 /*
232 **  ISHEADER -- predicate telling if argument is a header.
233 **
234 **	A line is a header if it has a single word followed by
235 **	optional white space followed by a colon.
236 **
237 **	Parameters:
238 **		s -- string to check for possible headerness.
239 **
240 **	Returns:
241 **		TRUE if s is a header.
242 **		FALSE otherwise.
243 **
244 **	Side Effects:
245 **		none.
246 */
247 
248 bool
249 isheader(s)
250 	register char *s;
251 {
252 	while (*s > ' ' && *s != ':' && *s != '\0')
253 		s++;
254 
255 	/* following technically violates RFC822 */
256 	while (isascii(*s) && isspace(*s))
257 		s++;
258 
259 	return (*s == ':');
260 }
261 /*
262 **  EATHEADER -- run through the stored header and extract info.
263 **
264 **	Parameters:
265 **		e -- the envelope to process.
266 **		full -- if set, do full processing (e.g., compute
267 **			message priority).
268 **
269 **	Returns:
270 **		none.
271 **
272 **	Side Effects:
273 **		Sets a bunch of global variables from information
274 **			in the collected header.
275 **		Aborts the message if the hop count is exceeded.
276 */
277 
278 eatheader(e, full)
279 	register ENVELOPE *e;
280 	bool full;
281 {
282 	register HDR *h;
283 	register char *p;
284 	int hopcnt = 0;
285 	char *msgid;
286 	char buf[MAXLINE];
287 
288 	/*
289 	**  Set up macros for possible expansion in headers.
290 	*/
291 
292 	define('f', e->e_sender, e);
293 	define('g', e->e_sender, e);
294 
295 	if (tTd(32, 1))
296 		printf("----- collected header -----\n");
297 	msgid = "<none>";
298 	for (h = e->e_header; h != NULL; h = h->h_link)
299 	{
300 		/* do early binding */
301 		if (bitset(H_DEFAULT, h->h_flags) && h->h_value != NULL)
302 		{
303 			expand(h->h_value, buf, &buf[sizeof buf], e);
304 			if (buf[0] != '\0')
305 			{
306 				h->h_value = newstr(buf);
307 				h->h_flags &= ~H_DEFAULT;
308 			}
309 		}
310 
311 		if (tTd(32, 1))
312 			printf("%s: %s\n", h->h_field, h->h_value);
313 
314 		/* count the number of times it has been processed */
315 		if (bitset(H_TRACE, h->h_flags))
316 			hopcnt++;
317 
318 		/* send to this person if we so desire */
319 		if (GrabTo && bitset(H_RCPT, h->h_flags) &&
320 		    !bitset(H_DEFAULT, h->h_flags) &&
321 		    (!bitset(EF_RESENT, e->e_flags) || bitset(H_RESENT, h->h_flags)))
322 		{
323 			(void) sendtolist(h->h_value, (ADDRESS *) NULL,
324 					  &e->e_sendqueue, e);
325 		}
326 
327 		/* save the message-id for logging */
328 		if (full && h->h_value != NULL &&
329 		    strcasecmp(h->h_field, "message-id") == 0)
330 		{
331 			msgid = h->h_value;
332 			while (isascii(*msgid) && isspace(*msgid))
333 				msgid++;
334 		}
335 
336 		/* see if this is a return-receipt header */
337 		if (bitset(H_RECEIPTTO, h->h_flags))
338 			e->e_receiptto = h->h_value;
339 
340 		/* see if this is an errors-to header */
341 		if (UseErrorsTo && bitset(H_ERRORSTO, h->h_flags))
342 			(void) sendtolist(h->h_value, (ADDRESS *) NULL,
343 					  &e->e_errorqueue, e);
344 	}
345 	if (tTd(32, 1))
346 		printf("----------------------------\n");
347 
348 	/* if we are just verifying (that is, sendmail -t -bv), drop out now */
349 	if (OpMode == MD_VERIFY)
350 		return;
351 
352 	/* store hop count */
353 	if (hopcnt > e->e_hopcount)
354 		e->e_hopcount = hopcnt;
355 
356 	/* message priority */
357 	p = hvalue("precedence", e);
358 	if (p != NULL)
359 		e->e_class = priencode(p);
360 	if (full)
361 		e->e_msgpriority = e->e_msgsize
362 				 - e->e_class * WkClassFact
363 				 + e->e_nrcpts * WkRecipFact;
364 
365 	/* full name of from person */
366 	p = hvalue("full-name", e);
367 	if (p != NULL)
368 		define('x', p, e);
369 
370 	/* date message originated */
371 	p = hvalue("posted-date", e);
372 	if (p == NULL)
373 		p = hvalue("date", e);
374 	if (p != NULL)
375 		define('a', p, e);
376 
377 	/*
378 	**  Log collection information.
379 	*/
380 
381 # ifdef LOG
382 	if (full && LogLevel > 4)
383 	{
384 		char *name;
385 		register char *sbp;
386 		char hbuf[MAXNAME];
387 		char sbuf[MAXLINE];
388 
389 		if (bitset(EF_RESPONSE, e->e_flags))
390 			name = "[RESPONSE]";
391 		else if ((name = macvalue('_', e)) != NULL)
392 			;
393 		else if (RealHostName[0] == '[')
394 			name = RealHostName;
395 		else
396 		{
397 			name = hbuf;
398 			(void) sprintf(hbuf, "%.80s", RealHostName);
399 			if (RealHostAddr.sa.sa_family != 0)
400 			{
401 				p = &hbuf[strlen(hbuf)];
402 				(void) sprintf(p, " (%s)",
403 					anynet_ntoa(&RealHostAddr));
404 			}
405 		}
406 
407 		/* some versions of syslog only take 5 printf args */
408 		sbp = sbuf;
409 		sprintf(sbp, "from=%.200s, size=%ld, class=%d, pri=%ld, nrcpts=%d, msgid=%.100s",
410 		    e->e_from.q_paddr, e->e_msgsize, e->e_class,
411 		    e->e_msgpriority, e->e_nrcpts, msgid);
412 		sbp += strlen(sbp);
413 		if (e->e_bodytype != NULL)
414 		{
415 			(void) sprintf(sbp, ", bodytype=%.20s", e->e_bodytype);
416 			sbp += strlen(sbp);
417 		}
418 		p = macvalue('r', e);
419 		if (p != NULL)
420 			(void) sprintf(sbp, ", proto=%.20s", p);
421 		syslog(LOG_INFO, "%s: %s, relay=%s",
422 		    e->e_id, sbuf, name);
423 	}
424 # endif /* LOG */
425 }
426 /*
427 **  PRIENCODE -- encode external priority names into internal values.
428 **
429 **	Parameters:
430 **		p -- priority in ascii.
431 **
432 **	Returns:
433 **		priority as a numeric level.
434 **
435 **	Side Effects:
436 **		none.
437 */
438 
439 priencode(p)
440 	char *p;
441 {
442 	register int i;
443 
444 	for (i = 0; i < NumPriorities; i++)
445 	{
446 		if (!strcasecmp(p, Priorities[i].pri_name))
447 			return (Priorities[i].pri_val);
448 	}
449 
450 	/* unknown priority */
451 	return (0);
452 }
453 /*
454 **  CRACKADDR -- parse an address and turn it into a macro
455 **
456 **	This doesn't actually parse the address -- it just extracts
457 **	it and replaces it with "$g".  The parse is totally ad hoc
458 **	and isn't even guaranteed to leave something syntactically
459 **	identical to what it started with.  However, it does leave
460 **	something semantically identical.
461 **
462 **	This algorithm has been cleaned up to handle a wider range
463 **	of cases -- notably quoted and backslash escaped strings.
464 **	This modification makes it substantially better at preserving
465 **	the original syntax.
466 **
467 **	Parameters:
468 **		addr -- the address to be cracked.
469 **
470 **	Returns:
471 **		a pointer to the new version.
472 **
473 **	Side Effects:
474 **		none.
475 **
476 **	Warning:
477 **		The return value is saved in local storage and should
478 **		be copied if it is to be reused.
479 */
480 
481 char *
482 crackaddr(addr)
483 	register char *addr;
484 {
485 	register char *p;
486 	register char c;
487 	int cmtlev;
488 	int realcmtlev;
489 	int anglelev, realanglelev;
490 	int copylev;
491 	bool qmode;
492 	bool realqmode;
493 	bool skipping;
494 	bool putgmac = FALSE;
495 	bool quoteit = FALSE;
496 	register char *bp;
497 	char *buflim;
498 	static char buf[MAXNAME];
499 
500 	if (tTd(33, 1))
501 		printf("crackaddr(%s)\n", addr);
502 
503 	/* strip leading spaces */
504 	while (*addr != '\0' && isascii(*addr) && isspace(*addr))
505 		addr++;
506 
507 	/*
508 	**  Start by assuming we have no angle brackets.  This will be
509 	**  adjusted later if we find them.
510 	*/
511 
512 	bp = buf;
513 	buflim = &buf[sizeof buf - 5];
514 	p = addr;
515 	copylev = anglelev = realanglelev = cmtlev = realcmtlev = 0;
516 	qmode = realqmode = FALSE;
517 
518 	while ((c = *p++) != '\0')
519 	{
520 		/*
521 		**  If the buffer is overful, go into a special "skipping"
522 		**  mode that tries to keep legal syntax but doesn't actually
523 		**  output things.
524 		*/
525 
526 		skipping = bp >= buflim;
527 
528 		if (copylev > 0 && !skipping)
529 			*bp++ = c;
530 
531 		/* check for backslash escapes */
532 		if (c == '\\')
533 		{
534 			/* arrange to quote the address */
535 			if (cmtlev <= 0 && !qmode)
536 				quoteit = TRUE;
537 
538 			if ((c = *p++) == '\0')
539 			{
540 				/* too far */
541 				p--;
542 				goto putg;
543 			}
544 			if (copylev > 0 && !skipping)
545 				*bp++ = c;
546 			goto putg;
547 		}
548 
549 		/* check for quoted strings */
550 		if (c == '"')
551 		{
552 			qmode = !qmode;
553 			if (copylev > 0 && !skipping)
554 				realqmode = !realqmode;
555 			continue;
556 		}
557 		if (qmode)
558 			goto putg;
559 
560 		/* check for comments */
561 		if (c == '(')
562 		{
563 			cmtlev++;
564 
565 			/* allow space for closing paren */
566 			if (!skipping)
567 			{
568 				buflim--;
569 				realcmtlev++;
570 				if (copylev++ <= 0)
571 				{
572 					*bp++ = ' ';
573 					*bp++ = c;
574 				}
575 			}
576 		}
577 		if (cmtlev > 0)
578 		{
579 			if (c == ')')
580 			{
581 				cmtlev--;
582 				copylev--;
583 				if (!skipping)
584 				{
585 					realcmtlev--;
586 					buflim++;
587 				}
588 			}
589 			continue;
590 		}
591 		else if (c == ')')
592 		{
593 			/* syntax error: unmatched ) */
594 			if (!skipping)
595 				bp--;
596 		}
597 
598 
599 		/* check for characters that may have to be quoted */
600 		if (strchr(".'@,;:\\()", c) != NULL)
601 		{
602 			/*
603 			**  If these occur as the phrase part of a <>
604 			**  construct, but are not inside of () or already
605 			**  quoted, they will have to be quoted.  Note that
606 			**  now (but don't actually do the quoting).
607 			*/
608 
609 			if (cmtlev <= 0 && !qmode)
610 				quoteit = TRUE;
611 		}
612 
613 		/* check for angle brackets */
614 		if (c == '<')
615 		{
616 			register char *q;
617 
618 			/* oops -- have to change our mind */
619 			anglelev++;
620 			if (!skipping)
621 				realanglelev++;
622 
623 			bp = buf;
624 			if (quoteit)
625 			{
626 				*bp++ = '"';
627 
628 				/* back up over the '<' and any spaces */
629 				--p;
630 				while (isascii(*--p) && isspace(*p))
631 					continue;
632 				p++;
633 			}
634 			for (q = addr; q < p; )
635 			{
636 				c = *q++;
637 				if (bp < buflim)
638 				{
639 					if (quoteit && c == '"')
640 						*bp++ = '\\';
641 					*bp++ = c;
642 				}
643 			}
644 			if (quoteit)
645 			{
646 				*bp++ = '"';
647 				while ((c = *p++) != '<')
648 				{
649 					if (bp < buflim)
650 						*bp++ = c;
651 				}
652 				*bp++ = c;
653 			}
654 			copylev = 0;
655 			putgmac = quoteit = FALSE;
656 			continue;
657 		}
658 
659 		if (c == '>')
660 		{
661 			if (anglelev > 0)
662 			{
663 				anglelev--;
664 				if (!skipping)
665 				{
666 					realanglelev--;
667 					buflim++;
668 				}
669 			}
670 			else if (!skipping)
671 			{
672 				/* syntax error: unmatched > */
673 				if (copylev > 0)
674 					bp--;
675 				continue;
676 			}
677 			if (copylev++ <= 0)
678 				*bp++ = c;
679 			continue;
680 		}
681 
682 		/* must be a real address character */
683 	putg:
684 		if (copylev <= 0 && !putgmac)
685 		{
686 			*bp++ = MACROEXPAND;
687 			*bp++ = 'g';
688 			putgmac = TRUE;
689 		}
690 	}
691 
692 	/* repair any syntactic damage */
693 	if (realqmode)
694 		*bp++ = '"';
695 	while (realcmtlev-- > 0)
696 		*bp++ = ')';
697 	while (realanglelev-- > 0)
698 		*bp++ = '>';
699 	*bp++ = '\0';
700 
701 	if (tTd(33, 1))
702 		printf("crackaddr=>`%s'\n", buf);
703 
704 	return (buf);
705 }
706 /*
707 **  PUTHEADER -- put the header part of a message from the in-core copy
708 **
709 **	Parameters:
710 **		fp -- file to put it on.
711 **		m -- mailer to use.
712 **		e -- envelope to use.
713 **
714 **	Returns:
715 **		none.
716 **
717 **	Side Effects:
718 **		none.
719 */
720 
721 /*
722  * Macro for fast max (not available in e.g. DG/UX, 386/ix).
723  */
724 #ifndef MAX
725 # define MAX(a,b) (((a)>(b))?(a):(b))
726 #endif
727 
728 putheader(fp, m, e)
729 	register FILE *fp;
730 	register MAILER *m;
731 	register ENVELOPE *e;
732 {
733 	char buf[MAX(MAXLINE,BUFSIZ)];
734 	register HDR *h;
735 	char obuf[MAXLINE];
736 
737 	if (tTd(34, 1))
738 		printf("--- putheader, mailer = %s ---\n", m->m_name);
739 
740 	for (h = e->e_header; h != NULL; h = h->h_link)
741 	{
742 		register char *p;
743 		extern bool bitintersect();
744 
745 		if (tTd(34, 11))
746 		{
747 			printf("  %s: ", h->h_field);
748 			xputs(h->h_value);
749 		}
750 
751 		if (bitset(H_CHECK|H_ACHECK, h->h_flags) &&
752 		    !bitintersect(h->h_mflags, m->m_flags))
753 		{
754 			if (tTd(34, 11))
755 				printf(" (skipped)\n");
756 			continue;
757 		}
758 
759 		/* handle Resent-... headers specially */
760 		if (bitset(H_RESENT, h->h_flags) && !bitset(EF_RESENT, e->e_flags))
761 		{
762 			if (tTd(34, 11))
763 				printf(" (skipped (resent))\n");
764 			continue;
765 		}
766 		if (tTd(34, 11))
767 			printf("\n");
768 
769 		p = h->h_value;
770 		if (bitset(H_DEFAULT, h->h_flags))
771 		{
772 			/* macro expand value if generated internally */
773 			expand(p, buf, &buf[sizeof buf], e);
774 			p = buf;
775 			if (p == NULL || *p == '\0')
776 				continue;
777 		}
778 
779 		if (bitset(H_FROM|H_RCPT, h->h_flags))
780 		{
781 			/* address field */
782 			bool oldstyle = bitset(EF_OLDSTYLE, e->e_flags);
783 
784 			if (bitset(H_FROM, h->h_flags))
785 				oldstyle = FALSE;
786 			commaize(h, p, fp, oldstyle, m, e);
787 		}
788 		else
789 		{
790 			/* vanilla header line */
791 			register char *nlp;
792 
793 			(void) sprintf(obuf, "%s: ", h->h_field);
794 			while ((nlp = strchr(p, '\n')) != NULL)
795 			{
796 				*nlp = '\0';
797 				(void) strcat(obuf, p);
798 				*nlp = '\n';
799 				putline(obuf, fp, m);
800 				p = ++nlp;
801 				obuf[0] = '\0';
802 			}
803 			(void) strcat(obuf, p);
804 			putline(obuf, fp, m);
805 		}
806 	}
807 }
808 /*
809 **  COMMAIZE -- output a header field, making a comma-translated list.
810 **
811 **	Parameters:
812 **		h -- the header field to output.
813 **		p -- the value to put in it.
814 **		fp -- file to put it to.
815 **		oldstyle -- TRUE if this is an old style header.
816 **		m -- a pointer to the mailer descriptor.  If NULL,
817 **			don't transform the name at all.
818 **		e -- the envelope containing the message.
819 **
820 **	Returns:
821 **		none.
822 **
823 **	Side Effects:
824 **		outputs "p" to file "fp".
825 */
826 
827 commaize(h, p, fp, oldstyle, m, e)
828 	register HDR *h;
829 	register char *p;
830 	FILE *fp;
831 	bool oldstyle;
832 	register MAILER *m;
833 	register ENVELOPE *e;
834 {
835 	register char *obp;
836 	int opos;
837 	bool firstone = TRUE;
838 	char obuf[MAXLINE + 3];
839 
840 	/*
841 	**  Output the address list translated by the
842 	**  mailer and with commas.
843 	*/
844 
845 	if (tTd(14, 2))
846 		printf("commaize(%s: %s)\n", h->h_field, p);
847 
848 	obp = obuf;
849 	(void) sprintf(obp, "%s: ", h->h_field);
850 	opos = strlen(h->h_field) + 2;
851 	obp += opos;
852 
853 	/*
854 	**  Run through the list of values.
855 	*/
856 
857 	while (*p != '\0')
858 	{
859 		register char *name;
860 		register int c;
861 		char savechar;
862 		int flags;
863 		auto int stat;
864 
865 		/*
866 		**  Find the end of the name.  New style names
867 		**  end with a comma, old style names end with
868 		**  a space character.  However, spaces do not
869 		**  necessarily delimit an old-style name -- at
870 		**  signs mean keep going.
871 		*/
872 
873 		/* find end of name */
874 		while ((isascii(*p) && isspace(*p)) || *p == ',')
875 			p++;
876 		name = p;
877 		for (;;)
878 		{
879 			auto char *oldp;
880 			char pvpbuf[PSBUFSIZE];
881 
882 			(void) prescan(p, oldstyle ? ' ' : ',', pvpbuf, &oldp);
883 			p = oldp;
884 
885 			/* look to see if we have an at sign */
886 			while (*p != '\0' && isascii(*p) && isspace(*p))
887 				p++;
888 
889 			if (*p != '@')
890 			{
891 				p = oldp;
892 				break;
893 			}
894 			p += *p == '@' ? 1 : 2;
895 			while (*p != '\0' && isascii(*p) && isspace(*p))
896 				p++;
897 		}
898 		/* at the end of one complete name */
899 
900 		/* strip off trailing white space */
901 		while (p >= name &&
902 		       ((isascii(*p) && isspace(*p)) || *p == ',' || *p == '\0'))
903 			p--;
904 		if (++p == name)
905 			continue;
906 		savechar = *p;
907 		*p = '\0';
908 
909 		/* translate the name to be relative */
910 		flags = RF_HEADERADDR|RF_ADDDOMAIN;
911 		if (bitset(H_FROM, h->h_flags))
912 			flags |= RF_SENDERADDR;
913 		stat = EX_OK;
914 		name = remotename(name, m, flags, &stat, e);
915 		if (*name == '\0')
916 		{
917 			*p = savechar;
918 			continue;
919 		}
920 
921 		/* output the name with nice formatting */
922 		opos += strlen(name);
923 		if (!firstone)
924 			opos += 2;
925 		if (opos > 78 && !firstone)
926 		{
927 			(void) strcpy(obp, ",\n");
928 			putline(obuf, fp, m);
929 			obp = obuf;
930 			(void) sprintf(obp, "        ");
931 			opos = strlen(obp);
932 			obp += opos;
933 			opos += strlen(name);
934 		}
935 		else if (!firstone)
936 		{
937 			(void) sprintf(obp, ", ");
938 			obp += 2;
939 		}
940 
941 		while ((c = *name++) != '\0' && obp < &obuf[MAXLINE])
942 			*obp++ = c;
943 		firstone = FALSE;
944 		*p = savechar;
945 	}
946 	(void) strcpy(obp, "\n");
947 	putline(obuf, fp, m);
948 }
949 /*
950 **  COPYHEADER -- copy header list
951 **
952 **	This routine is the equivalent of newstr for header lists
953 **
954 **	Parameters:
955 **		header -- list of header structures to copy.
956 **
957 **	Returns:
958 **		a copy of 'header'.
959 **
960 **	Side Effects:
961 **		none.
962 */
963 
964 HDR *
965 copyheader(header)
966 	register HDR *header;
967 {
968 	register HDR *newhdr;
969 	HDR *ret;
970 	register HDR **tail = &ret;
971 
972 	while (header != NULL)
973 	{
974 		newhdr = (HDR *) xalloc(sizeof(HDR));
975 		STRUCTCOPY(*header, *newhdr);
976 		*tail = newhdr;
977 		tail = &newhdr->h_link;
978 		header = header->h_link;
979 	}
980 	*tail = NULL;
981 
982 	return ret;
983 }
984