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*69726Seric static char sccsid[] = "@(#)headers.c 8.66 (Berkeley) 05/27/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 3568717Seric chompheader(line, def, hdrp, e) 364091Seric char *line; 374091Seric bool def; 3868717Seric HDR **hdrp; 3955012Seric register ENVELOPE *e; 404091Seric { 414091Seric register char *p; 424091Seric register HDR *h; 434091Seric HDR **hp; 444091Seric char *fname; 454091Seric char *fvalue; 464091Seric struct hdrinfo *hi; 479059Seric bool cond = FALSE; 4868717Seric bool headeronly; 4910689Seric BITMAP mopts; 5068528Seric char buf[MAXNAME + 1]; 514091Seric 527677Seric if (tTd(31, 6)) 5368812Seric { 5468812Seric printf("chompheader: "); 5568812Seric xputs(line); 5668812Seric printf("\n"); 5768812Seric } 587677Seric 5968717Seric headeronly = hdrp != NULL; 6068717Seric if (!headeronly) 6168717Seric hdrp = &e->e_header; 6268717Seric 634627Seric /* strip off options */ 6410689Seric clrbitmap(mopts); 654627Seric p = line; 6657405Seric if (*p == '?') 674627Seric { 684627Seric /* have some */ 6956795Seric register char *q = strchr(p + 1, *p); 704627Seric 714627Seric if (q != NULL) 724627Seric { 734627Seric *q++ = '\0'; 7410689Seric while (*++p != '\0') 7510689Seric setbitn(*p, mopts); 764627Seric p = q; 774627Seric } 784627Seric else 7968690Seric syserr("553 header syntax error, line \"%s\"", line); 809059Seric cond = TRUE; 814627Seric } 824627Seric 834091Seric /* find canonical name */ 844627Seric fname = p; 8564149Seric while (isascii(*p) && isgraph(*p) && *p != ':') 8664149Seric p++; 8764149Seric fvalue = p; 8864149Seric while (isascii(*p) && isspace(*p)) 8964149Seric p++; 9064150Seric if (*p++ != ':' || fname == fvalue) 9110118Seric { 9258151Seric syserr("553 header syntax error, line \"%s\"", line); 9310118Seric return (0); 9410118Seric } 9564149Seric *fvalue = '\0'; 9664149Seric fvalue = p; 974091Seric 984091Seric /* strip field value on front */ 994091Seric if (*fvalue == ' ') 1004091Seric fvalue++; 1014091Seric 1024091Seric /* see if it is a known type */ 1034091Seric for (hi = HdrInfo; hi->hi_field != NULL; hi++) 1044091Seric { 10559579Seric if (strcasecmp(hi->hi_field, fname) == 0) 1064091Seric break; 1074091Seric } 1084091Seric 10964283Seric if (tTd(31, 9)) 11064283Seric { 11164283Seric if (hi->hi_field == NULL) 11264283Seric printf("no header match\n"); 11364283Seric else 11467694Seric printf("header match, hi_flags=%x\n", hi->hi_flags); 11564283Seric } 11664283Seric 11711414Seric /* see if this is a resent message */ 11868717Seric if (!def && !headeronly && bitset(H_RESENT, hi->hi_flags)) 11955012Seric e->e_flags |= EF_RESENT; 12011414Seric 12168558Seric /* if this is an Errors-To: header keep track of it now */ 12268717Seric if (UseErrorsTo && !def && !headeronly && 12368717Seric bitset(H_ERRORSTO, hi->hi_flags)) 12468558Seric (void) sendtolist(fvalue, NULLADDR, &e->e_errorqueue, 0, e); 12568558Seric 1264091Seric /* if this means "end of header" quit now */ 1274091Seric if (bitset(H_EOH, hi->hi_flags)) 1284091Seric return (hi->hi_flags); 1294091Seric 13064653Seric /* 13164653Seric ** Drop explicit From: if same as what we would generate. 13264653Seric ** This is to make MH (which doesn't always give a full name) 13364653Seric ** insert the full name information in all circumstances. 13464653Seric */ 13564653Seric 13614784Seric p = "resent-from"; 13755012Seric if (!bitset(EF_RESENT, e->e_flags)) 13814784Seric p += 7; 13968717Seric if (!def && !headeronly && !bitset(EF_QUEUERUN, e->e_flags) && 14068717Seric strcasecmp(fname, p) == 0) 14111414Seric { 14263753Seric if (tTd(31, 2)) 14363753Seric { 14463753Seric printf("comparing header from (%s) against default (%s or %s)\n", 14563753Seric fvalue, e->e_from.q_paddr, e->e_from.q_user); 14663753Seric } 14755012Seric if (e->e_from.q_paddr != NULL && 14863753Seric (strcmp(fvalue, e->e_from.q_paddr) == 0 || 14963753Seric strcmp(fvalue, e->e_from.q_user) == 0)) 15011414Seric return (hi->hi_flags); 15164351Seric #ifdef MAYBENEXTRELEASE /* XXX UNTESTED XXX UNTESTED XXX UNTESTED XXX */ 15269713Seric #if USERDB 15364351Seric else 15464351Seric { 15564351Seric auto ADDRESS a; 15664351Seric char *fancy; 15766123Seric bool oldSuprErrs = SuprErrs; 15864351Seric extern char *crackaddr(); 15964351Seric extern char *udbsender(); 16064351Seric 16164653Seric /* 16264653Seric ** Try doing USERDB rewriting even on fully commented 16364653Seric ** names; this saves the "comment" information (such 16464653Seric ** as full name) and rewrites the electronic part. 16566106Seric ** 16666106Seric ** XXX This code doesn't belong here -- parsing should 16766106Seric ** XXX not be done during collect() phase because 16866106Seric ** XXX error messages can confuse the SMTP phase. 16966123Seric ** XXX Setting SuprErrs is a crude hack around this 17066106Seric ** XXX problem. 17164653Seric */ 17264653Seric 17366106Seric if (OpMode == MD_SMTP || OpMode == MD_ARPAFTP) 17466123Seric SuprErrs = TRUE; 17564351Seric fancy = crackaddr(fvalue); 17664351Seric if (parseaddr(fvalue, &a, RF_COPYNONE, '\0', NULL, e) != NULL && 17767472Seric bitnset(M_CHECKUDB, a.q_mailer->m_flags) && 17864351Seric (p = udbsender(a.q_user)) != NULL) 17964351Seric { 18064351Seric char *oldg = macvalue('g', e); 18164351Seric 18264351Seric define('g', p, e); 18368529Seric expand(fancy, buf, sizeof buf, e); 18464351Seric define('g', oldg, e); 18564351Seric fvalue = buf; 18664351Seric } 18766123Seric SuprErrs = oldSuprErrs; 18864351Seric } 18964351Seric #endif 19064351Seric #endif 19111414Seric } 19211414Seric 19314784Seric /* delete default value for this header */ 19468717Seric for (hp = hdrp; (h = *hp) != NULL; hp = &h->h_link) 19514784Seric { 19659579Seric if (strcasecmp(fname, h->h_field) == 0 && 19714784Seric bitset(H_DEFAULT, h->h_flags) && 19814784Seric !bitset(H_FORCE, h->h_flags)) 199*69726Seric { 20014784Seric h->h_value = NULL; 201*69726Seric if (!cond) 202*69726Seric { 203*69726Seric /* copy conditions from default case */ 204*69726Seric bcopy((char *)h->h_mflags, (char *)mopts, 205*69726Seric sizeof mopts); 206*69726Seric } 207*69726Seric } 20814784Seric } 20914784Seric 21013012Seric /* create a new node */ 21113012Seric h = (HDR *) xalloc(sizeof *h); 21213012Seric h->h_field = newstr(fname); 21364134Seric h->h_value = newstr(fvalue); 21413012Seric h->h_link = NULL; 21523117Seric bcopy((char *) mopts, (char *) h->h_mflags, sizeof mopts); 21613012Seric *hp = h; 2178066Seric h->h_flags = hi->hi_flags; 2184091Seric if (def) 2194091Seric h->h_flags |= H_DEFAULT; 2209059Seric if (cond) 2219059Seric h->h_flags |= H_CHECK; 2224091Seric 2235937Seric /* hack to see if this is a new format message */ 22468717Seric if (!def && !headeronly && bitset(H_RCPT|H_FROM, h->h_flags) && 22556795Seric (strchr(fvalue, ',') != NULL || strchr(fvalue, '(') != NULL || 22656795Seric strchr(fvalue, '<') != NULL || strchr(fvalue, ';') != NULL)) 2278089Seric { 22855012Seric e->e_flags &= ~EF_OLDSTYLE; 2298089Seric } 2305937Seric 2314091Seric return (h->h_flags); 2324091Seric } 2334091Seric /* 2346980Seric ** ADDHEADER -- add a header entry to the end of the queue. 2356980Seric ** 2366980Seric ** This bypasses the special checking of chompheader. 2376980Seric ** 2386980Seric ** Parameters: 23959579Seric ** field -- the name of the header field. 24058789Seric ** value -- the value of the field. 24167546Seric ** hp -- an indirect pointer to the header structure list. 2426980Seric ** 2436980Seric ** Returns: 2446980Seric ** none. 2456980Seric ** 2466980Seric ** Side Effects: 2476980Seric ** adds the field on the list of headers for this envelope. 2486980Seric */ 2496980Seric 25067546Seric addheader(field, value, hdrlist) 2516980Seric char *field; 2526980Seric char *value; 25367546Seric HDR **hdrlist; 2546980Seric { 2556980Seric register HDR *h; 2566980Seric register struct hdrinfo *hi; 2576980Seric HDR **hp; 2586980Seric 2596980Seric /* find info struct */ 2606980Seric for (hi = HdrInfo; hi->hi_field != NULL; hi++) 2616980Seric { 26259579Seric if (strcasecmp(field, hi->hi_field) == 0) 2636980Seric break; 2646980Seric } 2656980Seric 2666980Seric /* find current place in list -- keep back pointer? */ 26767546Seric for (hp = hdrlist; (h = *hp) != NULL; hp = &h->h_link) 2686980Seric { 26959579Seric if (strcasecmp(field, h->h_field) == 0) 2706980Seric break; 2716980Seric } 2726980Seric 2736980Seric /* allocate space for new header */ 2746980Seric h = (HDR *) xalloc(sizeof *h); 2756980Seric h->h_field = field; 2766980Seric h->h_value = newstr(value); 2777368Seric h->h_link = *hp; 2786980Seric h->h_flags = hi->hi_flags | H_DEFAULT; 27910689Seric clrbitmap(h->h_mflags); 2806980Seric *hp = h; 2816980Seric } 2826980Seric /* 2834091Seric ** HVALUE -- return value of a header. 2844091Seric ** 2854091Seric ** Only "real" fields (i.e., ones that have not been supplied 2864091Seric ** as a default) are used. 2874091Seric ** 2884091Seric ** Parameters: 2894091Seric ** field -- the field name. 29067546Seric ** header -- the header list. 2914091Seric ** 2924091Seric ** Returns: 2934091Seric ** pointer to the value part. 2944091Seric ** NULL if not found. 2954091Seric ** 2964091Seric ** Side Effects: 2979382Seric ** none. 2984091Seric */ 2994091Seric 3004091Seric char * 30167546Seric hvalue(field, header) 3024091Seric char *field; 30367546Seric HDR *header; 3044091Seric { 3054091Seric register HDR *h; 3064091Seric 30767546Seric for (h = header; h != NULL; h = h->h_link) 3084091Seric { 30959579Seric if (!bitset(H_DEFAULT, h->h_flags) && 31059579Seric strcasecmp(h->h_field, field) == 0) 3114091Seric return (h->h_value); 3124091Seric } 3134091Seric return (NULL); 3144091Seric } 3154091Seric /* 3164091Seric ** ISHEADER -- predicate telling if argument is a header. 3174091Seric ** 3184319Seric ** A line is a header if it has a single word followed by 3194319Seric ** optional white space followed by a colon. 3204319Seric ** 32168717Seric ** Header fields beginning with two dashes, although technically 32268717Seric ** permitted by RFC822, are automatically rejected in order 32368717Seric ** to make MIME work out. Without this we could have a technically 32468717Seric ** legal header such as ``--"foo:bar"'' that would also be a legal 32568717Seric ** MIME separator. 32668717Seric ** 3274091Seric ** Parameters: 32868690Seric ** h -- string to check for possible headerness. 3294091Seric ** 3304091Seric ** Returns: 33168690Seric ** TRUE if h is a header. 3324091Seric ** FALSE otherwise. 3334091Seric ** 3344091Seric ** Side Effects: 3354091Seric ** none. 3364091Seric */ 3374091Seric 3384091Seric bool 33968690Seric isheader(h) 34068690Seric char *h; 3414091Seric { 34268690Seric register char *s = h; 34368690Seric 34468717Seric if (s[0] == '-' && s[1] == '-') 34568717Seric return FALSE; 34668717Seric 3479382Seric while (*s > ' ' && *s != ':' && *s != '\0') 3484091Seric s++; 3499382Seric 35068690Seric if (h == s) 35168690Seric return FALSE; 35268690Seric 3539382Seric /* following technically violates RFC822 */ 35458050Seric while (isascii(*s) && isspace(*s)) 3554091Seric s++; 3569382Seric 3574091Seric return (*s == ':'); 3584091Seric } 3595919Seric /* 3607783Seric ** EATHEADER -- run through the stored header and extract info. 3617783Seric ** 3627783Seric ** Parameters: 3639382Seric ** e -- the envelope to process. 36458929Seric ** full -- if set, do full processing (e.g., compute 36569683Seric ** message priority). This should not be set 36669683Seric ** when reading a queue file because some info 36769683Seric ** needed to compute the priority is wrong. 3687783Seric ** 3697783Seric ** Returns: 3707783Seric ** none. 3717783Seric ** 3727783Seric ** Side Effects: 3737783Seric ** Sets a bunch of global variables from information 3749382Seric ** in the collected header. 3759382Seric ** Aborts the message if the hop count is exceeded. 3767783Seric */ 3777783Seric 37858929Seric eatheader(e, full) 3799382Seric register ENVELOPE *e; 38058929Seric bool full; 3817783Seric { 3827783Seric register HDR *h; 3837783Seric register char *p; 3849382Seric int hopcnt = 0; 38557208Seric char *msgid; 38658688Seric char buf[MAXLINE]; 3877783Seric 38858688Seric /* 38958688Seric ** Set up macros for possible expansion in headers. 39058688Seric */ 39158688Seric 39258704Seric define('f', e->e_sender, e); 39358704Seric define('g', e->e_sender, e); 39464148Seric if (e->e_origrcpt != NULL && *e->e_origrcpt != '\0') 39564148Seric define('u', e->e_origrcpt, e); 39664148Seric else 39764148Seric define('u', NULL, e); 39858688Seric 39965052Seric /* full name of from person */ 40067546Seric p = hvalue("full-name", e->e_header); 40165052Seric if (p != NULL) 40265052Seric define('x', p, e); 40365052Seric 4049382Seric if (tTd(32, 1)) 4059382Seric printf("----- collected header -----\n"); 40669683Seric msgid = NULL; 4079382Seric for (h = e->e_header; h != NULL; h = h->h_link) 4087783Seric { 40964156Seric if (h->h_value == NULL) 41064156Seric { 41164156Seric if (tTd(32, 1)) 41264156Seric printf("%s: <NULL>\n", h->h_field); 41364156Seric continue; 41464156Seric } 41564156Seric 41658688Seric /* do early binding */ 41764156Seric if (bitset(H_DEFAULT, h->h_flags)) 41858688Seric { 41968529Seric expand(h->h_value, buf, sizeof buf, e); 42058688Seric if (buf[0] != '\0') 42158688Seric { 42258688Seric h->h_value = newstr(buf); 42358688Seric h->h_flags &= ~H_DEFAULT; 42458688Seric } 42558688Seric } 42658688Seric 4279382Seric if (tTd(32, 1)) 42865152Seric { 42965152Seric printf("%s: ", h->h_field); 43065152Seric xputs(h->h_value); 43165152Seric printf("\n"); 43265152Seric } 43357359Seric 43411414Seric /* count the number of times it has been processed */ 4359382Seric if (bitset(H_TRACE, h->h_flags)) 4369382Seric hopcnt++; 43711414Seric 43811414Seric /* send to this person if we so desire */ 43911414Seric if (GrabTo && bitset(H_RCPT, h->h_flags) && 44011414Seric !bitset(H_DEFAULT, h->h_flags) && 44155012Seric (!bitset(EF_RESENT, e->e_flags) || bitset(H_RESENT, h->h_flags))) 44211414Seric { 44363839Seric int saveflags = e->e_flags; 44463839Seric 44564283Seric (void) sendtolist(h->h_value, NULLADDR, 44667982Seric &e->e_sendqueue, 0, e); 44763839Seric 44863839Seric /* delete fatal errors generated by this address */ 44964148Seric if (!GrabTo && !bitset(EF_FATALERRS, saveflags)) 45063839Seric e->e_flags &= ~EF_FATALERRS; 45111414Seric } 45211414Seric 45357208Seric /* save the message-id for logging */ 45469683Seric if (strcasecmp(h->h_field, "message-id") == 0) 45511290Seric { 45657208Seric msgid = h->h_value; 45759859Seric while (isascii(*msgid) && isspace(*msgid)) 45859859Seric msgid++; 45911290Seric } 46057359Seric 46157359Seric /* see if this is a return-receipt header */ 46257359Seric if (bitset(H_RECEIPTTO, h->h_flags)) 46357359Seric e->e_receiptto = h->h_value; 4649382Seric } 4659382Seric if (tTd(32, 1)) 4667783Seric printf("----------------------------\n"); 4677783Seric 46858145Seric /* if we are just verifying (that is, sendmail -t -bv), drop out now */ 46958145Seric if (OpMode == MD_VERIFY) 47058145Seric return; 47158145Seric 4729382Seric /* store hop count */ 4739382Seric if (hopcnt > e->e_hopcount) 4749382Seric e->e_hopcount = hopcnt; 4759382Seric 4767783Seric /* message priority */ 47767546Seric p = hvalue("precedence", e->e_header); 4789382Seric if (p != NULL) 4799382Seric e->e_class = priencode(p); 48069683Seric if (e->e_class < 0) 48169683Seric e->e_timeoutclass = TOC_NONURGENT; 48269683Seric else if (e->e_class > 0) 48369683Seric e->e_timeoutclass = TOC_URGENT; 48458929Seric if (full) 48567730Seric { 48625013Seric e->e_msgpriority = e->e_msgsize 48724981Seric - e->e_class * WkClassFact 48824981Seric + e->e_nrcpts * WkRecipFact; 48967730Seric } 4907783Seric 49167730Seric /* message timeout priority */ 49267730Seric p = hvalue("priority", e->e_header); 49369683Seric if (p != NULL) 49467730Seric { 49567730Seric /* (this should be in the configuration file) */ 49667730Seric if (strcasecmp(p, "urgent")) 49767730Seric e->e_timeoutclass = TOC_URGENT; 49867730Seric else if (strcasecmp(p, "normal")) 49967730Seric e->e_timeoutclass = TOC_NORMAL; 50067730Seric else if (strcasecmp(p, "non-urgent")) 50167730Seric e->e_timeoutclass = TOC_NONURGENT; 50267730Seric } 50367730Seric 5047783Seric /* date message originated */ 50567546Seric p = hvalue("posted-date", e->e_header); 5067783Seric if (p == NULL) 50767546Seric p = hvalue("date", e->e_header); 5087783Seric if (p != NULL) 5099382Seric define('a', p, e); 51011290Seric 51168884Seric /* check to see if this is a MIME message */ 51269105Seric if ((e->e_bodytype != NULL && 51369105Seric strcasecmp(e->e_bodytype, "8BITMIME") == 0) || 51468884Seric hvalue("MIME-Version", e->e_header) != NULL) 51569105Seric { 51668884Seric e->e_flags |= EF_IS_MIME; 51769105Seric if (HasEightBits) 51869105Seric e->e_bodytype = "8BITMIME"; 51969105Seric } 52068884Seric 52111290Seric /* 52265983Seric ** From person in antiquated ARPANET mode 52365983Seric ** required by UK Grey Book e-mail gateways (sigh) 52465983Seric */ 52565983Seric 52665983Seric if (OpMode == MD_ARPAFTP) 52765983Seric { 52865983Seric register struct hdrinfo *hi; 52965983Seric 53065983Seric for (hi = HdrInfo; hi->hi_field != NULL; hi++) 53165983Seric { 53265983Seric if (bitset(H_FROM, hi->hi_flags) && 53365983Seric (!bitset(H_RESENT, hi->hi_flags) || 53465983Seric bitset(EF_RESENT, e->e_flags)) && 53567546Seric (p = hvalue(hi->hi_field, e->e_header)) != NULL) 53665983Seric break; 53765983Seric } 53865983Seric if (hi->hi_field != NULL) 53965983Seric { 54065983Seric if (tTd(32, 2)) 54165983Seric printf("eatheader: setsender(*%s == %s)\n", 54265983Seric hi->hi_field, p); 54365983Seric setsender(p, e, NULL, TRUE); 54465983Seric } 54565983Seric } 54665983Seric 54765983Seric /* 54811290Seric ** Log collection information. 54911290Seric */ 55011290Seric 55111290Seric # ifdef LOG 55268036Seric if (bitset(EF_LOGSENDER, e->e_flags) && LogLevel > 4) 55365089Seric logsender(e, msgid); 55465089Seric # endif /* LOG */ 55565089Seric e->e_flags &= ~EF_LOGSENDER; 55665089Seric } 55765089Seric /* 55865089Seric ** LOGSENDER -- log sender information 55965089Seric ** 56065089Seric ** Parameters: 56165089Seric ** e -- the envelope to log 56265089Seric ** msgid -- the message id 56365089Seric ** 56465089Seric ** Returns: 56565089Seric ** none 56665089Seric */ 56765089Seric 56865089Seric logsender(e, msgid) 56965089Seric register ENVELOPE *e; 57065089Seric char *msgid; 57165089Seric { 57266748Seric # ifdef LOG 57365089Seric char *name; 57465089Seric register char *sbp; 57565089Seric register char *p; 57667901Seric int l; 57768528Seric char hbuf[MAXNAME + 1]; 57868528Seric char sbuf[MAXLINE + 1]; 57968528Seric char mbuf[MAXNAME + 1]; 58065089Seric 58167901Seric /* don't allow newlines in the message-id */ 58267901Seric if (msgid != NULL) 58367901Seric { 58467901Seric l = strlen(msgid); 58567901Seric if (l > sizeof mbuf - 1) 58667901Seric l = sizeof mbuf - 1; 58767901Seric bcopy(msgid, mbuf, l); 58867901Seric mbuf[l] = '\0'; 58967901Seric p = mbuf; 59067901Seric while ((p = strchr(p, '\n')) != NULL) 59167901Seric *p++ = ' '; 59267901Seric } 59367901Seric 59465089Seric if (bitset(EF_RESPONSE, e->e_flags)) 59565089Seric name = "[RESPONSE]"; 59665089Seric else if ((name = macvalue('_', e)) != NULL) 59765089Seric ; 59866003Seric else if (RealHostName == NULL) 59966003Seric name = "localhost"; 60065089Seric else if (RealHostName[0] == '[') 60165089Seric name = RealHostName; 60265089Seric else 60311290Seric { 60465089Seric name = hbuf; 60565089Seric (void) sprintf(hbuf, "%.80s", RealHostName); 60665089Seric if (RealHostAddr.sa.sa_family != 0) 60757359Seric { 60865089Seric p = &hbuf[strlen(hbuf)]; 60965089Seric (void) sprintf(p, " (%s)", 61065089Seric anynet_ntoa(&RealHostAddr)); 61157359Seric } 61265089Seric } 61357359Seric 61465089Seric /* some versions of syslog only take 5 printf args */ 61565059Seric # if (SYSLOG_BUFSIZE) >= 256 61665089Seric sbp = sbuf; 61765089Seric sprintf(sbp, "from=%.200s, size=%ld, class=%d, pri=%ld, nrcpts=%d", 61867788Seric e->e_from.q_paddr == NULL ? "<NONE>" : e->e_from.q_paddr, 61967788Seric e->e_msgsize, e->e_class, e->e_msgpriority, e->e_nrcpts); 62065089Seric sbp += strlen(sbp); 62165089Seric if (msgid != NULL) 62265089Seric { 62367901Seric sprintf(sbp, ", msgid=%.100s", mbuf); 62460575Seric sbp += strlen(sbp); 62565089Seric } 62665089Seric if (e->e_bodytype != NULL) 62765089Seric { 62865089Seric (void) sprintf(sbp, ", bodytype=%.20s", e->e_bodytype); 62965089Seric sbp += strlen(sbp); 63065089Seric } 63165089Seric p = macvalue('r', e); 63265089Seric if (p != NULL) 63365089Seric (void) sprintf(sbp, ", proto=%.20s", p); 63465089Seric syslog(LOG_INFO, "%s: %s, relay=%s", 63565089Seric e->e_id, sbuf, name); 63665059Seric 63765059Seric # else /* short syslog buffer */ 63865059Seric 63965089Seric syslog(LOG_INFO, "%s: from=%s", 64067788Seric e->e_id, e->e_from.q_paddr == NULL ? "<NONE>" : 64167788Seric shortenstring(e->e_from.q_paddr, 83)); 64265089Seric syslog(LOG_INFO, "%s: size=%ld, class=%ld, pri=%ld, nrcpts=%d", 64365089Seric e->e_id, e->e_msgsize, e->e_class, 64465089Seric e->e_msgpriority, e->e_nrcpts); 64565089Seric if (msgid != NULL) 64667901Seric syslog(LOG_INFO, "%s: msgid=%s", e->e_id, mbuf); 64765650Seric sbp = sbuf; 64865650Seric sprintf(sbp, "%s:", e->e_id); 64965650Seric sbp += strlen(sbp); 65065089Seric if (e->e_bodytype != NULL) 65165650Seric { 65265650Seric sprintf(sbp, " bodytype=%s,", e->e_bodytype); 65365650Seric sbp += strlen(sbp); 65465650Seric } 65565089Seric p = macvalue('r', e); 65665089Seric if (p != NULL) 65765650Seric { 65865731Seric sprintf(sbp, " proto=%s,", p); 65965650Seric sbp += strlen(sbp); 66065650Seric } 66165650Seric syslog(LOG_INFO, "%s relay=%s", sbuf, name); 66265059Seric # endif 66366748Seric # endif 6647783Seric } 6657783Seric /* 6667783Seric ** PRIENCODE -- encode external priority names into internal values. 6677783Seric ** 6687783Seric ** Parameters: 6697783Seric ** p -- priority in ascii. 6707783Seric ** 6717783Seric ** Returns: 6727783Seric ** priority as a numeric level. 6737783Seric ** 6747783Seric ** Side Effects: 6757783Seric ** none. 6767783Seric */ 6777783Seric 6787783Seric priencode(p) 6797783Seric char *p; 6807783Seric { 6818253Seric register int i; 6827783Seric 6838253Seric for (i = 0; i < NumPriorities; i++) 6847783Seric { 68533725Sbostic if (!strcasecmp(p, Priorities[i].pri_name)) 6868253Seric return (Priorities[i].pri_val); 6877783Seric } 6888253Seric 6898253Seric /* unknown priority */ 6908253Seric return (0); 6917783Seric } 6927783Seric /* 6937890Seric ** CRACKADDR -- parse an address and turn it into a macro 6947783Seric ** 6957783Seric ** This doesn't actually parse the address -- it just extracts 6967783Seric ** it and replaces it with "$g". The parse is totally ad hoc 6977783Seric ** and isn't even guaranteed to leave something syntactically 6987783Seric ** identical to what it started with. However, it does leave 6997783Seric ** something semantically identical. 7007783Seric ** 70151379Seric ** This algorithm has been cleaned up to handle a wider range 70251379Seric ** of cases -- notably quoted and backslash escaped strings. 70351379Seric ** This modification makes it substantially better at preserving 70451379Seric ** the original syntax. 7057783Seric ** 7067783Seric ** Parameters: 7077890Seric ** addr -- the address to be cracked. 7087783Seric ** 7097783Seric ** Returns: 7107783Seric ** a pointer to the new version. 7117783Seric ** 7127783Seric ** Side Effects: 7137890Seric ** none. 7147783Seric ** 7157783Seric ** Warning: 7167783Seric ** The return value is saved in local storage and should 7177783Seric ** be copied if it is to be reused. 7187783Seric */ 7197783Seric 7207783Seric char * 7217890Seric crackaddr(addr) 7227890Seric register char *addr; 7237783Seric { 7247783Seric register char *p; 72551379Seric register char c; 72651379Seric int cmtlev; 72756764Seric int realcmtlev; 72856764Seric int anglelev, realanglelev; 72951379Seric int copylev; 73051379Seric bool qmode; 73156764Seric bool realqmode; 73256764Seric bool skipping; 73351379Seric bool putgmac = FALSE; 73456735Seric bool quoteit = FALSE; 73564148Seric bool gotangle = FALSE; 73668756Seric bool gotcolon = FALSE; 73751379Seric register char *bp; 73856764Seric char *buflim; 73968756Seric char *bufhead; 74068756Seric char *addrhead; 74168528Seric static char buf[MAXNAME + 1]; 7427783Seric 7437783Seric if (tTd(33, 1)) 7447890Seric printf("crackaddr(%s)\n", addr); 7457783Seric 7468082Seric /* strip leading spaces */ 74758050Seric while (*addr != '\0' && isascii(*addr) && isspace(*addr)) 7488082Seric addr++; 7498082Seric 7507783Seric /* 75151379Seric ** Start by assuming we have no angle brackets. This will be 75251379Seric ** adjusted later if we find them. 7537783Seric */ 7547783Seric 75568756Seric bp = bufhead = buf; 75656764Seric buflim = &buf[sizeof buf - 5]; 75768756Seric p = addrhead = addr; 75856764Seric copylev = anglelev = realanglelev = cmtlev = realcmtlev = 0; 75956764Seric qmode = realqmode = FALSE; 76051379Seric 76151379Seric while ((c = *p++) != '\0') 7627783Seric { 76356764Seric /* 76456764Seric ** If the buffer is overful, go into a special "skipping" 76556764Seric ** mode that tries to keep legal syntax but doesn't actually 76656764Seric ** output things. 76756764Seric */ 7687783Seric 76956764Seric skipping = bp >= buflim; 77056735Seric 77156764Seric if (copylev > 0 && !skipping) 77256764Seric *bp++ = c; 77356735Seric 77451379Seric /* check for backslash escapes */ 77551379Seric if (c == '\\') 7767783Seric { 77758890Seric /* arrange to quote the address */ 77858890Seric if (cmtlev <= 0 && !qmode) 77958890Seric quoteit = TRUE; 78058890Seric 78151379Seric if ((c = *p++) == '\0') 7827783Seric { 78351379Seric /* too far */ 78451379Seric p--; 78551379Seric goto putg; 7867783Seric } 78756764Seric if (copylev > 0 && !skipping) 78851379Seric *bp++ = c; 78951379Seric goto putg; 7907783Seric } 7917783Seric 79251379Seric /* check for quoted strings */ 79364967Seric if (c == '"' && cmtlev <= 0) 7947783Seric { 79551379Seric qmode = !qmode; 79656764Seric if (copylev > 0 && !skipping) 79756764Seric realqmode = !realqmode; 79851379Seric continue; 7997783Seric } 80051379Seric if (qmode) 80151379Seric goto putg; 8027783Seric 80351379Seric /* check for comments */ 80451379Seric if (c == '(') 8057783Seric { 80651379Seric cmtlev++; 80756764Seric 80856764Seric /* allow space for closing paren */ 80956764Seric if (!skipping) 81056764Seric { 81156764Seric buflim--; 81256764Seric realcmtlev++; 81356764Seric if (copylev++ <= 0) 81456764Seric { 81556764Seric *bp++ = ' '; 81656764Seric *bp++ = c; 81756764Seric } 81856764Seric } 81951379Seric } 82051379Seric if (cmtlev > 0) 82151379Seric { 82251379Seric if (c == ')') 8237783Seric { 82451379Seric cmtlev--; 82551379Seric copylev--; 82656764Seric if (!skipping) 82756764Seric { 82856764Seric realcmtlev--; 82956764Seric buflim++; 83056764Seric } 8317783Seric } 8327783Seric continue; 8337783Seric } 83456764Seric else if (c == ')') 83556764Seric { 83656764Seric /* syntax error: unmatched ) */ 83765544Seric if (copylev > 0 && !skipping) 83856764Seric bp--; 83956764Seric } 8407783Seric 84168756Seric /* check for group: list; syntax */ 84268760Seric if (c == ':' && anglelev <= 0 && !gotcolon && !ColonOkInAddr) 84368756Seric { 84468756Seric register char *q; 84568756Seric 84668760Seric if (*p == ':') 84768760Seric { 84868760Seric /* special case -- :: syntax */ 84968760Seric if (cmtlev <= 0 && !qmode) 85068760Seric quoteit = TRUE; 85168760Seric if (copylev > 0 && !skipping) 85268760Seric { 85368760Seric *bp++ = c; 85468760Seric *bp++ = c; 85568760Seric } 85668760Seric p++; 85768760Seric goto putg; 85868760Seric } 85968760Seric 86068756Seric gotcolon = TRUE; 86168756Seric 86268760Seric bp = bufhead; 86368760Seric if (quoteit) 86468760Seric { 86568760Seric *bp++ = '"'; 86668760Seric 86768760Seric /* back up over the ':' and any spaces */ 86868760Seric --p; 86968760Seric while (isascii(*--p) && isspace(*p)) 87068760Seric continue; 87168756Seric p++; 87268760Seric } 87368756Seric for (q = addrhead; q < p; ) 87468756Seric { 87568756Seric c = *q++; 87668756Seric if (bp < buflim) 87768756Seric { 87868760Seric if (quoteit && c == '"') 87968760Seric *bp++ = '\\'; 88068756Seric *bp++ = c; 88168756Seric } 88268756Seric } 88368760Seric if (quoteit) 88468760Seric { 88568760Seric if (bp == &bufhead[1]) 88668760Seric bp--; 88768760Seric else 88868760Seric *bp++ = '"'; 88968760Seric while ((c = *p++) != ':') 89068760Seric { 89168760Seric if (bp < buflim) 89268760Seric *bp++ = c; 89368760Seric } 89468760Seric *bp++ = c; 89568760Seric } 89668760Seric 89768760Seric /* any trailing white space is part of group: */ 89868760Seric while (isascii(*p) && isspace(*p) && bp < buflim) 89968760Seric *bp++ = *p++; 90068756Seric copylev = 0; 90168760Seric putgmac = quoteit = FALSE; 90268756Seric bufhead = bp; 90368756Seric addrhead = p; 90468756Seric continue; 90568756Seric } 90668756Seric 90768756Seric if (c == ';' && copylev <= 0 && !ColonOkInAddr) 90868756Seric { 90968756Seric register char *q = p; 91068756Seric 91168756Seric if (bp < buflim) 91268756Seric *bp++ = c; 91368756Seric } 91468756Seric 91556764Seric /* check for characters that may have to be quoted */ 91664148Seric if (strchr(".'@,;:\\()[]", c) != NULL) 91756764Seric { 91856764Seric /* 91956764Seric ** If these occur as the phrase part of a <> 92056764Seric ** construct, but are not inside of () or already 92156764Seric ** quoted, they will have to be quoted. Note that 92256764Seric ** now (but don't actually do the quoting). 92356764Seric */ 92456764Seric 92556764Seric if (cmtlev <= 0 && !qmode) 92656764Seric quoteit = TRUE; 92756764Seric } 92856764Seric 92951379Seric /* check for angle brackets */ 93051379Seric if (c == '<') 93151379Seric { 93256735Seric register char *q; 93356735Seric 93464148Seric /* assume first of two angles is bogus */ 93564148Seric if (gotangle) 93664148Seric quoteit = TRUE; 93764148Seric gotangle = TRUE; 93864148Seric 93951379Seric /* oops -- have to change our mind */ 94064752Seric anglelev = 1; 94156764Seric if (!skipping) 94264752Seric realanglelev = 1; 94356764Seric 94468756Seric bp = bufhead; 94556735Seric if (quoteit) 94656735Seric { 94756735Seric *bp++ = '"'; 94856735Seric 94956735Seric /* back up over the '<' and any spaces */ 95056735Seric --p; 95158050Seric while (isascii(*--p) && isspace(*p)) 95256735Seric continue; 95356735Seric p++; 95456735Seric } 95568756Seric for (q = addrhead; q < p; ) 95656735Seric { 95756735Seric c = *q++; 95856764Seric if (bp < buflim) 95956764Seric { 96056764Seric if (quoteit && c == '"') 96156764Seric *bp++ = '\\'; 96256764Seric *bp++ = c; 96356764Seric } 96456735Seric } 96556735Seric if (quoteit) 96656735Seric { 96764148Seric if (bp == &buf[1]) 96864148Seric bp--; 96964148Seric else 97064148Seric *bp++ = '"'; 97156764Seric while ((c = *p++) != '<') 97256764Seric { 97356764Seric if (bp < buflim) 97456764Seric *bp++ = c; 97556764Seric } 97656764Seric *bp++ = c; 97756735Seric } 97851379Seric copylev = 0; 97956735Seric putgmac = quoteit = FALSE; 98051379Seric continue; 98151379Seric } 9827783Seric 98351379Seric if (c == '>') 9847783Seric { 98556764Seric if (anglelev > 0) 98656764Seric { 98756764Seric anglelev--; 98856764Seric if (!skipping) 98956764Seric { 99056764Seric realanglelev--; 99156764Seric buflim++; 99256764Seric } 99356764Seric } 99456764Seric else if (!skipping) 99556764Seric { 99656764Seric /* syntax error: unmatched > */ 99756764Seric if (copylev > 0) 99856764Seric bp--; 99964752Seric quoteit = TRUE; 100056764Seric continue; 100156764Seric } 100251379Seric if (copylev++ <= 0) 100351379Seric *bp++ = c; 100451379Seric continue; 10057783Seric } 100651379Seric 100751379Seric /* must be a real address character */ 100851379Seric putg: 100951379Seric if (copylev <= 0 && !putgmac) 101051379Seric { 101158050Seric *bp++ = MACROEXPAND; 101251379Seric *bp++ = 'g'; 101351379Seric putgmac = TRUE; 101451379Seric } 10157783Seric } 10167783Seric 101756764Seric /* repair any syntactic damage */ 101856764Seric if (realqmode) 101956764Seric *bp++ = '"'; 102056764Seric while (realcmtlev-- > 0) 102156764Seric *bp++ = ')'; 102256764Seric while (realanglelev-- > 0) 102356764Seric *bp++ = '>'; 102451379Seric *bp++ = '\0'; 10257783Seric 10267783Seric if (tTd(33, 1)) 10277944Seric printf("crackaddr=>`%s'\n", buf); 10287783Seric 10297783Seric return (buf); 10307783Seric } 10319382Seric /* 10329382Seric ** PUTHEADER -- put the header part of a message from the in-core copy 10339382Seric ** 10349382Seric ** Parameters: 103565870Seric ** mci -- the connection information. 103667546Seric ** h -- the header to put. 10379382Seric ** e -- envelope to use. 10389382Seric ** 10399382Seric ** Returns: 10409382Seric ** none. 10419382Seric ** 10429382Seric ** Side Effects: 10439382Seric ** none. 10449382Seric */ 10459382Seric 104657589Seric /* 104757589Seric * Macro for fast max (not available in e.g. DG/UX, 386/ix). 104857589Seric */ 104957589Seric #ifndef MAX 105057589Seric # define MAX(a,b) (((a)>(b))?(a):(b)) 105157589Seric #endif 105257589Seric 105368228Seric putheader(mci, h, e) 105465870Seric register MCI *mci; 105567546Seric register HDR *h; 10569382Seric register ENVELOPE *e; 10579382Seric { 105857135Seric char buf[MAX(MAXLINE,BUFSIZ)]; 105957135Seric char obuf[MAXLINE]; 10609382Seric 106159882Seric if (tTd(34, 1)) 106265870Seric printf("--- putheader, mailer = %s ---\n", 106365870Seric mci->mci_mailer->m_name); 106459882Seric 106567546Seric mci->mci_flags |= MCIF_INHEADER; 106667546Seric for (; h != NULL; h = h->h_link) 10679382Seric { 106869474Seric register char *p = h->h_value; 106910689Seric extern bool bitintersect(); 10709382Seric 107159882Seric if (tTd(34, 11)) 107259882Seric { 107359882Seric printf(" %s: ", h->h_field); 107469474Seric xputs(p); 107559882Seric } 107659882Seric 107769281Seric /* suppress Content-Transfer-Encoding: if we are MIMEing */ 107869281Seric if (bitset(H_CTE, h->h_flags) && 107969281Seric bitset(MCIF_CVT8TO7|MCIF_INMIME, mci->mci_flags)) 108069281Seric { 108169281Seric if (tTd(34, 11)) 108269281Seric printf(" (skipped (content-transfer-encoding))\n"); 108369281Seric continue; 108469281Seric } 108569281Seric 108669281Seric if (bitset(MCIF_INMIME, mci->mci_flags)) 108769281Seric goto vanilla; 108869281Seric 10899382Seric if (bitset(H_CHECK|H_ACHECK, h->h_flags) && 109065870Seric !bitintersect(h->h_mflags, mci->mci_mailer->m_flags)) 109159882Seric { 109259882Seric if (tTd(34, 11)) 109359882Seric printf(" (skipped)\n"); 10949382Seric continue; 109559882Seric } 10969382Seric 109711414Seric /* handle Resent-... headers specially */ 109811414Seric if (bitset(H_RESENT, h->h_flags) && !bitset(EF_RESENT, e->e_flags)) 109959882Seric { 110059882Seric if (tTd(34, 11)) 110159882Seric printf(" (skipped (resent))\n"); 110211414Seric continue; 110359882Seric } 110411414Seric 110566784Seric /* suppress return receipts if requested */ 110666784Seric if (bitset(H_RECEIPTTO, h->h_flags) && 110766784Seric bitset(EF_NORECEIPT, e->e_flags)) 110866784Seric { 110966784Seric if (tTd(34, 11)) 111066784Seric printf(" (skipped (receipt))\n"); 111166784Seric continue; 111266784Seric } 111366784Seric 111465152Seric /* macro expand value if generated internally */ 11159382Seric if (bitset(H_DEFAULT, h->h_flags)) 11169382Seric { 111768529Seric expand(p, buf, sizeof buf, e); 11189382Seric p = buf; 11199382Seric if (p == NULL || *p == '\0') 112065152Seric { 112165152Seric if (tTd(34, 11)) 112265152Seric printf(" (skipped -- null value)\n"); 11239382Seric continue; 112465152Seric } 11259382Seric } 11269382Seric 112765152Seric if (tTd(34, 11)) 112865152Seric printf("\n"); 112965152Seric 113068449Seric if (bitset(H_STRIPVAL, h->h_flags)) 11319382Seric { 113268449Seric /* empty field */ 113368449Seric (void) sprintf(obuf, "%s:", h->h_field); 113468449Seric putline(obuf, mci); 113568449Seric } 113668449Seric else if (bitset(H_FROM|H_RCPT, h->h_flags)) 113768449Seric { 11389382Seric /* address field */ 11399382Seric bool oldstyle = bitset(EF_OLDSTYLE, e->e_flags); 11409382Seric 11419382Seric if (bitset(H_FROM, h->h_flags)) 11429382Seric oldstyle = FALSE; 114365870Seric commaize(h, p, oldstyle, mci, e); 11449382Seric } 11459382Seric else 11469382Seric { 11479382Seric /* vanilla header line */ 114812159Seric register char *nlp; 114912159Seric 115069281Seric vanilla: 115159579Seric (void) sprintf(obuf, "%s: ", h->h_field); 115256795Seric while ((nlp = strchr(p, '\n')) != NULL) 115312159Seric { 115412159Seric *nlp = '\0'; 115512159Seric (void) strcat(obuf, p); 115612159Seric *nlp = '\n'; 115765870Seric putline(obuf, mci); 115812159Seric p = ++nlp; 115912161Seric obuf[0] = '\0'; 116012159Seric } 116112159Seric (void) strcat(obuf, p); 116265870Seric putline(obuf, mci); 11639382Seric } 11649382Seric } 116567887Seric 116667887Seric /* 116767887Seric ** If we are converting this to a MIME message, add the 116867889Seric ** MIME headers. 116967887Seric */ 117067887Seric 117169480Seric #if MIME8TO7 117267887Seric if (bitset(MM_MIME8BIT, MimeMode) && 117367887Seric bitset(EF_HAS8BIT, e->e_flags) && 117467887Seric !bitnset(M_8BITS, mci->mci_mailer->m_flags) && 117567889Seric !bitset(MCIF_CVT8TO7, mci->mci_flags)) 117667887Seric { 117767889Seric if (hvalue("MIME-Version", e->e_header) == NULL) 117867889Seric putline("MIME-Version: 1.0", mci); 117967889Seric if (hvalue("Content-Type", e->e_header) == NULL) 118067889Seric { 118167889Seric sprintf(obuf, "Content-Type: text/plain; charset=%s", 118267896Seric defcharset(e)); 118367889Seric putline(obuf, mci); 118467889Seric } 118567889Seric if (hvalue("Content-Transfer-Encoding", e->e_header) == NULL) 118667889Seric putline("Content-Transfer-Encoding: 8bit", mci); 118767887Seric } 118869480Seric #endif 11899382Seric } 11909382Seric /* 11919382Seric ** COMMAIZE -- output a header field, making a comma-translated list. 11929382Seric ** 11939382Seric ** Parameters: 11949382Seric ** h -- the header field to output. 11959382Seric ** p -- the value to put in it. 11969382Seric ** oldstyle -- TRUE if this is an old style header. 119765870Seric ** mci -- the connection information. 119855012Seric ** e -- the envelope containing the message. 11999382Seric ** 12009382Seric ** Returns: 12019382Seric ** none. 12029382Seric ** 12039382Seric ** Side Effects: 12049382Seric ** outputs "p" to file "fp". 12059382Seric */ 12069382Seric 120765870Seric void 120865870Seric commaize(h, p, oldstyle, mci, e) 12099382Seric register HDR *h; 12109382Seric register char *p; 12119382Seric bool oldstyle; 121265870Seric register MCI *mci; 121355012Seric register ENVELOPE *e; 12149382Seric { 12159382Seric register char *obp; 12169382Seric int opos; 121766004Seric int omax; 12189382Seric bool firstone = TRUE; 121911157Seric char obuf[MAXLINE + 3]; 12209382Seric 12219382Seric /* 12229382Seric ** Output the address list translated by the 12239382Seric ** mailer and with commas. 12249382Seric */ 12259382Seric 12269382Seric if (tTd(14, 2)) 12279382Seric printf("commaize(%s: %s)\n", h->h_field, p); 12289382Seric 12299382Seric obp = obuf; 123059579Seric (void) sprintf(obp, "%s: ", h->h_field); 12319382Seric opos = strlen(h->h_field) + 2; 12329382Seric obp += opos; 123366254Seric omax = mci->mci_mailer->m_linelimit - 2; 123466254Seric if (omax < 0 || omax > 78) 123566254Seric omax = 78; 12369382Seric 12379382Seric /* 12389382Seric ** Run through the list of values. 12399382Seric */ 12409382Seric 12419382Seric while (*p != '\0') 12429382Seric { 12439382Seric register char *name; 124454983Seric register int c; 12459382Seric char savechar; 124659163Seric int flags; 124759163Seric auto int stat; 12489382Seric 12499382Seric /* 12509382Seric ** Find the end of the name. New style names 12519382Seric ** end with a comma, old style names end with 12529382Seric ** a space character. However, spaces do not 12539382Seric ** necessarily delimit an old-style name -- at 12549382Seric ** signs mean keep going. 12559382Seric */ 12569382Seric 12579382Seric /* find end of name */ 125858050Seric while ((isascii(*p) && isspace(*p)) || *p == ',') 12599382Seric p++; 12609382Seric name = p; 12619382Seric for (;;) 12629382Seric { 126358333Seric auto char *oldp; 126416909Seric char pvpbuf[PSBUFSIZE]; 12659382Seric 126665066Seric (void) prescan(p, oldstyle ? ' ' : ',', pvpbuf, 126768711Seric sizeof pvpbuf, &oldp, NULL); 126858333Seric p = oldp; 12699382Seric 12709382Seric /* look to see if we have an at sign */ 127158050Seric while (*p != '\0' && isascii(*p) && isspace(*p)) 12729382Seric p++; 12739382Seric 127458170Seric if (*p != '@') 12759382Seric { 12769382Seric p = oldp; 12779382Seric break; 12789382Seric } 12799382Seric p += *p == '@' ? 1 : 2; 128058050Seric while (*p != '\0' && isascii(*p) && isspace(*p)) 12819382Seric p++; 12829382Seric } 12839382Seric /* at the end of one complete name */ 12849382Seric 12859382Seric /* strip off trailing white space */ 128658050Seric while (p >= name && 128758050Seric ((isascii(*p) && isspace(*p)) || *p == ',' || *p == '\0')) 12889382Seric p--; 12899382Seric if (++p == name) 12909382Seric continue; 12919382Seric savechar = *p; 12929382Seric *p = '\0'; 12939382Seric 12949382Seric /* translate the name to be relative */ 129559163Seric flags = RF_HEADERADDR|RF_ADDDOMAIN; 129659163Seric if (bitset(H_FROM, h->h_flags)) 129759163Seric flags |= RF_SENDERADDR; 129869713Seric #if USERDB 129968522Seric else if (e->e_from.q_mailer != NULL && 130068522Seric bitnset(M_UDBRECIPIENT, e->e_from.q_mailer->m_flags)) 130168522Seric { 130268522Seric extern char *udbsender(); 130368522Seric 130468522Seric name = udbsender(name); 130568522Seric } 130668522Seric #endif 130759163Seric stat = EX_OK; 130865870Seric name = remotename(name, mci->mci_mailer, flags, &stat, e); 13099382Seric if (*name == '\0') 13109382Seric { 13119382Seric *p = savechar; 13129382Seric continue; 13139382Seric } 13149382Seric 13159382Seric /* output the name with nice formatting */ 131654983Seric opos += strlen(name); 13179382Seric if (!firstone) 13189382Seric opos += 2; 131966004Seric if (opos > omax && !firstone) 13209382Seric { 132110178Seric (void) strcpy(obp, ",\n"); 132265870Seric putline(obuf, mci); 13239382Seric obp = obuf; 132466255Seric (void) strcpy(obp, " "); 132510161Seric opos = strlen(obp); 132610161Seric obp += opos; 132754983Seric opos += strlen(name); 13289382Seric } 13299382Seric else if (!firstone) 13309382Seric { 133166255Seric (void) strcpy(obp, ", "); 13329382Seric obp += 2; 13339382Seric } 13349382Seric 133554983Seric while ((c = *name++) != '\0' && obp < &obuf[MAXLINE]) 133654983Seric *obp++ = c; 13379382Seric firstone = FALSE; 13389382Seric *p = savechar; 13399382Seric } 13409382Seric (void) strcpy(obp, "\n"); 134165870Seric putline(obuf, mci); 13429382Seric } 13439382Seric /* 134458170Seric ** COPYHEADER -- copy header list 13459382Seric ** 134658170Seric ** This routine is the equivalent of newstr for header lists 134758170Seric ** 13489382Seric ** Parameters: 134958170Seric ** header -- list of header structures to copy. 13509382Seric ** 13519382Seric ** Returns: 135258170Seric ** a copy of 'header'. 13539382Seric ** 13549382Seric ** Side Effects: 13559382Seric ** none. 13569382Seric */ 13579382Seric 135858170Seric HDR * 135958170Seric copyheader(header) 136058170Seric register HDR *header; 13619382Seric { 136258170Seric register HDR *newhdr; 136358170Seric HDR *ret; 136458170Seric register HDR **tail = &ret; 13659382Seric 136658170Seric while (header != NULL) 136758170Seric { 136858170Seric newhdr = (HDR *) xalloc(sizeof(HDR)); 136958170Seric STRUCTCOPY(*header, *newhdr); 137058170Seric *tail = newhdr; 137158170Seric tail = &newhdr->h_link; 137258170Seric header = header->h_link; 137358170Seric } 137458170Seric *tail = NULL; 137558170Seric 137658170Seric return ret; 13779382Seric } 1378