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*68098Seric static char sccsid[] = "@(#)parseaddr.c 8.47 (Berkeley) 12/28/94"; 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; 15567998Seric a->q_status = "466"; 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 { 20964764Seric if (savedelim != '\0' && delimptr != NULL) 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; 349297Seric char 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 { 71856678Seric register STAB *s; 71958814Seric char buf[MAXLINE]; 72056326Seric 72156678Seric case MATCHCLASS: 72258825Seric /* match any phrase in a class */ 72358825Seric mlp->pattern = rvp; 72458814Seric mlp->first = avp; 72558814Seric extendclass: 72658825Seric ap = *avp; 72758825Seric if (ap == NULL) 72858814Seric goto backup; 72958814Seric mlp->last = avp++; 73058814Seric cataddr(mlp->first, mlp->last, buf, sizeof buf, '\0'); 73158814Seric s = stab(buf, ST_CLASS, ST_FIND); 73256678Seric if (s == NULL || !bitnset(rp[1], s->s_class)) 73356326Seric { 73458825Seric if (tTd(21, 36)) 73558825Seric { 73658825Seric printf("EXTEND rp="); 73758825Seric xputs(rp); 73858825Seric printf(", ap="); 73958825Seric xputs(ap); 74058825Seric printf("\n"); 74158825Seric } 74258825Seric goto extendclass; 74356326Seric } 74458825Seric if (tTd(21, 36)) 74558825Seric printf("CLMATCH\n"); 74658814Seric mlp++; 74758814Seric break; 7484060Seric 74958825Seric case MATCHNCLASS: 75058825Seric /* match any token not in a class */ 75158825Seric s = stab(ap, ST_CLASS, ST_FIND); 75258825Seric if (s != NULL && bitnset(rp[1], s->s_class)) 75358825Seric goto backup; 75458825Seric 75558825Seric /* fall through */ 75658825Seric 75756678Seric case MATCHONE: 75856678Seric case MATCHANY: 75956678Seric /* match exactly one token */ 76058825Seric mlp->pattern = rvp; 76156678Seric mlp->first = avp; 76256678Seric mlp->last = avp++; 7638058Seric mlp++; 76456678Seric break; 7658058Seric 76656678Seric case MATCHZANY: 76756678Seric /* match zero or more tokens */ 76858825Seric mlp->pattern = rvp; 76956678Seric mlp->first = avp; 77056678Seric mlp->last = avp - 1; 77156678Seric mlp++; 77256678Seric break; 77356326Seric 77458827Seric case MATCHZERO: 77558173Seric /* match zero tokens */ 77658173Seric break; 77758173Seric 77859027Seric case MACRODEXPAND: 77959027Seric /* 78059027Seric ** Match against run-time macro. 78159027Seric ** This algorithm is broken for the 78259027Seric ** general case (no recursive macros, 78359027Seric ** improper tokenization) but should 78459027Seric ** work for the usual cases. 78559027Seric */ 78659027Seric 78759027Seric ap = macvalue(rp[1], e); 78859027Seric mlp->first = avp; 78959027Seric if (tTd(21, 2)) 79059027Seric printf("rewrite: LHS $&%c => \"%s\"\n", 79159027Seric rp[1], 79259027Seric ap == NULL ? "(NULL)" : ap); 79359027Seric 79459027Seric if (ap == NULL) 79559027Seric break; 79660502Seric while (*ap != '\0') 79759027Seric { 79859027Seric if (*avp == NULL || 79959027Seric strncasecmp(ap, *avp, strlen(*avp)) != 0) 80059027Seric { 80159027Seric /* no match */ 80259027Seric avp = mlp->first; 80359027Seric goto backup; 80459027Seric } 80559027Seric ap += strlen(*avp++); 80659027Seric } 80759027Seric 80859027Seric /* match */ 80959027Seric break; 81059027Seric 81156678Seric default: 81256678Seric /* must have exact match */ 81356678Seric if (strcasecmp(rp, ap)) 8148058Seric goto backup; 8154468Seric avp++; 81656678Seric break; 8173149Seric } 8183149Seric 81956678Seric /* successful match on this token */ 8203149Seric rvp++; 8213149Seric continue; 8223149Seric 82358825Seric backup: 82456678Seric /* match failed -- back up */ 82558825Seric while (--mlp >= mlist) 8263149Seric { 82758825Seric rvp = mlp->pattern; 82856678Seric rp = *rvp; 82958825Seric avp = mlp->last + 1; 83058825Seric ap = *avp; 83158825Seric 83258825Seric if (tTd(21, 36)) 83358825Seric { 83458825Seric printf("BACKUP rp="); 83558825Seric xputs(rp); 83658825Seric printf(", ap="); 83758825Seric xputs(ap); 83858825Seric printf("\n"); 83958825Seric } 84058825Seric 84158825Seric if (ap == NULL) 84258825Seric { 84358825Seric /* run off the end -- back up again */ 84458825Seric continue; 84558825Seric } 84658050Seric if ((*rp & 0377) == MATCHANY || 84758050Seric (*rp & 0377) == MATCHZANY) 8484468Seric { 84956678Seric /* extend binding and continue */ 85058825Seric mlp->last = avp++; 85156678Seric rvp++; 85258825Seric mlp++; 85356678Seric break; 8544468Seric } 85558825Seric if ((*rp & 0377) == MATCHCLASS) 85656678Seric { 85758814Seric /* extend binding and try again */ 85863397Seric mlp->last = avp; 85958814Seric goto extendclass; 86058814Seric } 8613149Seric } 8623149Seric 86358825Seric if (mlp < mlist) 86456678Seric { 86556678Seric /* total failure to match */ 86656326Seric break; 8673149Seric } 868297Seric } 8693149Seric 8703149Seric /* 87156678Seric ** See if we successfully matched 8723149Seric */ 8733149Seric 87458827Seric if (mlp < mlist || *rvp != NULL) 8753149Seric { 8769374Seric if (tTd(21, 10)) 8779374Seric printf("----- rule fails\n"); 8789374Seric rwr = rwr->r_next; 87958866Seric ruleno++; 88064740Seric loopcount = 0; 8819374Seric continue; 8829374Seric } 8833149Seric 8849374Seric rvp = rwr->r_rhs; 8859374Seric if (tTd(21, 12)) 8869374Seric { 8879374Seric printf("-----rule matches:"); 88856678Seric printav(rvp); 8899374Seric } 8909374Seric 8919374Seric rp = *rvp; 89258050Seric if ((*rp & 0377) == CANONUSER) 8939374Seric { 8949374Seric rvp++; 8959374Seric rwr = rwr->r_next; 89658866Seric ruleno++; 89764740Seric loopcount = 0; 8989374Seric } 89958050Seric else if ((*rp & 0377) == CANONHOST) 9009374Seric { 9019374Seric rvp++; 9029374Seric rwr = NULL; 9039374Seric } 90458050Seric else if ((*rp & 0377) == CANONNET) 9059374Seric rwr = NULL; 9069374Seric 9079374Seric /* substitute */ 9089374Seric for (avp = npvp; *rvp != NULL; rvp++) 9099374Seric { 9109374Seric register struct match *m; 9119374Seric register char **pp; 9129374Seric 9138058Seric rp = *rvp; 91458050Seric if ((*rp & 0377) == MATCHREPL) 9158058Seric { 91616914Seric /* substitute from LHS */ 91716914Seric m = &mlist[rp[1] - '1']; 91856678Seric if (m < mlist || m >= mlp) 9199374Seric { 92058151Seric syserr("554 rewrite: ruleset %d: replacement $%c out of bounds", 92156326Seric ruleset, rp[1]); 92259084Seric return EX_CONFIG; 9239374Seric } 92416914Seric if (tTd(21, 15)) 92516914Seric { 92616914Seric printf("$%c:", rp[1]); 92716914Seric pp = m->first; 92856678Seric while (pp <= m->last) 92916914Seric { 93016914Seric printf(" %x=\"", *pp); 93116914Seric (void) fflush(stdout); 93216914Seric printf("%s\"", *pp++); 93316914Seric } 93416914Seric printf("\n"); 93516914Seric } 9369374Seric pp = m->first; 93756678Seric while (pp <= m->last) 9383149Seric { 93916914Seric if (avp >= &npvp[MAXATOM]) 94056678Seric { 94158151Seric syserr("554 rewrite: expansion too long"); 94259084Seric return EX_DATAERR; 94356678Seric } 94416914Seric *avp++ = *pp++; 9453149Seric } 9463149Seric } 94716914Seric else 9488226Seric { 94916914Seric /* vanilla replacement */ 9509374Seric if (avp >= &npvp[MAXATOM]) 95116889Seric { 95256678Seric toolong: 95358151Seric syserr("554 rewrite: expansion too long"); 95459084Seric return EX_DATAERR; 95516889Seric } 95659027Seric if ((*rp & 0377) != MACRODEXPAND) 95759027Seric *avp++ = rp; 95859027Seric else 95959027Seric { 96059027Seric *avp = macvalue(rp[1], e); 96159027Seric if (tTd(21, 2)) 96259027Seric printf("rewrite: RHS $&%c => \"%s\"\n", 96359027Seric rp[1], 96459027Seric *avp == NULL ? "(NULL)" : *avp); 96559027Seric if (*avp != NULL) 96659027Seric avp++; 96759027Seric } 9688226Seric } 9699374Seric } 9709374Seric *avp++ = NULL; 97116914Seric 97216914Seric /* 97356678Seric ** Check for any hostname/keyword lookups. 97416914Seric */ 97516914Seric 97616914Seric for (rvp = npvp; *rvp != NULL; rvp++) 97716914Seric { 97856678Seric char **hbrvp; 97916914Seric char **xpvp; 98016914Seric int trsize; 98156678Seric char *replac; 98256678Seric int endtoken; 98356678Seric STAB *map; 98456678Seric char *mapname; 98556678Seric char **key_rvp; 98656678Seric char **arg_rvp; 98756678Seric char **default_rvp; 98856678Seric char buf[MAXNAME + 1]; 98916914Seric char *pvpb1[MAXATOM + 1]; 99056823Seric char *argvect[10]; 99117174Seric char pvpbuf[PSBUFSIZE]; 99264404Seric char *nullpvp[1]; 99316914Seric 99458050Seric if ((**rvp & 0377) != HOSTBEGIN && 99558050Seric (**rvp & 0377) != LOOKUPBEGIN) 99616914Seric continue; 99716914Seric 99816914Seric /* 99956678Seric ** Got a hostname/keyword lookup. 100016914Seric ** 100116914Seric ** This could be optimized fairly easily. 100216914Seric */ 100316914Seric 100416914Seric hbrvp = rvp; 100558050Seric if ((**rvp & 0377) == HOSTBEGIN) 100656327Seric { 100756678Seric endtoken = HOSTEND; 100856678Seric mapname = "host"; 100956327Seric } 101056326Seric else 101156327Seric { 101256678Seric endtoken = LOOKUPEND; 101356678Seric mapname = *++rvp; 101456327Seric } 101556678Seric map = stab(mapname, ST_MAP, ST_FIND); 101656678Seric if (map == NULL) 101758151Seric syserr("554 rewrite: map %s not found", mapname); 101856678Seric 101956678Seric /* extract the match part */ 102056678Seric key_rvp = ++rvp; 102156823Seric default_rvp = NULL; 102256823Seric arg_rvp = argvect; 102356823Seric xpvp = NULL; 102456823Seric replac = pvpbuf; 102558050Seric while (*rvp != NULL && (**rvp & 0377) != endtoken) 102653654Seric { 102758050Seric int nodetype = **rvp & 0377; 102856823Seric 102956823Seric if (nodetype != CANONHOST && nodetype != CANONUSER) 103056678Seric { 103156823Seric rvp++; 103256823Seric continue; 103356823Seric } 103456823Seric 103556823Seric *rvp++ = NULL; 103656823Seric 103756823Seric if (xpvp != NULL) 103856823Seric { 103958814Seric cataddr(xpvp, NULL, replac, 104058082Seric &pvpbuf[sizeof pvpbuf] - replac, 104158082Seric '\0'); 104256823Seric *++arg_rvp = replac; 104356823Seric replac += strlen(replac) + 1; 104456823Seric xpvp = NULL; 104556823Seric } 104656823Seric switch (nodetype) 104756823Seric { 104856678Seric case CANONHOST: 104956823Seric xpvp = rvp; 105056678Seric break; 105156678Seric 105256678Seric case CANONUSER: 105356678Seric default_rvp = rvp; 105456678Seric break; 105556678Seric } 105653654Seric } 105716914Seric if (*rvp != NULL) 105816914Seric *rvp++ = NULL; 105956823Seric if (xpvp != NULL) 106056823Seric { 106158814Seric cataddr(xpvp, NULL, replac, 106258082Seric &pvpbuf[sizeof pvpbuf] - replac, 106358082Seric '\0'); 106456823Seric *++arg_rvp = replac; 106556823Seric } 106656823Seric *++arg_rvp = NULL; 106716914Seric 106816914Seric /* save the remainder of the input string */ 106916914Seric trsize = (int) (avp - rvp + 1) * sizeof *rvp; 107016914Seric bcopy((char *) rvp, (char *) pvpb1, trsize); 107116914Seric 107256678Seric /* look it up */ 107358814Seric cataddr(key_rvp, NULL, buf, sizeof buf, '\0'); 107456823Seric argvect[0] = buf; 107560538Seric if (map != NULL && bitset(MF_OPEN, map->s_map.map_mflags)) 107656836Seric { 107759084Seric auto int stat = EX_OK; 107856836Seric 107960215Seric /* XXX should try to auto-open the map here */ 108060215Seric 108158796Seric if (tTd(60, 1)) 108258796Seric printf("map_lookup(%s, %s) => ", 108358796Seric mapname, buf); 108456836Seric replac = (*map->s_map.map_class->map_lookup)(&map->s_map, 108560089Seric buf, argvect, &stat); 108658796Seric if (tTd(60, 1)) 108759084Seric printf("%s (%d)\n", 108859084Seric replac ? replac : "NOT FOUND", 108959084Seric stat); 109059084Seric 109159084Seric /* should recover if stat == EX_TEMPFAIL */ 109259084Seric if (stat == EX_TEMPFAIL) 109359084Seric rstat = stat; 109456836Seric } 109553654Seric else 109656678Seric replac = NULL; 109756678Seric 109856678Seric /* if no replacement, use default */ 109956823Seric if (replac == NULL && default_rvp != NULL) 110056823Seric { 110160089Seric /* create the default */ 110260089Seric cataddr(default_rvp, NULL, buf, sizeof buf, '\0'); 110356823Seric replac = buf; 110456823Seric } 110556823Seric 110656678Seric if (replac == NULL) 110751317Seric { 110856823Seric xpvp = key_rvp; 110953654Seric } 111064404Seric else if (*replac == '\0') 111164404Seric { 111264404Seric /* null replacement */ 111364404Seric nullpvp[0] = NULL; 111464404Seric xpvp = nullpvp; 111564404Seric } 111656678Seric else 111753654Seric { 111856678Seric /* scan the new replacement */ 111965066Seric xpvp = prescan(replac, '\0', pvpbuf, 112065066Seric sizeof pvpbuf, NULL); 112153654Seric if (xpvp == NULL) 112251317Seric { 112358403Seric /* prescan already printed error */ 112459084Seric return EX_DATAERR; 112556678Seric } 112651317Seric } 112751317Seric 112816914Seric /* append it to the token list */ 112956678Seric for (avp = hbrvp; *xpvp != NULL; xpvp++) 113056678Seric { 113117174Seric *avp++ = newstr(*xpvp); 113216920Seric if (avp >= &npvp[MAXATOM]) 113316914Seric goto toolong; 113417174Seric } 113516914Seric 113616914Seric /* restore the old trailing information */ 113756678Seric for (xpvp = pvpb1; (*avp++ = *xpvp++) != NULL; ) 113816920Seric if (avp >= &npvp[MAXATOM]) 113916914Seric goto toolong; 114017174Seric 114156678Seric break; 114216914Seric } 114316914Seric 114416914Seric /* 114516914Seric ** Check for subroutine calls. 114616914Seric */ 114716914Seric 114858050Seric if (*npvp != NULL && (**npvp & 0377) == CALLSUBR) 114956678Seric { 115059084Seric int stat; 115159084Seric 115265379Seric if (npvp[1] == NULL) 115365379Seric { 115465379Seric syserr("parseaddr: NULL subroutine call in ruleset %d, rule %d", 115565379Seric ruleset, ruleno); 115665379Seric *pvp = NULL; 115765379Seric } 115865379Seric else 115965379Seric { 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]); 116465379Seric stat = rewrite(pvp, atoi(npvp[1]), reclevel, e); 116565379Seric if (rstat == EX_OK || stat == EX_TEMPFAIL) 116665379Seric rstat = stat; 116765379Seric if (*pvp != NULL && (**pvp & 0377) == CANONNET) 116863581Seric rwr = NULL; 116965379Seric } 117056678Seric } 117156678Seric else 117256678Seric { 117317348Seric bcopy((char *) npvp, (char *) pvp, 117416900Seric (int) (avp - npvp) * sizeof *avp); 117556678Seric } 11769374Seric if (tTd(21, 4)) 11779374Seric { 11789374Seric printf("rewritten as:"); 117956678Seric printav(pvp); 11809374Seric } 1181297Seric } 11828069Seric 118367262Seric if (OpMode == MD_TEST || tTd(21, 1)) 11848069Seric { 11858959Seric printf("rewrite: ruleset %2d returns:", ruleset); 118656678Seric printav(pvp); 11878069Seric } 118859084Seric 118959084Seric return rstat; 11903149Seric } 11913149Seric /* 11923149Seric ** BUILDADDR -- build address from token vector. 11933149Seric ** 11943149Seric ** Parameters: 11953149Seric ** tv -- token vector. 11963149Seric ** a -- pointer to address descriptor to fill. 11973149Seric ** If NULL, one will be allocated. 119864284Seric ** flags -- info regarding whether this is a sender or 119964284Seric ** a recipient. 120058966Seric ** e -- the current envelope. 12013149Seric ** 12023149Seric ** Returns: 12034279Seric ** NULL if there was an error. 12044279Seric ** 'a' otherwise. 12053149Seric ** 12063149Seric ** Side Effects: 12073149Seric ** fills in 'a' 12083149Seric */ 12093149Seric 121057249Seric struct errcodes 121157249Seric { 121257249Seric char *ec_name; /* name of error code */ 121357249Seric int ec_code; /* numeric code */ 121457249Seric } ErrorCodes[] = 121557249Seric { 121657249Seric "usage", EX_USAGE, 121757249Seric "nouser", EX_NOUSER, 121857249Seric "nohost", EX_NOHOST, 121957249Seric "unavailable", EX_UNAVAILABLE, 122057249Seric "software", EX_SOFTWARE, 122157249Seric "tempfail", EX_TEMPFAIL, 122257249Seric "protocol", EX_PROTOCOL, 122357249Seric #ifdef EX_CONFIG 122457249Seric "config", EX_CONFIG, 122557249Seric #endif 122657249Seric NULL, EX_UNAVAILABLE, 122757249Seric }; 122857249Seric 122956678Seric ADDRESS * 123064284Seric buildaddr(tv, a, flags, e) 12313149Seric register char **tv; 12323149Seric register ADDRESS *a; 123364284Seric int flags; 123458966Seric register ENVELOPE *e; 12353149Seric { 12363149Seric struct mailer **mp; 12373149Seric register struct mailer *m; 123858008Seric char *bp; 123958008Seric int spaceleft; 124064306Seric static MAILER errormailer; 124164306Seric static char *errorargv[] = { "ERROR", NULL }; 124257402Seric static char buf[MAXNAME]; 12433149Seric 124464791Seric if (tTd(24, 5)) 124564791Seric { 124667693Seric printf("buildaddr, flags=%x, tv=", flags); 124764791Seric printav(tv); 124864791Seric } 124964791Seric 12503149Seric if (a == NULL) 12513149Seric a = (ADDRESS *) xalloc(sizeof *a); 125216889Seric bzero((char *) a, sizeof *a); 12533149Seric 125467880Seric /* set up default error return flags */ 125567963Seric a->q_flags |= QPINGONFAILURE|QPINGONDELAY; 125667880Seric 12573149Seric /* figure out what net/mailer to use */ 125864306Seric if (*tv == NULL || (**tv & 0377) != CANONNET) 12594279Seric { 126058151Seric syserr("554 buildaddr: no net"); 126164306Seric badaddr: 126264306Seric a->q_flags |= QBADADDR; 126364306Seric a->q_mailer = &errormailer; 126464306Seric if (errormailer.m_name == NULL) 126564306Seric { 126664306Seric /* initialize the bogus mailer */ 126764306Seric errormailer.m_name = "*error*"; 126864306Seric errormailer.m_mailer = "ERROR"; 126964306Seric errormailer.m_argv = errorargv; 127064306Seric } 127164306Seric return a; 12724279Seric } 12733149Seric tv++; 127458680Seric if (strcasecmp(*tv, "error") == 0) 12754279Seric { 127658050Seric if ((**++tv & 0377) == CANONHOST) 127710183Seric { 127857249Seric register struct errcodes *ep; 127957249Seric 128058050Seric if (isascii(**++tv) && isdigit(**tv)) 128157249Seric { 128257249Seric setstat(atoi(*tv)); 128357249Seric } 128457249Seric else 128557249Seric { 128657249Seric for (ep = ErrorCodes; ep->ec_name != NULL; ep++) 128757249Seric if (strcasecmp(ep->ec_name, *tv) == 0) 128857249Seric break; 128957249Seric setstat(ep->ec_code); 129057249Seric } 129110183Seric tv++; 129210183Seric } 129364928Seric else 129464928Seric setstat(EX_UNAVAILABLE); 129558050Seric if ((**tv & 0377) != CANONUSER) 129658151Seric syserr("554 buildaddr: error: no user"); 129758814Seric cataddr(++tv, NULL, buf, sizeof buf, ' '); 129858082Seric stripquotes(buf); 129964659Seric if (isascii(buf[0]) && isdigit(buf[0]) && 130064659Seric isascii(buf[1]) && isdigit(buf[1]) && 130164659Seric isascii(buf[2]) && isdigit(buf[2]) && 130264659Seric buf[3] == ' ') 130364659Seric { 130464659Seric char fmt[10]; 130564659Seric 130664659Seric strncpy(fmt, buf, 3); 130764659Seric strcpy(&fmt[3], " %s"); 130864659Seric usrerr(fmt, buf + 4); 130967786Seric 131067786Seric /* 131167786Seric ** If this is a 4xx code and we aren't running 131267786Seric ** SMTP on our input, bounce this message; 131367786Seric ** otherwise it disappears without a trace. 131467786Seric */ 131567786Seric 131667786Seric if (fmt[0] == '4' && OpMode != MD_SMTP && 131767786Seric OpMode != MD_DAEMON) 131867786Seric { 131967786Seric e->e_flags |= EF_FATALERRS; 132067786Seric } 132164659Seric } 132264659Seric else 132364659Seric { 132466039Seric usrerr("553 %s", buf); 132564659Seric } 132664306Seric goto badaddr; 13274279Seric } 132857402Seric 13294598Seric for (mp = Mailer; (m = *mp++) != NULL; ) 13303149Seric { 133158680Seric if (strcasecmp(m->m_name, *tv) == 0) 13323149Seric break; 13333149Seric } 13343149Seric if (m == NULL) 13354279Seric { 133658151Seric syserr("554 buildaddr: unknown mailer %s", *tv); 133764306Seric goto badaddr; 13384279Seric } 13394598Seric a->q_mailer = m; 13403149Seric 13413149Seric /* figure out what host (if any) */ 134256678Seric tv++; 134358509Seric if ((**tv & 0377) == CANONHOST) 13443149Seric { 134558008Seric bp = buf; 134658008Seric spaceleft = sizeof buf - 1; 134758050Seric while (*++tv != NULL && (**tv & 0377) != CANONUSER) 134858008Seric { 134958008Seric int i = strlen(*tv); 135058008Seric 135158008Seric if (i > spaceleft) 135258008Seric { 135358008Seric /* out of space for this address */ 135458008Seric if (spaceleft >= 0) 135558151Seric syserr("554 buildaddr: host too long (%.40s...)", 135658008Seric buf); 135758008Seric i = spaceleft; 135858008Seric spaceleft = 0; 135958008Seric } 136058008Seric if (i <= 0) 136158008Seric continue; 136258008Seric bcopy(*tv, bp, i); 136358008Seric bp += i; 136458008Seric spaceleft -= i; 136558008Seric } 136658010Seric *bp = '\0'; 13675704Seric a->q_host = newstr(buf); 13683149Seric } 136957249Seric else 137058509Seric { 137158509Seric if (!bitnset(M_LOCALMAILER, m->m_flags)) 137258509Seric { 137358509Seric syserr("554 buildaddr: no host"); 137464306Seric goto badaddr; 137558509Seric } 137657249Seric a->q_host = NULL; 137758509Seric } 13783149Seric 13793149Seric /* figure out the user */ 138058050Seric if (*tv == NULL || (**tv & 0377) != CANONUSER) 13814279Seric { 138258151Seric syserr("554 buildaddr: no user"); 138364306Seric goto badaddr; 13844279Seric } 138557402Seric tv++; 138651317Seric 1387*68098Seric if (bitnset(M_CHECKUDB, m->m_flags) && *tv != NULL && 1388*68098Seric strcmp(*tv, "@") == 0) 1389*68098Seric { 1390*68098Seric tv++; 1391*68098Seric a->q_flags |= QNOTREMOTE; 1392*68098Seric } 1393*68098Seric 139457402Seric /* do special mapping for local mailer */ 139567472Seric if (*tv != NULL) 139657402Seric { 139757454Seric register char *p = *tv; 139857454Seric 139957454Seric if (*p == '"') 140057454Seric p++; 140167472Seric if (*p == '|' && bitnset(M_CHECKPROG, m->m_flags)) 140257402Seric a->q_mailer = m = ProgMailer; 140367472Seric else if (*p == '/' && bitnset(M_CHECKFILE, m->m_flags)) 140457402Seric a->q_mailer = m = FileMailer; 140567472Seric else if (*p == ':' && bitnset(M_CHECKINCLUDE, m->m_flags)) 140657402Seric { 140757402Seric /* may be :include: */ 140858814Seric cataddr(tv, NULL, buf, sizeof buf, '\0'); 140958008Seric stripquotes(buf); 141058008Seric if (strncasecmp(buf, ":include:", 9) == 0) 141158008Seric { 141258008Seric /* if :include:, don't need further rewriting */ 141357402Seric a->q_mailer = m = InclMailer; 141458008Seric a->q_user = &buf[9]; 141558008Seric return (a); 141658008Seric } 141757402Seric } 141857402Seric } 141957402Seric 142064284Seric /* rewrite according recipient mailer rewriting rules */ 142164284Seric define('h', a->q_host, e); 142264284Seric if (!bitset(RF_SENDERADDR|RF_HEADERADDR, flags)) 142364284Seric { 142464284Seric /* sender addresses done later */ 142565071Seric (void) rewrite(tv, 2, 0, e); 142664284Seric if (m->m_re_rwset > 0) 142765071Seric (void) rewrite(tv, m->m_re_rwset, 0, e); 142864284Seric } 142965071Seric (void) rewrite(tv, 4, 0, e); 143019040Seric 143119040Seric /* save the result for the command line/RCPT argument */ 143258814Seric cataddr(tv, NULL, buf, sizeof buf, '\0'); 14333149Seric a->q_user = buf; 14343149Seric 143558670Seric /* 143658670Seric ** Do mapping to lower case as requested by mailer 143758670Seric */ 143858670Seric 143958670Seric if (a->q_host != NULL && !bitnset(M_HST_UPPER, m->m_flags)) 144058670Seric makelower(a->q_host); 144158670Seric if (!bitnset(M_USR_UPPER, m->m_flags)) 144258670Seric makelower(a->q_user); 144358670Seric 14443149Seric return (a); 14453149Seric } 14463188Seric /* 14474228Seric ** CATADDR -- concatenate pieces of addresses (putting in <LWSP> subs) 14484228Seric ** 14494228Seric ** Parameters: 14504228Seric ** pvp -- parameter vector to rebuild. 145158814Seric ** evp -- last parameter to include. Can be NULL to 145258814Seric ** use entire pvp. 14534228Seric ** buf -- buffer to build the string into. 14544228Seric ** sz -- size of buf. 145558082Seric ** spacesub -- the space separator character; if null, 145658082Seric ** use SpaceSub. 14574228Seric ** 14584228Seric ** Returns: 14594228Seric ** none. 14604228Seric ** 14614228Seric ** Side Effects: 14624228Seric ** Destroys buf. 14634228Seric */ 14644228Seric 146558814Seric cataddr(pvp, evp, buf, sz, spacesub) 14664228Seric char **pvp; 146758814Seric char **evp; 14684228Seric char *buf; 14694228Seric register int sz; 147058082Seric char spacesub; 14714228Seric { 14724228Seric bool oatomtok = FALSE; 147356678Seric bool natomtok = FALSE; 14744228Seric register int i; 14754228Seric register char *p; 14764228Seric 147758082Seric if (spacesub == '\0') 147858082Seric spacesub = SpaceSub; 147958082Seric 14808423Seric if (pvp == NULL) 14818423Seric { 148223109Seric (void) strcpy(buf, ""); 14838423Seric return; 14848423Seric } 14854228Seric p = buf; 148611156Seric sz -= 2; 14874228Seric while (*pvp != NULL && (i = strlen(*pvp)) < sz) 14884228Seric { 14898078Seric natomtok = (toktype(**pvp) == ATM); 14904228Seric if (oatomtok && natomtok) 149158082Seric *p++ = spacesub; 14924228Seric (void) strcpy(p, *pvp); 14934228Seric oatomtok = natomtok; 14944228Seric p += i; 149511156Seric sz -= i + 1; 149658814Seric if (pvp++ == evp) 149758814Seric break; 14984228Seric } 14994228Seric *p = '\0'; 15004228Seric } 15014228Seric /* 15023188Seric ** SAMEADDR -- Determine if two addresses are the same 15033188Seric ** 15043188Seric ** This is not just a straight comparison -- if the mailer doesn't 15053188Seric ** care about the host we just ignore it, etc. 15063188Seric ** 15073188Seric ** Parameters: 15083188Seric ** a, b -- pointers to the internal forms to compare. 15093188Seric ** 15103188Seric ** Returns: 15113188Seric ** TRUE -- they represent the same mailbox. 15123188Seric ** FALSE -- they don't. 15133188Seric ** 15143188Seric ** Side Effects: 15153188Seric ** none. 15163188Seric */ 15173188Seric 15183188Seric bool 15199374Seric sameaddr(a, b) 15203188Seric register ADDRESS *a; 15213188Seric register ADDRESS *b; 15223188Seric { 152365093Seric register ADDRESS *ca, *cb; 152465093Seric 15253188Seric /* if they don't have the same mailer, forget it */ 15263188Seric if (a->q_mailer != b->q_mailer) 15273188Seric return (FALSE); 15283188Seric 15293188Seric /* if the user isn't the same, we can drop out */ 153056678Seric if (strcmp(a->q_user, b->q_user) != 0) 15313188Seric return (FALSE); 15323188Seric 153365093Seric /* if we have good uids for both but they differ, these are different */ 153465379Seric if (a->q_mailer == ProgMailer) 153565379Seric { 153665379Seric ca = getctladdr(a); 153765379Seric cb = getctladdr(b); 153865379Seric if (ca != NULL && cb != NULL && 153965379Seric bitset(QGOODUID, ca->q_flags & cb->q_flags) && 154065379Seric ca->q_uid != cb->q_uid) 154165379Seric return (FALSE); 154265379Seric } 154358438Seric 154458509Seric /* otherwise compare hosts (but be careful for NULL ptrs) */ 154558509Seric if (a->q_host == b->q_host) 154658509Seric { 154758509Seric /* probably both null pointers */ 15483188Seric return (TRUE); 154958509Seric } 15503188Seric if (a->q_host == NULL || b->q_host == NULL) 155158509Seric { 155258509Seric /* only one is a null pointer */ 15533188Seric return (FALSE); 155458509Seric } 155556678Seric if (strcmp(a->q_host, b->q_host) != 0) 15563188Seric return (FALSE); 15573188Seric 15583188Seric return (TRUE); 15593188Seric } 15603234Seric /* 15613234Seric ** PRINTADDR -- print address (for debugging) 15623234Seric ** 15633234Seric ** Parameters: 15643234Seric ** a -- the address to print 15653234Seric ** follow -- follow the q_next chain. 15663234Seric ** 15673234Seric ** Returns: 15683234Seric ** none. 15693234Seric ** 15703234Seric ** Side Effects: 15713234Seric ** none. 15723234Seric */ 15733234Seric 157467994Seric struct qflags 157567994Seric { 157667994Seric char *qf_name; 157767994Seric u_long qf_bit; 157867994Seric }; 157967994Seric 158067994Seric struct qflags AddressFlags[] = 158167994Seric { 158267994Seric "QDONTSEND", QDONTSEND, 158367994Seric "QBADADDR", QBADADDR, 158467994Seric "QGOODUID", QGOODUID, 158567994Seric "QPRIMARY", QPRIMARY, 158667994Seric "QQUEUEUP", QQUEUEUP, 158767994Seric "QSENT", QSENT, 158867994Seric "QNOTREMOTE", QNOTREMOTE, 158967994Seric "QSELFREF", QSELFREF, 159067994Seric "QVERIFIED", QVERIFIED, 159167994Seric "QREPORT", QREPORT, 159267994Seric "QBOGUSSHELL", QBOGUSSHELL, 159367994Seric "QUNSAFEADDR", QUNSAFEADDR, 159467994Seric "QPINGONSUCCESS", QPINGONSUCCESS, 159567994Seric "QPINGONFAILURE", QPINGONFAILURE, 159667994Seric "QPINGONDELAY", QPINGONDELAY, 159767994Seric "QHAS_RET_PARAM", QHAS_RET_PARAM, 159867994Seric "QRET_HDRS", QRET_HDRS, 159967994Seric "QRELAYED", QRELAYED, 160067994Seric NULL 160167994Seric }; 160267994Seric 16033234Seric printaddr(a, follow) 16043234Seric register ADDRESS *a; 16053234Seric bool follow; 16063234Seric { 160757731Seric register MAILER *m; 160857731Seric MAILER pseudomailer; 160967994Seric register struct qflags *qfp; 161067994Seric bool firstone; 16115001Seric 161267994Seric if (a == NULL) 161367994Seric { 161467994Seric printf("[NULL]\n"); 161567994Seric return; 161667994Seric } 161767994Seric 16183234Seric while (a != NULL) 16193234Seric { 16204443Seric printf("%x=", a); 16214085Seric (void) fflush(stdout); 162257731Seric 162357731Seric /* find the mailer -- carefully */ 162457731Seric m = a->q_mailer; 162557731Seric if (m == NULL) 162657731Seric { 162757731Seric m = &pseudomailer; 162857731Seric m->m_mno = -1; 162957731Seric m->m_name = "NULL"; 163057731Seric } 163157731Seric 163258680Seric printf("%s:\n\tmailer %d (%s), host `%s', user `%s', ruser `%s'\n", 163357731Seric a->q_paddr, m->m_mno, m->m_name, 163467172Seric a->q_host == NULL ? "<null>" : a->q_host, a->q_user, 163567172Seric a->q_ruser == NULL ? "<null>" : a->q_ruser); 163667994Seric printf("\tnext=%x, alias %x, uid %d, gid %d\n", 163767994Seric a->q_next, a->q_alias, a->q_uid, a->q_gid); 163867994Seric printf("\tflags=%lx<", a->q_flags); 163967994Seric firstone = TRUE; 164067994Seric for (qfp = AddressFlags; qfp->qf_name != NULL; qfp++) 164167994Seric { 164267994Seric if (!bitset(qfp->qf_bit, a->q_flags)) 164367994Seric continue; 164467994Seric if (!firstone) 164567994Seric printf(","); 164667994Seric firstone = FALSE; 164767994Seric printf("%s", qfp->qf_name); 164867994Seric } 164967994Seric printf(">\n"); 165059269Seric printf("\towner=%s, home=\"%s\", fullname=\"%s\"\n", 165159269Seric a->q_owner == NULL ? "(none)" : a->q_owner, 165263756Seric a->q_home == NULL ? "(none)" : a->q_home, 165363756Seric a->q_fullname == NULL ? "(none)" : a->q_fullname); 165467990Seric printf("\torcpt=\"%s\", statmta=%s, fstatus=%s, rstatus=%s\n", 165567987Seric a->q_orcpt == NULL ? "(none)" : a->q_orcpt, 165667987Seric a->q_statmta == NULL ? "(none)" : a->q_statmta, 165767990Seric a->q_fstatus == NULL ? "(none)" : a->q_fstatus, 165867990Seric a->q_rstatus == NULL ? "(none)" : a->q_rstatus); 16594996Seric 16603234Seric if (!follow) 16613234Seric return; 16624996Seric a = a->q_next; 16633234Seric } 16643234Seric } 166567939Seric /* 166667939Seric ** EMPTYADDR -- return TRUE if this address is empty (``<>'') 166767939Seric ** 166867939Seric ** Parameters: 166967939Seric ** a -- pointer to the address 167067939Seric ** 167167939Seric ** Returns: 167267939Seric ** TRUE -- if this address is "empty" (i.e., no one should 167367939Seric ** ever generate replies to it. 167467939Seric ** FALSE -- if it is a "regular" (read: replyable) address. 167567939Seric */ 16764317Seric 167767939Seric bool 167867939Seric emptyaddr(a) 167967939Seric register ADDRESS *a; 168067939Seric { 168167939Seric return strcmp(a->q_paddr, "<>") == 0 || strcmp(a->q_user, "<>") == 0; 168267939Seric } 16837682Seric /* 16847682Seric ** REMOTENAME -- return the name relative to the current mailer 16857682Seric ** 16867682Seric ** Parameters: 16877682Seric ** name -- the name to translate. 16888069Seric ** m -- the mailer that we want to do rewriting relative 16898069Seric ** to. 169059163Seric ** flags -- fine tune operations. 169159163Seric ** pstat -- pointer to status word. 169258020Seric ** e -- the current envelope. 16937682Seric ** 16947682Seric ** Returns: 16957682Seric ** the text string representing this address relative to 16967682Seric ** the receiving mailer. 16977682Seric ** 16987682Seric ** Side Effects: 16997682Seric ** none. 17007682Seric ** 17017682Seric ** Warnings: 17027682Seric ** The text string returned is tucked away locally; 17037682Seric ** copy it if you intend to save it. 17047682Seric */ 17057682Seric 17067682Seric char * 170759163Seric remotename(name, m, flags, pstat, e) 17087682Seric char *name; 170956678Seric struct mailer *m; 171059163Seric int flags; 171159163Seric int *pstat; 171256678Seric register ENVELOPE *e; 17137682Seric { 17148069Seric register char **pvp; 17158069Seric char *fancy; 171656678Seric char *oldg = macvalue('g', e); 171758020Seric int rwset; 17187682Seric static char buf[MAXNAME]; 17197682Seric char lbuf[MAXNAME]; 172016914Seric char pvpbuf[PSBUFSIZE]; 172156678Seric extern char *crackaddr(); 17227682Seric 17237755Seric if (tTd(12, 1)) 17247755Seric printf("remotename(%s)\n", name); 17257755Seric 172610177Seric /* don't do anything if we are tagging it as special */ 172759163Seric if (bitset(RF_SENDERADDR, flags)) 172859163Seric rwset = bitset(RF_HEADERADDR, flags) ? m->m_sh_rwset 172959163Seric : m->m_se_rwset; 173058020Seric else 173159163Seric rwset = bitset(RF_HEADERADDR, flags) ? m->m_rh_rwset 173259163Seric : m->m_re_rwset; 173358020Seric if (rwset < 0) 173410177Seric return (name); 173510177Seric 17367682Seric /* 17378181Seric ** Do a heuristic crack of this name to extract any comment info. 17388181Seric ** This will leave the name as a comment and a $g macro. 17397889Seric */ 17407889Seric 174159163Seric if (bitset(RF_CANONICAL, flags) || bitnset(M_NOCOMMENT, m->m_flags)) 174258050Seric fancy = "\201g"; 174310310Seric else 174410310Seric fancy = crackaddr(name); 17457889Seric 17468181Seric /* 17478181Seric ** Turn the name into canonical form. 17488181Seric ** Normally this will be RFC 822 style, i.e., "user@domain". 17498181Seric ** If this only resolves to "user", and the "C" flag is 17508181Seric ** specified in the sending mailer, then the sender's 17518181Seric ** domain will be appended. 17528181Seric */ 17538181Seric 175465066Seric pvp = prescan(name, '\0', pvpbuf, sizeof pvpbuf, NULL); 17557889Seric if (pvp == NULL) 17567889Seric return (name); 175765071Seric if (rewrite(pvp, 3, 0, e) == EX_TEMPFAIL) 175859163Seric *pstat = EX_TEMPFAIL; 175959163Seric if (bitset(RF_ADDDOMAIN, flags) && e->e_fromdomain != NULL) 17608181Seric { 17618181Seric /* append from domain to this address */ 17628181Seric register char **pxp = pvp; 17638181Seric 17649594Seric /* see if there is an "@domain" in the current name */ 17658181Seric while (*pxp != NULL && strcmp(*pxp, "@") != 0) 17668181Seric pxp++; 17678181Seric if (*pxp == NULL) 17688181Seric { 17699594Seric /* no.... append the "@domain" from the sender */ 177056678Seric register char **qxq = e->e_fromdomain; 17718181Seric 17729594Seric while ((*pxp++ = *qxq++) != NULL) 17739594Seric continue; 177465071Seric if (rewrite(pvp, 3, 0, e) == EX_TEMPFAIL) 177559163Seric *pstat = EX_TEMPFAIL; 17768181Seric } 17778181Seric } 17788181Seric 17798181Seric /* 17808959Seric ** Do more specific rewriting. 178156678Seric ** Rewrite using ruleset 1 or 2 depending on whether this is 178256678Seric ** a sender address or not. 17838181Seric ** Then run it through any receiving-mailer-specific rulesets. 17848181Seric */ 17858181Seric 178659163Seric if (bitset(RF_SENDERADDR, flags)) 178759541Seric { 178865071Seric if (rewrite(pvp, 1, 0, e) == EX_TEMPFAIL) 178959163Seric *pstat = EX_TEMPFAIL; 179059541Seric } 17918069Seric else 179259541Seric { 179365071Seric if (rewrite(pvp, 2, 0, e) == EX_TEMPFAIL) 179459163Seric *pstat = EX_TEMPFAIL; 179559541Seric } 179658020Seric if (rwset > 0) 179759541Seric { 179865071Seric if (rewrite(pvp, rwset, 0, e) == EX_TEMPFAIL) 179959163Seric *pstat = EX_TEMPFAIL; 180059541Seric } 18017682Seric 18028181Seric /* 18038959Seric ** Do any final sanitation the address may require. 18048959Seric ** This will normally be used to turn internal forms 18058959Seric ** (e.g., user@host.LOCAL) into external form. This 18068959Seric ** may be used as a default to the above rules. 18078959Seric */ 18088959Seric 180965071Seric if (rewrite(pvp, 4, 0, e) == EX_TEMPFAIL) 181059163Seric *pstat = EX_TEMPFAIL; 18118959Seric 18128959Seric /* 18138181Seric ** Now restore the comment information we had at the beginning. 18148181Seric */ 18158181Seric 181658825Seric cataddr(pvp, NULL, lbuf, sizeof lbuf, '\0'); 181756678Seric define('g', lbuf, e); 181865494Seric 181965494Seric /* need to make sure route-addrs have <angle brackets> */ 182065494Seric if (bitset(RF_CANONICAL, flags) && lbuf[0] == '@') 182165494Seric expand("<\201g>", buf, &buf[sizeof buf - 1], e); 182265494Seric else 182365494Seric expand(fancy, buf, &buf[sizeof buf - 1], e); 182465494Seric 182556678Seric define('g', oldg, e); 18267682Seric 18277682Seric if (tTd(12, 1)) 18287755Seric printf("remotename => `%s'\n", buf); 18297682Seric return (buf); 18307682Seric } 183151317Seric /* 183256678Seric ** MAPLOCALUSER -- run local username through ruleset 5 for final redirection 183351317Seric ** 183451317Seric ** Parameters: 183556678Seric ** a -- the address to map (but just the user name part). 183656678Seric ** sendq -- the sendq in which to install any replacement 183756678Seric ** addresses. 183867982Seric ** aliaslevel -- the alias nesting depth. 183967982Seric ** e -- the envelope. 184051317Seric ** 184151317Seric ** Returns: 184251317Seric ** none. 184351317Seric */ 184451317Seric 184567982Seric maplocaluser(a, sendq, aliaslevel, e) 184656678Seric register ADDRESS *a; 184756678Seric ADDRESS **sendq; 184867982Seric int aliaslevel; 184956678Seric ENVELOPE *e; 185051317Seric { 185156678Seric register char **pvp; 185256678Seric register ADDRESS *a1 = NULL; 185358333Seric auto char *delimptr; 185456678Seric char pvpbuf[PSBUFSIZE]; 185551317Seric 185656678Seric if (tTd(29, 1)) 185756678Seric { 185856678Seric printf("maplocaluser: "); 185956678Seric printaddr(a, FALSE); 186056678Seric } 186165066Seric pvp = prescan(a->q_user, '\0', pvpbuf, sizeof pvpbuf, &delimptr); 186256678Seric if (pvp == NULL) 186356678Seric return; 186451317Seric 186565071Seric (void) rewrite(pvp, 5, 0, e); 186658050Seric if (pvp[0] == NULL || (pvp[0][0] & 0377) != CANONNET) 186756678Seric return; 186851317Seric 186956678Seric /* if non-null, mailer destination specified -- has it changed? */ 187064284Seric a1 = buildaddr(pvp, NULL, 0, e); 187156678Seric if (a1 == NULL || sameaddr(a, a1)) 187256678Seric return; 187351317Seric 187456678Seric /* mark old address as dead; insert new address */ 187556678Seric a->q_flags |= QDONTSEND; 187657731Seric if (tTd(29, 5)) 187757731Seric { 187857731Seric printf("maplocaluser: QDONTSEND "); 187957731Seric printaddr(a, FALSE); 188057731Seric } 188156678Seric a1->q_alias = a; 188264348Seric allocaddr(a1, RF_COPYALL, NULL); 188367982Seric (void) recipient(a1, sendq, aliaslevel, e); 188451317Seric } 188558802Seric /* 188658802Seric ** DEQUOTE_INIT -- initialize dequote map 188758802Seric ** 188858802Seric ** This is a no-op. 188958802Seric ** 189058802Seric ** Parameters: 189158802Seric ** map -- the internal map structure. 189258802Seric ** args -- arguments. 189358802Seric ** 189458802Seric ** Returns: 189558802Seric ** TRUE. 189658802Seric */ 189758802Seric 189858802Seric bool 189960219Seric dequote_init(map, args) 190058802Seric MAP *map; 190158802Seric char *args; 190258802Seric { 190358805Seric register char *p = args; 190458805Seric 190558805Seric for (;;) 190658805Seric { 190758805Seric while (isascii(*p) && isspace(*p)) 190858805Seric p++; 190958805Seric if (*p != '-') 191058805Seric break; 191158805Seric switch (*++p) 191258805Seric { 191358805Seric case 'a': 191458805Seric map->map_app = ++p; 191558805Seric break; 191667824Seric 191767824Seric case 's': 191867824Seric map->map_coldelim = *++p; 191967824Seric break; 192058805Seric } 192158805Seric while (*p != '\0' && !(isascii(*p) && isspace(*p))) 192258805Seric p++; 192358805Seric if (*p != '\0') 192458805Seric *p = '\0'; 192558805Seric } 192658805Seric if (map->map_app != NULL) 192758805Seric map->map_app = newstr(map->map_app); 192858805Seric 192958802Seric return TRUE; 193058802Seric } 193158802Seric /* 193258802Seric ** DEQUOTE_MAP -- unquote an address 193358802Seric ** 193458802Seric ** Parameters: 193558802Seric ** map -- the internal map structure (ignored). 193660089Seric ** name -- the name to dequote. 193758802Seric ** av -- arguments (ignored). 193859084Seric ** statp -- pointer to status out-parameter. 193958802Seric ** 194058802Seric ** Returns: 194158802Seric ** NULL -- if there were no quotes, or if the resulting 194258802Seric ** unquoted buffer would not be acceptable to prescan. 194358802Seric ** else -- The dequoted buffer. 194458802Seric */ 194558802Seric 194658802Seric char * 194760089Seric dequote_map(map, name, av, statp) 194858802Seric MAP *map; 194960089Seric char *name; 195058802Seric char **av; 195159084Seric int *statp; 195258802Seric { 195358802Seric register char *p; 195458802Seric register char *q; 195558802Seric register char c; 195667824Seric int anglecnt = 0; 195767824Seric int cmntcnt = 0; 195867824Seric int quotecnt = 0; 195967824Seric int spacecnt = 0; 196067824Seric bool quotemode = FALSE; 196167824Seric bool bslashmode = FALSE; 196267824Seric char spacesub = map->map_coldelim; 196358802Seric 196460089Seric for (p = q = name; (c = *p++) != '\0'; ) 196558802Seric { 196658802Seric if (bslashmode) 196758802Seric { 196858802Seric bslashmode = FALSE; 196958802Seric *q++ = c; 197058802Seric continue; 197158802Seric } 197258802Seric 197367824Seric if (c == ' ' && spacesub != '\0') 197467824Seric c = spacesub; 197567764Seric 197658802Seric switch (c) 197758802Seric { 197858802Seric case '\\': 197958802Seric bslashmode = TRUE; 198058802Seric break; 198158802Seric 198258802Seric case '(': 198358802Seric cmntcnt++; 198458802Seric break; 198558802Seric 198658802Seric case ')': 198758802Seric if (cmntcnt-- <= 0) 198858802Seric return NULL; 198958802Seric break; 199059089Seric 199159089Seric case ' ': 199259089Seric spacecnt++; 199359089Seric break; 199458802Seric } 199558802Seric 199658802Seric if (cmntcnt > 0) 199758802Seric { 199858802Seric *q++ = c; 199958802Seric continue; 200058802Seric } 200158802Seric 200258802Seric switch (c) 200358802Seric { 200458802Seric case '"': 200558802Seric quotemode = !quotemode; 200658802Seric quotecnt++; 200758802Seric continue; 200858802Seric 200958802Seric case '<': 201058802Seric anglecnt++; 201158802Seric break; 201258802Seric 201358802Seric case '>': 201458802Seric if (anglecnt-- <= 0) 201558802Seric return NULL; 201658802Seric break; 201758802Seric } 201858802Seric *q++ = c; 201958802Seric } 202058802Seric 202158802Seric if (anglecnt != 0 || cmntcnt != 0 || bslashmode || 202259089Seric quotemode || quotecnt <= 0 || spacecnt != 0) 202358802Seric return NULL; 202458802Seric *q++ = '\0'; 202560089Seric return name; 202658802Seric } 2027