122706Sdist /* 268839Seric * Copyright (c) 1983, 1995 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*69794Seric static char sccsid[] = "@(#)headers.c 8.68 (Berkeley) 06/01/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. 2468717Seric ** hdrp -- a pointer to the place to save the header. 2555012Seric ** e -- the envelope including this header. 264091Seric ** 274091Seric ** Returns: 284091Seric ** flags for this header. 294091Seric ** 304091Seric ** Side Effects: 314091Seric ** The header is saved on the header list. 324319Seric ** Contents of 'line' are destroyed. 334091Seric */ 344091Seric 3569748Seric int 3668717Seric chompheader(line, def, hdrp, e) 374091Seric char *line; 384091Seric bool def; 3968717Seric HDR **hdrp; 4055012Seric register ENVELOPE *e; 414091Seric { 424091Seric register char *p; 434091Seric register HDR *h; 444091Seric HDR **hp; 454091Seric char *fname; 464091Seric char *fvalue; 474091Seric struct hdrinfo *hi; 489059Seric bool cond = FALSE; 4968717Seric bool headeronly; 5010689Seric BITMAP mopts; 5168528Seric char buf[MAXNAME + 1]; 524091Seric 537677Seric if (tTd(31, 6)) 5468812Seric { 5568812Seric printf("chompheader: "); 5668812Seric xputs(line); 5768812Seric printf("\n"); 5868812Seric } 597677Seric 6068717Seric headeronly = hdrp != NULL; 6168717Seric if (!headeronly) 6268717Seric hdrp = &e->e_header; 6368717Seric 644627Seric /* strip off options */ 6510689Seric clrbitmap(mopts); 664627Seric p = line; 6757405Seric if (*p == '?') 684627Seric { 694627Seric /* have some */ 7056795Seric register char *q = strchr(p + 1, *p); 714627Seric 724627Seric if (q != NULL) 734627Seric { 744627Seric *q++ = '\0'; 7510689Seric while (*++p != '\0') 7610689Seric setbitn(*p, mopts); 774627Seric p = q; 784627Seric } 794627Seric else 8068690Seric syserr("553 header syntax error, line \"%s\"", line); 819059Seric cond = TRUE; 824627Seric } 834627Seric 844091Seric /* find canonical name */ 854627Seric fname = p; 8664149Seric while (isascii(*p) && isgraph(*p) && *p != ':') 8764149Seric p++; 8864149Seric fvalue = p; 8964149Seric while (isascii(*p) && isspace(*p)) 9064149Seric p++; 9164150Seric if (*p++ != ':' || fname == fvalue) 9210118Seric { 9358151Seric syserr("553 header syntax error, line \"%s\"", line); 9410118Seric return (0); 9510118Seric } 9664149Seric *fvalue = '\0'; 9764149Seric fvalue = p; 984091Seric 994091Seric /* strip field value on front */ 1004091Seric if (*fvalue == ' ') 1014091Seric fvalue++; 1024091Seric 1034091Seric /* see if it is a known type */ 1044091Seric for (hi = HdrInfo; hi->hi_field != NULL; hi++) 1054091Seric { 10659579Seric if (strcasecmp(hi->hi_field, fname) == 0) 1074091Seric break; 1084091Seric } 1094091Seric 11064283Seric if (tTd(31, 9)) 11164283Seric { 11264283Seric if (hi->hi_field == NULL) 11364283Seric printf("no header match\n"); 11464283Seric else 11567694Seric printf("header match, hi_flags=%x\n", hi->hi_flags); 11664283Seric } 11764283Seric 11811414Seric /* see if this is a resent message */ 11968717Seric if (!def && !headeronly && bitset(H_RESENT, hi->hi_flags)) 12055012Seric e->e_flags |= EF_RESENT; 12111414Seric 12268558Seric /* if this is an Errors-To: header keep track of it now */ 12368717Seric if (UseErrorsTo && !def && !headeronly && 12468717Seric bitset(H_ERRORSTO, hi->hi_flags)) 12568558Seric (void) sendtolist(fvalue, NULLADDR, &e->e_errorqueue, 0, e); 12668558Seric 1274091Seric /* if this means "end of header" quit now */ 1284091Seric if (bitset(H_EOH, hi->hi_flags)) 1294091Seric return (hi->hi_flags); 1304091Seric 13164653Seric /* 13264653Seric ** Drop explicit From: if same as what we would generate. 13364653Seric ** This is to make MH (which doesn't always give a full name) 13464653Seric ** insert the full name information in all circumstances. 13564653Seric */ 13664653Seric 13714784Seric p = "resent-from"; 13855012Seric if (!bitset(EF_RESENT, e->e_flags)) 13914784Seric p += 7; 14068717Seric if (!def && !headeronly && !bitset(EF_QUEUERUN, e->e_flags) && 14168717Seric strcasecmp(fname, p) == 0) 14211414Seric { 14363753Seric if (tTd(31, 2)) 14463753Seric { 14563753Seric printf("comparing header from (%s) against default (%s or %s)\n", 14663753Seric fvalue, e->e_from.q_paddr, e->e_from.q_user); 14763753Seric } 14855012Seric if (e->e_from.q_paddr != NULL && 14963753Seric (strcmp(fvalue, e->e_from.q_paddr) == 0 || 15063753Seric strcmp(fvalue, e->e_from.q_user) == 0)) 15111414Seric return (hi->hi_flags); 15264351Seric #ifdef MAYBENEXTRELEASE /* XXX UNTESTED XXX UNTESTED XXX UNTESTED XXX */ 15369713Seric #if USERDB 15464351Seric else 15564351Seric { 15664351Seric auto ADDRESS a; 15764351Seric char *fancy; 15866123Seric bool oldSuprErrs = SuprErrs; 15964351Seric extern char *crackaddr(); 16064351Seric extern char *udbsender(); 16164351Seric 16264653Seric /* 16364653Seric ** Try doing USERDB rewriting even on fully commented 16464653Seric ** names; this saves the "comment" information (such 16564653Seric ** as full name) and rewrites the electronic part. 16666106Seric ** 16766106Seric ** XXX This code doesn't belong here -- parsing should 16866106Seric ** XXX not be done during collect() phase because 16966106Seric ** XXX error messages can confuse the SMTP phase. 17066123Seric ** XXX Setting SuprErrs is a crude hack around this 17166106Seric ** XXX problem. 17264653Seric */ 17364653Seric 17466106Seric if (OpMode == MD_SMTP || OpMode == MD_ARPAFTP) 17566123Seric SuprErrs = TRUE; 17664351Seric fancy = crackaddr(fvalue); 17764351Seric if (parseaddr(fvalue, &a, RF_COPYNONE, '\0', NULL, e) != NULL && 17867472Seric bitnset(M_CHECKUDB, a.q_mailer->m_flags) && 17964351Seric (p = udbsender(a.q_user)) != NULL) 18064351Seric { 18164351Seric char *oldg = macvalue('g', e); 18264351Seric 18364351Seric define('g', p, e); 18468529Seric expand(fancy, buf, sizeof buf, e); 18564351Seric define('g', oldg, e); 18664351Seric fvalue = buf; 18764351Seric } 18866123Seric SuprErrs = oldSuprErrs; 18964351Seric } 19064351Seric #endif 19164351Seric #endif 19211414Seric } 19311414Seric 19414784Seric /* delete default value for this header */ 19568717Seric for (hp = hdrp; (h = *hp) != NULL; hp = &h->h_link) 19614784Seric { 19759579Seric if (strcasecmp(fname, h->h_field) == 0 && 19814784Seric bitset(H_DEFAULT, h->h_flags) && 19914784Seric !bitset(H_FORCE, h->h_flags)) 20069726Seric { 20114784Seric h->h_value = NULL; 20269726Seric if (!cond) 20369726Seric { 20469726Seric /* copy conditions from default case */ 20569726Seric bcopy((char *)h->h_mflags, (char *)mopts, 20669726Seric sizeof mopts); 20769726Seric } 20869726Seric } 20914784Seric } 21014784Seric 21113012Seric /* create a new node */ 21213012Seric h = (HDR *) xalloc(sizeof *h); 21313012Seric h->h_field = newstr(fname); 21464134Seric h->h_value = newstr(fvalue); 21513012Seric h->h_link = NULL; 21623117Seric bcopy((char *) mopts, (char *) h->h_mflags, sizeof mopts); 21713012Seric *hp = h; 2188066Seric h->h_flags = hi->hi_flags; 2194091Seric if (def) 2204091Seric h->h_flags |= H_DEFAULT; 2219059Seric if (cond) 2229059Seric h->h_flags |= H_CHECK; 2234091Seric 2245937Seric /* hack to see if this is a new format message */ 22568717Seric if (!def && !headeronly && bitset(H_RCPT|H_FROM, h->h_flags) && 22656795Seric (strchr(fvalue, ',') != NULL || strchr(fvalue, '(') != NULL || 22756795Seric strchr(fvalue, '<') != NULL || strchr(fvalue, ';') != NULL)) 2288089Seric { 22955012Seric e->e_flags &= ~EF_OLDSTYLE; 2308089Seric } 2315937Seric 2324091Seric return (h->h_flags); 2334091Seric } 2344091Seric /* 2356980Seric ** ADDHEADER -- add a header entry to the end of the queue. 2366980Seric ** 2376980Seric ** This bypasses the special checking of chompheader. 2386980Seric ** 2396980Seric ** Parameters: 24059579Seric ** field -- the name of the header field. 24158789Seric ** value -- the value of the field. 24267546Seric ** hp -- an indirect pointer to the header structure list. 2436980Seric ** 2446980Seric ** Returns: 2456980Seric ** none. 2466980Seric ** 2476980Seric ** Side Effects: 2486980Seric ** adds the field on the list of headers for this envelope. 2496980Seric */ 2506980Seric 25169748Seric void 25267546Seric addheader(field, value, hdrlist) 2536980Seric char *field; 2546980Seric char *value; 25567546Seric HDR **hdrlist; 2566980Seric { 2576980Seric register HDR *h; 2586980Seric register struct hdrinfo *hi; 2596980Seric HDR **hp; 2606980Seric 2616980Seric /* find info struct */ 2626980Seric for (hi = HdrInfo; hi->hi_field != NULL; hi++) 2636980Seric { 26459579Seric if (strcasecmp(field, hi->hi_field) == 0) 2656980Seric break; 2666980Seric } 2676980Seric 2686980Seric /* find current place in list -- keep back pointer? */ 26967546Seric for (hp = hdrlist; (h = *hp) != NULL; hp = &h->h_link) 2706980Seric { 27159579Seric if (strcasecmp(field, h->h_field) == 0) 2726980Seric break; 2736980Seric } 2746980Seric 2756980Seric /* allocate space for new header */ 2766980Seric h = (HDR *) xalloc(sizeof *h); 2776980Seric h->h_field = field; 2786980Seric h->h_value = newstr(value); 2797368Seric h->h_link = *hp; 2806980Seric h->h_flags = hi->hi_flags | H_DEFAULT; 28110689Seric clrbitmap(h->h_mflags); 2826980Seric *hp = h; 2836980Seric } 2846980Seric /* 2854091Seric ** HVALUE -- return value of a header. 2864091Seric ** 2874091Seric ** Only "real" fields (i.e., ones that have not been supplied 2884091Seric ** as a default) are used. 2894091Seric ** 2904091Seric ** Parameters: 2914091Seric ** field -- the field name. 29267546Seric ** header -- the header list. 2934091Seric ** 2944091Seric ** Returns: 2954091Seric ** pointer to the value part. 2964091Seric ** NULL if not found. 2974091Seric ** 2984091Seric ** Side Effects: 2999382Seric ** none. 3004091Seric */ 3014091Seric 3024091Seric char * 30367546Seric hvalue(field, header) 3044091Seric char *field; 30567546Seric HDR *header; 3064091Seric { 3074091Seric register HDR *h; 3084091Seric 30967546Seric for (h = header; h != NULL; h = h->h_link) 3104091Seric { 31159579Seric if (!bitset(H_DEFAULT, h->h_flags) && 31259579Seric strcasecmp(h->h_field, field) == 0) 3134091Seric return (h->h_value); 3144091Seric } 3154091Seric return (NULL); 3164091Seric } 3174091Seric /* 3184091Seric ** ISHEADER -- predicate telling if argument is a header. 3194091Seric ** 3204319Seric ** A line is a header if it has a single word followed by 3214319Seric ** optional white space followed by a colon. 3224319Seric ** 32368717Seric ** Header fields beginning with two dashes, although technically 32468717Seric ** permitted by RFC822, are automatically rejected in order 32568717Seric ** to make MIME work out. Without this we could have a technically 32668717Seric ** legal header such as ``--"foo:bar"'' that would also be a legal 32768717Seric ** MIME separator. 32868717Seric ** 3294091Seric ** Parameters: 33068690Seric ** h -- string to check for possible headerness. 3314091Seric ** 3324091Seric ** Returns: 33368690Seric ** TRUE if h is a header. 3344091Seric ** FALSE otherwise. 3354091Seric ** 3364091Seric ** Side Effects: 3374091Seric ** none. 3384091Seric */ 3394091Seric 3404091Seric bool 34168690Seric isheader(h) 34268690Seric char *h; 3434091Seric { 34468690Seric register char *s = h; 34568690Seric 34668717Seric if (s[0] == '-' && s[1] == '-') 34768717Seric return FALSE; 34868717Seric 3499382Seric while (*s > ' ' && *s != ':' && *s != '\0') 3504091Seric s++; 3519382Seric 35268690Seric if (h == s) 35368690Seric return FALSE; 35468690Seric 3559382Seric /* following technically violates RFC822 */ 35658050Seric while (isascii(*s) && isspace(*s)) 3574091Seric s++; 3589382Seric 3594091Seric return (*s == ':'); 3604091Seric } 3615919Seric /* 3627783Seric ** EATHEADER -- run through the stored header and extract info. 3637783Seric ** 3647783Seric ** Parameters: 3659382Seric ** e -- the envelope to process. 36658929Seric ** full -- if set, do full processing (e.g., compute 36769683Seric ** message priority). This should not be set 36869683Seric ** when reading a queue file because some info 36969683Seric ** needed to compute the priority is wrong. 3707783Seric ** 3717783Seric ** Returns: 3727783Seric ** none. 3737783Seric ** 3747783Seric ** Side Effects: 3757783Seric ** Sets a bunch of global variables from information 3769382Seric ** in the collected header. 3779382Seric ** Aborts the message if the hop count is exceeded. 3787783Seric */ 3797783Seric 38069748Seric void 38158929Seric eatheader(e, full) 3829382Seric register ENVELOPE *e; 38358929Seric bool full; 3847783Seric { 3857783Seric register HDR *h; 3867783Seric register char *p; 3879382Seric int hopcnt = 0; 38857208Seric char *msgid; 38958688Seric char buf[MAXLINE]; 3907783Seric 39158688Seric /* 39258688Seric ** Set up macros for possible expansion in headers. 39358688Seric */ 39458688Seric 39558704Seric define('f', e->e_sender, e); 39658704Seric define('g', e->e_sender, e); 39764148Seric if (e->e_origrcpt != NULL && *e->e_origrcpt != '\0') 39864148Seric define('u', e->e_origrcpt, e); 39964148Seric else 40064148Seric define('u', NULL, e); 40158688Seric 40265052Seric /* full name of from person */ 40367546Seric p = hvalue("full-name", e->e_header); 40465052Seric if (p != NULL) 40565052Seric define('x', p, e); 40665052Seric 4079382Seric if (tTd(32, 1)) 4089382Seric printf("----- collected header -----\n"); 40969683Seric msgid = NULL; 4109382Seric for (h = e->e_header; h != NULL; h = h->h_link) 4117783Seric { 412*69794Seric if (tTd(32, 1)) 413*69794Seric printf("%s: ", h->h_field); 41464156Seric if (h->h_value == NULL) 41564156Seric { 41664156Seric if (tTd(32, 1)) 417*69794Seric printf("<NULL>\n"); 41864156Seric continue; 41964156Seric } 42064156Seric 42158688Seric /* do early binding */ 42264156Seric if (bitset(H_DEFAULT, h->h_flags)) 42358688Seric { 424*69794Seric if (tTd(32, 1)) 425*69794Seric { 426*69794Seric printf("("); 427*69794Seric xputs(h->h_value); 428*69794Seric printf(") "); 429*69794Seric } 43068529Seric expand(h->h_value, buf, sizeof buf, e); 43158688Seric if (buf[0] != '\0') 43258688Seric { 43358688Seric h->h_value = newstr(buf); 43458688Seric h->h_flags &= ~H_DEFAULT; 43558688Seric } 43658688Seric } 43758688Seric 4389382Seric if (tTd(32, 1)) 43965152Seric { 44065152Seric xputs(h->h_value); 44165152Seric printf("\n"); 44265152Seric } 44357359Seric 44411414Seric /* count the number of times it has been processed */ 4459382Seric if (bitset(H_TRACE, h->h_flags)) 4469382Seric hopcnt++; 44711414Seric 44811414Seric /* send to this person if we so desire */ 44911414Seric if (GrabTo && bitset(H_RCPT, h->h_flags) && 45011414Seric !bitset(H_DEFAULT, h->h_flags) && 45155012Seric (!bitset(EF_RESENT, e->e_flags) || bitset(H_RESENT, h->h_flags))) 45211414Seric { 45363839Seric int saveflags = e->e_flags; 45463839Seric 45564283Seric (void) sendtolist(h->h_value, NULLADDR, 45667982Seric &e->e_sendqueue, 0, e); 45763839Seric 45863839Seric /* delete fatal errors generated by this address */ 45964148Seric if (!GrabTo && !bitset(EF_FATALERRS, saveflags)) 46063839Seric e->e_flags &= ~EF_FATALERRS; 46111414Seric } 46211414Seric 46357208Seric /* save the message-id for logging */ 46469683Seric if (strcasecmp(h->h_field, "message-id") == 0) 46511290Seric { 46657208Seric msgid = h->h_value; 46759859Seric while (isascii(*msgid) && isspace(*msgid)) 46859859Seric msgid++; 46911290Seric } 47057359Seric 47157359Seric /* see if this is a return-receipt header */ 47257359Seric if (bitset(H_RECEIPTTO, h->h_flags)) 47357359Seric e->e_receiptto = h->h_value; 4749382Seric } 4759382Seric if (tTd(32, 1)) 4767783Seric printf("----------------------------\n"); 4777783Seric 47858145Seric /* if we are just verifying (that is, sendmail -t -bv), drop out now */ 47958145Seric if (OpMode == MD_VERIFY) 48058145Seric return; 48158145Seric 4829382Seric /* store hop count */ 4839382Seric if (hopcnt > e->e_hopcount) 4849382Seric e->e_hopcount = hopcnt; 4859382Seric 4867783Seric /* message priority */ 48767546Seric p = hvalue("precedence", e->e_header); 4889382Seric if (p != NULL) 4899382Seric e->e_class = priencode(p); 49069683Seric if (e->e_class < 0) 49169683Seric e->e_timeoutclass = TOC_NONURGENT; 49269683Seric else if (e->e_class > 0) 49369683Seric e->e_timeoutclass = TOC_URGENT; 49458929Seric if (full) 49567730Seric { 49625013Seric e->e_msgpriority = e->e_msgsize 49724981Seric - e->e_class * WkClassFact 49824981Seric + e->e_nrcpts * WkRecipFact; 49967730Seric } 5007783Seric 50167730Seric /* message timeout priority */ 50267730Seric p = hvalue("priority", e->e_header); 50369683Seric if (p != NULL) 50467730Seric { 50567730Seric /* (this should be in the configuration file) */ 50667730Seric if (strcasecmp(p, "urgent")) 50767730Seric e->e_timeoutclass = TOC_URGENT; 50867730Seric else if (strcasecmp(p, "normal")) 50967730Seric e->e_timeoutclass = TOC_NORMAL; 51067730Seric else if (strcasecmp(p, "non-urgent")) 51167730Seric e->e_timeoutclass = TOC_NONURGENT; 51267730Seric } 51367730Seric 5147783Seric /* date message originated */ 51567546Seric p = hvalue("posted-date", e->e_header); 5167783Seric if (p == NULL) 51767546Seric p = hvalue("date", e->e_header); 5187783Seric if (p != NULL) 5199382Seric define('a', p, e); 52011290Seric 52168884Seric /* check to see if this is a MIME message */ 52269105Seric if ((e->e_bodytype != NULL && 52369105Seric strcasecmp(e->e_bodytype, "8BITMIME") == 0) || 52468884Seric hvalue("MIME-Version", e->e_header) != NULL) 52569105Seric { 52668884Seric e->e_flags |= EF_IS_MIME; 52769105Seric if (HasEightBits) 52869105Seric e->e_bodytype = "8BITMIME"; 52969105Seric } 53068884Seric 53111290Seric /* 53265983Seric ** From person in antiquated ARPANET mode 53365983Seric ** required by UK Grey Book e-mail gateways (sigh) 53465983Seric */ 53565983Seric 53665983Seric if (OpMode == MD_ARPAFTP) 53765983Seric { 53865983Seric register struct hdrinfo *hi; 53965983Seric 54065983Seric for (hi = HdrInfo; hi->hi_field != NULL; hi++) 54165983Seric { 54265983Seric if (bitset(H_FROM, hi->hi_flags) && 54365983Seric (!bitset(H_RESENT, hi->hi_flags) || 54465983Seric bitset(EF_RESENT, e->e_flags)) && 54567546Seric (p = hvalue(hi->hi_field, e->e_header)) != NULL) 54665983Seric break; 54765983Seric } 54865983Seric if (hi->hi_field != NULL) 54965983Seric { 55065983Seric if (tTd(32, 2)) 55165983Seric printf("eatheader: setsender(*%s == %s)\n", 55265983Seric hi->hi_field, p); 55365983Seric setsender(p, e, NULL, TRUE); 55465983Seric } 55565983Seric } 55665983Seric 55765983Seric /* 55811290Seric ** Log collection information. 55911290Seric */ 56011290Seric 56111290Seric # ifdef LOG 56268036Seric if (bitset(EF_LOGSENDER, e->e_flags) && LogLevel > 4) 56365089Seric logsender(e, msgid); 56465089Seric # endif /* LOG */ 56565089Seric e->e_flags &= ~EF_LOGSENDER; 56665089Seric } 56765089Seric /* 56865089Seric ** LOGSENDER -- log sender information 56965089Seric ** 57065089Seric ** Parameters: 57165089Seric ** e -- the envelope to log 57265089Seric ** msgid -- the message id 57365089Seric ** 57465089Seric ** Returns: 57565089Seric ** none 57665089Seric */ 57765089Seric 57869748Seric void 57965089Seric logsender(e, msgid) 58065089Seric register ENVELOPE *e; 58165089Seric char *msgid; 58265089Seric { 58366748Seric # ifdef LOG 58465089Seric char *name; 58565089Seric register char *sbp; 58665089Seric register char *p; 58767901Seric int l; 58868528Seric char hbuf[MAXNAME + 1]; 58968528Seric char sbuf[MAXLINE + 1]; 59068528Seric char mbuf[MAXNAME + 1]; 59165089Seric 59267901Seric /* don't allow newlines in the message-id */ 59367901Seric if (msgid != NULL) 59467901Seric { 59567901Seric l = strlen(msgid); 59667901Seric if (l > sizeof mbuf - 1) 59767901Seric l = sizeof mbuf - 1; 59867901Seric bcopy(msgid, mbuf, l); 59967901Seric mbuf[l] = '\0'; 60067901Seric p = mbuf; 60167901Seric while ((p = strchr(p, '\n')) != NULL) 60267901Seric *p++ = ' '; 60367901Seric } 60467901Seric 60565089Seric if (bitset(EF_RESPONSE, e->e_flags)) 60665089Seric name = "[RESPONSE]"; 60765089Seric else if ((name = macvalue('_', e)) != NULL) 60865089Seric ; 60966003Seric else if (RealHostName == NULL) 61066003Seric name = "localhost"; 61165089Seric else if (RealHostName[0] == '[') 61265089Seric name = RealHostName; 61365089Seric else 61411290Seric { 61565089Seric name = hbuf; 61665089Seric (void) sprintf(hbuf, "%.80s", RealHostName); 61765089Seric if (RealHostAddr.sa.sa_family != 0) 61857359Seric { 61965089Seric p = &hbuf[strlen(hbuf)]; 62065089Seric (void) sprintf(p, " (%s)", 62165089Seric anynet_ntoa(&RealHostAddr)); 62257359Seric } 62365089Seric } 62457359Seric 62565089Seric /* some versions of syslog only take 5 printf args */ 62665059Seric # if (SYSLOG_BUFSIZE) >= 256 62765089Seric sbp = sbuf; 62865089Seric sprintf(sbp, "from=%.200s, size=%ld, class=%d, pri=%ld, nrcpts=%d", 62967788Seric e->e_from.q_paddr == NULL ? "<NONE>" : e->e_from.q_paddr, 63067788Seric e->e_msgsize, e->e_class, e->e_msgpriority, e->e_nrcpts); 63165089Seric sbp += strlen(sbp); 63265089Seric if (msgid != NULL) 63365089Seric { 63467901Seric sprintf(sbp, ", msgid=%.100s", mbuf); 63560575Seric sbp += strlen(sbp); 63665089Seric } 63765089Seric if (e->e_bodytype != NULL) 63865089Seric { 63965089Seric (void) sprintf(sbp, ", bodytype=%.20s", e->e_bodytype); 64065089Seric sbp += strlen(sbp); 64165089Seric } 64265089Seric p = macvalue('r', e); 64365089Seric if (p != NULL) 64465089Seric (void) sprintf(sbp, ", proto=%.20s", p); 64565089Seric syslog(LOG_INFO, "%s: %s, relay=%s", 64665089Seric e->e_id, sbuf, name); 64765059Seric 64865059Seric # else /* short syslog buffer */ 64965059Seric 65065089Seric syslog(LOG_INFO, "%s: from=%s", 65167788Seric e->e_id, e->e_from.q_paddr == NULL ? "<NONE>" : 65267788Seric shortenstring(e->e_from.q_paddr, 83)); 65365089Seric syslog(LOG_INFO, "%s: size=%ld, class=%ld, pri=%ld, nrcpts=%d", 65465089Seric e->e_id, e->e_msgsize, e->e_class, 65565089Seric e->e_msgpriority, e->e_nrcpts); 65665089Seric if (msgid != NULL) 65767901Seric syslog(LOG_INFO, "%s: msgid=%s", e->e_id, mbuf); 65865650Seric sbp = sbuf; 65965650Seric sprintf(sbp, "%s:", e->e_id); 66065650Seric sbp += strlen(sbp); 66165089Seric if (e->e_bodytype != NULL) 66265650Seric { 66365650Seric sprintf(sbp, " bodytype=%s,", e->e_bodytype); 66465650Seric sbp += strlen(sbp); 66565650Seric } 66665089Seric p = macvalue('r', e); 66765089Seric if (p != NULL) 66865650Seric { 66965731Seric sprintf(sbp, " proto=%s,", p); 67065650Seric sbp += strlen(sbp); 67165650Seric } 67265650Seric syslog(LOG_INFO, "%s relay=%s", sbuf, name); 67365059Seric # endif 67466748Seric # endif 6757783Seric } 6767783Seric /* 6777783Seric ** PRIENCODE -- encode external priority names into internal values. 6787783Seric ** 6797783Seric ** Parameters: 6807783Seric ** p -- priority in ascii. 6817783Seric ** 6827783Seric ** Returns: 6837783Seric ** priority as a numeric level. 6847783Seric ** 6857783Seric ** Side Effects: 6867783Seric ** none. 6877783Seric */ 6887783Seric 68969748Seric int 6907783Seric priencode(p) 6917783Seric char *p; 6927783Seric { 6938253Seric register int i; 6947783Seric 6958253Seric for (i = 0; i < NumPriorities; i++) 6967783Seric { 69733725Sbostic if (!strcasecmp(p, Priorities[i].pri_name)) 6988253Seric return (Priorities[i].pri_val); 6997783Seric } 7008253Seric 7018253Seric /* unknown priority */ 7028253Seric return (0); 7037783Seric } 7047783Seric /* 7057890Seric ** CRACKADDR -- parse an address and turn it into a macro 7067783Seric ** 7077783Seric ** This doesn't actually parse the address -- it just extracts 7087783Seric ** it and replaces it with "$g". The parse is totally ad hoc 7097783Seric ** and isn't even guaranteed to leave something syntactically 7107783Seric ** identical to what it started with. However, it does leave 7117783Seric ** something semantically identical. 7127783Seric ** 71351379Seric ** This algorithm has been cleaned up to handle a wider range 71451379Seric ** of cases -- notably quoted and backslash escaped strings. 71551379Seric ** This modification makes it substantially better at preserving 71651379Seric ** the original syntax. 7177783Seric ** 7187783Seric ** Parameters: 7197890Seric ** addr -- the address to be cracked. 7207783Seric ** 7217783Seric ** Returns: 7227783Seric ** a pointer to the new version. 7237783Seric ** 7247783Seric ** Side Effects: 7257890Seric ** none. 7267783Seric ** 7277783Seric ** Warning: 7287783Seric ** The return value is saved in local storage and should 7297783Seric ** be copied if it is to be reused. 7307783Seric */ 7317783Seric 7327783Seric char * 7337890Seric crackaddr(addr) 7347890Seric register char *addr; 7357783Seric { 7367783Seric register char *p; 73751379Seric register char c; 73851379Seric int cmtlev; 73956764Seric int realcmtlev; 74056764Seric int anglelev, realanglelev; 74151379Seric int copylev; 74251379Seric bool qmode; 74356764Seric bool realqmode; 74456764Seric bool skipping; 74551379Seric bool putgmac = FALSE; 74656735Seric bool quoteit = FALSE; 74764148Seric bool gotangle = FALSE; 74868756Seric bool gotcolon = FALSE; 74951379Seric register char *bp; 75056764Seric char *buflim; 75168756Seric char *bufhead; 75268756Seric char *addrhead; 75368528Seric static char buf[MAXNAME + 1]; 7547783Seric 7557783Seric if (tTd(33, 1)) 7567890Seric printf("crackaddr(%s)\n", addr); 7577783Seric 7588082Seric /* strip leading spaces */ 75958050Seric while (*addr != '\0' && isascii(*addr) && isspace(*addr)) 7608082Seric addr++; 7618082Seric 7627783Seric /* 76351379Seric ** Start by assuming we have no angle brackets. This will be 76451379Seric ** adjusted later if we find them. 7657783Seric */ 7667783Seric 76768756Seric bp = bufhead = buf; 76856764Seric buflim = &buf[sizeof buf - 5]; 76968756Seric p = addrhead = addr; 77056764Seric copylev = anglelev = realanglelev = cmtlev = realcmtlev = 0; 77156764Seric qmode = realqmode = FALSE; 77251379Seric 77351379Seric while ((c = *p++) != '\0') 7747783Seric { 77556764Seric /* 77656764Seric ** If the buffer is overful, go into a special "skipping" 77756764Seric ** mode that tries to keep legal syntax but doesn't actually 77856764Seric ** output things. 77956764Seric */ 7807783Seric 78156764Seric skipping = bp >= buflim; 78256735Seric 78356764Seric if (copylev > 0 && !skipping) 78456764Seric *bp++ = c; 78556735Seric 78651379Seric /* check for backslash escapes */ 78751379Seric if (c == '\\') 7887783Seric { 78958890Seric /* arrange to quote the address */ 79058890Seric if (cmtlev <= 0 && !qmode) 79158890Seric quoteit = TRUE; 79258890Seric 79351379Seric if ((c = *p++) == '\0') 7947783Seric { 79551379Seric /* too far */ 79651379Seric p--; 79751379Seric goto putg; 7987783Seric } 79956764Seric if (copylev > 0 && !skipping) 80051379Seric *bp++ = c; 80151379Seric goto putg; 8027783Seric } 8037783Seric 80451379Seric /* check for quoted strings */ 80564967Seric if (c == '"' && cmtlev <= 0) 8067783Seric { 80751379Seric qmode = !qmode; 80856764Seric if (copylev > 0 && !skipping) 80956764Seric realqmode = !realqmode; 81051379Seric continue; 8117783Seric } 81251379Seric if (qmode) 81351379Seric goto putg; 8147783Seric 81551379Seric /* check for comments */ 81651379Seric if (c == '(') 8177783Seric { 81851379Seric cmtlev++; 81956764Seric 82056764Seric /* allow space for closing paren */ 82156764Seric if (!skipping) 82256764Seric { 82356764Seric buflim--; 82456764Seric realcmtlev++; 82556764Seric if (copylev++ <= 0) 82656764Seric { 82756764Seric *bp++ = ' '; 82856764Seric *bp++ = c; 82956764Seric } 83056764Seric } 83151379Seric } 83251379Seric if (cmtlev > 0) 83351379Seric { 83451379Seric if (c == ')') 8357783Seric { 83651379Seric cmtlev--; 83751379Seric copylev--; 83856764Seric if (!skipping) 83956764Seric { 84056764Seric realcmtlev--; 84156764Seric buflim++; 84256764Seric } 8437783Seric } 8447783Seric continue; 8457783Seric } 84656764Seric else if (c == ')') 84756764Seric { 84856764Seric /* syntax error: unmatched ) */ 84965544Seric if (copylev > 0 && !skipping) 85056764Seric bp--; 85156764Seric } 8527783Seric 85368756Seric /* check for group: list; syntax */ 85468760Seric if (c == ':' && anglelev <= 0 && !gotcolon && !ColonOkInAddr) 85568756Seric { 85668756Seric register char *q; 85768756Seric 85868760Seric if (*p == ':') 85968760Seric { 86068760Seric /* special case -- :: syntax */ 86168760Seric if (cmtlev <= 0 && !qmode) 86268760Seric quoteit = TRUE; 86368760Seric if (copylev > 0 && !skipping) 86468760Seric { 86568760Seric *bp++ = c; 86668760Seric *bp++ = c; 86768760Seric } 86868760Seric p++; 86968760Seric goto putg; 87068760Seric } 87168760Seric 87268756Seric gotcolon = TRUE; 87368756Seric 87468760Seric bp = bufhead; 87568760Seric if (quoteit) 87668760Seric { 87768760Seric *bp++ = '"'; 87868760Seric 87968760Seric /* back up over the ':' and any spaces */ 88068760Seric --p; 88168760Seric while (isascii(*--p) && isspace(*p)) 88268760Seric continue; 88368756Seric p++; 88468760Seric } 88568756Seric for (q = addrhead; q < p; ) 88668756Seric { 88768756Seric c = *q++; 88868756Seric if (bp < buflim) 88968756Seric { 89068760Seric if (quoteit && c == '"') 89168760Seric *bp++ = '\\'; 89268756Seric *bp++ = c; 89368756Seric } 89468756Seric } 89568760Seric if (quoteit) 89668760Seric { 89768760Seric if (bp == &bufhead[1]) 89868760Seric bp--; 89968760Seric else 90068760Seric *bp++ = '"'; 90168760Seric while ((c = *p++) != ':') 90268760Seric { 90368760Seric if (bp < buflim) 90468760Seric *bp++ = c; 90568760Seric } 90668760Seric *bp++ = c; 90768760Seric } 90868760Seric 90968760Seric /* any trailing white space is part of group: */ 91068760Seric while (isascii(*p) && isspace(*p) && bp < buflim) 91168760Seric *bp++ = *p++; 91268756Seric copylev = 0; 91368760Seric putgmac = quoteit = FALSE; 91468756Seric bufhead = bp; 91568756Seric addrhead = p; 91668756Seric continue; 91768756Seric } 91868756Seric 91968756Seric if (c == ';' && copylev <= 0 && !ColonOkInAddr) 92068756Seric { 92168756Seric if (bp < buflim) 92268756Seric *bp++ = c; 92368756Seric } 92468756Seric 92556764Seric /* check for characters that may have to be quoted */ 92664148Seric if (strchr(".'@,;:\\()[]", c) != NULL) 92756764Seric { 92856764Seric /* 92956764Seric ** If these occur as the phrase part of a <> 93056764Seric ** construct, but are not inside of () or already 93156764Seric ** quoted, they will have to be quoted. Note that 93256764Seric ** now (but don't actually do the quoting). 93356764Seric */ 93456764Seric 93556764Seric if (cmtlev <= 0 && !qmode) 93656764Seric quoteit = TRUE; 93756764Seric } 93856764Seric 93951379Seric /* check for angle brackets */ 94051379Seric if (c == '<') 94151379Seric { 94256735Seric register char *q; 94356735Seric 94464148Seric /* assume first of two angles is bogus */ 94564148Seric if (gotangle) 94664148Seric quoteit = TRUE; 94764148Seric gotangle = TRUE; 94864148Seric 94951379Seric /* oops -- have to change our mind */ 95064752Seric anglelev = 1; 95156764Seric if (!skipping) 95264752Seric realanglelev = 1; 95356764Seric 95468756Seric bp = bufhead; 95556735Seric if (quoteit) 95656735Seric { 95756735Seric *bp++ = '"'; 95856735Seric 95956735Seric /* back up over the '<' and any spaces */ 96056735Seric --p; 96158050Seric while (isascii(*--p) && isspace(*p)) 96256735Seric continue; 96356735Seric p++; 96456735Seric } 96568756Seric for (q = addrhead; q < p; ) 96656735Seric { 96756735Seric c = *q++; 96856764Seric if (bp < buflim) 96956764Seric { 97056764Seric if (quoteit && c == '"') 97156764Seric *bp++ = '\\'; 97256764Seric *bp++ = c; 97356764Seric } 97456735Seric } 97556735Seric if (quoteit) 97656735Seric { 97764148Seric if (bp == &buf[1]) 97864148Seric bp--; 97964148Seric else 98064148Seric *bp++ = '"'; 98156764Seric while ((c = *p++) != '<') 98256764Seric { 98356764Seric if (bp < buflim) 98456764Seric *bp++ = c; 98556764Seric } 98656764Seric *bp++ = c; 98756735Seric } 98851379Seric copylev = 0; 98956735Seric putgmac = quoteit = FALSE; 99051379Seric continue; 99151379Seric } 9927783Seric 99351379Seric if (c == '>') 9947783Seric { 99556764Seric if (anglelev > 0) 99656764Seric { 99756764Seric anglelev--; 99856764Seric if (!skipping) 99956764Seric { 100056764Seric realanglelev--; 100156764Seric buflim++; 100256764Seric } 100356764Seric } 100456764Seric else if (!skipping) 100556764Seric { 100656764Seric /* syntax error: unmatched > */ 100756764Seric if (copylev > 0) 100856764Seric bp--; 100964752Seric quoteit = TRUE; 101056764Seric continue; 101156764Seric } 101251379Seric if (copylev++ <= 0) 101351379Seric *bp++ = c; 101451379Seric continue; 10157783Seric } 101651379Seric 101751379Seric /* must be a real address character */ 101851379Seric putg: 101951379Seric if (copylev <= 0 && !putgmac) 102051379Seric { 102158050Seric *bp++ = MACROEXPAND; 102251379Seric *bp++ = 'g'; 102351379Seric putgmac = TRUE; 102451379Seric } 10257783Seric } 10267783Seric 102756764Seric /* repair any syntactic damage */ 102856764Seric if (realqmode) 102956764Seric *bp++ = '"'; 103056764Seric while (realcmtlev-- > 0) 103156764Seric *bp++ = ')'; 103256764Seric while (realanglelev-- > 0) 103356764Seric *bp++ = '>'; 103451379Seric *bp++ = '\0'; 10357783Seric 10367783Seric if (tTd(33, 1)) 10377944Seric printf("crackaddr=>`%s'\n", buf); 10387783Seric 10397783Seric return (buf); 10407783Seric } 10419382Seric /* 10429382Seric ** PUTHEADER -- put the header part of a message from the in-core copy 10439382Seric ** 10449382Seric ** Parameters: 104565870Seric ** mci -- the connection information. 104667546Seric ** h -- the header to put. 10479382Seric ** e -- envelope to use. 10489382Seric ** 10499382Seric ** Returns: 10509382Seric ** none. 10519382Seric ** 10529382Seric ** Side Effects: 10539382Seric ** none. 10549382Seric */ 10559382Seric 105657589Seric /* 105757589Seric * Macro for fast max (not available in e.g. DG/UX, 386/ix). 105857589Seric */ 105957589Seric #ifndef MAX 106057589Seric # define MAX(a,b) (((a)>(b))?(a):(b)) 106157589Seric #endif 106257589Seric 106369748Seric void 106468228Seric putheader(mci, h, e) 106565870Seric register MCI *mci; 106667546Seric register HDR *h; 10679382Seric register ENVELOPE *e; 10689382Seric { 106957135Seric char buf[MAX(MAXLINE,BUFSIZ)]; 107057135Seric char obuf[MAXLINE]; 10719382Seric 107259882Seric if (tTd(34, 1)) 107365870Seric printf("--- putheader, mailer = %s ---\n", 107465870Seric mci->mci_mailer->m_name); 107559882Seric 107667546Seric mci->mci_flags |= MCIF_INHEADER; 107767546Seric for (; h != NULL; h = h->h_link) 10789382Seric { 107969474Seric register char *p = h->h_value; 108010689Seric extern bool bitintersect(); 10819382Seric 108259882Seric if (tTd(34, 11)) 108359882Seric { 108459882Seric printf(" %s: ", h->h_field); 108569474Seric xputs(p); 108659882Seric } 108759882Seric 108869281Seric /* suppress Content-Transfer-Encoding: if we are MIMEing */ 108969281Seric if (bitset(H_CTE, h->h_flags) && 109069281Seric bitset(MCIF_CVT8TO7|MCIF_INMIME, mci->mci_flags)) 109169281Seric { 109269281Seric if (tTd(34, 11)) 109369281Seric printf(" (skipped (content-transfer-encoding))\n"); 109469281Seric continue; 109569281Seric } 109669281Seric 109769281Seric if (bitset(MCIF_INMIME, mci->mci_flags)) 109869281Seric goto vanilla; 109969281Seric 11009382Seric if (bitset(H_CHECK|H_ACHECK, h->h_flags) && 110165870Seric !bitintersect(h->h_mflags, mci->mci_mailer->m_flags)) 110259882Seric { 110359882Seric if (tTd(34, 11)) 110459882Seric printf(" (skipped)\n"); 11059382Seric continue; 110659882Seric } 11079382Seric 110811414Seric /* handle Resent-... headers specially */ 110911414Seric if (bitset(H_RESENT, h->h_flags) && !bitset(EF_RESENT, e->e_flags)) 111059882Seric { 111159882Seric if (tTd(34, 11)) 111259882Seric printf(" (skipped (resent))\n"); 111311414Seric continue; 111459882Seric } 111511414Seric 111666784Seric /* suppress return receipts if requested */ 111766784Seric if (bitset(H_RECEIPTTO, h->h_flags) && 111866784Seric bitset(EF_NORECEIPT, e->e_flags)) 111966784Seric { 112066784Seric if (tTd(34, 11)) 112166784Seric printf(" (skipped (receipt))\n"); 112266784Seric continue; 112366784Seric } 112466784Seric 112565152Seric /* macro expand value if generated internally */ 11269382Seric if (bitset(H_DEFAULT, h->h_flags)) 11279382Seric { 112868529Seric expand(p, buf, sizeof buf, e); 11299382Seric p = buf; 11309382Seric if (p == NULL || *p == '\0') 113165152Seric { 113265152Seric if (tTd(34, 11)) 113365152Seric printf(" (skipped -- null value)\n"); 11349382Seric continue; 113565152Seric } 11369382Seric } 11379382Seric 113865152Seric if (tTd(34, 11)) 113965152Seric printf("\n"); 114065152Seric 114168449Seric if (bitset(H_STRIPVAL, h->h_flags)) 11429382Seric { 114368449Seric /* empty field */ 114468449Seric (void) sprintf(obuf, "%s:", h->h_field); 114568449Seric putline(obuf, mci); 114668449Seric } 114768449Seric else if (bitset(H_FROM|H_RCPT, h->h_flags)) 114868449Seric { 11499382Seric /* address field */ 11509382Seric bool oldstyle = bitset(EF_OLDSTYLE, e->e_flags); 11519382Seric 11529382Seric if (bitset(H_FROM, h->h_flags)) 11539382Seric oldstyle = FALSE; 115465870Seric commaize(h, p, oldstyle, mci, e); 11559382Seric } 11569382Seric else 11579382Seric { 11589382Seric /* vanilla header line */ 115912159Seric register char *nlp; 116012159Seric 116169281Seric vanilla: 116259579Seric (void) sprintf(obuf, "%s: ", h->h_field); 116356795Seric while ((nlp = strchr(p, '\n')) != NULL) 116412159Seric { 116512159Seric *nlp = '\0'; 116612159Seric (void) strcat(obuf, p); 116712159Seric *nlp = '\n'; 116865870Seric putline(obuf, mci); 116912159Seric p = ++nlp; 117012161Seric obuf[0] = '\0'; 117112159Seric } 117212159Seric (void) strcat(obuf, p); 117365870Seric putline(obuf, mci); 11749382Seric } 11759382Seric } 117667887Seric 117767887Seric /* 117867887Seric ** If we are converting this to a MIME message, add the 117967889Seric ** MIME headers. 118067887Seric */ 118167887Seric 118269480Seric #if MIME8TO7 118367887Seric if (bitset(MM_MIME8BIT, MimeMode) && 118467887Seric bitset(EF_HAS8BIT, e->e_flags) && 118567887Seric !bitnset(M_8BITS, mci->mci_mailer->m_flags) && 118667889Seric !bitset(MCIF_CVT8TO7, mci->mci_flags)) 118767887Seric { 118867889Seric if (hvalue("MIME-Version", e->e_header) == NULL) 118967889Seric putline("MIME-Version: 1.0", mci); 119067889Seric if (hvalue("Content-Type", e->e_header) == NULL) 119167889Seric { 119267889Seric sprintf(obuf, "Content-Type: text/plain; charset=%s", 119367896Seric defcharset(e)); 119467889Seric putline(obuf, mci); 119567889Seric } 119667889Seric if (hvalue("Content-Transfer-Encoding", e->e_header) == NULL) 119767889Seric putline("Content-Transfer-Encoding: 8bit", mci); 119867887Seric } 119969480Seric #endif 12009382Seric } 12019382Seric /* 12029382Seric ** COMMAIZE -- output a header field, making a comma-translated list. 12039382Seric ** 12049382Seric ** Parameters: 12059382Seric ** h -- the header field to output. 12069382Seric ** p -- the value to put in it. 12079382Seric ** oldstyle -- TRUE if this is an old style header. 120865870Seric ** mci -- the connection information. 120955012Seric ** e -- the envelope containing the message. 12109382Seric ** 12119382Seric ** Returns: 12129382Seric ** none. 12139382Seric ** 12149382Seric ** Side Effects: 12159382Seric ** outputs "p" to file "fp". 12169382Seric */ 12179382Seric 121865870Seric void 121965870Seric commaize(h, p, oldstyle, mci, e) 12209382Seric register HDR *h; 12219382Seric register char *p; 12229382Seric bool oldstyle; 122365870Seric register MCI *mci; 122455012Seric register ENVELOPE *e; 12259382Seric { 12269382Seric register char *obp; 12279382Seric int opos; 122866004Seric int omax; 12299382Seric bool firstone = TRUE; 123011157Seric char obuf[MAXLINE + 3]; 12319382Seric 12329382Seric /* 12339382Seric ** Output the address list translated by the 12349382Seric ** mailer and with commas. 12359382Seric */ 12369382Seric 12379382Seric if (tTd(14, 2)) 12389382Seric printf("commaize(%s: %s)\n", h->h_field, p); 12399382Seric 12409382Seric obp = obuf; 124159579Seric (void) sprintf(obp, "%s: ", h->h_field); 12429382Seric opos = strlen(h->h_field) + 2; 12439382Seric obp += opos; 124466254Seric omax = mci->mci_mailer->m_linelimit - 2; 124566254Seric if (omax < 0 || omax > 78) 124666254Seric omax = 78; 12479382Seric 12489382Seric /* 12499382Seric ** Run through the list of values. 12509382Seric */ 12519382Seric 12529382Seric while (*p != '\0') 12539382Seric { 12549382Seric register char *name; 125554983Seric register int c; 12569382Seric char savechar; 125759163Seric int flags; 125859163Seric auto int stat; 12599382Seric 12609382Seric /* 12619382Seric ** Find the end of the name. New style names 12629382Seric ** end with a comma, old style names end with 12639382Seric ** a space character. However, spaces do not 12649382Seric ** necessarily delimit an old-style name -- at 12659382Seric ** signs mean keep going. 12669382Seric */ 12679382Seric 12689382Seric /* find end of name */ 126958050Seric while ((isascii(*p) && isspace(*p)) || *p == ',') 12709382Seric p++; 12719382Seric name = p; 12729382Seric for (;;) 12739382Seric { 127458333Seric auto char *oldp; 127516909Seric char pvpbuf[PSBUFSIZE]; 12769382Seric 127765066Seric (void) prescan(p, oldstyle ? ' ' : ',', pvpbuf, 127868711Seric sizeof pvpbuf, &oldp, NULL); 127958333Seric p = oldp; 12809382Seric 12819382Seric /* look to see if we have an at sign */ 128258050Seric while (*p != '\0' && isascii(*p) && isspace(*p)) 12839382Seric p++; 12849382Seric 128558170Seric if (*p != '@') 12869382Seric { 12879382Seric p = oldp; 12889382Seric break; 12899382Seric } 12909382Seric p += *p == '@' ? 1 : 2; 129158050Seric while (*p != '\0' && isascii(*p) && isspace(*p)) 12929382Seric p++; 12939382Seric } 12949382Seric /* at the end of one complete name */ 12959382Seric 12969382Seric /* strip off trailing white space */ 129758050Seric while (p >= name && 129858050Seric ((isascii(*p) && isspace(*p)) || *p == ',' || *p == '\0')) 12999382Seric p--; 13009382Seric if (++p == name) 13019382Seric continue; 13029382Seric savechar = *p; 13039382Seric *p = '\0'; 13049382Seric 13059382Seric /* translate the name to be relative */ 130659163Seric flags = RF_HEADERADDR|RF_ADDDOMAIN; 130759163Seric if (bitset(H_FROM, h->h_flags)) 130859163Seric flags |= RF_SENDERADDR; 130969713Seric #if USERDB 131068522Seric else if (e->e_from.q_mailer != NULL && 131168522Seric bitnset(M_UDBRECIPIENT, e->e_from.q_mailer->m_flags)) 131268522Seric { 131368522Seric extern char *udbsender(); 131468522Seric 131568522Seric name = udbsender(name); 131668522Seric } 131768522Seric #endif 131859163Seric stat = EX_OK; 131965870Seric name = remotename(name, mci->mci_mailer, flags, &stat, e); 13209382Seric if (*name == '\0') 13219382Seric { 13229382Seric *p = savechar; 13239382Seric continue; 13249382Seric } 13259382Seric 13269382Seric /* output the name with nice formatting */ 132754983Seric opos += strlen(name); 13289382Seric if (!firstone) 13299382Seric opos += 2; 133066004Seric if (opos > omax && !firstone) 13319382Seric { 133210178Seric (void) strcpy(obp, ",\n"); 133365870Seric putline(obuf, mci); 13349382Seric obp = obuf; 133566255Seric (void) strcpy(obp, " "); 133610161Seric opos = strlen(obp); 133710161Seric obp += opos; 133854983Seric opos += strlen(name); 13399382Seric } 13409382Seric else if (!firstone) 13419382Seric { 134266255Seric (void) strcpy(obp, ", "); 13439382Seric obp += 2; 13449382Seric } 13459382Seric 134654983Seric while ((c = *name++) != '\0' && obp < &obuf[MAXLINE]) 134754983Seric *obp++ = c; 13489382Seric firstone = FALSE; 13499382Seric *p = savechar; 13509382Seric } 13519382Seric (void) strcpy(obp, "\n"); 135265870Seric putline(obuf, mci); 13539382Seric } 13549382Seric /* 135558170Seric ** COPYHEADER -- copy header list 13569382Seric ** 135758170Seric ** This routine is the equivalent of newstr for header lists 135858170Seric ** 13599382Seric ** Parameters: 136058170Seric ** header -- list of header structures to copy. 13619382Seric ** 13629382Seric ** Returns: 136358170Seric ** a copy of 'header'. 13649382Seric ** 13659382Seric ** Side Effects: 13669382Seric ** none. 13679382Seric */ 13689382Seric 136958170Seric HDR * 137058170Seric copyheader(header) 137158170Seric register HDR *header; 13729382Seric { 137358170Seric register HDR *newhdr; 137458170Seric HDR *ret; 137558170Seric register HDR **tail = &ret; 13769382Seric 137758170Seric while (header != NULL) 137858170Seric { 137958170Seric newhdr = (HDR *) xalloc(sizeof(HDR)); 138058170Seric STRUCTCOPY(*header, *newhdr); 138158170Seric *tail = newhdr; 138258170Seric tail = &newhdr->h_link; 138358170Seric header = header->h_link; 138458170Seric } 138558170Seric *tail = NULL; 138658170Seric 138758170Seric return ret; 13889382Seric } 1389