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.27 (Berkeley) 03/31/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 **
268 **	Returns:
269 **		none.
270 **
271 **	Side Effects:
272 **		Sets a bunch of global variables from information
273 **			in the collected header.
274 **		Aborts the message if the hop count is exceeded.
275 */
276 
277 eatheader(e)
278 	register ENVELOPE *e;
279 {
280 	register HDR *h;
281 	register char *p;
282 	int hopcnt = 0;
283 	char *msgid;
284 	char buf[MAXLINE];
285 
286 	/*
287 	**  Set up macros for possible expansion in headers.
288 	*/
289 
290 	define('f', e->e_sender, e);
291 	define('g', e->e_sender, e);
292 
293 	if (tTd(32, 1))
294 		printf("----- collected header -----\n");
295 	msgid = "<none>";
296 	for (h = e->e_header; h != NULL; h = h->h_link)
297 	{
298 		extern char *capitalize();
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", capitalize(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 (!bitset(EF_QUEUERUN, e->e_flags) && h->h_value != NULL &&
329 		    strcmp(h->h_field, "message-id") == 0)
330 		{
331 			msgid = h->h_value;
332 		}
333 
334 		/* see if this is a return-receipt header */
335 		if (bitset(H_RECEIPTTO, h->h_flags))
336 			e->e_receiptto = h->h_value;
337 
338 		/* see if this is an errors-to header */
339 		if (bitset(H_ERRORSTO, h->h_flags))
340 			(void) sendtolist(h->h_value, (ADDRESS *) NULL,
341 					  &e->e_errorqueue, e);
342 	}
343 	if (tTd(32, 1))
344 		printf("----------------------------\n");
345 
346 	/* if we are just verifying (that is, sendmail -t -bv), drop out now */
347 	if (OpMode == MD_VERIFY)
348 		return;
349 
350 	/* store hop count */
351 	if (hopcnt > e->e_hopcount)
352 		e->e_hopcount = hopcnt;
353 
354 	/* message priority */
355 	p = hvalue("precedence", e);
356 	if (p != NULL)
357 		e->e_class = priencode(p);
358 	if (!bitset(EF_QUEUERUN, e->e_flags))
359 		e->e_msgpriority = e->e_msgsize
360 				 - e->e_class * WkClassFact
361 				 + e->e_nrcpts * WkRecipFact;
362 
363 	/* full name of from person */
364 	p = hvalue("full-name", e);
365 	if (p != NULL)
366 		define('x', p, e);
367 
368 	/* date message originated */
369 	p = hvalue("posted-date", e);
370 	if (p == NULL)
371 		p = hvalue("date", e);
372 	if (p != NULL)
373 		define('a', p, e);
374 
375 	/*
376 	**  Log collection information.
377 	*/
378 
379 # ifdef LOG
380 	if (!bitset(EF_QUEUERUN, e->e_flags) && LogLevel > 4)
381 	{
382 		char *name;
383 		char hbuf[MAXNAME];
384 		char sbuf[MAXLINE];
385 
386 		if (bitset(EF_RESPONSE, e->e_flags))
387 			name = "[RESPONSE]";
388 		else if (RealHostName[0] == '[')
389 			name = RealHostName;
390 		else
391 		{
392 			extern char *anynet_ntoa();
393 
394 			name = hbuf;
395 			(void) sprintf(hbuf, "%.80s", RealHostName);
396 			if (RealHostAddr.sa.sa_family != 0)
397 			{
398 				p = &hbuf[strlen(hbuf)];
399 				(void) sprintf(p, " (%s)",
400 					anynet_ntoa(&RealHostAddr));
401 			}
402 		}
403 
404 		/* some versions of syslog only take 5 printf args */
405 		sprintf(sbuf, "from=%.200s, size=%ld, class=%d, pri=%ld, nrcpts=%d, msgid=%.100s",
406 		    e->e_from.q_paddr, e->e_msgsize, e->e_class,
407 		    e->e_msgpriority, e->e_nrcpts, msgid);
408 		syslog(LOG_INFO, "%s: %s, relay=%s",
409 		    e->e_id, sbuf, name);
410 	}
411 # endif /* LOG */
412 }
413 /*
414 **  PRIENCODE -- encode external priority names into internal values.
415 **
416 **	Parameters:
417 **		p -- priority in ascii.
418 **
419 **	Returns:
420 **		priority as a numeric level.
421 **
422 **	Side Effects:
423 **		none.
424 */
425 
426 priencode(p)
427 	char *p;
428 {
429 	register int i;
430 
431 	for (i = 0; i < NumPriorities; i++)
432 	{
433 		if (!strcasecmp(p, Priorities[i].pri_name))
434 			return (Priorities[i].pri_val);
435 	}
436 
437 	/* unknown priority */
438 	return (0);
439 }
440 /*
441 **  CRACKADDR -- parse an address and turn it into a macro
442 **
443 **	This doesn't actually parse the address -- it just extracts
444 **	it and replaces it with "$g".  The parse is totally ad hoc
445 **	and isn't even guaranteed to leave something syntactically
446 **	identical to what it started with.  However, it does leave
447 **	something semantically identical.
448 **
449 **	This algorithm has been cleaned up to handle a wider range
450 **	of cases -- notably quoted and backslash escaped strings.
451 **	This modification makes it substantially better at preserving
452 **	the original syntax.
453 **
454 **	Parameters:
455 **		addr -- the address to be cracked.
456 **
457 **	Returns:
458 **		a pointer to the new version.
459 **
460 **	Side Effects:
461 **		none.
462 **
463 **	Warning:
464 **		The return value is saved in local storage and should
465 **		be copied if it is to be reused.
466 */
467 
468 char *
469 crackaddr(addr)
470 	register char *addr;
471 {
472 	register char *p;
473 	register char c;
474 	int cmtlev;
475 	int realcmtlev;
476 	int anglelev, realanglelev;
477 	int copylev;
478 	bool qmode;
479 	bool realqmode;
480 	bool skipping;
481 	bool putgmac = FALSE;
482 	bool quoteit = FALSE;
483 	register char *bp;
484 	char *buflim;
485 	static char buf[MAXNAME];
486 
487 	if (tTd(33, 1))
488 		printf("crackaddr(%s)\n", addr);
489 
490 	/* strip leading spaces */
491 	while (*addr != '\0' && isascii(*addr) && isspace(*addr))
492 		addr++;
493 
494 	/*
495 	**  Start by assuming we have no angle brackets.  This will be
496 	**  adjusted later if we find them.
497 	*/
498 
499 	bp = buf;
500 	buflim = &buf[sizeof buf - 5];
501 	p = addr;
502 	copylev = anglelev = realanglelev = cmtlev = realcmtlev = 0;
503 	qmode = realqmode = FALSE;
504 
505 	while ((c = *p++) != '\0')
506 	{
507 		/*
508 		**  If the buffer is overful, go into a special "skipping"
509 		**  mode that tries to keep legal syntax but doesn't actually
510 		**  output things.
511 		*/
512 
513 		skipping = bp >= buflim;
514 
515 		if (copylev > 0 && !skipping)
516 			*bp++ = c;
517 
518 		/* check for backslash escapes */
519 		if (c == '\\')
520 		{
521 			/* arrange to quote the address */
522 			if (cmtlev <= 0 && !qmode)
523 				quoteit = TRUE;
524 
525 			if ((c = *p++) == '\0')
526 			{
527 				/* too far */
528 				p--;
529 				goto putg;
530 			}
531 			if (copylev > 0 && !skipping)
532 				*bp++ = c;
533 			goto putg;
534 		}
535 
536 		/* check for quoted strings */
537 		if (c == '"')
538 		{
539 			qmode = !qmode;
540 			if (copylev > 0 && !skipping)
541 				realqmode = !realqmode;
542 			continue;
543 		}
544 		if (qmode)
545 			goto putg;
546 
547 		/* check for comments */
548 		if (c == '(')
549 		{
550 			cmtlev++;
551 
552 			/* allow space for closing paren */
553 			if (!skipping)
554 			{
555 				buflim--;
556 				realcmtlev++;
557 				if (copylev++ <= 0)
558 				{
559 					*bp++ = ' ';
560 					*bp++ = c;
561 				}
562 			}
563 		}
564 		if (cmtlev > 0)
565 		{
566 			if (c == ')')
567 			{
568 				cmtlev--;
569 				copylev--;
570 				if (!skipping)
571 				{
572 					realcmtlev--;
573 					buflim++;
574 				}
575 			}
576 			continue;
577 		}
578 		else if (c == ')')
579 		{
580 			/* syntax error: unmatched ) */
581 			if (!skipping)
582 				bp--;
583 		}
584 
585 
586 		/* check for characters that may have to be quoted */
587 		if (strchr(".'@,;:\\()", c) != NULL)
588 		{
589 			/*
590 			**  If these occur as the phrase part of a <>
591 			**  construct, but are not inside of () or already
592 			**  quoted, they will have to be quoted.  Note that
593 			**  now (but don't actually do the quoting).
594 			*/
595 
596 			if (cmtlev <= 0 && !qmode)
597 				quoteit = TRUE;
598 		}
599 
600 		/* check for angle brackets */
601 		if (c == '<')
602 		{
603 			register char *q;
604 
605 			/* oops -- have to change our mind */
606 			anglelev++;
607 			if (!skipping)
608 				realanglelev++;
609 
610 			bp = buf;
611 			if (quoteit)
612 			{
613 				*bp++ = '"';
614 
615 				/* back up over the '<' and any spaces */
616 				--p;
617 				while (isascii(*--p) && isspace(*p))
618 					continue;
619 				p++;
620 			}
621 			for (q = addr; q < p; )
622 			{
623 				c = *q++;
624 				if (bp < buflim)
625 				{
626 					if (quoteit && c == '"')
627 						*bp++ = '\\';
628 					*bp++ = c;
629 				}
630 			}
631 			if (quoteit)
632 			{
633 				*bp++ = '"';
634 				while ((c = *p++) != '<')
635 				{
636 					if (bp < buflim)
637 						*bp++ = c;
638 				}
639 				*bp++ = c;
640 			}
641 			copylev = 0;
642 			putgmac = quoteit = FALSE;
643 			continue;
644 		}
645 
646 		if (c == '>')
647 		{
648 			if (anglelev > 0)
649 			{
650 				anglelev--;
651 				if (!skipping)
652 				{
653 					realanglelev--;
654 					buflim++;
655 				}
656 			}
657 			else if (!skipping)
658 			{
659 				/* syntax error: unmatched > */
660 				if (copylev > 0)
661 					bp--;
662 				continue;
663 			}
664 			if (copylev++ <= 0)
665 				*bp++ = c;
666 			continue;
667 		}
668 
669 		/* must be a real address character */
670 	putg:
671 		if (copylev <= 0 && !putgmac)
672 		{
673 			*bp++ = MACROEXPAND;
674 			*bp++ = 'g';
675 			putgmac = TRUE;
676 		}
677 	}
678 
679 	/* repair any syntactic damage */
680 	if (realqmode)
681 		*bp++ = '"';
682 	while (realcmtlev-- > 0)
683 		*bp++ = ')';
684 	while (realanglelev-- > 0)
685 		*bp++ = '>';
686 	*bp++ = '\0';
687 
688 	if (tTd(33, 1))
689 		printf("crackaddr=>`%s'\n", buf);
690 
691 	return (buf);
692 }
693 /*
694 **  PUTHEADER -- put the header part of a message from the in-core copy
695 **
696 **	Parameters:
697 **		fp -- file to put it on.
698 **		m -- mailer to use.
699 **		e -- envelope to use.
700 **
701 **	Returns:
702 **		none.
703 **
704 **	Side Effects:
705 **		none.
706 */
707 
708 /*
709  * Macro for fast max (not available in e.g. DG/UX, 386/ix).
710  */
711 #ifndef MAX
712 # define MAX(a,b) (((a)>(b))?(a):(b))
713 #endif
714 
715 putheader(fp, m, e)
716 	register FILE *fp;
717 	register MAILER *m;
718 	register ENVELOPE *e;
719 {
720 	char buf[MAX(MAXLINE,BUFSIZ)];
721 	register HDR *h;
722 	char obuf[MAXLINE];
723 
724 	for (h = e->e_header; h != NULL; h = h->h_link)
725 	{
726 		register char *p;
727 		extern bool bitintersect();
728 
729 		if (bitset(H_CHECK|H_ACHECK, h->h_flags) &&
730 		    !bitintersect(h->h_mflags, m->m_flags))
731 			continue;
732 
733 		/* handle Resent-... headers specially */
734 		if (bitset(H_RESENT, h->h_flags) && !bitset(EF_RESENT, e->e_flags))
735 			continue;
736 
737 		p = h->h_value;
738 		if (bitset(H_DEFAULT, h->h_flags))
739 		{
740 			/* macro expand value if generated internally */
741 			expand(p, buf, &buf[sizeof buf], e);
742 			p = buf;
743 			if (p == NULL || *p == '\0')
744 				continue;
745 		}
746 
747 		if (bitset(H_FROM|H_RCPT, h->h_flags))
748 		{
749 			/* address field */
750 			bool oldstyle = bitset(EF_OLDSTYLE, e->e_flags);
751 
752 			if (bitset(H_FROM, h->h_flags))
753 				oldstyle = FALSE;
754 			commaize(h, p, fp, oldstyle, m, e);
755 		}
756 		else
757 		{
758 			/* vanilla header line */
759 			register char *nlp;
760 			extern char *capitalize();
761 
762 			(void) sprintf(obuf, "%s: ", capitalize(h->h_field));
763 			while ((nlp = strchr(p, '\n')) != NULL)
764 			{
765 				*nlp = '\0';
766 				(void) strcat(obuf, p);
767 				*nlp = '\n';
768 				putline(obuf, fp, m);
769 				p = ++nlp;
770 				obuf[0] = '\0';
771 			}
772 			(void) strcat(obuf, p);
773 			putline(obuf, fp, m);
774 		}
775 	}
776 }
777 /*
778 **  COMMAIZE -- output a header field, making a comma-translated list.
779 **
780 **	Parameters:
781 **		h -- the header field to output.
782 **		p -- the value to put in it.
783 **		fp -- file to put it to.
784 **		oldstyle -- TRUE if this is an old style header.
785 **		m -- a pointer to the mailer descriptor.  If NULL,
786 **			don't transform the name at all.
787 **		e -- the envelope containing the message.
788 **
789 **	Returns:
790 **		none.
791 **
792 **	Side Effects:
793 **		outputs "p" to file "fp".
794 */
795 
796 commaize(h, p, fp, oldstyle, m, e)
797 	register HDR *h;
798 	register char *p;
799 	FILE *fp;
800 	bool oldstyle;
801 	register MAILER *m;
802 	register ENVELOPE *e;
803 {
804 	register char *obp;
805 	int opos;
806 	bool firstone = TRUE;
807 	char obuf[MAXLINE + 3];
808 	extern char *capitalize();
809 
810 	/*
811 	**  Output the address list translated by the
812 	**  mailer and with commas.
813 	*/
814 
815 	if (tTd(14, 2))
816 		printf("commaize(%s: %s)\n", h->h_field, p);
817 
818 	obp = obuf;
819 	(void) sprintf(obp, "%s: ", capitalize(h->h_field));
820 	opos = strlen(h->h_field) + 2;
821 	obp += opos;
822 
823 	/*
824 	**  Run through the list of values.
825 	*/
826 
827 	while (*p != '\0')
828 	{
829 		register char *name;
830 		register int c;
831 		char savechar;
832 		extern char *remotename();
833 
834 		/*
835 		**  Find the end of the name.  New style names
836 		**  end with a comma, old style names end with
837 		**  a space character.  However, spaces do not
838 		**  necessarily delimit an old-style name -- at
839 		**  signs mean keep going.
840 		*/
841 
842 		/* find end of name */
843 		while ((isascii(*p) && isspace(*p)) || *p == ',')
844 			p++;
845 		name = p;
846 		for (;;)
847 		{
848 			auto char *oldp;
849 			char pvpbuf[PSBUFSIZE];
850 			extern char **prescan();
851 
852 			(void) prescan(p, oldstyle ? ' ' : ',', pvpbuf, &oldp);
853 			p = oldp;
854 
855 			/* look to see if we have an at sign */
856 			while (*p != '\0' && isascii(*p) && isspace(*p))
857 				p++;
858 
859 			if (*p != '@')
860 			{
861 				p = oldp;
862 				break;
863 			}
864 			p += *p == '@' ? 1 : 2;
865 			while (*p != '\0' && isascii(*p) && isspace(*p))
866 				p++;
867 		}
868 		/* at the end of one complete name */
869 
870 		/* strip off trailing white space */
871 		while (p >= name &&
872 		       ((isascii(*p) && isspace(*p)) || *p == ',' || *p == '\0'))
873 			p--;
874 		if (++p == name)
875 			continue;
876 		savechar = *p;
877 		*p = '\0';
878 
879 		/* translate the name to be relative */
880 		name = remotename(name, m, bitset(H_FROM, h->h_flags),
881 				  TRUE, FALSE, TRUE, e);
882 		if (*name == '\0')
883 		{
884 			*p = savechar;
885 			continue;
886 		}
887 
888 		/* output the name with nice formatting */
889 		opos += strlen(name);
890 		if (!firstone)
891 			opos += 2;
892 		if (opos > 78 && !firstone)
893 		{
894 			(void) strcpy(obp, ",\n");
895 			putline(obuf, fp, m);
896 			obp = obuf;
897 			(void) sprintf(obp, "        ");
898 			opos = strlen(obp);
899 			obp += opos;
900 			opos += strlen(name);
901 		}
902 		else if (!firstone)
903 		{
904 			(void) sprintf(obp, ", ");
905 			obp += 2;
906 		}
907 
908 		/* strip off quote bits as we output */
909 		while ((c = *name++) != '\0' && obp < &obuf[MAXLINE])
910 		{
911 			if (bitnset(M_7BITS, m->m_flags))
912 				c &= 0177;
913 			*obp++ = c;
914 		}
915 		firstone = FALSE;
916 		*p = savechar;
917 	}
918 	(void) strcpy(obp, "\n");
919 	putline(obuf, fp, m);
920 }
921 /*
922 **  COPYHEADER -- copy header list
923 **
924 **	This routine is the equivalent of newstr for header lists
925 **
926 **	Parameters:
927 **		header -- list of header structures to copy.
928 **
929 **	Returns:
930 **		a copy of 'header'.
931 **
932 **	Side Effects:
933 **		none.
934 */
935 
936 HDR *
937 copyheader(header)
938 	register HDR *header;
939 {
940 	register HDR *newhdr;
941 	HDR *ret;
942 	register HDR **tail = &ret;
943 
944 	while (header != NULL)
945 	{
946 		newhdr = (HDR *) xalloc(sizeof(HDR));
947 		STRUCTCOPY(*header, *newhdr);
948 		*tail = newhdr;
949 		tail = &newhdr->h_link;
950 		header = header->h_link;
951 	}
952 	*tail = NULL;
953 
954 	return ret;
955 }
956