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