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*66003Seric static char sccsid[] = "@(#)headers.c 8.25 (Berkeley) 02/05/94"; 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; 4764351Seric char buf[MAXNAME]; 484091Seric 497677Seric if (tTd(31, 6)) 507677Seric printf("chompheader: %s\n", line); 517677Seric 524627Seric /* strip off options */ 5310689Seric clrbitmap(mopts); 544627Seric p = line; 5557405Seric if (*p == '?') 564627Seric { 574627Seric /* have some */ 5856795Seric register char *q = strchr(p + 1, *p); 594627Seric 604627Seric if (q != NULL) 614627Seric { 624627Seric *q++ = '\0'; 6310689Seric while (*++p != '\0') 6410689Seric setbitn(*p, mopts); 654627Seric p = q; 664627Seric } 674627Seric else 6858151Seric usrerr("553 header syntax error, line \"%s\"", line); 699059Seric cond = TRUE; 704627Seric } 714627Seric 724091Seric /* find canonical name */ 734627Seric fname = p; 7464149Seric while (isascii(*p) && isgraph(*p) && *p != ':') 7564149Seric p++; 7664149Seric fvalue = p; 7764149Seric while (isascii(*p) && isspace(*p)) 7864149Seric p++; 7964150Seric if (*p++ != ':' || fname == fvalue) 8010118Seric { 8158151Seric syserr("553 header syntax error, line \"%s\"", line); 8210118Seric return (0); 8310118Seric } 8464149Seric *fvalue = '\0'; 8564149Seric fvalue = p; 864091Seric 874091Seric /* strip field value on front */ 884091Seric if (*fvalue == ' ') 894091Seric fvalue++; 904091Seric 914091Seric /* see if it is a known type */ 924091Seric for (hi = HdrInfo; hi->hi_field != NULL; hi++) 934091Seric { 9459579Seric if (strcasecmp(hi->hi_field, fname) == 0) 954091Seric break; 964091Seric } 974091Seric 9864283Seric if (tTd(31, 9)) 9964283Seric { 10064283Seric if (hi->hi_field == NULL) 10164283Seric printf("no header match\n"); 10264283Seric else 10364283Seric printf("header match, hi_flags=%o\n", hi->hi_flags); 10464283Seric } 10564283Seric 10611414Seric /* see if this is a resent message */ 10711930Seric if (!def && bitset(H_RESENT, hi->hi_flags)) 10855012Seric e->e_flags |= EF_RESENT; 10911414Seric 1104091Seric /* if this means "end of header" quit now */ 1114091Seric if (bitset(H_EOH, hi->hi_flags)) 1124091Seric return (hi->hi_flags); 1134091Seric 11464653Seric /* 11564653Seric ** Drop explicit From: if same as what we would generate. 11664653Seric ** This is to make MH (which doesn't always give a full name) 11764653Seric ** insert the full name information in all circumstances. 11864653Seric */ 11964653Seric 12014784Seric p = "resent-from"; 12155012Seric if (!bitset(EF_RESENT, e->e_flags)) 12214784Seric p += 7; 12359579Seric if (!def && !bitset(EF_QUEUERUN, e->e_flags) && strcasecmp(fname, p) == 0) 12411414Seric { 12563753Seric if (tTd(31, 2)) 12663753Seric { 12763753Seric printf("comparing header from (%s) against default (%s or %s)\n", 12863753Seric fvalue, e->e_from.q_paddr, e->e_from.q_user); 12963753Seric } 13055012Seric if (e->e_from.q_paddr != NULL && 13163753Seric (strcmp(fvalue, e->e_from.q_paddr) == 0 || 13263753Seric strcmp(fvalue, e->e_from.q_user) == 0)) 13311414Seric return (hi->hi_flags); 13464351Seric #ifdef MAYBENEXTRELEASE /* XXX UNTESTED XXX UNTESTED XXX UNTESTED XXX */ 13564351Seric #ifdef USERDB 13664351Seric else 13764351Seric { 13864351Seric auto ADDRESS a; 13964351Seric char *fancy; 14064351Seric extern char *crackaddr(); 14164351Seric extern char *udbsender(); 14264351Seric 14364653Seric /* 14464653Seric ** Try doing USERDB rewriting even on fully commented 14564653Seric ** names; this saves the "comment" information (such 14664653Seric ** as full name) and rewrites the electronic part. 14764653Seric */ 14864653Seric 14964351Seric fancy = crackaddr(fvalue); 15064351Seric if (parseaddr(fvalue, &a, RF_COPYNONE, '\0', NULL, e) != NULL && 15164351Seric a.q_mailer == LocalMailer && 15264351Seric (p = udbsender(a.q_user)) != NULL) 15364351Seric { 15464351Seric char *oldg = macvalue('g', e); 15564351Seric 15664351Seric define('g', p, e); 15764351Seric expand(fancy, buf, &buf[sizeof buf], e); 15864351Seric define('g', oldg, e); 15964351Seric fvalue = buf; 16064351Seric } 16164351Seric } 16264351Seric #endif 16364351Seric #endif 16411414Seric } 16511414Seric 16614784Seric /* delete default value for this header */ 16755012Seric for (hp = &e->e_header; (h = *hp) != NULL; hp = &h->h_link) 16814784Seric { 16959579Seric if (strcasecmp(fname, h->h_field) == 0 && 17014784Seric bitset(H_DEFAULT, h->h_flags) && 17114784Seric !bitset(H_FORCE, h->h_flags)) 17214784Seric h->h_value = NULL; 17314784Seric } 17414784Seric 17513012Seric /* create a new node */ 17613012Seric h = (HDR *) xalloc(sizeof *h); 17713012Seric h->h_field = newstr(fname); 17864134Seric h->h_value = newstr(fvalue); 17913012Seric h->h_link = NULL; 18023117Seric bcopy((char *) mopts, (char *) h->h_mflags, sizeof mopts); 18113012Seric *hp = h; 1828066Seric h->h_flags = hi->hi_flags; 1834091Seric if (def) 1844091Seric h->h_flags |= H_DEFAULT; 1859059Seric if (cond) 1869059Seric h->h_flags |= H_CHECK; 1874091Seric 1885937Seric /* hack to see if this is a new format message */ 1898095Seric if (!def && bitset(H_RCPT|H_FROM, h->h_flags) && 19056795Seric (strchr(fvalue, ',') != NULL || strchr(fvalue, '(') != NULL || 19156795Seric strchr(fvalue, '<') != NULL || strchr(fvalue, ';') != NULL)) 1928089Seric { 19355012Seric e->e_flags &= ~EF_OLDSTYLE; 1948089Seric } 1955937Seric 1964091Seric return (h->h_flags); 1974091Seric } 1984091Seric /* 1996980Seric ** ADDHEADER -- add a header entry to the end of the queue. 2006980Seric ** 2016980Seric ** This bypasses the special checking of chompheader. 2026980Seric ** 2036980Seric ** Parameters: 20459579Seric ** field -- the name of the header field. 20558789Seric ** value -- the value of the field. 2066980Seric ** e -- the envelope to add them to. 2076980Seric ** 2086980Seric ** Returns: 2096980Seric ** none. 2106980Seric ** 2116980Seric ** Side Effects: 2126980Seric ** adds the field on the list of headers for this envelope. 2136980Seric */ 2146980Seric 2156980Seric addheader(field, value, e) 2166980Seric char *field; 2176980Seric char *value; 2186980Seric ENVELOPE *e; 2196980Seric { 2206980Seric register HDR *h; 2216980Seric register struct hdrinfo *hi; 2226980Seric HDR **hp; 2236980Seric 2246980Seric /* find info struct */ 2256980Seric for (hi = HdrInfo; hi->hi_field != NULL; hi++) 2266980Seric { 22759579Seric if (strcasecmp(field, hi->hi_field) == 0) 2286980Seric break; 2296980Seric } 2306980Seric 2316980Seric /* find current place in list -- keep back pointer? */ 2326980Seric for (hp = &e->e_header; (h = *hp) != NULL; hp = &h->h_link) 2336980Seric { 23459579Seric if (strcasecmp(field, h->h_field) == 0) 2356980Seric break; 2366980Seric } 2376980Seric 2386980Seric /* allocate space for new header */ 2396980Seric h = (HDR *) xalloc(sizeof *h); 2406980Seric h->h_field = field; 2416980Seric h->h_value = newstr(value); 2427368Seric h->h_link = *hp; 2436980Seric h->h_flags = hi->hi_flags | H_DEFAULT; 24410689Seric clrbitmap(h->h_mflags); 2456980Seric *hp = h; 2466980Seric } 2476980Seric /* 2484091Seric ** HVALUE -- return value of a header. 2494091Seric ** 2504091Seric ** Only "real" fields (i.e., ones that have not been supplied 2514091Seric ** as a default) are used. 2524091Seric ** 2534091Seric ** Parameters: 2544091Seric ** field -- the field name. 25555012Seric ** e -- the envelope containing the header. 2564091Seric ** 2574091Seric ** Returns: 2584091Seric ** pointer to the value part. 2594091Seric ** NULL if not found. 2604091Seric ** 2614091Seric ** Side Effects: 2629382Seric ** none. 2634091Seric */ 2644091Seric 2654091Seric char * 26655012Seric hvalue(field, e) 2674091Seric char *field; 26855012Seric register ENVELOPE *e; 2694091Seric { 2704091Seric register HDR *h; 2714091Seric 27255012Seric for (h = e->e_header; h != NULL; h = h->h_link) 2734091Seric { 27459579Seric if (!bitset(H_DEFAULT, h->h_flags) && 27559579Seric strcasecmp(h->h_field, field) == 0) 2764091Seric return (h->h_value); 2774091Seric } 2784091Seric return (NULL); 2794091Seric } 2804091Seric /* 2814091Seric ** ISHEADER -- predicate telling if argument is a header. 2824091Seric ** 2834319Seric ** A line is a header if it has a single word followed by 2844319Seric ** optional white space followed by a colon. 2854319Seric ** 2864091Seric ** Parameters: 2874091Seric ** s -- string to check for possible headerness. 2884091Seric ** 2894091Seric ** Returns: 2904091Seric ** TRUE if s is a header. 2914091Seric ** FALSE otherwise. 2924091Seric ** 2934091Seric ** Side Effects: 2944091Seric ** none. 2954091Seric */ 2964091Seric 2974091Seric bool 2984091Seric isheader(s) 2994091Seric register char *s; 3004091Seric { 3019382Seric while (*s > ' ' && *s != ':' && *s != '\0') 3024091Seric s++; 3039382Seric 3049382Seric /* following technically violates RFC822 */ 30558050Seric while (isascii(*s) && isspace(*s)) 3064091Seric s++; 3079382Seric 3084091Seric return (*s == ':'); 3094091Seric } 3105919Seric /* 3117783Seric ** EATHEADER -- run through the stored header and extract info. 3127783Seric ** 3137783Seric ** Parameters: 3149382Seric ** e -- the envelope to process. 31558929Seric ** full -- if set, do full processing (e.g., compute 31658929Seric ** message priority). 3177783Seric ** 3187783Seric ** Returns: 3197783Seric ** none. 3207783Seric ** 3217783Seric ** Side Effects: 3227783Seric ** Sets a bunch of global variables from information 3239382Seric ** in the collected header. 3249382Seric ** Aborts the message if the hop count is exceeded. 3257783Seric */ 3267783Seric 32758929Seric eatheader(e, full) 3289382Seric register ENVELOPE *e; 32958929Seric bool full; 3307783Seric { 3317783Seric register HDR *h; 3327783Seric register char *p; 3339382Seric int hopcnt = 0; 33457208Seric char *msgid; 33558688Seric char buf[MAXLINE]; 3367783Seric 33758688Seric /* 33858688Seric ** Set up macros for possible expansion in headers. 33958688Seric */ 34058688Seric 34158704Seric define('f', e->e_sender, e); 34258704Seric define('g', e->e_sender, e); 34364148Seric if (e->e_origrcpt != NULL && *e->e_origrcpt != '\0') 34464148Seric define('u', e->e_origrcpt, e); 34564148Seric else 34664148Seric define('u', NULL, e); 34758688Seric 34865052Seric /* full name of from person */ 34965052Seric p = hvalue("full-name", e); 35065052Seric if (p != NULL) 35165052Seric define('x', p, e); 35265052Seric 3539382Seric if (tTd(32, 1)) 3549382Seric printf("----- collected header -----\n"); 35557208Seric msgid = "<none>"; 3569382Seric for (h = e->e_header; h != NULL; h = h->h_link) 3577783Seric { 35864156Seric if (h->h_value == NULL) 35964156Seric { 36064156Seric if (tTd(32, 1)) 36164156Seric printf("%s: <NULL>\n", h->h_field); 36264156Seric continue; 36364156Seric } 36464156Seric 36558688Seric /* do early binding */ 36664156Seric if (bitset(H_DEFAULT, h->h_flags)) 36758688Seric { 36858688Seric expand(h->h_value, buf, &buf[sizeof buf], e); 36958688Seric if (buf[0] != '\0') 37058688Seric { 37158688Seric h->h_value = newstr(buf); 37258688Seric h->h_flags &= ~H_DEFAULT; 37358688Seric } 37458688Seric } 37558688Seric 3769382Seric if (tTd(32, 1)) 37765152Seric { 37865152Seric printf("%s: ", h->h_field); 37965152Seric xputs(h->h_value); 38065152Seric printf("\n"); 38165152Seric } 38257359Seric 38311414Seric /* count the number of times it has been processed */ 3849382Seric if (bitset(H_TRACE, h->h_flags)) 3859382Seric hopcnt++; 38611414Seric 38711414Seric /* send to this person if we so desire */ 38811414Seric if (GrabTo && bitset(H_RCPT, h->h_flags) && 38911414Seric !bitset(H_DEFAULT, h->h_flags) && 39055012Seric (!bitset(EF_RESENT, e->e_flags) || bitset(H_RESENT, h->h_flags))) 39111414Seric { 39263839Seric int saveflags = e->e_flags; 39363839Seric 39464283Seric (void) sendtolist(h->h_value, NULLADDR, 39558082Seric &e->e_sendqueue, e); 39663839Seric 39763839Seric /* delete fatal errors generated by this address */ 39864148Seric if (!GrabTo && !bitset(EF_FATALERRS, saveflags)) 39963839Seric e->e_flags &= ~EF_FATALERRS; 40011414Seric } 40111414Seric 40257208Seric /* save the message-id for logging */ 40364156Seric if (full && strcasecmp(h->h_field, "message-id") == 0) 40411290Seric { 40557208Seric msgid = h->h_value; 40659859Seric while (isascii(*msgid) && isspace(*msgid)) 40759859Seric msgid++; 40811290Seric } 40957359Seric 41057359Seric /* see if this is a return-receipt header */ 41157359Seric if (bitset(H_RECEIPTTO, h->h_flags)) 41257359Seric e->e_receiptto = h->h_value; 41357359Seric 41457359Seric /* see if this is an errors-to header */ 41561104Seric if (UseErrorsTo && bitset(H_ERRORSTO, h->h_flags)) 41664283Seric (void) sendtolist(h->h_value, NULLADDR, 41758082Seric &e->e_errorqueue, e); 4189382Seric } 4199382Seric if (tTd(32, 1)) 4207783Seric printf("----------------------------\n"); 4217783Seric 42258145Seric /* if we are just verifying (that is, sendmail -t -bv), drop out now */ 42358145Seric if (OpMode == MD_VERIFY) 42458145Seric return; 42558145Seric 4269382Seric /* store hop count */ 4279382Seric if (hopcnt > e->e_hopcount) 4289382Seric e->e_hopcount = hopcnt; 4299382Seric 4307783Seric /* message priority */ 43155012Seric p = hvalue("precedence", e); 4329382Seric if (p != NULL) 4339382Seric e->e_class = priencode(p); 43458929Seric if (full) 43525013Seric e->e_msgpriority = e->e_msgsize 43624981Seric - e->e_class * WkClassFact 43724981Seric + e->e_nrcpts * WkRecipFact; 4387783Seric 4397783Seric /* date message originated */ 44055012Seric p = hvalue("posted-date", e); 4417783Seric if (p == NULL) 44255012Seric p = hvalue("date", e); 4437783Seric if (p != NULL) 4449382Seric define('a', p, e); 44511290Seric 44611290Seric /* 44765983Seric ** From person in antiquated ARPANET mode 44865983Seric ** required by UK Grey Book e-mail gateways (sigh) 44965983Seric */ 45065983Seric 45165983Seric if (OpMode == MD_ARPAFTP) 45265983Seric { 45365983Seric register struct hdrinfo *hi; 45465983Seric 45565983Seric for (hi = HdrInfo; hi->hi_field != NULL; hi++) 45665983Seric { 45765983Seric if (bitset(H_FROM, hi->hi_flags) && 45865983Seric (!bitset(H_RESENT, hi->hi_flags) || 45965983Seric bitset(EF_RESENT, e->e_flags)) && 46065983Seric (p = hvalue(hi->hi_field, e)) != NULL) 46165983Seric break; 46265983Seric } 46365983Seric if (hi->hi_field != NULL) 46465983Seric { 46565983Seric if (tTd(32, 2)) 46665983Seric printf("eatheader: setsender(*%s == %s)\n", 46765983Seric hi->hi_field, p); 46865983Seric setsender(p, e, NULL, TRUE); 46965983Seric } 47065983Seric } 47165983Seric 47265983Seric /* 47311290Seric ** Log collection information. 47411290Seric */ 47511290Seric 47611290Seric # ifdef LOG 47758929Seric if (full && LogLevel > 4) 47865089Seric logsender(e, msgid); 47965089Seric # endif /* LOG */ 48065089Seric e->e_flags &= ~EF_LOGSENDER; 48165089Seric } 48265089Seric /* 48365089Seric ** LOGSENDER -- log sender information 48465089Seric ** 48565089Seric ** Parameters: 48665089Seric ** e -- the envelope to log 48765089Seric ** msgid -- the message id 48865089Seric ** 48965089Seric ** Returns: 49065089Seric ** none 49165089Seric */ 49265089Seric 49365089Seric logsender(e, msgid) 49465089Seric register ENVELOPE *e; 49565089Seric char *msgid; 49665089Seric { 49765089Seric char *name; 49865089Seric register char *sbp; 49965089Seric register char *p; 50065089Seric char hbuf[MAXNAME]; 50165089Seric char sbuf[MAXLINE]; 50265089Seric 50365089Seric if (bitset(EF_RESPONSE, e->e_flags)) 50465089Seric name = "[RESPONSE]"; 50565089Seric else if ((name = macvalue('_', e)) != NULL) 50665089Seric ; 507*66003Seric else if (RealHostName == NULL) 508*66003Seric name = "localhost"; 50965089Seric else if (RealHostName[0] == '[') 51065089Seric name = RealHostName; 51165089Seric else 51211290Seric { 51365089Seric name = hbuf; 51465089Seric (void) sprintf(hbuf, "%.80s", RealHostName); 51565089Seric if (RealHostAddr.sa.sa_family != 0) 51657359Seric { 51765089Seric p = &hbuf[strlen(hbuf)]; 51865089Seric (void) sprintf(p, " (%s)", 51965089Seric anynet_ntoa(&RealHostAddr)); 52057359Seric } 52165089Seric } 52257359Seric 52365089Seric /* some versions of syslog only take 5 printf args */ 52465059Seric # if (SYSLOG_BUFSIZE) >= 256 52565089Seric sbp = sbuf; 52665089Seric sprintf(sbp, "from=%.200s, size=%ld, class=%d, pri=%ld, nrcpts=%d", 52765089Seric e->e_from.q_paddr, e->e_msgsize, e->e_class, 52865089Seric e->e_msgpriority, e->e_nrcpts); 52965089Seric sbp += strlen(sbp); 53065089Seric if (msgid != NULL) 53165089Seric { 53265089Seric sprintf(sbp, ", msgid=%.100s", msgid); 53360575Seric sbp += strlen(sbp); 53465089Seric } 53565089Seric if (e->e_bodytype != NULL) 53665089Seric { 53765089Seric (void) sprintf(sbp, ", bodytype=%.20s", e->e_bodytype); 53865089Seric sbp += strlen(sbp); 53965089Seric } 54065089Seric p = macvalue('r', e); 54165089Seric if (p != NULL) 54265089Seric (void) sprintf(sbp, ", proto=%.20s", p); 54365089Seric syslog(LOG_INFO, "%s: %s, relay=%s", 54465089Seric e->e_id, sbuf, name); 54565059Seric 54665059Seric # else /* short syslog buffer */ 54765059Seric 54865089Seric syslog(LOG_INFO, "%s: from=%s", 54965089Seric e->e_id, shortenstring(e->e_from.q_paddr, 83)); 55065089Seric syslog(LOG_INFO, "%s: size=%ld, class=%ld, pri=%ld, nrcpts=%d", 55165089Seric e->e_id, e->e_msgsize, e->e_class, 55265089Seric e->e_msgpriority, e->e_nrcpts); 55365089Seric if (msgid != NULL) 55465059Seric syslog(LOG_INFO, "%s: msgid=%s", e->e_id, msgid); 55565650Seric sbp = sbuf; 55665650Seric sprintf(sbp, "%s:", e->e_id); 55765650Seric sbp += strlen(sbp); 55865089Seric if (e->e_bodytype != NULL) 55965650Seric { 56065650Seric sprintf(sbp, " bodytype=%s,", e->e_bodytype); 56165650Seric sbp += strlen(sbp); 56265650Seric } 56365089Seric p = macvalue('r', e); 56465089Seric if (p != NULL) 56565650Seric { 56665731Seric sprintf(sbp, " proto=%s,", p); 56765650Seric sbp += strlen(sbp); 56865650Seric } 56965650Seric syslog(LOG_INFO, "%s relay=%s", sbuf, name); 57065059Seric # endif 5717783Seric } 5727783Seric /* 5737783Seric ** PRIENCODE -- encode external priority names into internal values. 5747783Seric ** 5757783Seric ** Parameters: 5767783Seric ** p -- priority in ascii. 5777783Seric ** 5787783Seric ** Returns: 5797783Seric ** priority as a numeric level. 5807783Seric ** 5817783Seric ** Side Effects: 5827783Seric ** none. 5837783Seric */ 5847783Seric 5857783Seric priencode(p) 5867783Seric char *p; 5877783Seric { 5888253Seric register int i; 5897783Seric 5908253Seric for (i = 0; i < NumPriorities; i++) 5917783Seric { 59233725Sbostic if (!strcasecmp(p, Priorities[i].pri_name)) 5938253Seric return (Priorities[i].pri_val); 5947783Seric } 5958253Seric 5968253Seric /* unknown priority */ 5978253Seric return (0); 5987783Seric } 5997783Seric /* 6007890Seric ** CRACKADDR -- parse an address and turn it into a macro 6017783Seric ** 6027783Seric ** This doesn't actually parse the address -- it just extracts 6037783Seric ** it and replaces it with "$g". The parse is totally ad hoc 6047783Seric ** and isn't even guaranteed to leave something syntactically 6057783Seric ** identical to what it started with. However, it does leave 6067783Seric ** something semantically identical. 6077783Seric ** 60851379Seric ** This algorithm has been cleaned up to handle a wider range 60951379Seric ** of cases -- notably quoted and backslash escaped strings. 61051379Seric ** This modification makes it substantially better at preserving 61151379Seric ** the original syntax. 6127783Seric ** 6137783Seric ** Parameters: 6147890Seric ** addr -- the address to be cracked. 6157783Seric ** 6167783Seric ** Returns: 6177783Seric ** a pointer to the new version. 6187783Seric ** 6197783Seric ** Side Effects: 6207890Seric ** none. 6217783Seric ** 6227783Seric ** Warning: 6237783Seric ** The return value is saved in local storage and should 6247783Seric ** be copied if it is to be reused. 6257783Seric */ 6267783Seric 6277783Seric char * 6287890Seric crackaddr(addr) 6297890Seric register char *addr; 6307783Seric { 6317783Seric register char *p; 63251379Seric register char c; 63351379Seric int cmtlev; 63456764Seric int realcmtlev; 63556764Seric int anglelev, realanglelev; 63651379Seric int copylev; 63751379Seric bool qmode; 63856764Seric bool realqmode; 63956764Seric bool skipping; 64051379Seric bool putgmac = FALSE; 64156735Seric bool quoteit = FALSE; 64264148Seric bool gotangle = FALSE; 64351379Seric register char *bp; 64456764Seric char *buflim; 6457783Seric static char buf[MAXNAME]; 6467783Seric 6477783Seric if (tTd(33, 1)) 6487890Seric printf("crackaddr(%s)\n", addr); 6497783Seric 6508082Seric /* strip leading spaces */ 65158050Seric while (*addr != '\0' && isascii(*addr) && isspace(*addr)) 6528082Seric addr++; 6538082Seric 6547783Seric /* 65551379Seric ** Start by assuming we have no angle brackets. This will be 65651379Seric ** adjusted later if we find them. 6577783Seric */ 6587783Seric 65951379Seric bp = buf; 66056764Seric buflim = &buf[sizeof buf - 5]; 66151379Seric p = addr; 66256764Seric copylev = anglelev = realanglelev = cmtlev = realcmtlev = 0; 66356764Seric qmode = realqmode = FALSE; 66451379Seric 66551379Seric while ((c = *p++) != '\0') 6667783Seric { 66756764Seric /* 66856764Seric ** If the buffer is overful, go into a special "skipping" 66956764Seric ** mode that tries to keep legal syntax but doesn't actually 67056764Seric ** output things. 67156764Seric */ 6727783Seric 67356764Seric skipping = bp >= buflim; 67456735Seric 67556764Seric if (copylev > 0 && !skipping) 67656764Seric *bp++ = c; 67756735Seric 67851379Seric /* check for backslash escapes */ 67951379Seric if (c == '\\') 6807783Seric { 68158890Seric /* arrange to quote the address */ 68258890Seric if (cmtlev <= 0 && !qmode) 68358890Seric quoteit = TRUE; 68458890Seric 68551379Seric if ((c = *p++) == '\0') 6867783Seric { 68751379Seric /* too far */ 68851379Seric p--; 68951379Seric goto putg; 6907783Seric } 69156764Seric if (copylev > 0 && !skipping) 69251379Seric *bp++ = c; 69351379Seric goto putg; 6947783Seric } 6957783Seric 69651379Seric /* check for quoted strings */ 69764967Seric if (c == '"' && cmtlev <= 0) 6987783Seric { 69951379Seric qmode = !qmode; 70056764Seric if (copylev > 0 && !skipping) 70156764Seric realqmode = !realqmode; 70251379Seric continue; 7037783Seric } 70451379Seric if (qmode) 70551379Seric goto putg; 7067783Seric 70751379Seric /* check for comments */ 70851379Seric if (c == '(') 7097783Seric { 71051379Seric cmtlev++; 71156764Seric 71256764Seric /* allow space for closing paren */ 71356764Seric if (!skipping) 71456764Seric { 71556764Seric buflim--; 71656764Seric realcmtlev++; 71756764Seric if (copylev++ <= 0) 71856764Seric { 71956764Seric *bp++ = ' '; 72056764Seric *bp++ = c; 72156764Seric } 72256764Seric } 72351379Seric } 72451379Seric if (cmtlev > 0) 72551379Seric { 72651379Seric if (c == ')') 7277783Seric { 72851379Seric cmtlev--; 72951379Seric copylev--; 73056764Seric if (!skipping) 73156764Seric { 73256764Seric realcmtlev--; 73356764Seric buflim++; 73456764Seric } 7357783Seric } 7367783Seric continue; 7377783Seric } 73856764Seric else if (c == ')') 73956764Seric { 74056764Seric /* syntax error: unmatched ) */ 74165544Seric if (copylev > 0 && !skipping) 74256764Seric bp--; 74356764Seric } 7447783Seric 74556764Seric /* check for characters that may have to be quoted */ 74664148Seric if (strchr(".'@,;:\\()[]", c) != NULL) 74756764Seric { 74856764Seric /* 74956764Seric ** If these occur as the phrase part of a <> 75056764Seric ** construct, but are not inside of () or already 75156764Seric ** quoted, they will have to be quoted. Note that 75256764Seric ** now (but don't actually do the quoting). 75356764Seric */ 75456764Seric 75556764Seric if (cmtlev <= 0 && !qmode) 75656764Seric quoteit = TRUE; 75756764Seric } 75856764Seric 75951379Seric /* check for angle brackets */ 76051379Seric if (c == '<') 76151379Seric { 76256735Seric register char *q; 76356735Seric 76464148Seric /* assume first of two angles is bogus */ 76564148Seric if (gotangle) 76664148Seric quoteit = TRUE; 76764148Seric gotangle = TRUE; 76864148Seric 76951379Seric /* oops -- have to change our mind */ 77064752Seric anglelev = 1; 77156764Seric if (!skipping) 77264752Seric realanglelev = 1; 77356764Seric 77456735Seric bp = buf; 77556735Seric if (quoteit) 77656735Seric { 77756735Seric *bp++ = '"'; 77856735Seric 77956735Seric /* back up over the '<' and any spaces */ 78056735Seric --p; 78158050Seric while (isascii(*--p) && isspace(*p)) 78256735Seric continue; 78356735Seric p++; 78456735Seric } 78556735Seric for (q = addr; q < p; ) 78656735Seric { 78756735Seric c = *q++; 78856764Seric if (bp < buflim) 78956764Seric { 79056764Seric if (quoteit && c == '"') 79156764Seric *bp++ = '\\'; 79256764Seric *bp++ = c; 79356764Seric } 79456735Seric } 79556735Seric if (quoteit) 79656735Seric { 79764148Seric if (bp == &buf[1]) 79864148Seric bp--; 79964148Seric else 80064148Seric *bp++ = '"'; 80156764Seric while ((c = *p++) != '<') 80256764Seric { 80356764Seric if (bp < buflim) 80456764Seric *bp++ = c; 80556764Seric } 80656764Seric *bp++ = c; 80756735Seric } 80851379Seric copylev = 0; 80956735Seric putgmac = quoteit = FALSE; 81051379Seric continue; 81151379Seric } 8127783Seric 81351379Seric if (c == '>') 8147783Seric { 81556764Seric if (anglelev > 0) 81656764Seric { 81756764Seric anglelev--; 81856764Seric if (!skipping) 81956764Seric { 82056764Seric realanglelev--; 82156764Seric buflim++; 82256764Seric } 82356764Seric } 82456764Seric else if (!skipping) 82556764Seric { 82656764Seric /* syntax error: unmatched > */ 82756764Seric if (copylev > 0) 82856764Seric bp--; 82964752Seric quoteit = TRUE; 83056764Seric continue; 83156764Seric } 83251379Seric if (copylev++ <= 0) 83351379Seric *bp++ = c; 83451379Seric continue; 8357783Seric } 83651379Seric 83751379Seric /* must be a real address character */ 83851379Seric putg: 83951379Seric if (copylev <= 0 && !putgmac) 84051379Seric { 84158050Seric *bp++ = MACROEXPAND; 84251379Seric *bp++ = 'g'; 84351379Seric putgmac = TRUE; 84451379Seric } 8457783Seric } 8467783Seric 84756764Seric /* repair any syntactic damage */ 84856764Seric if (realqmode) 84956764Seric *bp++ = '"'; 85056764Seric while (realcmtlev-- > 0) 85156764Seric *bp++ = ')'; 85256764Seric while (realanglelev-- > 0) 85356764Seric *bp++ = '>'; 85451379Seric *bp++ = '\0'; 8557783Seric 8567783Seric if (tTd(33, 1)) 8577944Seric printf("crackaddr=>`%s'\n", buf); 8587783Seric 8597783Seric return (buf); 8607783Seric } 8619382Seric /* 8629382Seric ** PUTHEADER -- put the header part of a message from the in-core copy 8639382Seric ** 8649382Seric ** Parameters: 86565870Seric ** mci -- the connection information. 8669382Seric ** e -- envelope to use. 8679382Seric ** 8689382Seric ** Returns: 8699382Seric ** none. 8709382Seric ** 8719382Seric ** Side Effects: 8729382Seric ** none. 8739382Seric */ 8749382Seric 87557589Seric /* 87657589Seric * Macro for fast max (not available in e.g. DG/UX, 386/ix). 87757589Seric */ 87857589Seric #ifndef MAX 87957589Seric # define MAX(a,b) (((a)>(b))?(a):(b)) 88057589Seric #endif 88157589Seric 88265870Seric putheader(mci, e) 88365870Seric register MCI *mci; 8849382Seric register ENVELOPE *e; 8859382Seric { 88657135Seric char buf[MAX(MAXLINE,BUFSIZ)]; 8879382Seric register HDR *h; 88857135Seric char obuf[MAXLINE]; 8899382Seric 89059882Seric if (tTd(34, 1)) 89165870Seric printf("--- putheader, mailer = %s ---\n", 89265870Seric mci->mci_mailer->m_name); 89359882Seric 8949382Seric for (h = e->e_header; h != NULL; h = h->h_link) 8959382Seric { 8969382Seric register char *p; 89710689Seric extern bool bitintersect(); 8989382Seric 89959882Seric if (tTd(34, 11)) 90059882Seric { 90159882Seric printf(" %s: ", h->h_field); 90259882Seric xputs(h->h_value); 90359882Seric } 90459882Seric 9059382Seric if (bitset(H_CHECK|H_ACHECK, h->h_flags) && 90665870Seric !bitintersect(h->h_mflags, mci->mci_mailer->m_flags)) 90759882Seric { 90859882Seric if (tTd(34, 11)) 90959882Seric printf(" (skipped)\n"); 9109382Seric continue; 91159882Seric } 9129382Seric 91311414Seric /* handle Resent-... headers specially */ 91411414Seric if (bitset(H_RESENT, h->h_flags) && !bitset(EF_RESENT, e->e_flags)) 91559882Seric { 91659882Seric if (tTd(34, 11)) 91759882Seric printf(" (skipped (resent))\n"); 91811414Seric continue; 91959882Seric } 92011414Seric 92165152Seric /* macro expand value if generated internally */ 9229382Seric p = h->h_value; 9239382Seric if (bitset(H_DEFAULT, h->h_flags)) 9249382Seric { 9259382Seric expand(p, buf, &buf[sizeof buf], e); 9269382Seric p = buf; 9279382Seric if (p == NULL || *p == '\0') 92865152Seric { 92965152Seric if (tTd(34, 11)) 93065152Seric printf(" (skipped -- null value)\n"); 9319382Seric continue; 93265152Seric } 9339382Seric } 9349382Seric 93565152Seric if (tTd(34, 11)) 93665152Seric printf("\n"); 93765152Seric 9389382Seric if (bitset(H_FROM|H_RCPT, h->h_flags)) 9399382Seric { 9409382Seric /* address field */ 9419382Seric bool oldstyle = bitset(EF_OLDSTYLE, e->e_flags); 9429382Seric 9439382Seric if (bitset(H_FROM, h->h_flags)) 9449382Seric oldstyle = FALSE; 94565870Seric commaize(h, p, oldstyle, mci, e); 9469382Seric } 9479382Seric else 9489382Seric { 9499382Seric /* vanilla header line */ 95012159Seric register char *nlp; 95112159Seric 95259579Seric (void) sprintf(obuf, "%s: ", h->h_field); 95356795Seric while ((nlp = strchr(p, '\n')) != NULL) 95412159Seric { 95512159Seric *nlp = '\0'; 95612159Seric (void) strcat(obuf, p); 95712159Seric *nlp = '\n'; 95865870Seric putline(obuf, mci); 95912159Seric p = ++nlp; 96012161Seric obuf[0] = '\0'; 96112159Seric } 96212159Seric (void) strcat(obuf, p); 96365870Seric putline(obuf, mci); 9649382Seric } 9659382Seric } 9669382Seric } 9679382Seric /* 9689382Seric ** COMMAIZE -- output a header field, making a comma-translated list. 9699382Seric ** 9709382Seric ** Parameters: 9719382Seric ** h -- the header field to output. 9729382Seric ** p -- the value to put in it. 9739382Seric ** oldstyle -- TRUE if this is an old style header. 97465870Seric ** mci -- the connection information. 97555012Seric ** e -- the envelope containing the message. 9769382Seric ** 9779382Seric ** Returns: 9789382Seric ** none. 9799382Seric ** 9809382Seric ** Side Effects: 9819382Seric ** outputs "p" to file "fp". 9829382Seric */ 9839382Seric 98465870Seric void 98565870Seric commaize(h, p, oldstyle, mci, e) 9869382Seric register HDR *h; 9879382Seric register char *p; 9889382Seric bool oldstyle; 98965870Seric register MCI *mci; 99055012Seric register ENVELOPE *e; 9919382Seric { 9929382Seric register char *obp; 9939382Seric int opos; 9949382Seric bool firstone = TRUE; 99511157Seric char obuf[MAXLINE + 3]; 9969382Seric 9979382Seric /* 9989382Seric ** Output the address list translated by the 9999382Seric ** mailer and with commas. 10009382Seric */ 10019382Seric 10029382Seric if (tTd(14, 2)) 10039382Seric printf("commaize(%s: %s)\n", h->h_field, p); 10049382Seric 10059382Seric obp = obuf; 100659579Seric (void) sprintf(obp, "%s: ", h->h_field); 10079382Seric opos = strlen(h->h_field) + 2; 10089382Seric obp += opos; 10099382Seric 10109382Seric /* 10119382Seric ** Run through the list of values. 10129382Seric */ 10139382Seric 10149382Seric while (*p != '\0') 10159382Seric { 10169382Seric register char *name; 101754983Seric register int c; 10189382Seric char savechar; 101959163Seric int flags; 102059163Seric auto int stat; 10219382Seric 10229382Seric /* 10239382Seric ** Find the end of the name. New style names 10249382Seric ** end with a comma, old style names end with 10259382Seric ** a space character. However, spaces do not 10269382Seric ** necessarily delimit an old-style name -- at 10279382Seric ** signs mean keep going. 10289382Seric */ 10299382Seric 10309382Seric /* find end of name */ 103158050Seric while ((isascii(*p) && isspace(*p)) || *p == ',') 10329382Seric p++; 10339382Seric name = p; 10349382Seric for (;;) 10359382Seric { 103658333Seric auto char *oldp; 103716909Seric char pvpbuf[PSBUFSIZE]; 10389382Seric 103965066Seric (void) prescan(p, oldstyle ? ' ' : ',', pvpbuf, 104065066Seric sizeof pvpbuf, &oldp); 104158333Seric p = oldp; 10429382Seric 10439382Seric /* look to see if we have an at sign */ 104458050Seric while (*p != '\0' && isascii(*p) && isspace(*p)) 10459382Seric p++; 10469382Seric 104758170Seric if (*p != '@') 10489382Seric { 10499382Seric p = oldp; 10509382Seric break; 10519382Seric } 10529382Seric p += *p == '@' ? 1 : 2; 105358050Seric while (*p != '\0' && isascii(*p) && isspace(*p)) 10549382Seric p++; 10559382Seric } 10569382Seric /* at the end of one complete name */ 10579382Seric 10589382Seric /* strip off trailing white space */ 105958050Seric while (p >= name && 106058050Seric ((isascii(*p) && isspace(*p)) || *p == ',' || *p == '\0')) 10619382Seric p--; 10629382Seric if (++p == name) 10639382Seric continue; 10649382Seric savechar = *p; 10659382Seric *p = '\0'; 10669382Seric 10679382Seric /* translate the name to be relative */ 106859163Seric flags = RF_HEADERADDR|RF_ADDDOMAIN; 106959163Seric if (bitset(H_FROM, h->h_flags)) 107059163Seric flags |= RF_SENDERADDR; 107159163Seric stat = EX_OK; 107265870Seric name = remotename(name, mci->mci_mailer, flags, &stat, e); 10739382Seric if (*name == '\0') 10749382Seric { 10759382Seric *p = savechar; 10769382Seric continue; 10779382Seric } 10789382Seric 10799382Seric /* output the name with nice formatting */ 108054983Seric opos += strlen(name); 10819382Seric if (!firstone) 10829382Seric opos += 2; 10839382Seric if (opos > 78 && !firstone) 10849382Seric { 108510178Seric (void) strcpy(obp, ",\n"); 108665870Seric putline(obuf, mci); 10879382Seric obp = obuf; 10889382Seric (void) sprintf(obp, " "); 108910161Seric opos = strlen(obp); 109010161Seric obp += opos; 109154983Seric opos += strlen(name); 10929382Seric } 10939382Seric else if (!firstone) 10949382Seric { 10959382Seric (void) sprintf(obp, ", "); 10969382Seric obp += 2; 10979382Seric } 10989382Seric 109954983Seric while ((c = *name++) != '\0' && obp < &obuf[MAXLINE]) 110054983Seric *obp++ = c; 11019382Seric firstone = FALSE; 11029382Seric *p = savechar; 11039382Seric } 11049382Seric (void) strcpy(obp, "\n"); 110565870Seric putline(obuf, mci); 11069382Seric } 11079382Seric /* 110858170Seric ** COPYHEADER -- copy header list 11099382Seric ** 111058170Seric ** This routine is the equivalent of newstr for header lists 111158170Seric ** 11129382Seric ** Parameters: 111358170Seric ** header -- list of header structures to copy. 11149382Seric ** 11159382Seric ** Returns: 111658170Seric ** a copy of 'header'. 11179382Seric ** 11189382Seric ** Side Effects: 11199382Seric ** none. 11209382Seric */ 11219382Seric 112258170Seric HDR * 112358170Seric copyheader(header) 112458170Seric register HDR *header; 11259382Seric { 112658170Seric register HDR *newhdr; 112758170Seric HDR *ret; 112858170Seric register HDR **tail = &ret; 11299382Seric 113058170Seric while (header != NULL) 113158170Seric { 113258170Seric newhdr = (HDR *) xalloc(sizeof(HDR)); 113358170Seric STRUCTCOPY(*header, *newhdr); 113458170Seric *tail = newhdr; 113558170Seric tail = &newhdr->h_link; 113658170Seric header = header->h_link; 113758170Seric } 113858170Seric *tail = NULL; 113958170Seric 114058170Seric return ret; 11419382Seric } 1142