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*68358Seric static char sccsid[] = "@(#)parseaddr.c 8.51 (Berkeley) 02/19/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; 155*68358Seric 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 { 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; 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 { 115765379Seric bcopy((char *) &npvp[2], (char *) pvp, 115865379Seric (int) (avp - npvp - 2) * sizeof *avp); 115965379Seric if (tTd(21, 3)) 116065379Seric printf("-----callsubr %s\n", npvp[1]); 116165379Seric stat = rewrite(pvp, atoi(npvp[1]), reclevel, e); 116265379Seric if (rstat == EX_OK || stat == EX_TEMPFAIL) 116365379Seric rstat = stat; 116465379Seric if (*pvp != NULL && (**pvp & 0377) == CANONNET) 116563581Seric rwr = NULL; 116665379Seric } 116756678Seric } 116856678Seric else 116956678Seric { 117017348Seric bcopy((char *) npvp, (char *) pvp, 117116900Seric (int) (avp - npvp) * sizeof *avp); 117256678Seric } 11739374Seric if (tTd(21, 4)) 11749374Seric { 11759374Seric printf("rewritten as:"); 117656678Seric printav(pvp); 11779374Seric } 1178297Seric } 11798069Seric 118067262Seric if (OpMode == MD_TEST || tTd(21, 1)) 11818069Seric { 11828959Seric printf("rewrite: ruleset %2d returns:", ruleset); 118356678Seric printav(pvp); 11848069Seric } 118559084Seric 118659084Seric return rstat; 11873149Seric } 11883149Seric /* 11893149Seric ** BUILDADDR -- build address from token vector. 11903149Seric ** 11913149Seric ** Parameters: 11923149Seric ** tv -- token vector. 11933149Seric ** a -- pointer to address descriptor to fill. 11943149Seric ** If NULL, one will be allocated. 119564284Seric ** flags -- info regarding whether this is a sender or 119664284Seric ** a recipient. 119758966Seric ** e -- the current envelope. 11983149Seric ** 11993149Seric ** Returns: 12004279Seric ** NULL if there was an error. 12014279Seric ** 'a' otherwise. 12023149Seric ** 12033149Seric ** Side Effects: 12043149Seric ** fills in 'a' 12053149Seric */ 12063149Seric 120757249Seric struct errcodes 120857249Seric { 120957249Seric char *ec_name; /* name of error code */ 121057249Seric int ec_code; /* numeric code */ 121157249Seric } ErrorCodes[] = 121257249Seric { 121357249Seric "usage", EX_USAGE, 121457249Seric "nouser", EX_NOUSER, 121557249Seric "nohost", EX_NOHOST, 121657249Seric "unavailable", EX_UNAVAILABLE, 121757249Seric "software", EX_SOFTWARE, 121857249Seric "tempfail", EX_TEMPFAIL, 121957249Seric "protocol", EX_PROTOCOL, 122057249Seric #ifdef EX_CONFIG 122157249Seric "config", EX_CONFIG, 122257249Seric #endif 122357249Seric NULL, EX_UNAVAILABLE, 122457249Seric }; 122557249Seric 122656678Seric ADDRESS * 122764284Seric buildaddr(tv, a, flags, e) 12283149Seric register char **tv; 12293149Seric register ADDRESS *a; 123064284Seric int flags; 123158966Seric register ENVELOPE *e; 12323149Seric { 12333149Seric struct mailer **mp; 12343149Seric register struct mailer *m; 123558008Seric char *bp; 123658008Seric int spaceleft; 123764306Seric static MAILER errormailer; 123864306Seric static char *errorargv[] = { "ERROR", NULL }; 123957402Seric static char buf[MAXNAME]; 12403149Seric 124164791Seric if (tTd(24, 5)) 124264791Seric { 124367693Seric printf("buildaddr, flags=%x, tv=", flags); 124464791Seric printav(tv); 124564791Seric } 124664791Seric 12473149Seric if (a == NULL) 12483149Seric a = (ADDRESS *) xalloc(sizeof *a); 124916889Seric bzero((char *) a, sizeof *a); 12503149Seric 125167880Seric /* set up default error return flags */ 125267963Seric a->q_flags |= QPINGONFAILURE|QPINGONDELAY; 125367880Seric 12543149Seric /* figure out what net/mailer to use */ 125564306Seric if (*tv == NULL || (**tv & 0377) != CANONNET) 12564279Seric { 125758151Seric syserr("554 buildaddr: no net"); 125864306Seric badaddr: 125964306Seric a->q_flags |= QBADADDR; 126064306Seric a->q_mailer = &errormailer; 126164306Seric if (errormailer.m_name == NULL) 126264306Seric { 126364306Seric /* initialize the bogus mailer */ 126464306Seric errormailer.m_name = "*error*"; 126564306Seric errormailer.m_mailer = "ERROR"; 126664306Seric errormailer.m_argv = errorargv; 126764306Seric } 126864306Seric return a; 12694279Seric } 12703149Seric tv++; 127158680Seric if (strcasecmp(*tv, "error") == 0) 12724279Seric { 127358050Seric if ((**++tv & 0377) == CANONHOST) 127410183Seric { 127557249Seric register struct errcodes *ep; 127657249Seric 127758050Seric if (isascii(**++tv) && isdigit(**tv)) 127857249Seric { 127957249Seric setstat(atoi(*tv)); 128057249Seric } 128157249Seric else 128257249Seric { 128357249Seric for (ep = ErrorCodes; ep->ec_name != NULL; ep++) 128457249Seric if (strcasecmp(ep->ec_name, *tv) == 0) 128557249Seric break; 128657249Seric setstat(ep->ec_code); 128757249Seric } 128810183Seric tv++; 128910183Seric } 129064928Seric else 129164928Seric setstat(EX_UNAVAILABLE); 129258050Seric if ((**tv & 0377) != CANONUSER) 129358151Seric syserr("554 buildaddr: error: no user"); 129458814Seric cataddr(++tv, NULL, buf, sizeof buf, ' '); 129558082Seric stripquotes(buf); 129664659Seric if (isascii(buf[0]) && isdigit(buf[0]) && 129764659Seric isascii(buf[1]) && isdigit(buf[1]) && 129864659Seric isascii(buf[2]) && isdigit(buf[2]) && 129964659Seric buf[3] == ' ') 130064659Seric { 130164659Seric char fmt[10]; 130264659Seric 130364659Seric strncpy(fmt, buf, 3); 130464659Seric strcpy(&fmt[3], " %s"); 130564659Seric usrerr(fmt, buf + 4); 130667786Seric 130767786Seric /* 130867786Seric ** If this is a 4xx code and we aren't running 130967786Seric ** SMTP on our input, bounce this message; 131067786Seric ** otherwise it disappears without a trace. 131167786Seric */ 131267786Seric 131367786Seric if (fmt[0] == '4' && OpMode != MD_SMTP && 131467786Seric OpMode != MD_DAEMON) 131567786Seric { 131667786Seric e->e_flags |= EF_FATALERRS; 131767786Seric } 131864659Seric } 131964659Seric else 132064659Seric { 132166039Seric usrerr("553 %s", buf); 132264659Seric } 132364306Seric goto badaddr; 13244279Seric } 132557402Seric 13264598Seric for (mp = Mailer; (m = *mp++) != NULL; ) 13273149Seric { 132858680Seric if (strcasecmp(m->m_name, *tv) == 0) 13293149Seric break; 13303149Seric } 13313149Seric if (m == NULL) 13324279Seric { 133358151Seric syserr("554 buildaddr: unknown mailer %s", *tv); 133464306Seric goto badaddr; 13354279Seric } 13364598Seric a->q_mailer = m; 13373149Seric 13383149Seric /* figure out what host (if any) */ 133956678Seric tv++; 134058509Seric if ((**tv & 0377) == CANONHOST) 13413149Seric { 134258008Seric bp = buf; 134358008Seric spaceleft = sizeof buf - 1; 134458050Seric while (*++tv != NULL && (**tv & 0377) != CANONUSER) 134558008Seric { 134658008Seric int i = strlen(*tv); 134758008Seric 134858008Seric if (i > spaceleft) 134958008Seric { 135058008Seric /* out of space for this address */ 135158008Seric if (spaceleft >= 0) 135258151Seric syserr("554 buildaddr: host too long (%.40s...)", 135358008Seric buf); 135458008Seric i = spaceleft; 135558008Seric spaceleft = 0; 135658008Seric } 135758008Seric if (i <= 0) 135858008Seric continue; 135958008Seric bcopy(*tv, bp, i); 136058008Seric bp += i; 136158008Seric spaceleft -= i; 136258008Seric } 136358010Seric *bp = '\0'; 13645704Seric a->q_host = newstr(buf); 13653149Seric } 136657249Seric else 136758509Seric { 136858509Seric if (!bitnset(M_LOCALMAILER, m->m_flags)) 136958509Seric { 137058509Seric syserr("554 buildaddr: no host"); 137164306Seric goto badaddr; 137258509Seric } 137357249Seric a->q_host = NULL; 137458509Seric } 13753149Seric 13763149Seric /* figure out the user */ 137758050Seric if (*tv == NULL || (**tv & 0377) != CANONUSER) 13784279Seric { 137958151Seric syserr("554 buildaddr: no user"); 138064306Seric goto badaddr; 13814279Seric } 138257402Seric tv++; 138351317Seric 138468098Seric if (bitnset(M_CHECKUDB, m->m_flags) && *tv != NULL && 138568098Seric strcmp(*tv, "@") == 0) 138668098Seric { 138768098Seric tv++; 138868098Seric a->q_flags |= QNOTREMOTE; 138968098Seric } 139068098Seric 139157402Seric /* do special mapping for local mailer */ 139267472Seric if (*tv != NULL) 139357402Seric { 139457454Seric register char *p = *tv; 139557454Seric 139657454Seric if (*p == '"') 139757454Seric p++; 139867472Seric if (*p == '|' && bitnset(M_CHECKPROG, m->m_flags)) 139957402Seric a->q_mailer = m = ProgMailer; 140067472Seric else if (*p == '/' && bitnset(M_CHECKFILE, m->m_flags)) 140157402Seric a->q_mailer = m = FileMailer; 140267472Seric else if (*p == ':' && bitnset(M_CHECKINCLUDE, m->m_flags)) 140357402Seric { 140457402Seric /* may be :include: */ 140558814Seric cataddr(tv, NULL, buf, sizeof buf, '\0'); 140658008Seric stripquotes(buf); 140758008Seric if (strncasecmp(buf, ":include:", 9) == 0) 140858008Seric { 140958008Seric /* if :include:, don't need further rewriting */ 141057402Seric a->q_mailer = m = InclMailer; 141158008Seric a->q_user = &buf[9]; 141258008Seric return (a); 141358008Seric } 141457402Seric } 141557402Seric } 141657402Seric 141764284Seric /* rewrite according recipient mailer rewriting rules */ 141864284Seric define('h', a->q_host, e); 141964284Seric if (!bitset(RF_SENDERADDR|RF_HEADERADDR, flags)) 142064284Seric { 142164284Seric /* sender addresses done later */ 142265071Seric (void) rewrite(tv, 2, 0, e); 142364284Seric if (m->m_re_rwset > 0) 142465071Seric (void) rewrite(tv, m->m_re_rwset, 0, e); 142564284Seric } 142665071Seric (void) rewrite(tv, 4, 0, e); 142719040Seric 142819040Seric /* save the result for the command line/RCPT argument */ 142958814Seric cataddr(tv, NULL, buf, sizeof buf, '\0'); 14303149Seric a->q_user = buf; 14313149Seric 143258670Seric /* 143358670Seric ** Do mapping to lower case as requested by mailer 143458670Seric */ 143558670Seric 143658670Seric if (a->q_host != NULL && !bitnset(M_HST_UPPER, m->m_flags)) 143758670Seric makelower(a->q_host); 143858670Seric if (!bitnset(M_USR_UPPER, m->m_flags)) 143958670Seric makelower(a->q_user); 144058670Seric 14413149Seric return (a); 14423149Seric } 14433188Seric /* 14444228Seric ** CATADDR -- concatenate pieces of addresses (putting in <LWSP> subs) 14454228Seric ** 14464228Seric ** Parameters: 14474228Seric ** pvp -- parameter vector to rebuild. 144858814Seric ** evp -- last parameter to include. Can be NULL to 144958814Seric ** use entire pvp. 14504228Seric ** buf -- buffer to build the string into. 14514228Seric ** sz -- size of buf. 145258082Seric ** spacesub -- the space separator character; if null, 145358082Seric ** use SpaceSub. 14544228Seric ** 14554228Seric ** Returns: 14564228Seric ** none. 14574228Seric ** 14584228Seric ** Side Effects: 14594228Seric ** Destroys buf. 14604228Seric */ 14614228Seric 146258814Seric cataddr(pvp, evp, buf, sz, spacesub) 14634228Seric char **pvp; 146458814Seric char **evp; 14654228Seric char *buf; 14664228Seric register int sz; 146758082Seric char spacesub; 14684228Seric { 14694228Seric bool oatomtok = FALSE; 147056678Seric bool natomtok = FALSE; 14714228Seric register int i; 14724228Seric register char *p; 14734228Seric 147458082Seric if (spacesub == '\0') 147558082Seric spacesub = SpaceSub; 147658082Seric 14778423Seric if (pvp == NULL) 14788423Seric { 147923109Seric (void) strcpy(buf, ""); 14808423Seric return; 14818423Seric } 14824228Seric p = buf; 148311156Seric sz -= 2; 14844228Seric while (*pvp != NULL && (i = strlen(*pvp)) < sz) 14854228Seric { 14868078Seric natomtok = (toktype(**pvp) == ATM); 14874228Seric if (oatomtok && natomtok) 148858082Seric *p++ = spacesub; 14894228Seric (void) strcpy(p, *pvp); 14904228Seric oatomtok = natomtok; 14914228Seric p += i; 149211156Seric sz -= i + 1; 149358814Seric if (pvp++ == evp) 149458814Seric break; 14954228Seric } 14964228Seric *p = '\0'; 14974228Seric } 14984228Seric /* 14993188Seric ** SAMEADDR -- Determine if two addresses are the same 15003188Seric ** 15013188Seric ** This is not just a straight comparison -- if the mailer doesn't 15023188Seric ** care about the host we just ignore it, etc. 15033188Seric ** 15043188Seric ** Parameters: 15053188Seric ** a, b -- pointers to the internal forms to compare. 15063188Seric ** 15073188Seric ** Returns: 15083188Seric ** TRUE -- they represent the same mailbox. 15093188Seric ** FALSE -- they don't. 15103188Seric ** 15113188Seric ** Side Effects: 15123188Seric ** none. 15133188Seric */ 15143188Seric 15153188Seric bool 15169374Seric sameaddr(a, b) 15173188Seric register ADDRESS *a; 15183188Seric register ADDRESS *b; 15193188Seric { 152065093Seric register ADDRESS *ca, *cb; 152165093Seric 15223188Seric /* if they don't have the same mailer, forget it */ 15233188Seric if (a->q_mailer != b->q_mailer) 15243188Seric return (FALSE); 15253188Seric 15263188Seric /* if the user isn't the same, we can drop out */ 152756678Seric if (strcmp(a->q_user, b->q_user) != 0) 15283188Seric return (FALSE); 15293188Seric 153065093Seric /* if we have good uids for both but they differ, these are different */ 153165379Seric if (a->q_mailer == ProgMailer) 153265379Seric { 153365379Seric ca = getctladdr(a); 153465379Seric cb = getctladdr(b); 153565379Seric if (ca != NULL && cb != NULL && 153665379Seric bitset(QGOODUID, ca->q_flags & cb->q_flags) && 153765379Seric ca->q_uid != cb->q_uid) 153865379Seric return (FALSE); 153965379Seric } 154058438Seric 154158509Seric /* otherwise compare hosts (but be careful for NULL ptrs) */ 154258509Seric if (a->q_host == b->q_host) 154358509Seric { 154458509Seric /* probably both null pointers */ 15453188Seric return (TRUE); 154658509Seric } 15473188Seric if (a->q_host == NULL || b->q_host == NULL) 154858509Seric { 154958509Seric /* only one is a null pointer */ 15503188Seric return (FALSE); 155158509Seric } 155256678Seric if (strcmp(a->q_host, b->q_host) != 0) 15533188Seric return (FALSE); 15543188Seric 15553188Seric return (TRUE); 15563188Seric } 15573234Seric /* 15583234Seric ** PRINTADDR -- print address (for debugging) 15593234Seric ** 15603234Seric ** Parameters: 15613234Seric ** a -- the address to print 15623234Seric ** follow -- follow the q_next chain. 15633234Seric ** 15643234Seric ** Returns: 15653234Seric ** none. 15663234Seric ** 15673234Seric ** Side Effects: 15683234Seric ** none. 15693234Seric */ 15703234Seric 157167994Seric struct qflags 157267994Seric { 157367994Seric char *qf_name; 157467994Seric u_long qf_bit; 157567994Seric }; 157667994Seric 157767994Seric struct qflags AddressFlags[] = 157867994Seric { 157967994Seric "QDONTSEND", QDONTSEND, 158067994Seric "QBADADDR", QBADADDR, 158167994Seric "QGOODUID", QGOODUID, 158267994Seric "QPRIMARY", QPRIMARY, 158367994Seric "QQUEUEUP", QQUEUEUP, 158467994Seric "QSENT", QSENT, 158567994Seric "QNOTREMOTE", QNOTREMOTE, 158667994Seric "QSELFREF", QSELFREF, 158767994Seric "QVERIFIED", QVERIFIED, 158867994Seric "QREPORT", QREPORT, 158967994Seric "QBOGUSSHELL", QBOGUSSHELL, 159067994Seric "QUNSAFEADDR", QUNSAFEADDR, 159167994Seric "QPINGONSUCCESS", QPINGONSUCCESS, 159267994Seric "QPINGONFAILURE", QPINGONFAILURE, 159367994Seric "QPINGONDELAY", QPINGONDELAY, 159467994Seric "QHAS_RET_PARAM", QHAS_RET_PARAM, 159567994Seric "QRET_HDRS", QRET_HDRS, 159667994Seric "QRELAYED", QRELAYED, 159767994Seric NULL 159867994Seric }; 159967994Seric 16003234Seric printaddr(a, follow) 16013234Seric register ADDRESS *a; 16023234Seric bool follow; 16033234Seric { 160457731Seric register MAILER *m; 160557731Seric MAILER pseudomailer; 160667994Seric register struct qflags *qfp; 160767994Seric bool firstone; 16085001Seric 160967994Seric if (a == NULL) 161067994Seric { 161167994Seric printf("[NULL]\n"); 161267994Seric return; 161367994Seric } 161467994Seric 16153234Seric while (a != NULL) 16163234Seric { 16174443Seric printf("%x=", a); 16184085Seric (void) fflush(stdout); 161957731Seric 162057731Seric /* find the mailer -- carefully */ 162157731Seric m = a->q_mailer; 162257731Seric if (m == NULL) 162357731Seric { 162457731Seric m = &pseudomailer; 162557731Seric m->m_mno = -1; 162657731Seric m->m_name = "NULL"; 162757731Seric } 162857731Seric 162958680Seric printf("%s:\n\tmailer %d (%s), host `%s', user `%s', ruser `%s'\n", 163057731Seric a->q_paddr, m->m_mno, m->m_name, 163167172Seric a->q_host == NULL ? "<null>" : a->q_host, a->q_user, 163267172Seric a->q_ruser == NULL ? "<null>" : a->q_ruser); 163367994Seric printf("\tnext=%x, alias %x, uid %d, gid %d\n", 163467994Seric a->q_next, a->q_alias, a->q_uid, a->q_gid); 163567994Seric printf("\tflags=%lx<", a->q_flags); 163667994Seric firstone = TRUE; 163767994Seric for (qfp = AddressFlags; qfp->qf_name != NULL; qfp++) 163867994Seric { 163967994Seric if (!bitset(qfp->qf_bit, a->q_flags)) 164067994Seric continue; 164167994Seric if (!firstone) 164267994Seric printf(","); 164367994Seric firstone = FALSE; 164467994Seric printf("%s", qfp->qf_name); 164567994Seric } 164667994Seric printf(">\n"); 164759269Seric printf("\towner=%s, home=\"%s\", fullname=\"%s\"\n", 164859269Seric a->q_owner == NULL ? "(none)" : a->q_owner, 164963756Seric a->q_home == NULL ? "(none)" : a->q_home, 165063756Seric a->q_fullname == NULL ? "(none)" : a->q_fullname); 165168228Seric printf("\torcpt=\"%s\", statmta=%s, rstatus=%s\n", 165267987Seric a->q_orcpt == NULL ? "(none)" : a->q_orcpt, 165367987Seric a->q_statmta == NULL ? "(none)" : a->q_statmta, 165467990Seric a->q_rstatus == NULL ? "(none)" : a->q_rstatus); 16554996Seric 16563234Seric if (!follow) 16573234Seric return; 16584996Seric a = a->q_next; 16593234Seric } 16603234Seric } 166167939Seric /* 166267939Seric ** EMPTYADDR -- return TRUE if this address is empty (``<>'') 166367939Seric ** 166467939Seric ** Parameters: 166567939Seric ** a -- pointer to the address 166667939Seric ** 166767939Seric ** Returns: 166867939Seric ** TRUE -- if this address is "empty" (i.e., no one should 166967939Seric ** ever generate replies to it. 167067939Seric ** FALSE -- if it is a "regular" (read: replyable) address. 167167939Seric */ 16724317Seric 167367939Seric bool 167467939Seric emptyaddr(a) 167567939Seric register ADDRESS *a; 167667939Seric { 167767939Seric return strcmp(a->q_paddr, "<>") == 0 || strcmp(a->q_user, "<>") == 0; 167867939Seric } 16797682Seric /* 16807682Seric ** REMOTENAME -- return the name relative to the current mailer 16817682Seric ** 16827682Seric ** Parameters: 16837682Seric ** name -- the name to translate. 16848069Seric ** m -- the mailer that we want to do rewriting relative 16858069Seric ** to. 168659163Seric ** flags -- fine tune operations. 168759163Seric ** pstat -- pointer to status word. 168858020Seric ** e -- the current envelope. 16897682Seric ** 16907682Seric ** Returns: 16917682Seric ** the text string representing this address relative to 16927682Seric ** the receiving mailer. 16937682Seric ** 16947682Seric ** Side Effects: 16957682Seric ** none. 16967682Seric ** 16977682Seric ** Warnings: 16987682Seric ** The text string returned is tucked away locally; 16997682Seric ** copy it if you intend to save it. 17007682Seric */ 17017682Seric 17027682Seric char * 170359163Seric remotename(name, m, flags, pstat, e) 17047682Seric char *name; 170556678Seric struct mailer *m; 170659163Seric int flags; 170759163Seric int *pstat; 170856678Seric register ENVELOPE *e; 17097682Seric { 17108069Seric register char **pvp; 17118069Seric char *fancy; 171256678Seric char *oldg = macvalue('g', e); 171358020Seric int rwset; 17147682Seric static char buf[MAXNAME]; 17157682Seric char lbuf[MAXNAME]; 171616914Seric char pvpbuf[PSBUFSIZE]; 171756678Seric extern char *crackaddr(); 17187682Seric 17197755Seric if (tTd(12, 1)) 17207755Seric printf("remotename(%s)\n", name); 17217755Seric 172210177Seric /* don't do anything if we are tagging it as special */ 172359163Seric if (bitset(RF_SENDERADDR, flags)) 172459163Seric rwset = bitset(RF_HEADERADDR, flags) ? m->m_sh_rwset 172559163Seric : m->m_se_rwset; 172658020Seric else 172759163Seric rwset = bitset(RF_HEADERADDR, flags) ? m->m_rh_rwset 172859163Seric : m->m_re_rwset; 172958020Seric if (rwset < 0) 173010177Seric return (name); 173110177Seric 17327682Seric /* 17338181Seric ** Do a heuristic crack of this name to extract any comment info. 17348181Seric ** This will leave the name as a comment and a $g macro. 17357889Seric */ 17367889Seric 173759163Seric if (bitset(RF_CANONICAL, flags) || bitnset(M_NOCOMMENT, m->m_flags)) 173858050Seric fancy = "\201g"; 173910310Seric else 174010310Seric fancy = crackaddr(name); 17417889Seric 17428181Seric /* 17438181Seric ** Turn the name into canonical form. 17448181Seric ** Normally this will be RFC 822 style, i.e., "user@domain". 17458181Seric ** If this only resolves to "user", and the "C" flag is 17468181Seric ** specified in the sending mailer, then the sender's 17478181Seric ** domain will be appended. 17488181Seric */ 17498181Seric 175065066Seric pvp = prescan(name, '\0', pvpbuf, sizeof pvpbuf, NULL); 17517889Seric if (pvp == NULL) 17527889Seric return (name); 175365071Seric if (rewrite(pvp, 3, 0, e) == EX_TEMPFAIL) 175459163Seric *pstat = EX_TEMPFAIL; 175559163Seric if (bitset(RF_ADDDOMAIN, flags) && e->e_fromdomain != NULL) 17568181Seric { 17578181Seric /* append from domain to this address */ 17588181Seric register char **pxp = pvp; 17598181Seric 17609594Seric /* see if there is an "@domain" in the current name */ 17618181Seric while (*pxp != NULL && strcmp(*pxp, "@") != 0) 17628181Seric pxp++; 17638181Seric if (*pxp == NULL) 17648181Seric { 17659594Seric /* no.... append the "@domain" from the sender */ 176656678Seric register char **qxq = e->e_fromdomain; 17678181Seric 17689594Seric while ((*pxp++ = *qxq++) != NULL) 17699594Seric continue; 177065071Seric if (rewrite(pvp, 3, 0, e) == EX_TEMPFAIL) 177159163Seric *pstat = EX_TEMPFAIL; 17728181Seric } 17738181Seric } 17748181Seric 17758181Seric /* 17768959Seric ** Do more specific rewriting. 177756678Seric ** Rewrite using ruleset 1 or 2 depending on whether this is 177856678Seric ** a sender address or not. 17798181Seric ** Then run it through any receiving-mailer-specific rulesets. 17808181Seric */ 17818181Seric 178259163Seric if (bitset(RF_SENDERADDR, flags)) 178359541Seric { 178465071Seric if (rewrite(pvp, 1, 0, e) == EX_TEMPFAIL) 178559163Seric *pstat = EX_TEMPFAIL; 178659541Seric } 17878069Seric else 178859541Seric { 178965071Seric if (rewrite(pvp, 2, 0, e) == EX_TEMPFAIL) 179059163Seric *pstat = EX_TEMPFAIL; 179159541Seric } 179258020Seric if (rwset > 0) 179359541Seric { 179465071Seric if (rewrite(pvp, rwset, 0, e) == EX_TEMPFAIL) 179559163Seric *pstat = EX_TEMPFAIL; 179659541Seric } 17977682Seric 17988181Seric /* 17998959Seric ** Do any final sanitation the address may require. 18008959Seric ** This will normally be used to turn internal forms 18018959Seric ** (e.g., user@host.LOCAL) into external form. This 18028959Seric ** may be used as a default to the above rules. 18038959Seric */ 18048959Seric 180565071Seric if (rewrite(pvp, 4, 0, e) == EX_TEMPFAIL) 180659163Seric *pstat = EX_TEMPFAIL; 18078959Seric 18088959Seric /* 18098181Seric ** Now restore the comment information we had at the beginning. 18108181Seric */ 18118181Seric 181258825Seric cataddr(pvp, NULL, lbuf, sizeof lbuf, '\0'); 181356678Seric define('g', lbuf, e); 181465494Seric 181565494Seric /* need to make sure route-addrs have <angle brackets> */ 181665494Seric if (bitset(RF_CANONICAL, flags) && lbuf[0] == '@') 181765494Seric expand("<\201g>", buf, &buf[sizeof buf - 1], e); 181865494Seric else 181965494Seric expand(fancy, buf, &buf[sizeof buf - 1], e); 182065494Seric 182156678Seric define('g', oldg, e); 18227682Seric 18237682Seric if (tTd(12, 1)) 18247755Seric printf("remotename => `%s'\n", buf); 18257682Seric return (buf); 18267682Seric } 182751317Seric /* 182856678Seric ** MAPLOCALUSER -- run local username through ruleset 5 for final redirection 182951317Seric ** 183051317Seric ** Parameters: 183156678Seric ** a -- the address to map (but just the user name part). 183256678Seric ** sendq -- the sendq in which to install any replacement 183356678Seric ** addresses. 183467982Seric ** aliaslevel -- the alias nesting depth. 183567982Seric ** e -- the envelope. 183651317Seric ** 183751317Seric ** Returns: 183851317Seric ** none. 183951317Seric */ 184051317Seric 184167982Seric maplocaluser(a, sendq, aliaslevel, e) 184256678Seric register ADDRESS *a; 184356678Seric ADDRESS **sendq; 184467982Seric int aliaslevel; 184556678Seric ENVELOPE *e; 184651317Seric { 184756678Seric register char **pvp; 184856678Seric register ADDRESS *a1 = NULL; 184958333Seric auto char *delimptr; 185056678Seric char pvpbuf[PSBUFSIZE]; 185151317Seric 185256678Seric if (tTd(29, 1)) 185356678Seric { 185456678Seric printf("maplocaluser: "); 185556678Seric printaddr(a, FALSE); 185656678Seric } 185765066Seric pvp = prescan(a->q_user, '\0', pvpbuf, sizeof pvpbuf, &delimptr); 185856678Seric if (pvp == NULL) 185956678Seric return; 186051317Seric 186165071Seric (void) rewrite(pvp, 5, 0, e); 186258050Seric if (pvp[0] == NULL || (pvp[0][0] & 0377) != CANONNET) 186356678Seric return; 186451317Seric 186556678Seric /* if non-null, mailer destination specified -- has it changed? */ 186664284Seric a1 = buildaddr(pvp, NULL, 0, e); 186756678Seric if (a1 == NULL || sameaddr(a, a1)) 186856678Seric return; 186951317Seric 187056678Seric /* mark old address as dead; insert new address */ 187156678Seric a->q_flags |= QDONTSEND; 187257731Seric if (tTd(29, 5)) 187357731Seric { 187457731Seric printf("maplocaluser: QDONTSEND "); 187557731Seric printaddr(a, FALSE); 187657731Seric } 187756678Seric a1->q_alias = a; 187864348Seric allocaddr(a1, RF_COPYALL, NULL); 187967982Seric (void) recipient(a1, sendq, aliaslevel, e); 188051317Seric } 188158802Seric /* 188258802Seric ** DEQUOTE_INIT -- initialize dequote map 188358802Seric ** 188458802Seric ** This is a no-op. 188558802Seric ** 188658802Seric ** Parameters: 188758802Seric ** map -- the internal map structure. 188858802Seric ** args -- arguments. 188958802Seric ** 189058802Seric ** Returns: 189158802Seric ** TRUE. 189258802Seric */ 189358802Seric 189458802Seric bool 189560219Seric dequote_init(map, args) 189658802Seric MAP *map; 189758802Seric char *args; 189858802Seric { 189958805Seric register char *p = args; 190058805Seric 190158805Seric for (;;) 190258805Seric { 190358805Seric while (isascii(*p) && isspace(*p)) 190458805Seric p++; 190558805Seric if (*p != '-') 190658805Seric break; 190758805Seric switch (*++p) 190858805Seric { 190958805Seric case 'a': 191058805Seric map->map_app = ++p; 191158805Seric break; 191267824Seric 191367824Seric case 's': 191467824Seric map->map_coldelim = *++p; 191567824Seric break; 191658805Seric } 191758805Seric while (*p != '\0' && !(isascii(*p) && isspace(*p))) 191858805Seric p++; 191958805Seric if (*p != '\0') 192058805Seric *p = '\0'; 192158805Seric } 192258805Seric if (map->map_app != NULL) 192358805Seric map->map_app = newstr(map->map_app); 192458805Seric 192558802Seric return TRUE; 192658802Seric } 192758802Seric /* 192858802Seric ** DEQUOTE_MAP -- unquote an address 192958802Seric ** 193058802Seric ** Parameters: 193158802Seric ** map -- the internal map structure (ignored). 193260089Seric ** name -- the name to dequote. 193358802Seric ** av -- arguments (ignored). 193459084Seric ** statp -- pointer to status out-parameter. 193558802Seric ** 193658802Seric ** Returns: 193758802Seric ** NULL -- if there were no quotes, or if the resulting 193858802Seric ** unquoted buffer would not be acceptable to prescan. 193958802Seric ** else -- The dequoted buffer. 194058802Seric */ 194158802Seric 194258802Seric char * 194360089Seric dequote_map(map, name, av, statp) 194458802Seric MAP *map; 194560089Seric char *name; 194658802Seric char **av; 194759084Seric int *statp; 194858802Seric { 194958802Seric register char *p; 195058802Seric register char *q; 195158802Seric register char c; 195267824Seric int anglecnt = 0; 195367824Seric int cmntcnt = 0; 195467824Seric int quotecnt = 0; 195567824Seric int spacecnt = 0; 195667824Seric bool quotemode = FALSE; 195767824Seric bool bslashmode = FALSE; 195867824Seric char spacesub = map->map_coldelim; 195958802Seric 196060089Seric for (p = q = name; (c = *p++) != '\0'; ) 196158802Seric { 196258802Seric if (bslashmode) 196358802Seric { 196458802Seric bslashmode = FALSE; 196558802Seric *q++ = c; 196658802Seric continue; 196758802Seric } 196858802Seric 196967824Seric if (c == ' ' && spacesub != '\0') 197067824Seric c = spacesub; 197167764Seric 197258802Seric switch (c) 197358802Seric { 197458802Seric case '\\': 197558802Seric bslashmode = TRUE; 197658802Seric break; 197758802Seric 197858802Seric case '(': 197958802Seric cmntcnt++; 198058802Seric break; 198158802Seric 198258802Seric case ')': 198358802Seric if (cmntcnt-- <= 0) 198458802Seric return NULL; 198558802Seric break; 198659089Seric 198759089Seric case ' ': 198859089Seric spacecnt++; 198959089Seric break; 199058802Seric } 199158802Seric 199258802Seric if (cmntcnt > 0) 199358802Seric { 199458802Seric *q++ = c; 199558802Seric continue; 199658802Seric } 199758802Seric 199858802Seric switch (c) 199958802Seric { 200058802Seric case '"': 200158802Seric quotemode = !quotemode; 200258802Seric quotecnt++; 200358802Seric continue; 200458802Seric 200558802Seric case '<': 200658802Seric anglecnt++; 200758802Seric break; 200858802Seric 200958802Seric case '>': 201058802Seric if (anglecnt-- <= 0) 201158802Seric return NULL; 201258802Seric break; 201358802Seric } 201458802Seric *q++ = c; 201558802Seric } 201658802Seric 201758802Seric if (anglecnt != 0 || cmntcnt != 0 || bslashmode || 201859089Seric quotemode || quotecnt <= 0 || spacecnt != 0) 201958802Seric return NULL; 202058802Seric *q++ = '\0'; 202160089Seric return name; 202258802Seric } 2023