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*64283Seric static char sccsid[] = "@(#)headers.c 8.10 (Berkeley) 08/17/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; 7364149Seric while (isascii(*p) && isgraph(*p) && *p != ':') 7464149Seric p++; 7564149Seric fvalue = p; 7664149Seric while (isascii(*p) && isspace(*p)) 7764149Seric p++; 7864150Seric if (*p++ != ':' || fname == fvalue) 7910118Seric { 8058151Seric syserr("553 header syntax error, line \"%s\"", line); 8110118Seric return (0); 8210118Seric } 8364149Seric *fvalue = '\0'; 8464149Seric fvalue = p; 854091Seric 864091Seric /* strip field value on front */ 874091Seric if (*fvalue == ' ') 884091Seric fvalue++; 894091Seric 904091Seric /* see if it is a known type */ 914091Seric for (hi = HdrInfo; hi->hi_field != NULL; hi++) 924091Seric { 9359579Seric if (strcasecmp(hi->hi_field, fname) == 0) 944091Seric break; 954091Seric } 964091Seric 97*64283Seric if (tTd(31, 9)) 98*64283Seric { 99*64283Seric if (hi->hi_field == NULL) 100*64283Seric printf("no header match\n"); 101*64283Seric else 102*64283Seric printf("header match, hi_flags=%o\n", hi->hi_flags); 103*64283Seric } 104*64283Seric 10511414Seric /* see if this is a resent message */ 10611930Seric if (!def && bitset(H_RESENT, hi->hi_flags)) 10755012Seric e->e_flags |= EF_RESENT; 10811414Seric 1094091Seric /* if this means "end of header" quit now */ 1104091Seric if (bitset(H_EOH, hi->hi_flags)) 1114091Seric return (hi->hi_flags); 1124091Seric 11311414Seric /* drop explicit From: if same as what we would generate -- for MH */ 11414784Seric p = "resent-from"; 11555012Seric if (!bitset(EF_RESENT, e->e_flags)) 11614784Seric p += 7; 11759579Seric if (!def && !bitset(EF_QUEUERUN, e->e_flags) && strcasecmp(fname, p) == 0) 11811414Seric { 11963753Seric if (tTd(31, 2)) 12063753Seric { 12163753Seric printf("comparing header from (%s) against default (%s or %s)\n", 12263753Seric fvalue, e->e_from.q_paddr, e->e_from.q_user); 12363753Seric } 12455012Seric if (e->e_from.q_paddr != NULL && 12563753Seric (strcmp(fvalue, e->e_from.q_paddr) == 0 || 12663753Seric strcmp(fvalue, e->e_from.q_user) == 0)) 12711414Seric return (hi->hi_flags); 12811414Seric } 12911414Seric 13014784Seric /* delete default value for this header */ 13155012Seric for (hp = &e->e_header; (h = *hp) != NULL; hp = &h->h_link) 13214784Seric { 13359579Seric if (strcasecmp(fname, h->h_field) == 0 && 13414784Seric bitset(H_DEFAULT, h->h_flags) && 13514784Seric !bitset(H_FORCE, h->h_flags)) 13614784Seric h->h_value = NULL; 13714784Seric } 13814784Seric 13913012Seric /* create a new node */ 14013012Seric h = (HDR *) xalloc(sizeof *h); 14113012Seric h->h_field = newstr(fname); 14264134Seric h->h_value = newstr(fvalue); 14313012Seric h->h_link = NULL; 14423117Seric bcopy((char *) mopts, (char *) h->h_mflags, sizeof mopts); 14513012Seric *hp = h; 1468066Seric h->h_flags = hi->hi_flags; 1474091Seric if (def) 1484091Seric h->h_flags |= H_DEFAULT; 1499059Seric if (cond) 1509059Seric h->h_flags |= H_CHECK; 1514091Seric 1525937Seric /* hack to see if this is a new format message */ 1538095Seric if (!def && bitset(H_RCPT|H_FROM, h->h_flags) && 15456795Seric (strchr(fvalue, ',') != NULL || strchr(fvalue, '(') != NULL || 15556795Seric strchr(fvalue, '<') != NULL || strchr(fvalue, ';') != NULL)) 1568089Seric { 15755012Seric e->e_flags &= ~EF_OLDSTYLE; 1588089Seric } 1595937Seric 1604091Seric return (h->h_flags); 1614091Seric } 1624091Seric /* 1636980Seric ** ADDHEADER -- add a header entry to the end of the queue. 1646980Seric ** 1656980Seric ** This bypasses the special checking of chompheader. 1666980Seric ** 1676980Seric ** Parameters: 16859579Seric ** field -- the name of the header field. 16958789Seric ** value -- the value of the field. 1706980Seric ** e -- the envelope to add them to. 1716980Seric ** 1726980Seric ** Returns: 1736980Seric ** none. 1746980Seric ** 1756980Seric ** Side Effects: 1766980Seric ** adds the field on the list of headers for this envelope. 1776980Seric */ 1786980Seric 1796980Seric addheader(field, value, e) 1806980Seric char *field; 1816980Seric char *value; 1826980Seric ENVELOPE *e; 1836980Seric { 1846980Seric register HDR *h; 1856980Seric register struct hdrinfo *hi; 1866980Seric HDR **hp; 1876980Seric 1886980Seric /* find info struct */ 1896980Seric for (hi = HdrInfo; hi->hi_field != NULL; hi++) 1906980Seric { 19159579Seric if (strcasecmp(field, hi->hi_field) == 0) 1926980Seric break; 1936980Seric } 1946980Seric 1956980Seric /* find current place in list -- keep back pointer? */ 1966980Seric for (hp = &e->e_header; (h = *hp) != NULL; hp = &h->h_link) 1976980Seric { 19859579Seric if (strcasecmp(field, h->h_field) == 0) 1996980Seric break; 2006980Seric } 2016980Seric 2026980Seric /* allocate space for new header */ 2036980Seric h = (HDR *) xalloc(sizeof *h); 2046980Seric h->h_field = field; 2056980Seric h->h_value = newstr(value); 2067368Seric h->h_link = *hp; 2076980Seric h->h_flags = hi->hi_flags | H_DEFAULT; 20810689Seric clrbitmap(h->h_mflags); 2096980Seric *hp = h; 2106980Seric } 2116980Seric /* 2124091Seric ** HVALUE -- return value of a header. 2134091Seric ** 2144091Seric ** Only "real" fields (i.e., ones that have not been supplied 2154091Seric ** as a default) are used. 2164091Seric ** 2174091Seric ** Parameters: 2184091Seric ** field -- the field name. 21955012Seric ** e -- the envelope containing the header. 2204091Seric ** 2214091Seric ** Returns: 2224091Seric ** pointer to the value part. 2234091Seric ** NULL if not found. 2244091Seric ** 2254091Seric ** Side Effects: 2269382Seric ** none. 2274091Seric */ 2284091Seric 2294091Seric char * 23055012Seric hvalue(field, e) 2314091Seric char *field; 23255012Seric register ENVELOPE *e; 2334091Seric { 2344091Seric register HDR *h; 2354091Seric 23655012Seric for (h = e->e_header; h != NULL; h = h->h_link) 2374091Seric { 23859579Seric if (!bitset(H_DEFAULT, h->h_flags) && 23959579Seric strcasecmp(h->h_field, field) == 0) 2404091Seric return (h->h_value); 2414091Seric } 2424091Seric return (NULL); 2434091Seric } 2444091Seric /* 2454091Seric ** ISHEADER -- predicate telling if argument is a header. 2464091Seric ** 2474319Seric ** A line is a header if it has a single word followed by 2484319Seric ** optional white space followed by a colon. 2494319Seric ** 2504091Seric ** Parameters: 2514091Seric ** s -- string to check for possible headerness. 2524091Seric ** 2534091Seric ** Returns: 2544091Seric ** TRUE if s is a header. 2554091Seric ** FALSE otherwise. 2564091Seric ** 2574091Seric ** Side Effects: 2584091Seric ** none. 2594091Seric */ 2604091Seric 2614091Seric bool 2624091Seric isheader(s) 2634091Seric register char *s; 2644091Seric { 2659382Seric while (*s > ' ' && *s != ':' && *s != '\0') 2664091Seric s++; 2679382Seric 2689382Seric /* following technically violates RFC822 */ 26958050Seric while (isascii(*s) && isspace(*s)) 2704091Seric s++; 2719382Seric 2724091Seric return (*s == ':'); 2734091Seric } 2745919Seric /* 2757783Seric ** EATHEADER -- run through the stored header and extract info. 2767783Seric ** 2777783Seric ** Parameters: 2789382Seric ** e -- the envelope to process. 27958929Seric ** full -- if set, do full processing (e.g., compute 28058929Seric ** message priority). 2817783Seric ** 2827783Seric ** Returns: 2837783Seric ** none. 2847783Seric ** 2857783Seric ** Side Effects: 2867783Seric ** Sets a bunch of global variables from information 2879382Seric ** in the collected header. 2889382Seric ** Aborts the message if the hop count is exceeded. 2897783Seric */ 2907783Seric 29158929Seric eatheader(e, full) 2929382Seric register ENVELOPE *e; 29358929Seric bool full; 2947783Seric { 2957783Seric register HDR *h; 2967783Seric register char *p; 2979382Seric int hopcnt = 0; 29857208Seric char *msgid; 29958688Seric char buf[MAXLINE]; 3007783Seric 30158688Seric /* 30258688Seric ** Set up macros for possible expansion in headers. 30358688Seric */ 30458688Seric 30558704Seric define('f', e->e_sender, e); 30658704Seric define('g', e->e_sender, e); 30764148Seric if (e->e_origrcpt != NULL && *e->e_origrcpt != '\0') 30864148Seric define('u', e->e_origrcpt, e); 30964148Seric else 31064148Seric define('u', NULL, e); 31158688Seric 3129382Seric if (tTd(32, 1)) 3139382Seric printf("----- collected header -----\n"); 31457208Seric msgid = "<none>"; 3159382Seric for (h = e->e_header; h != NULL; h = h->h_link) 3167783Seric { 31764156Seric if (h->h_value == NULL) 31864156Seric { 31964156Seric if (tTd(32, 1)) 32064156Seric printf("%s: <NULL>\n", h->h_field); 32164156Seric continue; 32264156Seric } 32364156Seric 32458688Seric /* do early binding */ 32564156Seric if (bitset(H_DEFAULT, h->h_flags)) 32658688Seric { 32758688Seric expand(h->h_value, buf, &buf[sizeof buf], e); 32858688Seric if (buf[0] != '\0') 32958688Seric { 33058688Seric h->h_value = newstr(buf); 33158688Seric h->h_flags &= ~H_DEFAULT; 33258688Seric } 33358688Seric } 33458688Seric 3359382Seric if (tTd(32, 1)) 33659579Seric printf("%s: %s\n", h->h_field, h->h_value); 33757359Seric 33811414Seric /* count the number of times it has been processed */ 3399382Seric if (bitset(H_TRACE, h->h_flags)) 3409382Seric hopcnt++; 34111414Seric 34211414Seric /* send to this person if we so desire */ 34311414Seric if (GrabTo && bitset(H_RCPT, h->h_flags) && 34411414Seric !bitset(H_DEFAULT, h->h_flags) && 34555012Seric (!bitset(EF_RESENT, e->e_flags) || bitset(H_RESENT, h->h_flags))) 34611414Seric { 34763839Seric int saveflags = e->e_flags; 34863839Seric 349*64283Seric (void) sendtolist(h->h_value, NULLADDR, 35058082Seric &e->e_sendqueue, e); 35163839Seric 35263839Seric /* delete fatal errors generated by this address */ 35364148Seric if (!GrabTo && !bitset(EF_FATALERRS, saveflags)) 35463839Seric e->e_flags &= ~EF_FATALERRS; 35511414Seric } 35611414Seric 35757208Seric /* save the message-id for logging */ 35864156Seric if (full && strcasecmp(h->h_field, "message-id") == 0) 35911290Seric { 36057208Seric msgid = h->h_value; 36159859Seric while (isascii(*msgid) && isspace(*msgid)) 36259859Seric msgid++; 36311290Seric } 36457359Seric 36557359Seric /* see if this is a return-receipt header */ 36657359Seric if (bitset(H_RECEIPTTO, h->h_flags)) 36757359Seric e->e_receiptto = h->h_value; 36857359Seric 36957359Seric /* see if this is an errors-to header */ 37061104Seric if (UseErrorsTo && bitset(H_ERRORSTO, h->h_flags)) 371*64283Seric (void) sendtolist(h->h_value, NULLADDR, 37258082Seric &e->e_errorqueue, e); 3739382Seric } 3749382Seric if (tTd(32, 1)) 3757783Seric printf("----------------------------\n"); 3767783Seric 37758145Seric /* if we are just verifying (that is, sendmail -t -bv), drop out now */ 37858145Seric if (OpMode == MD_VERIFY) 37958145Seric return; 38058145Seric 3819382Seric /* store hop count */ 3829382Seric if (hopcnt > e->e_hopcount) 3839382Seric e->e_hopcount = hopcnt; 3849382Seric 3857783Seric /* message priority */ 38655012Seric p = hvalue("precedence", e); 3879382Seric if (p != NULL) 3889382Seric e->e_class = priencode(p); 38958929Seric if (full) 39025013Seric e->e_msgpriority = e->e_msgsize 39124981Seric - e->e_class * WkClassFact 39224981Seric + e->e_nrcpts * WkRecipFact; 3937783Seric 3947783Seric /* full name of from person */ 39555012Seric p = hvalue("full-name", e); 3967783Seric if (p != NULL) 3979382Seric define('x', p, e); 3987783Seric 3997783Seric /* date message originated */ 40055012Seric p = hvalue("posted-date", e); 4017783Seric if (p == NULL) 40255012Seric p = hvalue("date", e); 4037783Seric if (p != NULL) 4049382Seric define('a', p, e); 40511290Seric 40611290Seric /* 40711290Seric ** Log collection information. 40811290Seric */ 40911290Seric 41011290Seric # ifdef LOG 41158929Seric if (full && LogLevel > 4) 41211290Seric { 41357359Seric char *name; 41460575Seric register char *sbp; 41557232Seric char hbuf[MAXNAME]; 41657359Seric char sbuf[MAXLINE]; 41736230Skarels 41858667Seric if (bitset(EF_RESPONSE, e->e_flags)) 41958667Seric name = "[RESPONSE]"; 42058951Seric else if ((name = macvalue('_', e)) != NULL) 42158951Seric ; 42258667Seric else if (RealHostName[0] == '[') 42336230Skarels name = RealHostName; 42436230Skarels else 42557359Seric { 42657359Seric name = hbuf; 42758798Seric (void) sprintf(hbuf, "%.80s", RealHostName); 42858798Seric if (RealHostAddr.sa.sa_family != 0) 42958798Seric { 43058798Seric p = &hbuf[strlen(hbuf)]; 43158798Seric (void) sprintf(p, " (%s)", 43258798Seric anynet_ntoa(&RealHostAddr)); 43358798Seric } 43457359Seric } 43557359Seric 43657359Seric /* some versions of syslog only take 5 printf args */ 43760575Seric sbp = sbuf; 43860575Seric sprintf(sbp, "from=%.200s, size=%ld, class=%d, pri=%ld, nrcpts=%d, msgid=%.100s", 43958558Seric e->e_from.q_paddr, e->e_msgsize, e->e_class, 44057589Seric e->e_msgpriority, e->e_nrcpts, msgid); 44160575Seric sbp += strlen(sbp); 44260575Seric if (e->e_bodytype != NULL) 44360575Seric { 44460575Seric (void) sprintf(sbp, ", bodytype=%.20s", e->e_bodytype); 44560575Seric sbp += strlen(sbp); 44660575Seric } 44760575Seric p = macvalue('r', e); 44860575Seric if (p != NULL) 44960575Seric (void) sprintf(sbp, ", proto=%.20s", p); 45058686Seric syslog(LOG_INFO, "%s: %s, relay=%s", 45157359Seric e->e_id, sbuf, name); 45211290Seric } 45356795Seric # endif /* LOG */ 4547783Seric } 4557783Seric /* 4567783Seric ** PRIENCODE -- encode external priority names into internal values. 4577783Seric ** 4587783Seric ** Parameters: 4597783Seric ** p -- priority in ascii. 4607783Seric ** 4617783Seric ** Returns: 4627783Seric ** priority as a numeric level. 4637783Seric ** 4647783Seric ** Side Effects: 4657783Seric ** none. 4667783Seric */ 4677783Seric 4687783Seric priencode(p) 4697783Seric char *p; 4707783Seric { 4718253Seric register int i; 4727783Seric 4738253Seric for (i = 0; i < NumPriorities; i++) 4747783Seric { 47533725Sbostic if (!strcasecmp(p, Priorities[i].pri_name)) 4768253Seric return (Priorities[i].pri_val); 4777783Seric } 4788253Seric 4798253Seric /* unknown priority */ 4808253Seric return (0); 4817783Seric } 4827783Seric /* 4837890Seric ** CRACKADDR -- parse an address and turn it into a macro 4847783Seric ** 4857783Seric ** This doesn't actually parse the address -- it just extracts 4867783Seric ** it and replaces it with "$g". The parse is totally ad hoc 4877783Seric ** and isn't even guaranteed to leave something syntactically 4887783Seric ** identical to what it started with. However, it does leave 4897783Seric ** something semantically identical. 4907783Seric ** 49151379Seric ** This algorithm has been cleaned up to handle a wider range 49251379Seric ** of cases -- notably quoted and backslash escaped strings. 49351379Seric ** This modification makes it substantially better at preserving 49451379Seric ** the original syntax. 4957783Seric ** 4967783Seric ** Parameters: 4977890Seric ** addr -- the address to be cracked. 4987783Seric ** 4997783Seric ** Returns: 5007783Seric ** a pointer to the new version. 5017783Seric ** 5027783Seric ** Side Effects: 5037890Seric ** none. 5047783Seric ** 5057783Seric ** Warning: 5067783Seric ** The return value is saved in local storage and should 5077783Seric ** be copied if it is to be reused. 5087783Seric */ 5097783Seric 5107783Seric char * 5117890Seric crackaddr(addr) 5127890Seric register char *addr; 5137783Seric { 5147783Seric register char *p; 51551379Seric register char c; 51651379Seric int cmtlev; 51756764Seric int realcmtlev; 51856764Seric int anglelev, realanglelev; 51951379Seric int copylev; 52051379Seric bool qmode; 52156764Seric bool realqmode; 52256764Seric bool skipping; 52351379Seric bool putgmac = FALSE; 52456735Seric bool quoteit = FALSE; 52564148Seric bool gotangle = FALSE; 52651379Seric register char *bp; 52756764Seric char *buflim; 5287783Seric static char buf[MAXNAME]; 5297783Seric 5307783Seric if (tTd(33, 1)) 5317890Seric printf("crackaddr(%s)\n", addr); 5327783Seric 5338082Seric /* strip leading spaces */ 53458050Seric while (*addr != '\0' && isascii(*addr) && isspace(*addr)) 5358082Seric addr++; 5368082Seric 5377783Seric /* 53851379Seric ** Start by assuming we have no angle brackets. This will be 53951379Seric ** adjusted later if we find them. 5407783Seric */ 5417783Seric 54251379Seric bp = buf; 54356764Seric buflim = &buf[sizeof buf - 5]; 54451379Seric p = addr; 54556764Seric copylev = anglelev = realanglelev = cmtlev = realcmtlev = 0; 54656764Seric qmode = realqmode = FALSE; 54751379Seric 54851379Seric while ((c = *p++) != '\0') 5497783Seric { 55056764Seric /* 55156764Seric ** If the buffer is overful, go into a special "skipping" 55256764Seric ** mode that tries to keep legal syntax but doesn't actually 55356764Seric ** output things. 55456764Seric */ 5557783Seric 55656764Seric skipping = bp >= buflim; 55756735Seric 55856764Seric if (copylev > 0 && !skipping) 55956764Seric *bp++ = c; 56056735Seric 56151379Seric /* check for backslash escapes */ 56251379Seric if (c == '\\') 5637783Seric { 56458890Seric /* arrange to quote the address */ 56558890Seric if (cmtlev <= 0 && !qmode) 56658890Seric quoteit = TRUE; 56758890Seric 56851379Seric if ((c = *p++) == '\0') 5697783Seric { 57051379Seric /* too far */ 57151379Seric p--; 57251379Seric goto putg; 5737783Seric } 57456764Seric if (copylev > 0 && !skipping) 57551379Seric *bp++ = c; 57651379Seric goto putg; 5777783Seric } 5787783Seric 57951379Seric /* check for quoted strings */ 58051379Seric if (c == '"') 5817783Seric { 58251379Seric qmode = !qmode; 58356764Seric if (copylev > 0 && !skipping) 58456764Seric realqmode = !realqmode; 58551379Seric continue; 5867783Seric } 58751379Seric if (qmode) 58851379Seric goto putg; 5897783Seric 59051379Seric /* check for comments */ 59151379Seric if (c == '(') 5927783Seric { 59351379Seric cmtlev++; 59456764Seric 59556764Seric /* allow space for closing paren */ 59656764Seric if (!skipping) 59756764Seric { 59856764Seric buflim--; 59956764Seric realcmtlev++; 60056764Seric if (copylev++ <= 0) 60156764Seric { 60256764Seric *bp++ = ' '; 60356764Seric *bp++ = c; 60456764Seric } 60556764Seric } 60651379Seric } 60751379Seric if (cmtlev > 0) 60851379Seric { 60951379Seric if (c == ')') 6107783Seric { 61151379Seric cmtlev--; 61251379Seric copylev--; 61356764Seric if (!skipping) 61456764Seric { 61556764Seric realcmtlev--; 61656764Seric buflim++; 61756764Seric } 6187783Seric } 6197783Seric continue; 6207783Seric } 62156764Seric else if (c == ')') 62256764Seric { 62356764Seric /* syntax error: unmatched ) */ 62456764Seric if (!skipping) 62556764Seric bp--; 62656764Seric } 6277783Seric 62856764Seric 62956764Seric /* check for characters that may have to be quoted */ 63064148Seric if (strchr(".'@,;:\\()[]", c) != NULL) 63156764Seric { 63256764Seric /* 63356764Seric ** If these occur as the phrase part of a <> 63456764Seric ** construct, but are not inside of () or already 63556764Seric ** quoted, they will have to be quoted. Note that 63656764Seric ** now (but don't actually do the quoting). 63756764Seric */ 63856764Seric 63956764Seric if (cmtlev <= 0 && !qmode) 64056764Seric quoteit = TRUE; 64156764Seric } 64256764Seric 64351379Seric /* check for angle brackets */ 64451379Seric if (c == '<') 64551379Seric { 64656735Seric register char *q; 64756735Seric 64864148Seric /* assume first of two angles is bogus */ 64964148Seric if (gotangle) 65064148Seric quoteit = TRUE; 65164148Seric gotangle = TRUE; 65264148Seric 65351379Seric /* oops -- have to change our mind */ 65456764Seric anglelev++; 65556764Seric if (!skipping) 65656764Seric realanglelev++; 65756764Seric 65856735Seric bp = buf; 65956735Seric if (quoteit) 66056735Seric { 66156735Seric *bp++ = '"'; 66256735Seric 66356735Seric /* back up over the '<' and any spaces */ 66456735Seric --p; 66558050Seric while (isascii(*--p) && isspace(*p)) 66656735Seric continue; 66756735Seric p++; 66856735Seric } 66956735Seric for (q = addr; q < p; ) 67056735Seric { 67156735Seric c = *q++; 67256764Seric if (bp < buflim) 67356764Seric { 67456764Seric if (quoteit && c == '"') 67556764Seric *bp++ = '\\'; 67656764Seric *bp++ = c; 67756764Seric } 67856735Seric } 67956735Seric if (quoteit) 68056735Seric { 68164148Seric if (bp == &buf[1]) 68264148Seric bp--; 68364148Seric else 68464148Seric *bp++ = '"'; 68556764Seric while ((c = *p++) != '<') 68656764Seric { 68756764Seric if (bp < buflim) 68856764Seric *bp++ = c; 68956764Seric } 69056764Seric *bp++ = c; 69156735Seric } 69251379Seric copylev = 0; 69356735Seric putgmac = quoteit = FALSE; 69451379Seric continue; 69551379Seric } 6967783Seric 69751379Seric if (c == '>') 6987783Seric { 69956764Seric if (anglelev > 0) 70056764Seric { 70156764Seric anglelev--; 70256764Seric if (!skipping) 70356764Seric { 70456764Seric realanglelev--; 70556764Seric buflim++; 70656764Seric } 70756764Seric } 70856764Seric else if (!skipping) 70956764Seric { 71056764Seric /* syntax error: unmatched > */ 71156764Seric if (copylev > 0) 71256764Seric bp--; 71356764Seric continue; 71456764Seric } 71551379Seric if (copylev++ <= 0) 71651379Seric *bp++ = c; 71751379Seric continue; 7187783Seric } 71951379Seric 72051379Seric /* must be a real address character */ 72151379Seric putg: 72251379Seric if (copylev <= 0 && !putgmac) 72351379Seric { 72458050Seric *bp++ = MACROEXPAND; 72551379Seric *bp++ = 'g'; 72651379Seric putgmac = TRUE; 72751379Seric } 7287783Seric } 7297783Seric 73056764Seric /* repair any syntactic damage */ 73156764Seric if (realqmode) 73256764Seric *bp++ = '"'; 73356764Seric while (realcmtlev-- > 0) 73456764Seric *bp++ = ')'; 73556764Seric while (realanglelev-- > 0) 73656764Seric *bp++ = '>'; 73751379Seric *bp++ = '\0'; 7387783Seric 7397783Seric if (tTd(33, 1)) 7407944Seric printf("crackaddr=>`%s'\n", buf); 7417783Seric 7427783Seric return (buf); 7437783Seric } 7449382Seric /* 7459382Seric ** PUTHEADER -- put the header part of a message from the in-core copy 7469382Seric ** 7479382Seric ** Parameters: 7489382Seric ** fp -- file to put it on. 7499382Seric ** m -- mailer to use. 7509382Seric ** e -- envelope to use. 7519382Seric ** 7529382Seric ** Returns: 7539382Seric ** none. 7549382Seric ** 7559382Seric ** Side Effects: 7569382Seric ** none. 7579382Seric */ 7589382Seric 75957589Seric /* 76057589Seric * Macro for fast max (not available in e.g. DG/UX, 386/ix). 76157589Seric */ 76257589Seric #ifndef MAX 76357589Seric # define MAX(a,b) (((a)>(b))?(a):(b)) 76457589Seric #endif 76557589Seric 76610176Seric putheader(fp, m, e) 7679382Seric register FILE *fp; 7689382Seric register MAILER *m; 7699382Seric register ENVELOPE *e; 7709382Seric { 77157135Seric char buf[MAX(MAXLINE,BUFSIZ)]; 7729382Seric register HDR *h; 77357135Seric char obuf[MAXLINE]; 7749382Seric 77559882Seric if (tTd(34, 1)) 77659882Seric printf("--- putheader, mailer = %s ---\n", m->m_name); 77759882Seric 7789382Seric for (h = e->e_header; h != NULL; h = h->h_link) 7799382Seric { 7809382Seric register char *p; 78110689Seric extern bool bitintersect(); 7829382Seric 78359882Seric if (tTd(34, 11)) 78459882Seric { 78559882Seric printf(" %s: ", h->h_field); 78659882Seric xputs(h->h_value); 78759882Seric } 78859882Seric 7899382Seric if (bitset(H_CHECK|H_ACHECK, h->h_flags) && 79010689Seric !bitintersect(h->h_mflags, m->m_flags)) 79159882Seric { 79259882Seric if (tTd(34, 11)) 79359882Seric printf(" (skipped)\n"); 7949382Seric continue; 79559882Seric } 7969382Seric 79711414Seric /* handle Resent-... headers specially */ 79811414Seric if (bitset(H_RESENT, h->h_flags) && !bitset(EF_RESENT, e->e_flags)) 79959882Seric { 80059882Seric if (tTd(34, 11)) 80159882Seric printf(" (skipped (resent))\n"); 80211414Seric continue; 80359882Seric } 80459882Seric if (tTd(34, 11)) 80559882Seric printf("\n"); 80611414Seric 8079382Seric p = h->h_value; 8089382Seric if (bitset(H_DEFAULT, h->h_flags)) 8099382Seric { 8109382Seric /* macro expand value if generated internally */ 8119382Seric expand(p, buf, &buf[sizeof buf], e); 8129382Seric p = buf; 8139382Seric if (p == NULL || *p == '\0') 8149382Seric continue; 8159382Seric } 8169382Seric 8179382Seric if (bitset(H_FROM|H_RCPT, h->h_flags)) 8189382Seric { 8199382Seric /* address field */ 8209382Seric bool oldstyle = bitset(EF_OLDSTYLE, e->e_flags); 8219382Seric 8229382Seric if (bitset(H_FROM, h->h_flags)) 8239382Seric oldstyle = FALSE; 82455012Seric commaize(h, p, fp, oldstyle, m, e); 8259382Seric } 8269382Seric else 8279382Seric { 8289382Seric /* vanilla header line */ 82912159Seric register char *nlp; 83012159Seric 83159579Seric (void) sprintf(obuf, "%s: ", h->h_field); 83256795Seric while ((nlp = strchr(p, '\n')) != NULL) 83312159Seric { 83412159Seric *nlp = '\0'; 83512159Seric (void) strcat(obuf, p); 83612159Seric *nlp = '\n'; 83712159Seric putline(obuf, fp, m); 83812159Seric p = ++nlp; 83912161Seric obuf[0] = '\0'; 84012159Seric } 84112159Seric (void) strcat(obuf, p); 84210176Seric putline(obuf, fp, m); 8439382Seric } 8449382Seric } 8459382Seric } 8469382Seric /* 8479382Seric ** COMMAIZE -- output a header field, making a comma-translated list. 8489382Seric ** 8499382Seric ** Parameters: 8509382Seric ** h -- the header field to output. 8519382Seric ** p -- the value to put in it. 8529382Seric ** fp -- file to put it to. 8539382Seric ** oldstyle -- TRUE if this is an old style header. 8549382Seric ** m -- a pointer to the mailer descriptor. If NULL, 8559382Seric ** don't transform the name at all. 85655012Seric ** e -- the envelope containing the message. 8579382Seric ** 8589382Seric ** Returns: 8599382Seric ** none. 8609382Seric ** 8619382Seric ** Side Effects: 8629382Seric ** outputs "p" to file "fp". 8639382Seric */ 8649382Seric 86555012Seric commaize(h, p, fp, oldstyle, m, e) 8669382Seric register HDR *h; 8679382Seric register char *p; 8689382Seric FILE *fp; 8699382Seric bool oldstyle; 8709382Seric register MAILER *m; 87155012Seric register ENVELOPE *e; 8729382Seric { 8739382Seric register char *obp; 8749382Seric int opos; 8759382Seric bool firstone = TRUE; 87611157Seric char obuf[MAXLINE + 3]; 8779382Seric 8789382Seric /* 8799382Seric ** Output the address list translated by the 8809382Seric ** mailer and with commas. 8819382Seric */ 8829382Seric 8839382Seric if (tTd(14, 2)) 8849382Seric printf("commaize(%s: %s)\n", h->h_field, p); 8859382Seric 8869382Seric obp = obuf; 88759579Seric (void) sprintf(obp, "%s: ", h->h_field); 8889382Seric opos = strlen(h->h_field) + 2; 8899382Seric obp += opos; 8909382Seric 8919382Seric /* 8929382Seric ** Run through the list of values. 8939382Seric */ 8949382Seric 8959382Seric while (*p != '\0') 8969382Seric { 8979382Seric register char *name; 89854983Seric register int c; 8999382Seric char savechar; 90059163Seric int flags; 90159163Seric auto int stat; 9029382Seric 9039382Seric /* 9049382Seric ** Find the end of the name. New style names 9059382Seric ** end with a comma, old style names end with 9069382Seric ** a space character. However, spaces do not 9079382Seric ** necessarily delimit an old-style name -- at 9089382Seric ** signs mean keep going. 9099382Seric */ 9109382Seric 9119382Seric /* find end of name */ 91258050Seric while ((isascii(*p) && isspace(*p)) || *p == ',') 9139382Seric p++; 9149382Seric name = p; 9159382Seric for (;;) 9169382Seric { 91758333Seric auto char *oldp; 91816909Seric char pvpbuf[PSBUFSIZE]; 9199382Seric 92058333Seric (void) prescan(p, oldstyle ? ' ' : ',', pvpbuf, &oldp); 92158333Seric p = oldp; 9229382Seric 9239382Seric /* look to see if we have an at sign */ 92458050Seric while (*p != '\0' && isascii(*p) && isspace(*p)) 9259382Seric p++; 9269382Seric 92758170Seric if (*p != '@') 9289382Seric { 9299382Seric p = oldp; 9309382Seric break; 9319382Seric } 9329382Seric p += *p == '@' ? 1 : 2; 93358050Seric while (*p != '\0' && isascii(*p) && isspace(*p)) 9349382Seric p++; 9359382Seric } 9369382Seric /* at the end of one complete name */ 9379382Seric 9389382Seric /* strip off trailing white space */ 93958050Seric while (p >= name && 94058050Seric ((isascii(*p) && isspace(*p)) || *p == ',' || *p == '\0')) 9419382Seric p--; 9429382Seric if (++p == name) 9439382Seric continue; 9449382Seric savechar = *p; 9459382Seric *p = '\0'; 9469382Seric 9479382Seric /* translate the name to be relative */ 94859163Seric flags = RF_HEADERADDR|RF_ADDDOMAIN; 94959163Seric if (bitset(H_FROM, h->h_flags)) 95059163Seric flags |= RF_SENDERADDR; 95159163Seric stat = EX_OK; 95259163Seric name = remotename(name, m, flags, &stat, e); 9539382Seric if (*name == '\0') 9549382Seric { 9559382Seric *p = savechar; 9569382Seric continue; 9579382Seric } 9589382Seric 9599382Seric /* output the name with nice formatting */ 96054983Seric opos += strlen(name); 9619382Seric if (!firstone) 9629382Seric opos += 2; 9639382Seric if (opos > 78 && !firstone) 9649382Seric { 96510178Seric (void) strcpy(obp, ",\n"); 96610176Seric putline(obuf, fp, m); 9679382Seric obp = obuf; 9689382Seric (void) sprintf(obp, " "); 96910161Seric opos = strlen(obp); 97010161Seric obp += opos; 97154983Seric opos += strlen(name); 9729382Seric } 9739382Seric else if (!firstone) 9749382Seric { 9759382Seric (void) sprintf(obp, ", "); 9769382Seric obp += 2; 9779382Seric } 9789382Seric 97954983Seric while ((c = *name++) != '\0' && obp < &obuf[MAXLINE]) 98054983Seric *obp++ = c; 9819382Seric firstone = FALSE; 9829382Seric *p = savechar; 9839382Seric } 9849382Seric (void) strcpy(obp, "\n"); 98510176Seric putline(obuf, fp, m); 9869382Seric } 9879382Seric /* 98858170Seric ** COPYHEADER -- copy header list 9899382Seric ** 99058170Seric ** This routine is the equivalent of newstr for header lists 99158170Seric ** 9929382Seric ** Parameters: 99358170Seric ** header -- list of header structures to copy. 9949382Seric ** 9959382Seric ** Returns: 99658170Seric ** a copy of 'header'. 9979382Seric ** 9989382Seric ** Side Effects: 9999382Seric ** none. 10009382Seric */ 10019382Seric 100258170Seric HDR * 100358170Seric copyheader(header) 100458170Seric register HDR *header; 10059382Seric { 100658170Seric register HDR *newhdr; 100758170Seric HDR *ret; 100858170Seric register HDR **tail = &ret; 10099382Seric 101058170Seric while (header != NULL) 101158170Seric { 101258170Seric newhdr = (HDR *) xalloc(sizeof(HDR)); 101358170Seric STRUCTCOPY(*header, *newhdr); 101458170Seric *tail = newhdr; 101558170Seric tail = &newhdr->h_link; 101658170Seric header = header->h_link; 101758170Seric } 101858170Seric *tail = NULL; 101958170Seric 102058170Seric return ret; 10219382Seric } 1022