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.53 (Berkeley) 04/02/95";
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 	char buf[MAXNAME + 1];
48 
49 	if (tTd(31, 6))
50 		printf("chompheader: %s\n", line);
51 
52 	/* strip off options */
53 	clrbitmap(mopts);
54 	p = line;
55 	if (*p == '?')
56 	{
57 		/* have some */
58 		register char *q = strchr(p + 1, *p);
59 
60 		if (q != NULL)
61 		{
62 			*q++ = '\0';
63 			while (*++p != '\0')
64 				setbitn(*p, mopts);
65 			p = q;
66 		}
67 		else
68 			syserr("553 header syntax error, line \"%s\"", line);
69 		cond = TRUE;
70 	}
71 
72 	/* find canonical name */
73 	fname = p;
74 	while (isascii(*p) && isgraph(*p) && *p != ':')
75 		p++;
76 	fvalue = p;
77 	while (isascii(*p) && isspace(*p))
78 		p++;
79 	if (*p++ != ':' || fname == fvalue)
80 	{
81 		syserr("553 header syntax error, line \"%s\"", line);
82 		return (0);
83 	}
84 	*fvalue = '\0';
85 	fvalue = p;
86 
87 	/* strip field value on front */
88 	if (*fvalue == ' ')
89 		fvalue++;
90 
91 	/* see if it is a known type */
92 	for (hi = HdrInfo; hi->hi_field != NULL; hi++)
93 	{
94 		if (strcasecmp(hi->hi_field, fname) == 0)
95 			break;
96 	}
97 
98 	if (tTd(31, 9))
99 	{
100 		if (hi->hi_field == NULL)
101 			printf("no header match\n");
102 		else
103 			printf("header match, hi_flags=%x\n", hi->hi_flags);
104 	}
105 
106 	/* see if this is a resent message */
107 	if (!def && bitset(H_RESENT, hi->hi_flags))
108 		e->e_flags |= EF_RESENT;
109 
110 	/* if this is an Errors-To: header keep track of it now */
111 	if (UseErrorsTo && !def && bitset(H_ERRORSTO, hi->hi_flags))
112 		(void) sendtolist(fvalue, NULLADDR, &e->e_errorqueue, 0, e);
113 
114 	/* if this means "end of header" quit now */
115 	if (bitset(H_EOH, hi->hi_flags))
116 		return (hi->hi_flags);
117 
118 	/*
119 	**  Drop explicit From: if same as what we would generate.
120 	**  This is to make MH (which doesn't always give a full name)
121 	**  insert the full name information in all circumstances.
122 	*/
123 
124 	p = "resent-from";
125 	if (!bitset(EF_RESENT, e->e_flags))
126 		p += 7;
127 	if (!def && !bitset(EF_QUEUERUN, e->e_flags) && strcasecmp(fname, p) == 0)
128 	{
129 		if (tTd(31, 2))
130 		{
131 			printf("comparing header from (%s) against default (%s or %s)\n",
132 				fvalue, e->e_from.q_paddr, e->e_from.q_user);
133 		}
134 		if (e->e_from.q_paddr != NULL &&
135 		    (strcmp(fvalue, e->e_from.q_paddr) == 0 ||
136 		     strcmp(fvalue, e->e_from.q_user) == 0))
137 			return (hi->hi_flags);
138 #ifdef MAYBENEXTRELEASE		/* XXX UNTESTED XXX UNTESTED XXX UNTESTED XXX */
139 #ifdef USERDB
140 		else
141 		{
142 			auto ADDRESS a;
143 			char *fancy;
144 			bool oldSuprErrs = SuprErrs;
145 			extern char *crackaddr();
146 			extern char *udbsender();
147 
148 			/*
149 			**  Try doing USERDB rewriting even on fully commented
150 			**  names; this saves the "comment" information (such
151 			**  as full name) and rewrites the electronic part.
152 			**
153 			** XXX	This code doesn't belong here -- parsing should
154 			** XXX	not be done during collect() phase because
155 			** XXX	error messages can confuse the SMTP phase.
156 			** XXX	Setting SuprErrs is a crude hack around this
157 			** XXX	problem.
158 			*/
159 
160 			if (OpMode == MD_SMTP || OpMode == MD_ARPAFTP)
161 				SuprErrs = TRUE;
162 			fancy = crackaddr(fvalue);
163 			if (parseaddr(fvalue, &a, RF_COPYNONE, '\0', NULL, e) != NULL &&
164 			    bitnset(M_CHECKUDB, a.q_mailer->m_flags) &&
165 			    (p = udbsender(a.q_user)) != NULL)
166 			{
167 				char *oldg = macvalue('g', e);
168 
169 				define('g', p, e);
170 				expand(fancy, buf, sizeof buf, e);
171 				define('g', oldg, e);
172 				fvalue = buf;
173 			}
174 			SuprErrs = oldSuprErrs;
175 		}
176 #endif
177 #endif
178 	}
179 
180 	/* delete default value for this header */
181 	for (hp = &e->e_header; (h = *hp) != NULL; hp = &h->h_link)
182 	{
183 		if (strcasecmp(fname, h->h_field) == 0 &&
184 		    bitset(H_DEFAULT, h->h_flags) &&
185 		    !bitset(H_FORCE, h->h_flags))
186 			h->h_value = NULL;
187 	}
188 
189 	/* create a new node */
190 	h = (HDR *) xalloc(sizeof *h);
191 	h->h_field = newstr(fname);
192 	h->h_value = newstr(fvalue);
193 	h->h_link = NULL;
194 	bcopy((char *) mopts, (char *) h->h_mflags, sizeof mopts);
195 	*hp = h;
196 	h->h_flags = hi->hi_flags;
197 	if (def)
198 		h->h_flags |= H_DEFAULT;
199 	if (cond)
200 		h->h_flags |= H_CHECK;
201 
202 	/* hack to see if this is a new format message */
203 	if (!def && bitset(H_RCPT|H_FROM, h->h_flags) &&
204 	    (strchr(fvalue, ',') != NULL || strchr(fvalue, '(') != NULL ||
205 	     strchr(fvalue, '<') != NULL || strchr(fvalue, ';') != NULL))
206 	{
207 		e->e_flags &= ~EF_OLDSTYLE;
208 	}
209 
210 	return (h->h_flags);
211 }
212 /*
213 **  ADDHEADER -- add a header entry to the end of the queue.
214 **
215 **	This bypasses the special checking of chompheader.
216 **
217 **	Parameters:
218 **		field -- the name of the header field.
219 **		value -- the value of the field.
220 **		hp -- an indirect pointer to the header structure list.
221 **
222 **	Returns:
223 **		none.
224 **
225 **	Side Effects:
226 **		adds the field on the list of headers for this envelope.
227 */
228 
229 addheader(field, value, hdrlist)
230 	char *field;
231 	char *value;
232 	HDR **hdrlist;
233 {
234 	register HDR *h;
235 	register struct hdrinfo *hi;
236 	HDR **hp;
237 
238 	/* find info struct */
239 	for (hi = HdrInfo; hi->hi_field != NULL; hi++)
240 	{
241 		if (strcasecmp(field, hi->hi_field) == 0)
242 			break;
243 	}
244 
245 	/* find current place in list -- keep back pointer? */
246 	for (hp = hdrlist; (h = *hp) != NULL; hp = &h->h_link)
247 	{
248 		if (strcasecmp(field, h->h_field) == 0)
249 			break;
250 	}
251 
252 	/* allocate space for new header */
253 	h = (HDR *) xalloc(sizeof *h);
254 	h->h_field = field;
255 	h->h_value = newstr(value);
256 	h->h_link = *hp;
257 	h->h_flags = hi->hi_flags | H_DEFAULT;
258 	clrbitmap(h->h_mflags);
259 	*hp = h;
260 }
261 /*
262 **  HVALUE -- return value of a header.
263 **
264 **	Only "real" fields (i.e., ones that have not been supplied
265 **	as a default) are used.
266 **
267 **	Parameters:
268 **		field -- the field name.
269 **		header -- the header list.
270 **
271 **	Returns:
272 **		pointer to the value part.
273 **		NULL if not found.
274 **
275 **	Side Effects:
276 **		none.
277 */
278 
279 char *
280 hvalue(field, header)
281 	char *field;
282 	HDR *header;
283 {
284 	register HDR *h;
285 
286 	for (h = header; h != NULL; h = h->h_link)
287 	{
288 		if (!bitset(H_DEFAULT, h->h_flags) &&
289 		    strcasecmp(h->h_field, field) == 0)
290 			return (h->h_value);
291 	}
292 	return (NULL);
293 }
294 /*
295 **  ISHEADER -- predicate telling if argument is a header.
296 **
297 **	A line is a header if it has a single word followed by
298 **	optional white space followed by a colon.
299 **
300 **	Parameters:
301 **		h -- string to check for possible headerness.
302 **
303 **	Returns:
304 **		TRUE if h is a header.
305 **		FALSE otherwise.
306 **
307 **	Side Effects:
308 **		none.
309 */
310 
311 bool
312 isheader(h)
313 	char *h;
314 {
315 	register char *s = h;
316 
317 	while (*s > ' ' && *s != ':' && *s != '\0')
318 		s++;
319 
320 	if (h == s)
321 		return FALSE;
322 
323 	/* following technically violates RFC822 */
324 	while (isascii(*s) && isspace(*s))
325 		s++;
326 
327 	return (*s == ':');
328 }
329 /*
330 **  EATHEADER -- run through the stored header and extract info.
331 **
332 **	Parameters:
333 **		e -- the envelope to process.
334 **		full -- if set, do full processing (e.g., compute
335 **			message priority).
336 **
337 **	Returns:
338 **		none.
339 **
340 **	Side Effects:
341 **		Sets a bunch of global variables from information
342 **			in the collected header.
343 **		Aborts the message if the hop count is exceeded.
344 */
345 
346 eatheader(e, full)
347 	register ENVELOPE *e;
348 	bool full;
349 {
350 	register HDR *h;
351 	register char *p;
352 	int hopcnt = 0;
353 	char *msgid;
354 	char buf[MAXLINE];
355 
356 	/*
357 	**  Set up macros for possible expansion in headers.
358 	*/
359 
360 	define('f', e->e_sender, e);
361 	define('g', e->e_sender, e);
362 	if (e->e_origrcpt != NULL && *e->e_origrcpt != '\0')
363 		define('u', e->e_origrcpt, e);
364 	else
365 		define('u', NULL, e);
366 
367 	/* full name of from person */
368 	p = hvalue("full-name", e->e_header);
369 	if (p != NULL)
370 		define('x', p, e);
371 
372 	if (tTd(32, 1))
373 		printf("----- collected header -----\n");
374 	msgid = "<none>";
375 	for (h = e->e_header; h != NULL; h = h->h_link)
376 	{
377 		if (h->h_value == NULL)
378 		{
379 			if (tTd(32, 1))
380 				printf("%s: <NULL>\n", h->h_field);
381 			continue;
382 		}
383 
384 		/* do early binding */
385 		if (bitset(H_DEFAULT, h->h_flags))
386 		{
387 			expand(h->h_value, buf, sizeof buf, e);
388 			if (buf[0] != '\0')
389 			{
390 				h->h_value = newstr(buf);
391 				h->h_flags &= ~H_DEFAULT;
392 			}
393 		}
394 
395 		if (tTd(32, 1))
396 		{
397 			printf("%s: ", h->h_field);
398 			xputs(h->h_value);
399 			printf("\n");
400 		}
401 
402 		/* count the number of times it has been processed */
403 		if (bitset(H_TRACE, h->h_flags))
404 			hopcnt++;
405 
406 		/* send to this person if we so desire */
407 		if (GrabTo && bitset(H_RCPT, h->h_flags) &&
408 		    !bitset(H_DEFAULT, h->h_flags) &&
409 		    (!bitset(EF_RESENT, e->e_flags) || bitset(H_RESENT, h->h_flags)))
410 		{
411 			int saveflags = e->e_flags;
412 
413 			(void) sendtolist(h->h_value, NULLADDR,
414 					  &e->e_sendqueue, 0, e);
415 
416 			/* delete fatal errors generated by this address */
417 			if (!GrabTo && !bitset(EF_FATALERRS, saveflags))
418 				e->e_flags &= ~EF_FATALERRS;
419 		}
420 
421 		/* save the message-id for logging */
422 		if (full && strcasecmp(h->h_field, "message-id") == 0)
423 		{
424 			msgid = h->h_value;
425 			while (isascii(*msgid) && isspace(*msgid))
426 				msgid++;
427 		}
428 
429 		/* see if this is a return-receipt header */
430 		if (bitset(H_RECEIPTTO, h->h_flags))
431 			e->e_receiptto = h->h_value;
432 	}
433 	if (tTd(32, 1))
434 		printf("----------------------------\n");
435 
436 	/* if we are just verifying (that is, sendmail -t -bv), drop out now */
437 	if (OpMode == MD_VERIFY)
438 		return;
439 
440 	/* store hop count */
441 	if (hopcnt > e->e_hopcount)
442 		e->e_hopcount = hopcnt;
443 
444 	/* message priority */
445 	p = hvalue("precedence", e->e_header);
446 	if (p != NULL)
447 		e->e_class = priencode(p);
448 	if (full)
449 	{
450 		e->e_msgpriority = e->e_msgsize
451 				 - e->e_class * WkClassFact
452 				 + e->e_nrcpts * WkRecipFact;
453 		if (e->e_class < 0)
454 			e->e_timeoutclass = TOC_NONURGENT;
455 		else if (e->e_class > 0)
456 			e->e_timeoutclass = TOC_URGENT;
457 	}
458 
459 	/* message timeout priority */
460 	p = hvalue("priority", e->e_header);
461 	if (full && p != NULL)
462 	{
463 		/* (this should be in the configuration file) */
464 		if (strcasecmp(p, "urgent"))
465 			e->e_timeoutclass = TOC_URGENT;
466 		else if (strcasecmp(p, "normal"))
467 			e->e_timeoutclass = TOC_NORMAL;
468 		else if (strcasecmp(p, "non-urgent"))
469 			e->e_timeoutclass = TOC_NONURGENT;
470 	}
471 
472 	/* date message originated */
473 	p = hvalue("posted-date", e->e_header);
474 	if (p == NULL)
475 		p = hvalue("date", e->e_header);
476 	if (p != NULL)
477 		define('a', p, e);
478 
479 	/*
480 	**  From person in antiquated ARPANET mode
481 	**	required by UK Grey Book e-mail gateways (sigh)
482 	*/
483 
484 	if (OpMode == MD_ARPAFTP)
485 	{
486 		register struct hdrinfo *hi;
487 
488 		for (hi = HdrInfo; hi->hi_field != NULL; hi++)
489 		{
490 			if (bitset(H_FROM, hi->hi_flags) &&
491 			    (!bitset(H_RESENT, hi->hi_flags) ||
492 			     bitset(EF_RESENT, e->e_flags)) &&
493 			    (p = hvalue(hi->hi_field, e->e_header)) != NULL)
494 				break;
495 		}
496 		if (hi->hi_field != NULL)
497 		{
498 			if (tTd(32, 2))
499 				printf("eatheader: setsender(*%s == %s)\n",
500 					hi->hi_field, p);
501 			setsender(p, e, NULL, TRUE);
502 		}
503 	}
504 
505 	/*
506 	**  Log collection information.
507 	*/
508 
509 # ifdef LOG
510 	if (bitset(EF_LOGSENDER, e->e_flags) && LogLevel > 4)
511 		logsender(e, msgid);
512 # endif /* LOG */
513 	e->e_flags &= ~EF_LOGSENDER;
514 }
515 /*
516 **  LOGSENDER -- log sender information
517 **
518 **	Parameters:
519 **		e -- the envelope to log
520 **		msgid -- the message id
521 **
522 **	Returns:
523 **		none
524 */
525 
526 logsender(e, msgid)
527 	register ENVELOPE *e;
528 	char *msgid;
529 {
530 # ifdef LOG
531 	char *name;
532 	register char *sbp;
533 	register char *p;
534 	int l;
535 	char hbuf[MAXNAME + 1];
536 	char sbuf[MAXLINE + 1];
537 	char mbuf[MAXNAME + 1];
538 
539 	/* don't allow newlines in the message-id */
540 	if (msgid != NULL)
541 	{
542 		l = strlen(msgid);
543 		if (l > sizeof mbuf - 1)
544 			l = sizeof mbuf - 1;
545 		bcopy(msgid, mbuf, l);
546 		mbuf[l] = '\0';
547 		p = mbuf;
548 		while ((p = strchr(p, '\n')) != NULL)
549 			*p++ = ' ';
550 	}
551 
552 	if (bitset(EF_RESPONSE, e->e_flags))
553 		name = "[RESPONSE]";
554 	else if ((name = macvalue('_', e)) != NULL)
555 		;
556 	else if (RealHostName == NULL)
557 		name = "localhost";
558 	else if (RealHostName[0] == '[')
559 		name = RealHostName;
560 	else
561 	{
562 		name = hbuf;
563 		(void) sprintf(hbuf, "%.80s", RealHostName);
564 		if (RealHostAddr.sa.sa_family != 0)
565 		{
566 			p = &hbuf[strlen(hbuf)];
567 			(void) sprintf(p, " (%s)",
568 				anynet_ntoa(&RealHostAddr));
569 		}
570 	}
571 
572 	/* some versions of syslog only take 5 printf args */
573 #  if (SYSLOG_BUFSIZE) >= 256
574 	sbp = sbuf;
575 	sprintf(sbp, "from=%.200s, size=%ld, class=%d, pri=%ld, nrcpts=%d",
576 	    e->e_from.q_paddr == NULL ? "<NONE>" : e->e_from.q_paddr,
577 	    e->e_msgsize, e->e_class, e->e_msgpriority, e->e_nrcpts);
578 	sbp += strlen(sbp);
579 	if (msgid != NULL)
580 	{
581 		sprintf(sbp, ", msgid=%.100s", mbuf);
582 		sbp += strlen(sbp);
583 	}
584 	if (e->e_bodytype != NULL)
585 	{
586 		(void) sprintf(sbp, ", bodytype=%.20s", e->e_bodytype);
587 		sbp += strlen(sbp);
588 	}
589 	p = macvalue('r', e);
590 	if (p != NULL)
591 		(void) sprintf(sbp, ", proto=%.20s", p);
592 	syslog(LOG_INFO, "%s: %s, relay=%s",
593 	    e->e_id, sbuf, name);
594 
595 #  else			/* short syslog buffer */
596 
597 	syslog(LOG_INFO, "%s: from=%s",
598 		e->e_id, e->e_from.q_paddr == NULL ? "<NONE>" :
599 				shortenstring(e->e_from.q_paddr, 83));
600 	syslog(LOG_INFO, "%s: size=%ld, class=%ld, pri=%ld, nrcpts=%d",
601 		e->e_id, e->e_msgsize, e->e_class,
602 		e->e_msgpriority, e->e_nrcpts);
603 	if (msgid != NULL)
604 		syslog(LOG_INFO, "%s: msgid=%s", e->e_id, mbuf);
605 	sbp = sbuf;
606 	sprintf(sbp, "%s:", e->e_id);
607 	sbp += strlen(sbp);
608 	if (e->e_bodytype != NULL)
609 	{
610 		sprintf(sbp, " bodytype=%s,", e->e_bodytype);
611 		sbp += strlen(sbp);
612 	}
613 	p = macvalue('r', e);
614 	if (p != NULL)
615 	{
616 		sprintf(sbp, " proto=%s,", p);
617 		sbp += strlen(sbp);
618 	}
619 	syslog(LOG_INFO, "%s relay=%s", sbuf, name);
620 #  endif
621 # endif
622 }
623 /*
624 **  PRIENCODE -- encode external priority names into internal values.
625 **
626 **	Parameters:
627 **		p -- priority in ascii.
628 **
629 **	Returns:
630 **		priority as a numeric level.
631 **
632 **	Side Effects:
633 **		none.
634 */
635 
636 priencode(p)
637 	char *p;
638 {
639 	register int i;
640 
641 	for (i = 0; i < NumPriorities; i++)
642 	{
643 		if (!strcasecmp(p, Priorities[i].pri_name))
644 			return (Priorities[i].pri_val);
645 	}
646 
647 	/* unknown priority */
648 	return (0);
649 }
650 /*
651 **  CRACKADDR -- parse an address and turn it into a macro
652 **
653 **	This doesn't actually parse the address -- it just extracts
654 **	it and replaces it with "$g".  The parse is totally ad hoc
655 **	and isn't even guaranteed to leave something syntactically
656 **	identical to what it started with.  However, it does leave
657 **	something semantically identical.
658 **
659 **	This algorithm has been cleaned up to handle a wider range
660 **	of cases -- notably quoted and backslash escaped strings.
661 **	This modification makes it substantially better at preserving
662 **	the original syntax.
663 **
664 **	Parameters:
665 **		addr -- the address to be cracked.
666 **
667 **	Returns:
668 **		a pointer to the new version.
669 **
670 **	Side Effects:
671 **		none.
672 **
673 **	Warning:
674 **		The return value is saved in local storage and should
675 **		be copied if it is to be reused.
676 */
677 
678 char *
679 crackaddr(addr)
680 	register char *addr;
681 {
682 	register char *p;
683 	register char c;
684 	int cmtlev;
685 	int realcmtlev;
686 	int anglelev, realanglelev;
687 	int copylev;
688 	bool qmode;
689 	bool realqmode;
690 	bool skipping;
691 	bool putgmac = FALSE;
692 	bool quoteit = FALSE;
693 	bool gotangle = FALSE;
694 	register char *bp;
695 	char *buflim;
696 	static char buf[MAXNAME + 1];
697 
698 	if (tTd(33, 1))
699 		printf("crackaddr(%s)\n", addr);
700 
701 	/* strip leading spaces */
702 	while (*addr != '\0' && isascii(*addr) && isspace(*addr))
703 		addr++;
704 
705 	/*
706 	**  Start by assuming we have no angle brackets.  This will be
707 	**  adjusted later if we find them.
708 	*/
709 
710 	bp = buf;
711 	buflim = &buf[sizeof buf - 5];
712 	p = addr;
713 	copylev = anglelev = realanglelev = cmtlev = realcmtlev = 0;
714 	qmode = realqmode = FALSE;
715 
716 	while ((c = *p++) != '\0')
717 	{
718 		/*
719 		**  If the buffer is overful, go into a special "skipping"
720 		**  mode that tries to keep legal syntax but doesn't actually
721 		**  output things.
722 		*/
723 
724 		skipping = bp >= buflim;
725 
726 		if (copylev > 0 && !skipping)
727 			*bp++ = c;
728 
729 		/* check for backslash escapes */
730 		if (c == '\\')
731 		{
732 			/* arrange to quote the address */
733 			if (cmtlev <= 0 && !qmode)
734 				quoteit = TRUE;
735 
736 			if ((c = *p++) == '\0')
737 			{
738 				/* too far */
739 				p--;
740 				goto putg;
741 			}
742 			if (copylev > 0 && !skipping)
743 				*bp++ = c;
744 			goto putg;
745 		}
746 
747 		/* check for quoted strings */
748 		if (c == '"' && cmtlev <= 0)
749 		{
750 			qmode = !qmode;
751 			if (copylev > 0 && !skipping)
752 				realqmode = !realqmode;
753 			continue;
754 		}
755 		if (qmode)
756 			goto putg;
757 
758 		/* check for comments */
759 		if (c == '(')
760 		{
761 			cmtlev++;
762 
763 			/* allow space for closing paren */
764 			if (!skipping)
765 			{
766 				buflim--;
767 				realcmtlev++;
768 				if (copylev++ <= 0)
769 				{
770 					*bp++ = ' ';
771 					*bp++ = c;
772 				}
773 			}
774 		}
775 		if (cmtlev > 0)
776 		{
777 			if (c == ')')
778 			{
779 				cmtlev--;
780 				copylev--;
781 				if (!skipping)
782 				{
783 					realcmtlev--;
784 					buflim++;
785 				}
786 			}
787 			continue;
788 		}
789 		else if (c == ')')
790 		{
791 			/* syntax error: unmatched ) */
792 			if (copylev > 0 && !skipping)
793 				bp--;
794 		}
795 
796 		/* check for characters that may have to be quoted */
797 		if (strchr(".'@,;:\\()[]", c) != NULL)
798 		{
799 			/*
800 			**  If these occur as the phrase part of a <>
801 			**  construct, but are not inside of () or already
802 			**  quoted, they will have to be quoted.  Note that
803 			**  now (but don't actually do the quoting).
804 			*/
805 
806 			if (cmtlev <= 0 && !qmode)
807 				quoteit = TRUE;
808 		}
809 
810 		/* check for angle brackets */
811 		if (c == '<')
812 		{
813 			register char *q;
814 
815 			/* assume first of two angles is bogus */
816 			if (gotangle)
817 				quoteit = TRUE;
818 			gotangle = TRUE;
819 
820 			/* oops -- have to change our mind */
821 			anglelev = 1;
822 			if (!skipping)
823 				realanglelev = 1;
824 
825 			bp = buf;
826 			if (quoteit)
827 			{
828 				*bp++ = '"';
829 
830 				/* back up over the '<' and any spaces */
831 				--p;
832 				while (isascii(*--p) && isspace(*p))
833 					continue;
834 				p++;
835 			}
836 			for (q = addr; q < p; )
837 			{
838 				c = *q++;
839 				if (bp < buflim)
840 				{
841 					if (quoteit && c == '"')
842 						*bp++ = '\\';
843 					*bp++ = c;
844 				}
845 			}
846 			if (quoteit)
847 			{
848 				if (bp == &buf[1])
849 					bp--;
850 				else
851 					*bp++ = '"';
852 				while ((c = *p++) != '<')
853 				{
854 					if (bp < buflim)
855 						*bp++ = c;
856 				}
857 				*bp++ = c;
858 			}
859 			copylev = 0;
860 			putgmac = quoteit = FALSE;
861 			continue;
862 		}
863 
864 		if (c == '>')
865 		{
866 			if (anglelev > 0)
867 			{
868 				anglelev--;
869 				if (!skipping)
870 				{
871 					realanglelev--;
872 					buflim++;
873 				}
874 			}
875 			else if (!skipping)
876 			{
877 				/* syntax error: unmatched > */
878 				if (copylev > 0)
879 					bp--;
880 				quoteit = TRUE;
881 				continue;
882 			}
883 			if (copylev++ <= 0)
884 				*bp++ = c;
885 			continue;
886 		}
887 
888 		/* must be a real address character */
889 	putg:
890 		if (copylev <= 0 && !putgmac)
891 		{
892 			*bp++ = MACROEXPAND;
893 			*bp++ = 'g';
894 			putgmac = TRUE;
895 		}
896 	}
897 
898 	/* repair any syntactic damage */
899 	if (realqmode)
900 		*bp++ = '"';
901 	while (realcmtlev-- > 0)
902 		*bp++ = ')';
903 	while (realanglelev-- > 0)
904 		*bp++ = '>';
905 	*bp++ = '\0';
906 
907 	if (tTd(33, 1))
908 		printf("crackaddr=>`%s'\n", buf);
909 
910 	return (buf);
911 }
912 /*
913 **  PUTHEADER -- put the header part of a message from the in-core copy
914 **
915 **	Parameters:
916 **		mci -- the connection information.
917 **		h -- the header to put.
918 **		e -- envelope to use.
919 **
920 **	Returns:
921 **		none.
922 **
923 **	Side Effects:
924 **		none.
925 */
926 
927 /*
928  * Macro for fast max (not available in e.g. DG/UX, 386/ix).
929  */
930 #ifndef MAX
931 # define MAX(a,b) (((a)>(b))?(a):(b))
932 #endif
933 
934 putheader(mci, h, e)
935 	register MCI *mci;
936 	register HDR *h;
937 	register ENVELOPE *e;
938 {
939 	char buf[MAX(MAXLINE,BUFSIZ)];
940 	char obuf[MAXLINE];
941 
942 	if (tTd(34, 1))
943 		printf("--- putheader, mailer = %s ---\n",
944 			mci->mci_mailer->m_name);
945 
946 	mci->mci_flags |= MCIF_INHEADER;
947 	for (; h != NULL; h = h->h_link)
948 	{
949 		register char *p;
950 		extern bool bitintersect();
951 
952 		if (tTd(34, 11))
953 		{
954 			printf("  %s: ", h->h_field);
955 			xputs(h->h_value);
956 		}
957 
958 		if (bitset(H_CHECK|H_ACHECK, h->h_flags) &&
959 		    !bitintersect(h->h_mflags, mci->mci_mailer->m_flags))
960 		{
961 			if (tTd(34, 11))
962 				printf(" (skipped)\n");
963 			continue;
964 		}
965 
966 		/* handle Resent-... headers specially */
967 		if (bitset(H_RESENT, h->h_flags) && !bitset(EF_RESENT, e->e_flags))
968 		{
969 			if (tTd(34, 11))
970 				printf(" (skipped (resent))\n");
971 			continue;
972 		}
973 
974 		/* suppress return receipts if requested */
975 		if (bitset(H_RECEIPTTO, h->h_flags) &&
976 		    bitset(EF_NORECEIPT, e->e_flags))
977 		{
978 			if (tTd(34, 11))
979 				printf(" (skipped (receipt))\n");
980 			continue;
981 		}
982 
983 		/* suppress Content-Transfer-Encoding: if we are MIMEing */
984 		if (bitset(H_CTE, h->h_flags) &&
985 		    bitset(MCIF_CVT8TO7, mci->mci_flags))
986 		{
987 			if (tTd(34, 11))
988 				printf(" (skipped (content-transfer-encoding))\n");
989 			continue;
990 		}
991 
992 		/* macro expand value if generated internally */
993 		p = h->h_value;
994 		if (bitset(H_DEFAULT, h->h_flags))
995 		{
996 			expand(p, buf, sizeof buf, e);
997 			p = buf;
998 			if (p == NULL || *p == '\0')
999 			{
1000 				if (tTd(34, 11))
1001 					printf(" (skipped -- null value)\n");
1002 				continue;
1003 			}
1004 		}
1005 
1006 		if (tTd(34, 11))
1007 			printf("\n");
1008 
1009 		if (bitset(H_STRIPVAL, h->h_flags))
1010 		{
1011 			/* empty field */
1012 			(void) sprintf(obuf, "%s:", h->h_field);
1013 			putline(obuf, mci);
1014 		}
1015 		else if (bitset(H_FROM|H_RCPT, h->h_flags))
1016 		{
1017 			/* address field */
1018 			bool oldstyle = bitset(EF_OLDSTYLE, e->e_flags);
1019 
1020 			if (bitset(H_FROM, h->h_flags))
1021 				oldstyle = FALSE;
1022 			commaize(h, p, oldstyle, mci, e);
1023 		}
1024 		else
1025 		{
1026 			/* vanilla header line */
1027 			register char *nlp;
1028 
1029 			(void) sprintf(obuf, "%s: ", h->h_field);
1030 			while ((nlp = strchr(p, '\n')) != NULL)
1031 			{
1032 				*nlp = '\0';
1033 				(void) strcat(obuf, p);
1034 				*nlp = '\n';
1035 				putline(obuf, mci);
1036 				p = ++nlp;
1037 				obuf[0] = '\0';
1038 			}
1039 			(void) strcat(obuf, p);
1040 			putline(obuf, mci);
1041 		}
1042 	}
1043 
1044 	/*
1045 	**  If we are converting this to a MIME message, add the
1046 	**  MIME headers.
1047 	*/
1048 
1049 	if (bitset(MM_MIME8BIT, MimeMode) &&
1050 	    bitset(EF_HAS8BIT, e->e_flags) &&
1051 	    !bitnset(M_8BITS, mci->mci_mailer->m_flags) &&
1052 	    !bitset(MCIF_CVT8TO7, mci->mci_flags))
1053 	{
1054 		if (hvalue("MIME-Version", e->e_header) == NULL)
1055 			putline("MIME-Version: 1.0", mci);
1056 		if (hvalue("Content-Type", e->e_header) == NULL)
1057 		{
1058 			sprintf(obuf, "Content-Type: text/plain; charset=%s",
1059 				defcharset(e));
1060 			putline(obuf, mci);
1061 		}
1062 		if (hvalue("Content-Transfer-Encoding", e->e_header) == NULL)
1063 			putline("Content-Transfer-Encoding: 8bit", mci);
1064 	}
1065 }
1066 /*
1067 **  COMMAIZE -- output a header field, making a comma-translated list.
1068 **
1069 **	Parameters:
1070 **		h -- the header field to output.
1071 **		p -- the value to put in it.
1072 **		oldstyle -- TRUE if this is an old style header.
1073 **		mci -- the connection information.
1074 **		e -- the envelope containing the message.
1075 **
1076 **	Returns:
1077 **		none.
1078 **
1079 **	Side Effects:
1080 **		outputs "p" to file "fp".
1081 */
1082 
1083 void
1084 commaize(h, p, oldstyle, mci, e)
1085 	register HDR *h;
1086 	register char *p;
1087 	bool oldstyle;
1088 	register MCI *mci;
1089 	register ENVELOPE *e;
1090 {
1091 	register char *obp;
1092 	int opos;
1093 	int omax;
1094 	bool firstone = TRUE;
1095 	char obuf[MAXLINE + 3];
1096 
1097 	/*
1098 	**  Output the address list translated by the
1099 	**  mailer and with commas.
1100 	*/
1101 
1102 	if (tTd(14, 2))
1103 		printf("commaize(%s: %s)\n", h->h_field, p);
1104 
1105 	obp = obuf;
1106 	(void) sprintf(obp, "%s: ", h->h_field);
1107 	opos = strlen(h->h_field) + 2;
1108 	obp += opos;
1109 	omax = mci->mci_mailer->m_linelimit - 2;
1110 	if (omax < 0 || omax > 78)
1111 		omax = 78;
1112 
1113 	/*
1114 	**  Run through the list of values.
1115 	*/
1116 
1117 	while (*p != '\0')
1118 	{
1119 		register char *name;
1120 		register int c;
1121 		char savechar;
1122 		int flags;
1123 		auto int stat;
1124 
1125 		/*
1126 		**  Find the end of the name.  New style names
1127 		**  end with a comma, old style names end with
1128 		**  a space character.  However, spaces do not
1129 		**  necessarily delimit an old-style name -- at
1130 		**  signs mean keep going.
1131 		*/
1132 
1133 		/* find end of name */
1134 		while ((isascii(*p) && isspace(*p)) || *p == ',')
1135 			p++;
1136 		name = p;
1137 		for (;;)
1138 		{
1139 			auto char *oldp;
1140 			char pvpbuf[PSBUFSIZE];
1141 
1142 			(void) prescan(p, oldstyle ? ' ' : ',', pvpbuf,
1143 				       sizeof pvpbuf, &oldp, NULL);
1144 			p = oldp;
1145 
1146 			/* look to see if we have an at sign */
1147 			while (*p != '\0' && isascii(*p) && isspace(*p))
1148 				p++;
1149 
1150 			if (*p != '@')
1151 			{
1152 				p = oldp;
1153 				break;
1154 			}
1155 			p += *p == '@' ? 1 : 2;
1156 			while (*p != '\0' && isascii(*p) && isspace(*p))
1157 				p++;
1158 		}
1159 		/* at the end of one complete name */
1160 
1161 		/* strip off trailing white space */
1162 		while (p >= name &&
1163 		       ((isascii(*p) && isspace(*p)) || *p == ',' || *p == '\0'))
1164 			p--;
1165 		if (++p == name)
1166 			continue;
1167 		savechar = *p;
1168 		*p = '\0';
1169 
1170 		/* translate the name to be relative */
1171 		flags = RF_HEADERADDR|RF_ADDDOMAIN;
1172 		if (bitset(H_FROM, h->h_flags))
1173 			flags |= RF_SENDERADDR;
1174 #ifdef USERDB
1175 		else if (e->e_from.q_mailer != NULL &&
1176 			 bitnset(M_UDBRECIPIENT, e->e_from.q_mailer->m_flags))
1177 		{
1178 			extern char *udbsender();
1179 
1180 			name = udbsender(name);
1181 		}
1182 #endif
1183 		stat = EX_OK;
1184 		name = remotename(name, mci->mci_mailer, flags, &stat, e);
1185 		if (*name == '\0')
1186 		{
1187 			*p = savechar;
1188 			continue;
1189 		}
1190 
1191 		/* output the name with nice formatting */
1192 		opos += strlen(name);
1193 		if (!firstone)
1194 			opos += 2;
1195 		if (opos > omax && !firstone)
1196 		{
1197 			(void) strcpy(obp, ",\n");
1198 			putline(obuf, mci);
1199 			obp = obuf;
1200 			(void) strcpy(obp, "        ");
1201 			opos = strlen(obp);
1202 			obp += opos;
1203 			opos += strlen(name);
1204 		}
1205 		else if (!firstone)
1206 		{
1207 			(void) strcpy(obp, ", ");
1208 			obp += 2;
1209 		}
1210 
1211 		while ((c = *name++) != '\0' && obp < &obuf[MAXLINE])
1212 			*obp++ = c;
1213 		firstone = FALSE;
1214 		*p = savechar;
1215 	}
1216 	(void) strcpy(obp, "\n");
1217 	putline(obuf, mci);
1218 }
1219 /*
1220 **  COPYHEADER -- copy header list
1221 **
1222 **	This routine is the equivalent of newstr for header lists
1223 **
1224 **	Parameters:
1225 **		header -- list of header structures to copy.
1226 **
1227 **	Returns:
1228 **		a copy of 'header'.
1229 **
1230 **	Side Effects:
1231 **		none.
1232 */
1233 
1234 HDR *
1235 copyheader(header)
1236 	register HDR *header;
1237 {
1238 	register HDR *newhdr;
1239 	HDR *ret;
1240 	register HDR **tail = &ret;
1241 
1242 	while (header != NULL)
1243 	{
1244 		newhdr = (HDR *) xalloc(sizeof(HDR));
1245 		STRUCTCOPY(*header, *newhdr);
1246 		*tail = newhdr;
1247 		tail = &newhdr->h_link;
1248 		header = header->h_link;
1249 	}
1250 	*tail = NULL;
1251 
1252 	return ret;
1253 }
1254