122706Sdist /* 234921Sbostic * Copyright (c) 1983 Eric P. Allman 362525Sbostic * Copyright (c) 1988, 1993 462525Sbostic * The Regents of the University of California. All rights reserved. 533729Sbostic * 642826Sbostic * %sccs.include.redist.c% 733729Sbostic */ 822706Sdist 922706Sdist #ifndef lint 10*63753Seric static char sccsid[] = "@(#)headers.c 8.2 (Berkeley) 07/11/93"; 1133729Sbostic #endif /* not lint */ 1222706Sdist 134091Seric # include <errno.h> 144091Seric # include "sendmail.h" 154091Seric 164091Seric /* 174091Seric ** CHOMPHEADER -- process and save a header line. 184091Seric ** 194091Seric ** Called by collect and by readcf to deal with header lines. 204091Seric ** 214091Seric ** Parameters: 224091Seric ** line -- header as a text line. 234091Seric ** def -- if set, this is a default value. 2455012Seric ** e -- the envelope including this header. 254091Seric ** 264091Seric ** Returns: 274091Seric ** flags for this header. 284091Seric ** 294091Seric ** Side Effects: 304091Seric ** The header is saved on the header list. 314319Seric ** Contents of 'line' are destroyed. 324091Seric */ 334091Seric 3455012Seric chompheader(line, def, e) 354091Seric char *line; 364091Seric bool def; 3755012Seric register ENVELOPE *e; 384091Seric { 394091Seric register char *p; 404091Seric register HDR *h; 414091Seric HDR **hp; 424091Seric char *fname; 434091Seric char *fvalue; 444091Seric struct hdrinfo *hi; 459059Seric bool cond = FALSE; 4610689Seric BITMAP mopts; 474091Seric 487677Seric if (tTd(31, 6)) 497677Seric printf("chompheader: %s\n", line); 507677Seric 514627Seric /* strip off options */ 5210689Seric clrbitmap(mopts); 534627Seric p = line; 5457405Seric if (*p == '?') 554627Seric { 564627Seric /* have some */ 5756795Seric register char *q = strchr(p + 1, *p); 584627Seric 594627Seric if (q != NULL) 604627Seric { 614627Seric *q++ = '\0'; 6210689Seric while (*++p != '\0') 6310689Seric setbitn(*p, mopts); 644627Seric p = q; 654627Seric } 664627Seric else 6758151Seric usrerr("553 header syntax error, line \"%s\"", line); 689059Seric cond = TRUE; 694627Seric } 704627Seric 714091Seric /* find canonical name */ 724627Seric fname = p; 7356795Seric p = strchr(p, ':'); 7410118Seric if (p == NULL) 7510118Seric { 7658151Seric syserr("553 header syntax error, line \"%s\"", line); 7710118Seric return (0); 7810118Seric } 794091Seric fvalue = &p[1]; 8058050Seric while (isascii(*--p) && isspace(*p)) 814091Seric continue; 824091Seric *++p = '\0'; 834091Seric 844091Seric /* strip field value on front */ 854091Seric if (*fvalue == ' ') 864091Seric fvalue++; 874091Seric 884091Seric /* see if it is a known type */ 894091Seric for (hi = HdrInfo; hi->hi_field != NULL; hi++) 904091Seric { 9159579Seric if (strcasecmp(hi->hi_field, fname) == 0) 924091Seric break; 934091Seric } 944091Seric 9511414Seric /* see if this is a resent message */ 9611930Seric if (!def && bitset(H_RESENT, hi->hi_flags)) 9755012Seric e->e_flags |= EF_RESENT; 9811414Seric 994091Seric /* if this means "end of header" quit now */ 1004091Seric if (bitset(H_EOH, hi->hi_flags)) 1014091Seric return (hi->hi_flags); 1024091Seric 10311414Seric /* drop explicit From: if same as what we would generate -- for MH */ 10414784Seric p = "resent-from"; 10555012Seric if (!bitset(EF_RESENT, e->e_flags)) 10614784Seric p += 7; 10759579Seric if (!def && !bitset(EF_QUEUERUN, e->e_flags) && strcasecmp(fname, p) == 0) 10811414Seric { 109*63753Seric if (tTd(31, 2)) 110*63753Seric { 111*63753Seric printf("comparing header from (%s) against default (%s or %s)\n", 112*63753Seric fvalue, e->e_from.q_paddr, e->e_from.q_user); 113*63753Seric } 11455012Seric if (e->e_from.q_paddr != NULL && 115*63753Seric (strcmp(fvalue, e->e_from.q_paddr) == 0 || 116*63753Seric strcmp(fvalue, e->e_from.q_user) == 0)) 11711414Seric return (hi->hi_flags); 11811414Seric } 11911414Seric 12014784Seric /* delete default value for this header */ 12155012Seric for (hp = &e->e_header; (h = *hp) != NULL; hp = &h->h_link) 12214784Seric { 12359579Seric if (strcasecmp(fname, h->h_field) == 0 && 12414784Seric bitset(H_DEFAULT, h->h_flags) && 12514784Seric !bitset(H_FORCE, h->h_flags)) 12614784Seric h->h_value = NULL; 12714784Seric } 12814784Seric 12913012Seric /* create a new node */ 13013012Seric h = (HDR *) xalloc(sizeof *h); 13113012Seric h->h_field = newstr(fname); 13213012Seric h->h_value = NULL; 13313012Seric h->h_link = NULL; 13423117Seric bcopy((char *) mopts, (char *) h->h_mflags, sizeof mopts); 13513012Seric *hp = h; 1368066Seric h->h_flags = hi->hi_flags; 1374091Seric if (def) 1384091Seric h->h_flags |= H_DEFAULT; 1399059Seric if (cond) 1409059Seric h->h_flags |= H_CHECK; 1414091Seric if (h->h_value != NULL) 1429351Seric free((char *) h->h_value); 1438066Seric h->h_value = newstr(fvalue); 1444091Seric 1455937Seric /* hack to see if this is a new format message */ 1468095Seric if (!def && bitset(H_RCPT|H_FROM, h->h_flags) && 14756795Seric (strchr(fvalue, ',') != NULL || strchr(fvalue, '(') != NULL || 14856795Seric strchr(fvalue, '<') != NULL || strchr(fvalue, ';') != NULL)) 1498089Seric { 15055012Seric e->e_flags &= ~EF_OLDSTYLE; 1518089Seric } 1525937Seric 1534091Seric return (h->h_flags); 1544091Seric } 1554091Seric /* 1566980Seric ** ADDHEADER -- add a header entry to the end of the queue. 1576980Seric ** 1586980Seric ** This bypasses the special checking of chompheader. 1596980Seric ** 1606980Seric ** Parameters: 16159579Seric ** field -- the name of the header field. 16258789Seric ** value -- the value of the field. 1636980Seric ** e -- the envelope to add them to. 1646980Seric ** 1656980Seric ** Returns: 1666980Seric ** none. 1676980Seric ** 1686980Seric ** Side Effects: 1696980Seric ** adds the field on the list of headers for this envelope. 1706980Seric */ 1716980Seric 1726980Seric addheader(field, value, e) 1736980Seric char *field; 1746980Seric char *value; 1756980Seric ENVELOPE *e; 1766980Seric { 1776980Seric register HDR *h; 1786980Seric register struct hdrinfo *hi; 1796980Seric HDR **hp; 1806980Seric 1816980Seric /* find info struct */ 1826980Seric for (hi = HdrInfo; hi->hi_field != NULL; hi++) 1836980Seric { 18459579Seric if (strcasecmp(field, hi->hi_field) == 0) 1856980Seric break; 1866980Seric } 1876980Seric 1886980Seric /* find current place in list -- keep back pointer? */ 1896980Seric for (hp = &e->e_header; (h = *hp) != NULL; hp = &h->h_link) 1906980Seric { 19159579Seric if (strcasecmp(field, h->h_field) == 0) 1926980Seric break; 1936980Seric } 1946980Seric 1956980Seric /* allocate space for new header */ 1966980Seric h = (HDR *) xalloc(sizeof *h); 1976980Seric h->h_field = field; 1986980Seric h->h_value = newstr(value); 1997368Seric h->h_link = *hp; 2006980Seric h->h_flags = hi->hi_flags | H_DEFAULT; 20110689Seric clrbitmap(h->h_mflags); 2026980Seric *hp = h; 2036980Seric } 2046980Seric /* 2054091Seric ** HVALUE -- return value of a header. 2064091Seric ** 2074091Seric ** Only "real" fields (i.e., ones that have not been supplied 2084091Seric ** as a default) are used. 2094091Seric ** 2104091Seric ** Parameters: 2114091Seric ** field -- the field name. 21255012Seric ** e -- the envelope containing the header. 2134091Seric ** 2144091Seric ** Returns: 2154091Seric ** pointer to the value part. 2164091Seric ** NULL if not found. 2174091Seric ** 2184091Seric ** Side Effects: 2199382Seric ** none. 2204091Seric */ 2214091Seric 2224091Seric char * 22355012Seric hvalue(field, e) 2244091Seric char *field; 22555012Seric register ENVELOPE *e; 2264091Seric { 2274091Seric register HDR *h; 2284091Seric 22955012Seric for (h = e->e_header; h != NULL; h = h->h_link) 2304091Seric { 23159579Seric if (!bitset(H_DEFAULT, h->h_flags) && 23259579Seric strcasecmp(h->h_field, field) == 0) 2334091Seric return (h->h_value); 2344091Seric } 2354091Seric return (NULL); 2364091Seric } 2374091Seric /* 2384091Seric ** ISHEADER -- predicate telling if argument is a header. 2394091Seric ** 2404319Seric ** A line is a header if it has a single word followed by 2414319Seric ** optional white space followed by a colon. 2424319Seric ** 2434091Seric ** Parameters: 2444091Seric ** s -- string to check for possible headerness. 2454091Seric ** 2464091Seric ** Returns: 2474091Seric ** TRUE if s is a header. 2484091Seric ** FALSE otherwise. 2494091Seric ** 2504091Seric ** Side Effects: 2514091Seric ** none. 2524091Seric */ 2534091Seric 2544091Seric bool 2554091Seric isheader(s) 2564091Seric register char *s; 2574091Seric { 2589382Seric while (*s > ' ' && *s != ':' && *s != '\0') 2594091Seric s++; 2609382Seric 2619382Seric /* following technically violates RFC822 */ 26258050Seric while (isascii(*s) && isspace(*s)) 2634091Seric s++; 2649382Seric 2654091Seric return (*s == ':'); 2664091Seric } 2675919Seric /* 2687783Seric ** EATHEADER -- run through the stored header and extract info. 2697783Seric ** 2707783Seric ** Parameters: 2719382Seric ** e -- the envelope to process. 27258929Seric ** full -- if set, do full processing (e.g., compute 27358929Seric ** message priority). 2747783Seric ** 2757783Seric ** Returns: 2767783Seric ** none. 2777783Seric ** 2787783Seric ** Side Effects: 2797783Seric ** Sets a bunch of global variables from information 2809382Seric ** in the collected header. 2819382Seric ** Aborts the message if the hop count is exceeded. 2827783Seric */ 2837783Seric 28458929Seric eatheader(e, full) 2859382Seric register ENVELOPE *e; 28658929Seric bool full; 2877783Seric { 2887783Seric register HDR *h; 2897783Seric register char *p; 2909382Seric int hopcnt = 0; 29157208Seric char *msgid; 29258688Seric char buf[MAXLINE]; 2937783Seric 29458688Seric /* 29558688Seric ** Set up macros for possible expansion in headers. 29658688Seric */ 29758688Seric 29858704Seric define('f', e->e_sender, e); 29958704Seric define('g', e->e_sender, e); 30058688Seric 3019382Seric if (tTd(32, 1)) 3029382Seric printf("----- collected header -----\n"); 30357208Seric msgid = "<none>"; 3049382Seric for (h = e->e_header; h != NULL; h = h->h_link) 3057783Seric { 30658688Seric /* do early binding */ 30758688Seric if (bitset(H_DEFAULT, h->h_flags) && h->h_value != NULL) 30858688Seric { 30958688Seric expand(h->h_value, buf, &buf[sizeof buf], e); 31058688Seric if (buf[0] != '\0') 31158688Seric { 31258688Seric h->h_value = newstr(buf); 31358688Seric h->h_flags &= ~H_DEFAULT; 31458688Seric } 31558688Seric } 31658688Seric 3179382Seric if (tTd(32, 1)) 31859579Seric printf("%s: %s\n", h->h_field, h->h_value); 31957359Seric 32011414Seric /* count the number of times it has been processed */ 3219382Seric if (bitset(H_TRACE, h->h_flags)) 3229382Seric hopcnt++; 32311414Seric 32411414Seric /* send to this person if we so desire */ 32511414Seric if (GrabTo && bitset(H_RCPT, h->h_flags) && 32611414Seric !bitset(H_DEFAULT, h->h_flags) && 32755012Seric (!bitset(EF_RESENT, e->e_flags) || bitset(H_RESENT, h->h_flags))) 32811414Seric { 32958082Seric (void) sendtolist(h->h_value, (ADDRESS *) NULL, 33058082Seric &e->e_sendqueue, e); 33111414Seric } 33211414Seric 33357208Seric /* save the message-id for logging */ 33458929Seric if (full && h->h_value != NULL && 33559579Seric strcasecmp(h->h_field, "message-id") == 0) 33611290Seric { 33757208Seric msgid = h->h_value; 33859859Seric while (isascii(*msgid) && isspace(*msgid)) 33959859Seric msgid++; 34011290Seric } 34157359Seric 34257359Seric /* see if this is a return-receipt header */ 34357359Seric if (bitset(H_RECEIPTTO, h->h_flags)) 34457359Seric e->e_receiptto = h->h_value; 34557359Seric 34657359Seric /* see if this is an errors-to header */ 34761104Seric if (UseErrorsTo && bitset(H_ERRORSTO, h->h_flags)) 34858082Seric (void) sendtolist(h->h_value, (ADDRESS *) NULL, 34958082Seric &e->e_errorqueue, e); 3509382Seric } 3519382Seric if (tTd(32, 1)) 3527783Seric printf("----------------------------\n"); 3537783Seric 35458145Seric /* if we are just verifying (that is, sendmail -t -bv), drop out now */ 35558145Seric if (OpMode == MD_VERIFY) 35658145Seric return; 35758145Seric 3589382Seric /* store hop count */ 3599382Seric if (hopcnt > e->e_hopcount) 3609382Seric e->e_hopcount = hopcnt; 3619382Seric 3627783Seric /* message priority */ 36355012Seric p = hvalue("precedence", e); 3649382Seric if (p != NULL) 3659382Seric e->e_class = priencode(p); 36658929Seric if (full) 36725013Seric e->e_msgpriority = e->e_msgsize 36824981Seric - e->e_class * WkClassFact 36924981Seric + e->e_nrcpts * WkRecipFact; 3707783Seric 3717783Seric /* full name of from person */ 37255012Seric p = hvalue("full-name", e); 3737783Seric if (p != NULL) 3749382Seric define('x', p, e); 3757783Seric 3767783Seric /* date message originated */ 37755012Seric p = hvalue("posted-date", e); 3787783Seric if (p == NULL) 37955012Seric p = hvalue("date", e); 3807783Seric if (p != NULL) 3819382Seric define('a', p, e); 38211290Seric 38311290Seric /* 38411290Seric ** Log collection information. 38511290Seric */ 38611290Seric 38711290Seric # ifdef LOG 38858929Seric if (full && LogLevel > 4) 38911290Seric { 39057359Seric char *name; 39160575Seric register char *sbp; 39257232Seric char hbuf[MAXNAME]; 39357359Seric char sbuf[MAXLINE]; 39436230Skarels 39558667Seric if (bitset(EF_RESPONSE, e->e_flags)) 39658667Seric name = "[RESPONSE]"; 39758951Seric else if ((name = macvalue('_', e)) != NULL) 39858951Seric ; 39958667Seric else if (RealHostName[0] == '[') 40036230Skarels name = RealHostName; 40136230Skarels else 40257359Seric { 40357359Seric name = hbuf; 40458798Seric (void) sprintf(hbuf, "%.80s", RealHostName); 40558798Seric if (RealHostAddr.sa.sa_family != 0) 40658798Seric { 40758798Seric p = &hbuf[strlen(hbuf)]; 40858798Seric (void) sprintf(p, " (%s)", 40958798Seric anynet_ntoa(&RealHostAddr)); 41058798Seric } 41157359Seric } 41257359Seric 41357359Seric /* some versions of syslog only take 5 printf args */ 41460575Seric sbp = sbuf; 41560575Seric sprintf(sbp, "from=%.200s, size=%ld, class=%d, pri=%ld, nrcpts=%d, msgid=%.100s", 41658558Seric e->e_from.q_paddr, e->e_msgsize, e->e_class, 41757589Seric e->e_msgpriority, e->e_nrcpts, msgid); 41860575Seric sbp += strlen(sbp); 41960575Seric if (e->e_bodytype != NULL) 42060575Seric { 42160575Seric (void) sprintf(sbp, ", bodytype=%.20s", e->e_bodytype); 42260575Seric sbp += strlen(sbp); 42360575Seric } 42460575Seric p = macvalue('r', e); 42560575Seric if (p != NULL) 42660575Seric (void) sprintf(sbp, ", proto=%.20s", p); 42758686Seric syslog(LOG_INFO, "%s: %s, relay=%s", 42857359Seric e->e_id, sbuf, name); 42911290Seric } 43056795Seric # endif /* LOG */ 4317783Seric } 4327783Seric /* 4337783Seric ** PRIENCODE -- encode external priority names into internal values. 4347783Seric ** 4357783Seric ** Parameters: 4367783Seric ** p -- priority in ascii. 4377783Seric ** 4387783Seric ** Returns: 4397783Seric ** priority as a numeric level. 4407783Seric ** 4417783Seric ** Side Effects: 4427783Seric ** none. 4437783Seric */ 4447783Seric 4457783Seric priencode(p) 4467783Seric char *p; 4477783Seric { 4488253Seric register int i; 4497783Seric 4508253Seric for (i = 0; i < NumPriorities; i++) 4517783Seric { 45233725Sbostic if (!strcasecmp(p, Priorities[i].pri_name)) 4538253Seric return (Priorities[i].pri_val); 4547783Seric } 4558253Seric 4568253Seric /* unknown priority */ 4578253Seric return (0); 4587783Seric } 4597783Seric /* 4607890Seric ** CRACKADDR -- parse an address and turn it into a macro 4617783Seric ** 4627783Seric ** This doesn't actually parse the address -- it just extracts 4637783Seric ** it and replaces it with "$g". The parse is totally ad hoc 4647783Seric ** and isn't even guaranteed to leave something syntactically 4657783Seric ** identical to what it started with. However, it does leave 4667783Seric ** something semantically identical. 4677783Seric ** 46851379Seric ** This algorithm has been cleaned up to handle a wider range 46951379Seric ** of cases -- notably quoted and backslash escaped strings. 47051379Seric ** This modification makes it substantially better at preserving 47151379Seric ** the original syntax. 4727783Seric ** 4737783Seric ** Parameters: 4747890Seric ** addr -- the address to be cracked. 4757783Seric ** 4767783Seric ** Returns: 4777783Seric ** a pointer to the new version. 4787783Seric ** 4797783Seric ** Side Effects: 4807890Seric ** none. 4817783Seric ** 4827783Seric ** Warning: 4837783Seric ** The return value is saved in local storage and should 4847783Seric ** be copied if it is to be reused. 4857783Seric */ 4867783Seric 4877783Seric char * 4887890Seric crackaddr(addr) 4897890Seric register char *addr; 4907783Seric { 4917783Seric register char *p; 49251379Seric register char c; 49351379Seric int cmtlev; 49456764Seric int realcmtlev; 49556764Seric int anglelev, realanglelev; 49651379Seric int copylev; 49751379Seric bool qmode; 49856764Seric bool realqmode; 49956764Seric bool skipping; 50051379Seric bool putgmac = FALSE; 50156735Seric bool quoteit = FALSE; 50251379Seric register char *bp; 50356764Seric char *buflim; 5047783Seric static char buf[MAXNAME]; 5057783Seric 5067783Seric if (tTd(33, 1)) 5077890Seric printf("crackaddr(%s)\n", addr); 5087783Seric 5098082Seric /* strip leading spaces */ 51058050Seric while (*addr != '\0' && isascii(*addr) && isspace(*addr)) 5118082Seric addr++; 5128082Seric 5137783Seric /* 51451379Seric ** Start by assuming we have no angle brackets. This will be 51551379Seric ** adjusted later if we find them. 5167783Seric */ 5177783Seric 51851379Seric bp = buf; 51956764Seric buflim = &buf[sizeof buf - 5]; 52051379Seric p = addr; 52156764Seric copylev = anglelev = realanglelev = cmtlev = realcmtlev = 0; 52256764Seric qmode = realqmode = FALSE; 52351379Seric 52451379Seric while ((c = *p++) != '\0') 5257783Seric { 52656764Seric /* 52756764Seric ** If the buffer is overful, go into a special "skipping" 52856764Seric ** mode that tries to keep legal syntax but doesn't actually 52956764Seric ** output things. 53056764Seric */ 5317783Seric 53256764Seric skipping = bp >= buflim; 53356735Seric 53456764Seric if (copylev > 0 && !skipping) 53556764Seric *bp++ = c; 53656735Seric 53751379Seric /* check for backslash escapes */ 53851379Seric if (c == '\\') 5397783Seric { 54058890Seric /* arrange to quote the address */ 54158890Seric if (cmtlev <= 0 && !qmode) 54258890Seric quoteit = TRUE; 54358890Seric 54451379Seric if ((c = *p++) == '\0') 5457783Seric { 54651379Seric /* too far */ 54751379Seric p--; 54851379Seric goto putg; 5497783Seric } 55056764Seric if (copylev > 0 && !skipping) 55151379Seric *bp++ = c; 55251379Seric goto putg; 5537783Seric } 5547783Seric 55551379Seric /* check for quoted strings */ 55651379Seric if (c == '"') 5577783Seric { 55851379Seric qmode = !qmode; 55956764Seric if (copylev > 0 && !skipping) 56056764Seric realqmode = !realqmode; 56151379Seric continue; 5627783Seric } 56351379Seric if (qmode) 56451379Seric goto putg; 5657783Seric 56651379Seric /* check for comments */ 56751379Seric if (c == '(') 5687783Seric { 56951379Seric cmtlev++; 57056764Seric 57156764Seric /* allow space for closing paren */ 57256764Seric if (!skipping) 57356764Seric { 57456764Seric buflim--; 57556764Seric realcmtlev++; 57656764Seric if (copylev++ <= 0) 57756764Seric { 57856764Seric *bp++ = ' '; 57956764Seric *bp++ = c; 58056764Seric } 58156764Seric } 58251379Seric } 58351379Seric if (cmtlev > 0) 58451379Seric { 58551379Seric if (c == ')') 5867783Seric { 58751379Seric cmtlev--; 58851379Seric copylev--; 58956764Seric if (!skipping) 59056764Seric { 59156764Seric realcmtlev--; 59256764Seric buflim++; 59356764Seric } 5947783Seric } 5957783Seric continue; 5967783Seric } 59756764Seric else if (c == ')') 59856764Seric { 59956764Seric /* syntax error: unmatched ) */ 60056764Seric if (!skipping) 60156764Seric bp--; 60256764Seric } 6037783Seric 60456764Seric 60556764Seric /* check for characters that may have to be quoted */ 60657175Seric if (strchr(".'@,;:\\()", c) != NULL) 60756764Seric { 60856764Seric /* 60956764Seric ** If these occur as the phrase part of a <> 61056764Seric ** construct, but are not inside of () or already 61156764Seric ** quoted, they will have to be quoted. Note that 61256764Seric ** now (but don't actually do the quoting). 61356764Seric */ 61456764Seric 61556764Seric if (cmtlev <= 0 && !qmode) 61656764Seric quoteit = TRUE; 61756764Seric } 61856764Seric 61951379Seric /* check for angle brackets */ 62051379Seric if (c == '<') 62151379Seric { 62256735Seric register char *q; 62356735Seric 62451379Seric /* oops -- have to change our mind */ 62556764Seric anglelev++; 62656764Seric if (!skipping) 62756764Seric realanglelev++; 62856764Seric 62956735Seric bp = buf; 63056735Seric if (quoteit) 63156735Seric { 63256735Seric *bp++ = '"'; 63356735Seric 63456735Seric /* back up over the '<' and any spaces */ 63556735Seric --p; 63658050Seric while (isascii(*--p) && isspace(*p)) 63756735Seric continue; 63856735Seric p++; 63956735Seric } 64056735Seric for (q = addr; q < p; ) 64156735Seric { 64256735Seric c = *q++; 64356764Seric if (bp < buflim) 64456764Seric { 64556764Seric if (quoteit && c == '"') 64656764Seric *bp++ = '\\'; 64756764Seric *bp++ = c; 64856764Seric } 64956735Seric } 65056735Seric if (quoteit) 65156735Seric { 65256735Seric *bp++ = '"'; 65356764Seric while ((c = *p++) != '<') 65456764Seric { 65556764Seric if (bp < buflim) 65656764Seric *bp++ = c; 65756764Seric } 65856764Seric *bp++ = c; 65956735Seric } 66051379Seric copylev = 0; 66156735Seric putgmac = quoteit = FALSE; 66251379Seric continue; 66351379Seric } 6647783Seric 66551379Seric if (c == '>') 6667783Seric { 66756764Seric if (anglelev > 0) 66856764Seric { 66956764Seric anglelev--; 67056764Seric if (!skipping) 67156764Seric { 67256764Seric realanglelev--; 67356764Seric buflim++; 67456764Seric } 67556764Seric } 67656764Seric else if (!skipping) 67756764Seric { 67856764Seric /* syntax error: unmatched > */ 67956764Seric if (copylev > 0) 68056764Seric bp--; 68156764Seric continue; 68256764Seric } 68351379Seric if (copylev++ <= 0) 68451379Seric *bp++ = c; 68551379Seric continue; 6867783Seric } 68751379Seric 68851379Seric /* must be a real address character */ 68951379Seric putg: 69051379Seric if (copylev <= 0 && !putgmac) 69151379Seric { 69258050Seric *bp++ = MACROEXPAND; 69351379Seric *bp++ = 'g'; 69451379Seric putgmac = TRUE; 69551379Seric } 6967783Seric } 6977783Seric 69856764Seric /* repair any syntactic damage */ 69956764Seric if (realqmode) 70056764Seric *bp++ = '"'; 70156764Seric while (realcmtlev-- > 0) 70256764Seric *bp++ = ')'; 70356764Seric while (realanglelev-- > 0) 70456764Seric *bp++ = '>'; 70551379Seric *bp++ = '\0'; 7067783Seric 7077783Seric if (tTd(33, 1)) 7087944Seric printf("crackaddr=>`%s'\n", buf); 7097783Seric 7107783Seric return (buf); 7117783Seric } 7129382Seric /* 7139382Seric ** PUTHEADER -- put the header part of a message from the in-core copy 7149382Seric ** 7159382Seric ** Parameters: 7169382Seric ** fp -- file to put it on. 7179382Seric ** m -- mailer to use. 7189382Seric ** e -- envelope to use. 7199382Seric ** 7209382Seric ** Returns: 7219382Seric ** none. 7229382Seric ** 7239382Seric ** Side Effects: 7249382Seric ** none. 7259382Seric */ 7269382Seric 72757589Seric /* 72857589Seric * Macro for fast max (not available in e.g. DG/UX, 386/ix). 72957589Seric */ 73057589Seric #ifndef MAX 73157589Seric # define MAX(a,b) (((a)>(b))?(a):(b)) 73257589Seric #endif 73357589Seric 73410176Seric putheader(fp, m, e) 7359382Seric register FILE *fp; 7369382Seric register MAILER *m; 7379382Seric register ENVELOPE *e; 7389382Seric { 73957135Seric char buf[MAX(MAXLINE,BUFSIZ)]; 7409382Seric register HDR *h; 74157135Seric char obuf[MAXLINE]; 7429382Seric 74359882Seric if (tTd(34, 1)) 74459882Seric printf("--- putheader, mailer = %s ---\n", m->m_name); 74559882Seric 7469382Seric for (h = e->e_header; h != NULL; h = h->h_link) 7479382Seric { 7489382Seric register char *p; 74910689Seric extern bool bitintersect(); 7509382Seric 75159882Seric if (tTd(34, 11)) 75259882Seric { 75359882Seric printf(" %s: ", h->h_field); 75459882Seric xputs(h->h_value); 75559882Seric } 75659882Seric 7579382Seric if (bitset(H_CHECK|H_ACHECK, h->h_flags) && 75810689Seric !bitintersect(h->h_mflags, m->m_flags)) 75959882Seric { 76059882Seric if (tTd(34, 11)) 76159882Seric printf(" (skipped)\n"); 7629382Seric continue; 76359882Seric } 7649382Seric 76511414Seric /* handle Resent-... headers specially */ 76611414Seric if (bitset(H_RESENT, h->h_flags) && !bitset(EF_RESENT, e->e_flags)) 76759882Seric { 76859882Seric if (tTd(34, 11)) 76959882Seric printf(" (skipped (resent))\n"); 77011414Seric continue; 77159882Seric } 77259882Seric if (tTd(34, 11)) 77359882Seric printf("\n"); 77411414Seric 7759382Seric p = h->h_value; 7769382Seric if (bitset(H_DEFAULT, h->h_flags)) 7779382Seric { 7789382Seric /* macro expand value if generated internally */ 7799382Seric expand(p, buf, &buf[sizeof buf], e); 7809382Seric p = buf; 7819382Seric if (p == NULL || *p == '\0') 7829382Seric continue; 7839382Seric } 7849382Seric 7859382Seric if (bitset(H_FROM|H_RCPT, h->h_flags)) 7869382Seric { 7879382Seric /* address field */ 7889382Seric bool oldstyle = bitset(EF_OLDSTYLE, e->e_flags); 7899382Seric 7909382Seric if (bitset(H_FROM, h->h_flags)) 7919382Seric oldstyle = FALSE; 79255012Seric commaize(h, p, fp, oldstyle, m, e); 7939382Seric } 7949382Seric else 7959382Seric { 7969382Seric /* vanilla header line */ 79712159Seric register char *nlp; 79812159Seric 79959579Seric (void) sprintf(obuf, "%s: ", h->h_field); 80056795Seric while ((nlp = strchr(p, '\n')) != NULL) 80112159Seric { 80212159Seric *nlp = '\0'; 80312159Seric (void) strcat(obuf, p); 80412159Seric *nlp = '\n'; 80512159Seric putline(obuf, fp, m); 80612159Seric p = ++nlp; 80712161Seric obuf[0] = '\0'; 80812159Seric } 80912159Seric (void) strcat(obuf, p); 81010176Seric putline(obuf, fp, m); 8119382Seric } 8129382Seric } 8139382Seric } 8149382Seric /* 8159382Seric ** COMMAIZE -- output a header field, making a comma-translated list. 8169382Seric ** 8179382Seric ** Parameters: 8189382Seric ** h -- the header field to output. 8199382Seric ** p -- the value to put in it. 8209382Seric ** fp -- file to put it to. 8219382Seric ** oldstyle -- TRUE if this is an old style header. 8229382Seric ** m -- a pointer to the mailer descriptor. If NULL, 8239382Seric ** don't transform the name at all. 82455012Seric ** e -- the envelope containing the message. 8259382Seric ** 8269382Seric ** Returns: 8279382Seric ** none. 8289382Seric ** 8299382Seric ** Side Effects: 8309382Seric ** outputs "p" to file "fp". 8319382Seric */ 8329382Seric 83355012Seric commaize(h, p, fp, oldstyle, m, e) 8349382Seric register HDR *h; 8359382Seric register char *p; 8369382Seric FILE *fp; 8379382Seric bool oldstyle; 8389382Seric register MAILER *m; 83955012Seric register ENVELOPE *e; 8409382Seric { 8419382Seric register char *obp; 8429382Seric int opos; 8439382Seric bool firstone = TRUE; 84411157Seric char obuf[MAXLINE + 3]; 8459382Seric 8469382Seric /* 8479382Seric ** Output the address list translated by the 8489382Seric ** mailer and with commas. 8499382Seric */ 8509382Seric 8519382Seric if (tTd(14, 2)) 8529382Seric printf("commaize(%s: %s)\n", h->h_field, p); 8539382Seric 8549382Seric obp = obuf; 85559579Seric (void) sprintf(obp, "%s: ", h->h_field); 8569382Seric opos = strlen(h->h_field) + 2; 8579382Seric obp += opos; 8589382Seric 8599382Seric /* 8609382Seric ** Run through the list of values. 8619382Seric */ 8629382Seric 8639382Seric while (*p != '\0') 8649382Seric { 8659382Seric register char *name; 86654983Seric register int c; 8679382Seric char savechar; 86859163Seric int flags; 86959163Seric auto int stat; 8709382Seric 8719382Seric /* 8729382Seric ** Find the end of the name. New style names 8739382Seric ** end with a comma, old style names end with 8749382Seric ** a space character. However, spaces do not 8759382Seric ** necessarily delimit an old-style name -- at 8769382Seric ** signs mean keep going. 8779382Seric */ 8789382Seric 8799382Seric /* find end of name */ 88058050Seric while ((isascii(*p) && isspace(*p)) || *p == ',') 8819382Seric p++; 8829382Seric name = p; 8839382Seric for (;;) 8849382Seric { 88558333Seric auto char *oldp; 88616909Seric char pvpbuf[PSBUFSIZE]; 8879382Seric 88858333Seric (void) prescan(p, oldstyle ? ' ' : ',', pvpbuf, &oldp); 88958333Seric p = oldp; 8909382Seric 8919382Seric /* look to see if we have an at sign */ 89258050Seric while (*p != '\0' && isascii(*p) && isspace(*p)) 8939382Seric p++; 8949382Seric 89558170Seric if (*p != '@') 8969382Seric { 8979382Seric p = oldp; 8989382Seric break; 8999382Seric } 9009382Seric p += *p == '@' ? 1 : 2; 90158050Seric while (*p != '\0' && isascii(*p) && isspace(*p)) 9029382Seric p++; 9039382Seric } 9049382Seric /* at the end of one complete name */ 9059382Seric 9069382Seric /* strip off trailing white space */ 90758050Seric while (p >= name && 90858050Seric ((isascii(*p) && isspace(*p)) || *p == ',' || *p == '\0')) 9099382Seric p--; 9109382Seric if (++p == name) 9119382Seric continue; 9129382Seric savechar = *p; 9139382Seric *p = '\0'; 9149382Seric 9159382Seric /* translate the name to be relative */ 91659163Seric flags = RF_HEADERADDR|RF_ADDDOMAIN; 91759163Seric if (bitset(H_FROM, h->h_flags)) 91859163Seric flags |= RF_SENDERADDR; 91959163Seric stat = EX_OK; 92059163Seric name = remotename(name, m, flags, &stat, e); 9219382Seric if (*name == '\0') 9229382Seric { 9239382Seric *p = savechar; 9249382Seric continue; 9259382Seric } 9269382Seric 9279382Seric /* output the name with nice formatting */ 92854983Seric opos += strlen(name); 9299382Seric if (!firstone) 9309382Seric opos += 2; 9319382Seric if (opos > 78 && !firstone) 9329382Seric { 93310178Seric (void) strcpy(obp, ",\n"); 93410176Seric putline(obuf, fp, m); 9359382Seric obp = obuf; 9369382Seric (void) sprintf(obp, " "); 93710161Seric opos = strlen(obp); 93810161Seric obp += opos; 93954983Seric opos += strlen(name); 9409382Seric } 9419382Seric else if (!firstone) 9429382Seric { 9439382Seric (void) sprintf(obp, ", "); 9449382Seric obp += 2; 9459382Seric } 9469382Seric 94754983Seric while ((c = *name++) != '\0' && obp < &obuf[MAXLINE]) 94854983Seric *obp++ = c; 9499382Seric firstone = FALSE; 9509382Seric *p = savechar; 9519382Seric } 9529382Seric (void) strcpy(obp, "\n"); 95310176Seric putline(obuf, fp, m); 9549382Seric } 9559382Seric /* 95658170Seric ** COPYHEADER -- copy header list 9579382Seric ** 95858170Seric ** This routine is the equivalent of newstr for header lists 95958170Seric ** 9609382Seric ** Parameters: 96158170Seric ** header -- list of header structures to copy. 9629382Seric ** 9639382Seric ** Returns: 96458170Seric ** a copy of 'header'. 9659382Seric ** 9669382Seric ** Side Effects: 9679382Seric ** none. 9689382Seric */ 9699382Seric 97058170Seric HDR * 97158170Seric copyheader(header) 97258170Seric register HDR *header; 9739382Seric { 97458170Seric register HDR *newhdr; 97558170Seric HDR *ret; 97658170Seric register HDR **tail = &ret; 9779382Seric 97858170Seric while (header != NULL) 97958170Seric { 98058170Seric newhdr = (HDR *) xalloc(sizeof(HDR)); 98158170Seric STRUCTCOPY(*header, *newhdr); 98258170Seric *tail = newhdr; 98358170Seric tail = &newhdr->h_link; 98458170Seric header = header->h_link; 98558170Seric } 98658170Seric *tail = NULL; 98758170Seric 98858170Seric return ret; 9899382Seric } 990