122976Smiriam /* 234921Sbostic * Copyright (c) 1983 Eric P. Allman 363589Sbostic * Copyright (c) 1988, 1993 463589Sbostic * The Regents of the University of California. All rights reserved. 533730Sbostic * 642828Sbostic * %sccs.include.redist.c% 733730Sbostic */ 822976Smiriam 922976Smiriam #ifndef lint 10*68400Seric static char sccsid[] = "@(#)parseaddr.c 8.53 (Berkeley) 02/21/95"; 1133730Sbostic #endif /* not lint */ 1222976Smiriam 1356678Seric # 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. 3364284Seric ** flags -- describe detail for parsing. See RF_ definitions 3464284Seric ** in sendmail.h. 3511445Seric ** delim -- the character to terminate the address, passed 3611445Seric ** to prescan. 3758333Seric ** delimptr -- if non-NULL, set to the location of the 3858333Seric ** delim character that was found. 3956678Seric ** e -- the envelope that will contain this address. 40297Seric ** 41297Seric ** Returns: 42297Seric ** A pointer to the address descriptor header (`a' if 43297Seric ** `a' is non-NULL). 44297Seric ** NULL on error. 45297Seric ** 46297Seric ** Side Effects: 47297Seric ** none 48297Seric */ 49297Seric 509374Seric /* following delimiters are inherent to the internal algorithms */ 5159278Seric # define DELIMCHARS "()<>,;\r\n" /* default word delimiters */ 522091Seric 532973Seric ADDRESS * 5464284Seric parseaddr(addr, a, flags, delim, delimptr, e) 55297Seric char *addr; 562973Seric register ADDRESS *a; 5764284Seric int flags; 5859700Seric int delim; 5958333Seric char **delimptr; 6056678Seric register ENVELOPE *e; 61297Seric { 623149Seric register char **pvp; 6358333Seric auto char *delimptrbuf; 6459084Seric bool queueup; 6516914Seric char pvpbuf[PSBUFSIZE]; 6656678Seric extern ADDRESS *buildaddr(); 6757388Seric extern bool invalidaddr(); 68297Seric 69297Seric /* 70297Seric ** Initialize and prescan address. 71297Seric */ 72297Seric 7356678Seric e->e_to = addr; 747675Seric if (tTd(20, 1)) 759888Seric printf("\n--parseaddr(%s)\n", addr); 763188Seric 7758333Seric if (delimptr == NULL) 7858333Seric delimptr = &delimptrbuf; 7958333Seric 8065066Seric pvp = prescan(addr, delim, pvpbuf, sizeof pvpbuf, delimptr); 813149Seric if (pvp == NULL) 8256729Seric { 8356729Seric if (tTd(20, 1)) 8456729Seric printf("parseaddr-->NULL\n"); 85297Seric return (NULL); 8656729Seric } 87297Seric 8864726Seric if (invalidaddr(addr, delim == '\0' ? NULL : *delimptr)) 8964726Seric { 9064726Seric if (tTd(20, 1)) 9164726Seric printf("parseaddr-->bad address\n"); 9264726Seric return NULL; 9364726Seric } 9464726Seric 95297Seric /* 9664348Seric ** Save addr if we are going to have to. 9764348Seric ** 9864348Seric ** We have to do this early because there is a chance that 9964348Seric ** the map lookups in the rewriting rules could clobber 10064348Seric ** static memory somewhere. 10164348Seric */ 10264348Seric 10364348Seric if (bitset(RF_COPYPADDR, flags) && addr != NULL) 10464348Seric { 10564348Seric char savec = **delimptr; 10664348Seric 10764348Seric if (savec != '\0') 10864348Seric **delimptr = '\0'; 10966794Seric e->e_to = addr = newstr(addr); 11064348Seric if (savec != '\0') 11164348Seric **delimptr = savec; 11264348Seric } 11364348Seric 11464348Seric /* 1153149Seric ** Apply rewriting rules. 1167889Seric ** Ruleset 0 does basic parsing. It must resolve. 117297Seric */ 118297Seric 11959084Seric queueup = FALSE; 12065071Seric if (rewrite(pvp, 3, 0, e) == EX_TEMPFAIL) 12159084Seric queueup = TRUE; 12265071Seric if (rewrite(pvp, 0, 0, e) == EX_TEMPFAIL) 12359084Seric queueup = TRUE; 124297Seric 125297Seric 126297Seric /* 1273149Seric ** Build canonical address from pvp. 128297Seric */ 129297Seric 13064284Seric a = buildaddr(pvp, a, flags, e); 131297Seric 132297Seric /* 1333149Seric ** Make local copies of the host & user and then 1343149Seric ** transport them out. 135297Seric */ 136297Seric 13764348Seric allocaddr(a, flags, addr); 13864306Seric if (bitset(QBADADDR, a->q_flags)) 13964306Seric return a; 14056678Seric 14156678Seric /* 14259084Seric ** If there was a parsing failure, mark it for queueing. 14359084Seric */ 14459084Seric 14559084Seric if (queueup) 14659595Seric { 14759734Seric char *msg = "Transient parse error -- message queued for future delivery"; 14859734Seric 14959595Seric if (tTd(20, 1)) 15059595Seric printf("parseaddr: queuing message\n"); 15159734Seric message(msg); 15259734Seric if (e->e_message == NULL) 15360009Seric e->e_message = newstr(msg); 15459084Seric a->q_flags |= QQUEUEUP; 15568358Seric a->q_status = "4.4.3"; 15659595Seric } 15759084Seric 15859084Seric /* 15956678Seric ** Compute return value. 16056678Seric */ 16156678Seric 16256678Seric if (tTd(20, 1)) 1638078Seric { 16456678Seric printf("parseaddr-->"); 16556678Seric printaddr(a, FALSE); 16656678Seric } 16756678Seric 16856678Seric return (a); 16956678Seric } 17056678Seric /* 17157388Seric ** INVALIDADDR -- check for address containing meta-characters 17257388Seric ** 17357388Seric ** Parameters: 17457388Seric ** addr -- the address to check. 17557388Seric ** 17657388Seric ** Returns: 17757388Seric ** TRUE -- if the address has any "wierd" characters 17857388Seric ** FALSE -- otherwise. 17957388Seric */ 18057388Seric 18157388Seric bool 18264726Seric invalidaddr(addr, delimptr) 18357388Seric register char *addr; 18464726Seric char *delimptr; 18557388Seric { 18664726Seric char savedelim; 18764726Seric 18864726Seric if (delimptr != NULL) 18964764Seric { 19064726Seric savedelim = *delimptr; 19164764Seric if (savedelim != '\0') 19264764Seric *delimptr = '\0'; 19364764Seric } 19464726Seric #if 0 19564726Seric /* for testing.... */ 19664726Seric if (strcmp(addr, "INvalidADDR") == 0) 19757388Seric { 19864726Seric usrerr("553 INvalid ADDRess"); 19964764Seric goto addrfailure; 20057388Seric } 20164726Seric #endif 20264726Seric for (; *addr != '\0'; addr++) 20364726Seric { 20464726Seric if ((*addr & 0340) == 0200) 20564726Seric break; 20664726Seric } 20764726Seric if (*addr == '\0') 20864764Seric { 209*68400Seric if (delimptr != NULL && savedelim != '\0') 21064764Seric *delimptr = savedelim; 21164726Seric return FALSE; 21264764Seric } 21364726Seric setstat(EX_USAGE); 21464726Seric usrerr("553 Address contained invalid control characters"); 21564764Seric addrfailure: 21664764Seric if (savedelim != '\0' && delimptr != NULL) 21764764Seric *delimptr = savedelim; 21864726Seric return TRUE; 21957388Seric } 22057388Seric /* 22156678Seric ** ALLOCADDR -- do local allocations of address on demand. 22256678Seric ** 22356678Seric ** Also lowercases the host name if requested. 22456678Seric ** 22556678Seric ** Parameters: 22656678Seric ** a -- the address to reallocate. 22764284Seric ** flags -- the copy flag (see RF_ definitions in sendmail.h 22864284Seric ** for a description). 22956678Seric ** paddr -- the printname of the address. 23056678Seric ** 23156678Seric ** Returns: 23256678Seric ** none. 23356678Seric ** 23456678Seric ** Side Effects: 23556678Seric ** Copies portions of a into local buffers as requested. 23656678Seric */ 23756678Seric 23864348Seric allocaddr(a, flags, paddr) 23956678Seric register ADDRESS *a; 24064284Seric int flags; 24156678Seric char *paddr; 24256678Seric { 24358673Seric if (tTd(24, 4)) 24467693Seric printf("allocaddr(flags=%x, paddr=%s)\n", flags, paddr); 24558673Seric 24664348Seric a->q_paddr = paddr; 2478078Seric 24824944Seric if (a->q_user == NULL) 24924944Seric a->q_user = ""; 25024944Seric if (a->q_host == NULL) 25124944Seric a->q_host = ""; 25224944Seric 25364284Seric if (bitset(RF_COPYPARSE, flags)) 254297Seric { 25524944Seric a->q_host = newstr(a->q_host); 2563149Seric if (a->q_user != a->q_paddr) 2573149Seric a->q_user = newstr(a->q_user); 258297Seric } 259297Seric 26056678Seric if (a->q_paddr == NULL) 26156678Seric a->q_paddr = a->q_user; 262297Seric } 263297Seric /* 264297Seric ** PRESCAN -- Prescan name and make it canonical 265297Seric ** 2669374Seric ** Scans a name and turns it into a set of tokens. This process 2679374Seric ** deletes blanks and comments (in parentheses). 268297Seric ** 269297Seric ** This routine knows about quoted strings and angle brackets. 270297Seric ** 271297Seric ** There are certain subtleties to this routine. The one that 272297Seric ** comes to mind now is that backslashes on the ends of names 273297Seric ** are silently stripped off; this is intentional. The problem 274297Seric ** is that some versions of sndmsg (like at LBL) set the kill 275297Seric ** character to something other than @ when reading addresses; 276297Seric ** so people type "csvax.eric\@berkeley" -- which screws up the 277297Seric ** berknet mailer. 278297Seric ** 279297Seric ** Parameters: 280297Seric ** addr -- the name to chomp. 281297Seric ** delim -- the delimiter for the address, normally 282297Seric ** '\0' or ','; \0 is accepted in any case. 28315284Seric ** If '\t' then we are reading the .cf file. 28416914Seric ** pvpbuf -- place to put the saved text -- note that 28516914Seric ** the pointers are static. 28665066Seric ** pvpbsize -- size of pvpbuf. 28758333Seric ** delimptr -- if non-NULL, set to the location of the 28858333Seric ** terminating delimiter. 289297Seric ** 290297Seric ** Returns: 2913149Seric ** A pointer to a vector of tokens. 292297Seric ** NULL on error. 293297Seric */ 294297Seric 2958078Seric /* states and character types */ 2968078Seric # define OPR 0 /* operator */ 2978078Seric # define ATM 1 /* atom */ 2988078Seric # define QST 2 /* in quoted string */ 2998078Seric # define SPC 3 /* chewing up spaces */ 3008078Seric # define ONE 4 /* pick up one character */ 3013149Seric 3028078Seric # define NSTATES 5 /* number of states */ 3038078Seric # define TYPE 017 /* mask to select state type */ 3048078Seric 3058078Seric /* meta bits for table */ 3068078Seric # define M 020 /* meta character; don't pass through */ 3078078Seric # define B 040 /* cause a break */ 3088078Seric # define MB M|B /* meta-break */ 3098078Seric 3108078Seric static short StateTab[NSTATES][NSTATES] = 3118078Seric { 3128087Seric /* oldst chtype> OPR ATM QST SPC ONE */ 3139051Seric /*OPR*/ OPR|B, ATM|B, QST|B, SPC|MB, ONE|B, 3149051Seric /*ATM*/ OPR|B, ATM, QST|B, SPC|MB, ONE|B, 3159051Seric /*QST*/ QST, QST, OPR, QST, QST, 3168078Seric /*SPC*/ OPR, ATM, QST, SPC|M, ONE, 3178078Seric /*ONE*/ OPR, OPR, OPR, OPR, OPR, 3188078Seric }; 3198078Seric 32065092Seric /* token type table -- it gets modified with $o characters */ 32165092Seric static TokTypeTab[256] = 32265092Seric { 32365092Seric ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,SPC,SPC,SPC,SPC,SPC,ATM,ATM, 32465092Seric ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 32565092Seric SPC,ATM,QST,ATM,ATM,ATM,ATM,ATM,ATM,SPC,ATM,ATM,ATM,ATM,ATM,ATM, 32665092Seric ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 32765092Seric ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 32865092Seric ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 32965092Seric ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 33065092Seric ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 33165092Seric OPR,OPR,ONE,OPR,OPR,OPR,OPR,OPR,OPR,OPR,OPR,OPR,OPR,OPR,OPR,OPR, 33265092Seric OPR,OPR,OPR,ONE,ONE,ONE,OPR,OPR,OPR,OPR,OPR,OPR,OPR,OPR,OPR,OPR, 33365092Seric ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 33465092Seric ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 33565092Seric ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 33665092Seric ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 33765092Seric ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 33865092Seric ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 33965092Seric }; 34065092Seric 34165092Seric #define toktype(c) ((int) TokTypeTab[(c) & 0xff]) 34265092Seric 34365092Seric 3448078Seric # define NOCHAR -1 /* signal nothing in lookahead token */ 3458078Seric 3463149Seric char ** 34765066Seric prescan(addr, delim, pvpbuf, pvpbsize, delimptr) 348297Seric char *addr; 34968353Seric int delim; 35016914Seric char pvpbuf[]; 35158333Seric char **delimptr; 352297Seric { 353297Seric register char *p; 3548078Seric register char *q; 3559346Seric register int c; 3563149Seric char **avp; 357297Seric bool bslashmode; 358297Seric int cmntcnt; 3598423Seric int anglecnt; 3603149Seric char *tok; 3618078Seric int state; 3628078Seric int newstate; 36359747Seric char *saveto = CurEnv->e_to; 3648078Seric static char *av[MAXATOM+1]; 36565092Seric static char firsttime = TRUE; 36656678Seric extern int errno; 367297Seric 36865092Seric if (firsttime) 36965092Seric { 37065092Seric /* initialize the token type table */ 37165092Seric char obuf[50]; 37265092Seric 37365092Seric firsttime = FALSE; 37465092Seric expand("\201o", obuf, &obuf[sizeof obuf - sizeof DELIMCHARS], CurEnv); 37565092Seric strcat(obuf, DELIMCHARS); 37665092Seric for (p = obuf; *p != '\0'; p++) 37765092Seric { 37865092Seric if (TokTypeTab[*p & 0xff] == ATM) 37965092Seric TokTypeTab[*p & 0xff] = OPR; 38065092Seric } 38165092Seric } 38265092Seric 38315253Seric /* make sure error messages don't have garbage on them */ 38415253Seric errno = 0; 38515253Seric 38616914Seric q = pvpbuf; 3873149Seric bslashmode = FALSE; 3887800Seric cmntcnt = 0; 3898423Seric anglecnt = 0; 3903149Seric avp = av; 39156678Seric state = ATM; 3928078Seric c = NOCHAR; 3938078Seric p = addr; 39459747Seric CurEnv->e_to = p; 39556764Seric if (tTd(22, 11)) 396297Seric { 3978078Seric printf("prescan: "); 3988078Seric xputs(p); 39923109Seric (void) putchar('\n'); 4008078Seric } 4018078Seric 4028078Seric do 4038078Seric { 4043149Seric /* read a token */ 4053149Seric tok = q; 4068078Seric for (;;) 407297Seric { 4088078Seric /* store away any old lookahead character */ 40959277Seric if (c != NOCHAR && !bslashmode) 4108078Seric { 41115284Seric /* see if there is room */ 41265066Seric if (q >= &pvpbuf[pvpbsize - 5]) 4138078Seric { 41458151Seric usrerr("553 Address too long"); 41565015Seric returnnull: 41658333Seric if (delimptr != NULL) 41758333Seric *delimptr = p; 41859747Seric CurEnv->e_to = saveto; 4198078Seric return (NULL); 4208078Seric } 42115284Seric 42215284Seric /* squirrel it away */ 4238078Seric *q++ = c; 4248078Seric } 4258078Seric 4268078Seric /* read a new input character */ 4278078Seric c = *p++; 42857631Seric if (c == '\0') 42956764Seric { 43056764Seric /* diagnose and patch up bad syntax */ 43156764Seric if (state == QST) 43256764Seric { 43364767Seric usrerr("653 Unbalanced '\"'"); 43456764Seric c = '"'; 43556764Seric } 43656764Seric else if (cmntcnt > 0) 43756764Seric { 43864767Seric usrerr("653 Unbalanced '('"); 43956764Seric c = ')'; 44056764Seric } 44156764Seric else if (anglecnt > 0) 44256764Seric { 44356764Seric c = '>'; 44464767Seric usrerr("653 Unbalanced '<'"); 44556764Seric } 44656764Seric else 44756764Seric break; 44815284Seric 44956764Seric p--; 45056764Seric } 45157631Seric else if (c == delim && anglecnt <= 0 && 45257631Seric cmntcnt <= 0 && state != QST) 45357631Seric break; 45456764Seric 4558078Seric if (tTd(22, 101)) 4568078Seric printf("c=%c, s=%d; ", c, state); 4578078Seric 4583149Seric /* chew up special characters */ 4593149Seric *q = '\0'; 4603149Seric if (bslashmode) 4613149Seric { 46259105Seric bslashmode = FALSE; 46359105Seric 46424944Seric /* kludge \! for naive users */ 46558061Seric if (cmntcnt > 0) 46659105Seric { 46758061Seric c = NOCHAR; 46859105Seric continue; 46959105Seric } 47059105Seric else if (c != '!' || state == QST) 47159105Seric { 47256678Seric *q++ = '\\'; 47359105Seric continue; 47459105Seric } 4753149Seric } 47656678Seric 47756678Seric if (c == '\\') 4783149Seric { 4793149Seric bslashmode = TRUE; 4803149Seric } 48156678Seric else if (state == QST) 4828514Seric { 4838514Seric /* do nothing, just avoid next clauses */ 4848514Seric } 4858078Seric else if (c == '(') 4864100Seric { 4878078Seric cmntcnt++; 4888078Seric c = NOCHAR; 4894100Seric } 4908078Seric else if (c == ')') 4913149Seric { 4928078Seric if (cmntcnt <= 0) 4933149Seric { 49464767Seric usrerr("653 Unbalanced ')'"); 49563844Seric c = NOCHAR; 4963149Seric } 4978078Seric else 4988078Seric cmntcnt--; 4998078Seric } 5008078Seric else if (cmntcnt > 0) 5018078Seric c = NOCHAR; 5028423Seric else if (c == '<') 5038423Seric anglecnt++; 5048423Seric else if (c == '>') 5058423Seric { 5068423Seric if (anglecnt <= 0) 5078423Seric { 50864767Seric usrerr("653 Unbalanced '>'"); 50963844Seric c = NOCHAR; 5108423Seric } 51163844Seric else 51263844Seric anglecnt--; 5138423Seric } 51458050Seric else if (delim == ' ' && isascii(c) && isspace(c)) 51511423Seric c = ' '; 5163149Seric 5178078Seric if (c == NOCHAR) 5188078Seric continue; 5193149Seric 5208078Seric /* see if this is end of input */ 52111405Seric if (c == delim && anglecnt <= 0 && state != QST) 5223149Seric break; 5233149Seric 5248078Seric newstate = StateTab[state][toktype(c)]; 5258078Seric if (tTd(22, 101)) 5268078Seric printf("ns=%02o\n", newstate); 5278078Seric state = newstate & TYPE; 5288078Seric if (bitset(M, newstate)) 5298078Seric c = NOCHAR; 5308078Seric if (bitset(B, newstate)) 5314228Seric break; 532297Seric } 5333149Seric 5343149Seric /* new token */ 5358078Seric if (tok != q) 5361378Seric { 5378078Seric *q++ = '\0'; 5388078Seric if (tTd(22, 36)) 539297Seric { 5408078Seric printf("tok="); 5418078Seric xputs(tok); 54223109Seric (void) putchar('\n'); 543297Seric } 5448078Seric if (avp >= &av[MAXATOM]) 545297Seric { 54658151Seric syserr("553 prescan: too many tokens"); 54765015Seric goto returnnull; 548297Seric } 54965015Seric if (q - tok > MAXNAME) 55065015Seric { 55165015Seric syserr("553 prescan: token too long"); 55265015Seric goto returnnull; 55365015Seric } 5548078Seric *avp++ = tok; 555297Seric } 5568423Seric } while (c != '\0' && (c != delim || anglecnt > 0)); 5573149Seric *avp = NULL; 55858333Seric p--; 55958333Seric if (delimptr != NULL) 56058333Seric *delimptr = p; 56156764Seric if (tTd(22, 12)) 56256764Seric { 56356764Seric printf("prescan==>"); 56456764Seric printav(av); 56556764Seric } 56659747Seric CurEnv->e_to = saveto; 56758546Seric if (av[0] == NULL) 56864966Seric { 56964966Seric if (tTd(22, 1)) 57064966Seric printf("prescan: null leading token\n"); 57158546Seric return (NULL); 57264966Seric } 57358403Seric return (av); 5743149Seric } 5753149Seric /* 5763149Seric ** REWRITE -- apply rewrite rules to token vector. 5773149Seric ** 5784476Seric ** This routine is an ordered production system. Each rewrite 5794476Seric ** rule has a LHS (called the pattern) and a RHS (called the 5804476Seric ** rewrite); 'rwr' points the the current rewrite rule. 5814476Seric ** 5824476Seric ** For each rewrite rule, 'avp' points the address vector we 5834476Seric ** are trying to match against, and 'pvp' points to the pattern. 5848058Seric ** If pvp points to a special match value (MATCHZANY, MATCHANY, 5859585Seric ** MATCHONE, MATCHCLASS, MATCHNCLASS) then the address in avp 5869585Seric ** matched is saved away in the match vector (pointed to by 'mvp'). 5874476Seric ** 5884476Seric ** When a match between avp & pvp does not match, we try to 5899585Seric ** back out. If we back up over MATCHONE, MATCHCLASS, or MATCHNCLASS 5904476Seric ** we must also back out the match in mvp. If we reach a 5918058Seric ** MATCHANY or MATCHZANY we just extend the match and start 5928058Seric ** over again. 5934476Seric ** 5944476Seric ** When we finally match, we rewrite the address vector 5954476Seric ** and try over again. 5964476Seric ** 5973149Seric ** Parameters: 5983149Seric ** pvp -- pointer to token vector. 59959027Seric ** ruleset -- the ruleset to use for rewriting. 60065071Seric ** reclevel -- recursion level (to catch loops). 60159027Seric ** e -- the current envelope. 6023149Seric ** 6033149Seric ** Returns: 60459084Seric ** A status code. If EX_TEMPFAIL, higher level code should 60559084Seric ** attempt recovery. 6063149Seric ** 6073149Seric ** Side Effects: 6083149Seric ** pvp is modified. 6093149Seric */ 6102091Seric 6113149Seric struct match 6123149Seric { 6134468Seric char **first; /* first token matched */ 6144468Seric char **last; /* last token matched */ 61558825Seric char **pattern; /* pointer to pattern */ 6163149Seric }; 6173149Seric 6184468Seric # define MAXMATCH 9 /* max params per rewrite */ 6193149Seric 62065136Seric # ifndef MAXRULERECURSION 62165136Seric # define MAXRULERECURSION 50 /* max recursion depth */ 62265136Seric # endif 6233149Seric 62465136Seric 62559084Seric int 62665071Seric rewrite(pvp, ruleset, reclevel, e) 6273149Seric char **pvp; 6284070Seric int ruleset; 62965071Seric int reclevel; 63059027Seric register ENVELOPE *e; 6313149Seric { 6323149Seric register char *ap; /* address pointer */ 6333149Seric register char *rp; /* rewrite pointer */ 6343149Seric register char **avp; /* address vector pointer */ 6353149Seric register char **rvp; /* rewrite vector pointer */ 6368058Seric register struct match *mlp; /* cur ptr into mlist */ 6378058Seric register struct rewrite *rwr; /* pointer to current rewrite rule */ 63858866Seric int ruleno; /* current rule number */ 63959084Seric int rstat = EX_OK; /* return status */ 64064740Seric int loopcount; 64156678Seric struct match mlist[MAXMATCH]; /* stores match on LHS */ 6423149Seric char *npvp[MAXATOM+1]; /* temporary space for rebuild */ 6433149Seric 64467262Seric if (OpMode == MD_TEST || tTd(21, 1)) 6453149Seric { 6468959Seric printf("rewrite: ruleset %2d input:", ruleset); 64756678Seric printav(pvp); 6483149Seric } 64956678Seric if (ruleset < 0 || ruleset >= MAXRWSETS) 65056326Seric { 65158151Seric syserr("554 rewrite: illegal ruleset number %d", ruleset); 65259084Seric return EX_CONFIG; 65356326Seric } 65465136Seric if (reclevel++ > MAXRULERECURSION) 65565071Seric { 65665071Seric syserr("rewrite: infinite recursion, ruleset %d", ruleset); 65765071Seric return EX_CONFIG; 65865071Seric } 65956678Seric if (pvp == NULL) 66059084Seric return EX_USAGE; 66156326Seric 6623149Seric /* 66356678Seric ** Run through the list of rewrite rules, applying 66456678Seric ** any that match. 6653149Seric */ 6663149Seric 66758866Seric ruleno = 1; 66864740Seric loopcount = 0; 6694070Seric for (rwr = RewriteRules[ruleset]; rwr != NULL; ) 6703149Seric { 6717675Seric if (tTd(21, 12)) 672297Seric { 6738069Seric printf("-----trying rule:"); 67456678Seric printav(rwr->r_lhs); 6753149Seric } 6763149Seric 6773149Seric /* try to match on this rule */ 6784468Seric mlp = mlist; 6798058Seric rvp = rwr->r_lhs; 6808058Seric avp = pvp; 68158866Seric if (++loopcount > 100) 6823149Seric { 68358866Seric syserr("554 Infinite loop in ruleset %d, rule %d", 68458866Seric ruleset, ruleno); 68558866Seric if (tTd(21, 1)) 68652637Seric { 68756678Seric printf("workspace: "); 68856678Seric printav(pvp); 68952637Seric } 69058866Seric break; 69158866Seric } 69258866Seric 69358866Seric while ((ap = *avp) != NULL || *rvp != NULL) 69458866Seric { 6953149Seric rp = *rvp; 6968058Seric if (tTd(21, 35)) 6978058Seric { 69858825Seric printf("ADVANCE rp="); 69957531Seric xputs(rp); 70057532Seric printf(", ap="); 7018058Seric xputs(ap); 7028069Seric printf("\n"); 7038058Seric } 70456678Seric if (rp == NULL) 70556326Seric { 7063149Seric /* end-of-pattern before end-of-address */ 7078058Seric goto backup; 70856678Seric } 70958173Seric if (ap == NULL && (*rp & 0377) != MATCHZANY && 71058827Seric (*rp & 0377) != MATCHZERO) 71156326Seric { 71258825Seric /* end-of-input with patterns left */ 71358825Seric goto backup; 714297Seric } 71556326Seric 71658050Seric switch (*rp & 0377) 7178058Seric { 71858814Seric char buf[MAXLINE]; 71956326Seric 72056678Seric case MATCHCLASS: 72158825Seric /* match any phrase in a class */ 72258825Seric mlp->pattern = rvp; 72358814Seric mlp->first = avp; 72458814Seric extendclass: 72558825Seric ap = *avp; 72658825Seric if (ap == NULL) 72758814Seric goto backup; 72858814Seric mlp->last = avp++; 72958814Seric cataddr(mlp->first, mlp->last, buf, sizeof buf, '\0'); 73068199Seric if (!wordinclass(buf, rp[1])) 73156326Seric { 73258825Seric if (tTd(21, 36)) 73358825Seric { 73458825Seric printf("EXTEND rp="); 73558825Seric xputs(rp); 73658825Seric printf(", ap="); 73758825Seric xputs(ap); 73858825Seric printf("\n"); 73958825Seric } 74058825Seric goto extendclass; 74156326Seric } 74258825Seric if (tTd(21, 36)) 74358825Seric printf("CLMATCH\n"); 74458814Seric mlp++; 74558814Seric break; 7464060Seric 74758825Seric case MATCHNCLASS: 74858825Seric /* match any token not in a class */ 74968199Seric if (wordinclass(ap, rp[1])) 75058825Seric goto backup; 75158825Seric 75258825Seric /* fall through */ 75358825Seric 75456678Seric case MATCHONE: 75556678Seric case MATCHANY: 75656678Seric /* match exactly one token */ 75758825Seric mlp->pattern = rvp; 75856678Seric mlp->first = avp; 75956678Seric mlp->last = avp++; 7608058Seric mlp++; 76156678Seric break; 7628058Seric 76356678Seric case MATCHZANY: 76456678Seric /* match zero or more tokens */ 76558825Seric mlp->pattern = rvp; 76656678Seric mlp->first = avp; 76756678Seric mlp->last = avp - 1; 76856678Seric mlp++; 76956678Seric break; 77056326Seric 77158827Seric case MATCHZERO: 77258173Seric /* match zero tokens */ 77358173Seric break; 77458173Seric 77559027Seric case MACRODEXPAND: 77659027Seric /* 77759027Seric ** Match against run-time macro. 77859027Seric ** This algorithm is broken for the 77959027Seric ** general case (no recursive macros, 78059027Seric ** improper tokenization) but should 78159027Seric ** work for the usual cases. 78259027Seric */ 78359027Seric 78459027Seric ap = macvalue(rp[1], e); 78559027Seric mlp->first = avp; 78659027Seric if (tTd(21, 2)) 78759027Seric printf("rewrite: LHS $&%c => \"%s\"\n", 78859027Seric rp[1], 78959027Seric ap == NULL ? "(NULL)" : ap); 79059027Seric 79159027Seric if (ap == NULL) 79259027Seric break; 79360502Seric while (*ap != '\0') 79459027Seric { 79559027Seric if (*avp == NULL || 79659027Seric strncasecmp(ap, *avp, strlen(*avp)) != 0) 79759027Seric { 79859027Seric /* no match */ 79959027Seric avp = mlp->first; 80059027Seric goto backup; 80159027Seric } 80259027Seric ap += strlen(*avp++); 80359027Seric } 80459027Seric 80559027Seric /* match */ 80659027Seric break; 80759027Seric 80856678Seric default: 80956678Seric /* must have exact match */ 81056678Seric if (strcasecmp(rp, ap)) 8118058Seric goto backup; 8124468Seric avp++; 81356678Seric break; 8143149Seric } 8153149Seric 81656678Seric /* successful match on this token */ 8173149Seric rvp++; 8183149Seric continue; 8193149Seric 82058825Seric backup: 82156678Seric /* match failed -- back up */ 82258825Seric while (--mlp >= mlist) 8233149Seric { 82458825Seric rvp = mlp->pattern; 82556678Seric rp = *rvp; 82658825Seric avp = mlp->last + 1; 82758825Seric ap = *avp; 82858825Seric 82958825Seric if (tTd(21, 36)) 83058825Seric { 83158825Seric printf("BACKUP rp="); 83258825Seric xputs(rp); 83358825Seric printf(", ap="); 83458825Seric xputs(ap); 83558825Seric printf("\n"); 83658825Seric } 83758825Seric 83858825Seric if (ap == NULL) 83958825Seric { 84058825Seric /* run off the end -- back up again */ 84158825Seric continue; 84258825Seric } 84358050Seric if ((*rp & 0377) == MATCHANY || 84458050Seric (*rp & 0377) == MATCHZANY) 8454468Seric { 84656678Seric /* extend binding and continue */ 84758825Seric mlp->last = avp++; 84856678Seric rvp++; 84958825Seric mlp++; 85056678Seric break; 8514468Seric } 85258825Seric if ((*rp & 0377) == MATCHCLASS) 85356678Seric { 85458814Seric /* extend binding and try again */ 85563397Seric mlp->last = avp; 85658814Seric goto extendclass; 85758814Seric } 8583149Seric } 8593149Seric 86058825Seric if (mlp < mlist) 86156678Seric { 86256678Seric /* total failure to match */ 86356326Seric break; 8643149Seric } 865297Seric } 8663149Seric 8673149Seric /* 86856678Seric ** See if we successfully matched 8693149Seric */ 8703149Seric 87158827Seric if (mlp < mlist || *rvp != NULL) 8723149Seric { 8739374Seric if (tTd(21, 10)) 8749374Seric printf("----- rule fails\n"); 8759374Seric rwr = rwr->r_next; 87658866Seric ruleno++; 87764740Seric loopcount = 0; 8789374Seric continue; 8799374Seric } 8803149Seric 8819374Seric rvp = rwr->r_rhs; 8829374Seric if (tTd(21, 12)) 8839374Seric { 8849374Seric printf("-----rule matches:"); 88556678Seric printav(rvp); 8869374Seric } 8879374Seric 8889374Seric rp = *rvp; 88958050Seric if ((*rp & 0377) == CANONUSER) 8909374Seric { 8919374Seric rvp++; 8929374Seric rwr = rwr->r_next; 89358866Seric ruleno++; 89464740Seric loopcount = 0; 8959374Seric } 89658050Seric else if ((*rp & 0377) == CANONHOST) 8979374Seric { 8989374Seric rvp++; 8999374Seric rwr = NULL; 9009374Seric } 90158050Seric else if ((*rp & 0377) == CANONNET) 9029374Seric rwr = NULL; 9039374Seric 9049374Seric /* substitute */ 9059374Seric for (avp = npvp; *rvp != NULL; rvp++) 9069374Seric { 9079374Seric register struct match *m; 9089374Seric register char **pp; 9099374Seric 9108058Seric rp = *rvp; 91158050Seric if ((*rp & 0377) == MATCHREPL) 9128058Seric { 91316914Seric /* substitute from LHS */ 91416914Seric m = &mlist[rp[1] - '1']; 91556678Seric if (m < mlist || m >= mlp) 9169374Seric { 91758151Seric syserr("554 rewrite: ruleset %d: replacement $%c out of bounds", 91856326Seric ruleset, rp[1]); 91959084Seric return EX_CONFIG; 9209374Seric } 92116914Seric if (tTd(21, 15)) 92216914Seric { 92316914Seric printf("$%c:", rp[1]); 92416914Seric pp = m->first; 92556678Seric while (pp <= m->last) 92616914Seric { 92716914Seric printf(" %x=\"", *pp); 92816914Seric (void) fflush(stdout); 92916914Seric printf("%s\"", *pp++); 93016914Seric } 93116914Seric printf("\n"); 93216914Seric } 9339374Seric pp = m->first; 93456678Seric while (pp <= m->last) 9353149Seric { 93616914Seric if (avp >= &npvp[MAXATOM]) 93756678Seric { 93858151Seric syserr("554 rewrite: expansion too long"); 93959084Seric return EX_DATAERR; 94056678Seric } 94116914Seric *avp++ = *pp++; 9423149Seric } 9433149Seric } 94416914Seric else 9458226Seric { 94616914Seric /* vanilla replacement */ 9479374Seric if (avp >= &npvp[MAXATOM]) 94816889Seric { 94956678Seric toolong: 95058151Seric syserr("554 rewrite: expansion too long"); 95159084Seric return EX_DATAERR; 95216889Seric } 95359027Seric if ((*rp & 0377) != MACRODEXPAND) 95459027Seric *avp++ = rp; 95559027Seric else 95659027Seric { 95759027Seric *avp = macvalue(rp[1], e); 95859027Seric if (tTd(21, 2)) 95959027Seric printf("rewrite: RHS $&%c => \"%s\"\n", 96059027Seric rp[1], 96159027Seric *avp == NULL ? "(NULL)" : *avp); 96259027Seric if (*avp != NULL) 96359027Seric avp++; 96459027Seric } 9658226Seric } 9669374Seric } 9679374Seric *avp++ = NULL; 96816914Seric 96916914Seric /* 97056678Seric ** Check for any hostname/keyword lookups. 97116914Seric */ 97216914Seric 97316914Seric for (rvp = npvp; *rvp != NULL; rvp++) 97416914Seric { 97556678Seric char **hbrvp; 97616914Seric char **xpvp; 97716914Seric int trsize; 97856678Seric char *replac; 97956678Seric int endtoken; 98056678Seric STAB *map; 98156678Seric char *mapname; 98256678Seric char **key_rvp; 98356678Seric char **arg_rvp; 98456678Seric char **default_rvp; 98556678Seric char buf[MAXNAME + 1]; 98616914Seric char *pvpb1[MAXATOM + 1]; 98756823Seric char *argvect[10]; 98817174Seric char pvpbuf[PSBUFSIZE]; 98964404Seric char *nullpvp[1]; 99016914Seric 99158050Seric if ((**rvp & 0377) != HOSTBEGIN && 99258050Seric (**rvp & 0377) != LOOKUPBEGIN) 99316914Seric continue; 99416914Seric 99516914Seric /* 99656678Seric ** Got a hostname/keyword lookup. 99716914Seric ** 99816914Seric ** This could be optimized fairly easily. 99916914Seric */ 100016914Seric 100116914Seric hbrvp = rvp; 100258050Seric if ((**rvp & 0377) == HOSTBEGIN) 100356327Seric { 100456678Seric endtoken = HOSTEND; 100556678Seric mapname = "host"; 100656327Seric } 100756326Seric else 100856327Seric { 100956678Seric endtoken = LOOKUPEND; 101056678Seric mapname = *++rvp; 101156327Seric } 101256678Seric map = stab(mapname, ST_MAP, ST_FIND); 101356678Seric if (map == NULL) 101458151Seric syserr("554 rewrite: map %s not found", mapname); 101556678Seric 101656678Seric /* extract the match part */ 101756678Seric key_rvp = ++rvp; 101856823Seric default_rvp = NULL; 101956823Seric arg_rvp = argvect; 102056823Seric xpvp = NULL; 102156823Seric replac = pvpbuf; 102258050Seric while (*rvp != NULL && (**rvp & 0377) != endtoken) 102353654Seric { 102458050Seric int nodetype = **rvp & 0377; 102556823Seric 102656823Seric if (nodetype != CANONHOST && nodetype != CANONUSER) 102756678Seric { 102856823Seric rvp++; 102956823Seric continue; 103056823Seric } 103156823Seric 103256823Seric *rvp++ = NULL; 103356823Seric 103456823Seric if (xpvp != NULL) 103556823Seric { 103658814Seric cataddr(xpvp, NULL, replac, 103758082Seric &pvpbuf[sizeof pvpbuf] - replac, 103858082Seric '\0'); 103956823Seric *++arg_rvp = replac; 104056823Seric replac += strlen(replac) + 1; 104156823Seric xpvp = NULL; 104256823Seric } 104356823Seric switch (nodetype) 104456823Seric { 104556678Seric case CANONHOST: 104656823Seric xpvp = rvp; 104756678Seric break; 104856678Seric 104956678Seric case CANONUSER: 105056678Seric default_rvp = rvp; 105156678Seric break; 105256678Seric } 105353654Seric } 105416914Seric if (*rvp != NULL) 105516914Seric *rvp++ = NULL; 105656823Seric if (xpvp != NULL) 105756823Seric { 105858814Seric cataddr(xpvp, NULL, replac, 105958082Seric &pvpbuf[sizeof pvpbuf] - replac, 106058082Seric '\0'); 106156823Seric *++arg_rvp = replac; 106256823Seric } 106356823Seric *++arg_rvp = NULL; 106416914Seric 106516914Seric /* save the remainder of the input string */ 106616914Seric trsize = (int) (avp - rvp + 1) * sizeof *rvp; 106716914Seric bcopy((char *) rvp, (char *) pvpb1, trsize); 106816914Seric 106956678Seric /* look it up */ 107058814Seric cataddr(key_rvp, NULL, buf, sizeof buf, '\0'); 107156823Seric argvect[0] = buf; 107260538Seric if (map != NULL && bitset(MF_OPEN, map->s_map.map_mflags)) 107356836Seric { 107459084Seric auto int stat = EX_OK; 107556836Seric 107660215Seric /* XXX should try to auto-open the map here */ 107760215Seric 107858796Seric if (tTd(60, 1)) 107958796Seric printf("map_lookup(%s, %s) => ", 108058796Seric mapname, buf); 108156836Seric replac = (*map->s_map.map_class->map_lookup)(&map->s_map, 108260089Seric buf, argvect, &stat); 108358796Seric if (tTd(60, 1)) 108459084Seric printf("%s (%d)\n", 108559084Seric replac ? replac : "NOT FOUND", 108659084Seric stat); 108759084Seric 108859084Seric /* should recover if stat == EX_TEMPFAIL */ 108959084Seric if (stat == EX_TEMPFAIL) 109059084Seric rstat = stat; 109156836Seric } 109253654Seric else 109356678Seric replac = NULL; 109456678Seric 109556678Seric /* if no replacement, use default */ 109656823Seric if (replac == NULL && default_rvp != NULL) 109756823Seric { 109860089Seric /* create the default */ 109960089Seric cataddr(default_rvp, NULL, buf, sizeof buf, '\0'); 110056823Seric replac = buf; 110156823Seric } 110256823Seric 110356678Seric if (replac == NULL) 110451317Seric { 110556823Seric xpvp = key_rvp; 110653654Seric } 110764404Seric else if (*replac == '\0') 110864404Seric { 110964404Seric /* null replacement */ 111064404Seric nullpvp[0] = NULL; 111164404Seric xpvp = nullpvp; 111264404Seric } 111356678Seric else 111453654Seric { 111556678Seric /* scan the new replacement */ 111665066Seric xpvp = prescan(replac, '\0', pvpbuf, 111765066Seric sizeof pvpbuf, NULL); 111853654Seric if (xpvp == NULL) 111951317Seric { 112058403Seric /* prescan already printed error */ 112159084Seric return EX_DATAERR; 112256678Seric } 112351317Seric } 112451317Seric 112516914Seric /* append it to the token list */ 112656678Seric for (avp = hbrvp; *xpvp != NULL; xpvp++) 112756678Seric { 112817174Seric *avp++ = newstr(*xpvp); 112916920Seric if (avp >= &npvp[MAXATOM]) 113016914Seric goto toolong; 113117174Seric } 113216914Seric 113316914Seric /* restore the old trailing information */ 113456678Seric for (xpvp = pvpb1; (*avp++ = *xpvp++) != NULL; ) 113516920Seric if (avp >= &npvp[MAXATOM]) 113616914Seric goto toolong; 113717174Seric 113856678Seric break; 113916914Seric } 114016914Seric 114116914Seric /* 114216914Seric ** Check for subroutine calls. 114316914Seric */ 114416914Seric 114558050Seric if (*npvp != NULL && (**npvp & 0377) == CALLSUBR) 114656678Seric { 114759084Seric int stat; 114859084Seric 114965379Seric if (npvp[1] == NULL) 115065379Seric { 115165379Seric syserr("parseaddr: NULL subroutine call in ruleset %d, rule %d", 115265379Seric ruleset, ruleno); 115365379Seric *pvp = NULL; 115465379Seric } 115565379Seric else 115665379Seric { 115768385Seric int ruleset; 115868385Seric STAB *s; 115968385Seric 116065379Seric bcopy((char *) &npvp[2], (char *) pvp, 116165379Seric (int) (avp - npvp - 2) * sizeof *avp); 116265379Seric if (tTd(21, 3)) 116365379Seric printf("-----callsubr %s\n", npvp[1]); 116468385Seric s = stab(npvp[1], ST_RULESET, ST_FIND); 116568385Seric if (s == NULL) 116668385Seric ruleset = atoi(npvp[1]); 116768385Seric else 116868385Seric ruleset = s->s_ruleset; 116968385Seric stat = rewrite(pvp, ruleset, reclevel, e); 117065379Seric if (rstat == EX_OK || stat == EX_TEMPFAIL) 117165379Seric rstat = stat; 117265379Seric if (*pvp != NULL && (**pvp & 0377) == CANONNET) 117363581Seric rwr = NULL; 117465379Seric } 117556678Seric } 117656678Seric else 117756678Seric { 117817348Seric bcopy((char *) npvp, (char *) pvp, 117916900Seric (int) (avp - npvp) * sizeof *avp); 118056678Seric } 11819374Seric if (tTd(21, 4)) 11829374Seric { 11839374Seric printf("rewritten as:"); 118456678Seric printav(pvp); 11859374Seric } 1186297Seric } 11878069Seric 118867262Seric if (OpMode == MD_TEST || tTd(21, 1)) 11898069Seric { 11908959Seric printf("rewrite: ruleset %2d returns:", ruleset); 119156678Seric printav(pvp); 11928069Seric } 119359084Seric 119459084Seric return rstat; 11953149Seric } 11963149Seric /* 11973149Seric ** BUILDADDR -- build address from token vector. 11983149Seric ** 11993149Seric ** Parameters: 12003149Seric ** tv -- token vector. 12013149Seric ** a -- pointer to address descriptor to fill. 12023149Seric ** If NULL, one will be allocated. 120364284Seric ** flags -- info regarding whether this is a sender or 120464284Seric ** a recipient. 120558966Seric ** e -- the current envelope. 12063149Seric ** 12073149Seric ** Returns: 12084279Seric ** NULL if there was an error. 12094279Seric ** 'a' otherwise. 12103149Seric ** 12113149Seric ** Side Effects: 12123149Seric ** fills in 'a' 12133149Seric */ 12143149Seric 121557249Seric struct errcodes 121657249Seric { 121757249Seric char *ec_name; /* name of error code */ 121857249Seric int ec_code; /* numeric code */ 121957249Seric } ErrorCodes[] = 122057249Seric { 122157249Seric "usage", EX_USAGE, 122257249Seric "nouser", EX_NOUSER, 122357249Seric "nohost", EX_NOHOST, 122457249Seric "unavailable", EX_UNAVAILABLE, 122557249Seric "software", EX_SOFTWARE, 122657249Seric "tempfail", EX_TEMPFAIL, 122757249Seric "protocol", EX_PROTOCOL, 122857249Seric #ifdef EX_CONFIG 122957249Seric "config", EX_CONFIG, 123057249Seric #endif 123157249Seric NULL, EX_UNAVAILABLE, 123257249Seric }; 123357249Seric 123456678Seric ADDRESS * 123564284Seric buildaddr(tv, a, flags, e) 12363149Seric register char **tv; 12373149Seric register ADDRESS *a; 123864284Seric int flags; 123958966Seric register ENVELOPE *e; 12403149Seric { 12413149Seric struct mailer **mp; 12423149Seric register struct mailer *m; 124358008Seric char *bp; 124458008Seric int spaceleft; 124564306Seric static MAILER errormailer; 124664306Seric static char *errorargv[] = { "ERROR", NULL }; 124757402Seric static char buf[MAXNAME]; 12483149Seric 124964791Seric if (tTd(24, 5)) 125064791Seric { 125167693Seric printf("buildaddr, flags=%x, tv=", flags); 125264791Seric printav(tv); 125364791Seric } 125464791Seric 12553149Seric if (a == NULL) 12563149Seric a = (ADDRESS *) xalloc(sizeof *a); 125716889Seric bzero((char *) a, sizeof *a); 12583149Seric 125967880Seric /* set up default error return flags */ 126067963Seric a->q_flags |= QPINGONFAILURE|QPINGONDELAY; 126167880Seric 12623149Seric /* figure out what net/mailer to use */ 126364306Seric if (*tv == NULL || (**tv & 0377) != CANONNET) 12644279Seric { 126558151Seric syserr("554 buildaddr: no net"); 126664306Seric badaddr: 126764306Seric a->q_flags |= QBADADDR; 126864306Seric a->q_mailer = &errormailer; 126964306Seric if (errormailer.m_name == NULL) 127064306Seric { 127164306Seric /* initialize the bogus mailer */ 127264306Seric errormailer.m_name = "*error*"; 127364306Seric errormailer.m_mailer = "ERROR"; 127464306Seric errormailer.m_argv = errorargv; 127564306Seric } 127664306Seric return a; 12774279Seric } 12783149Seric tv++; 127958680Seric if (strcasecmp(*tv, "error") == 0) 12804279Seric { 128158050Seric if ((**++tv & 0377) == CANONHOST) 128210183Seric { 128357249Seric register struct errcodes *ep; 128457249Seric 128558050Seric if (isascii(**++tv) && isdigit(**tv)) 128657249Seric { 128757249Seric setstat(atoi(*tv)); 128857249Seric } 128957249Seric else 129057249Seric { 129157249Seric for (ep = ErrorCodes; ep->ec_name != NULL; ep++) 129257249Seric if (strcasecmp(ep->ec_name, *tv) == 0) 129357249Seric break; 129457249Seric setstat(ep->ec_code); 129557249Seric } 129610183Seric tv++; 129710183Seric } 129864928Seric else 129964928Seric setstat(EX_UNAVAILABLE); 130058050Seric if ((**tv & 0377) != CANONUSER) 130158151Seric syserr("554 buildaddr: error: no user"); 130258814Seric cataddr(++tv, NULL, buf, sizeof buf, ' '); 130358082Seric stripquotes(buf); 130464659Seric if (isascii(buf[0]) && isdigit(buf[0]) && 130564659Seric isascii(buf[1]) && isdigit(buf[1]) && 130664659Seric isascii(buf[2]) && isdigit(buf[2]) && 130764659Seric buf[3] == ' ') 130864659Seric { 130964659Seric char fmt[10]; 131064659Seric 131164659Seric strncpy(fmt, buf, 3); 131264659Seric strcpy(&fmt[3], " %s"); 131364659Seric usrerr(fmt, buf + 4); 131467786Seric 131567786Seric /* 131667786Seric ** If this is a 4xx code and we aren't running 131767786Seric ** SMTP on our input, bounce this message; 131867786Seric ** otherwise it disappears without a trace. 131967786Seric */ 132067786Seric 132167786Seric if (fmt[0] == '4' && OpMode != MD_SMTP && 132267786Seric OpMode != MD_DAEMON) 132367786Seric { 132467786Seric e->e_flags |= EF_FATALERRS; 132567786Seric } 132664659Seric } 132764659Seric else 132864659Seric { 132966039Seric usrerr("553 %s", buf); 133064659Seric } 133164306Seric goto badaddr; 13324279Seric } 133357402Seric 13344598Seric for (mp = Mailer; (m = *mp++) != NULL; ) 13353149Seric { 133658680Seric if (strcasecmp(m->m_name, *tv) == 0) 13373149Seric break; 13383149Seric } 13393149Seric if (m == NULL) 13404279Seric { 134158151Seric syserr("554 buildaddr: unknown mailer %s", *tv); 134264306Seric goto badaddr; 13434279Seric } 13444598Seric a->q_mailer = m; 13453149Seric 13463149Seric /* figure out what host (if any) */ 134756678Seric tv++; 134858509Seric if ((**tv & 0377) == CANONHOST) 13493149Seric { 135058008Seric bp = buf; 135158008Seric spaceleft = sizeof buf - 1; 135258050Seric while (*++tv != NULL && (**tv & 0377) != CANONUSER) 135358008Seric { 135458008Seric int i = strlen(*tv); 135558008Seric 135658008Seric if (i > spaceleft) 135758008Seric { 135858008Seric /* out of space for this address */ 135958008Seric if (spaceleft >= 0) 136058151Seric syserr("554 buildaddr: host too long (%.40s...)", 136158008Seric buf); 136258008Seric i = spaceleft; 136358008Seric spaceleft = 0; 136458008Seric } 136558008Seric if (i <= 0) 136658008Seric continue; 136758008Seric bcopy(*tv, bp, i); 136858008Seric bp += i; 136958008Seric spaceleft -= i; 137058008Seric } 137158010Seric *bp = '\0'; 13725704Seric a->q_host = newstr(buf); 13733149Seric } 137457249Seric else 137558509Seric { 137658509Seric if (!bitnset(M_LOCALMAILER, m->m_flags)) 137758509Seric { 137858509Seric syserr("554 buildaddr: no host"); 137964306Seric goto badaddr; 138058509Seric } 138157249Seric a->q_host = NULL; 138258509Seric } 13833149Seric 13843149Seric /* figure out the user */ 138558050Seric if (*tv == NULL || (**tv & 0377) != CANONUSER) 13864279Seric { 138758151Seric syserr("554 buildaddr: no user"); 138864306Seric goto badaddr; 13894279Seric } 139057402Seric tv++; 139151317Seric 139268098Seric if (bitnset(M_CHECKUDB, m->m_flags) && *tv != NULL && 139368098Seric strcmp(*tv, "@") == 0) 139468098Seric { 139568098Seric tv++; 139668098Seric a->q_flags |= QNOTREMOTE; 139768098Seric } 139868098Seric 139957402Seric /* do special mapping for local mailer */ 140067472Seric if (*tv != NULL) 140157402Seric { 140257454Seric register char *p = *tv; 140357454Seric 140457454Seric if (*p == '"') 140557454Seric p++; 140667472Seric if (*p == '|' && bitnset(M_CHECKPROG, m->m_flags)) 140757402Seric a->q_mailer = m = ProgMailer; 140867472Seric else if (*p == '/' && bitnset(M_CHECKFILE, m->m_flags)) 140957402Seric a->q_mailer = m = FileMailer; 141067472Seric else if (*p == ':' && bitnset(M_CHECKINCLUDE, m->m_flags)) 141157402Seric { 141257402Seric /* may be :include: */ 141358814Seric cataddr(tv, NULL, buf, sizeof buf, '\0'); 141458008Seric stripquotes(buf); 141558008Seric if (strncasecmp(buf, ":include:", 9) == 0) 141658008Seric { 141758008Seric /* if :include:, don't need further rewriting */ 141857402Seric a->q_mailer = m = InclMailer; 141958008Seric a->q_user = &buf[9]; 142058008Seric return (a); 142158008Seric } 142257402Seric } 142357402Seric } 142457402Seric 142564284Seric /* rewrite according recipient mailer rewriting rules */ 142664284Seric define('h', a->q_host, e); 142764284Seric if (!bitset(RF_SENDERADDR|RF_HEADERADDR, flags)) 142864284Seric { 142964284Seric /* sender addresses done later */ 143065071Seric (void) rewrite(tv, 2, 0, e); 143164284Seric if (m->m_re_rwset > 0) 143265071Seric (void) rewrite(tv, m->m_re_rwset, 0, e); 143364284Seric } 143465071Seric (void) rewrite(tv, 4, 0, e); 143519040Seric 143619040Seric /* save the result for the command line/RCPT argument */ 143758814Seric cataddr(tv, NULL, buf, sizeof buf, '\0'); 14383149Seric a->q_user = buf; 14393149Seric 144058670Seric /* 144158670Seric ** Do mapping to lower case as requested by mailer 144258670Seric */ 144358670Seric 144458670Seric if (a->q_host != NULL && !bitnset(M_HST_UPPER, m->m_flags)) 144558670Seric makelower(a->q_host); 144658670Seric if (!bitnset(M_USR_UPPER, m->m_flags)) 144758670Seric makelower(a->q_user); 144858670Seric 14493149Seric return (a); 14503149Seric } 14513188Seric /* 14524228Seric ** CATADDR -- concatenate pieces of addresses (putting in <LWSP> subs) 14534228Seric ** 14544228Seric ** Parameters: 14554228Seric ** pvp -- parameter vector to rebuild. 145658814Seric ** evp -- last parameter to include. Can be NULL to 145758814Seric ** use entire pvp. 14584228Seric ** buf -- buffer to build the string into. 14594228Seric ** sz -- size of buf. 146058082Seric ** spacesub -- the space separator character; if null, 146158082Seric ** use SpaceSub. 14624228Seric ** 14634228Seric ** Returns: 14644228Seric ** none. 14654228Seric ** 14664228Seric ** Side Effects: 14674228Seric ** Destroys buf. 14684228Seric */ 14694228Seric 147058814Seric cataddr(pvp, evp, buf, sz, spacesub) 14714228Seric char **pvp; 147258814Seric char **evp; 14734228Seric char *buf; 14744228Seric register int sz; 147558082Seric char spacesub; 14764228Seric { 14774228Seric bool oatomtok = FALSE; 147856678Seric bool natomtok = FALSE; 14794228Seric register int i; 14804228Seric register char *p; 14814228Seric 148258082Seric if (spacesub == '\0') 148358082Seric spacesub = SpaceSub; 148458082Seric 14858423Seric if (pvp == NULL) 14868423Seric { 148723109Seric (void) strcpy(buf, ""); 14888423Seric return; 14898423Seric } 14904228Seric p = buf; 149111156Seric sz -= 2; 14924228Seric while (*pvp != NULL && (i = strlen(*pvp)) < sz) 14934228Seric { 14948078Seric natomtok = (toktype(**pvp) == ATM); 14954228Seric if (oatomtok && natomtok) 149658082Seric *p++ = spacesub; 14974228Seric (void) strcpy(p, *pvp); 14984228Seric oatomtok = natomtok; 14994228Seric p += i; 150011156Seric sz -= i + 1; 150158814Seric if (pvp++ == evp) 150258814Seric break; 15034228Seric } 15044228Seric *p = '\0'; 15054228Seric } 15064228Seric /* 15073188Seric ** SAMEADDR -- Determine if two addresses are the same 15083188Seric ** 15093188Seric ** This is not just a straight comparison -- if the mailer doesn't 15103188Seric ** care about the host we just ignore it, etc. 15113188Seric ** 15123188Seric ** Parameters: 15133188Seric ** a, b -- pointers to the internal forms to compare. 15143188Seric ** 15153188Seric ** Returns: 15163188Seric ** TRUE -- they represent the same mailbox. 15173188Seric ** FALSE -- they don't. 15183188Seric ** 15193188Seric ** Side Effects: 15203188Seric ** none. 15213188Seric */ 15223188Seric 15233188Seric bool 15249374Seric sameaddr(a, b) 15253188Seric register ADDRESS *a; 15263188Seric register ADDRESS *b; 15273188Seric { 152865093Seric register ADDRESS *ca, *cb; 152965093Seric 15303188Seric /* if they don't have the same mailer, forget it */ 15313188Seric if (a->q_mailer != b->q_mailer) 15323188Seric return (FALSE); 15333188Seric 15343188Seric /* if the user isn't the same, we can drop out */ 153556678Seric if (strcmp(a->q_user, b->q_user) != 0) 15363188Seric return (FALSE); 15373188Seric 153865093Seric /* if we have good uids for both but they differ, these are different */ 153965379Seric if (a->q_mailer == ProgMailer) 154065379Seric { 154165379Seric ca = getctladdr(a); 154265379Seric cb = getctladdr(b); 154365379Seric if (ca != NULL && cb != NULL && 154465379Seric bitset(QGOODUID, ca->q_flags & cb->q_flags) && 154565379Seric ca->q_uid != cb->q_uid) 154665379Seric return (FALSE); 154765379Seric } 154858438Seric 154958509Seric /* otherwise compare hosts (but be careful for NULL ptrs) */ 155058509Seric if (a->q_host == b->q_host) 155158509Seric { 155258509Seric /* probably both null pointers */ 15533188Seric return (TRUE); 155458509Seric } 15553188Seric if (a->q_host == NULL || b->q_host == NULL) 155658509Seric { 155758509Seric /* only one is a null pointer */ 15583188Seric return (FALSE); 155958509Seric } 156056678Seric if (strcmp(a->q_host, b->q_host) != 0) 15613188Seric return (FALSE); 15623188Seric 15633188Seric return (TRUE); 15643188Seric } 15653234Seric /* 15663234Seric ** PRINTADDR -- print address (for debugging) 15673234Seric ** 15683234Seric ** Parameters: 15693234Seric ** a -- the address to print 15703234Seric ** follow -- follow the q_next chain. 15713234Seric ** 15723234Seric ** Returns: 15733234Seric ** none. 15743234Seric ** 15753234Seric ** Side Effects: 15763234Seric ** none. 15773234Seric */ 15783234Seric 157967994Seric struct qflags 158067994Seric { 158167994Seric char *qf_name; 158267994Seric u_long qf_bit; 158367994Seric }; 158467994Seric 158567994Seric struct qflags AddressFlags[] = 158667994Seric { 158767994Seric "QDONTSEND", QDONTSEND, 158867994Seric "QBADADDR", QBADADDR, 158967994Seric "QGOODUID", QGOODUID, 159067994Seric "QPRIMARY", QPRIMARY, 159167994Seric "QQUEUEUP", QQUEUEUP, 159267994Seric "QSENT", QSENT, 159367994Seric "QNOTREMOTE", QNOTREMOTE, 159467994Seric "QSELFREF", QSELFREF, 159567994Seric "QVERIFIED", QVERIFIED, 159667994Seric "QREPORT", QREPORT, 159767994Seric "QBOGUSSHELL", QBOGUSSHELL, 159867994Seric "QUNSAFEADDR", QUNSAFEADDR, 159967994Seric "QPINGONSUCCESS", QPINGONSUCCESS, 160067994Seric "QPINGONFAILURE", QPINGONFAILURE, 160167994Seric "QPINGONDELAY", QPINGONDELAY, 160267994Seric "QHAS_RET_PARAM", QHAS_RET_PARAM, 160367994Seric "QRET_HDRS", QRET_HDRS, 160467994Seric "QRELAYED", QRELAYED, 160567994Seric NULL 160667994Seric }; 160767994Seric 16083234Seric printaddr(a, follow) 16093234Seric register ADDRESS *a; 16103234Seric bool follow; 16113234Seric { 161257731Seric register MAILER *m; 161357731Seric MAILER pseudomailer; 161467994Seric register struct qflags *qfp; 161567994Seric bool firstone; 16165001Seric 161767994Seric if (a == NULL) 161867994Seric { 161967994Seric printf("[NULL]\n"); 162067994Seric return; 162167994Seric } 162267994Seric 16233234Seric while (a != NULL) 16243234Seric { 16254443Seric printf("%x=", a); 16264085Seric (void) fflush(stdout); 162757731Seric 162857731Seric /* find the mailer -- carefully */ 162957731Seric m = a->q_mailer; 163057731Seric if (m == NULL) 163157731Seric { 163257731Seric m = &pseudomailer; 163357731Seric m->m_mno = -1; 163457731Seric m->m_name = "NULL"; 163557731Seric } 163657731Seric 163758680Seric printf("%s:\n\tmailer %d (%s), host `%s', user `%s', ruser `%s'\n", 163857731Seric a->q_paddr, m->m_mno, m->m_name, 163967172Seric a->q_host == NULL ? "<null>" : a->q_host, a->q_user, 164067172Seric a->q_ruser == NULL ? "<null>" : a->q_ruser); 164167994Seric printf("\tnext=%x, alias %x, uid %d, gid %d\n", 164267994Seric a->q_next, a->q_alias, a->q_uid, a->q_gid); 164367994Seric printf("\tflags=%lx<", a->q_flags); 164467994Seric firstone = TRUE; 164567994Seric for (qfp = AddressFlags; qfp->qf_name != NULL; qfp++) 164667994Seric { 164767994Seric if (!bitset(qfp->qf_bit, a->q_flags)) 164867994Seric continue; 164967994Seric if (!firstone) 165067994Seric printf(","); 165167994Seric firstone = FALSE; 165267994Seric printf("%s", qfp->qf_name); 165367994Seric } 165467994Seric printf(">\n"); 165559269Seric printf("\towner=%s, home=\"%s\", fullname=\"%s\"\n", 165659269Seric a->q_owner == NULL ? "(none)" : a->q_owner, 165763756Seric a->q_home == NULL ? "(none)" : a->q_home, 165863756Seric a->q_fullname == NULL ? "(none)" : a->q_fullname); 165968228Seric printf("\torcpt=\"%s\", statmta=%s, rstatus=%s\n", 166067987Seric a->q_orcpt == NULL ? "(none)" : a->q_orcpt, 166167987Seric a->q_statmta == NULL ? "(none)" : a->q_statmta, 166267990Seric a->q_rstatus == NULL ? "(none)" : a->q_rstatus); 16634996Seric 16643234Seric if (!follow) 16653234Seric return; 16664996Seric a = a->q_next; 16673234Seric } 16683234Seric } 166967939Seric /* 167067939Seric ** EMPTYADDR -- return TRUE if this address is empty (``<>'') 167167939Seric ** 167267939Seric ** Parameters: 167367939Seric ** a -- pointer to the address 167467939Seric ** 167567939Seric ** Returns: 167667939Seric ** TRUE -- if this address is "empty" (i.e., no one should 167767939Seric ** ever generate replies to it. 167867939Seric ** FALSE -- if it is a "regular" (read: replyable) address. 167967939Seric */ 16804317Seric 168167939Seric bool 168267939Seric emptyaddr(a) 168367939Seric register ADDRESS *a; 168467939Seric { 168567939Seric return strcmp(a->q_paddr, "<>") == 0 || strcmp(a->q_user, "<>") == 0; 168667939Seric } 16877682Seric /* 16887682Seric ** REMOTENAME -- return the name relative to the current mailer 16897682Seric ** 16907682Seric ** Parameters: 16917682Seric ** name -- the name to translate. 16928069Seric ** m -- the mailer that we want to do rewriting relative 16938069Seric ** to. 169459163Seric ** flags -- fine tune operations. 169559163Seric ** pstat -- pointer to status word. 169658020Seric ** e -- the current envelope. 16977682Seric ** 16987682Seric ** Returns: 16997682Seric ** the text string representing this address relative to 17007682Seric ** the receiving mailer. 17017682Seric ** 17027682Seric ** Side Effects: 17037682Seric ** none. 17047682Seric ** 17057682Seric ** Warnings: 17067682Seric ** The text string returned is tucked away locally; 17077682Seric ** copy it if you intend to save it. 17087682Seric */ 17097682Seric 17107682Seric char * 171159163Seric remotename(name, m, flags, pstat, e) 17127682Seric char *name; 171356678Seric struct mailer *m; 171459163Seric int flags; 171559163Seric int *pstat; 171656678Seric register ENVELOPE *e; 17177682Seric { 17188069Seric register char **pvp; 17198069Seric char *fancy; 172056678Seric char *oldg = macvalue('g', e); 172158020Seric int rwset; 17227682Seric static char buf[MAXNAME]; 17237682Seric char lbuf[MAXNAME]; 172416914Seric char pvpbuf[PSBUFSIZE]; 172556678Seric extern char *crackaddr(); 17267682Seric 17277755Seric if (tTd(12, 1)) 17287755Seric printf("remotename(%s)\n", name); 17297755Seric 173010177Seric /* don't do anything if we are tagging it as special */ 173159163Seric if (bitset(RF_SENDERADDR, flags)) 173259163Seric rwset = bitset(RF_HEADERADDR, flags) ? m->m_sh_rwset 173359163Seric : m->m_se_rwset; 173458020Seric else 173559163Seric rwset = bitset(RF_HEADERADDR, flags) ? m->m_rh_rwset 173659163Seric : m->m_re_rwset; 173758020Seric if (rwset < 0) 173810177Seric return (name); 173910177Seric 17407682Seric /* 17418181Seric ** Do a heuristic crack of this name to extract any comment info. 17428181Seric ** This will leave the name as a comment and a $g macro. 17437889Seric */ 17447889Seric 174559163Seric if (bitset(RF_CANONICAL, flags) || bitnset(M_NOCOMMENT, m->m_flags)) 174658050Seric fancy = "\201g"; 174710310Seric else 174810310Seric fancy = crackaddr(name); 17497889Seric 17508181Seric /* 17518181Seric ** Turn the name into canonical form. 17528181Seric ** Normally this will be RFC 822 style, i.e., "user@domain". 17538181Seric ** If this only resolves to "user", and the "C" flag is 17548181Seric ** specified in the sending mailer, then the sender's 17558181Seric ** domain will be appended. 17568181Seric */ 17578181Seric 175865066Seric pvp = prescan(name, '\0', pvpbuf, sizeof pvpbuf, NULL); 17597889Seric if (pvp == NULL) 17607889Seric return (name); 176165071Seric if (rewrite(pvp, 3, 0, e) == EX_TEMPFAIL) 176259163Seric *pstat = EX_TEMPFAIL; 176359163Seric if (bitset(RF_ADDDOMAIN, flags) && e->e_fromdomain != NULL) 17648181Seric { 17658181Seric /* append from domain to this address */ 17668181Seric register char **pxp = pvp; 17678181Seric 17689594Seric /* see if there is an "@domain" in the current name */ 17698181Seric while (*pxp != NULL && strcmp(*pxp, "@") != 0) 17708181Seric pxp++; 17718181Seric if (*pxp == NULL) 17728181Seric { 17739594Seric /* no.... append the "@domain" from the sender */ 177456678Seric register char **qxq = e->e_fromdomain; 17758181Seric 17769594Seric while ((*pxp++ = *qxq++) != NULL) 17779594Seric continue; 177865071Seric if (rewrite(pvp, 3, 0, e) == EX_TEMPFAIL) 177959163Seric *pstat = EX_TEMPFAIL; 17808181Seric } 17818181Seric } 17828181Seric 17838181Seric /* 17848959Seric ** Do more specific rewriting. 178556678Seric ** Rewrite using ruleset 1 or 2 depending on whether this is 178656678Seric ** a sender address or not. 17878181Seric ** Then run it through any receiving-mailer-specific rulesets. 17888181Seric */ 17898181Seric 179059163Seric if (bitset(RF_SENDERADDR, flags)) 179159541Seric { 179265071Seric if (rewrite(pvp, 1, 0, e) == EX_TEMPFAIL) 179359163Seric *pstat = EX_TEMPFAIL; 179459541Seric } 17958069Seric else 179659541Seric { 179765071Seric if (rewrite(pvp, 2, 0, e) == EX_TEMPFAIL) 179859163Seric *pstat = EX_TEMPFAIL; 179959541Seric } 180058020Seric if (rwset > 0) 180159541Seric { 180265071Seric if (rewrite(pvp, rwset, 0, e) == EX_TEMPFAIL) 180359163Seric *pstat = EX_TEMPFAIL; 180459541Seric } 18057682Seric 18068181Seric /* 18078959Seric ** Do any final sanitation the address may require. 18088959Seric ** This will normally be used to turn internal forms 18098959Seric ** (e.g., user@host.LOCAL) into external form. This 18108959Seric ** may be used as a default to the above rules. 18118959Seric */ 18128959Seric 181365071Seric if (rewrite(pvp, 4, 0, e) == EX_TEMPFAIL) 181459163Seric *pstat = EX_TEMPFAIL; 18158959Seric 18168959Seric /* 18178181Seric ** Now restore the comment information we had at the beginning. 18188181Seric */ 18198181Seric 182058825Seric cataddr(pvp, NULL, lbuf, sizeof lbuf, '\0'); 182156678Seric define('g', lbuf, e); 182265494Seric 182365494Seric /* need to make sure route-addrs have <angle brackets> */ 182465494Seric if (bitset(RF_CANONICAL, flags) && lbuf[0] == '@') 182565494Seric expand("<\201g>", buf, &buf[sizeof buf - 1], e); 182665494Seric else 182765494Seric expand(fancy, buf, &buf[sizeof buf - 1], e); 182865494Seric 182956678Seric define('g', oldg, e); 18307682Seric 18317682Seric if (tTd(12, 1)) 18327755Seric printf("remotename => `%s'\n", buf); 18337682Seric return (buf); 18347682Seric } 183551317Seric /* 183656678Seric ** MAPLOCALUSER -- run local username through ruleset 5 for final redirection 183751317Seric ** 183851317Seric ** Parameters: 183956678Seric ** a -- the address to map (but just the user name part). 184056678Seric ** sendq -- the sendq in which to install any replacement 184156678Seric ** addresses. 184267982Seric ** aliaslevel -- the alias nesting depth. 184367982Seric ** e -- the envelope. 184451317Seric ** 184551317Seric ** Returns: 184651317Seric ** none. 184751317Seric */ 184851317Seric 184967982Seric maplocaluser(a, sendq, aliaslevel, e) 185056678Seric register ADDRESS *a; 185156678Seric ADDRESS **sendq; 185267982Seric int aliaslevel; 185356678Seric ENVELOPE *e; 185451317Seric { 185556678Seric register char **pvp; 185656678Seric register ADDRESS *a1 = NULL; 185758333Seric auto char *delimptr; 185856678Seric char pvpbuf[PSBUFSIZE]; 185951317Seric 186056678Seric if (tTd(29, 1)) 186156678Seric { 186256678Seric printf("maplocaluser: "); 186356678Seric printaddr(a, FALSE); 186456678Seric } 186565066Seric pvp = prescan(a->q_user, '\0', pvpbuf, sizeof pvpbuf, &delimptr); 186656678Seric if (pvp == NULL) 186756678Seric return; 186851317Seric 186965071Seric (void) rewrite(pvp, 5, 0, e); 187058050Seric if (pvp[0] == NULL || (pvp[0][0] & 0377) != CANONNET) 187156678Seric return; 187251317Seric 187356678Seric /* if non-null, mailer destination specified -- has it changed? */ 187464284Seric a1 = buildaddr(pvp, NULL, 0, e); 187556678Seric if (a1 == NULL || sameaddr(a, a1)) 187656678Seric return; 187751317Seric 187856678Seric /* mark old address as dead; insert new address */ 187956678Seric a->q_flags |= QDONTSEND; 188057731Seric if (tTd(29, 5)) 188157731Seric { 188257731Seric printf("maplocaluser: QDONTSEND "); 188357731Seric printaddr(a, FALSE); 188457731Seric } 188556678Seric a1->q_alias = a; 188664348Seric allocaddr(a1, RF_COPYALL, NULL); 188767982Seric (void) recipient(a1, sendq, aliaslevel, e); 188851317Seric } 188958802Seric /* 189058802Seric ** DEQUOTE_INIT -- initialize dequote map 189158802Seric ** 189258802Seric ** This is a no-op. 189358802Seric ** 189458802Seric ** Parameters: 189558802Seric ** map -- the internal map structure. 189658802Seric ** args -- arguments. 189758802Seric ** 189858802Seric ** Returns: 189958802Seric ** TRUE. 190058802Seric */ 190158802Seric 190258802Seric bool 190360219Seric dequote_init(map, args) 190458802Seric MAP *map; 190558802Seric char *args; 190658802Seric { 190758805Seric register char *p = args; 190858805Seric 190958805Seric for (;;) 191058805Seric { 191158805Seric while (isascii(*p) && isspace(*p)) 191258805Seric p++; 191358805Seric if (*p != '-') 191458805Seric break; 191558805Seric switch (*++p) 191658805Seric { 191758805Seric case 'a': 191858805Seric map->map_app = ++p; 191958805Seric break; 192067824Seric 192167824Seric case 's': 192267824Seric map->map_coldelim = *++p; 192367824Seric break; 192458805Seric } 192558805Seric while (*p != '\0' && !(isascii(*p) && isspace(*p))) 192658805Seric p++; 192758805Seric if (*p != '\0') 192858805Seric *p = '\0'; 192958805Seric } 193058805Seric if (map->map_app != NULL) 193158805Seric map->map_app = newstr(map->map_app); 193258805Seric 193358802Seric return TRUE; 193458802Seric } 193558802Seric /* 193658802Seric ** DEQUOTE_MAP -- unquote an address 193758802Seric ** 193858802Seric ** Parameters: 193958802Seric ** map -- the internal map structure (ignored). 194060089Seric ** name -- the name to dequote. 194158802Seric ** av -- arguments (ignored). 194259084Seric ** statp -- pointer to status out-parameter. 194358802Seric ** 194458802Seric ** Returns: 194558802Seric ** NULL -- if there were no quotes, or if the resulting 194658802Seric ** unquoted buffer would not be acceptable to prescan. 194758802Seric ** else -- The dequoted buffer. 194858802Seric */ 194958802Seric 195058802Seric char * 195160089Seric dequote_map(map, name, av, statp) 195258802Seric MAP *map; 195360089Seric char *name; 195458802Seric char **av; 195559084Seric int *statp; 195658802Seric { 195758802Seric register char *p; 195858802Seric register char *q; 195958802Seric register char c; 196067824Seric int anglecnt = 0; 196167824Seric int cmntcnt = 0; 196267824Seric int quotecnt = 0; 196367824Seric int spacecnt = 0; 196467824Seric bool quotemode = FALSE; 196567824Seric bool bslashmode = FALSE; 196667824Seric char spacesub = map->map_coldelim; 196758802Seric 196860089Seric for (p = q = name; (c = *p++) != '\0'; ) 196958802Seric { 197058802Seric if (bslashmode) 197158802Seric { 197258802Seric bslashmode = FALSE; 197358802Seric *q++ = c; 197458802Seric continue; 197558802Seric } 197658802Seric 197767824Seric if (c == ' ' && spacesub != '\0') 197867824Seric c = spacesub; 197967764Seric 198058802Seric switch (c) 198158802Seric { 198258802Seric case '\\': 198358802Seric bslashmode = TRUE; 198458802Seric break; 198558802Seric 198658802Seric case '(': 198758802Seric cmntcnt++; 198858802Seric break; 198958802Seric 199058802Seric case ')': 199158802Seric if (cmntcnt-- <= 0) 199258802Seric return NULL; 199358802Seric break; 199459089Seric 199559089Seric case ' ': 199659089Seric spacecnt++; 199759089Seric break; 199858802Seric } 199958802Seric 200058802Seric if (cmntcnt > 0) 200158802Seric { 200258802Seric *q++ = c; 200358802Seric continue; 200458802Seric } 200558802Seric 200658802Seric switch (c) 200758802Seric { 200858802Seric case '"': 200958802Seric quotemode = !quotemode; 201058802Seric quotecnt++; 201158802Seric continue; 201258802Seric 201358802Seric case '<': 201458802Seric anglecnt++; 201558802Seric break; 201658802Seric 201758802Seric case '>': 201858802Seric if (anglecnt-- <= 0) 201958802Seric return NULL; 202058802Seric break; 202158802Seric } 202258802Seric *q++ = c; 202358802Seric } 202458802Seric 202558802Seric if (anglecnt != 0 || cmntcnt != 0 || bslashmode || 202659089Seric quotemode || quotecnt <= 0 || spacecnt != 0) 202758802Seric return NULL; 202858802Seric *q++ = '\0'; 202960089Seric return name; 203058802Seric } 2031