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*69713Seric static char sccsid[] = "@(#)headers.c 8.65 (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 */ 152*69713Seric #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)) 19914784Seric h->h_value = NULL; 20014784Seric } 20114784Seric 20213012Seric /* create a new node */ 20313012Seric h = (HDR *) xalloc(sizeof *h); 20413012Seric h->h_field = newstr(fname); 20564134Seric h->h_value = newstr(fvalue); 20613012Seric h->h_link = NULL; 20723117Seric bcopy((char *) mopts, (char *) h->h_mflags, sizeof mopts); 20813012Seric *hp = h; 2098066Seric h->h_flags = hi->hi_flags; 2104091Seric if (def) 2114091Seric h->h_flags |= H_DEFAULT; 2129059Seric if (cond) 2139059Seric h->h_flags |= H_CHECK; 2144091Seric 2155937Seric /* hack to see if this is a new format message */ 21668717Seric if (!def && !headeronly && bitset(H_RCPT|H_FROM, h->h_flags) && 21756795Seric (strchr(fvalue, ',') != NULL || strchr(fvalue, '(') != NULL || 21856795Seric strchr(fvalue, '<') != NULL || strchr(fvalue, ';') != NULL)) 2198089Seric { 22055012Seric e->e_flags &= ~EF_OLDSTYLE; 2218089Seric } 2225937Seric 2234091Seric return (h->h_flags); 2244091Seric } 2254091Seric /* 2266980Seric ** ADDHEADER -- add a header entry to the end of the queue. 2276980Seric ** 2286980Seric ** This bypasses the special checking of chompheader. 2296980Seric ** 2306980Seric ** Parameters: 23159579Seric ** field -- the name of the header field. 23258789Seric ** value -- the value of the field. 23367546Seric ** hp -- an indirect pointer to the header structure list. 2346980Seric ** 2356980Seric ** Returns: 2366980Seric ** none. 2376980Seric ** 2386980Seric ** Side Effects: 2396980Seric ** adds the field on the list of headers for this envelope. 2406980Seric */ 2416980Seric 24267546Seric addheader(field, value, hdrlist) 2436980Seric char *field; 2446980Seric char *value; 24567546Seric HDR **hdrlist; 2466980Seric { 2476980Seric register HDR *h; 2486980Seric register struct hdrinfo *hi; 2496980Seric HDR **hp; 2506980Seric 2516980Seric /* find info struct */ 2526980Seric for (hi = HdrInfo; hi->hi_field != NULL; hi++) 2536980Seric { 25459579Seric if (strcasecmp(field, hi->hi_field) == 0) 2556980Seric break; 2566980Seric } 2576980Seric 2586980Seric /* find current place in list -- keep back pointer? */ 25967546Seric for (hp = hdrlist; (h = *hp) != NULL; hp = &h->h_link) 2606980Seric { 26159579Seric if (strcasecmp(field, h->h_field) == 0) 2626980Seric break; 2636980Seric } 2646980Seric 2656980Seric /* allocate space for new header */ 2666980Seric h = (HDR *) xalloc(sizeof *h); 2676980Seric h->h_field = field; 2686980Seric h->h_value = newstr(value); 2697368Seric h->h_link = *hp; 2706980Seric h->h_flags = hi->hi_flags | H_DEFAULT; 27110689Seric clrbitmap(h->h_mflags); 2726980Seric *hp = h; 2736980Seric } 2746980Seric /* 2754091Seric ** HVALUE -- return value of a header. 2764091Seric ** 2774091Seric ** Only "real" fields (i.e., ones that have not been supplied 2784091Seric ** as a default) are used. 2794091Seric ** 2804091Seric ** Parameters: 2814091Seric ** field -- the field name. 28267546Seric ** header -- the header list. 2834091Seric ** 2844091Seric ** Returns: 2854091Seric ** pointer to the value part. 2864091Seric ** NULL if not found. 2874091Seric ** 2884091Seric ** Side Effects: 2899382Seric ** none. 2904091Seric */ 2914091Seric 2924091Seric char * 29367546Seric hvalue(field, header) 2944091Seric char *field; 29567546Seric HDR *header; 2964091Seric { 2974091Seric register HDR *h; 2984091Seric 29967546Seric for (h = header; h != NULL; h = h->h_link) 3004091Seric { 30159579Seric if (!bitset(H_DEFAULT, h->h_flags) && 30259579Seric strcasecmp(h->h_field, field) == 0) 3034091Seric return (h->h_value); 3044091Seric } 3054091Seric return (NULL); 3064091Seric } 3074091Seric /* 3084091Seric ** ISHEADER -- predicate telling if argument is a header. 3094091Seric ** 3104319Seric ** A line is a header if it has a single word followed by 3114319Seric ** optional white space followed by a colon. 3124319Seric ** 31368717Seric ** Header fields beginning with two dashes, although technically 31468717Seric ** permitted by RFC822, are automatically rejected in order 31568717Seric ** to make MIME work out. Without this we could have a technically 31668717Seric ** legal header such as ``--"foo:bar"'' that would also be a legal 31768717Seric ** MIME separator. 31868717Seric ** 3194091Seric ** Parameters: 32068690Seric ** h -- string to check for possible headerness. 3214091Seric ** 3224091Seric ** Returns: 32368690Seric ** TRUE if h is a header. 3244091Seric ** FALSE otherwise. 3254091Seric ** 3264091Seric ** Side Effects: 3274091Seric ** none. 3284091Seric */ 3294091Seric 3304091Seric bool 33168690Seric isheader(h) 33268690Seric char *h; 3334091Seric { 33468690Seric register char *s = h; 33568690Seric 33668717Seric if (s[0] == '-' && s[1] == '-') 33768717Seric return FALSE; 33868717Seric 3399382Seric while (*s > ' ' && *s != ':' && *s != '\0') 3404091Seric s++; 3419382Seric 34268690Seric if (h == s) 34368690Seric return FALSE; 34468690Seric 3459382Seric /* following technically violates RFC822 */ 34658050Seric while (isascii(*s) && isspace(*s)) 3474091Seric s++; 3489382Seric 3494091Seric return (*s == ':'); 3504091Seric } 3515919Seric /* 3527783Seric ** EATHEADER -- run through the stored header and extract info. 3537783Seric ** 3547783Seric ** Parameters: 3559382Seric ** e -- the envelope to process. 35658929Seric ** full -- if set, do full processing (e.g., compute 35769683Seric ** message priority). This should not be set 35869683Seric ** when reading a queue file because some info 35969683Seric ** needed to compute the priority is wrong. 3607783Seric ** 3617783Seric ** Returns: 3627783Seric ** none. 3637783Seric ** 3647783Seric ** Side Effects: 3657783Seric ** Sets a bunch of global variables from information 3669382Seric ** in the collected header. 3679382Seric ** Aborts the message if the hop count is exceeded. 3687783Seric */ 3697783Seric 37058929Seric eatheader(e, full) 3719382Seric register ENVELOPE *e; 37258929Seric bool full; 3737783Seric { 3747783Seric register HDR *h; 3757783Seric register char *p; 3769382Seric int hopcnt = 0; 37757208Seric char *msgid; 37858688Seric char buf[MAXLINE]; 3797783Seric 38058688Seric /* 38158688Seric ** Set up macros for possible expansion in headers. 38258688Seric */ 38358688Seric 38458704Seric define('f', e->e_sender, e); 38558704Seric define('g', e->e_sender, e); 38664148Seric if (e->e_origrcpt != NULL && *e->e_origrcpt != '\0') 38764148Seric define('u', e->e_origrcpt, e); 38864148Seric else 38964148Seric define('u', NULL, e); 39058688Seric 39165052Seric /* full name of from person */ 39267546Seric p = hvalue("full-name", e->e_header); 39365052Seric if (p != NULL) 39465052Seric define('x', p, e); 39565052Seric 3969382Seric if (tTd(32, 1)) 3979382Seric printf("----- collected header -----\n"); 39869683Seric msgid = NULL; 3999382Seric for (h = e->e_header; h != NULL; h = h->h_link) 4007783Seric { 40164156Seric if (h->h_value == NULL) 40264156Seric { 40364156Seric if (tTd(32, 1)) 40464156Seric printf("%s: <NULL>\n", h->h_field); 40564156Seric continue; 40664156Seric } 40764156Seric 40858688Seric /* do early binding */ 40964156Seric if (bitset(H_DEFAULT, h->h_flags)) 41058688Seric { 41168529Seric expand(h->h_value, buf, sizeof buf, e); 41258688Seric if (buf[0] != '\0') 41358688Seric { 41458688Seric h->h_value = newstr(buf); 41558688Seric h->h_flags &= ~H_DEFAULT; 41658688Seric } 41758688Seric } 41858688Seric 4199382Seric if (tTd(32, 1)) 42065152Seric { 42165152Seric printf("%s: ", h->h_field); 42265152Seric xputs(h->h_value); 42365152Seric printf("\n"); 42465152Seric } 42557359Seric 42611414Seric /* count the number of times it has been processed */ 4279382Seric if (bitset(H_TRACE, h->h_flags)) 4289382Seric hopcnt++; 42911414Seric 43011414Seric /* send to this person if we so desire */ 43111414Seric if (GrabTo && bitset(H_RCPT, h->h_flags) && 43211414Seric !bitset(H_DEFAULT, h->h_flags) && 43355012Seric (!bitset(EF_RESENT, e->e_flags) || bitset(H_RESENT, h->h_flags))) 43411414Seric { 43563839Seric int saveflags = e->e_flags; 43663839Seric 43764283Seric (void) sendtolist(h->h_value, NULLADDR, 43867982Seric &e->e_sendqueue, 0, e); 43963839Seric 44063839Seric /* delete fatal errors generated by this address */ 44164148Seric if (!GrabTo && !bitset(EF_FATALERRS, saveflags)) 44263839Seric e->e_flags &= ~EF_FATALERRS; 44311414Seric } 44411414Seric 44557208Seric /* save the message-id for logging */ 44669683Seric if (strcasecmp(h->h_field, "message-id") == 0) 44711290Seric { 44857208Seric msgid = h->h_value; 44959859Seric while (isascii(*msgid) && isspace(*msgid)) 45059859Seric msgid++; 45111290Seric } 45257359Seric 45357359Seric /* see if this is a return-receipt header */ 45457359Seric if (bitset(H_RECEIPTTO, h->h_flags)) 45557359Seric e->e_receiptto = h->h_value; 4569382Seric } 4579382Seric if (tTd(32, 1)) 4587783Seric printf("----------------------------\n"); 4597783Seric 46058145Seric /* if we are just verifying (that is, sendmail -t -bv), drop out now */ 46158145Seric if (OpMode == MD_VERIFY) 46258145Seric return; 46358145Seric 4649382Seric /* store hop count */ 4659382Seric if (hopcnt > e->e_hopcount) 4669382Seric e->e_hopcount = hopcnt; 4679382Seric 4687783Seric /* message priority */ 46967546Seric p = hvalue("precedence", e->e_header); 4709382Seric if (p != NULL) 4719382Seric e->e_class = priencode(p); 47269683Seric if (e->e_class < 0) 47369683Seric e->e_timeoutclass = TOC_NONURGENT; 47469683Seric else if (e->e_class > 0) 47569683Seric e->e_timeoutclass = TOC_URGENT; 47658929Seric if (full) 47767730Seric { 47825013Seric e->e_msgpriority = e->e_msgsize 47924981Seric - e->e_class * WkClassFact 48024981Seric + e->e_nrcpts * WkRecipFact; 48167730Seric } 4827783Seric 48367730Seric /* message timeout priority */ 48467730Seric p = hvalue("priority", e->e_header); 48569683Seric if (p != NULL) 48667730Seric { 48767730Seric /* (this should be in the configuration file) */ 48867730Seric if (strcasecmp(p, "urgent")) 48967730Seric e->e_timeoutclass = TOC_URGENT; 49067730Seric else if (strcasecmp(p, "normal")) 49167730Seric e->e_timeoutclass = TOC_NORMAL; 49267730Seric else if (strcasecmp(p, "non-urgent")) 49367730Seric e->e_timeoutclass = TOC_NONURGENT; 49467730Seric } 49567730Seric 4967783Seric /* date message originated */ 49767546Seric p = hvalue("posted-date", e->e_header); 4987783Seric if (p == NULL) 49967546Seric p = hvalue("date", e->e_header); 5007783Seric if (p != NULL) 5019382Seric define('a', p, e); 50211290Seric 50368884Seric /* check to see if this is a MIME message */ 50469105Seric if ((e->e_bodytype != NULL && 50569105Seric strcasecmp(e->e_bodytype, "8BITMIME") == 0) || 50668884Seric hvalue("MIME-Version", e->e_header) != NULL) 50769105Seric { 50868884Seric e->e_flags |= EF_IS_MIME; 50969105Seric if (HasEightBits) 51069105Seric e->e_bodytype = "8BITMIME"; 51169105Seric } 51268884Seric 51311290Seric /* 51465983Seric ** From person in antiquated ARPANET mode 51565983Seric ** required by UK Grey Book e-mail gateways (sigh) 51665983Seric */ 51765983Seric 51865983Seric if (OpMode == MD_ARPAFTP) 51965983Seric { 52065983Seric register struct hdrinfo *hi; 52165983Seric 52265983Seric for (hi = HdrInfo; hi->hi_field != NULL; hi++) 52365983Seric { 52465983Seric if (bitset(H_FROM, hi->hi_flags) && 52565983Seric (!bitset(H_RESENT, hi->hi_flags) || 52665983Seric bitset(EF_RESENT, e->e_flags)) && 52767546Seric (p = hvalue(hi->hi_field, e->e_header)) != NULL) 52865983Seric break; 52965983Seric } 53065983Seric if (hi->hi_field != NULL) 53165983Seric { 53265983Seric if (tTd(32, 2)) 53365983Seric printf("eatheader: setsender(*%s == %s)\n", 53465983Seric hi->hi_field, p); 53565983Seric setsender(p, e, NULL, TRUE); 53665983Seric } 53765983Seric } 53865983Seric 53965983Seric /* 54011290Seric ** Log collection information. 54111290Seric */ 54211290Seric 54311290Seric # ifdef LOG 54468036Seric if (bitset(EF_LOGSENDER, e->e_flags) && LogLevel > 4) 54565089Seric logsender(e, msgid); 54665089Seric # endif /* LOG */ 54765089Seric e->e_flags &= ~EF_LOGSENDER; 54865089Seric } 54965089Seric /* 55065089Seric ** LOGSENDER -- log sender information 55165089Seric ** 55265089Seric ** Parameters: 55365089Seric ** e -- the envelope to log 55465089Seric ** msgid -- the message id 55565089Seric ** 55665089Seric ** Returns: 55765089Seric ** none 55865089Seric */ 55965089Seric 56065089Seric logsender(e, msgid) 56165089Seric register ENVELOPE *e; 56265089Seric char *msgid; 56365089Seric { 56466748Seric # ifdef LOG 56565089Seric char *name; 56665089Seric register char *sbp; 56765089Seric register char *p; 56867901Seric int l; 56968528Seric char hbuf[MAXNAME + 1]; 57068528Seric char sbuf[MAXLINE + 1]; 57168528Seric char mbuf[MAXNAME + 1]; 57265089Seric 57367901Seric /* don't allow newlines in the message-id */ 57467901Seric if (msgid != NULL) 57567901Seric { 57667901Seric l = strlen(msgid); 57767901Seric if (l > sizeof mbuf - 1) 57867901Seric l = sizeof mbuf - 1; 57967901Seric bcopy(msgid, mbuf, l); 58067901Seric mbuf[l] = '\0'; 58167901Seric p = mbuf; 58267901Seric while ((p = strchr(p, '\n')) != NULL) 58367901Seric *p++ = ' '; 58467901Seric } 58567901Seric 58665089Seric if (bitset(EF_RESPONSE, e->e_flags)) 58765089Seric name = "[RESPONSE]"; 58865089Seric else if ((name = macvalue('_', e)) != NULL) 58965089Seric ; 59066003Seric else if (RealHostName == NULL) 59166003Seric name = "localhost"; 59265089Seric else if (RealHostName[0] == '[') 59365089Seric name = RealHostName; 59465089Seric else 59511290Seric { 59665089Seric name = hbuf; 59765089Seric (void) sprintf(hbuf, "%.80s", RealHostName); 59865089Seric if (RealHostAddr.sa.sa_family != 0) 59957359Seric { 60065089Seric p = &hbuf[strlen(hbuf)]; 60165089Seric (void) sprintf(p, " (%s)", 60265089Seric anynet_ntoa(&RealHostAddr)); 60357359Seric } 60465089Seric } 60557359Seric 60665089Seric /* some versions of syslog only take 5 printf args */ 60765059Seric # if (SYSLOG_BUFSIZE) >= 256 60865089Seric sbp = sbuf; 60965089Seric sprintf(sbp, "from=%.200s, size=%ld, class=%d, pri=%ld, nrcpts=%d", 61067788Seric e->e_from.q_paddr == NULL ? "<NONE>" : e->e_from.q_paddr, 61167788Seric e->e_msgsize, e->e_class, e->e_msgpriority, e->e_nrcpts); 61265089Seric sbp += strlen(sbp); 61365089Seric if (msgid != NULL) 61465089Seric { 61567901Seric sprintf(sbp, ", msgid=%.100s", mbuf); 61660575Seric sbp += strlen(sbp); 61765089Seric } 61865089Seric if (e->e_bodytype != NULL) 61965089Seric { 62065089Seric (void) sprintf(sbp, ", bodytype=%.20s", e->e_bodytype); 62165089Seric sbp += strlen(sbp); 62265089Seric } 62365089Seric p = macvalue('r', e); 62465089Seric if (p != NULL) 62565089Seric (void) sprintf(sbp, ", proto=%.20s", p); 62665089Seric syslog(LOG_INFO, "%s: %s, relay=%s", 62765089Seric e->e_id, sbuf, name); 62865059Seric 62965059Seric # else /* short syslog buffer */ 63065059Seric 63165089Seric syslog(LOG_INFO, "%s: from=%s", 63267788Seric e->e_id, e->e_from.q_paddr == NULL ? "<NONE>" : 63367788Seric shortenstring(e->e_from.q_paddr, 83)); 63465089Seric syslog(LOG_INFO, "%s: size=%ld, class=%ld, pri=%ld, nrcpts=%d", 63565089Seric e->e_id, e->e_msgsize, e->e_class, 63665089Seric e->e_msgpriority, e->e_nrcpts); 63765089Seric if (msgid != NULL) 63867901Seric syslog(LOG_INFO, "%s: msgid=%s", e->e_id, mbuf); 63965650Seric sbp = sbuf; 64065650Seric sprintf(sbp, "%s:", e->e_id); 64165650Seric sbp += strlen(sbp); 64265089Seric if (e->e_bodytype != NULL) 64365650Seric { 64465650Seric sprintf(sbp, " bodytype=%s,", e->e_bodytype); 64565650Seric sbp += strlen(sbp); 64665650Seric } 64765089Seric p = macvalue('r', e); 64865089Seric if (p != NULL) 64965650Seric { 65065731Seric sprintf(sbp, " proto=%s,", p); 65165650Seric sbp += strlen(sbp); 65265650Seric } 65365650Seric syslog(LOG_INFO, "%s relay=%s", sbuf, name); 65465059Seric # endif 65566748Seric # endif 6567783Seric } 6577783Seric /* 6587783Seric ** PRIENCODE -- encode external priority names into internal values. 6597783Seric ** 6607783Seric ** Parameters: 6617783Seric ** p -- priority in ascii. 6627783Seric ** 6637783Seric ** Returns: 6647783Seric ** priority as a numeric level. 6657783Seric ** 6667783Seric ** Side Effects: 6677783Seric ** none. 6687783Seric */ 6697783Seric 6707783Seric priencode(p) 6717783Seric char *p; 6727783Seric { 6738253Seric register int i; 6747783Seric 6758253Seric for (i = 0; i < NumPriorities; i++) 6767783Seric { 67733725Sbostic if (!strcasecmp(p, Priorities[i].pri_name)) 6788253Seric return (Priorities[i].pri_val); 6797783Seric } 6808253Seric 6818253Seric /* unknown priority */ 6828253Seric return (0); 6837783Seric } 6847783Seric /* 6857890Seric ** CRACKADDR -- parse an address and turn it into a macro 6867783Seric ** 6877783Seric ** This doesn't actually parse the address -- it just extracts 6887783Seric ** it and replaces it with "$g". The parse is totally ad hoc 6897783Seric ** and isn't even guaranteed to leave something syntactically 6907783Seric ** identical to what it started with. However, it does leave 6917783Seric ** something semantically identical. 6927783Seric ** 69351379Seric ** This algorithm has been cleaned up to handle a wider range 69451379Seric ** of cases -- notably quoted and backslash escaped strings. 69551379Seric ** This modification makes it substantially better at preserving 69651379Seric ** the original syntax. 6977783Seric ** 6987783Seric ** Parameters: 6997890Seric ** addr -- the address to be cracked. 7007783Seric ** 7017783Seric ** Returns: 7027783Seric ** a pointer to the new version. 7037783Seric ** 7047783Seric ** Side Effects: 7057890Seric ** none. 7067783Seric ** 7077783Seric ** Warning: 7087783Seric ** The return value is saved in local storage and should 7097783Seric ** be copied if it is to be reused. 7107783Seric */ 7117783Seric 7127783Seric char * 7137890Seric crackaddr(addr) 7147890Seric register char *addr; 7157783Seric { 7167783Seric register char *p; 71751379Seric register char c; 71851379Seric int cmtlev; 71956764Seric int realcmtlev; 72056764Seric int anglelev, realanglelev; 72151379Seric int copylev; 72251379Seric bool qmode; 72356764Seric bool realqmode; 72456764Seric bool skipping; 72551379Seric bool putgmac = FALSE; 72656735Seric bool quoteit = FALSE; 72764148Seric bool gotangle = FALSE; 72868756Seric bool gotcolon = FALSE; 72951379Seric register char *bp; 73056764Seric char *buflim; 73168756Seric char *bufhead; 73268756Seric char *addrhead; 73368528Seric static char buf[MAXNAME + 1]; 7347783Seric 7357783Seric if (tTd(33, 1)) 7367890Seric printf("crackaddr(%s)\n", addr); 7377783Seric 7388082Seric /* strip leading spaces */ 73958050Seric while (*addr != '\0' && isascii(*addr) && isspace(*addr)) 7408082Seric addr++; 7418082Seric 7427783Seric /* 74351379Seric ** Start by assuming we have no angle brackets. This will be 74451379Seric ** adjusted later if we find them. 7457783Seric */ 7467783Seric 74768756Seric bp = bufhead = buf; 74856764Seric buflim = &buf[sizeof buf - 5]; 74968756Seric p = addrhead = addr; 75056764Seric copylev = anglelev = realanglelev = cmtlev = realcmtlev = 0; 75156764Seric qmode = realqmode = FALSE; 75251379Seric 75351379Seric while ((c = *p++) != '\0') 7547783Seric { 75556764Seric /* 75656764Seric ** If the buffer is overful, go into a special "skipping" 75756764Seric ** mode that tries to keep legal syntax but doesn't actually 75856764Seric ** output things. 75956764Seric */ 7607783Seric 76156764Seric skipping = bp >= buflim; 76256735Seric 76356764Seric if (copylev > 0 && !skipping) 76456764Seric *bp++ = c; 76556735Seric 76651379Seric /* check for backslash escapes */ 76751379Seric if (c == '\\') 7687783Seric { 76958890Seric /* arrange to quote the address */ 77058890Seric if (cmtlev <= 0 && !qmode) 77158890Seric quoteit = TRUE; 77258890Seric 77351379Seric if ((c = *p++) == '\0') 7747783Seric { 77551379Seric /* too far */ 77651379Seric p--; 77751379Seric goto putg; 7787783Seric } 77956764Seric if (copylev > 0 && !skipping) 78051379Seric *bp++ = c; 78151379Seric goto putg; 7827783Seric } 7837783Seric 78451379Seric /* check for quoted strings */ 78564967Seric if (c == '"' && cmtlev <= 0) 7867783Seric { 78751379Seric qmode = !qmode; 78856764Seric if (copylev > 0 && !skipping) 78956764Seric realqmode = !realqmode; 79051379Seric continue; 7917783Seric } 79251379Seric if (qmode) 79351379Seric goto putg; 7947783Seric 79551379Seric /* check for comments */ 79651379Seric if (c == '(') 7977783Seric { 79851379Seric cmtlev++; 79956764Seric 80056764Seric /* allow space for closing paren */ 80156764Seric if (!skipping) 80256764Seric { 80356764Seric buflim--; 80456764Seric realcmtlev++; 80556764Seric if (copylev++ <= 0) 80656764Seric { 80756764Seric *bp++ = ' '; 80856764Seric *bp++ = c; 80956764Seric } 81056764Seric } 81151379Seric } 81251379Seric if (cmtlev > 0) 81351379Seric { 81451379Seric if (c == ')') 8157783Seric { 81651379Seric cmtlev--; 81751379Seric copylev--; 81856764Seric if (!skipping) 81956764Seric { 82056764Seric realcmtlev--; 82156764Seric buflim++; 82256764Seric } 8237783Seric } 8247783Seric continue; 8257783Seric } 82656764Seric else if (c == ')') 82756764Seric { 82856764Seric /* syntax error: unmatched ) */ 82965544Seric if (copylev > 0 && !skipping) 83056764Seric bp--; 83156764Seric } 8327783Seric 83368756Seric /* check for group: list; syntax */ 83468760Seric if (c == ':' && anglelev <= 0 && !gotcolon && !ColonOkInAddr) 83568756Seric { 83668756Seric register char *q; 83768756Seric 83868760Seric if (*p == ':') 83968760Seric { 84068760Seric /* special case -- :: syntax */ 84168760Seric if (cmtlev <= 0 && !qmode) 84268760Seric quoteit = TRUE; 84368760Seric if (copylev > 0 && !skipping) 84468760Seric { 84568760Seric *bp++ = c; 84668760Seric *bp++ = c; 84768760Seric } 84868760Seric p++; 84968760Seric goto putg; 85068760Seric } 85168760Seric 85268756Seric gotcolon = TRUE; 85368756Seric 85468760Seric bp = bufhead; 85568760Seric if (quoteit) 85668760Seric { 85768760Seric *bp++ = '"'; 85868760Seric 85968760Seric /* back up over the ':' and any spaces */ 86068760Seric --p; 86168760Seric while (isascii(*--p) && isspace(*p)) 86268760Seric continue; 86368756Seric p++; 86468760Seric } 86568756Seric for (q = addrhead; q < p; ) 86668756Seric { 86768756Seric c = *q++; 86868756Seric if (bp < buflim) 86968756Seric { 87068760Seric if (quoteit && c == '"') 87168760Seric *bp++ = '\\'; 87268756Seric *bp++ = c; 87368756Seric } 87468756Seric } 87568760Seric if (quoteit) 87668760Seric { 87768760Seric if (bp == &bufhead[1]) 87868760Seric bp--; 87968760Seric else 88068760Seric *bp++ = '"'; 88168760Seric while ((c = *p++) != ':') 88268760Seric { 88368760Seric if (bp < buflim) 88468760Seric *bp++ = c; 88568760Seric } 88668760Seric *bp++ = c; 88768760Seric } 88868760Seric 88968760Seric /* any trailing white space is part of group: */ 89068760Seric while (isascii(*p) && isspace(*p) && bp < buflim) 89168760Seric *bp++ = *p++; 89268756Seric copylev = 0; 89368760Seric putgmac = quoteit = FALSE; 89468756Seric bufhead = bp; 89568756Seric addrhead = p; 89668756Seric continue; 89768756Seric } 89868756Seric 89968756Seric if (c == ';' && copylev <= 0 && !ColonOkInAddr) 90068756Seric { 90168756Seric register char *q = p; 90268756Seric 90368756Seric if (bp < buflim) 90468756Seric *bp++ = c; 90568756Seric } 90668756Seric 90756764Seric /* check for characters that may have to be quoted */ 90864148Seric if (strchr(".'@,;:\\()[]", c) != NULL) 90956764Seric { 91056764Seric /* 91156764Seric ** If these occur as the phrase part of a <> 91256764Seric ** construct, but are not inside of () or already 91356764Seric ** quoted, they will have to be quoted. Note that 91456764Seric ** now (but don't actually do the quoting). 91556764Seric */ 91656764Seric 91756764Seric if (cmtlev <= 0 && !qmode) 91856764Seric quoteit = TRUE; 91956764Seric } 92056764Seric 92151379Seric /* check for angle brackets */ 92251379Seric if (c == '<') 92351379Seric { 92456735Seric register char *q; 92556735Seric 92664148Seric /* assume first of two angles is bogus */ 92764148Seric if (gotangle) 92864148Seric quoteit = TRUE; 92964148Seric gotangle = TRUE; 93064148Seric 93151379Seric /* oops -- have to change our mind */ 93264752Seric anglelev = 1; 93356764Seric if (!skipping) 93464752Seric realanglelev = 1; 93556764Seric 93668756Seric bp = bufhead; 93756735Seric if (quoteit) 93856735Seric { 93956735Seric *bp++ = '"'; 94056735Seric 94156735Seric /* back up over the '<' and any spaces */ 94256735Seric --p; 94358050Seric while (isascii(*--p) && isspace(*p)) 94456735Seric continue; 94556735Seric p++; 94656735Seric } 94768756Seric for (q = addrhead; q < p; ) 94856735Seric { 94956735Seric c = *q++; 95056764Seric if (bp < buflim) 95156764Seric { 95256764Seric if (quoteit && c == '"') 95356764Seric *bp++ = '\\'; 95456764Seric *bp++ = c; 95556764Seric } 95656735Seric } 95756735Seric if (quoteit) 95856735Seric { 95964148Seric if (bp == &buf[1]) 96064148Seric bp--; 96164148Seric else 96264148Seric *bp++ = '"'; 96356764Seric while ((c = *p++) != '<') 96456764Seric { 96556764Seric if (bp < buflim) 96656764Seric *bp++ = c; 96756764Seric } 96856764Seric *bp++ = c; 96956735Seric } 97051379Seric copylev = 0; 97156735Seric putgmac = quoteit = FALSE; 97251379Seric continue; 97351379Seric } 9747783Seric 97551379Seric if (c == '>') 9767783Seric { 97756764Seric if (anglelev > 0) 97856764Seric { 97956764Seric anglelev--; 98056764Seric if (!skipping) 98156764Seric { 98256764Seric realanglelev--; 98356764Seric buflim++; 98456764Seric } 98556764Seric } 98656764Seric else if (!skipping) 98756764Seric { 98856764Seric /* syntax error: unmatched > */ 98956764Seric if (copylev > 0) 99056764Seric bp--; 99164752Seric quoteit = TRUE; 99256764Seric continue; 99356764Seric } 99451379Seric if (copylev++ <= 0) 99551379Seric *bp++ = c; 99651379Seric continue; 9977783Seric } 99851379Seric 99951379Seric /* must be a real address character */ 100051379Seric putg: 100151379Seric if (copylev <= 0 && !putgmac) 100251379Seric { 100358050Seric *bp++ = MACROEXPAND; 100451379Seric *bp++ = 'g'; 100551379Seric putgmac = TRUE; 100651379Seric } 10077783Seric } 10087783Seric 100956764Seric /* repair any syntactic damage */ 101056764Seric if (realqmode) 101156764Seric *bp++ = '"'; 101256764Seric while (realcmtlev-- > 0) 101356764Seric *bp++ = ')'; 101456764Seric while (realanglelev-- > 0) 101556764Seric *bp++ = '>'; 101651379Seric *bp++ = '\0'; 10177783Seric 10187783Seric if (tTd(33, 1)) 10197944Seric printf("crackaddr=>`%s'\n", buf); 10207783Seric 10217783Seric return (buf); 10227783Seric } 10239382Seric /* 10249382Seric ** PUTHEADER -- put the header part of a message from the in-core copy 10259382Seric ** 10269382Seric ** Parameters: 102765870Seric ** mci -- the connection information. 102867546Seric ** h -- the header to put. 10299382Seric ** e -- envelope to use. 10309382Seric ** 10319382Seric ** Returns: 10329382Seric ** none. 10339382Seric ** 10349382Seric ** Side Effects: 10359382Seric ** none. 10369382Seric */ 10379382Seric 103857589Seric /* 103957589Seric * Macro for fast max (not available in e.g. DG/UX, 386/ix). 104057589Seric */ 104157589Seric #ifndef MAX 104257589Seric # define MAX(a,b) (((a)>(b))?(a):(b)) 104357589Seric #endif 104457589Seric 104568228Seric putheader(mci, h, e) 104665870Seric register MCI *mci; 104767546Seric register HDR *h; 10489382Seric register ENVELOPE *e; 10499382Seric { 105057135Seric char buf[MAX(MAXLINE,BUFSIZ)]; 105157135Seric char obuf[MAXLINE]; 10529382Seric 105359882Seric if (tTd(34, 1)) 105465870Seric printf("--- putheader, mailer = %s ---\n", 105565870Seric mci->mci_mailer->m_name); 105659882Seric 105767546Seric mci->mci_flags |= MCIF_INHEADER; 105867546Seric for (; h != NULL; h = h->h_link) 10599382Seric { 106069474Seric register char *p = h->h_value; 106110689Seric extern bool bitintersect(); 10629382Seric 106359882Seric if (tTd(34, 11)) 106459882Seric { 106559882Seric printf(" %s: ", h->h_field); 106669474Seric xputs(p); 106759882Seric } 106859882Seric 106969281Seric /* suppress Content-Transfer-Encoding: if we are MIMEing */ 107069281Seric if (bitset(H_CTE, h->h_flags) && 107169281Seric bitset(MCIF_CVT8TO7|MCIF_INMIME, mci->mci_flags)) 107269281Seric { 107369281Seric if (tTd(34, 11)) 107469281Seric printf(" (skipped (content-transfer-encoding))\n"); 107569281Seric continue; 107669281Seric } 107769281Seric 107869281Seric if (bitset(MCIF_INMIME, mci->mci_flags)) 107969281Seric goto vanilla; 108069281Seric 10819382Seric if (bitset(H_CHECK|H_ACHECK, h->h_flags) && 108265870Seric !bitintersect(h->h_mflags, mci->mci_mailer->m_flags)) 108359882Seric { 108459882Seric if (tTd(34, 11)) 108559882Seric printf(" (skipped)\n"); 10869382Seric continue; 108759882Seric } 10889382Seric 108911414Seric /* handle Resent-... headers specially */ 109011414Seric if (bitset(H_RESENT, h->h_flags) && !bitset(EF_RESENT, e->e_flags)) 109159882Seric { 109259882Seric if (tTd(34, 11)) 109359882Seric printf(" (skipped (resent))\n"); 109411414Seric continue; 109559882Seric } 109611414Seric 109766784Seric /* suppress return receipts if requested */ 109866784Seric if (bitset(H_RECEIPTTO, h->h_flags) && 109966784Seric bitset(EF_NORECEIPT, e->e_flags)) 110066784Seric { 110166784Seric if (tTd(34, 11)) 110266784Seric printf(" (skipped (receipt))\n"); 110366784Seric continue; 110466784Seric } 110566784Seric 110665152Seric /* macro expand value if generated internally */ 11079382Seric if (bitset(H_DEFAULT, h->h_flags)) 11089382Seric { 110968529Seric expand(p, buf, sizeof buf, e); 11109382Seric p = buf; 11119382Seric if (p == NULL || *p == '\0') 111265152Seric { 111365152Seric if (tTd(34, 11)) 111465152Seric printf(" (skipped -- null value)\n"); 11159382Seric continue; 111665152Seric } 11179382Seric } 11189382Seric 111965152Seric if (tTd(34, 11)) 112065152Seric printf("\n"); 112165152Seric 112268449Seric if (bitset(H_STRIPVAL, h->h_flags)) 11239382Seric { 112468449Seric /* empty field */ 112568449Seric (void) sprintf(obuf, "%s:", h->h_field); 112668449Seric putline(obuf, mci); 112768449Seric } 112868449Seric else if (bitset(H_FROM|H_RCPT, h->h_flags)) 112968449Seric { 11309382Seric /* address field */ 11319382Seric bool oldstyle = bitset(EF_OLDSTYLE, e->e_flags); 11329382Seric 11339382Seric if (bitset(H_FROM, h->h_flags)) 11349382Seric oldstyle = FALSE; 113565870Seric commaize(h, p, oldstyle, mci, e); 11369382Seric } 11379382Seric else 11389382Seric { 11399382Seric /* vanilla header line */ 114012159Seric register char *nlp; 114112159Seric 114269281Seric vanilla: 114359579Seric (void) sprintf(obuf, "%s: ", h->h_field); 114456795Seric while ((nlp = strchr(p, '\n')) != NULL) 114512159Seric { 114612159Seric *nlp = '\0'; 114712159Seric (void) strcat(obuf, p); 114812159Seric *nlp = '\n'; 114965870Seric putline(obuf, mci); 115012159Seric p = ++nlp; 115112161Seric obuf[0] = '\0'; 115212159Seric } 115312159Seric (void) strcat(obuf, p); 115465870Seric putline(obuf, mci); 11559382Seric } 11569382Seric } 115767887Seric 115867887Seric /* 115967887Seric ** If we are converting this to a MIME message, add the 116067889Seric ** MIME headers. 116167887Seric */ 116267887Seric 116369480Seric #if MIME8TO7 116467887Seric if (bitset(MM_MIME8BIT, MimeMode) && 116567887Seric bitset(EF_HAS8BIT, e->e_flags) && 116667887Seric !bitnset(M_8BITS, mci->mci_mailer->m_flags) && 116767889Seric !bitset(MCIF_CVT8TO7, mci->mci_flags)) 116867887Seric { 116967889Seric if (hvalue("MIME-Version", e->e_header) == NULL) 117067889Seric putline("MIME-Version: 1.0", mci); 117167889Seric if (hvalue("Content-Type", e->e_header) == NULL) 117267889Seric { 117367889Seric sprintf(obuf, "Content-Type: text/plain; charset=%s", 117467896Seric defcharset(e)); 117567889Seric putline(obuf, mci); 117667889Seric } 117767889Seric if (hvalue("Content-Transfer-Encoding", e->e_header) == NULL) 117867889Seric putline("Content-Transfer-Encoding: 8bit", mci); 117967887Seric } 118069480Seric #endif 11819382Seric } 11829382Seric /* 11839382Seric ** COMMAIZE -- output a header field, making a comma-translated list. 11849382Seric ** 11859382Seric ** Parameters: 11869382Seric ** h -- the header field to output. 11879382Seric ** p -- the value to put in it. 11889382Seric ** oldstyle -- TRUE if this is an old style header. 118965870Seric ** mci -- the connection information. 119055012Seric ** e -- the envelope containing the message. 11919382Seric ** 11929382Seric ** Returns: 11939382Seric ** none. 11949382Seric ** 11959382Seric ** Side Effects: 11969382Seric ** outputs "p" to file "fp". 11979382Seric */ 11989382Seric 119965870Seric void 120065870Seric commaize(h, p, oldstyle, mci, e) 12019382Seric register HDR *h; 12029382Seric register char *p; 12039382Seric bool oldstyle; 120465870Seric register MCI *mci; 120555012Seric register ENVELOPE *e; 12069382Seric { 12079382Seric register char *obp; 12089382Seric int opos; 120966004Seric int omax; 12109382Seric bool firstone = TRUE; 121111157Seric char obuf[MAXLINE + 3]; 12129382Seric 12139382Seric /* 12149382Seric ** Output the address list translated by the 12159382Seric ** mailer and with commas. 12169382Seric */ 12179382Seric 12189382Seric if (tTd(14, 2)) 12199382Seric printf("commaize(%s: %s)\n", h->h_field, p); 12209382Seric 12219382Seric obp = obuf; 122259579Seric (void) sprintf(obp, "%s: ", h->h_field); 12239382Seric opos = strlen(h->h_field) + 2; 12249382Seric obp += opos; 122566254Seric omax = mci->mci_mailer->m_linelimit - 2; 122666254Seric if (omax < 0 || omax > 78) 122766254Seric omax = 78; 12289382Seric 12299382Seric /* 12309382Seric ** Run through the list of values. 12319382Seric */ 12329382Seric 12339382Seric while (*p != '\0') 12349382Seric { 12359382Seric register char *name; 123654983Seric register int c; 12379382Seric char savechar; 123859163Seric int flags; 123959163Seric auto int stat; 12409382Seric 12419382Seric /* 12429382Seric ** Find the end of the name. New style names 12439382Seric ** end with a comma, old style names end with 12449382Seric ** a space character. However, spaces do not 12459382Seric ** necessarily delimit an old-style name -- at 12469382Seric ** signs mean keep going. 12479382Seric */ 12489382Seric 12499382Seric /* find end of name */ 125058050Seric while ((isascii(*p) && isspace(*p)) || *p == ',') 12519382Seric p++; 12529382Seric name = p; 12539382Seric for (;;) 12549382Seric { 125558333Seric auto char *oldp; 125616909Seric char pvpbuf[PSBUFSIZE]; 12579382Seric 125865066Seric (void) prescan(p, oldstyle ? ' ' : ',', pvpbuf, 125968711Seric sizeof pvpbuf, &oldp, NULL); 126058333Seric p = oldp; 12619382Seric 12629382Seric /* look to see if we have an at sign */ 126358050Seric while (*p != '\0' && isascii(*p) && isspace(*p)) 12649382Seric p++; 12659382Seric 126658170Seric if (*p != '@') 12679382Seric { 12689382Seric p = oldp; 12699382Seric break; 12709382Seric } 12719382Seric p += *p == '@' ? 1 : 2; 127258050Seric while (*p != '\0' && isascii(*p) && isspace(*p)) 12739382Seric p++; 12749382Seric } 12759382Seric /* at the end of one complete name */ 12769382Seric 12779382Seric /* strip off trailing white space */ 127858050Seric while (p >= name && 127958050Seric ((isascii(*p) && isspace(*p)) || *p == ',' || *p == '\0')) 12809382Seric p--; 12819382Seric if (++p == name) 12829382Seric continue; 12839382Seric savechar = *p; 12849382Seric *p = '\0'; 12859382Seric 12869382Seric /* translate the name to be relative */ 128759163Seric flags = RF_HEADERADDR|RF_ADDDOMAIN; 128859163Seric if (bitset(H_FROM, h->h_flags)) 128959163Seric flags |= RF_SENDERADDR; 1290*69713Seric #if USERDB 129168522Seric else if (e->e_from.q_mailer != NULL && 129268522Seric bitnset(M_UDBRECIPIENT, e->e_from.q_mailer->m_flags)) 129368522Seric { 129468522Seric extern char *udbsender(); 129568522Seric 129668522Seric name = udbsender(name); 129768522Seric } 129868522Seric #endif 129959163Seric stat = EX_OK; 130065870Seric name = remotename(name, mci->mci_mailer, flags, &stat, e); 13019382Seric if (*name == '\0') 13029382Seric { 13039382Seric *p = savechar; 13049382Seric continue; 13059382Seric } 13069382Seric 13079382Seric /* output the name with nice formatting */ 130854983Seric opos += strlen(name); 13099382Seric if (!firstone) 13109382Seric opos += 2; 131166004Seric if (opos > omax && !firstone) 13129382Seric { 131310178Seric (void) strcpy(obp, ",\n"); 131465870Seric putline(obuf, mci); 13159382Seric obp = obuf; 131666255Seric (void) strcpy(obp, " "); 131710161Seric opos = strlen(obp); 131810161Seric obp += opos; 131954983Seric opos += strlen(name); 13209382Seric } 13219382Seric else if (!firstone) 13229382Seric { 132366255Seric (void) strcpy(obp, ", "); 13249382Seric obp += 2; 13259382Seric } 13269382Seric 132754983Seric while ((c = *name++) != '\0' && obp < &obuf[MAXLINE]) 132854983Seric *obp++ = c; 13299382Seric firstone = FALSE; 13309382Seric *p = savechar; 13319382Seric } 13329382Seric (void) strcpy(obp, "\n"); 133365870Seric putline(obuf, mci); 13349382Seric } 13359382Seric /* 133658170Seric ** COPYHEADER -- copy header list 13379382Seric ** 133858170Seric ** This routine is the equivalent of newstr for header lists 133958170Seric ** 13409382Seric ** Parameters: 134158170Seric ** header -- list of header structures to copy. 13429382Seric ** 13439382Seric ** Returns: 134458170Seric ** a copy of 'header'. 13459382Seric ** 13469382Seric ** Side Effects: 13479382Seric ** none. 13489382Seric */ 13499382Seric 135058170Seric HDR * 135158170Seric copyheader(header) 135258170Seric register HDR *header; 13539382Seric { 135458170Seric register HDR *newhdr; 135558170Seric HDR *ret; 135658170Seric register HDR **tail = &ret; 13579382Seric 135858170Seric while (header != NULL) 135958170Seric { 136058170Seric newhdr = (HDR *) xalloc(sizeof(HDR)); 136158170Seric STRUCTCOPY(*header, *newhdr); 136258170Seric *tail = newhdr; 136358170Seric tail = &newhdr->h_link; 136458170Seric header = header->h_link; 136558170Seric } 136658170Seric *tail = NULL; 136758170Seric 136858170Seric return ret; 13699382Seric } 1370