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*69105Seric static char sccsid[] = "@(#)headers.c 8.60 (Berkeley) 04/29/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 */ 15264351Seric #ifdef 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 35758929Seric ** message priority). 3587783Seric ** 3597783Seric ** Returns: 3607783Seric ** none. 3617783Seric ** 3627783Seric ** Side Effects: 3637783Seric ** Sets a bunch of global variables from information 3649382Seric ** in the collected header. 3659382Seric ** Aborts the message if the hop count is exceeded. 3667783Seric */ 3677783Seric 36858929Seric eatheader(e, full) 3699382Seric register ENVELOPE *e; 37058929Seric bool full; 3717783Seric { 3727783Seric register HDR *h; 3737783Seric register char *p; 3749382Seric int hopcnt = 0; 37557208Seric char *msgid; 37658688Seric char buf[MAXLINE]; 3777783Seric 37858688Seric /* 37958688Seric ** Set up macros for possible expansion in headers. 38058688Seric */ 38158688Seric 38258704Seric define('f', e->e_sender, e); 38358704Seric define('g', e->e_sender, e); 38464148Seric if (e->e_origrcpt != NULL && *e->e_origrcpt != '\0') 38564148Seric define('u', e->e_origrcpt, e); 38664148Seric else 38764148Seric define('u', NULL, e); 38858688Seric 38965052Seric /* full name of from person */ 39067546Seric p = hvalue("full-name", e->e_header); 39165052Seric if (p != NULL) 39265052Seric define('x', p, e); 39365052Seric 3949382Seric if (tTd(32, 1)) 3959382Seric printf("----- collected header -----\n"); 39657208Seric msgid = "<none>"; 3979382Seric for (h = e->e_header; h != NULL; h = h->h_link) 3987783Seric { 39964156Seric if (h->h_value == NULL) 40064156Seric { 40164156Seric if (tTd(32, 1)) 40264156Seric printf("%s: <NULL>\n", h->h_field); 40364156Seric continue; 40464156Seric } 40564156Seric 40658688Seric /* do early binding */ 40764156Seric if (bitset(H_DEFAULT, h->h_flags)) 40858688Seric { 40968529Seric expand(h->h_value, buf, sizeof buf, e); 41058688Seric if (buf[0] != '\0') 41158688Seric { 41258688Seric h->h_value = newstr(buf); 41358688Seric h->h_flags &= ~H_DEFAULT; 41458688Seric } 41558688Seric } 41658688Seric 4179382Seric if (tTd(32, 1)) 41865152Seric { 41965152Seric printf("%s: ", h->h_field); 42065152Seric xputs(h->h_value); 42165152Seric printf("\n"); 42265152Seric } 42357359Seric 42411414Seric /* count the number of times it has been processed */ 4259382Seric if (bitset(H_TRACE, h->h_flags)) 4269382Seric hopcnt++; 42711414Seric 42811414Seric /* send to this person if we so desire */ 42911414Seric if (GrabTo && bitset(H_RCPT, h->h_flags) && 43011414Seric !bitset(H_DEFAULT, h->h_flags) && 43155012Seric (!bitset(EF_RESENT, e->e_flags) || bitset(H_RESENT, h->h_flags))) 43211414Seric { 43363839Seric int saveflags = e->e_flags; 43463839Seric 43564283Seric (void) sendtolist(h->h_value, NULLADDR, 43667982Seric &e->e_sendqueue, 0, e); 43763839Seric 43863839Seric /* delete fatal errors generated by this address */ 43964148Seric if (!GrabTo && !bitset(EF_FATALERRS, saveflags)) 44063839Seric e->e_flags &= ~EF_FATALERRS; 44111414Seric } 44211414Seric 44357208Seric /* save the message-id for logging */ 44464156Seric if (full && strcasecmp(h->h_field, "message-id") == 0) 44511290Seric { 44657208Seric msgid = h->h_value; 44759859Seric while (isascii(*msgid) && isspace(*msgid)) 44859859Seric msgid++; 44911290Seric } 45057359Seric 45157359Seric /* see if this is a return-receipt header */ 45257359Seric if (bitset(H_RECEIPTTO, h->h_flags)) 45357359Seric e->e_receiptto = h->h_value; 4549382Seric } 4559382Seric if (tTd(32, 1)) 4567783Seric printf("----------------------------\n"); 4577783Seric 45858145Seric /* if we are just verifying (that is, sendmail -t -bv), drop out now */ 45958145Seric if (OpMode == MD_VERIFY) 46058145Seric return; 46158145Seric 4629382Seric /* store hop count */ 4639382Seric if (hopcnt > e->e_hopcount) 4649382Seric e->e_hopcount = hopcnt; 4659382Seric 4667783Seric /* message priority */ 46767546Seric p = hvalue("precedence", e->e_header); 4689382Seric if (p != NULL) 4699382Seric e->e_class = priencode(p); 47058929Seric if (full) 47167730Seric { 47225013Seric e->e_msgpriority = e->e_msgsize 47324981Seric - e->e_class * WkClassFact 47424981Seric + e->e_nrcpts * WkRecipFact; 47567730Seric if (e->e_class < 0) 47667730Seric e->e_timeoutclass = TOC_NONURGENT; 47767730Seric else if (e->e_class > 0) 47867730Seric e->e_timeoutclass = TOC_URGENT; 47967730Seric } 4807783Seric 48167730Seric /* message timeout priority */ 48267730Seric p = hvalue("priority", e->e_header); 48367730Seric if (full && p != NULL) 48467730Seric { 48567730Seric /* (this should be in the configuration file) */ 48667730Seric if (strcasecmp(p, "urgent")) 48767730Seric e->e_timeoutclass = TOC_URGENT; 48867730Seric else if (strcasecmp(p, "normal")) 48967730Seric e->e_timeoutclass = TOC_NORMAL; 49067730Seric else if (strcasecmp(p, "non-urgent")) 49167730Seric e->e_timeoutclass = TOC_NONURGENT; 49267730Seric } 49367730Seric 4947783Seric /* date message originated */ 49567546Seric p = hvalue("posted-date", e->e_header); 4967783Seric if (p == NULL) 49767546Seric p = hvalue("date", e->e_header); 4987783Seric if (p != NULL) 4999382Seric define('a', p, e); 50011290Seric 50168884Seric /* check to see if this is a MIME message */ 502*69105Seric if ((e->e_bodytype != NULL && 503*69105Seric strcasecmp(e->e_bodytype, "8BITMIME") == 0) || 50468884Seric hvalue("MIME-Version", e->e_header) != NULL) 505*69105Seric { 50668884Seric e->e_flags |= EF_IS_MIME; 507*69105Seric if (HasEightBits) 508*69105Seric e->e_bodytype = "8BITMIME"; 509*69105Seric } 51068884Seric 51111290Seric /* 51265983Seric ** From person in antiquated ARPANET mode 51365983Seric ** required by UK Grey Book e-mail gateways (sigh) 51465983Seric */ 51565983Seric 51665983Seric if (OpMode == MD_ARPAFTP) 51765983Seric { 51865983Seric register struct hdrinfo *hi; 51965983Seric 52065983Seric for (hi = HdrInfo; hi->hi_field != NULL; hi++) 52165983Seric { 52265983Seric if (bitset(H_FROM, hi->hi_flags) && 52365983Seric (!bitset(H_RESENT, hi->hi_flags) || 52465983Seric bitset(EF_RESENT, e->e_flags)) && 52567546Seric (p = hvalue(hi->hi_field, e->e_header)) != NULL) 52665983Seric break; 52765983Seric } 52865983Seric if (hi->hi_field != NULL) 52965983Seric { 53065983Seric if (tTd(32, 2)) 53165983Seric printf("eatheader: setsender(*%s == %s)\n", 53265983Seric hi->hi_field, p); 53365983Seric setsender(p, e, NULL, TRUE); 53465983Seric } 53565983Seric } 53665983Seric 53765983Seric /* 53811290Seric ** Log collection information. 53911290Seric */ 54011290Seric 54111290Seric # ifdef LOG 54268036Seric if (bitset(EF_LOGSENDER, e->e_flags) && LogLevel > 4) 54365089Seric logsender(e, msgid); 54465089Seric # endif /* LOG */ 54565089Seric e->e_flags &= ~EF_LOGSENDER; 54665089Seric } 54765089Seric /* 54865089Seric ** LOGSENDER -- log sender information 54965089Seric ** 55065089Seric ** Parameters: 55165089Seric ** e -- the envelope to log 55265089Seric ** msgid -- the message id 55365089Seric ** 55465089Seric ** Returns: 55565089Seric ** none 55665089Seric */ 55765089Seric 55865089Seric logsender(e, msgid) 55965089Seric register ENVELOPE *e; 56065089Seric char *msgid; 56165089Seric { 56266748Seric # ifdef LOG 56365089Seric char *name; 56465089Seric register char *sbp; 56565089Seric register char *p; 56667901Seric int l; 56768528Seric char hbuf[MAXNAME + 1]; 56868528Seric char sbuf[MAXLINE + 1]; 56968528Seric char mbuf[MAXNAME + 1]; 57065089Seric 57167901Seric /* don't allow newlines in the message-id */ 57267901Seric if (msgid != NULL) 57367901Seric { 57467901Seric l = strlen(msgid); 57567901Seric if (l > sizeof mbuf - 1) 57667901Seric l = sizeof mbuf - 1; 57767901Seric bcopy(msgid, mbuf, l); 57867901Seric mbuf[l] = '\0'; 57967901Seric p = mbuf; 58067901Seric while ((p = strchr(p, '\n')) != NULL) 58167901Seric *p++ = ' '; 58267901Seric } 58367901Seric 58465089Seric if (bitset(EF_RESPONSE, e->e_flags)) 58565089Seric name = "[RESPONSE]"; 58665089Seric else if ((name = macvalue('_', e)) != NULL) 58765089Seric ; 58866003Seric else if (RealHostName == NULL) 58966003Seric name = "localhost"; 59065089Seric else if (RealHostName[0] == '[') 59165089Seric name = RealHostName; 59265089Seric else 59311290Seric { 59465089Seric name = hbuf; 59565089Seric (void) sprintf(hbuf, "%.80s", RealHostName); 59665089Seric if (RealHostAddr.sa.sa_family != 0) 59757359Seric { 59865089Seric p = &hbuf[strlen(hbuf)]; 59965089Seric (void) sprintf(p, " (%s)", 60065089Seric anynet_ntoa(&RealHostAddr)); 60157359Seric } 60265089Seric } 60357359Seric 60465089Seric /* some versions of syslog only take 5 printf args */ 60565059Seric # if (SYSLOG_BUFSIZE) >= 256 60665089Seric sbp = sbuf; 60765089Seric sprintf(sbp, "from=%.200s, size=%ld, class=%d, pri=%ld, nrcpts=%d", 60867788Seric e->e_from.q_paddr == NULL ? "<NONE>" : e->e_from.q_paddr, 60967788Seric e->e_msgsize, e->e_class, e->e_msgpriority, e->e_nrcpts); 61065089Seric sbp += strlen(sbp); 61165089Seric if (msgid != NULL) 61265089Seric { 61367901Seric sprintf(sbp, ", msgid=%.100s", mbuf); 61460575Seric sbp += strlen(sbp); 61565089Seric } 61665089Seric if (e->e_bodytype != NULL) 61765089Seric { 61865089Seric (void) sprintf(sbp, ", bodytype=%.20s", e->e_bodytype); 61965089Seric sbp += strlen(sbp); 62065089Seric } 62165089Seric p = macvalue('r', e); 62265089Seric if (p != NULL) 62365089Seric (void) sprintf(sbp, ", proto=%.20s", p); 62465089Seric syslog(LOG_INFO, "%s: %s, relay=%s", 62565089Seric e->e_id, sbuf, name); 62665059Seric 62765059Seric # else /* short syslog buffer */ 62865059Seric 62965089Seric syslog(LOG_INFO, "%s: from=%s", 63067788Seric e->e_id, e->e_from.q_paddr == NULL ? "<NONE>" : 63167788Seric shortenstring(e->e_from.q_paddr, 83)); 63265089Seric syslog(LOG_INFO, "%s: size=%ld, class=%ld, pri=%ld, nrcpts=%d", 63365089Seric e->e_id, e->e_msgsize, e->e_class, 63465089Seric e->e_msgpriority, e->e_nrcpts); 63565089Seric if (msgid != NULL) 63667901Seric syslog(LOG_INFO, "%s: msgid=%s", e->e_id, mbuf); 63765650Seric sbp = sbuf; 63865650Seric sprintf(sbp, "%s:", e->e_id); 63965650Seric sbp += strlen(sbp); 64065089Seric if (e->e_bodytype != NULL) 64165650Seric { 64265650Seric sprintf(sbp, " bodytype=%s,", e->e_bodytype); 64365650Seric sbp += strlen(sbp); 64465650Seric } 64565089Seric p = macvalue('r', e); 64665089Seric if (p != NULL) 64765650Seric { 64865731Seric sprintf(sbp, " proto=%s,", p); 64965650Seric sbp += strlen(sbp); 65065650Seric } 65165650Seric syslog(LOG_INFO, "%s relay=%s", sbuf, name); 65265059Seric # endif 65366748Seric # endif 6547783Seric } 6557783Seric /* 6567783Seric ** PRIENCODE -- encode external priority names into internal values. 6577783Seric ** 6587783Seric ** Parameters: 6597783Seric ** p -- priority in ascii. 6607783Seric ** 6617783Seric ** Returns: 6627783Seric ** priority as a numeric level. 6637783Seric ** 6647783Seric ** Side Effects: 6657783Seric ** none. 6667783Seric */ 6677783Seric 6687783Seric priencode(p) 6697783Seric char *p; 6707783Seric { 6718253Seric register int i; 6727783Seric 6738253Seric for (i = 0; i < NumPriorities; i++) 6747783Seric { 67533725Sbostic if (!strcasecmp(p, Priorities[i].pri_name)) 6768253Seric return (Priorities[i].pri_val); 6777783Seric } 6788253Seric 6798253Seric /* unknown priority */ 6808253Seric return (0); 6817783Seric } 6827783Seric /* 6837890Seric ** CRACKADDR -- parse an address and turn it into a macro 6847783Seric ** 6857783Seric ** This doesn't actually parse the address -- it just extracts 6867783Seric ** it and replaces it with "$g". The parse is totally ad hoc 6877783Seric ** and isn't even guaranteed to leave something syntactically 6887783Seric ** identical to what it started with. However, it does leave 6897783Seric ** something semantically identical. 6907783Seric ** 69151379Seric ** This algorithm has been cleaned up to handle a wider range 69251379Seric ** of cases -- notably quoted and backslash escaped strings. 69351379Seric ** This modification makes it substantially better at preserving 69451379Seric ** the original syntax. 6957783Seric ** 6967783Seric ** Parameters: 6977890Seric ** addr -- the address to be cracked. 6987783Seric ** 6997783Seric ** Returns: 7007783Seric ** a pointer to the new version. 7017783Seric ** 7027783Seric ** Side Effects: 7037890Seric ** none. 7047783Seric ** 7057783Seric ** Warning: 7067783Seric ** The return value is saved in local storage and should 7077783Seric ** be copied if it is to be reused. 7087783Seric */ 7097783Seric 7107783Seric char * 7117890Seric crackaddr(addr) 7127890Seric register char *addr; 7137783Seric { 7147783Seric register char *p; 71551379Seric register char c; 71651379Seric int cmtlev; 71756764Seric int realcmtlev; 71856764Seric int anglelev, realanglelev; 71951379Seric int copylev; 72051379Seric bool qmode; 72156764Seric bool realqmode; 72256764Seric bool skipping; 72351379Seric bool putgmac = FALSE; 72456735Seric bool quoteit = FALSE; 72564148Seric bool gotangle = FALSE; 72668756Seric bool gotcolon = FALSE; 72751379Seric register char *bp; 72856764Seric char *buflim; 72968756Seric char *bufhead; 73068756Seric char *addrhead; 73168528Seric static char buf[MAXNAME + 1]; 7327783Seric 7337783Seric if (tTd(33, 1)) 7347890Seric printf("crackaddr(%s)\n", addr); 7357783Seric 7368082Seric /* strip leading spaces */ 73758050Seric while (*addr != '\0' && isascii(*addr) && isspace(*addr)) 7388082Seric addr++; 7398082Seric 7407783Seric /* 74151379Seric ** Start by assuming we have no angle brackets. This will be 74251379Seric ** adjusted later if we find them. 7437783Seric */ 7447783Seric 74568756Seric bp = bufhead = buf; 74656764Seric buflim = &buf[sizeof buf - 5]; 74768756Seric p = addrhead = addr; 74856764Seric copylev = anglelev = realanglelev = cmtlev = realcmtlev = 0; 74956764Seric qmode = realqmode = FALSE; 75051379Seric 75151379Seric while ((c = *p++) != '\0') 7527783Seric { 75356764Seric /* 75456764Seric ** If the buffer is overful, go into a special "skipping" 75556764Seric ** mode that tries to keep legal syntax but doesn't actually 75656764Seric ** output things. 75756764Seric */ 7587783Seric 75956764Seric skipping = bp >= buflim; 76056735Seric 76156764Seric if (copylev > 0 && !skipping) 76256764Seric *bp++ = c; 76356735Seric 76451379Seric /* check for backslash escapes */ 76551379Seric if (c == '\\') 7667783Seric { 76758890Seric /* arrange to quote the address */ 76858890Seric if (cmtlev <= 0 && !qmode) 76958890Seric quoteit = TRUE; 77058890Seric 77151379Seric if ((c = *p++) == '\0') 7727783Seric { 77351379Seric /* too far */ 77451379Seric p--; 77551379Seric goto putg; 7767783Seric } 77756764Seric if (copylev > 0 && !skipping) 77851379Seric *bp++ = c; 77951379Seric goto putg; 7807783Seric } 7817783Seric 78251379Seric /* check for quoted strings */ 78364967Seric if (c == '"' && cmtlev <= 0) 7847783Seric { 78551379Seric qmode = !qmode; 78656764Seric if (copylev > 0 && !skipping) 78756764Seric realqmode = !realqmode; 78851379Seric continue; 7897783Seric } 79051379Seric if (qmode) 79151379Seric goto putg; 7927783Seric 79351379Seric /* check for comments */ 79451379Seric if (c == '(') 7957783Seric { 79651379Seric cmtlev++; 79756764Seric 79856764Seric /* allow space for closing paren */ 79956764Seric if (!skipping) 80056764Seric { 80156764Seric buflim--; 80256764Seric realcmtlev++; 80356764Seric if (copylev++ <= 0) 80456764Seric { 80556764Seric *bp++ = ' '; 80656764Seric *bp++ = c; 80756764Seric } 80856764Seric } 80951379Seric } 81051379Seric if (cmtlev > 0) 81151379Seric { 81251379Seric if (c == ')') 8137783Seric { 81451379Seric cmtlev--; 81551379Seric copylev--; 81656764Seric if (!skipping) 81756764Seric { 81856764Seric realcmtlev--; 81956764Seric buflim++; 82056764Seric } 8217783Seric } 8227783Seric continue; 8237783Seric } 82456764Seric else if (c == ')') 82556764Seric { 82656764Seric /* syntax error: unmatched ) */ 82765544Seric if (copylev > 0 && !skipping) 82856764Seric bp--; 82956764Seric } 8307783Seric 83168756Seric /* check for group: list; syntax */ 83268760Seric if (c == ':' && anglelev <= 0 && !gotcolon && !ColonOkInAddr) 83368756Seric { 83468756Seric register char *q; 83568756Seric 83668760Seric if (*p == ':') 83768760Seric { 83868760Seric /* special case -- :: syntax */ 83968760Seric if (cmtlev <= 0 && !qmode) 84068760Seric quoteit = TRUE; 84168760Seric if (copylev > 0 && !skipping) 84268760Seric { 84368760Seric *bp++ = c; 84468760Seric *bp++ = c; 84568760Seric } 84668760Seric p++; 84768760Seric goto putg; 84868760Seric } 84968760Seric 85068756Seric gotcolon = TRUE; 85168756Seric 85268760Seric bp = bufhead; 85368760Seric if (quoteit) 85468760Seric { 85568760Seric *bp++ = '"'; 85668760Seric 85768760Seric /* back up over the ':' and any spaces */ 85868760Seric --p; 85968760Seric while (isascii(*--p) && isspace(*p)) 86068760Seric continue; 86168756Seric p++; 86268760Seric } 86368756Seric for (q = addrhead; q < p; ) 86468756Seric { 86568756Seric c = *q++; 86668756Seric if (bp < buflim) 86768756Seric { 86868760Seric if (quoteit && c == '"') 86968760Seric *bp++ = '\\'; 87068756Seric *bp++ = c; 87168756Seric } 87268756Seric } 87368760Seric if (quoteit) 87468760Seric { 87568760Seric if (bp == &bufhead[1]) 87668760Seric bp--; 87768760Seric else 87868760Seric *bp++ = '"'; 87968760Seric while ((c = *p++) != ':') 88068760Seric { 88168760Seric if (bp < buflim) 88268760Seric *bp++ = c; 88368760Seric } 88468760Seric *bp++ = c; 88568760Seric } 88668760Seric 88768760Seric /* any trailing white space is part of group: */ 88868760Seric while (isascii(*p) && isspace(*p) && bp < buflim) 88968760Seric *bp++ = *p++; 89068756Seric copylev = 0; 89168760Seric putgmac = quoteit = FALSE; 89268756Seric bufhead = bp; 89368756Seric addrhead = p; 89468756Seric continue; 89568756Seric } 89668756Seric 89768756Seric if (c == ';' && copylev <= 0 && !ColonOkInAddr) 89868756Seric { 89968756Seric register char *q = p; 90068756Seric 90168756Seric if (bp < buflim) 90268756Seric *bp++ = c; 90368756Seric } 90468756Seric 90556764Seric /* check for characters that may have to be quoted */ 90664148Seric if (strchr(".'@,;:\\()[]", c) != NULL) 90756764Seric { 90856764Seric /* 90956764Seric ** If these occur as the phrase part of a <> 91056764Seric ** construct, but are not inside of () or already 91156764Seric ** quoted, they will have to be quoted. Note that 91256764Seric ** now (but don't actually do the quoting). 91356764Seric */ 91456764Seric 91556764Seric if (cmtlev <= 0 && !qmode) 91656764Seric quoteit = TRUE; 91756764Seric } 91856764Seric 91951379Seric /* check for angle brackets */ 92051379Seric if (c == '<') 92151379Seric { 92256735Seric register char *q; 92356735Seric 92464148Seric /* assume first of two angles is bogus */ 92564148Seric if (gotangle) 92664148Seric quoteit = TRUE; 92764148Seric gotangle = TRUE; 92864148Seric 92951379Seric /* oops -- have to change our mind */ 93064752Seric anglelev = 1; 93156764Seric if (!skipping) 93264752Seric realanglelev = 1; 93356764Seric 93468756Seric bp = bufhead; 93556735Seric if (quoteit) 93656735Seric { 93756735Seric *bp++ = '"'; 93856735Seric 93956735Seric /* back up over the '<' and any spaces */ 94056735Seric --p; 94158050Seric while (isascii(*--p) && isspace(*p)) 94256735Seric continue; 94356735Seric p++; 94456735Seric } 94568756Seric for (q = addrhead; q < p; ) 94656735Seric { 94756735Seric c = *q++; 94856764Seric if (bp < buflim) 94956764Seric { 95056764Seric if (quoteit && c == '"') 95156764Seric *bp++ = '\\'; 95256764Seric *bp++ = c; 95356764Seric } 95456735Seric } 95556735Seric if (quoteit) 95656735Seric { 95764148Seric if (bp == &buf[1]) 95864148Seric bp--; 95964148Seric else 96064148Seric *bp++ = '"'; 96156764Seric while ((c = *p++) != '<') 96256764Seric { 96356764Seric if (bp < buflim) 96456764Seric *bp++ = c; 96556764Seric } 96656764Seric *bp++ = c; 96756735Seric } 96851379Seric copylev = 0; 96956735Seric putgmac = quoteit = FALSE; 97051379Seric continue; 97151379Seric } 9727783Seric 97351379Seric if (c == '>') 9747783Seric { 97556764Seric if (anglelev > 0) 97656764Seric { 97756764Seric anglelev--; 97856764Seric if (!skipping) 97956764Seric { 98056764Seric realanglelev--; 98156764Seric buflim++; 98256764Seric } 98356764Seric } 98456764Seric else if (!skipping) 98556764Seric { 98656764Seric /* syntax error: unmatched > */ 98756764Seric if (copylev > 0) 98856764Seric bp--; 98964752Seric quoteit = TRUE; 99056764Seric continue; 99156764Seric } 99251379Seric if (copylev++ <= 0) 99351379Seric *bp++ = c; 99451379Seric continue; 9957783Seric } 99651379Seric 99751379Seric /* must be a real address character */ 99851379Seric putg: 99951379Seric if (copylev <= 0 && !putgmac) 100051379Seric { 100158050Seric *bp++ = MACROEXPAND; 100251379Seric *bp++ = 'g'; 100351379Seric putgmac = TRUE; 100451379Seric } 10057783Seric } 10067783Seric 100756764Seric /* repair any syntactic damage */ 100856764Seric if (realqmode) 100956764Seric *bp++ = '"'; 101056764Seric while (realcmtlev-- > 0) 101156764Seric *bp++ = ')'; 101256764Seric while (realanglelev-- > 0) 101356764Seric *bp++ = '>'; 101451379Seric *bp++ = '\0'; 10157783Seric 10167783Seric if (tTd(33, 1)) 10177944Seric printf("crackaddr=>`%s'\n", buf); 10187783Seric 10197783Seric return (buf); 10207783Seric } 10219382Seric /* 10229382Seric ** PUTHEADER -- put the header part of a message from the in-core copy 10239382Seric ** 10249382Seric ** Parameters: 102565870Seric ** mci -- the connection information. 102667546Seric ** h -- the header to put. 10279382Seric ** e -- envelope to use. 10289382Seric ** 10299382Seric ** Returns: 10309382Seric ** none. 10319382Seric ** 10329382Seric ** Side Effects: 10339382Seric ** none. 10349382Seric */ 10359382Seric 103657589Seric /* 103757589Seric * Macro for fast max (not available in e.g. DG/UX, 386/ix). 103857589Seric */ 103957589Seric #ifndef MAX 104057589Seric # define MAX(a,b) (((a)>(b))?(a):(b)) 104157589Seric #endif 104257589Seric 104368228Seric putheader(mci, h, e) 104465870Seric register MCI *mci; 104567546Seric register HDR *h; 10469382Seric register ENVELOPE *e; 10479382Seric { 104857135Seric char buf[MAX(MAXLINE,BUFSIZ)]; 104957135Seric char obuf[MAXLINE]; 10509382Seric 105159882Seric if (tTd(34, 1)) 105265870Seric printf("--- putheader, mailer = %s ---\n", 105365870Seric mci->mci_mailer->m_name); 105459882Seric 105567546Seric mci->mci_flags |= MCIF_INHEADER; 105667546Seric for (; h != NULL; h = h->h_link) 10579382Seric { 10589382Seric register char *p; 105910689Seric extern bool bitintersect(); 10609382Seric 106159882Seric if (tTd(34, 11)) 106259882Seric { 106359882Seric printf(" %s: ", h->h_field); 106459882Seric xputs(h->h_value); 106559882Seric } 106659882Seric 10679382Seric if (bitset(H_CHECK|H_ACHECK, h->h_flags) && 106865870Seric !bitintersect(h->h_mflags, mci->mci_mailer->m_flags)) 106959882Seric { 107059882Seric if (tTd(34, 11)) 107159882Seric printf(" (skipped)\n"); 10729382Seric continue; 107359882Seric } 10749382Seric 107511414Seric /* handle Resent-... headers specially */ 107611414Seric if (bitset(H_RESENT, h->h_flags) && !bitset(EF_RESENT, e->e_flags)) 107759882Seric { 107859882Seric if (tTd(34, 11)) 107959882Seric printf(" (skipped (resent))\n"); 108011414Seric continue; 108159882Seric } 108211414Seric 108366784Seric /* suppress return receipts if requested */ 108466784Seric if (bitset(H_RECEIPTTO, h->h_flags) && 108566784Seric bitset(EF_NORECEIPT, e->e_flags)) 108666784Seric { 108766784Seric if (tTd(34, 11)) 108866784Seric printf(" (skipped (receipt))\n"); 108966784Seric continue; 109066784Seric } 109166784Seric 109267694Seric /* suppress Content-Transfer-Encoding: if we are MIMEing */ 109367694Seric if (bitset(H_CTE, h->h_flags) && 109468228Seric bitset(MCIF_CVT8TO7, mci->mci_flags)) 109567694Seric { 109667694Seric if (tTd(34, 11)) 109767694Seric printf(" (skipped (content-transfer-encoding))\n"); 109867694Seric continue; 109967694Seric } 110067694Seric 110165152Seric /* macro expand value if generated internally */ 11029382Seric p = h->h_value; 11039382Seric if (bitset(H_DEFAULT, h->h_flags)) 11049382Seric { 110568529Seric expand(p, buf, sizeof buf, e); 11069382Seric p = buf; 11079382Seric if (p == NULL || *p == '\0') 110865152Seric { 110965152Seric if (tTd(34, 11)) 111065152Seric printf(" (skipped -- null value)\n"); 11119382Seric continue; 111265152Seric } 11139382Seric } 11149382Seric 111565152Seric if (tTd(34, 11)) 111665152Seric printf("\n"); 111765152Seric 111868449Seric if (bitset(H_STRIPVAL, h->h_flags)) 11199382Seric { 112068449Seric /* empty field */ 112168449Seric (void) sprintf(obuf, "%s:", h->h_field); 112268449Seric putline(obuf, mci); 112368449Seric } 112468449Seric else if (bitset(H_FROM|H_RCPT, h->h_flags)) 112568449Seric { 11269382Seric /* address field */ 11279382Seric bool oldstyle = bitset(EF_OLDSTYLE, e->e_flags); 11289382Seric 11299382Seric if (bitset(H_FROM, h->h_flags)) 11309382Seric oldstyle = FALSE; 113165870Seric commaize(h, p, oldstyle, mci, e); 11329382Seric } 11339382Seric else 11349382Seric { 11359382Seric /* vanilla header line */ 113612159Seric register char *nlp; 113712159Seric 113859579Seric (void) sprintf(obuf, "%s: ", h->h_field); 113956795Seric while ((nlp = strchr(p, '\n')) != NULL) 114012159Seric { 114112159Seric *nlp = '\0'; 114212159Seric (void) strcat(obuf, p); 114312159Seric *nlp = '\n'; 114465870Seric putline(obuf, mci); 114512159Seric p = ++nlp; 114612161Seric obuf[0] = '\0'; 114712159Seric } 114812159Seric (void) strcat(obuf, p); 114965870Seric putline(obuf, mci); 11509382Seric } 11519382Seric } 115267887Seric 115367887Seric /* 115467887Seric ** If we are converting this to a MIME message, add the 115567889Seric ** MIME headers. 115667887Seric */ 115767887Seric 115867887Seric if (bitset(MM_MIME8BIT, MimeMode) && 115967887Seric bitset(EF_HAS8BIT, e->e_flags) && 116067887Seric !bitnset(M_8BITS, mci->mci_mailer->m_flags) && 116167889Seric !bitset(MCIF_CVT8TO7, mci->mci_flags)) 116267887Seric { 116367889Seric if (hvalue("MIME-Version", e->e_header) == NULL) 116467889Seric putline("MIME-Version: 1.0", mci); 116567889Seric if (hvalue("Content-Type", e->e_header) == NULL) 116667889Seric { 116767889Seric sprintf(obuf, "Content-Type: text/plain; charset=%s", 116867896Seric defcharset(e)); 116967889Seric putline(obuf, mci); 117067889Seric } 117167889Seric if (hvalue("Content-Transfer-Encoding", e->e_header) == NULL) 117267889Seric putline("Content-Transfer-Encoding: 8bit", mci); 117367887Seric } 11749382Seric } 11759382Seric /* 11769382Seric ** COMMAIZE -- output a header field, making a comma-translated list. 11779382Seric ** 11789382Seric ** Parameters: 11799382Seric ** h -- the header field to output. 11809382Seric ** p -- the value to put in it. 11819382Seric ** oldstyle -- TRUE if this is an old style header. 118265870Seric ** mci -- the connection information. 118355012Seric ** e -- the envelope containing the message. 11849382Seric ** 11859382Seric ** Returns: 11869382Seric ** none. 11879382Seric ** 11889382Seric ** Side Effects: 11899382Seric ** outputs "p" to file "fp". 11909382Seric */ 11919382Seric 119265870Seric void 119365870Seric commaize(h, p, oldstyle, mci, e) 11949382Seric register HDR *h; 11959382Seric register char *p; 11969382Seric bool oldstyle; 119765870Seric register MCI *mci; 119855012Seric register ENVELOPE *e; 11999382Seric { 12009382Seric register char *obp; 12019382Seric int opos; 120266004Seric int omax; 12039382Seric bool firstone = TRUE; 120411157Seric char obuf[MAXLINE + 3]; 12059382Seric 12069382Seric /* 12079382Seric ** Output the address list translated by the 12089382Seric ** mailer and with commas. 12099382Seric */ 12109382Seric 12119382Seric if (tTd(14, 2)) 12129382Seric printf("commaize(%s: %s)\n", h->h_field, p); 12139382Seric 12149382Seric obp = obuf; 121559579Seric (void) sprintf(obp, "%s: ", h->h_field); 12169382Seric opos = strlen(h->h_field) + 2; 12179382Seric obp += opos; 121866254Seric omax = mci->mci_mailer->m_linelimit - 2; 121966254Seric if (omax < 0 || omax > 78) 122066254Seric omax = 78; 12219382Seric 12229382Seric /* 12239382Seric ** Run through the list of values. 12249382Seric */ 12259382Seric 12269382Seric while (*p != '\0') 12279382Seric { 12289382Seric register char *name; 122954983Seric register int c; 12309382Seric char savechar; 123159163Seric int flags; 123259163Seric auto int stat; 12339382Seric 12349382Seric /* 12359382Seric ** Find the end of the name. New style names 12369382Seric ** end with a comma, old style names end with 12379382Seric ** a space character. However, spaces do not 12389382Seric ** necessarily delimit an old-style name -- at 12399382Seric ** signs mean keep going. 12409382Seric */ 12419382Seric 12429382Seric /* find end of name */ 124358050Seric while ((isascii(*p) && isspace(*p)) || *p == ',') 12449382Seric p++; 12459382Seric name = p; 12469382Seric for (;;) 12479382Seric { 124858333Seric auto char *oldp; 124916909Seric char pvpbuf[PSBUFSIZE]; 12509382Seric 125165066Seric (void) prescan(p, oldstyle ? ' ' : ',', pvpbuf, 125268711Seric sizeof pvpbuf, &oldp, NULL); 125358333Seric p = oldp; 12549382Seric 12559382Seric /* look to see if we have an at sign */ 125658050Seric while (*p != '\0' && isascii(*p) && isspace(*p)) 12579382Seric p++; 12589382Seric 125958170Seric if (*p != '@') 12609382Seric { 12619382Seric p = oldp; 12629382Seric break; 12639382Seric } 12649382Seric p += *p == '@' ? 1 : 2; 126558050Seric while (*p != '\0' && isascii(*p) && isspace(*p)) 12669382Seric p++; 12679382Seric } 12689382Seric /* at the end of one complete name */ 12699382Seric 12709382Seric /* strip off trailing white space */ 127158050Seric while (p >= name && 127258050Seric ((isascii(*p) && isspace(*p)) || *p == ',' || *p == '\0')) 12739382Seric p--; 12749382Seric if (++p == name) 12759382Seric continue; 12769382Seric savechar = *p; 12779382Seric *p = '\0'; 12789382Seric 12799382Seric /* translate the name to be relative */ 128059163Seric flags = RF_HEADERADDR|RF_ADDDOMAIN; 128159163Seric if (bitset(H_FROM, h->h_flags)) 128259163Seric flags |= RF_SENDERADDR; 128368522Seric #ifdef USERDB 128468522Seric else if (e->e_from.q_mailer != NULL && 128568522Seric bitnset(M_UDBRECIPIENT, e->e_from.q_mailer->m_flags)) 128668522Seric { 128768522Seric extern char *udbsender(); 128868522Seric 128968522Seric name = udbsender(name); 129068522Seric } 129168522Seric #endif 129259163Seric stat = EX_OK; 129365870Seric name = remotename(name, mci->mci_mailer, flags, &stat, e); 12949382Seric if (*name == '\0') 12959382Seric { 12969382Seric *p = savechar; 12979382Seric continue; 12989382Seric } 12999382Seric 13009382Seric /* output the name with nice formatting */ 130154983Seric opos += strlen(name); 13029382Seric if (!firstone) 13039382Seric opos += 2; 130466004Seric if (opos > omax && !firstone) 13059382Seric { 130610178Seric (void) strcpy(obp, ",\n"); 130765870Seric putline(obuf, mci); 13089382Seric obp = obuf; 130966255Seric (void) strcpy(obp, " "); 131010161Seric opos = strlen(obp); 131110161Seric obp += opos; 131254983Seric opos += strlen(name); 13139382Seric } 13149382Seric else if (!firstone) 13159382Seric { 131666255Seric (void) strcpy(obp, ", "); 13179382Seric obp += 2; 13189382Seric } 13199382Seric 132054983Seric while ((c = *name++) != '\0' && obp < &obuf[MAXLINE]) 132154983Seric *obp++ = c; 13229382Seric firstone = FALSE; 13239382Seric *p = savechar; 13249382Seric } 13259382Seric (void) strcpy(obp, "\n"); 132665870Seric putline(obuf, mci); 13279382Seric } 13289382Seric /* 132958170Seric ** COPYHEADER -- copy header list 13309382Seric ** 133158170Seric ** This routine is the equivalent of newstr for header lists 133258170Seric ** 13339382Seric ** Parameters: 133458170Seric ** header -- list of header structures to copy. 13359382Seric ** 13369382Seric ** Returns: 133758170Seric ** a copy of 'header'. 13389382Seric ** 13399382Seric ** Side Effects: 13409382Seric ** none. 13419382Seric */ 13429382Seric 134358170Seric HDR * 134458170Seric copyheader(header) 134558170Seric register HDR *header; 13469382Seric { 134758170Seric register HDR *newhdr; 134858170Seric HDR *ret; 134958170Seric register HDR **tail = &ret; 13509382Seric 135158170Seric while (header != NULL) 135258170Seric { 135358170Seric newhdr = (HDR *) xalloc(sizeof(HDR)); 135458170Seric STRUCTCOPY(*header, *newhdr); 135558170Seric *tail = newhdr; 135658170Seric tail = &newhdr->h_link; 135758170Seric header = header->h_link; 135858170Seric } 135958170Seric *tail = NULL; 136058170Seric 136158170Seric return ret; 13629382Seric } 1363