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