122976Smiriam /* 234921Sbostic * Copyright (c) 1983 Eric P. Allman 333730Sbostic * Copyright (c) 1988 Regents of the University of California. 433730Sbostic * All rights reserved. 533730Sbostic * 642828Sbostic * %sccs.include.redist.c% 733730Sbostic */ 822976Smiriam 922976Smiriam #ifndef lint 10*56678Seric static char sccsid[] = "@(#)parseaddr.c 5.22 (Berkeley) 11/04/92"; 1133730Sbostic #endif /* not lint */ 1222976Smiriam 13*56678Seric # include "sendmail.h" 14297Seric 15297Seric /* 169888Seric ** PARSEADDR -- Parse an address 17297Seric ** 18297Seric ** Parses an address and breaks it up into three parts: a 19297Seric ** net to transmit the message on, the host to transmit it 20297Seric ** to, and a user on that host. These are loaded into an 212973Seric ** ADDRESS header with the values squirreled away if necessary. 22297Seric ** The "user" part may not be a real user; the process may 23297Seric ** just reoccur on that machine. For example, on a machine 24297Seric ** with an arpanet connection, the address 25297Seric ** csvax.bill@berkeley 26297Seric ** will break up to a "user" of 'csvax.bill' and a host 27297Seric ** of 'berkeley' -- to be transmitted over the arpanet. 28297Seric ** 29297Seric ** Parameters: 30297Seric ** addr -- the address to parse. 31297Seric ** a -- a pointer to the address descriptor buffer. 32297Seric ** If NULL, a header will be created. 33297Seric ** copyf -- determines what shall be copied: 34297Seric ** -1 -- don't copy anything. The printname 35297Seric ** (q_paddr) is just addr, and the 36297Seric ** user & host are allocated internally 37297Seric ** to parse. 38297Seric ** 0 -- copy out the parsed user & host, but 39297Seric ** don't copy the printname. 40297Seric ** +1 -- copy everything. 4111445Seric ** delim -- the character to terminate the address, passed 4211445Seric ** to prescan. 43*56678Seric ** e -- the envelope that will contain this address. 44297Seric ** 45297Seric ** Returns: 46297Seric ** A pointer to the address descriptor header (`a' if 47297Seric ** `a' is non-NULL). 48297Seric ** NULL on error. 49297Seric ** 50297Seric ** Side Effects: 51297Seric ** none 52297Seric */ 53297Seric 549374Seric /* following delimiters are inherent to the internal algorithms */ 5516155Seric # define DELIMCHARS "\001()<>,;\\\"\r\n" /* word delimiters */ 562091Seric 572973Seric ADDRESS * 58*56678Seric parseaddr(addr, a, copyf, delim, e) 59297Seric char *addr; 602973Seric register ADDRESS *a; 61297Seric int copyf; 6211445Seric char delim; 63*56678Seric register ENVELOPE *e; 64297Seric { 653149Seric register char **pvp; 6616914Seric char pvpbuf[PSBUFSIZE]; 67*56678Seric extern char **prescan(); 68*56678Seric extern ADDRESS *buildaddr(); 69297Seric 70297Seric /* 71297Seric ** Initialize and prescan address. 72297Seric */ 73297Seric 74*56678Seric e->e_to = addr; 757675Seric if (tTd(20, 1)) 769888Seric printf("\n--parseaddr(%s)\n", addr); 773188Seric 7816914Seric pvp = prescan(addr, delim, pvpbuf); 793149Seric if (pvp == NULL) 80297Seric return (NULL); 81297Seric 82297Seric /* 833149Seric ** Apply rewriting rules. 847889Seric ** Ruleset 0 does basic parsing. It must resolve. 85297Seric */ 86297Seric 878181Seric rewrite(pvp, 3); 884070Seric rewrite(pvp, 0); 89297Seric 903149Seric /* 913149Seric ** See if we resolved to a real mailer. 923149Seric */ 93297Seric 943149Seric if (pvp[0][0] != CANONNET) 953149Seric { 963149Seric setstat(EX_USAGE); 973149Seric usrerr("cannot resolve name"); 983149Seric return (NULL); 99297Seric } 100297Seric 101297Seric /* 1023149Seric ** Build canonical address from pvp. 103297Seric */ 104297Seric 1053149Seric a = buildaddr(pvp, a); 1064279Seric if (a == NULL) 1074279Seric return (NULL); 108297Seric 109297Seric /* 1103149Seric ** Make local copies of the host & user and then 1113149Seric ** transport them out. 112297Seric */ 113297Seric 114*56678Seric allocaddr(a, copyf, addr); 115*56678Seric 116*56678Seric /* 117*56678Seric ** Compute return value. 118*56678Seric */ 119*56678Seric 120*56678Seric if (tTd(20, 1)) 1218078Seric { 122*56678Seric printf("parseaddr-->"); 123*56678Seric printaddr(a, FALSE); 124*56678Seric } 125*56678Seric 126*56678Seric return (a); 127*56678Seric } 128*56678Seric /* 129*56678Seric ** ALLOCADDR -- do local allocations of address on demand. 130*56678Seric ** 131*56678Seric ** Also lowercases the host name if requested. 132*56678Seric ** 133*56678Seric ** Parameters: 134*56678Seric ** a -- the address to reallocate. 135*56678Seric ** copyf -- the copy flag (see parseaddr for description). 136*56678Seric ** paddr -- the printname of the address. 137*56678Seric ** 138*56678Seric ** Returns: 139*56678Seric ** none. 140*56678Seric ** 141*56678Seric ** Side Effects: 142*56678Seric ** Copies portions of a into local buffers as requested. 143*56678Seric */ 144*56678Seric 145*56678Seric allocaddr(a, copyf, paddr) 146*56678Seric register ADDRESS *a; 147*56678Seric int copyf; 148*56678Seric char *paddr; 149*56678Seric { 150*56678Seric register MAILER *m = a->q_mailer; 151*56678Seric 152*56678Seric if (copyf > 0 && paddr != NULL) 153*56678Seric { 154*56678Seric extern char *DelimChar; 1558078Seric char savec = *DelimChar; 1568078Seric 1578078Seric *DelimChar = '\0'; 158*56678Seric a->q_paddr = newstr(paddr); 1598078Seric *DelimChar = savec; 1608078Seric } 161297Seric else 162*56678Seric a->q_paddr = paddr; 16324944Seric 16424944Seric if (a->q_user == NULL) 16524944Seric a->q_user = ""; 16624944Seric if (a->q_host == NULL) 16724944Seric a->q_host = ""; 16824944Seric 1693149Seric if (copyf >= 0) 170297Seric { 17124944Seric a->q_host = newstr(a->q_host); 1723149Seric if (a->q_user != a->q_paddr) 1733149Seric a->q_user = newstr(a->q_user); 174297Seric } 175297Seric 176*56678Seric if (a->q_paddr == NULL) 177*56678Seric a->q_paddr = a->q_user; 178*56678Seric 179297Seric /* 18016202Seric ** Convert host name to lower case if requested. 18116202Seric ** User name will be done later. 18216202Seric */ 18316202Seric 18416202Seric if (!bitnset(M_HST_UPPER, m->m_flags)) 18516202Seric makelower(a->q_host); 186297Seric } 187297Seric /* 18816162Seric ** LOWERADDR -- map UPPER->lower case on addresses as requested. 18916162Seric ** 19016162Seric ** Parameters: 19116162Seric ** a -- address to be mapped. 19216162Seric ** 19316162Seric ** Returns: 19416162Seric ** none. 19516162Seric ** 19616162Seric ** Side Effects: 19716162Seric ** none. 19816162Seric */ 19916162Seric 20016162Seric loweraddr(a) 20116162Seric register ADDRESS *a; 20216162Seric { 20316162Seric register MAILER *m = a->q_mailer; 20416162Seric 20516162Seric if (!bitnset(M_USR_UPPER, m->m_flags)) 20616162Seric makelower(a->q_user); 20716162Seric } 20816162Seric /* 209297Seric ** PRESCAN -- Prescan name and make it canonical 210297Seric ** 2119374Seric ** Scans a name and turns it into a set of tokens. This process 2129374Seric ** deletes blanks and comments (in parentheses). 213297Seric ** 214297Seric ** This routine knows about quoted strings and angle brackets. 215297Seric ** 216297Seric ** There are certain subtleties to this routine. The one that 217297Seric ** comes to mind now is that backslashes on the ends of names 218297Seric ** are silently stripped off; this is intentional. The problem 219297Seric ** is that some versions of sndmsg (like at LBL) set the kill 220297Seric ** character to something other than @ when reading addresses; 221297Seric ** so people type "csvax.eric\@berkeley" -- which screws up the 222297Seric ** berknet mailer. 223297Seric ** 224297Seric ** Parameters: 225297Seric ** addr -- the name to chomp. 226297Seric ** delim -- the delimiter for the address, normally 227297Seric ** '\0' or ','; \0 is accepted in any case. 22815284Seric ** If '\t' then we are reading the .cf file. 22916914Seric ** pvpbuf -- place to put the saved text -- note that 23016914Seric ** the pointers are static. 231297Seric ** 232297Seric ** Returns: 2333149Seric ** A pointer to a vector of tokens. 234297Seric ** NULL on error. 235297Seric ** 236297Seric ** Side Effects: 23725279Seric ** sets DelimChar to point to the character matching 'delim'. 238297Seric */ 239297Seric 2408078Seric /* states and character types */ 2418078Seric # define OPR 0 /* operator */ 2428078Seric # define ATM 1 /* atom */ 2438078Seric # define QST 2 /* in quoted string */ 2448078Seric # define SPC 3 /* chewing up spaces */ 2458078Seric # define ONE 4 /* pick up one character */ 2463149Seric 2478078Seric # define NSTATES 5 /* number of states */ 2488078Seric # define TYPE 017 /* mask to select state type */ 2498078Seric 2508078Seric /* meta bits for table */ 2518078Seric # define M 020 /* meta character; don't pass through */ 2528078Seric # define B 040 /* cause a break */ 2538078Seric # define MB M|B /* meta-break */ 2548078Seric 2558078Seric static short StateTab[NSTATES][NSTATES] = 2568078Seric { 2578087Seric /* oldst chtype> OPR ATM QST SPC ONE */ 2589051Seric /*OPR*/ OPR|B, ATM|B, QST|B, SPC|MB, ONE|B, 2599051Seric /*ATM*/ OPR|B, ATM, QST|B, SPC|MB, ONE|B, 2609051Seric /*QST*/ QST, QST, OPR, QST, QST, 2618078Seric /*SPC*/ OPR, ATM, QST, SPC|M, ONE, 2628078Seric /*ONE*/ OPR, OPR, OPR, OPR, OPR, 2638078Seric }; 2648078Seric 2658078Seric # define NOCHAR -1 /* signal nothing in lookahead token */ 2668078Seric 267*56678Seric char *DelimChar; /* set to point to the delimiter */ 268*56678Seric 2693149Seric char ** 27016914Seric prescan(addr, delim, pvpbuf) 271297Seric char *addr; 272297Seric char delim; 27316914Seric char pvpbuf[]; 274297Seric { 275297Seric register char *p; 2768078Seric register char *q; 2779346Seric register int c; 2783149Seric char **avp; 279297Seric bool bslashmode; 280297Seric int cmntcnt; 2818423Seric int anglecnt; 2823149Seric char *tok; 2838078Seric int state; 2848078Seric int newstate; 2858078Seric static char *av[MAXATOM+1]; 286*56678Seric extern int errno; 287297Seric 28815253Seric /* make sure error messages don't have garbage on them */ 28915253Seric errno = 0; 29015253Seric 29116914Seric q = pvpbuf; 2923149Seric bslashmode = FALSE; 2937800Seric cmntcnt = 0; 2948423Seric anglecnt = 0; 2953149Seric avp = av; 296*56678Seric state = ATM; 2978078Seric c = NOCHAR; 2988078Seric p = addr; 2998078Seric if (tTd(22, 45)) 300297Seric { 3018078Seric printf("prescan: "); 3028078Seric xputs(p); 30323109Seric (void) putchar('\n'); 3048078Seric } 3058078Seric 3068078Seric do 3078078Seric { 3083149Seric /* read a token */ 3093149Seric tok = q; 3108078Seric for (;;) 311297Seric { 3128078Seric /* store away any old lookahead character */ 3138078Seric if (c != NOCHAR) 3148078Seric { 31515284Seric /* see if there is room */ 31616914Seric if (q >= &pvpbuf[PSBUFSIZE - 5]) 3178078Seric { 3188078Seric usrerr("Address too long"); 3198078Seric DelimChar = p; 3208078Seric return (NULL); 3218078Seric } 32215284Seric 32315284Seric /* squirrel it away */ 3248078Seric *q++ = c; 3258078Seric } 3268078Seric 3278078Seric /* read a new input character */ 3288078Seric c = *p++; 3298078Seric if (c == '\0') 3308078Seric break; 33115284Seric 3328078Seric if (tTd(22, 101)) 3338078Seric printf("c=%c, s=%d; ", c, state); 3348078Seric 3353149Seric /* chew up special characters */ 3363149Seric *q = '\0'; 3373149Seric if (bslashmode) 3383149Seric { 33924944Seric /* kludge \! for naive users */ 34024944Seric if (c != '!') 341*56678Seric *q++ = '\\'; 3423149Seric bslashmode = FALSE; 343*56678Seric continue; 3443149Seric } 345*56678Seric 346*56678Seric if (c == '\\') 3473149Seric { 3483149Seric bslashmode = TRUE; 3498078Seric c = NOCHAR; 350*56678Seric continue; 3513149Seric } 352*56678Seric else if (state == QST) 3538514Seric { 3548514Seric /* do nothing, just avoid next clauses */ 3558514Seric } 3568078Seric else if (c == '(') 3574100Seric { 3588078Seric cmntcnt++; 3598078Seric c = NOCHAR; 3604100Seric } 3618078Seric else if (c == ')') 3623149Seric { 3638078Seric if (cmntcnt <= 0) 3643149Seric { 3658078Seric usrerr("Unbalanced ')'"); 3668078Seric DelimChar = p; 3678078Seric return (NULL); 3683149Seric } 3698078Seric else 3708078Seric cmntcnt--; 3718078Seric } 3728078Seric else if (cmntcnt > 0) 3738078Seric c = NOCHAR; 3748423Seric else if (c == '<') 3758423Seric anglecnt++; 3768423Seric else if (c == '>') 3778423Seric { 3788423Seric if (anglecnt <= 0) 3798423Seric { 3808423Seric usrerr("Unbalanced '>'"); 3818423Seric DelimChar = p; 3828423Seric return (NULL); 3838423Seric } 3848423Seric anglecnt--; 3858423Seric } 38611423Seric else if (delim == ' ' && isspace(c)) 38711423Seric c = ' '; 3883149Seric 3898078Seric if (c == NOCHAR) 3908078Seric continue; 3913149Seric 3928078Seric /* see if this is end of input */ 39311405Seric if (c == delim && anglecnt <= 0 && state != QST) 3943149Seric break; 3953149Seric 3968078Seric newstate = StateTab[state][toktype(c)]; 3978078Seric if (tTd(22, 101)) 3988078Seric printf("ns=%02o\n", newstate); 3998078Seric state = newstate & TYPE; 4008078Seric if (bitset(M, newstate)) 4018078Seric c = NOCHAR; 4028078Seric if (bitset(B, newstate)) 4034228Seric break; 404297Seric } 4053149Seric 4063149Seric /* new token */ 4078078Seric if (tok != q) 4081378Seric { 4098078Seric *q++ = '\0'; 4108078Seric if (tTd(22, 36)) 411297Seric { 4128078Seric printf("tok="); 4138078Seric xputs(tok); 41423109Seric (void) putchar('\n'); 415297Seric } 4168078Seric if (avp >= &av[MAXATOM]) 417297Seric { 4188078Seric syserr("prescan: too many tokens"); 4198078Seric DelimChar = p; 4208078Seric return (NULL); 421297Seric } 4228078Seric *avp++ = tok; 423297Seric } 4248423Seric } while (c != '\0' && (c != delim || anglecnt > 0)); 4253149Seric *avp = NULL; 4268078Seric DelimChar = --p; 4273149Seric if (cmntcnt > 0) 4283149Seric usrerr("Unbalanced '('"); 4298423Seric else if (anglecnt > 0) 4308423Seric usrerr("Unbalanced '<'"); 4318078Seric else if (state == QST) 4323149Seric usrerr("Unbalanced '\"'"); 4333149Seric else if (av[0] != NULL) 4343149Seric return (av); 4353149Seric return (NULL); 4363149Seric } 4373149Seric /* 4383149Seric ** TOKTYPE -- return token type 4393149Seric ** 4403149Seric ** Parameters: 4413149Seric ** c -- the character in question. 4423149Seric ** 4433149Seric ** Returns: 4443149Seric ** Its type. 4453149Seric ** 4463149Seric ** Side Effects: 4473149Seric ** none. 4483149Seric */ 449297Seric 4503149Seric toktype(c) 4513149Seric register char c; 4523149Seric { 4533380Seric static char buf[50]; 4543382Seric static bool firstime = TRUE; 4553380Seric 4563382Seric if (firstime) 4573380Seric { 4583382Seric firstime = FALSE; 45916155Seric expand("\001o", buf, &buf[sizeof buf - 1], CurEnv); 4607005Seric (void) strcat(buf, DELIMCHARS); 4613380Seric } 46256327Seric if (c == MATCHCLASS || c == MATCHREPL || c == MATCHNCLASS) 4638078Seric return (ONE); 4648078Seric if (c == '"') 4658078Seric return (QST); 4664100Seric if (!isascii(c)) 4678078Seric return (ATM); 4688078Seric if (isspace(c) || c == ')') 4698078Seric return (SPC); 4703380Seric if (iscntrl(c) || index(buf, c) != NULL) 4718078Seric return (OPR); 4728078Seric return (ATM); 4733149Seric } 4743149Seric /* 4753149Seric ** REWRITE -- apply rewrite rules to token vector. 4763149Seric ** 4774476Seric ** This routine is an ordered production system. Each rewrite 4784476Seric ** rule has a LHS (called the pattern) and a RHS (called the 4794476Seric ** rewrite); 'rwr' points the the current rewrite rule. 4804476Seric ** 4814476Seric ** For each rewrite rule, 'avp' points the address vector we 4824476Seric ** are trying to match against, and 'pvp' points to the pattern. 4838058Seric ** If pvp points to a special match value (MATCHZANY, MATCHANY, 4849585Seric ** MATCHONE, MATCHCLASS, MATCHNCLASS) then the address in avp 4859585Seric ** matched is saved away in the match vector (pointed to by 'mvp'). 4864476Seric ** 4874476Seric ** When a match between avp & pvp does not match, we try to 4889585Seric ** back out. If we back up over MATCHONE, MATCHCLASS, or MATCHNCLASS 4894476Seric ** we must also back out the match in mvp. If we reach a 4908058Seric ** MATCHANY or MATCHZANY we just extend the match and start 4918058Seric ** over again. 4924476Seric ** 4934476Seric ** When we finally match, we rewrite the address vector 4944476Seric ** and try over again. 4954476Seric ** 4963149Seric ** Parameters: 4973149Seric ** pvp -- pointer to token vector. 4983149Seric ** 4993149Seric ** Returns: 5003149Seric ** none. 5013149Seric ** 5023149Seric ** Side Effects: 5033149Seric ** pvp is modified. 5043149Seric */ 5052091Seric 5063149Seric struct match 5073149Seric { 5084468Seric char **first; /* first token matched */ 5094468Seric char **last; /* last token matched */ 5103149Seric }; 5113149Seric 5124468Seric # define MAXMATCH 9 /* max params per rewrite */ 5133149Seric 5143149Seric 5154070Seric rewrite(pvp, ruleset) 5163149Seric char **pvp; 5174070Seric int ruleset; 5183149Seric { 5193149Seric register char *ap; /* address pointer */ 5203149Seric register char *rp; /* rewrite pointer */ 5213149Seric register char **avp; /* address vector pointer */ 5223149Seric register char **rvp; /* rewrite vector pointer */ 5238058Seric register struct match *mlp; /* cur ptr into mlist */ 5248058Seric register struct rewrite *rwr; /* pointer to current rewrite rule */ 525*56678Seric struct match mlist[MAXMATCH]; /* stores match on LHS */ 5263149Seric char *npvp[MAXATOM+1]; /* temporary space for rebuild */ 5273149Seric 5289279Seric if (OpMode == MD_TEST || tTd(21, 2)) 5293149Seric { 5308959Seric printf("rewrite: ruleset %2d input:", ruleset); 531*56678Seric printav(pvp); 5323149Seric } 533*56678Seric if (ruleset < 0 || ruleset >= MAXRWSETS) 53456326Seric { 535*56678Seric syserr("rewrite: illegal ruleset number %d", ruleset); 53656326Seric return; 53756326Seric } 538*56678Seric if (pvp == NULL) 539*56678Seric return; 54056326Seric 5413149Seric /* 542*56678Seric ** Run through the list of rewrite rules, applying 543*56678Seric ** any that match. 5443149Seric */ 5453149Seric 5464070Seric for (rwr = RewriteRules[ruleset]; rwr != NULL; ) 5473149Seric { 548*56678Seric int loopcount = 0; 549*56678Seric 5507675Seric if (tTd(21, 12)) 551297Seric { 5528069Seric printf("-----trying rule:"); 553*56678Seric printav(rwr->r_lhs); 5543149Seric } 5553149Seric 5563149Seric /* try to match on this rule */ 5574468Seric mlp = mlist; 5588058Seric rvp = rwr->r_lhs; 5598058Seric avp = pvp; 5608058Seric while ((ap = *avp) != NULL || *rvp != NULL) 5613149Seric { 562*56678Seric if (++loopcount > 100) 56352637Seric { 564*56678Seric syserr("Infinite loop in ruleset %d", ruleset); 565*56678Seric printf("workspace: "); 566*56678Seric printav(pvp); 56752637Seric break; 56852637Seric } 5693149Seric rp = *rvp; 5708058Seric if (tTd(21, 35)) 5718058Seric { 572*56678Seric printf("operator="); 5738058Seric xputs(ap); 574*56678Seric printf(", token="); 5758058Seric xputs(rp); 5768069Seric printf("\n"); 5778058Seric } 578*56678Seric if (rp == NULL) 57956326Seric { 5803149Seric /* end-of-pattern before end-of-address */ 5818058Seric goto backup; 582*56678Seric } 583*56678Seric if (ap == NULL && *rp != MATCHZANY) 58456326Seric { 585*56678Seric /* end-of-input */ 586*56678Seric break; 587297Seric } 58856326Seric 589*56678Seric switch (*rp) 5908058Seric { 591*56678Seric register STAB *s; 59256326Seric 593*56678Seric case MATCHCLASS: 594*56678Seric case MATCHNCLASS: 595*56678Seric /* match any token in (not in) a class */ 596*56678Seric s = stab(ap, ST_CLASS, ST_FIND); 597*56678Seric if (s == NULL || !bitnset(rp[1], s->s_class)) 59856326Seric { 599*56678Seric if (*rp == MATCHCLASS) 6009585Seric goto backup; 60156326Seric } 602*56678Seric else if (*rp == MATCHNCLASS) 603*56678Seric goto backup; 6044060Seric 605*56678Seric /* explicit fall-through */ 606*56678Seric 607*56678Seric case MATCHONE: 608*56678Seric case MATCHANY: 609*56678Seric /* match exactly one token */ 610*56678Seric mlp->first = avp; 611*56678Seric mlp->last = avp++; 6128058Seric mlp++; 613*56678Seric break; 6148058Seric 615*56678Seric case MATCHZANY: 616*56678Seric /* match zero or more tokens */ 617*56678Seric mlp->first = avp; 618*56678Seric mlp->last = avp - 1; 619*56678Seric mlp++; 620*56678Seric break; 62156326Seric 622*56678Seric default: 623*56678Seric /* must have exact match */ 624*56678Seric if (strcasecmp(rp, ap)) 6258058Seric goto backup; 6264468Seric avp++; 627*56678Seric break; 6283149Seric } 6293149Seric 630*56678Seric /* successful match on this token */ 6313149Seric rvp++; 6323149Seric continue; 6333149Seric 634*56678Seric backup: 635*56678Seric /* match failed -- back up */ 636*56678Seric while (--rvp >= rwr->r_lhs) 6373149Seric { 638*56678Seric rp = *rvp; 639*56678Seric if (*rp == MATCHANY || *rp == MATCHZANY) 6404468Seric { 641*56678Seric /* extend binding and continue */ 642*56678Seric avp = ++mlp[-1].last; 643*56678Seric avp++; 644*56678Seric rvp++; 645*56678Seric break; 6464468Seric } 647*56678Seric avp--; 648*56678Seric if (*rp == MATCHONE || *rp == MATCHCLASS || 649*56678Seric *rp == MATCHNCLASS) 650*56678Seric { 651*56678Seric /* back out binding */ 652*56678Seric mlp--; 653*56678Seric } 6543149Seric } 6553149Seric 656*56678Seric if (rvp < rwr->r_lhs) 657*56678Seric { 658*56678Seric /* total failure to match */ 65956326Seric break; 6603149Seric } 661297Seric } 6623149Seric 6633149Seric /* 664*56678Seric ** See if we successfully matched 6653149Seric */ 6663149Seric 667*56678Seric if (rvp < rwr->r_lhs || *rvp != NULL) 6683149Seric { 6699374Seric if (tTd(21, 10)) 6709374Seric printf("----- rule fails\n"); 6719374Seric rwr = rwr->r_next; 6729374Seric continue; 6739374Seric } 6743149Seric 6759374Seric rvp = rwr->r_rhs; 6769374Seric if (tTd(21, 12)) 6779374Seric { 6789374Seric printf("-----rule matches:"); 679*56678Seric printav(rvp); 6809374Seric } 6819374Seric 6829374Seric rp = *rvp; 6839374Seric if (*rp == CANONUSER) 6849374Seric { 6859374Seric rvp++; 6869374Seric rwr = rwr->r_next; 6879374Seric } 6889374Seric else if (*rp == CANONHOST) 6899374Seric { 6909374Seric rvp++; 6919374Seric rwr = NULL; 6929374Seric } 6939374Seric else if (*rp == CANONNET) 6949374Seric rwr = NULL; 6959374Seric 6969374Seric /* substitute */ 6979374Seric for (avp = npvp; *rvp != NULL; rvp++) 6989374Seric { 6999374Seric register struct match *m; 7009374Seric register char **pp; 7019374Seric 7028058Seric rp = *rvp; 703*56678Seric if (*rp == MATCHREPL) 7048058Seric { 70516914Seric /* substitute from LHS */ 70616914Seric m = &mlist[rp[1] - '1']; 707*56678Seric if (m < mlist || m >= mlp) 7089374Seric { 709*56678Seric syserr("rewrite: ruleset %d: replacement $%c out of bounds", 71056326Seric ruleset, rp[1]); 7119374Seric return; 7129374Seric } 71316914Seric if (tTd(21, 15)) 71416914Seric { 71516914Seric printf("$%c:", rp[1]); 71616914Seric pp = m->first; 717*56678Seric while (pp <= m->last) 71816914Seric { 71916914Seric printf(" %x=\"", *pp); 72016914Seric (void) fflush(stdout); 72116914Seric printf("%s\"", *pp++); 72216914Seric } 72316914Seric printf("\n"); 72416914Seric } 7259374Seric pp = m->first; 726*56678Seric while (pp <= m->last) 7273149Seric { 72816914Seric if (avp >= &npvp[MAXATOM]) 729*56678Seric { 730*56678Seric syserr("rewrite: expansion too long"); 731*56678Seric return; 732*56678Seric } 73316914Seric *avp++ = *pp++; 7343149Seric } 7353149Seric } 73616914Seric else 7378226Seric { 73816914Seric /* vanilla replacement */ 7399374Seric if (avp >= &npvp[MAXATOM]) 74016889Seric { 741*56678Seric toolong: 74216889Seric syserr("rewrite: expansion too long"); 74316889Seric return; 74416889Seric } 745*56678Seric *avp++ = rp; 7468226Seric } 7479374Seric } 7489374Seric *avp++ = NULL; 74916914Seric 75016914Seric /* 751*56678Seric ** Check for any hostname/keyword lookups. 75216914Seric */ 75316914Seric 75416914Seric for (rvp = npvp; *rvp != NULL; rvp++) 75516914Seric { 756*56678Seric char **hbrvp; 75716914Seric char **xpvp; 75816914Seric int trsize; 75917473Seric char *olddelimchar; 760*56678Seric char *replac; 761*56678Seric int endtoken; 762*56678Seric STAB *map; 763*56678Seric char *mapname; 764*56678Seric char **key_rvp; 765*56678Seric char **arg_rvp; 766*56678Seric char **default_rvp; 767*56678Seric char buf[MAXNAME + 1]; 76816914Seric char *pvpb1[MAXATOM + 1]; 76917174Seric char pvpbuf[PSBUFSIZE]; 770*56678Seric extern char *DelimChar; 77116914Seric 772*56678Seric if (**rvp != HOSTBEGIN && **rvp != LOOKUPBEGIN) 77316914Seric continue; 77416914Seric 77516914Seric /* 776*56678Seric ** Got a hostname/keyword lookup. 77716914Seric ** 77816914Seric ** This could be optimized fairly easily. 77916914Seric */ 78016914Seric 78116914Seric hbrvp = rvp; 782*56678Seric arg_rvp = default_rvp = NULL; 783*56678Seric if (**rvp == HOSTBEGIN) 78456327Seric { 785*56678Seric endtoken = HOSTEND; 786*56678Seric mapname = "host"; 78756327Seric } 78856326Seric else 78956327Seric { 790*56678Seric endtoken = LOOKUPEND; 791*56678Seric mapname = *++rvp; 79256327Seric } 793*56678Seric map = stab(mapname, ST_MAP, ST_FIND); 794*56678Seric if (map == NULL) 795*56678Seric syserr("rewrite: map %s not found", mapname); 796*56678Seric 797*56678Seric /* extract the match part */ 798*56678Seric key_rvp = ++rvp; 799*56678Seric while (*rvp != NULL && **rvp != endtoken) 80053654Seric { 801*56678Seric switch (**rvp) 802*56678Seric { 803*56678Seric case CANONHOST: 804*56678Seric *rvp++ = NULL; 805*56678Seric arg_rvp = rvp; 806*56678Seric break; 807*56678Seric 808*56678Seric case CANONUSER: 809*56678Seric *rvp++ = NULL; 810*56678Seric default_rvp = rvp; 811*56678Seric break; 812*56678Seric 813*56678Seric default: 814*56678Seric rvp++; 815*56678Seric break; 816*56678Seric } 81753654Seric } 81816914Seric if (*rvp != NULL) 81916914Seric *rvp++ = NULL; 82016914Seric 82116914Seric /* save the remainder of the input string */ 82216914Seric trsize = (int) (avp - rvp + 1) * sizeof *rvp; 82316914Seric bcopy((char *) rvp, (char *) pvpb1, trsize); 82416914Seric 825*56678Seric /* look it up */ 826*56678Seric cataddr(key_rvp, buf, sizeof buf); 827*56678Seric if (map != NULL && bitset(MF_VALID, map->s_map.map_flags)) 828*56678Seric replac = (*map->s_map.map_class->map_lookup)(buf, 829*56678Seric sizeof buf - 1, arg_rvp); 83053654Seric else 831*56678Seric replac = NULL; 832*56678Seric 833*56678Seric /* if no replacement, use default */ 834*56678Seric if (replac == NULL) 83551317Seric { 836*56678Seric if (default_rvp != NULL) 837*56678Seric xpvp = default_rvp; 83853654Seric else 839*56678Seric xpvp = key_rvp; 84053654Seric } 841*56678Seric else 84253654Seric { 843*56678Seric /* scan the new replacement */ 844*56678Seric olddelimchar = DelimChar; 845*56678Seric xpvp = prescan(replac, '\0', pvpbuf); 846*56678Seric DelimChar = olddelimchar; 84753654Seric if (xpvp == NULL) 84851317Seric { 849*56678Seric syserr("rewrite: cannot prescan map value: %s", replac); 850*56678Seric return; 851*56678Seric } 85251317Seric } 85351317Seric 85416914Seric /* append it to the token list */ 855*56678Seric for (avp = hbrvp; *xpvp != NULL; xpvp++) 856*56678Seric { 85717174Seric *avp++ = newstr(*xpvp); 85816920Seric if (avp >= &npvp[MAXATOM]) 85916914Seric goto toolong; 86017174Seric } 86116914Seric 86216914Seric /* restore the old trailing information */ 863*56678Seric for (xpvp = pvpb1; (*avp++ = *xpvp++) != NULL; ) 86416920Seric if (avp >= &npvp[MAXATOM]) 86516914Seric goto toolong; 86617174Seric 867*56678Seric break; 86816914Seric } 86916914Seric 87016914Seric /* 87116914Seric ** Check for subroutine calls. 87216914Seric */ 87316914Seric 874*56678Seric if (*npvp != NULL && **npvp == CALLSUBR) 875*56678Seric { 876*56678Seric bcopy((char *) &npvp[2], (char *) pvp, 877*56678Seric (int) (avp - npvp - 2) * sizeof *avp); 878*56678Seric if (tTd(21, 3)) 879*56678Seric printf("-----callsubr %s\n", npvp[1]); 880*56678Seric rewrite(pvp, atoi(npvp[1])); 881*56678Seric } 882*56678Seric else 883*56678Seric { 88417348Seric bcopy((char *) npvp, (char *) pvp, 88516900Seric (int) (avp - npvp) * sizeof *avp); 886*56678Seric } 8879374Seric if (tTd(21, 4)) 8889374Seric { 8899374Seric printf("rewritten as:"); 890*56678Seric printav(pvp); 8919374Seric } 892297Seric } 8938069Seric 8949279Seric if (OpMode == MD_TEST || tTd(21, 2)) 8958069Seric { 8968959Seric printf("rewrite: ruleset %2d returns:", ruleset); 897*56678Seric printav(pvp); 8988069Seric } 8993149Seric } 9003149Seric /* 9013149Seric ** BUILDADDR -- build address from token vector. 9023149Seric ** 9033149Seric ** Parameters: 9043149Seric ** tv -- token vector. 9053149Seric ** a -- pointer to address descriptor to fill. 9063149Seric ** If NULL, one will be allocated. 9073149Seric ** 9083149Seric ** Returns: 9094279Seric ** NULL if there was an error. 9104279Seric ** 'a' otherwise. 9113149Seric ** 9123149Seric ** Side Effects: 9133149Seric ** fills in 'a' 9143149Seric */ 9153149Seric 916*56678Seric ADDRESS * 9173149Seric buildaddr(tv, a) 9183149Seric register char **tv; 9193149Seric register ADDRESS *a; 9203149Seric { 9213149Seric static char buf[MAXNAME]; 9223149Seric struct mailer **mp; 9233149Seric register struct mailer *m; 9243149Seric 9253149Seric if (a == NULL) 9263149Seric a = (ADDRESS *) xalloc(sizeof *a); 92716889Seric bzero((char *) a, sizeof *a); 9283149Seric 9293149Seric /* figure out what net/mailer to use */ 930*56678Seric if (**tv != CANONNET) 9314279Seric { 9323149Seric syserr("buildaddr: no net"); 9334279Seric return (NULL); 9344279Seric } 9353149Seric tv++; 93633725Sbostic if (!strcasecmp(*tv, "error")) 9374279Seric { 93810183Seric if (**++tv == CANONHOST) 93910183Seric { 94010183Seric setstat(atoi(*++tv)); 94110183Seric tv++; 94210183Seric } 94310183Seric if (**tv != CANONUSER) 9444279Seric syserr("buildaddr: error: no user"); 945*56678Seric buf[0] = '\0'; 9464279Seric while (*++tv != NULL) 9474279Seric { 9484279Seric if (buf[0] != '\0') 9497005Seric (void) strcat(buf, " "); 9507005Seric (void) strcat(buf, *tv); 9514279Seric } 9524279Seric usrerr(buf); 9534279Seric return (NULL); 9544279Seric } 9554598Seric for (mp = Mailer; (m = *mp++) != NULL; ) 9563149Seric { 95733725Sbostic if (!strcasecmp(m->m_name, *tv)) 9583149Seric break; 9593149Seric } 9603149Seric if (m == NULL) 9614279Seric { 96224944Seric syserr("buildaddr: unknown mailer %s", *tv); 9634279Seric return (NULL); 9644279Seric } 9654598Seric a->q_mailer = m; 9663149Seric 9673149Seric /* figure out what host (if any) */ 968*56678Seric tv++; 969*56678Seric if (!bitnset(M_LOCAL, m->m_flags)) 9703149Seric { 971*56678Seric if (**tv++ != CANONHOST) 9724279Seric { 9733149Seric syserr("buildaddr: no host"); 9744279Seric return (NULL); 9754279Seric } 9765704Seric buf[0] = '\0'; 977*56678Seric while (*tv != NULL && **tv != CANONUSER) 978*56678Seric (void) strcat(buf, *tv++); 9795704Seric a->q_host = newstr(buf); 9803149Seric } 981*56678Seric else 982*56678Seric a->q_host = NULL; 9833149Seric 9843149Seric /* figure out the user */ 98536615Sbostic if (*tv == NULL || **tv != CANONUSER) 9864279Seric { 9873149Seric syserr("buildaddr: no user"); 9884279Seric return (NULL); 9894279Seric } 99019040Seric 991*56678Seric if (m == LocalMailer && tv[1] != NULL && strcmp(tv[1], "@") == 0) 992*56678Seric { 993*56678Seric tv++; 994*56678Seric a->q_flags |= QNOTREMOTE; 995*56678Seric } 99651317Seric 99719040Seric /* rewrite according recipient mailer rewriting rules */ 99819040Seric rewrite(++tv, 2); 99956327Seric if (m->m_r_rwset > 0) 100056327Seric rewrite(tv, m->m_r_rwset); 100119040Seric rewrite(tv, 4); 100219040Seric 100319040Seric /* save the result for the command line/RCPT argument */ 100411278Seric cataddr(tv, buf, sizeof buf); 10053149Seric a->q_user = buf; 10063149Seric 10073149Seric return (a); 10083149Seric } 10093188Seric /* 10104228Seric ** CATADDR -- concatenate pieces of addresses (putting in <LWSP> subs) 10114228Seric ** 10124228Seric ** Parameters: 10134228Seric ** pvp -- parameter vector to rebuild. 10144228Seric ** buf -- buffer to build the string into. 10154228Seric ** sz -- size of buf. 10164228Seric ** 10174228Seric ** Returns: 10184228Seric ** none. 10194228Seric ** 10204228Seric ** Side Effects: 10214228Seric ** Destroys buf. 10224228Seric */ 10234228Seric 10244228Seric cataddr(pvp, buf, sz) 10254228Seric char **pvp; 10264228Seric char *buf; 10274228Seric register int sz; 10284228Seric { 10294228Seric bool oatomtok = FALSE; 1030*56678Seric bool natomtok = FALSE; 10314228Seric register int i; 10324228Seric register char *p; 10334228Seric 10348423Seric if (pvp == NULL) 10358423Seric { 103623109Seric (void) strcpy(buf, ""); 10378423Seric return; 10388423Seric } 10394228Seric p = buf; 104011156Seric sz -= 2; 10414228Seric while (*pvp != NULL && (i = strlen(*pvp)) < sz) 10424228Seric { 10438078Seric natomtok = (toktype(**pvp) == ATM); 10444228Seric if (oatomtok && natomtok) 10459042Seric *p++ = SpaceSub; 10464228Seric (void) strcpy(p, *pvp); 10474228Seric oatomtok = natomtok; 10484228Seric p += i; 104911156Seric sz -= i + 1; 10504228Seric pvp++; 10514228Seric } 10524228Seric *p = '\0'; 10534228Seric } 10544228Seric /* 10553188Seric ** SAMEADDR -- Determine if two addresses are the same 10563188Seric ** 10573188Seric ** This is not just a straight comparison -- if the mailer doesn't 10583188Seric ** care about the host we just ignore it, etc. 10593188Seric ** 10603188Seric ** Parameters: 10613188Seric ** a, b -- pointers to the internal forms to compare. 10623188Seric ** 10633188Seric ** Returns: 10643188Seric ** TRUE -- they represent the same mailbox. 10653188Seric ** FALSE -- they don't. 10663188Seric ** 10673188Seric ** Side Effects: 10683188Seric ** none. 10693188Seric */ 10703188Seric 10713188Seric bool 10729374Seric sameaddr(a, b) 10733188Seric register ADDRESS *a; 10743188Seric register ADDRESS *b; 10753188Seric { 10763188Seric /* if they don't have the same mailer, forget it */ 10773188Seric if (a->q_mailer != b->q_mailer) 10783188Seric return (FALSE); 10793188Seric 10803188Seric /* if the user isn't the same, we can drop out */ 1081*56678Seric if (strcmp(a->q_user, b->q_user) != 0) 10823188Seric return (FALSE); 10833188Seric 10843188Seric /* if the mailer ignores hosts, we have succeeded! */ 108510690Seric if (bitnset(M_LOCAL, a->q_mailer->m_flags)) 10863188Seric return (TRUE); 10873188Seric 10883188Seric /* otherwise compare hosts (but be careful for NULL ptrs) */ 10893188Seric if (a->q_host == NULL || b->q_host == NULL) 10903188Seric return (FALSE); 1091*56678Seric if (strcmp(a->q_host, b->q_host) != 0) 10923188Seric return (FALSE); 10933188Seric 10943188Seric return (TRUE); 10953188Seric } 10963234Seric /* 10973234Seric ** PRINTADDR -- print address (for debugging) 10983234Seric ** 10993234Seric ** Parameters: 11003234Seric ** a -- the address to print 11013234Seric ** follow -- follow the q_next chain. 11023234Seric ** 11033234Seric ** Returns: 11043234Seric ** none. 11053234Seric ** 11063234Seric ** Side Effects: 11073234Seric ** none. 11083234Seric */ 11093234Seric 11103234Seric printaddr(a, follow) 11113234Seric register ADDRESS *a; 11123234Seric bool follow; 11133234Seric { 11145001Seric bool first = TRUE; 11155001Seric 11163234Seric while (a != NULL) 11173234Seric { 11185001Seric first = FALSE; 11194443Seric printf("%x=", a); 11204085Seric (void) fflush(stdout); 112140973Sbostic printf("%s: mailer %d (%s), host `%s', user `%s', ruser `%s'\n", 112240973Sbostic a->q_paddr, a->q_mailer->m_mno, a->q_mailer->m_name, 112340973Sbostic a->q_host, a->q_user, a->q_ruser? a->q_ruser: "<null>"); 11248181Seric printf("\tnext=%x, flags=%o, alias %x\n", a->q_next, a->q_flags, 11258181Seric a->q_alias); 11268181Seric printf("\thome=\"%s\", fullname=\"%s\"\n", a->q_home, 11278181Seric a->q_fullname); 11284996Seric 11293234Seric if (!follow) 11303234Seric return; 11314996Seric a = a->q_next; 11323234Seric } 11335001Seric if (first) 11344443Seric printf("[NULL]\n"); 11353234Seric } 11364317Seric 11377682Seric /* 11387682Seric ** REMOTENAME -- return the name relative to the current mailer 11397682Seric ** 11407682Seric ** Parameters: 11417682Seric ** name -- the name to translate. 11428069Seric ** m -- the mailer that we want to do rewriting relative 11438069Seric ** to. 11448069Seric ** senderaddress -- if set, uses the sender rewriting rules 11458069Seric ** rather than the recipient rewriting rules. 114610310Seric ** canonical -- if set, strip out any comment information, 114710310Seric ** etc. 11487682Seric ** 11497682Seric ** Returns: 11507682Seric ** the text string representing this address relative to 11517682Seric ** the receiving mailer. 11527682Seric ** 11537682Seric ** Side Effects: 11547682Seric ** none. 11557682Seric ** 11567682Seric ** Warnings: 11577682Seric ** The text string returned is tucked away locally; 11587682Seric ** copy it if you intend to save it. 11597682Seric */ 11607682Seric 11617682Seric char * 1162*56678Seric remotename(name, m, senderaddress, canonical, e) 11637682Seric char *name; 1164*56678Seric struct mailer *m; 11658069Seric bool senderaddress; 116610310Seric bool canonical; 1167*56678Seric register ENVELOPE *e; 11687682Seric { 11698069Seric register char **pvp; 11708069Seric char *fancy; 1171*56678Seric extern char *macvalue(); 1172*56678Seric char *oldg = macvalue('g', e); 11737682Seric static char buf[MAXNAME]; 11747682Seric char lbuf[MAXNAME]; 117516914Seric char pvpbuf[PSBUFSIZE]; 1176*56678Seric extern char **prescan(); 1177*56678Seric extern char *crackaddr(); 11787682Seric 11797755Seric if (tTd(12, 1)) 11807755Seric printf("remotename(%s)\n", name); 11817755Seric 118210177Seric /* don't do anything if we are tagging it as special */ 118356327Seric if ((senderaddress ? m->m_s_rwset : m->m_r_rwset) < 0) 118410177Seric return (name); 118510177Seric 11867682Seric /* 11878181Seric ** Do a heuristic crack of this name to extract any comment info. 11888181Seric ** This will leave the name as a comment and a $g macro. 11897889Seric */ 11907889Seric 119110310Seric if (canonical) 119216155Seric fancy = "\001g"; 119310310Seric else 119410310Seric fancy = crackaddr(name); 11957889Seric 11968181Seric /* 11978181Seric ** Turn the name into canonical form. 11988181Seric ** Normally this will be RFC 822 style, i.e., "user@domain". 11998181Seric ** If this only resolves to "user", and the "C" flag is 12008181Seric ** specified in the sending mailer, then the sender's 12018181Seric ** domain will be appended. 12028181Seric */ 12038181Seric 120416914Seric pvp = prescan(name, '\0', pvpbuf); 12057889Seric if (pvp == NULL) 12067889Seric return (name); 12078181Seric rewrite(pvp, 3); 1208*56678Seric if (e->e_fromdomain != NULL) 12098181Seric { 12108181Seric /* append from domain to this address */ 12118181Seric register char **pxp = pvp; 12128181Seric 12139594Seric /* see if there is an "@domain" in the current name */ 12148181Seric while (*pxp != NULL && strcmp(*pxp, "@") != 0) 12158181Seric pxp++; 12168181Seric if (*pxp == NULL) 12178181Seric { 12189594Seric /* no.... append the "@domain" from the sender */ 1219*56678Seric register char **qxq = e->e_fromdomain; 12208181Seric 12219594Seric while ((*pxp++ = *qxq++) != NULL) 12229594Seric continue; 122311726Seric rewrite(pvp, 3); 12248181Seric } 12258181Seric } 12268181Seric 12278181Seric /* 12288959Seric ** Do more specific rewriting. 1229*56678Seric ** Rewrite using ruleset 1 or 2 depending on whether this is 1230*56678Seric ** a sender address or not. 12318181Seric ** Then run it through any receiving-mailer-specific rulesets. 12328181Seric */ 12338181Seric 12348069Seric if (senderaddress) 12357755Seric { 123656327Seric rewrite(pvp, 1); 123756327Seric if (m->m_s_rwset > 0) 123856327Seric rewrite(pvp, m->m_s_rwset); 12398069Seric } 12408069Seric else 12418069Seric { 124256327Seric rewrite(pvp, 2); 124356327Seric if (m->m_r_rwset > 0) 124456327Seric rewrite(pvp, m->m_r_rwset); 12457682Seric } 12467682Seric 12478181Seric /* 12488959Seric ** Do any final sanitation the address may require. 12498959Seric ** This will normally be used to turn internal forms 12508959Seric ** (e.g., user@host.LOCAL) into external form. This 12518959Seric ** may be used as a default to the above rules. 12528959Seric */ 12538959Seric 12548959Seric rewrite(pvp, 4); 12558959Seric 12568959Seric /* 12578181Seric ** Now restore the comment information we had at the beginning. 12588181Seric */ 12598181Seric 12607682Seric cataddr(pvp, lbuf, sizeof lbuf); 1261*56678Seric define('g', lbuf, e); 1262*56678Seric expand(fancy, buf, &buf[sizeof buf - 1], e); 1263*56678Seric define('g', oldg, e); 12647682Seric 12657682Seric if (tTd(12, 1)) 12667755Seric printf("remotename => `%s'\n", buf); 12677682Seric return (buf); 12687682Seric } 126951317Seric /* 1270*56678Seric ** MAPLOCALUSER -- run local username through ruleset 5 for final redirection 127151317Seric ** 127251317Seric ** Parameters: 1273*56678Seric ** a -- the address to map (but just the user name part). 1274*56678Seric ** sendq -- the sendq in which to install any replacement 1275*56678Seric ** addresses. 127651317Seric ** 127751317Seric ** Returns: 127851317Seric ** none. 127951317Seric */ 128051317Seric 1281*56678Seric maplocaluser(a, sendq, e) 1282*56678Seric register ADDRESS *a; 1283*56678Seric ADDRESS **sendq; 1284*56678Seric ENVELOPE *e; 128551317Seric { 1286*56678Seric register char **pvp; 1287*56678Seric register ADDRESS *a1 = NULL; 1288*56678Seric char pvpbuf[PSBUFSIZE]; 128951317Seric 1290*56678Seric if (tTd(29, 1)) 1291*56678Seric { 1292*56678Seric printf("maplocaluser: "); 1293*56678Seric printaddr(a, FALSE); 1294*56678Seric } 1295*56678Seric pvp = prescan(a->q_user, '\0', pvpbuf); 1296*56678Seric if (pvp == NULL) 1297*56678Seric return; 129851317Seric 1299*56678Seric rewrite(pvp, 5); 1300*56678Seric if (pvp[0] == NULL || pvp[0][0] != CANONNET) 1301*56678Seric return; 130251317Seric 1303*56678Seric /* if non-null, mailer destination specified -- has it changed? */ 1304*56678Seric a1 = buildaddr(pvp, NULL); 1305*56678Seric if (a1 == NULL || sameaddr(a, a1)) 1306*56678Seric return; 130751317Seric 1308*56678Seric /* mark old address as dead; insert new address */ 1309*56678Seric a->q_flags |= QDONTSEND; 1310*56678Seric a1->q_alias = a; 1311*56678Seric allocaddr(a1, 1, NULL); 1312*56678Seric (void) recipient(a1, sendq, e); 131351317Seric } 1314