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*68690Seric static char sccsid[] = "@(#)headers.c 8.52 (Berkeley) 03/30/95"; 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; 4768528Seric char buf[MAXNAME + 1]; 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 68*68690Seric syserr("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 10367694Seric printf("header match, hi_flags=%x\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 11068558Seric /* if this is an Errors-To: header keep track of it now */ 11168558Seric if (UseErrorsTo && !def && bitset(H_ERRORSTO, hi->hi_flags)) 11268558Seric (void) sendtolist(fvalue, NULLADDR, &e->e_errorqueue, 0, e); 11368558Seric 1144091Seric /* if this means "end of header" quit now */ 1154091Seric if (bitset(H_EOH, hi->hi_flags)) 1164091Seric return (hi->hi_flags); 1174091Seric 11864653Seric /* 11964653Seric ** Drop explicit From: if same as what we would generate. 12064653Seric ** This is to make MH (which doesn't always give a full name) 12164653Seric ** insert the full name information in all circumstances. 12264653Seric */ 12364653Seric 12414784Seric p = "resent-from"; 12555012Seric if (!bitset(EF_RESENT, e->e_flags)) 12614784Seric p += 7; 12759579Seric if (!def && !bitset(EF_QUEUERUN, e->e_flags) && strcasecmp(fname, p) == 0) 12811414Seric { 12963753Seric if (tTd(31, 2)) 13063753Seric { 13163753Seric printf("comparing header from (%s) against default (%s or %s)\n", 13263753Seric fvalue, e->e_from.q_paddr, e->e_from.q_user); 13363753Seric } 13455012Seric if (e->e_from.q_paddr != NULL && 13563753Seric (strcmp(fvalue, e->e_from.q_paddr) == 0 || 13663753Seric strcmp(fvalue, e->e_from.q_user) == 0)) 13711414Seric return (hi->hi_flags); 13864351Seric #ifdef MAYBENEXTRELEASE /* XXX UNTESTED XXX UNTESTED XXX UNTESTED XXX */ 13964351Seric #ifdef USERDB 14064351Seric else 14164351Seric { 14264351Seric auto ADDRESS a; 14364351Seric char *fancy; 14466123Seric bool oldSuprErrs = SuprErrs; 14564351Seric extern char *crackaddr(); 14664351Seric extern char *udbsender(); 14764351Seric 14864653Seric /* 14964653Seric ** Try doing USERDB rewriting even on fully commented 15064653Seric ** names; this saves the "comment" information (such 15164653Seric ** as full name) and rewrites the electronic part. 15266106Seric ** 15366106Seric ** XXX This code doesn't belong here -- parsing should 15466106Seric ** XXX not be done during collect() phase because 15566106Seric ** XXX error messages can confuse the SMTP phase. 15666123Seric ** XXX Setting SuprErrs is a crude hack around this 15766106Seric ** XXX problem. 15864653Seric */ 15964653Seric 16066106Seric if (OpMode == MD_SMTP || OpMode == MD_ARPAFTP) 16166123Seric SuprErrs = TRUE; 16264351Seric fancy = crackaddr(fvalue); 16364351Seric if (parseaddr(fvalue, &a, RF_COPYNONE, '\0', NULL, e) != NULL && 16467472Seric bitnset(M_CHECKUDB, a.q_mailer->m_flags) && 16564351Seric (p = udbsender(a.q_user)) != NULL) 16664351Seric { 16764351Seric char *oldg = macvalue('g', e); 16864351Seric 16964351Seric define('g', p, e); 17068529Seric expand(fancy, buf, sizeof buf, e); 17164351Seric define('g', oldg, e); 17264351Seric fvalue = buf; 17364351Seric } 17466123Seric SuprErrs = oldSuprErrs; 17564351Seric } 17664351Seric #endif 17764351Seric #endif 17811414Seric } 17911414Seric 18014784Seric /* delete default value for this header */ 18155012Seric for (hp = &e->e_header; (h = *hp) != NULL; hp = &h->h_link) 18214784Seric { 18359579Seric if (strcasecmp(fname, h->h_field) == 0 && 18414784Seric bitset(H_DEFAULT, h->h_flags) && 18514784Seric !bitset(H_FORCE, h->h_flags)) 18614784Seric h->h_value = NULL; 18714784Seric } 18814784Seric 18913012Seric /* create a new node */ 19013012Seric h = (HDR *) xalloc(sizeof *h); 19113012Seric h->h_field = newstr(fname); 19264134Seric h->h_value = newstr(fvalue); 19313012Seric h->h_link = NULL; 19423117Seric bcopy((char *) mopts, (char *) h->h_mflags, sizeof mopts); 19513012Seric *hp = h; 1968066Seric h->h_flags = hi->hi_flags; 1974091Seric if (def) 1984091Seric h->h_flags |= H_DEFAULT; 1999059Seric if (cond) 2009059Seric h->h_flags |= H_CHECK; 2014091Seric 2025937Seric /* hack to see if this is a new format message */ 2038095Seric if (!def && bitset(H_RCPT|H_FROM, h->h_flags) && 20456795Seric (strchr(fvalue, ',') != NULL || strchr(fvalue, '(') != NULL || 20556795Seric strchr(fvalue, '<') != NULL || strchr(fvalue, ';') != NULL)) 2068089Seric { 20755012Seric e->e_flags &= ~EF_OLDSTYLE; 2088089Seric } 2095937Seric 2104091Seric return (h->h_flags); 2114091Seric } 2124091Seric /* 2136980Seric ** ADDHEADER -- add a header entry to the end of the queue. 2146980Seric ** 2156980Seric ** This bypasses the special checking of chompheader. 2166980Seric ** 2176980Seric ** Parameters: 21859579Seric ** field -- the name of the header field. 21958789Seric ** value -- the value of the field. 22067546Seric ** hp -- an indirect pointer to the header structure list. 2216980Seric ** 2226980Seric ** Returns: 2236980Seric ** none. 2246980Seric ** 2256980Seric ** Side Effects: 2266980Seric ** adds the field on the list of headers for this envelope. 2276980Seric */ 2286980Seric 22967546Seric addheader(field, value, hdrlist) 2306980Seric char *field; 2316980Seric char *value; 23267546Seric HDR **hdrlist; 2336980Seric { 2346980Seric register HDR *h; 2356980Seric register struct hdrinfo *hi; 2366980Seric HDR **hp; 2376980Seric 2386980Seric /* find info struct */ 2396980Seric for (hi = HdrInfo; hi->hi_field != NULL; hi++) 2406980Seric { 24159579Seric if (strcasecmp(field, hi->hi_field) == 0) 2426980Seric break; 2436980Seric } 2446980Seric 2456980Seric /* find current place in list -- keep back pointer? */ 24667546Seric for (hp = hdrlist; (h = *hp) != NULL; hp = &h->h_link) 2476980Seric { 24859579Seric if (strcasecmp(field, h->h_field) == 0) 2496980Seric break; 2506980Seric } 2516980Seric 2526980Seric /* allocate space for new header */ 2536980Seric h = (HDR *) xalloc(sizeof *h); 2546980Seric h->h_field = field; 2556980Seric h->h_value = newstr(value); 2567368Seric h->h_link = *hp; 2576980Seric h->h_flags = hi->hi_flags | H_DEFAULT; 25810689Seric clrbitmap(h->h_mflags); 2596980Seric *hp = h; 2606980Seric } 2616980Seric /* 2624091Seric ** HVALUE -- return value of a header. 2634091Seric ** 2644091Seric ** Only "real" fields (i.e., ones that have not been supplied 2654091Seric ** as a default) are used. 2664091Seric ** 2674091Seric ** Parameters: 2684091Seric ** field -- the field name. 26967546Seric ** header -- the header list. 2704091Seric ** 2714091Seric ** Returns: 2724091Seric ** pointer to the value part. 2734091Seric ** NULL if not found. 2744091Seric ** 2754091Seric ** Side Effects: 2769382Seric ** none. 2774091Seric */ 2784091Seric 2794091Seric char * 28067546Seric hvalue(field, header) 2814091Seric char *field; 28267546Seric HDR *header; 2834091Seric { 2844091Seric register HDR *h; 2854091Seric 28667546Seric for (h = header; h != NULL; h = h->h_link) 2874091Seric { 28859579Seric if (!bitset(H_DEFAULT, h->h_flags) && 28959579Seric strcasecmp(h->h_field, field) == 0) 2904091Seric return (h->h_value); 2914091Seric } 2924091Seric return (NULL); 2934091Seric } 2944091Seric /* 2954091Seric ** ISHEADER -- predicate telling if argument is a header. 2964091Seric ** 2974319Seric ** A line is a header if it has a single word followed by 2984319Seric ** optional white space followed by a colon. 2994319Seric ** 3004091Seric ** Parameters: 301*68690Seric ** h -- string to check for possible headerness. 3024091Seric ** 3034091Seric ** Returns: 304*68690Seric ** TRUE if h is a header. 3054091Seric ** FALSE otherwise. 3064091Seric ** 3074091Seric ** Side Effects: 3084091Seric ** none. 3094091Seric */ 3104091Seric 3114091Seric bool 312*68690Seric isheader(h) 313*68690Seric char *h; 3144091Seric { 315*68690Seric register char *s = h; 316*68690Seric 3179382Seric while (*s > ' ' && *s != ':' && *s != '\0') 3184091Seric s++; 3199382Seric 320*68690Seric if (h == s) 321*68690Seric return FALSE; 322*68690Seric 3239382Seric /* following technically violates RFC822 */ 32458050Seric while (isascii(*s) && isspace(*s)) 3254091Seric s++; 3269382Seric 3274091Seric return (*s == ':'); 3284091Seric } 3295919Seric /* 3307783Seric ** EATHEADER -- run through the stored header and extract info. 3317783Seric ** 3327783Seric ** Parameters: 3339382Seric ** e -- the envelope to process. 33458929Seric ** full -- if set, do full processing (e.g., compute 33558929Seric ** message priority). 3367783Seric ** 3377783Seric ** Returns: 3387783Seric ** none. 3397783Seric ** 3407783Seric ** Side Effects: 3417783Seric ** Sets a bunch of global variables from information 3429382Seric ** in the collected header. 3439382Seric ** Aborts the message if the hop count is exceeded. 3447783Seric */ 3457783Seric 34658929Seric eatheader(e, full) 3479382Seric register ENVELOPE *e; 34858929Seric bool full; 3497783Seric { 3507783Seric register HDR *h; 3517783Seric register char *p; 3529382Seric int hopcnt = 0; 35357208Seric char *msgid; 35458688Seric char buf[MAXLINE]; 3557783Seric 35658688Seric /* 35758688Seric ** Set up macros for possible expansion in headers. 35858688Seric */ 35958688Seric 36058704Seric define('f', e->e_sender, e); 36158704Seric define('g', e->e_sender, e); 36264148Seric if (e->e_origrcpt != NULL && *e->e_origrcpt != '\0') 36364148Seric define('u', e->e_origrcpt, e); 36464148Seric else 36564148Seric define('u', NULL, e); 36658688Seric 36765052Seric /* full name of from person */ 36867546Seric p = hvalue("full-name", e->e_header); 36965052Seric if (p != NULL) 37065052Seric define('x', p, e); 37165052Seric 3729382Seric if (tTd(32, 1)) 3739382Seric printf("----- collected header -----\n"); 37457208Seric msgid = "<none>"; 3759382Seric for (h = e->e_header; h != NULL; h = h->h_link) 3767783Seric { 37764156Seric if (h->h_value == NULL) 37864156Seric { 37964156Seric if (tTd(32, 1)) 38064156Seric printf("%s: <NULL>\n", h->h_field); 38164156Seric continue; 38264156Seric } 38364156Seric 38458688Seric /* do early binding */ 38564156Seric if (bitset(H_DEFAULT, h->h_flags)) 38658688Seric { 38768529Seric expand(h->h_value, buf, sizeof buf, e); 38858688Seric if (buf[0] != '\0') 38958688Seric { 39058688Seric h->h_value = newstr(buf); 39158688Seric h->h_flags &= ~H_DEFAULT; 39258688Seric } 39358688Seric } 39458688Seric 3959382Seric if (tTd(32, 1)) 39665152Seric { 39765152Seric printf("%s: ", h->h_field); 39865152Seric xputs(h->h_value); 39965152Seric printf("\n"); 40065152Seric } 40157359Seric 40211414Seric /* count the number of times it has been processed */ 4039382Seric if (bitset(H_TRACE, h->h_flags)) 4049382Seric hopcnt++; 40511414Seric 40611414Seric /* send to this person if we so desire */ 40711414Seric if (GrabTo && bitset(H_RCPT, h->h_flags) && 40811414Seric !bitset(H_DEFAULT, h->h_flags) && 40955012Seric (!bitset(EF_RESENT, e->e_flags) || bitset(H_RESENT, h->h_flags))) 41011414Seric { 41163839Seric int saveflags = e->e_flags; 41263839Seric 41364283Seric (void) sendtolist(h->h_value, NULLADDR, 41467982Seric &e->e_sendqueue, 0, e); 41563839Seric 41663839Seric /* delete fatal errors generated by this address */ 41764148Seric if (!GrabTo && !bitset(EF_FATALERRS, saveflags)) 41863839Seric e->e_flags &= ~EF_FATALERRS; 41911414Seric } 42011414Seric 42157208Seric /* save the message-id for logging */ 42264156Seric if (full && strcasecmp(h->h_field, "message-id") == 0) 42311290Seric { 42457208Seric msgid = h->h_value; 42559859Seric while (isascii(*msgid) && isspace(*msgid)) 42659859Seric msgid++; 42711290Seric } 42857359Seric 42957359Seric /* see if this is a return-receipt header */ 43057359Seric if (bitset(H_RECEIPTTO, h->h_flags)) 43157359Seric e->e_receiptto = h->h_value; 4329382Seric } 4339382Seric if (tTd(32, 1)) 4347783Seric printf("----------------------------\n"); 4357783Seric 43658145Seric /* if we are just verifying (that is, sendmail -t -bv), drop out now */ 43758145Seric if (OpMode == MD_VERIFY) 43858145Seric return; 43958145Seric 4409382Seric /* store hop count */ 4419382Seric if (hopcnt > e->e_hopcount) 4429382Seric e->e_hopcount = hopcnt; 4439382Seric 4447783Seric /* message priority */ 44567546Seric p = hvalue("precedence", e->e_header); 4469382Seric if (p != NULL) 4479382Seric e->e_class = priencode(p); 44858929Seric if (full) 44967730Seric { 45025013Seric e->e_msgpriority = e->e_msgsize 45124981Seric - e->e_class * WkClassFact 45224981Seric + e->e_nrcpts * WkRecipFact; 45367730Seric if (e->e_class < 0) 45467730Seric e->e_timeoutclass = TOC_NONURGENT; 45567730Seric else if (e->e_class > 0) 45667730Seric e->e_timeoutclass = TOC_URGENT; 45767730Seric } 4587783Seric 45967730Seric /* message timeout priority */ 46067730Seric p = hvalue("priority", e->e_header); 46167730Seric if (full && p != NULL) 46267730Seric { 46367730Seric /* (this should be in the configuration file) */ 46467730Seric if (strcasecmp(p, "urgent")) 46567730Seric e->e_timeoutclass = TOC_URGENT; 46667730Seric else if (strcasecmp(p, "normal")) 46767730Seric e->e_timeoutclass = TOC_NORMAL; 46867730Seric else if (strcasecmp(p, "non-urgent")) 46967730Seric e->e_timeoutclass = TOC_NONURGENT; 47067730Seric } 47167730Seric 4727783Seric /* date message originated */ 47367546Seric p = hvalue("posted-date", e->e_header); 4747783Seric if (p == NULL) 47567546Seric p = hvalue("date", e->e_header); 4767783Seric if (p != NULL) 4779382Seric define('a', p, e); 47811290Seric 47911290Seric /* 48065983Seric ** From person in antiquated ARPANET mode 48165983Seric ** required by UK Grey Book e-mail gateways (sigh) 48265983Seric */ 48365983Seric 48465983Seric if (OpMode == MD_ARPAFTP) 48565983Seric { 48665983Seric register struct hdrinfo *hi; 48765983Seric 48865983Seric for (hi = HdrInfo; hi->hi_field != NULL; hi++) 48965983Seric { 49065983Seric if (bitset(H_FROM, hi->hi_flags) && 49165983Seric (!bitset(H_RESENT, hi->hi_flags) || 49265983Seric bitset(EF_RESENT, e->e_flags)) && 49367546Seric (p = hvalue(hi->hi_field, e->e_header)) != NULL) 49465983Seric break; 49565983Seric } 49665983Seric if (hi->hi_field != NULL) 49765983Seric { 49865983Seric if (tTd(32, 2)) 49965983Seric printf("eatheader: setsender(*%s == %s)\n", 50065983Seric hi->hi_field, p); 50165983Seric setsender(p, e, NULL, TRUE); 50265983Seric } 50365983Seric } 50465983Seric 50565983Seric /* 50611290Seric ** Log collection information. 50711290Seric */ 50811290Seric 50911290Seric # ifdef LOG 51068036Seric if (bitset(EF_LOGSENDER, e->e_flags) && LogLevel > 4) 51165089Seric logsender(e, msgid); 51265089Seric # endif /* LOG */ 51365089Seric e->e_flags &= ~EF_LOGSENDER; 51465089Seric } 51565089Seric /* 51665089Seric ** LOGSENDER -- log sender information 51765089Seric ** 51865089Seric ** Parameters: 51965089Seric ** e -- the envelope to log 52065089Seric ** msgid -- the message id 52165089Seric ** 52265089Seric ** Returns: 52365089Seric ** none 52465089Seric */ 52565089Seric 52665089Seric logsender(e, msgid) 52765089Seric register ENVELOPE *e; 52865089Seric char *msgid; 52965089Seric { 53066748Seric # ifdef LOG 53165089Seric char *name; 53265089Seric register char *sbp; 53365089Seric register char *p; 53467901Seric int l; 53568528Seric char hbuf[MAXNAME + 1]; 53668528Seric char sbuf[MAXLINE + 1]; 53768528Seric char mbuf[MAXNAME + 1]; 53865089Seric 53967901Seric /* don't allow newlines in the message-id */ 54067901Seric if (msgid != NULL) 54167901Seric { 54267901Seric l = strlen(msgid); 54367901Seric if (l > sizeof mbuf - 1) 54467901Seric l = sizeof mbuf - 1; 54567901Seric bcopy(msgid, mbuf, l); 54667901Seric mbuf[l] = '\0'; 54767901Seric p = mbuf; 54867901Seric while ((p = strchr(p, '\n')) != NULL) 54967901Seric *p++ = ' '; 55067901Seric } 55167901Seric 55265089Seric if (bitset(EF_RESPONSE, e->e_flags)) 55365089Seric name = "[RESPONSE]"; 55465089Seric else if ((name = macvalue('_', e)) != NULL) 55565089Seric ; 55666003Seric else if (RealHostName == NULL) 55766003Seric name = "localhost"; 55865089Seric else if (RealHostName[0] == '[') 55965089Seric name = RealHostName; 56065089Seric else 56111290Seric { 56265089Seric name = hbuf; 56365089Seric (void) sprintf(hbuf, "%.80s", RealHostName); 56465089Seric if (RealHostAddr.sa.sa_family != 0) 56557359Seric { 56665089Seric p = &hbuf[strlen(hbuf)]; 56765089Seric (void) sprintf(p, " (%s)", 56865089Seric anynet_ntoa(&RealHostAddr)); 56957359Seric } 57065089Seric } 57157359Seric 57265089Seric /* some versions of syslog only take 5 printf args */ 57365059Seric # if (SYSLOG_BUFSIZE) >= 256 57465089Seric sbp = sbuf; 57565089Seric sprintf(sbp, "from=%.200s, size=%ld, class=%d, pri=%ld, nrcpts=%d", 57667788Seric e->e_from.q_paddr == NULL ? "<NONE>" : e->e_from.q_paddr, 57767788Seric e->e_msgsize, e->e_class, e->e_msgpriority, e->e_nrcpts); 57865089Seric sbp += strlen(sbp); 57965089Seric if (msgid != NULL) 58065089Seric { 58167901Seric sprintf(sbp, ", msgid=%.100s", mbuf); 58260575Seric sbp += strlen(sbp); 58365089Seric } 58465089Seric if (e->e_bodytype != NULL) 58565089Seric { 58665089Seric (void) sprintf(sbp, ", bodytype=%.20s", e->e_bodytype); 58765089Seric sbp += strlen(sbp); 58865089Seric } 58965089Seric p = macvalue('r', e); 59065089Seric if (p != NULL) 59165089Seric (void) sprintf(sbp, ", proto=%.20s", p); 59265089Seric syslog(LOG_INFO, "%s: %s, relay=%s", 59365089Seric e->e_id, sbuf, name); 59465059Seric 59565059Seric # else /* short syslog buffer */ 59665059Seric 59765089Seric syslog(LOG_INFO, "%s: from=%s", 59867788Seric e->e_id, e->e_from.q_paddr == NULL ? "<NONE>" : 59967788Seric shortenstring(e->e_from.q_paddr, 83)); 60065089Seric syslog(LOG_INFO, "%s: size=%ld, class=%ld, pri=%ld, nrcpts=%d", 60165089Seric e->e_id, e->e_msgsize, e->e_class, 60265089Seric e->e_msgpriority, e->e_nrcpts); 60365089Seric if (msgid != NULL) 60467901Seric syslog(LOG_INFO, "%s: msgid=%s", e->e_id, mbuf); 60565650Seric sbp = sbuf; 60665650Seric sprintf(sbp, "%s:", e->e_id); 60765650Seric sbp += strlen(sbp); 60865089Seric if (e->e_bodytype != NULL) 60965650Seric { 61065650Seric sprintf(sbp, " bodytype=%s,", e->e_bodytype); 61165650Seric sbp += strlen(sbp); 61265650Seric } 61365089Seric p = macvalue('r', e); 61465089Seric if (p != NULL) 61565650Seric { 61665731Seric sprintf(sbp, " proto=%s,", p); 61765650Seric sbp += strlen(sbp); 61865650Seric } 61965650Seric syslog(LOG_INFO, "%s relay=%s", sbuf, name); 62065059Seric # endif 62166748Seric # endif 6227783Seric } 6237783Seric /* 6247783Seric ** PRIENCODE -- encode external priority names into internal values. 6257783Seric ** 6267783Seric ** Parameters: 6277783Seric ** p -- priority in ascii. 6287783Seric ** 6297783Seric ** Returns: 6307783Seric ** priority as a numeric level. 6317783Seric ** 6327783Seric ** Side Effects: 6337783Seric ** none. 6347783Seric */ 6357783Seric 6367783Seric priencode(p) 6377783Seric char *p; 6387783Seric { 6398253Seric register int i; 6407783Seric 6418253Seric for (i = 0; i < NumPriorities; i++) 6427783Seric { 64333725Sbostic if (!strcasecmp(p, Priorities[i].pri_name)) 6448253Seric return (Priorities[i].pri_val); 6457783Seric } 6468253Seric 6478253Seric /* unknown priority */ 6488253Seric return (0); 6497783Seric } 6507783Seric /* 6517890Seric ** CRACKADDR -- parse an address and turn it into a macro 6527783Seric ** 6537783Seric ** This doesn't actually parse the address -- it just extracts 6547783Seric ** it and replaces it with "$g". The parse is totally ad hoc 6557783Seric ** and isn't even guaranteed to leave something syntactically 6567783Seric ** identical to what it started with. However, it does leave 6577783Seric ** something semantically identical. 6587783Seric ** 65951379Seric ** This algorithm has been cleaned up to handle a wider range 66051379Seric ** of cases -- notably quoted and backslash escaped strings. 66151379Seric ** This modification makes it substantially better at preserving 66251379Seric ** the original syntax. 6637783Seric ** 6647783Seric ** Parameters: 6657890Seric ** addr -- the address to be cracked. 6667783Seric ** 6677783Seric ** Returns: 6687783Seric ** a pointer to the new version. 6697783Seric ** 6707783Seric ** Side Effects: 6717890Seric ** none. 6727783Seric ** 6737783Seric ** Warning: 6747783Seric ** The return value is saved in local storage and should 6757783Seric ** be copied if it is to be reused. 6767783Seric */ 6777783Seric 6787783Seric char * 6797890Seric crackaddr(addr) 6807890Seric register char *addr; 6817783Seric { 6827783Seric register char *p; 68351379Seric register char c; 68451379Seric int cmtlev; 68556764Seric int realcmtlev; 68656764Seric int anglelev, realanglelev; 68751379Seric int copylev; 68851379Seric bool qmode; 68956764Seric bool realqmode; 69056764Seric bool skipping; 69151379Seric bool putgmac = FALSE; 69256735Seric bool quoteit = FALSE; 69364148Seric bool gotangle = FALSE; 69451379Seric register char *bp; 69556764Seric char *buflim; 69668528Seric static char buf[MAXNAME + 1]; 6977783Seric 6987783Seric if (tTd(33, 1)) 6997890Seric printf("crackaddr(%s)\n", addr); 7007783Seric 7018082Seric /* strip leading spaces */ 70258050Seric while (*addr != '\0' && isascii(*addr) && isspace(*addr)) 7038082Seric addr++; 7048082Seric 7057783Seric /* 70651379Seric ** Start by assuming we have no angle brackets. This will be 70751379Seric ** adjusted later if we find them. 7087783Seric */ 7097783Seric 71051379Seric bp = buf; 71156764Seric buflim = &buf[sizeof buf - 5]; 71251379Seric p = addr; 71356764Seric copylev = anglelev = realanglelev = cmtlev = realcmtlev = 0; 71456764Seric qmode = realqmode = FALSE; 71551379Seric 71651379Seric while ((c = *p++) != '\0') 7177783Seric { 71856764Seric /* 71956764Seric ** If the buffer is overful, go into a special "skipping" 72056764Seric ** mode that tries to keep legal syntax but doesn't actually 72156764Seric ** output things. 72256764Seric */ 7237783Seric 72456764Seric skipping = bp >= buflim; 72556735Seric 72656764Seric if (copylev > 0 && !skipping) 72756764Seric *bp++ = c; 72856735Seric 72951379Seric /* check for backslash escapes */ 73051379Seric if (c == '\\') 7317783Seric { 73258890Seric /* arrange to quote the address */ 73358890Seric if (cmtlev <= 0 && !qmode) 73458890Seric quoteit = TRUE; 73558890Seric 73651379Seric if ((c = *p++) == '\0') 7377783Seric { 73851379Seric /* too far */ 73951379Seric p--; 74051379Seric goto putg; 7417783Seric } 74256764Seric if (copylev > 0 && !skipping) 74351379Seric *bp++ = c; 74451379Seric goto putg; 7457783Seric } 7467783Seric 74751379Seric /* check for quoted strings */ 74864967Seric if (c == '"' && cmtlev <= 0) 7497783Seric { 75051379Seric qmode = !qmode; 75156764Seric if (copylev > 0 && !skipping) 75256764Seric realqmode = !realqmode; 75351379Seric continue; 7547783Seric } 75551379Seric if (qmode) 75651379Seric goto putg; 7577783Seric 75851379Seric /* check for comments */ 75951379Seric if (c == '(') 7607783Seric { 76151379Seric cmtlev++; 76256764Seric 76356764Seric /* allow space for closing paren */ 76456764Seric if (!skipping) 76556764Seric { 76656764Seric buflim--; 76756764Seric realcmtlev++; 76856764Seric if (copylev++ <= 0) 76956764Seric { 77056764Seric *bp++ = ' '; 77156764Seric *bp++ = c; 77256764Seric } 77356764Seric } 77451379Seric } 77551379Seric if (cmtlev > 0) 77651379Seric { 77751379Seric if (c == ')') 7787783Seric { 77951379Seric cmtlev--; 78051379Seric copylev--; 78156764Seric if (!skipping) 78256764Seric { 78356764Seric realcmtlev--; 78456764Seric buflim++; 78556764Seric } 7867783Seric } 7877783Seric continue; 7887783Seric } 78956764Seric else if (c == ')') 79056764Seric { 79156764Seric /* syntax error: unmatched ) */ 79265544Seric if (copylev > 0 && !skipping) 79356764Seric bp--; 79456764Seric } 7957783Seric 79656764Seric /* check for characters that may have to be quoted */ 79764148Seric if (strchr(".'@,;:\\()[]", c) != NULL) 79856764Seric { 79956764Seric /* 80056764Seric ** If these occur as the phrase part of a <> 80156764Seric ** construct, but are not inside of () or already 80256764Seric ** quoted, they will have to be quoted. Note that 80356764Seric ** now (but don't actually do the quoting). 80456764Seric */ 80556764Seric 80656764Seric if (cmtlev <= 0 && !qmode) 80756764Seric quoteit = TRUE; 80856764Seric } 80956764Seric 81051379Seric /* check for angle brackets */ 81151379Seric if (c == '<') 81251379Seric { 81356735Seric register char *q; 81456735Seric 81564148Seric /* assume first of two angles is bogus */ 81664148Seric if (gotangle) 81764148Seric quoteit = TRUE; 81864148Seric gotangle = TRUE; 81964148Seric 82051379Seric /* oops -- have to change our mind */ 82164752Seric anglelev = 1; 82256764Seric if (!skipping) 82364752Seric realanglelev = 1; 82456764Seric 82556735Seric bp = buf; 82656735Seric if (quoteit) 82756735Seric { 82856735Seric *bp++ = '"'; 82956735Seric 83056735Seric /* back up over the '<' and any spaces */ 83156735Seric --p; 83258050Seric while (isascii(*--p) && isspace(*p)) 83356735Seric continue; 83456735Seric p++; 83556735Seric } 83656735Seric for (q = addr; q < p; ) 83756735Seric { 83856735Seric c = *q++; 83956764Seric if (bp < buflim) 84056764Seric { 84156764Seric if (quoteit && c == '"') 84256764Seric *bp++ = '\\'; 84356764Seric *bp++ = c; 84456764Seric } 84556735Seric } 84656735Seric if (quoteit) 84756735Seric { 84864148Seric if (bp == &buf[1]) 84964148Seric bp--; 85064148Seric else 85164148Seric *bp++ = '"'; 85256764Seric while ((c = *p++) != '<') 85356764Seric { 85456764Seric if (bp < buflim) 85556764Seric *bp++ = c; 85656764Seric } 85756764Seric *bp++ = c; 85856735Seric } 85951379Seric copylev = 0; 86056735Seric putgmac = quoteit = FALSE; 86151379Seric continue; 86251379Seric } 8637783Seric 86451379Seric if (c == '>') 8657783Seric { 86656764Seric if (anglelev > 0) 86756764Seric { 86856764Seric anglelev--; 86956764Seric if (!skipping) 87056764Seric { 87156764Seric realanglelev--; 87256764Seric buflim++; 87356764Seric } 87456764Seric } 87556764Seric else if (!skipping) 87656764Seric { 87756764Seric /* syntax error: unmatched > */ 87856764Seric if (copylev > 0) 87956764Seric bp--; 88064752Seric quoteit = TRUE; 88156764Seric continue; 88256764Seric } 88351379Seric if (copylev++ <= 0) 88451379Seric *bp++ = c; 88551379Seric continue; 8867783Seric } 88751379Seric 88851379Seric /* must be a real address character */ 88951379Seric putg: 89051379Seric if (copylev <= 0 && !putgmac) 89151379Seric { 89258050Seric *bp++ = MACROEXPAND; 89351379Seric *bp++ = 'g'; 89451379Seric putgmac = TRUE; 89551379Seric } 8967783Seric } 8977783Seric 89856764Seric /* repair any syntactic damage */ 89956764Seric if (realqmode) 90056764Seric *bp++ = '"'; 90156764Seric while (realcmtlev-- > 0) 90256764Seric *bp++ = ')'; 90356764Seric while (realanglelev-- > 0) 90456764Seric *bp++ = '>'; 90551379Seric *bp++ = '\0'; 9067783Seric 9077783Seric if (tTd(33, 1)) 9087944Seric printf("crackaddr=>`%s'\n", buf); 9097783Seric 9107783Seric return (buf); 9117783Seric } 9129382Seric /* 9139382Seric ** PUTHEADER -- put the header part of a message from the in-core copy 9149382Seric ** 9159382Seric ** Parameters: 91665870Seric ** mci -- the connection information. 91767546Seric ** h -- the header to put. 9189382Seric ** e -- envelope to use. 9199382Seric ** 9209382Seric ** Returns: 9219382Seric ** none. 9229382Seric ** 9239382Seric ** Side Effects: 9249382Seric ** none. 9259382Seric */ 9269382Seric 92757589Seric /* 92857589Seric * Macro for fast max (not available in e.g. DG/UX, 386/ix). 92957589Seric */ 93057589Seric #ifndef MAX 93157589Seric # define MAX(a,b) (((a)>(b))?(a):(b)) 93257589Seric #endif 93357589Seric 93468228Seric putheader(mci, h, e) 93565870Seric register MCI *mci; 93667546Seric register HDR *h; 9379382Seric register ENVELOPE *e; 9389382Seric { 93957135Seric char buf[MAX(MAXLINE,BUFSIZ)]; 94057135Seric char obuf[MAXLINE]; 9419382Seric 94259882Seric if (tTd(34, 1)) 94365870Seric printf("--- putheader, mailer = %s ---\n", 94465870Seric mci->mci_mailer->m_name); 94559882Seric 94667546Seric mci->mci_flags |= MCIF_INHEADER; 94767546Seric for (; h != NULL; h = h->h_link) 9489382Seric { 9499382Seric register char *p; 95010689Seric extern bool bitintersect(); 9519382Seric 95259882Seric if (tTd(34, 11)) 95359882Seric { 95459882Seric printf(" %s: ", h->h_field); 95559882Seric xputs(h->h_value); 95659882Seric } 95759882Seric 9589382Seric if (bitset(H_CHECK|H_ACHECK, h->h_flags) && 95965870Seric !bitintersect(h->h_mflags, mci->mci_mailer->m_flags)) 96059882Seric { 96159882Seric if (tTd(34, 11)) 96259882Seric printf(" (skipped)\n"); 9639382Seric continue; 96459882Seric } 9659382Seric 96611414Seric /* handle Resent-... headers specially */ 96711414Seric if (bitset(H_RESENT, h->h_flags) && !bitset(EF_RESENT, e->e_flags)) 96859882Seric { 96959882Seric if (tTd(34, 11)) 97059882Seric printf(" (skipped (resent))\n"); 97111414Seric continue; 97259882Seric } 97311414Seric 97466784Seric /* suppress return receipts if requested */ 97566784Seric if (bitset(H_RECEIPTTO, h->h_flags) && 97666784Seric bitset(EF_NORECEIPT, e->e_flags)) 97766784Seric { 97866784Seric if (tTd(34, 11)) 97966784Seric printf(" (skipped (receipt))\n"); 98066784Seric continue; 98166784Seric } 98266784Seric 98367694Seric /* suppress Content-Transfer-Encoding: if we are MIMEing */ 98467694Seric if (bitset(H_CTE, h->h_flags) && 98568228Seric bitset(MCIF_CVT8TO7, mci->mci_flags)) 98667694Seric { 98767694Seric if (tTd(34, 11)) 98867694Seric printf(" (skipped (content-transfer-encoding))\n"); 98967694Seric continue; 99067694Seric } 99167694Seric 99265152Seric /* macro expand value if generated internally */ 9939382Seric p = h->h_value; 9949382Seric if (bitset(H_DEFAULT, h->h_flags)) 9959382Seric { 99668529Seric expand(p, buf, sizeof buf, e); 9979382Seric p = buf; 9989382Seric if (p == NULL || *p == '\0') 99965152Seric { 100065152Seric if (tTd(34, 11)) 100165152Seric printf(" (skipped -- null value)\n"); 10029382Seric continue; 100365152Seric } 10049382Seric } 10059382Seric 100665152Seric if (tTd(34, 11)) 100765152Seric printf("\n"); 100865152Seric 100968449Seric if (bitset(H_STRIPVAL, h->h_flags)) 10109382Seric { 101168449Seric /* empty field */ 101268449Seric (void) sprintf(obuf, "%s:", h->h_field); 101368449Seric putline(obuf, mci); 101468449Seric } 101568449Seric else if (bitset(H_FROM|H_RCPT, h->h_flags)) 101668449Seric { 10179382Seric /* address field */ 10189382Seric bool oldstyle = bitset(EF_OLDSTYLE, e->e_flags); 10199382Seric 10209382Seric if (bitset(H_FROM, h->h_flags)) 10219382Seric oldstyle = FALSE; 102265870Seric commaize(h, p, oldstyle, mci, e); 10239382Seric } 10249382Seric else 10259382Seric { 10269382Seric /* vanilla header line */ 102712159Seric register char *nlp; 102812159Seric 102959579Seric (void) sprintf(obuf, "%s: ", h->h_field); 103056795Seric while ((nlp = strchr(p, '\n')) != NULL) 103112159Seric { 103212159Seric *nlp = '\0'; 103312159Seric (void) strcat(obuf, p); 103412159Seric *nlp = '\n'; 103565870Seric putline(obuf, mci); 103612159Seric p = ++nlp; 103712161Seric obuf[0] = '\0'; 103812159Seric } 103912159Seric (void) strcat(obuf, p); 104065870Seric putline(obuf, mci); 10419382Seric } 10429382Seric } 104367887Seric 104467887Seric /* 104567887Seric ** If we are converting this to a MIME message, add the 104667889Seric ** MIME headers. 104767887Seric */ 104867887Seric 104967887Seric if (bitset(MM_MIME8BIT, MimeMode) && 105067887Seric bitset(EF_HAS8BIT, e->e_flags) && 105167887Seric !bitnset(M_8BITS, mci->mci_mailer->m_flags) && 105267889Seric !bitset(MCIF_CVT8TO7, mci->mci_flags)) 105367887Seric { 105467889Seric if (hvalue("MIME-Version", e->e_header) == NULL) 105567889Seric putline("MIME-Version: 1.0", mci); 105667889Seric if (hvalue("Content-Type", e->e_header) == NULL) 105767889Seric { 105867889Seric sprintf(obuf, "Content-Type: text/plain; charset=%s", 105967896Seric defcharset(e)); 106067889Seric putline(obuf, mci); 106167889Seric } 106267889Seric if (hvalue("Content-Transfer-Encoding", e->e_header) == NULL) 106367889Seric putline("Content-Transfer-Encoding: 8bit", mci); 106467887Seric } 10659382Seric } 10669382Seric /* 10679382Seric ** COMMAIZE -- output a header field, making a comma-translated list. 10689382Seric ** 10699382Seric ** Parameters: 10709382Seric ** h -- the header field to output. 10719382Seric ** p -- the value to put in it. 10729382Seric ** oldstyle -- TRUE if this is an old style header. 107365870Seric ** mci -- the connection information. 107455012Seric ** e -- the envelope containing the message. 10759382Seric ** 10769382Seric ** Returns: 10779382Seric ** none. 10789382Seric ** 10799382Seric ** Side Effects: 10809382Seric ** outputs "p" to file "fp". 10819382Seric */ 10829382Seric 108365870Seric void 108465870Seric commaize(h, p, oldstyle, mci, e) 10859382Seric register HDR *h; 10869382Seric register char *p; 10879382Seric bool oldstyle; 108865870Seric register MCI *mci; 108955012Seric register ENVELOPE *e; 10909382Seric { 10919382Seric register char *obp; 10929382Seric int opos; 109366004Seric int omax; 10949382Seric bool firstone = TRUE; 109511157Seric char obuf[MAXLINE + 3]; 10969382Seric 10979382Seric /* 10989382Seric ** Output the address list translated by the 10999382Seric ** mailer and with commas. 11009382Seric */ 11019382Seric 11029382Seric if (tTd(14, 2)) 11039382Seric printf("commaize(%s: %s)\n", h->h_field, p); 11049382Seric 11059382Seric obp = obuf; 110659579Seric (void) sprintf(obp, "%s: ", h->h_field); 11079382Seric opos = strlen(h->h_field) + 2; 11089382Seric obp += opos; 110966254Seric omax = mci->mci_mailer->m_linelimit - 2; 111066254Seric if (omax < 0 || omax > 78) 111166254Seric omax = 78; 11129382Seric 11139382Seric /* 11149382Seric ** Run through the list of values. 11159382Seric */ 11169382Seric 11179382Seric while (*p != '\0') 11189382Seric { 11199382Seric register char *name; 112054983Seric register int c; 11219382Seric char savechar; 112259163Seric int flags; 112359163Seric auto int stat; 11249382Seric 11259382Seric /* 11269382Seric ** Find the end of the name. New style names 11279382Seric ** end with a comma, old style names end with 11289382Seric ** a space character. However, spaces do not 11299382Seric ** necessarily delimit an old-style name -- at 11309382Seric ** signs mean keep going. 11319382Seric */ 11329382Seric 11339382Seric /* find end of name */ 113458050Seric while ((isascii(*p) && isspace(*p)) || *p == ',') 11359382Seric p++; 11369382Seric name = p; 11379382Seric for (;;) 11389382Seric { 113958333Seric auto char *oldp; 114016909Seric char pvpbuf[PSBUFSIZE]; 11419382Seric 114265066Seric (void) prescan(p, oldstyle ? ' ' : ',', pvpbuf, 114365066Seric sizeof pvpbuf, &oldp); 114458333Seric p = oldp; 11459382Seric 11469382Seric /* look to see if we have an at sign */ 114758050Seric while (*p != '\0' && isascii(*p) && isspace(*p)) 11489382Seric p++; 11499382Seric 115058170Seric if (*p != '@') 11519382Seric { 11529382Seric p = oldp; 11539382Seric break; 11549382Seric } 11559382Seric p += *p == '@' ? 1 : 2; 115658050Seric while (*p != '\0' && isascii(*p) && isspace(*p)) 11579382Seric p++; 11589382Seric } 11599382Seric /* at the end of one complete name */ 11609382Seric 11619382Seric /* strip off trailing white space */ 116258050Seric while (p >= name && 116358050Seric ((isascii(*p) && isspace(*p)) || *p == ',' || *p == '\0')) 11649382Seric p--; 11659382Seric if (++p == name) 11669382Seric continue; 11679382Seric savechar = *p; 11689382Seric *p = '\0'; 11699382Seric 11709382Seric /* translate the name to be relative */ 117159163Seric flags = RF_HEADERADDR|RF_ADDDOMAIN; 117259163Seric if (bitset(H_FROM, h->h_flags)) 117359163Seric flags |= RF_SENDERADDR; 117468522Seric #ifdef USERDB 117568522Seric else if (e->e_from.q_mailer != NULL && 117668522Seric bitnset(M_UDBRECIPIENT, e->e_from.q_mailer->m_flags)) 117768522Seric { 117868522Seric extern char *udbsender(); 117968522Seric 118068522Seric name = udbsender(name); 118168522Seric } 118268522Seric #endif 118359163Seric stat = EX_OK; 118465870Seric name = remotename(name, mci->mci_mailer, flags, &stat, e); 11859382Seric if (*name == '\0') 11869382Seric { 11879382Seric *p = savechar; 11889382Seric continue; 11899382Seric } 11909382Seric 11919382Seric /* output the name with nice formatting */ 119254983Seric opos += strlen(name); 11939382Seric if (!firstone) 11949382Seric opos += 2; 119566004Seric if (opos > omax && !firstone) 11969382Seric { 119710178Seric (void) strcpy(obp, ",\n"); 119865870Seric putline(obuf, mci); 11999382Seric obp = obuf; 120066255Seric (void) strcpy(obp, " "); 120110161Seric opos = strlen(obp); 120210161Seric obp += opos; 120354983Seric opos += strlen(name); 12049382Seric } 12059382Seric else if (!firstone) 12069382Seric { 120766255Seric (void) strcpy(obp, ", "); 12089382Seric obp += 2; 12099382Seric } 12109382Seric 121154983Seric while ((c = *name++) != '\0' && obp < &obuf[MAXLINE]) 121254983Seric *obp++ = c; 12139382Seric firstone = FALSE; 12149382Seric *p = savechar; 12159382Seric } 12169382Seric (void) strcpy(obp, "\n"); 121765870Seric putline(obuf, mci); 12189382Seric } 12199382Seric /* 122058170Seric ** COPYHEADER -- copy header list 12219382Seric ** 122258170Seric ** This routine is the equivalent of newstr for header lists 122358170Seric ** 12249382Seric ** Parameters: 122558170Seric ** header -- list of header structures to copy. 12269382Seric ** 12279382Seric ** Returns: 122858170Seric ** a copy of 'header'. 12299382Seric ** 12309382Seric ** Side Effects: 12319382Seric ** none. 12329382Seric */ 12339382Seric 123458170Seric HDR * 123558170Seric copyheader(header) 123658170Seric register HDR *header; 12379382Seric { 123858170Seric register HDR *newhdr; 123958170Seric HDR *ret; 124058170Seric register HDR **tail = &ret; 12419382Seric 124258170Seric while (header != NULL) 124358170Seric { 124458170Seric newhdr = (HDR *) xalloc(sizeof(HDR)); 124558170Seric STRUCTCOPY(*header, *newhdr); 124658170Seric *tail = newhdr; 124758170Seric tail = &newhdr->h_link; 124858170Seric header = header->h_link; 124958170Seric } 125058170Seric *tail = NULL; 125158170Seric 125258170Seric return ret; 12539382Seric } 1254