122706Sdist /* 234921Sbostic * Copyright (c) 1983 Eric P. Allman 362525Sbostic * Copyright (c) 1988, 1993 462525Sbostic * The Regents of the University of California. All rights reserved. 533729Sbostic * 642826Sbostic * %sccs.include.redist.c% 733729Sbostic */ 822706Sdist 922706Sdist #ifndef lint 10*68760Seric static char sccsid[] = "@(#)headers.c 8.56 (Berkeley) 04/09/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)) 537677Seric printf("chompheader: %s\n", line); 547677Seric 5568717Seric headeronly = hdrp != NULL; 5668717Seric if (!headeronly) 5768717Seric hdrp = &e->e_header; 5868717Seric 594627Seric /* strip off options */ 6010689Seric clrbitmap(mopts); 614627Seric p = line; 6257405Seric if (*p == '?') 634627Seric { 644627Seric /* have some */ 6556795Seric register char *q = strchr(p + 1, *p); 664627Seric 674627Seric if (q != NULL) 684627Seric { 694627Seric *q++ = '\0'; 7010689Seric while (*++p != '\0') 7110689Seric setbitn(*p, mopts); 724627Seric p = q; 734627Seric } 744627Seric else 7568690Seric syserr("553 header syntax error, line \"%s\"", line); 769059Seric cond = TRUE; 774627Seric } 784627Seric 794091Seric /* find canonical name */ 804627Seric fname = p; 8164149Seric while (isascii(*p) && isgraph(*p) && *p != ':') 8264149Seric p++; 8364149Seric fvalue = p; 8464149Seric while (isascii(*p) && isspace(*p)) 8564149Seric p++; 8664150Seric if (*p++ != ':' || fname == fvalue) 8710118Seric { 8858151Seric syserr("553 header syntax error, line \"%s\"", line); 8910118Seric return (0); 9010118Seric } 9164149Seric *fvalue = '\0'; 9264149Seric fvalue = p; 934091Seric 944091Seric /* strip field value on front */ 954091Seric if (*fvalue == ' ') 964091Seric fvalue++; 974091Seric 984091Seric /* see if it is a known type */ 994091Seric for (hi = HdrInfo; hi->hi_field != NULL; hi++) 1004091Seric { 10159579Seric if (strcasecmp(hi->hi_field, fname) == 0) 1024091Seric break; 1034091Seric } 1044091Seric 10564283Seric if (tTd(31, 9)) 10664283Seric { 10764283Seric if (hi->hi_field == NULL) 10864283Seric printf("no header match\n"); 10964283Seric else 11067694Seric printf("header match, hi_flags=%x\n", hi->hi_flags); 11164283Seric } 11264283Seric 11311414Seric /* see if this is a resent message */ 11468717Seric if (!def && !headeronly && bitset(H_RESENT, hi->hi_flags)) 11555012Seric e->e_flags |= EF_RESENT; 11611414Seric 11768558Seric /* if this is an Errors-To: header keep track of it now */ 11868717Seric if (UseErrorsTo && !def && !headeronly && 11968717Seric bitset(H_ERRORSTO, hi->hi_flags)) 12068558Seric (void) sendtolist(fvalue, NULLADDR, &e->e_errorqueue, 0, e); 12168558Seric 1224091Seric /* if this means "end of header" quit now */ 1234091Seric if (bitset(H_EOH, hi->hi_flags)) 1244091Seric return (hi->hi_flags); 1254091Seric 12664653Seric /* 12764653Seric ** Drop explicit From: if same as what we would generate. 12864653Seric ** This is to make MH (which doesn't always give a full name) 12964653Seric ** insert the full name information in all circumstances. 13064653Seric */ 13164653Seric 13214784Seric p = "resent-from"; 13355012Seric if (!bitset(EF_RESENT, e->e_flags)) 13414784Seric p += 7; 13568717Seric if (!def && !headeronly && !bitset(EF_QUEUERUN, e->e_flags) && 13668717Seric strcasecmp(fname, p) == 0) 13711414Seric { 13863753Seric if (tTd(31, 2)) 13963753Seric { 14063753Seric printf("comparing header from (%s) against default (%s or %s)\n", 14163753Seric fvalue, e->e_from.q_paddr, e->e_from.q_user); 14263753Seric } 14355012Seric if (e->e_from.q_paddr != NULL && 14463753Seric (strcmp(fvalue, e->e_from.q_paddr) == 0 || 14563753Seric strcmp(fvalue, e->e_from.q_user) == 0)) 14611414Seric return (hi->hi_flags); 14764351Seric #ifdef MAYBENEXTRELEASE /* XXX UNTESTED XXX UNTESTED XXX UNTESTED XXX */ 14864351Seric #ifdef USERDB 14964351Seric else 15064351Seric { 15164351Seric auto ADDRESS a; 15264351Seric char *fancy; 15366123Seric bool oldSuprErrs = SuprErrs; 15464351Seric extern char *crackaddr(); 15564351Seric extern char *udbsender(); 15664351Seric 15764653Seric /* 15864653Seric ** Try doing USERDB rewriting even on fully commented 15964653Seric ** names; this saves the "comment" information (such 16064653Seric ** as full name) and rewrites the electronic part. 16166106Seric ** 16266106Seric ** XXX This code doesn't belong here -- parsing should 16366106Seric ** XXX not be done during collect() phase because 16466106Seric ** XXX error messages can confuse the SMTP phase. 16566123Seric ** XXX Setting SuprErrs is a crude hack around this 16666106Seric ** XXX problem. 16764653Seric */ 16864653Seric 16966106Seric if (OpMode == MD_SMTP || OpMode == MD_ARPAFTP) 17066123Seric SuprErrs = TRUE; 17164351Seric fancy = crackaddr(fvalue); 17264351Seric if (parseaddr(fvalue, &a, RF_COPYNONE, '\0', NULL, e) != NULL && 17367472Seric bitnset(M_CHECKUDB, a.q_mailer->m_flags) && 17464351Seric (p = udbsender(a.q_user)) != NULL) 17564351Seric { 17664351Seric char *oldg = macvalue('g', e); 17764351Seric 17864351Seric define('g', p, e); 17968529Seric expand(fancy, buf, sizeof buf, e); 18064351Seric define('g', oldg, e); 18164351Seric fvalue = buf; 18264351Seric } 18366123Seric SuprErrs = oldSuprErrs; 18464351Seric } 18564351Seric #endif 18664351Seric #endif 18711414Seric } 18811414Seric 18914784Seric /* delete default value for this header */ 19068717Seric for (hp = hdrp; (h = *hp) != NULL; hp = &h->h_link) 19114784Seric { 19259579Seric if (strcasecmp(fname, h->h_field) == 0 && 19314784Seric bitset(H_DEFAULT, h->h_flags) && 19414784Seric !bitset(H_FORCE, h->h_flags)) 19514784Seric h->h_value = NULL; 19614784Seric } 19714784Seric 19813012Seric /* create a new node */ 19913012Seric h = (HDR *) xalloc(sizeof *h); 20013012Seric h->h_field = newstr(fname); 20164134Seric h->h_value = newstr(fvalue); 20213012Seric h->h_link = NULL; 20323117Seric bcopy((char *) mopts, (char *) h->h_mflags, sizeof mopts); 20413012Seric *hp = h; 2058066Seric h->h_flags = hi->hi_flags; 2064091Seric if (def) 2074091Seric h->h_flags |= H_DEFAULT; 2089059Seric if (cond) 2099059Seric h->h_flags |= H_CHECK; 2104091Seric 2115937Seric /* hack to see if this is a new format message */ 21268717Seric if (!def && !headeronly && bitset(H_RCPT|H_FROM, h->h_flags) && 21356795Seric (strchr(fvalue, ',') != NULL || strchr(fvalue, '(') != NULL || 21456795Seric strchr(fvalue, '<') != NULL || strchr(fvalue, ';') != NULL)) 2158089Seric { 21655012Seric e->e_flags &= ~EF_OLDSTYLE; 2178089Seric } 2185937Seric 2194091Seric return (h->h_flags); 2204091Seric } 2214091Seric /* 2226980Seric ** ADDHEADER -- add a header entry to the end of the queue. 2236980Seric ** 2246980Seric ** This bypasses the special checking of chompheader. 2256980Seric ** 2266980Seric ** Parameters: 22759579Seric ** field -- the name of the header field. 22858789Seric ** value -- the value of the field. 22967546Seric ** hp -- an indirect pointer to the header structure list. 2306980Seric ** 2316980Seric ** Returns: 2326980Seric ** none. 2336980Seric ** 2346980Seric ** Side Effects: 2356980Seric ** adds the field on the list of headers for this envelope. 2366980Seric */ 2376980Seric 23867546Seric addheader(field, value, hdrlist) 2396980Seric char *field; 2406980Seric char *value; 24167546Seric HDR **hdrlist; 2426980Seric { 2436980Seric register HDR *h; 2446980Seric register struct hdrinfo *hi; 2456980Seric HDR **hp; 2466980Seric 2476980Seric /* find info struct */ 2486980Seric for (hi = HdrInfo; hi->hi_field != NULL; hi++) 2496980Seric { 25059579Seric if (strcasecmp(field, hi->hi_field) == 0) 2516980Seric break; 2526980Seric } 2536980Seric 2546980Seric /* find current place in list -- keep back pointer? */ 25567546Seric for (hp = hdrlist; (h = *hp) != NULL; hp = &h->h_link) 2566980Seric { 25759579Seric if (strcasecmp(field, h->h_field) == 0) 2586980Seric break; 2596980Seric } 2606980Seric 2616980Seric /* allocate space for new header */ 2626980Seric h = (HDR *) xalloc(sizeof *h); 2636980Seric h->h_field = field; 2646980Seric h->h_value = newstr(value); 2657368Seric h->h_link = *hp; 2666980Seric h->h_flags = hi->hi_flags | H_DEFAULT; 26710689Seric clrbitmap(h->h_mflags); 2686980Seric *hp = h; 2696980Seric } 2706980Seric /* 2714091Seric ** HVALUE -- return value of a header. 2724091Seric ** 2734091Seric ** Only "real" fields (i.e., ones that have not been supplied 2744091Seric ** as a default) are used. 2754091Seric ** 2764091Seric ** Parameters: 2774091Seric ** field -- the field name. 27867546Seric ** header -- the header list. 2794091Seric ** 2804091Seric ** Returns: 2814091Seric ** pointer to the value part. 2824091Seric ** NULL if not found. 2834091Seric ** 2844091Seric ** Side Effects: 2859382Seric ** none. 2864091Seric */ 2874091Seric 2884091Seric char * 28967546Seric hvalue(field, header) 2904091Seric char *field; 29167546Seric HDR *header; 2924091Seric { 2934091Seric register HDR *h; 2944091Seric 29567546Seric for (h = header; h != NULL; h = h->h_link) 2964091Seric { 29759579Seric if (!bitset(H_DEFAULT, h->h_flags) && 29859579Seric strcasecmp(h->h_field, field) == 0) 2994091Seric return (h->h_value); 3004091Seric } 3014091Seric return (NULL); 3024091Seric } 3034091Seric /* 3044091Seric ** ISHEADER -- predicate telling if argument is a header. 3054091Seric ** 3064319Seric ** A line is a header if it has a single word followed by 3074319Seric ** optional white space followed by a colon. 3084319Seric ** 30968717Seric ** Header fields beginning with two dashes, although technically 31068717Seric ** permitted by RFC822, are automatically rejected in order 31168717Seric ** to make MIME work out. Without this we could have a technically 31268717Seric ** legal header such as ``--"foo:bar"'' that would also be a legal 31368717Seric ** MIME separator. 31468717Seric ** 3154091Seric ** Parameters: 31668690Seric ** h -- string to check for possible headerness. 3174091Seric ** 3184091Seric ** Returns: 31968690Seric ** TRUE if h is a header. 3204091Seric ** FALSE otherwise. 3214091Seric ** 3224091Seric ** Side Effects: 3234091Seric ** none. 3244091Seric */ 3254091Seric 3264091Seric bool 32768690Seric isheader(h) 32868690Seric char *h; 3294091Seric { 33068690Seric register char *s = h; 33168690Seric 33268717Seric if (s[0] == '-' && s[1] == '-') 33368717Seric return FALSE; 33468717Seric 3359382Seric while (*s > ' ' && *s != ':' && *s != '\0') 3364091Seric s++; 3379382Seric 33868690Seric if (h == s) 33968690Seric return FALSE; 34068690Seric 3419382Seric /* following technically violates RFC822 */ 34258050Seric while (isascii(*s) && isspace(*s)) 3434091Seric s++; 3449382Seric 3454091Seric return (*s == ':'); 3464091Seric } 3475919Seric /* 3487783Seric ** EATHEADER -- run through the stored header and extract info. 3497783Seric ** 3507783Seric ** Parameters: 3519382Seric ** e -- the envelope to process. 35258929Seric ** full -- if set, do full processing (e.g., compute 35358929Seric ** message priority). 3547783Seric ** 3557783Seric ** Returns: 3567783Seric ** none. 3577783Seric ** 3587783Seric ** Side Effects: 3597783Seric ** Sets a bunch of global variables from information 3609382Seric ** in the collected header. 3619382Seric ** Aborts the message if the hop count is exceeded. 3627783Seric */ 3637783Seric 36458929Seric eatheader(e, full) 3659382Seric register ENVELOPE *e; 36658929Seric bool full; 3677783Seric { 3687783Seric register HDR *h; 3697783Seric register char *p; 3709382Seric int hopcnt = 0; 37157208Seric char *msgid; 37258688Seric char buf[MAXLINE]; 3737783Seric 37458688Seric /* 37558688Seric ** Set up macros for possible expansion in headers. 37658688Seric */ 37758688Seric 37858704Seric define('f', e->e_sender, e); 37958704Seric define('g', e->e_sender, e); 38064148Seric if (e->e_origrcpt != NULL && *e->e_origrcpt != '\0') 38164148Seric define('u', e->e_origrcpt, e); 38264148Seric else 38364148Seric define('u', NULL, e); 38458688Seric 38565052Seric /* full name of from person */ 38667546Seric p = hvalue("full-name", e->e_header); 38765052Seric if (p != NULL) 38865052Seric define('x', p, e); 38965052Seric 3909382Seric if (tTd(32, 1)) 3919382Seric printf("----- collected header -----\n"); 39257208Seric msgid = "<none>"; 3939382Seric for (h = e->e_header; h != NULL; h = h->h_link) 3947783Seric { 39564156Seric if (h->h_value == NULL) 39664156Seric { 39764156Seric if (tTd(32, 1)) 39864156Seric printf("%s: <NULL>\n", h->h_field); 39964156Seric continue; 40064156Seric } 40164156Seric 40258688Seric /* do early binding */ 40364156Seric if (bitset(H_DEFAULT, h->h_flags)) 40458688Seric { 40568529Seric expand(h->h_value, buf, sizeof buf, e); 40658688Seric if (buf[0] != '\0') 40758688Seric { 40858688Seric h->h_value = newstr(buf); 40958688Seric h->h_flags &= ~H_DEFAULT; 41058688Seric } 41158688Seric } 41258688Seric 4139382Seric if (tTd(32, 1)) 41465152Seric { 41565152Seric printf("%s: ", h->h_field); 41665152Seric xputs(h->h_value); 41765152Seric printf("\n"); 41865152Seric } 41957359Seric 42011414Seric /* count the number of times it has been processed */ 4219382Seric if (bitset(H_TRACE, h->h_flags)) 4229382Seric hopcnt++; 42311414Seric 42411414Seric /* send to this person if we so desire */ 42511414Seric if (GrabTo && bitset(H_RCPT, h->h_flags) && 42611414Seric !bitset(H_DEFAULT, h->h_flags) && 42755012Seric (!bitset(EF_RESENT, e->e_flags) || bitset(H_RESENT, h->h_flags))) 42811414Seric { 42963839Seric int saveflags = e->e_flags; 43063839Seric 43164283Seric (void) sendtolist(h->h_value, NULLADDR, 43267982Seric &e->e_sendqueue, 0, e); 43363839Seric 43463839Seric /* delete fatal errors generated by this address */ 43564148Seric if (!GrabTo && !bitset(EF_FATALERRS, saveflags)) 43663839Seric e->e_flags &= ~EF_FATALERRS; 43711414Seric } 43811414Seric 43957208Seric /* save the message-id for logging */ 44064156Seric if (full && strcasecmp(h->h_field, "message-id") == 0) 44111290Seric { 44257208Seric msgid = h->h_value; 44359859Seric while (isascii(*msgid) && isspace(*msgid)) 44459859Seric msgid++; 44511290Seric } 44657359Seric 44757359Seric /* see if this is a return-receipt header */ 44857359Seric if (bitset(H_RECEIPTTO, h->h_flags)) 44957359Seric e->e_receiptto = h->h_value; 4509382Seric } 4519382Seric if (tTd(32, 1)) 4527783Seric printf("----------------------------\n"); 4537783Seric 45458145Seric /* if we are just verifying (that is, sendmail -t -bv), drop out now */ 45558145Seric if (OpMode == MD_VERIFY) 45658145Seric return; 45758145Seric 4589382Seric /* store hop count */ 4599382Seric if (hopcnt > e->e_hopcount) 4609382Seric e->e_hopcount = hopcnt; 4619382Seric 4627783Seric /* message priority */ 46367546Seric p = hvalue("precedence", e->e_header); 4649382Seric if (p != NULL) 4659382Seric e->e_class = priencode(p); 46658929Seric if (full) 46767730Seric { 46825013Seric e->e_msgpriority = e->e_msgsize 46924981Seric - e->e_class * WkClassFact 47024981Seric + e->e_nrcpts * WkRecipFact; 47167730Seric if (e->e_class < 0) 47267730Seric e->e_timeoutclass = TOC_NONURGENT; 47367730Seric else if (e->e_class > 0) 47467730Seric e->e_timeoutclass = TOC_URGENT; 47567730Seric } 4767783Seric 47767730Seric /* message timeout priority */ 47867730Seric p = hvalue("priority", e->e_header); 47967730Seric if (full && p != NULL) 48067730Seric { 48167730Seric /* (this should be in the configuration file) */ 48267730Seric if (strcasecmp(p, "urgent")) 48367730Seric e->e_timeoutclass = TOC_URGENT; 48467730Seric else if (strcasecmp(p, "normal")) 48567730Seric e->e_timeoutclass = TOC_NORMAL; 48667730Seric else if (strcasecmp(p, "non-urgent")) 48767730Seric e->e_timeoutclass = TOC_NONURGENT; 48867730Seric } 48967730Seric 4907783Seric /* date message originated */ 49167546Seric p = hvalue("posted-date", e->e_header); 4927783Seric if (p == NULL) 49367546Seric p = hvalue("date", e->e_header); 4947783Seric if (p != NULL) 4959382Seric define('a', p, e); 49611290Seric 49711290Seric /* 49865983Seric ** From person in antiquated ARPANET mode 49965983Seric ** required by UK Grey Book e-mail gateways (sigh) 50065983Seric */ 50165983Seric 50265983Seric if (OpMode == MD_ARPAFTP) 50365983Seric { 50465983Seric register struct hdrinfo *hi; 50565983Seric 50665983Seric for (hi = HdrInfo; hi->hi_field != NULL; hi++) 50765983Seric { 50865983Seric if (bitset(H_FROM, hi->hi_flags) && 50965983Seric (!bitset(H_RESENT, hi->hi_flags) || 51065983Seric bitset(EF_RESENT, e->e_flags)) && 51167546Seric (p = hvalue(hi->hi_field, e->e_header)) != NULL) 51265983Seric break; 51365983Seric } 51465983Seric if (hi->hi_field != NULL) 51565983Seric { 51665983Seric if (tTd(32, 2)) 51765983Seric printf("eatheader: setsender(*%s == %s)\n", 51865983Seric hi->hi_field, p); 51965983Seric setsender(p, e, NULL, TRUE); 52065983Seric } 52165983Seric } 52265983Seric 52365983Seric /* 52411290Seric ** Log collection information. 52511290Seric */ 52611290Seric 52711290Seric # ifdef LOG 52868036Seric if (bitset(EF_LOGSENDER, e->e_flags) && LogLevel > 4) 52965089Seric logsender(e, msgid); 53065089Seric # endif /* LOG */ 53165089Seric e->e_flags &= ~EF_LOGSENDER; 53265089Seric } 53365089Seric /* 53465089Seric ** LOGSENDER -- log sender information 53565089Seric ** 53665089Seric ** Parameters: 53765089Seric ** e -- the envelope to log 53865089Seric ** msgid -- the message id 53965089Seric ** 54065089Seric ** Returns: 54165089Seric ** none 54265089Seric */ 54365089Seric 54465089Seric logsender(e, msgid) 54565089Seric register ENVELOPE *e; 54665089Seric char *msgid; 54765089Seric { 54866748Seric # ifdef LOG 54965089Seric char *name; 55065089Seric register char *sbp; 55165089Seric register char *p; 55267901Seric int l; 55368528Seric char hbuf[MAXNAME + 1]; 55468528Seric char sbuf[MAXLINE + 1]; 55568528Seric char mbuf[MAXNAME + 1]; 55665089Seric 55767901Seric /* don't allow newlines in the message-id */ 55867901Seric if (msgid != NULL) 55967901Seric { 56067901Seric l = strlen(msgid); 56167901Seric if (l > sizeof mbuf - 1) 56267901Seric l = sizeof mbuf - 1; 56367901Seric bcopy(msgid, mbuf, l); 56467901Seric mbuf[l] = '\0'; 56567901Seric p = mbuf; 56667901Seric while ((p = strchr(p, '\n')) != NULL) 56767901Seric *p++ = ' '; 56867901Seric } 56967901Seric 57065089Seric if (bitset(EF_RESPONSE, e->e_flags)) 57165089Seric name = "[RESPONSE]"; 57265089Seric else if ((name = macvalue('_', e)) != NULL) 57365089Seric ; 57466003Seric else if (RealHostName == NULL) 57566003Seric name = "localhost"; 57665089Seric else if (RealHostName[0] == '[') 57765089Seric name = RealHostName; 57865089Seric else 57911290Seric { 58065089Seric name = hbuf; 58165089Seric (void) sprintf(hbuf, "%.80s", RealHostName); 58265089Seric if (RealHostAddr.sa.sa_family != 0) 58357359Seric { 58465089Seric p = &hbuf[strlen(hbuf)]; 58565089Seric (void) sprintf(p, " (%s)", 58665089Seric anynet_ntoa(&RealHostAddr)); 58757359Seric } 58865089Seric } 58957359Seric 59065089Seric /* some versions of syslog only take 5 printf args */ 59165059Seric # if (SYSLOG_BUFSIZE) >= 256 59265089Seric sbp = sbuf; 59365089Seric sprintf(sbp, "from=%.200s, size=%ld, class=%d, pri=%ld, nrcpts=%d", 59467788Seric e->e_from.q_paddr == NULL ? "<NONE>" : e->e_from.q_paddr, 59567788Seric e->e_msgsize, e->e_class, e->e_msgpriority, e->e_nrcpts); 59665089Seric sbp += strlen(sbp); 59765089Seric if (msgid != NULL) 59865089Seric { 59967901Seric sprintf(sbp, ", msgid=%.100s", mbuf); 60060575Seric sbp += strlen(sbp); 60165089Seric } 60265089Seric if (e->e_bodytype != NULL) 60365089Seric { 60465089Seric (void) sprintf(sbp, ", bodytype=%.20s", e->e_bodytype); 60565089Seric sbp += strlen(sbp); 60665089Seric } 60765089Seric p = macvalue('r', e); 60865089Seric if (p != NULL) 60965089Seric (void) sprintf(sbp, ", proto=%.20s", p); 61065089Seric syslog(LOG_INFO, "%s: %s, relay=%s", 61165089Seric e->e_id, sbuf, name); 61265059Seric 61365059Seric # else /* short syslog buffer */ 61465059Seric 61565089Seric syslog(LOG_INFO, "%s: from=%s", 61667788Seric e->e_id, e->e_from.q_paddr == NULL ? "<NONE>" : 61767788Seric shortenstring(e->e_from.q_paddr, 83)); 61865089Seric syslog(LOG_INFO, "%s: size=%ld, class=%ld, pri=%ld, nrcpts=%d", 61965089Seric e->e_id, e->e_msgsize, e->e_class, 62065089Seric e->e_msgpriority, e->e_nrcpts); 62165089Seric if (msgid != NULL) 62267901Seric syslog(LOG_INFO, "%s: msgid=%s", e->e_id, mbuf); 62365650Seric sbp = sbuf; 62465650Seric sprintf(sbp, "%s:", e->e_id); 62565650Seric sbp += strlen(sbp); 62665089Seric if (e->e_bodytype != NULL) 62765650Seric { 62865650Seric sprintf(sbp, " bodytype=%s,", e->e_bodytype); 62965650Seric sbp += strlen(sbp); 63065650Seric } 63165089Seric p = macvalue('r', e); 63265089Seric if (p != NULL) 63365650Seric { 63465731Seric sprintf(sbp, " proto=%s,", p); 63565650Seric sbp += strlen(sbp); 63665650Seric } 63765650Seric syslog(LOG_INFO, "%s relay=%s", sbuf, name); 63865059Seric # endif 63966748Seric # endif 6407783Seric } 6417783Seric /* 6427783Seric ** PRIENCODE -- encode external priority names into internal values. 6437783Seric ** 6447783Seric ** Parameters: 6457783Seric ** p -- priority in ascii. 6467783Seric ** 6477783Seric ** Returns: 6487783Seric ** priority as a numeric level. 6497783Seric ** 6507783Seric ** Side Effects: 6517783Seric ** none. 6527783Seric */ 6537783Seric 6547783Seric priencode(p) 6557783Seric char *p; 6567783Seric { 6578253Seric register int i; 6587783Seric 6598253Seric for (i = 0; i < NumPriorities; i++) 6607783Seric { 66133725Sbostic if (!strcasecmp(p, Priorities[i].pri_name)) 6628253Seric return (Priorities[i].pri_val); 6637783Seric } 6648253Seric 6658253Seric /* unknown priority */ 6668253Seric return (0); 6677783Seric } 6687783Seric /* 6697890Seric ** CRACKADDR -- parse an address and turn it into a macro 6707783Seric ** 6717783Seric ** This doesn't actually parse the address -- it just extracts 6727783Seric ** it and replaces it with "$g". The parse is totally ad hoc 6737783Seric ** and isn't even guaranteed to leave something syntactically 6747783Seric ** identical to what it started with. However, it does leave 6757783Seric ** something semantically identical. 6767783Seric ** 67751379Seric ** This algorithm has been cleaned up to handle a wider range 67851379Seric ** of cases -- notably quoted and backslash escaped strings. 67951379Seric ** This modification makes it substantially better at preserving 68051379Seric ** the original syntax. 6817783Seric ** 6827783Seric ** Parameters: 6837890Seric ** addr -- the address to be cracked. 6847783Seric ** 6857783Seric ** Returns: 6867783Seric ** a pointer to the new version. 6877783Seric ** 6887783Seric ** Side Effects: 6897890Seric ** none. 6907783Seric ** 6917783Seric ** Warning: 6927783Seric ** The return value is saved in local storage and should 6937783Seric ** be copied if it is to be reused. 6947783Seric */ 6957783Seric 6967783Seric char * 6977890Seric crackaddr(addr) 6987890Seric register char *addr; 6997783Seric { 7007783Seric register char *p; 70151379Seric register char c; 70251379Seric int cmtlev; 70356764Seric int realcmtlev; 70456764Seric int anglelev, realanglelev; 70551379Seric int copylev; 70651379Seric bool qmode; 70756764Seric bool realqmode; 70856764Seric bool skipping; 70951379Seric bool putgmac = FALSE; 71056735Seric bool quoteit = FALSE; 71164148Seric bool gotangle = FALSE; 71268756Seric bool gotcolon = FALSE; 71351379Seric register char *bp; 71456764Seric char *buflim; 71568756Seric char *bufhead; 71668756Seric char *addrhead; 71768528Seric static char buf[MAXNAME + 1]; 7187783Seric 7197783Seric if (tTd(33, 1)) 7207890Seric printf("crackaddr(%s)\n", addr); 7217783Seric 7228082Seric /* strip leading spaces */ 72358050Seric while (*addr != '\0' && isascii(*addr) && isspace(*addr)) 7248082Seric addr++; 7258082Seric 7267783Seric /* 72751379Seric ** Start by assuming we have no angle brackets. This will be 72851379Seric ** adjusted later if we find them. 7297783Seric */ 7307783Seric 73168756Seric bp = bufhead = buf; 73256764Seric buflim = &buf[sizeof buf - 5]; 73368756Seric p = addrhead = addr; 73456764Seric copylev = anglelev = realanglelev = cmtlev = realcmtlev = 0; 73556764Seric qmode = realqmode = FALSE; 73651379Seric 73751379Seric while ((c = *p++) != '\0') 7387783Seric { 73956764Seric /* 74056764Seric ** If the buffer is overful, go into a special "skipping" 74156764Seric ** mode that tries to keep legal syntax but doesn't actually 74256764Seric ** output things. 74356764Seric */ 7447783Seric 74556764Seric skipping = bp >= buflim; 74656735Seric 74756764Seric if (copylev > 0 && !skipping) 74856764Seric *bp++ = c; 74956735Seric 75051379Seric /* check for backslash escapes */ 75151379Seric if (c == '\\') 7527783Seric { 75358890Seric /* arrange to quote the address */ 75458890Seric if (cmtlev <= 0 && !qmode) 75558890Seric quoteit = TRUE; 75658890Seric 75751379Seric if ((c = *p++) == '\0') 7587783Seric { 75951379Seric /* too far */ 76051379Seric p--; 76151379Seric goto putg; 7627783Seric } 76356764Seric if (copylev > 0 && !skipping) 76451379Seric *bp++ = c; 76551379Seric goto putg; 7667783Seric } 7677783Seric 76851379Seric /* check for quoted strings */ 76964967Seric if (c == '"' && cmtlev <= 0) 7707783Seric { 77151379Seric qmode = !qmode; 77256764Seric if (copylev > 0 && !skipping) 77356764Seric realqmode = !realqmode; 77451379Seric continue; 7757783Seric } 77651379Seric if (qmode) 77751379Seric goto putg; 7787783Seric 77951379Seric /* check for comments */ 78051379Seric if (c == '(') 7817783Seric { 78251379Seric cmtlev++; 78356764Seric 78456764Seric /* allow space for closing paren */ 78556764Seric if (!skipping) 78656764Seric { 78756764Seric buflim--; 78856764Seric realcmtlev++; 78956764Seric if (copylev++ <= 0) 79056764Seric { 79156764Seric *bp++ = ' '; 79256764Seric *bp++ = c; 79356764Seric } 79456764Seric } 79551379Seric } 79651379Seric if (cmtlev > 0) 79751379Seric { 79851379Seric if (c == ')') 7997783Seric { 80051379Seric cmtlev--; 80151379Seric copylev--; 80256764Seric if (!skipping) 80356764Seric { 80456764Seric realcmtlev--; 80556764Seric buflim++; 80656764Seric } 8077783Seric } 8087783Seric continue; 8097783Seric } 81056764Seric else if (c == ')') 81156764Seric { 81256764Seric /* syntax error: unmatched ) */ 81365544Seric if (copylev > 0 && !skipping) 81456764Seric bp--; 81556764Seric } 8167783Seric 81768756Seric /* check for group: list; syntax */ 818*68760Seric if (c == ':' && anglelev <= 0 && !gotcolon && !ColonOkInAddr) 81968756Seric { 82068756Seric register char *q; 82168756Seric 822*68760Seric if (*p == ':') 823*68760Seric { 824*68760Seric /* special case -- :: syntax */ 825*68760Seric if (cmtlev <= 0 && !qmode) 826*68760Seric quoteit = TRUE; 827*68760Seric if (copylev > 0 && !skipping) 828*68760Seric { 829*68760Seric *bp++ = c; 830*68760Seric *bp++ = c; 831*68760Seric } 832*68760Seric p++; 833*68760Seric goto putg; 834*68760Seric } 835*68760Seric 83668756Seric gotcolon = TRUE; 83768756Seric 838*68760Seric bp = bufhead; 839*68760Seric if (quoteit) 840*68760Seric { 841*68760Seric *bp++ = '"'; 842*68760Seric 843*68760Seric /* back up over the ':' and any spaces */ 844*68760Seric --p; 845*68760Seric while (isascii(*--p) && isspace(*p)) 846*68760Seric continue; 84768756Seric p++; 848*68760Seric } 84968756Seric for (q = addrhead; q < p; ) 85068756Seric { 85168756Seric c = *q++; 85268756Seric if (bp < buflim) 85368756Seric { 854*68760Seric if (quoteit && c == '"') 855*68760Seric *bp++ = '\\'; 85668756Seric *bp++ = c; 85768756Seric } 85868756Seric } 859*68760Seric if (quoteit) 860*68760Seric { 861*68760Seric if (bp == &bufhead[1]) 862*68760Seric bp--; 863*68760Seric else 864*68760Seric *bp++ = '"'; 865*68760Seric while ((c = *p++) != ':') 866*68760Seric { 867*68760Seric if (bp < buflim) 868*68760Seric *bp++ = c; 869*68760Seric } 870*68760Seric *bp++ = c; 871*68760Seric } 872*68760Seric 873*68760Seric /* any trailing white space is part of group: */ 874*68760Seric while (isascii(*p) && isspace(*p) && bp < buflim) 875*68760Seric *bp++ = *p++; 87668756Seric copylev = 0; 877*68760Seric putgmac = quoteit = FALSE; 87868756Seric bufhead = bp; 87968756Seric addrhead = p; 88068756Seric continue; 88168756Seric } 88268756Seric 88368756Seric if (c == ';' && copylev <= 0 && !ColonOkInAddr) 88468756Seric { 88568756Seric register char *q = p; 88668756Seric 88768756Seric if (bp < buflim) 88868756Seric *bp++ = c; 88968756Seric } 89068756Seric 89156764Seric /* check for characters that may have to be quoted */ 89264148Seric if (strchr(".'@,;:\\()[]", c) != NULL) 89356764Seric { 89456764Seric /* 89556764Seric ** If these occur as the phrase part of a <> 89656764Seric ** construct, but are not inside of () or already 89756764Seric ** quoted, they will have to be quoted. Note that 89856764Seric ** now (but don't actually do the quoting). 89956764Seric */ 90056764Seric 90156764Seric if (cmtlev <= 0 && !qmode) 90256764Seric quoteit = TRUE; 90356764Seric } 90456764Seric 90551379Seric /* check for angle brackets */ 90651379Seric if (c == '<') 90751379Seric { 90856735Seric register char *q; 90956735Seric 91064148Seric /* assume first of two angles is bogus */ 91164148Seric if (gotangle) 91264148Seric quoteit = TRUE; 91364148Seric gotangle = TRUE; 91464148Seric 91551379Seric /* oops -- have to change our mind */ 91664752Seric anglelev = 1; 91756764Seric if (!skipping) 91864752Seric realanglelev = 1; 91956764Seric 92068756Seric bp = bufhead; 92156735Seric if (quoteit) 92256735Seric { 92356735Seric *bp++ = '"'; 92456735Seric 92556735Seric /* back up over the '<' and any spaces */ 92656735Seric --p; 92758050Seric while (isascii(*--p) && isspace(*p)) 92856735Seric continue; 92956735Seric p++; 93056735Seric } 93168756Seric for (q = addrhead; q < p; ) 93256735Seric { 93356735Seric c = *q++; 93456764Seric if (bp < buflim) 93556764Seric { 93656764Seric if (quoteit && c == '"') 93756764Seric *bp++ = '\\'; 93856764Seric *bp++ = c; 93956764Seric } 94056735Seric } 94156735Seric if (quoteit) 94256735Seric { 94364148Seric if (bp == &buf[1]) 94464148Seric bp--; 94564148Seric else 94664148Seric *bp++ = '"'; 94756764Seric while ((c = *p++) != '<') 94856764Seric { 94956764Seric if (bp < buflim) 95056764Seric *bp++ = c; 95156764Seric } 95256764Seric *bp++ = c; 95356735Seric } 95451379Seric copylev = 0; 95556735Seric putgmac = quoteit = FALSE; 95651379Seric continue; 95751379Seric } 9587783Seric 95951379Seric if (c == '>') 9607783Seric { 96156764Seric if (anglelev > 0) 96256764Seric { 96356764Seric anglelev--; 96456764Seric if (!skipping) 96556764Seric { 96656764Seric realanglelev--; 96756764Seric buflim++; 96856764Seric } 96956764Seric } 97056764Seric else if (!skipping) 97156764Seric { 97256764Seric /* syntax error: unmatched > */ 97356764Seric if (copylev > 0) 97456764Seric bp--; 97564752Seric quoteit = TRUE; 97656764Seric continue; 97756764Seric } 97851379Seric if (copylev++ <= 0) 97951379Seric *bp++ = c; 98051379Seric continue; 9817783Seric } 98251379Seric 98351379Seric /* must be a real address character */ 98451379Seric putg: 98551379Seric if (copylev <= 0 && !putgmac) 98651379Seric { 98758050Seric *bp++ = MACROEXPAND; 98851379Seric *bp++ = 'g'; 98951379Seric putgmac = TRUE; 99051379Seric } 9917783Seric } 9927783Seric 99356764Seric /* repair any syntactic damage */ 99456764Seric if (realqmode) 99556764Seric *bp++ = '"'; 99656764Seric while (realcmtlev-- > 0) 99756764Seric *bp++ = ')'; 99856764Seric while (realanglelev-- > 0) 99956764Seric *bp++ = '>'; 100051379Seric *bp++ = '\0'; 10017783Seric 10027783Seric if (tTd(33, 1)) 10037944Seric printf("crackaddr=>`%s'\n", buf); 10047783Seric 10057783Seric return (buf); 10067783Seric } 10079382Seric /* 10089382Seric ** PUTHEADER -- put the header part of a message from the in-core copy 10099382Seric ** 10109382Seric ** Parameters: 101165870Seric ** mci -- the connection information. 101267546Seric ** h -- the header to put. 10139382Seric ** e -- envelope to use. 10149382Seric ** 10159382Seric ** Returns: 10169382Seric ** none. 10179382Seric ** 10189382Seric ** Side Effects: 10199382Seric ** none. 10209382Seric */ 10219382Seric 102257589Seric /* 102357589Seric * Macro for fast max (not available in e.g. DG/UX, 386/ix). 102457589Seric */ 102557589Seric #ifndef MAX 102657589Seric # define MAX(a,b) (((a)>(b))?(a):(b)) 102757589Seric #endif 102857589Seric 102968228Seric putheader(mci, h, e) 103065870Seric register MCI *mci; 103167546Seric register HDR *h; 10329382Seric register ENVELOPE *e; 10339382Seric { 103457135Seric char buf[MAX(MAXLINE,BUFSIZ)]; 103557135Seric char obuf[MAXLINE]; 10369382Seric 103759882Seric if (tTd(34, 1)) 103865870Seric printf("--- putheader, mailer = %s ---\n", 103965870Seric mci->mci_mailer->m_name); 104059882Seric 104167546Seric mci->mci_flags |= MCIF_INHEADER; 104267546Seric for (; h != NULL; h = h->h_link) 10439382Seric { 10449382Seric register char *p; 104510689Seric extern bool bitintersect(); 10469382Seric 104759882Seric if (tTd(34, 11)) 104859882Seric { 104959882Seric printf(" %s: ", h->h_field); 105059882Seric xputs(h->h_value); 105159882Seric } 105259882Seric 10539382Seric if (bitset(H_CHECK|H_ACHECK, h->h_flags) && 105465870Seric !bitintersect(h->h_mflags, mci->mci_mailer->m_flags)) 105559882Seric { 105659882Seric if (tTd(34, 11)) 105759882Seric printf(" (skipped)\n"); 10589382Seric continue; 105959882Seric } 10609382Seric 106111414Seric /* handle Resent-... headers specially */ 106211414Seric if (bitset(H_RESENT, h->h_flags) && !bitset(EF_RESENT, e->e_flags)) 106359882Seric { 106459882Seric if (tTd(34, 11)) 106559882Seric printf(" (skipped (resent))\n"); 106611414Seric continue; 106759882Seric } 106811414Seric 106966784Seric /* suppress return receipts if requested */ 107066784Seric if (bitset(H_RECEIPTTO, h->h_flags) && 107166784Seric bitset(EF_NORECEIPT, e->e_flags)) 107266784Seric { 107366784Seric if (tTd(34, 11)) 107466784Seric printf(" (skipped (receipt))\n"); 107566784Seric continue; 107666784Seric } 107766784Seric 107867694Seric /* suppress Content-Transfer-Encoding: if we are MIMEing */ 107967694Seric if (bitset(H_CTE, h->h_flags) && 108068228Seric bitset(MCIF_CVT8TO7, mci->mci_flags)) 108167694Seric { 108267694Seric if (tTd(34, 11)) 108367694Seric printf(" (skipped (content-transfer-encoding))\n"); 108467694Seric continue; 108567694Seric } 108667694Seric 108765152Seric /* macro expand value if generated internally */ 10889382Seric p = h->h_value; 10899382Seric if (bitset(H_DEFAULT, h->h_flags)) 10909382Seric { 109168529Seric expand(p, buf, sizeof buf, e); 10929382Seric p = buf; 10939382Seric if (p == NULL || *p == '\0') 109465152Seric { 109565152Seric if (tTd(34, 11)) 109665152Seric printf(" (skipped -- null value)\n"); 10979382Seric continue; 109865152Seric } 10999382Seric } 11009382Seric 110165152Seric if (tTd(34, 11)) 110265152Seric printf("\n"); 110365152Seric 110468449Seric if (bitset(H_STRIPVAL, h->h_flags)) 11059382Seric { 110668449Seric /* empty field */ 110768449Seric (void) sprintf(obuf, "%s:", h->h_field); 110868449Seric putline(obuf, mci); 110968449Seric } 111068449Seric else if (bitset(H_FROM|H_RCPT, h->h_flags)) 111168449Seric { 11129382Seric /* address field */ 11139382Seric bool oldstyle = bitset(EF_OLDSTYLE, e->e_flags); 11149382Seric 11159382Seric if (bitset(H_FROM, h->h_flags)) 11169382Seric oldstyle = FALSE; 111765870Seric commaize(h, p, oldstyle, mci, e); 11189382Seric } 11199382Seric else 11209382Seric { 11219382Seric /* vanilla header line */ 112212159Seric register char *nlp; 112312159Seric 112459579Seric (void) sprintf(obuf, "%s: ", h->h_field); 112556795Seric while ((nlp = strchr(p, '\n')) != NULL) 112612159Seric { 112712159Seric *nlp = '\0'; 112812159Seric (void) strcat(obuf, p); 112912159Seric *nlp = '\n'; 113065870Seric putline(obuf, mci); 113112159Seric p = ++nlp; 113212161Seric obuf[0] = '\0'; 113312159Seric } 113412159Seric (void) strcat(obuf, p); 113565870Seric putline(obuf, mci); 11369382Seric } 11379382Seric } 113867887Seric 113967887Seric /* 114067887Seric ** If we are converting this to a MIME message, add the 114167889Seric ** MIME headers. 114267887Seric */ 114367887Seric 114467887Seric if (bitset(MM_MIME8BIT, MimeMode) && 114567887Seric bitset(EF_HAS8BIT, e->e_flags) && 114667887Seric !bitnset(M_8BITS, mci->mci_mailer->m_flags) && 114767889Seric !bitset(MCIF_CVT8TO7, mci->mci_flags)) 114867887Seric { 114967889Seric if (hvalue("MIME-Version", e->e_header) == NULL) 115067889Seric putline("MIME-Version: 1.0", mci); 115167889Seric if (hvalue("Content-Type", e->e_header) == NULL) 115267889Seric { 115367889Seric sprintf(obuf, "Content-Type: text/plain; charset=%s", 115467896Seric defcharset(e)); 115567889Seric putline(obuf, mci); 115667889Seric } 115767889Seric if (hvalue("Content-Transfer-Encoding", e->e_header) == NULL) 115867889Seric putline("Content-Transfer-Encoding: 8bit", mci); 115967887Seric } 11609382Seric } 11619382Seric /* 11629382Seric ** COMMAIZE -- output a header field, making a comma-translated list. 11639382Seric ** 11649382Seric ** Parameters: 11659382Seric ** h -- the header field to output. 11669382Seric ** p -- the value to put in it. 11679382Seric ** oldstyle -- TRUE if this is an old style header. 116865870Seric ** mci -- the connection information. 116955012Seric ** e -- the envelope containing the message. 11709382Seric ** 11719382Seric ** Returns: 11729382Seric ** none. 11739382Seric ** 11749382Seric ** Side Effects: 11759382Seric ** outputs "p" to file "fp". 11769382Seric */ 11779382Seric 117865870Seric void 117965870Seric commaize(h, p, oldstyle, mci, e) 11809382Seric register HDR *h; 11819382Seric register char *p; 11829382Seric bool oldstyle; 118365870Seric register MCI *mci; 118455012Seric register ENVELOPE *e; 11859382Seric { 11869382Seric register char *obp; 11879382Seric int opos; 118866004Seric int omax; 11899382Seric bool firstone = TRUE; 119011157Seric char obuf[MAXLINE + 3]; 11919382Seric 11929382Seric /* 11939382Seric ** Output the address list translated by the 11949382Seric ** mailer and with commas. 11959382Seric */ 11969382Seric 11979382Seric if (tTd(14, 2)) 11989382Seric printf("commaize(%s: %s)\n", h->h_field, p); 11999382Seric 12009382Seric obp = obuf; 120159579Seric (void) sprintf(obp, "%s: ", h->h_field); 12029382Seric opos = strlen(h->h_field) + 2; 12039382Seric obp += opos; 120466254Seric omax = mci->mci_mailer->m_linelimit - 2; 120566254Seric if (omax < 0 || omax > 78) 120666254Seric omax = 78; 12079382Seric 12089382Seric /* 12099382Seric ** Run through the list of values. 12109382Seric */ 12119382Seric 12129382Seric while (*p != '\0') 12139382Seric { 12149382Seric register char *name; 121554983Seric register int c; 12169382Seric char savechar; 121759163Seric int flags; 121859163Seric auto int stat; 12199382Seric 12209382Seric /* 12219382Seric ** Find the end of the name. New style names 12229382Seric ** end with a comma, old style names end with 12239382Seric ** a space character. However, spaces do not 12249382Seric ** necessarily delimit an old-style name -- at 12259382Seric ** signs mean keep going. 12269382Seric */ 12279382Seric 12289382Seric /* find end of name */ 122958050Seric while ((isascii(*p) && isspace(*p)) || *p == ',') 12309382Seric p++; 12319382Seric name = p; 12329382Seric for (;;) 12339382Seric { 123458333Seric auto char *oldp; 123516909Seric char pvpbuf[PSBUFSIZE]; 12369382Seric 123765066Seric (void) prescan(p, oldstyle ? ' ' : ',', pvpbuf, 123868711Seric sizeof pvpbuf, &oldp, NULL); 123958333Seric p = oldp; 12409382Seric 12419382Seric /* look to see if we have an at sign */ 124258050Seric while (*p != '\0' && isascii(*p) && isspace(*p)) 12439382Seric p++; 12449382Seric 124558170Seric if (*p != '@') 12469382Seric { 12479382Seric p = oldp; 12489382Seric break; 12499382Seric } 12509382Seric p += *p == '@' ? 1 : 2; 125158050Seric while (*p != '\0' && isascii(*p) && isspace(*p)) 12529382Seric p++; 12539382Seric } 12549382Seric /* at the end of one complete name */ 12559382Seric 12569382Seric /* strip off trailing white space */ 125758050Seric while (p >= name && 125858050Seric ((isascii(*p) && isspace(*p)) || *p == ',' || *p == '\0')) 12599382Seric p--; 12609382Seric if (++p == name) 12619382Seric continue; 12629382Seric savechar = *p; 12639382Seric *p = '\0'; 12649382Seric 12659382Seric /* translate the name to be relative */ 126659163Seric flags = RF_HEADERADDR|RF_ADDDOMAIN; 126759163Seric if (bitset(H_FROM, h->h_flags)) 126859163Seric flags |= RF_SENDERADDR; 126968522Seric #ifdef USERDB 127068522Seric else if (e->e_from.q_mailer != NULL && 127168522Seric bitnset(M_UDBRECIPIENT, e->e_from.q_mailer->m_flags)) 127268522Seric { 127368522Seric extern char *udbsender(); 127468522Seric 127568522Seric name = udbsender(name); 127668522Seric } 127768522Seric #endif 127859163Seric stat = EX_OK; 127965870Seric name = remotename(name, mci->mci_mailer, flags, &stat, e); 12809382Seric if (*name == '\0') 12819382Seric { 12829382Seric *p = savechar; 12839382Seric continue; 12849382Seric } 12859382Seric 12869382Seric /* output the name with nice formatting */ 128754983Seric opos += strlen(name); 12889382Seric if (!firstone) 12899382Seric opos += 2; 129066004Seric if (opos > omax && !firstone) 12919382Seric { 129210178Seric (void) strcpy(obp, ",\n"); 129365870Seric putline(obuf, mci); 12949382Seric obp = obuf; 129566255Seric (void) strcpy(obp, " "); 129610161Seric opos = strlen(obp); 129710161Seric obp += opos; 129854983Seric opos += strlen(name); 12999382Seric } 13009382Seric else if (!firstone) 13019382Seric { 130266255Seric (void) strcpy(obp, ", "); 13039382Seric obp += 2; 13049382Seric } 13059382Seric 130654983Seric while ((c = *name++) != '\0' && obp < &obuf[MAXLINE]) 130754983Seric *obp++ = c; 13089382Seric firstone = FALSE; 13099382Seric *p = savechar; 13109382Seric } 13119382Seric (void) strcpy(obp, "\n"); 131265870Seric putline(obuf, mci); 13139382Seric } 13149382Seric /* 131558170Seric ** COPYHEADER -- copy header list 13169382Seric ** 131758170Seric ** This routine is the equivalent of newstr for header lists 131858170Seric ** 13199382Seric ** Parameters: 132058170Seric ** header -- list of header structures to copy. 13219382Seric ** 13229382Seric ** Returns: 132358170Seric ** a copy of 'header'. 13249382Seric ** 13259382Seric ** Side Effects: 13269382Seric ** none. 13279382Seric */ 13289382Seric 132958170Seric HDR * 133058170Seric copyheader(header) 133158170Seric register HDR *header; 13329382Seric { 133358170Seric register HDR *newhdr; 133458170Seric HDR *ret; 133558170Seric register HDR **tail = &ret; 13369382Seric 133758170Seric while (header != NULL) 133858170Seric { 133958170Seric newhdr = (HDR *) xalloc(sizeof(HDR)); 134058170Seric STRUCTCOPY(*header, *newhdr); 134158170Seric *tail = newhdr; 134258170Seric tail = &newhdr->h_link; 134358170Seric header = header->h_link; 134458170Seric } 134558170Seric *tail = NULL; 134658170Seric 134758170Seric return ret; 13489382Seric } 1349