This commit was generated by cvs2svn to track changes on a CVS vendor
[unix-history] / usr.sbin / sendmail / src / headers.c
CommitLineData
15637ed4
RG
1/*
2 * Copyright (c) 1983 Eric P. Allman
6f14531a
RG
3 * Copyright (c) 1988, 1993
4 * The Regents of the University of California. All rights reserved.
15637ed4
RG
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. All advertising materials mentioning features or use of this software
15 * must display the following acknowledgement:
16 * This product includes software developed by the University of
17 * California, Berkeley and its contributors.
18 * 4. Neither the name of the University nor the names of its contributors
19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 */
34
35#ifndef lint
d747e748 36static char sccsid[] = "@(#)headers.c 8.13 (Berkeley) 10/24/93";
15637ed4
RG
37#endif /* not lint */
38
15637ed4
RG
39# include <errno.h>
40# include "sendmail.h"
41
42/*
43** CHOMPHEADER -- process and save a header line.
44**
45** Called by collect and by readcf to deal with header lines.
46**
47** Parameters:
48** line -- header as a text line.
49** def -- if set, this is a default value.
6f14531a 50** e -- the envelope including this header.
15637ed4
RG
51**
52** Returns:
53** flags for this header.
54**
55** Side Effects:
56** The header is saved on the header list.
57** Contents of 'line' are destroyed.
58*/
59
6f14531a 60chompheader(line, def, e)
15637ed4
RG
61 char *line;
62 bool def;
6f14531a 63 register ENVELOPE *e;
15637ed4
RG
64{
65 register char *p;
66 register HDR *h;
67 HDR **hp;
68 char *fname;
69 char *fvalue;
70 struct hdrinfo *hi;
71 bool cond = FALSE;
72 BITMAP mopts;
d747e748 73 char buf[MAXNAME];
15637ed4
RG
74
75 if (tTd(31, 6))
76 printf("chompheader: %s\n", line);
77
78 /* strip off options */
79 clrbitmap(mopts);
80 p = line;
81 if (*p == '?')
82 {
83 /* have some */
6f14531a 84 register char *q = strchr(p + 1, *p);
15637ed4
RG
85
86 if (q != NULL)
87 {
88 *q++ = '\0';
89 while (*++p != '\0')
90 setbitn(*p, mopts);
91 p = q;
92 }
93 else
6f14531a 94 usrerr("553 header syntax error, line \"%s\"", line);
15637ed4
RG
95 cond = TRUE;
96 }
97
98 /* find canonical name */
99 fname = p;
d747e748
JH
100 while (isascii(*p) && isgraph(*p) && *p != ':')
101 p++;
102 fvalue = p;
103 while (isascii(*p) && isspace(*p))
104 p++;
105 if (*p++ != ':' || fname == fvalue)
15637ed4 106 {
6f14531a 107 syserr("553 header syntax error, line \"%s\"", line);
15637ed4
RG
108 return (0);
109 }
d747e748
JH
110 *fvalue = '\0';
111 fvalue = p;
15637ed4
RG
112
113 /* strip field value on front */
114 if (*fvalue == ' ')
115 fvalue++;
116
117 /* see if it is a known type */
118 for (hi = HdrInfo; hi->hi_field != NULL; hi++)
119 {
6f14531a 120 if (strcasecmp(hi->hi_field, fname) == 0)
15637ed4
RG
121 break;
122 }
123
d747e748
JH
124 if (tTd(31, 9))
125 {
126 if (hi->hi_field == NULL)
127 printf("no header match\n");
128 else
129 printf("header match, hi_flags=%o\n", hi->hi_flags);
130 }
131
15637ed4
RG
132 /* see if this is a resent message */
133 if (!def && bitset(H_RESENT, hi->hi_flags))
6f14531a 134 e->e_flags |= EF_RESENT;
15637ed4
RG
135
136 /* if this means "end of header" quit now */
137 if (bitset(H_EOH, hi->hi_flags))
138 return (hi->hi_flags);
139
d747e748
JH
140 /*
141 ** Drop explicit From: if same as what we would generate.
142 ** This is to make MH (which doesn't always give a full name)
143 ** insert the full name information in all circumstances.
144 */
145
15637ed4 146 p = "resent-from";
6f14531a 147 if (!bitset(EF_RESENT, e->e_flags))
15637ed4 148 p += 7;
6f14531a 149 if (!def && !bitset(EF_QUEUERUN, e->e_flags) && strcasecmp(fname, p) == 0)
15637ed4 150 {
3a363396
NW
151 if (tTd(31, 2))
152 {
153 printf("comparing header from (%s) against default (%s or %s)\n",
154 fvalue, e->e_from.q_paddr, e->e_from.q_user);
155 }
6f14531a 156 if (e->e_from.q_paddr != NULL &&
3a363396
NW
157 (strcmp(fvalue, e->e_from.q_paddr) == 0 ||
158 strcmp(fvalue, e->e_from.q_user) == 0))
15637ed4 159 return (hi->hi_flags);
d747e748
JH
160#ifdef MAYBENEXTRELEASE /* XXX UNTESTED XXX UNTESTED XXX UNTESTED XXX */
161#ifdef USERDB
162 else
163 {
164 auto ADDRESS a;
165 char *fancy;
166 extern char *crackaddr();
167 extern char *udbsender();
168
169 /*
170 ** Try doing USERDB rewriting even on fully commented
171 ** names; this saves the "comment" information (such
172 ** as full name) and rewrites the electronic part.
173 */
174
175 fancy = crackaddr(fvalue);
176 if (parseaddr(fvalue, &a, RF_COPYNONE, '\0', NULL, e) != NULL &&
177 a.q_mailer == LocalMailer &&
178 (p = udbsender(a.q_user)) != NULL)
179 {
180 char *oldg = macvalue('g', e);
181
182 define('g', p, e);
183 expand(fancy, buf, &buf[sizeof buf], e);
184 define('g', oldg, e);
185 fvalue = buf;
186 }
187 }
188#endif
189#endif
15637ed4
RG
190 }
191
192 /* delete default value for this header */
6f14531a 193 for (hp = &e->e_header; (h = *hp) != NULL; hp = &h->h_link)
15637ed4 194 {
6f14531a 195 if (strcasecmp(fname, h->h_field) == 0 &&
15637ed4
RG
196 bitset(H_DEFAULT, h->h_flags) &&
197 !bitset(H_FORCE, h->h_flags))
198 h->h_value = NULL;
199 }
200
201 /* create a new node */
202 h = (HDR *) xalloc(sizeof *h);
203 h->h_field = newstr(fname);
d747e748 204 h->h_value = newstr(fvalue);
15637ed4
RG
205 h->h_link = NULL;
206 bcopy((char *) mopts, (char *) h->h_mflags, sizeof mopts);
207 *hp = h;
208 h->h_flags = hi->hi_flags;
209 if (def)
210 h->h_flags |= H_DEFAULT;
211 if (cond)
212 h->h_flags |= H_CHECK;
15637ed4
RG
213
214 /* hack to see if this is a new format message */
215 if (!def && bitset(H_RCPT|H_FROM, h->h_flags) &&
6f14531a
RG
216 (strchr(fvalue, ',') != NULL || strchr(fvalue, '(') != NULL ||
217 strchr(fvalue, '<') != NULL || strchr(fvalue, ';') != NULL))
15637ed4 218 {
6f14531a 219 e->e_flags &= ~EF_OLDSTYLE;
15637ed4
RG
220 }
221
222 return (h->h_flags);
223}
224\f/*
225** ADDHEADER -- add a header entry to the end of the queue.
226**
227** This bypasses the special checking of chompheader.
228**
229** Parameters:
230** field -- the name of the header field.
6f14531a 231** value -- the value of the field.
15637ed4
RG
232** e -- the envelope to add them to.
233**
234** Returns:
235** none.
236**
237** Side Effects:
238** adds the field on the list of headers for this envelope.
239*/
240
241addheader(field, value, e)
242 char *field;
243 char *value;
244 ENVELOPE *e;
245{
246 register HDR *h;
247 register struct hdrinfo *hi;
248 HDR **hp;
249
250 /* find info struct */
251 for (hi = HdrInfo; hi->hi_field != NULL; hi++)
252 {
6f14531a 253 if (strcasecmp(field, hi->hi_field) == 0)
15637ed4
RG
254 break;
255 }
256
257 /* find current place in list -- keep back pointer? */
258 for (hp = &e->e_header; (h = *hp) != NULL; hp = &h->h_link)
259 {
6f14531a 260 if (strcasecmp(field, h->h_field) == 0)
15637ed4
RG
261 break;
262 }
263
264 /* allocate space for new header */
265 h = (HDR *) xalloc(sizeof *h);
266 h->h_field = field;
267 h->h_value = newstr(value);
268 h->h_link = *hp;
269 h->h_flags = hi->hi_flags | H_DEFAULT;
270 clrbitmap(h->h_mflags);
271 *hp = h;
272}
273\f/*
274** HVALUE -- return value of a header.
275**
276** Only "real" fields (i.e., ones that have not been supplied
277** as a default) are used.
278**
279** Parameters:
280** field -- the field name.
6f14531a 281** e -- the envelope containing the header.
15637ed4
RG
282**
283** Returns:
284** pointer to the value part.
285** NULL if not found.
286**
287** Side Effects:
288** none.
289*/
290
291char *
6f14531a 292hvalue(field, e)
15637ed4 293 char *field;
6f14531a 294 register ENVELOPE *e;
15637ed4
RG
295{
296 register HDR *h;
297
6f14531a 298 for (h = e->e_header; h != NULL; h = h->h_link)
15637ed4 299 {
6f14531a
RG
300 if (!bitset(H_DEFAULT, h->h_flags) &&
301 strcasecmp(h->h_field, field) == 0)
15637ed4
RG
302 return (h->h_value);
303 }
304 return (NULL);
305}
306\f/*
307** ISHEADER -- predicate telling if argument is a header.
308**
309** A line is a header if it has a single word followed by
310** optional white space followed by a colon.
311**
312** Parameters:
313** s -- string to check for possible headerness.
314**
315** Returns:
316** TRUE if s is a header.
317** FALSE otherwise.
318**
319** Side Effects:
320** none.
321*/
322
323bool
324isheader(s)
325 register char *s;
326{
327 while (*s > ' ' && *s != ':' && *s != '\0')
328 s++;
329
330 /* following technically violates RFC822 */
6f14531a 331 while (isascii(*s) && isspace(*s))
15637ed4
RG
332 s++;
333
334 return (*s == ':');
335}
336\f/*
337** EATHEADER -- run through the stored header and extract info.
338**
339** Parameters:
340** e -- the envelope to process.
6f14531a
RG
341** full -- if set, do full processing (e.g., compute
342** message priority).
15637ed4
RG
343**
344** Returns:
345** none.
346**
347** Side Effects:
348** Sets a bunch of global variables from information
349** in the collected header.
350** Aborts the message if the hop count is exceeded.
351*/
352
6f14531a 353eatheader(e, full)
15637ed4 354 register ENVELOPE *e;
6f14531a 355 bool full;
15637ed4
RG
356{
357 register HDR *h;
358 register char *p;
359 int hopcnt = 0;
6f14531a
RG
360 char *msgid;
361 char buf[MAXLINE];
362
363 /*
364 ** Set up macros for possible expansion in headers.
365 */
366
367 define('f', e->e_sender, e);
368 define('g', e->e_sender, e);
d747e748
JH
369 if (e->e_origrcpt != NULL && *e->e_origrcpt != '\0')
370 define('u', e->e_origrcpt, e);
371 else
372 define('u', NULL, e);
15637ed4
RG
373
374 if (tTd(32, 1))
375 printf("----- collected header -----\n");
6f14531a 376 msgid = "<none>";
15637ed4
RG
377 for (h = e->e_header; h != NULL; h = h->h_link)
378 {
d747e748
JH
379 if (h->h_value == NULL)
380 {
381 if (tTd(32, 1))
382 printf("%s: <NULL>\n", h->h_field);
383 continue;
384 }
385
6f14531a 386 /* do early binding */
d747e748 387 if (bitset(H_DEFAULT, h->h_flags))
6f14531a
RG
388 {
389 expand(h->h_value, buf, &buf[sizeof buf], e);
390 if (buf[0] != '\0')
391 {
392 h->h_value = newstr(buf);
393 h->h_flags &= ~H_DEFAULT;
394 }
395 }
15637ed4
RG
396
397 if (tTd(32, 1))
6f14531a
RG
398 printf("%s: %s\n", h->h_field, h->h_value);
399
15637ed4
RG
400 /* count the number of times it has been processed */
401 if (bitset(H_TRACE, h->h_flags))
402 hopcnt++;
403
404 /* send to this person if we so desire */
405 if (GrabTo && bitset(H_RCPT, h->h_flags) &&
406 !bitset(H_DEFAULT, h->h_flags) &&
6f14531a 407 (!bitset(EF_RESENT, e->e_flags) || bitset(H_RESENT, h->h_flags)))
15637ed4 408 {
d747e748
JH
409 int saveflags = e->e_flags;
410
411 (void) sendtolist(h->h_value, NULLADDR,
6f14531a 412 &e->e_sendqueue, e);
d747e748
JH
413
414 /* delete fatal errors generated by this address */
415 if (!GrabTo && !bitset(EF_FATALERRS, saveflags))
416 e->e_flags &= ~EF_FATALERRS;
15637ed4
RG
417 }
418
6f14531a 419 /* save the message-id for logging */
d747e748 420 if (full && strcasecmp(h->h_field, "message-id") == 0)
15637ed4 421 {
6f14531a
RG
422 msgid = h->h_value;
423 while (isascii(*msgid) && isspace(*msgid))
424 msgid++;
15637ed4 425 }
6f14531a
RG
426
427 /* see if this is a return-receipt header */
428 if (bitset(H_RECEIPTTO, h->h_flags))
429 e->e_receiptto = h->h_value;
430
431 /* see if this is an errors-to header */
432 if (UseErrorsTo && bitset(H_ERRORSTO, h->h_flags))
d747e748 433 (void) sendtolist(h->h_value, NULLADDR,
6f14531a 434 &e->e_errorqueue, e);
15637ed4
RG
435 }
436 if (tTd(32, 1))
437 printf("----------------------------\n");
438
6f14531a
RG
439 /* if we are just verifying (that is, sendmail -t -bv), drop out now */
440 if (OpMode == MD_VERIFY)
441 return;
442
15637ed4
RG
443 /* store hop count */
444 if (hopcnt > e->e_hopcount)
445 e->e_hopcount = hopcnt;
446
447 /* message priority */
6f14531a 448 p = hvalue("precedence", e);
15637ed4
RG
449 if (p != NULL)
450 e->e_class = priencode(p);
6f14531a 451 if (full)
15637ed4
RG
452 e->e_msgpriority = e->e_msgsize
453 - e->e_class * WkClassFact
454 + e->e_nrcpts * WkRecipFact;
455
15637ed4 456 /* full name of from person */
6f14531a 457 p = hvalue("full-name", e);
15637ed4
RG
458 if (p != NULL)
459 define('x', p, e);
460
461 /* date message originated */
6f14531a 462 p = hvalue("posted-date", e);
15637ed4 463 if (p == NULL)
6f14531a 464 p = hvalue("date", e);
15637ed4 465 if (p != NULL)
15637ed4 466 define('a', p, e);
15637ed4
RG
467
468 /*
469 ** Log collection information.
470 */
471
472# ifdef LOG
6f14531a 473 if (full && LogLevel > 4)
15637ed4 474 {
6f14531a
RG
475 char *name;
476 register char *sbp;
477 char hbuf[MAXNAME];
478 char sbuf[MAXLINE];
479
480 if (bitset(EF_RESPONSE, e->e_flags))
481 name = "[RESPONSE]";
482 else if ((name = macvalue('_', e)) != NULL)
483 ;
15637ed4
RG
484 else if (RealHostName[0] == '[')
485 name = RealHostName;
486 else
6f14531a
RG
487 {
488 name = hbuf;
489 (void) sprintf(hbuf, "%.80s", RealHostName);
490 if (RealHostAddr.sa.sa_family != 0)
491 {
492 p = &hbuf[strlen(hbuf)];
493 (void) sprintf(p, " (%s)",
494 anynet_ntoa(&RealHostAddr));
495 }
496 }
497
498 /* some versions of syslog only take 5 printf args */
499 sbp = sbuf;
500 sprintf(sbp, "from=%.200s, size=%ld, class=%d, pri=%ld, nrcpts=%d, msgid=%.100s",
501 e->e_from.q_paddr, e->e_msgsize, e->e_class,
502 e->e_msgpriority, e->e_nrcpts, msgid);
503 sbp += strlen(sbp);
504 if (e->e_bodytype != NULL)
505 {
506 (void) sprintf(sbp, ", bodytype=%.20s", e->e_bodytype);
507 sbp += strlen(sbp);
508 }
509 p = macvalue('r', e);
510 if (p != NULL)
511 (void) sprintf(sbp, ", proto=%.20s", p);
512 syslog(LOG_INFO, "%s: %s, relay=%s",
513 e->e_id, sbuf, name);
15637ed4 514 }
6f14531a 515# endif /* LOG */
15637ed4
RG
516}
517\f/*
518** PRIENCODE -- encode external priority names into internal values.
519**
520** Parameters:
521** p -- priority in ascii.
522**
523** Returns:
524** priority as a numeric level.
525**
526** Side Effects:
527** none.
528*/
529
530priencode(p)
531 char *p;
532{
533 register int i;
534
535 for (i = 0; i < NumPriorities; i++)
536 {
537 if (!strcasecmp(p, Priorities[i].pri_name))
538 return (Priorities[i].pri_val);
539 }
540
541 /* unknown priority */
542 return (0);
543}
544\f/*
545** CRACKADDR -- parse an address and turn it into a macro
546**
547** This doesn't actually parse the address -- it just extracts
548** it and replaces it with "$g". The parse is totally ad hoc
549** and isn't even guaranteed to leave something syntactically
550** identical to what it started with. However, it does leave
551** something semantically identical.
552**
6f14531a
RG
553** This algorithm has been cleaned up to handle a wider range
554** of cases -- notably quoted and backslash escaped strings.
555** This modification makes it substantially better at preserving
556** the original syntax.
15637ed4
RG
557**
558** Parameters:
559** addr -- the address to be cracked.
560**
561** Returns:
562** a pointer to the new version.
563**
564** Side Effects:
565** none.
566**
567** Warning:
568** The return value is saved in local storage and should
569** be copied if it is to be reused.
570*/
571
572char *
573crackaddr(addr)
574 register char *addr;
575{
576 register char *p;
6f14531a
RG
577 register char c;
578 int cmtlev;
579 int realcmtlev;
580 int anglelev, realanglelev;
581 int copylev;
582 bool qmode;
583 bool realqmode;
584 bool skipping;
585 bool putgmac = FALSE;
586 bool quoteit = FALSE;
d747e748 587 bool gotangle = FALSE;
15637ed4 588 register char *bp;
6f14531a
RG
589 char *buflim;
590 static char buf[MAXNAME];
15637ed4
RG
591
592 if (tTd(33, 1))
593 printf("crackaddr(%s)\n", addr);
594
15637ed4 595 /* strip leading spaces */
6f14531a 596 while (*addr != '\0' && isascii(*addr) && isspace(*addr))
15637ed4
RG
597 addr++;
598
599 /*
6f14531a
RG
600 ** Start by assuming we have no angle brackets. This will be
601 ** adjusted later if we find them.
15637ed4
RG
602 */
603
6f14531a
RG
604 bp = buf;
605 buflim = &buf[sizeof buf - 5];
606 p = addr;
607 copylev = anglelev = realanglelev = cmtlev = realcmtlev = 0;
608 qmode = realqmode = FALSE;
609
610 while ((c = *p++) != '\0')
15637ed4 611 {
6f14531a
RG
612 /*
613 ** If the buffer is overful, go into a special "skipping"
614 ** mode that tries to keep legal syntax but doesn't actually
615 ** output things.
616 */
15637ed4 617
6f14531a
RG
618 skipping = bp >= buflim;
619
620 if (copylev > 0 && !skipping)
621 *bp++ = c;
15637ed4 622
6f14531a
RG
623 /* check for backslash escapes */
624 if (c == '\\')
15637ed4 625 {
6f14531a
RG
626 /* arrange to quote the address */
627 if (cmtlev <= 0 && !qmode)
628 quoteit = TRUE;
15637ed4 629
6f14531a
RG
630 if ((c = *p++) == '\0')
631 {
632 /* too far */
633 p--;
634 goto putg;
15637ed4 635 }
6f14531a
RG
636 if (copylev > 0 && !skipping)
637 *bp++ = c;
638 goto putg;
15637ed4
RG
639 }
640
6f14531a
RG
641 /* check for quoted strings */
642 if (c == '"')
15637ed4 643 {
6f14531a
RG
644 qmode = !qmode;
645 if (copylev > 0 && !skipping)
646 realqmode = !realqmode;
647 continue;
15637ed4 648 }
6f14531a
RG
649 if (qmode)
650 goto putg;
15637ed4 651
6f14531a
RG
652 /* check for comments */
653 if (c == '(')
654 {
655 cmtlev++;
15637ed4 656
6f14531a
RG
657 /* allow space for closing paren */
658 if (!skipping)
659 {
660 buflim--;
661 realcmtlev++;
662 if (copylev++ <= 0)
663 {
664 *bp++ = ' ';
665 *bp++ = c;
666 }
667 }
668 }
669 if (cmtlev > 0)
15637ed4 670 {
6f14531a 671 if (c == ')')
15637ed4 672 {
6f14531a
RG
673 cmtlev--;
674 copylev--;
675 if (!skipping)
15637ed4 676 {
6f14531a
RG
677 realcmtlev--;
678 buflim++;
15637ed4 679 }
15637ed4
RG
680 }
681 continue;
682 }
6f14531a
RG
683 else if (c == ')')
684 {
685 /* syntax error: unmatched ) */
686 if (!skipping)
687 bp--;
688 }
15637ed4 689
15637ed4 690
6f14531a 691 /* check for characters that may have to be quoted */
d747e748 692 if (strchr(".'@,;:\\()[]", c) != NULL)
15637ed4 693 {
6f14531a
RG
694 /*
695 ** If these occur as the phrase part of a <>
696 ** construct, but are not inside of () or already
697 ** quoted, they will have to be quoted. Note that
698 ** now (but don't actually do the quoting).
699 */
700
701 if (cmtlev <= 0 && !qmode)
702 quoteit = TRUE;
15637ed4 703 }
15637ed4 704
6f14531a
RG
705 /* check for angle brackets */
706 if (c == '<')
707 {
708 register char *q;
15637ed4 709
d747e748
JH
710 /* assume first of two angles is bogus */
711 if (gotangle)
712 quoteit = TRUE;
713 gotangle = TRUE;
714
6f14531a 715 /* oops -- have to change our mind */
d747e748 716 anglelev = 1;
6f14531a 717 if (!skipping)
d747e748 718 realanglelev = 1;
6f14531a
RG
719
720 bp = buf;
721 if (quoteit)
722 {
723 *bp++ = '"';
724
725 /* back up over the '<' and any spaces */
726 --p;
727 while (isascii(*--p) && isspace(*p))
728 continue;
729 p++;
730 }
731 for (q = addr; q < p; )
732 {
733 c = *q++;
734 if (bp < buflim)
735 {
736 if (quoteit && c == '"')
737 *bp++ = '\\';
738 *bp++ = c;
739 }
740 }
741 if (quoteit)
742 {
d747e748
JH
743 if (bp == &buf[1])
744 bp--;
745 else
746 *bp++ = '"';
6f14531a
RG
747 while ((c = *p++) != '<')
748 {
749 if (bp < buflim)
750 *bp++ = c;
751 }
752 *bp++ = c;
753 }
754 copylev = 0;
755 putgmac = quoteit = FALSE;
756 continue;
757 }
758
759 if (c == '>')
760 {
761 if (anglelev > 0)
762 {
763 anglelev--;
764 if (!skipping)
765 {
766 realanglelev--;
767 buflim++;
768 }
769 }
770 else if (!skipping)
771 {
772 /* syntax error: unmatched > */
773 if (copylev > 0)
774 bp--;
d747e748 775 quoteit = TRUE;
6f14531a
RG
776 continue;
777 }
778 if (copylev++ <= 0)
779 *bp++ = c;
780 continue;
781 }
782
783 /* must be a real address character */
784 putg:
785 if (copylev <= 0 && !putgmac)
786 {
787 *bp++ = MACROEXPAND;
788 *bp++ = 'g';
789 putgmac = TRUE;
790 }
15637ed4
RG
791 }
792
6f14531a
RG
793 /* repair any syntactic damage */
794 if (realqmode)
795 *bp++ = '"';
796 while (realcmtlev-- > 0)
797 *bp++ = ')';
798 while (realanglelev-- > 0)
799 *bp++ = '>';
800 *bp++ = '\0';
801
15637ed4
RG
802 if (tTd(33, 1))
803 printf("crackaddr=>`%s'\n", buf);
804
805 return (buf);
806}
807\f/*
808** PUTHEADER -- put the header part of a message from the in-core copy
809**
810** Parameters:
811** fp -- file to put it on.
812** m -- mailer to use.
813** e -- envelope to use.
814**
815** Returns:
816** none.
817**
818** Side Effects:
819** none.
820*/
821
6f14531a
RG
822/*
823 * Macro for fast max (not available in e.g. DG/UX, 386/ix).
824 */
825#ifndef MAX
826# define MAX(a,b) (((a)>(b))?(a):(b))
827#endif
828
15637ed4
RG
829putheader(fp, m, e)
830 register FILE *fp;
831 register MAILER *m;
832 register ENVELOPE *e;
833{
6f14531a 834 char buf[MAX(MAXLINE,BUFSIZ)];
15637ed4 835 register HDR *h;
6f14531a
RG
836 char obuf[MAXLINE];
837
838 if (tTd(34, 1))
839 printf("--- putheader, mailer = %s ---\n", m->m_name);
15637ed4
RG
840
841 for (h = e->e_header; h != NULL; h = h->h_link)
842 {
843 register char *p;
844 extern bool bitintersect();
845
6f14531a
RG
846 if (tTd(34, 11))
847 {
848 printf(" %s: ", h->h_field);
849 xputs(h->h_value);
850 }
851
15637ed4
RG
852 if (bitset(H_CHECK|H_ACHECK, h->h_flags) &&
853 !bitintersect(h->h_mflags, m->m_flags))
6f14531a
RG
854 {
855 if (tTd(34, 11))
856 printf(" (skipped)\n");
15637ed4 857 continue;
6f14531a 858 }
15637ed4
RG
859
860 /* handle Resent-... headers specially */
861 if (bitset(H_RESENT, h->h_flags) && !bitset(EF_RESENT, e->e_flags))
6f14531a
RG
862 {
863 if (tTd(34, 11))
864 printf(" (skipped (resent))\n");
15637ed4 865 continue;
6f14531a
RG
866 }
867 if (tTd(34, 11))
868 printf("\n");
15637ed4
RG
869
870 p = h->h_value;
871 if (bitset(H_DEFAULT, h->h_flags))
872 {
873 /* macro expand value if generated internally */
874 expand(p, buf, &buf[sizeof buf], e);
875 p = buf;
876 if (p == NULL || *p == '\0')
877 continue;
878 }
879
880 if (bitset(H_FROM|H_RCPT, h->h_flags))
881 {
882 /* address field */
883 bool oldstyle = bitset(EF_OLDSTYLE, e->e_flags);
884
885 if (bitset(H_FROM, h->h_flags))
886 oldstyle = FALSE;
6f14531a 887 commaize(h, p, fp, oldstyle, m, e);
15637ed4
RG
888 }
889 else
890 {
891 /* vanilla header line */
892 register char *nlp;
893
6f14531a
RG
894 (void) sprintf(obuf, "%s: ", h->h_field);
895 while ((nlp = strchr(p, '\n')) != NULL)
15637ed4
RG
896 {
897 *nlp = '\0';
898 (void) strcat(obuf, p);
899 *nlp = '\n';
900 putline(obuf, fp, m);
901 p = ++nlp;
902 obuf[0] = '\0';
903 }
904 (void) strcat(obuf, p);
905 putline(obuf, fp, m);
906 }
907 }
908}
909\f/*
910** COMMAIZE -- output a header field, making a comma-translated list.
911**
912** Parameters:
913** h -- the header field to output.
914** p -- the value to put in it.
915** fp -- file to put it to.
916** oldstyle -- TRUE if this is an old style header.
917** m -- a pointer to the mailer descriptor. If NULL,
918** don't transform the name at all.
6f14531a 919** e -- the envelope containing the message.
15637ed4
RG
920**
921** Returns:
922** none.
923**
924** Side Effects:
925** outputs "p" to file "fp".
926*/
927
6f14531a 928commaize(h, p, fp, oldstyle, m, e)
15637ed4
RG
929 register HDR *h;
930 register char *p;
931 FILE *fp;
932 bool oldstyle;
933 register MAILER *m;
6f14531a 934 register ENVELOPE *e;
15637ed4
RG
935{
936 register char *obp;
937 int opos;
938 bool firstone = TRUE;
939 char obuf[MAXLINE + 3];
940
941 /*
942 ** Output the address list translated by the
943 ** mailer and with commas.
944 */
945
946 if (tTd(14, 2))
947 printf("commaize(%s: %s)\n", h->h_field, p);
948
949 obp = obuf;
6f14531a 950 (void) sprintf(obp, "%s: ", h->h_field);
15637ed4
RG
951 opos = strlen(h->h_field) + 2;
952 obp += opos;
953
954 /*
955 ** Run through the list of values.
956 */
957
958 while (*p != '\0')
959 {
960 register char *name;
6f14531a 961 register int c;
15637ed4 962 char savechar;
6f14531a
RG
963 int flags;
964 auto int stat;
15637ed4
RG
965
966 /*
967 ** Find the end of the name. New style names
968 ** end with a comma, old style names end with
969 ** a space character. However, spaces do not
970 ** necessarily delimit an old-style name -- at
971 ** signs mean keep going.
972 */
973
974 /* find end of name */
6f14531a 975 while ((isascii(*p) && isspace(*p)) || *p == ',')
15637ed4
RG
976 p++;
977 name = p;
978 for (;;)
979 {
6f14531a 980 auto char *oldp;
15637ed4 981 char pvpbuf[PSBUFSIZE];
15637ed4 982
6f14531a
RG
983 (void) prescan(p, oldstyle ? ' ' : ',', pvpbuf, &oldp);
984 p = oldp;
15637ed4
RG
985
986 /* look to see if we have an at sign */
6f14531a 987 while (*p != '\0' && isascii(*p) && isspace(*p))
15637ed4
RG
988 p++;
989
6f14531a 990 if (*p != '@')
15637ed4
RG
991 {
992 p = oldp;
993 break;
994 }
995 p += *p == '@' ? 1 : 2;
6f14531a 996 while (*p != '\0' && isascii(*p) && isspace(*p))
15637ed4
RG
997 p++;
998 }
999 /* at the end of one complete name */
1000
1001 /* strip off trailing white space */
6f14531a
RG
1002 while (p >= name &&
1003 ((isascii(*p) && isspace(*p)) || *p == ',' || *p == '\0'))
15637ed4
RG
1004 p--;
1005 if (++p == name)
1006 continue;
1007 savechar = *p;
1008 *p = '\0';
1009
1010 /* translate the name to be relative */
6f14531a
RG
1011 flags = RF_HEADERADDR|RF_ADDDOMAIN;
1012 if (bitset(H_FROM, h->h_flags))
1013 flags |= RF_SENDERADDR;
1014 stat = EX_OK;
1015 name = remotename(name, m, flags, &stat, e);
15637ed4
RG
1016 if (*name == '\0')
1017 {
1018 *p = savechar;
1019 continue;
1020 }
1021
1022 /* output the name with nice formatting */
6f14531a 1023 opos += strlen(name);
15637ed4
RG
1024 if (!firstone)
1025 opos += 2;
1026 if (opos > 78 && !firstone)
1027 {
1028 (void) strcpy(obp, ",\n");
1029 putline(obuf, fp, m);
1030 obp = obuf;
1031 (void) sprintf(obp, " ");
1032 opos = strlen(obp);
1033 obp += opos;
6f14531a 1034 opos += strlen(name);
15637ed4
RG
1035 }
1036 else if (!firstone)
1037 {
1038 (void) sprintf(obp, ", ");
1039 obp += 2;
1040 }
1041
6f14531a
RG
1042 while ((c = *name++) != '\0' && obp < &obuf[MAXLINE])
1043 *obp++ = c;
15637ed4
RG
1044 firstone = FALSE;
1045 *p = savechar;
1046 }
1047 (void) strcpy(obp, "\n");
1048 putline(obuf, fp, m);
1049}
1050\f/*
6f14531a
RG
1051** COPYHEADER -- copy header list
1052**
1053** This routine is the equivalent of newstr for header lists
15637ed4
RG
1054**
1055** Parameters:
6f14531a 1056** header -- list of header structures to copy.
15637ed4
RG
1057**
1058** Returns:
6f14531a 1059** a copy of 'header'.
15637ed4
RG
1060**
1061** Side Effects:
1062** none.
1063*/
1064
6f14531a
RG
1065HDR *
1066copyheader(header)
1067 register HDR *header;
15637ed4 1068{
6f14531a
RG
1069 register HDR *newhdr;
1070 HDR *ret;
1071 register HDR **tail = &ret;
15637ed4 1072
6f14531a
RG
1073 while (header != NULL)
1074 {
1075 newhdr = (HDR *) xalloc(sizeof(HDR));
1076 STRUCTCOPY(*header, *newhdr);
1077 *tail = newhdr;
1078 tail = &newhdr->h_link;
1079 header = header->h_link;
1080 }
1081 *tail = NULL;
1082
1083 return ret;
15637ed4 1084}