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