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