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*68559Seric static char sccsid[] = "@(#)parseaddr.c 8.59 (Berkeley) 03/21/95"; 1133730Sbostic #endif /* not lint */ 1222976Smiriam 1356678Seric # include "sendmail.h" 14297Seric 15297Seric /* 169888Seric ** PARSEADDR -- Parse an address 17297Seric ** 18297Seric ** Parses an address and breaks it up into three parts: a 19297Seric ** net to transmit the message on, the host to transmit it 20297Seric ** to, and a user on that host. These are loaded into an 212973Seric ** ADDRESS header with the values squirreled away if necessary. 22297Seric ** The "user" part may not be a real user; the process may 23297Seric ** just reoccur on that machine. For example, on a machine 24297Seric ** with an arpanet connection, the address 25297Seric ** csvax.bill@berkeley 26297Seric ** will break up to a "user" of 'csvax.bill' and a host 27297Seric ** of 'berkeley' -- to be transmitted over the arpanet. 28297Seric ** 29297Seric ** Parameters: 30297Seric ** addr -- the address to parse. 31297Seric ** a -- a pointer to the address descriptor buffer. 32297Seric ** If NULL, a header will be created. 3364284Seric ** flags -- describe detail for parsing. See RF_ definitions 3464284Seric ** in sendmail.h. 3511445Seric ** delim -- the character to terminate the address, passed 3611445Seric ** to prescan. 3758333Seric ** delimptr -- if non-NULL, set to the location of the 3858333Seric ** delim character that was found. 3956678Seric ** e -- the envelope that will contain this address. 40297Seric ** 41297Seric ** Returns: 42297Seric ** A pointer to the address descriptor header (`a' if 43297Seric ** `a' is non-NULL). 44297Seric ** NULL on error. 45297Seric ** 46297Seric ** Side Effects: 47297Seric ** none 48297Seric */ 49297Seric 509374Seric /* following delimiters are inherent to the internal algorithms */ 5159278Seric # define DELIMCHARS "()<>,;\r\n" /* default word delimiters */ 522091Seric 532973Seric ADDRESS * 5464284Seric parseaddr(addr, a, flags, delim, delimptr, e) 55297Seric char *addr; 562973Seric register ADDRESS *a; 5764284Seric int flags; 5859700Seric int delim; 5958333Seric char **delimptr; 6056678Seric register ENVELOPE *e; 61297Seric { 623149Seric register char **pvp; 6358333Seric auto char *delimptrbuf; 6459084Seric bool queueup; 6516914Seric char pvpbuf[PSBUFSIZE]; 6656678Seric extern ADDRESS *buildaddr(); 6757388Seric extern bool invalidaddr(); 68297Seric 69297Seric /* 70297Seric ** Initialize and prescan address. 71297Seric */ 72297Seric 7356678Seric e->e_to = addr; 747675Seric if (tTd(20, 1)) 759888Seric printf("\n--parseaddr(%s)\n", addr); 763188Seric 7758333Seric if (delimptr == NULL) 7858333Seric delimptr = &delimptrbuf; 7958333Seric 8065066Seric pvp = prescan(addr, delim, pvpbuf, sizeof pvpbuf, delimptr); 813149Seric if (pvp == NULL) 8256729Seric { 8356729Seric if (tTd(20, 1)) 8456729Seric printf("parseaddr-->NULL\n"); 85297Seric return (NULL); 8656729Seric } 87297Seric 8864726Seric if (invalidaddr(addr, delim == '\0' ? NULL : *delimptr)) 8964726Seric { 9064726Seric if (tTd(20, 1)) 9164726Seric printf("parseaddr-->bad address\n"); 9264726Seric return NULL; 9364726Seric } 9464726Seric 95297Seric /* 9664348Seric ** Save addr if we are going to have to. 9764348Seric ** 9864348Seric ** We have to do this early because there is a chance that 9964348Seric ** the map lookups in the rewriting rules could clobber 10064348Seric ** static memory somewhere. 10164348Seric */ 10264348Seric 10364348Seric if (bitset(RF_COPYPADDR, flags) && addr != NULL) 10464348Seric { 10564348Seric char savec = **delimptr; 10664348Seric 10764348Seric if (savec != '\0') 10864348Seric **delimptr = '\0'; 10966794Seric e->e_to = addr = newstr(addr); 11064348Seric if (savec != '\0') 11164348Seric **delimptr = savec; 11264348Seric } 11364348Seric 11464348Seric /* 1153149Seric ** Apply rewriting rules. 1167889Seric ** Ruleset 0 does basic parsing. It must resolve. 117297Seric */ 118297Seric 11959084Seric queueup = FALSE; 12065071Seric if (rewrite(pvp, 3, 0, e) == EX_TEMPFAIL) 12159084Seric queueup = TRUE; 12265071Seric if (rewrite(pvp, 0, 0, e) == EX_TEMPFAIL) 12359084Seric queueup = TRUE; 124297Seric 125297Seric 126297Seric /* 1273149Seric ** Build canonical address from pvp. 128297Seric */ 129297Seric 13064284Seric a = buildaddr(pvp, a, flags, e); 131297Seric 132297Seric /* 1333149Seric ** Make local copies of the host & user and then 1343149Seric ** transport them out. 135297Seric */ 136297Seric 13764348Seric allocaddr(a, flags, addr); 13864306Seric if (bitset(QBADADDR, a->q_flags)) 13964306Seric return a; 14056678Seric 14156678Seric /* 14259084Seric ** If there was a parsing failure, mark it for queueing. 14359084Seric */ 14459084Seric 14559084Seric if (queueup) 14659595Seric { 14759734Seric char *msg = "Transient parse error -- message queued for future delivery"; 14859734Seric 14959595Seric if (tTd(20, 1)) 15059595Seric printf("parseaddr: queuing message\n"); 15159734Seric message(msg); 15259734Seric if (e->e_message == NULL) 15360009Seric e->e_message = newstr(msg); 15459084Seric a->q_flags |= QQUEUEUP; 15568358Seric a->q_status = "4.4.3"; 15659595Seric } 15759084Seric 15859084Seric /* 15956678Seric ** Compute return value. 16056678Seric */ 16156678Seric 16256678Seric if (tTd(20, 1)) 1638078Seric { 16456678Seric printf("parseaddr-->"); 16556678Seric printaddr(a, FALSE); 16656678Seric } 16756678Seric 16856678Seric return (a); 16956678Seric } 17056678Seric /* 17157388Seric ** INVALIDADDR -- check for address containing meta-characters 17257388Seric ** 17357388Seric ** Parameters: 17457388Seric ** addr -- the address to check. 17557388Seric ** 17657388Seric ** Returns: 17757388Seric ** TRUE -- if the address has any "wierd" characters 17857388Seric ** FALSE -- otherwise. 17957388Seric */ 18057388Seric 18157388Seric bool 18264726Seric invalidaddr(addr, delimptr) 18357388Seric register char *addr; 18464726Seric char *delimptr; 18557388Seric { 18668433Seric char savedelim = '\0'; 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 { 20968400Seric if (delimptr != NULL && savedelim != '\0') 21064764Seric *delimptr = savedelim; 21164726Seric return FALSE; 21264764Seric } 21364726Seric setstat(EX_USAGE); 21464726Seric usrerr("553 Address contained invalid control characters"); 21564764Seric addrfailure: 21668446Seric if (delimptr != NULL && savedelim != '\0') 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; 37468529Seric expand("\201o", 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"); 41568526Seric if (strlen(addr) > MAXNAME) 41668526Seric addr[MAXNAME] = '\0'; 41765015Seric returnnull: 41858333Seric if (delimptr != NULL) 41958333Seric *delimptr = p; 42059747Seric CurEnv->e_to = saveto; 4218078Seric return (NULL); 4228078Seric } 42315284Seric 42415284Seric /* squirrel it away */ 4258078Seric *q++ = c; 4268078Seric } 4278078Seric 4288078Seric /* read a new input character */ 4298078Seric c = *p++; 43057631Seric if (c == '\0') 43156764Seric { 43256764Seric /* diagnose and patch up bad syntax */ 43356764Seric if (state == QST) 43456764Seric { 43564767Seric usrerr("653 Unbalanced '\"'"); 43656764Seric c = '"'; 43756764Seric } 43856764Seric else if (cmntcnt > 0) 43956764Seric { 44064767Seric usrerr("653 Unbalanced '('"); 44156764Seric c = ')'; 44256764Seric } 44356764Seric else if (anglecnt > 0) 44456764Seric { 44556764Seric c = '>'; 44664767Seric usrerr("653 Unbalanced '<'"); 44756764Seric } 44856764Seric else 44956764Seric break; 45015284Seric 45156764Seric p--; 45256764Seric } 45357631Seric else if (c == delim && anglecnt <= 0 && 45457631Seric cmntcnt <= 0 && state != QST) 45557631Seric break; 45656764Seric 4578078Seric if (tTd(22, 101)) 4588078Seric printf("c=%c, s=%d; ", c, state); 4598078Seric 4603149Seric /* chew up special characters */ 4613149Seric *q = '\0'; 4623149Seric if (bslashmode) 4633149Seric { 46459105Seric bslashmode = FALSE; 46559105Seric 46624944Seric /* kludge \! for naive users */ 46758061Seric if (cmntcnt > 0) 46859105Seric { 46958061Seric c = NOCHAR; 47059105Seric continue; 47159105Seric } 47259105Seric else if (c != '!' || state == QST) 47359105Seric { 47456678Seric *q++ = '\\'; 47559105Seric continue; 47659105Seric } 4773149Seric } 47856678Seric 47956678Seric if (c == '\\') 4803149Seric { 4813149Seric bslashmode = TRUE; 4823149Seric } 48356678Seric else if (state == QST) 4848514Seric { 4858514Seric /* do nothing, just avoid next clauses */ 4868514Seric } 4878078Seric else if (c == '(') 4884100Seric { 4898078Seric cmntcnt++; 4908078Seric c = NOCHAR; 4914100Seric } 4928078Seric else if (c == ')') 4933149Seric { 4948078Seric if (cmntcnt <= 0) 4953149Seric { 49664767Seric usrerr("653 Unbalanced ')'"); 49763844Seric c = NOCHAR; 4983149Seric } 4998078Seric else 5008078Seric cmntcnt--; 5018078Seric } 5028078Seric else if (cmntcnt > 0) 5038078Seric c = NOCHAR; 5048423Seric else if (c == '<') 5058423Seric anglecnt++; 5068423Seric else if (c == '>') 5078423Seric { 5088423Seric if (anglecnt <= 0) 5098423Seric { 51064767Seric usrerr("653 Unbalanced '>'"); 51163844Seric c = NOCHAR; 5128423Seric } 51363844Seric else 51463844Seric anglecnt--; 5158423Seric } 51658050Seric else if (delim == ' ' && isascii(c) && isspace(c)) 51711423Seric c = ' '; 5183149Seric 5198078Seric if (c == NOCHAR) 5208078Seric continue; 5213149Seric 5228078Seric /* see if this is end of input */ 52311405Seric if (c == delim && anglecnt <= 0 && state != QST) 5243149Seric break; 5253149Seric 5268078Seric newstate = StateTab[state][toktype(c)]; 5278078Seric if (tTd(22, 101)) 5288078Seric printf("ns=%02o\n", newstate); 5298078Seric state = newstate & TYPE; 5308078Seric if (bitset(M, newstate)) 5318078Seric c = NOCHAR; 5328078Seric if (bitset(B, newstate)) 5334228Seric break; 534297Seric } 5353149Seric 5363149Seric /* new token */ 5378078Seric if (tok != q) 5381378Seric { 5398078Seric *q++ = '\0'; 5408078Seric if (tTd(22, 36)) 541297Seric { 5428078Seric printf("tok="); 5438078Seric xputs(tok); 54423109Seric (void) putchar('\n'); 545297Seric } 5468078Seric if (avp >= &av[MAXATOM]) 547297Seric { 54858151Seric syserr("553 prescan: too many tokens"); 54965015Seric goto returnnull; 550297Seric } 55165015Seric if (q - tok > MAXNAME) 55265015Seric { 55365015Seric syserr("553 prescan: token too long"); 55465015Seric goto returnnull; 55565015Seric } 5568078Seric *avp++ = tok; 557297Seric } 5588423Seric } while (c != '\0' && (c != delim || anglecnt > 0)); 5593149Seric *avp = NULL; 56058333Seric p--; 56158333Seric if (delimptr != NULL) 56258333Seric *delimptr = p; 56356764Seric if (tTd(22, 12)) 56456764Seric { 56556764Seric printf("prescan==>"); 56656764Seric printav(av); 56756764Seric } 56859747Seric CurEnv->e_to = saveto; 56958546Seric if (av[0] == NULL) 57064966Seric { 57164966Seric if (tTd(22, 1)) 57264966Seric printf("prescan: null leading token\n"); 57358546Seric return (NULL); 57464966Seric } 57558403Seric return (av); 5763149Seric } 5773149Seric /* 5783149Seric ** REWRITE -- apply rewrite rules to token vector. 5793149Seric ** 5804476Seric ** This routine is an ordered production system. Each rewrite 5814476Seric ** rule has a LHS (called the pattern) and a RHS (called the 5824476Seric ** rewrite); 'rwr' points the the current rewrite rule. 5834476Seric ** 5844476Seric ** For each rewrite rule, 'avp' points the address vector we 5854476Seric ** are trying to match against, and 'pvp' points to the pattern. 5868058Seric ** If pvp points to a special match value (MATCHZANY, MATCHANY, 5879585Seric ** MATCHONE, MATCHCLASS, MATCHNCLASS) then the address in avp 5889585Seric ** matched is saved away in the match vector (pointed to by 'mvp'). 5894476Seric ** 5904476Seric ** When a match between avp & pvp does not match, we try to 5919585Seric ** back out. If we back up over MATCHONE, MATCHCLASS, or MATCHNCLASS 5924476Seric ** we must also back out the match in mvp. If we reach a 5938058Seric ** MATCHANY or MATCHZANY we just extend the match and start 5948058Seric ** over again. 5954476Seric ** 5964476Seric ** When we finally match, we rewrite the address vector 5974476Seric ** and try over again. 5984476Seric ** 5993149Seric ** Parameters: 6003149Seric ** pvp -- pointer to token vector. 60159027Seric ** ruleset -- the ruleset to use for rewriting. 60265071Seric ** reclevel -- recursion level (to catch loops). 60359027Seric ** e -- the current envelope. 6043149Seric ** 6053149Seric ** Returns: 60659084Seric ** A status code. If EX_TEMPFAIL, higher level code should 60759084Seric ** attempt recovery. 6083149Seric ** 6093149Seric ** Side Effects: 6103149Seric ** pvp is modified. 6113149Seric */ 6122091Seric 6133149Seric struct match 6143149Seric { 6154468Seric char **first; /* first token matched */ 6164468Seric char **last; /* last token matched */ 61758825Seric char **pattern; /* pointer to pattern */ 6183149Seric }; 6193149Seric 6204468Seric # define MAXMATCH 9 /* max params per rewrite */ 6213149Seric 62265136Seric # ifndef MAXRULERECURSION 62365136Seric # define MAXRULERECURSION 50 /* max recursion depth */ 62465136Seric # endif 6253149Seric 62665136Seric 62759084Seric int 62865071Seric rewrite(pvp, ruleset, reclevel, e) 6293149Seric char **pvp; 6304070Seric int ruleset; 63165071Seric int reclevel; 63259027Seric register ENVELOPE *e; 6333149Seric { 6343149Seric register char *ap; /* address pointer */ 6353149Seric register char *rp; /* rewrite pointer */ 6363149Seric register char **avp; /* address vector pointer */ 6373149Seric register char **rvp; /* rewrite vector pointer */ 6388058Seric register struct match *mlp; /* cur ptr into mlist */ 6398058Seric register struct rewrite *rwr; /* pointer to current rewrite rule */ 64058866Seric int ruleno; /* current rule number */ 64159084Seric int rstat = EX_OK; /* return status */ 64264740Seric int loopcount; 64356678Seric struct match mlist[MAXMATCH]; /* stores match on LHS */ 6443149Seric char *npvp[MAXATOM+1]; /* temporary space for rebuild */ 6453149Seric 64667262Seric if (OpMode == MD_TEST || tTd(21, 1)) 6473149Seric { 6488959Seric printf("rewrite: ruleset %2d input:", ruleset); 64956678Seric printav(pvp); 6503149Seric } 65156678Seric if (ruleset < 0 || ruleset >= MAXRWSETS) 65256326Seric { 65358151Seric syserr("554 rewrite: illegal ruleset number %d", ruleset); 65459084Seric return EX_CONFIG; 65556326Seric } 65665136Seric if (reclevel++ > MAXRULERECURSION) 65765071Seric { 65865071Seric syserr("rewrite: infinite recursion, ruleset %d", ruleset); 65965071Seric return EX_CONFIG; 66065071Seric } 66156678Seric if (pvp == NULL) 66259084Seric return EX_USAGE; 66356326Seric 6643149Seric /* 66556678Seric ** Run through the list of rewrite rules, applying 66656678Seric ** any that match. 6673149Seric */ 6683149Seric 66958866Seric ruleno = 1; 67064740Seric loopcount = 0; 6714070Seric for (rwr = RewriteRules[ruleset]; rwr != NULL; ) 6723149Seric { 6737675Seric if (tTd(21, 12)) 674297Seric { 6758069Seric printf("-----trying rule:"); 67656678Seric printav(rwr->r_lhs); 6773149Seric } 6783149Seric 6793149Seric /* try to match on this rule */ 6804468Seric mlp = mlist; 6818058Seric rvp = rwr->r_lhs; 6828058Seric avp = pvp; 68358866Seric if (++loopcount > 100) 6843149Seric { 68558866Seric syserr("554 Infinite loop in ruleset %d, rule %d", 68658866Seric ruleset, ruleno); 68758866Seric if (tTd(21, 1)) 68852637Seric { 68956678Seric printf("workspace: "); 69056678Seric printav(pvp); 69152637Seric } 69258866Seric break; 69358866Seric } 69458866Seric 69558866Seric while ((ap = *avp) != NULL || *rvp != NULL) 69658866Seric { 6973149Seric rp = *rvp; 6988058Seric if (tTd(21, 35)) 6998058Seric { 70058825Seric printf("ADVANCE rp="); 70157531Seric xputs(rp); 70257532Seric printf(", ap="); 7038058Seric xputs(ap); 7048069Seric printf("\n"); 7058058Seric } 70656678Seric if (rp == NULL) 70756326Seric { 7083149Seric /* end-of-pattern before end-of-address */ 7098058Seric goto backup; 71056678Seric } 71158173Seric if (ap == NULL && (*rp & 0377) != MATCHZANY && 71258827Seric (*rp & 0377) != MATCHZERO) 71356326Seric { 71458825Seric /* end-of-input with patterns left */ 71558825Seric goto backup; 716297Seric } 71756326Seric 71858050Seric switch (*rp & 0377) 7198058Seric { 72058814Seric char buf[MAXLINE]; 72156326Seric 72256678Seric case MATCHCLASS: 72358825Seric /* match any phrase in a class */ 72458825Seric mlp->pattern = rvp; 72558814Seric mlp->first = avp; 72658814Seric extendclass: 72758825Seric ap = *avp; 72858825Seric if (ap == NULL) 72958814Seric goto backup; 73058814Seric mlp->last = avp++; 73158814Seric cataddr(mlp->first, mlp->last, buf, sizeof buf, '\0'); 73268199Seric if (!wordinclass(buf, rp[1])) 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 */ 75168199Seric if (wordinclass(ap, rp[1])) 75258825Seric goto backup; 75358825Seric 75458825Seric /* fall through */ 75558825Seric 75656678Seric case MATCHONE: 75756678Seric case MATCHANY: 75856678Seric /* match exactly one token */ 75958825Seric mlp->pattern = rvp; 76056678Seric mlp->first = avp; 76156678Seric mlp->last = avp++; 7628058Seric mlp++; 76356678Seric break; 7648058Seric 76556678Seric case MATCHZANY: 76656678Seric /* match zero or more tokens */ 76758825Seric mlp->pattern = rvp; 76856678Seric mlp->first = avp; 76956678Seric mlp->last = avp - 1; 77056678Seric mlp++; 77156678Seric break; 77256326Seric 77358827Seric case MATCHZERO: 77458173Seric /* match zero tokens */ 77558173Seric break; 77658173Seric 77759027Seric case MACRODEXPAND: 77859027Seric /* 77959027Seric ** Match against run-time macro. 78059027Seric ** This algorithm is broken for the 78159027Seric ** general case (no recursive macros, 78259027Seric ** improper tokenization) but should 78359027Seric ** work for the usual cases. 78459027Seric */ 78559027Seric 78659027Seric ap = macvalue(rp[1], e); 78759027Seric mlp->first = avp; 78859027Seric if (tTd(21, 2)) 78959027Seric printf("rewrite: LHS $&%c => \"%s\"\n", 79059027Seric rp[1], 79159027Seric ap == NULL ? "(NULL)" : ap); 79259027Seric 79359027Seric if (ap == NULL) 79459027Seric break; 79560502Seric while (*ap != '\0') 79659027Seric { 79759027Seric if (*avp == NULL || 79859027Seric strncasecmp(ap, *avp, strlen(*avp)) != 0) 79959027Seric { 80059027Seric /* no match */ 80159027Seric avp = mlp->first; 80259027Seric goto backup; 80359027Seric } 80459027Seric ap += strlen(*avp++); 80559027Seric } 80659027Seric 80759027Seric /* match */ 80859027Seric break; 80959027Seric 81056678Seric default: 81156678Seric /* must have exact match */ 81256678Seric if (strcasecmp(rp, ap)) 8138058Seric goto backup; 8144468Seric avp++; 81556678Seric break; 8163149Seric } 8173149Seric 81856678Seric /* successful match on this token */ 8193149Seric rvp++; 8203149Seric continue; 8213149Seric 82258825Seric backup: 82356678Seric /* match failed -- back up */ 82458825Seric while (--mlp >= mlist) 8253149Seric { 82658825Seric rvp = mlp->pattern; 82756678Seric rp = *rvp; 82858825Seric avp = mlp->last + 1; 82958825Seric ap = *avp; 83058825Seric 83158825Seric if (tTd(21, 36)) 83258825Seric { 83358825Seric printf("BACKUP rp="); 83458825Seric xputs(rp); 83558825Seric printf(", ap="); 83658825Seric xputs(ap); 83758825Seric printf("\n"); 83858825Seric } 83958825Seric 84058825Seric if (ap == NULL) 84158825Seric { 84258825Seric /* run off the end -- back up again */ 84358825Seric continue; 84458825Seric } 84558050Seric if ((*rp & 0377) == MATCHANY || 84658050Seric (*rp & 0377) == MATCHZANY) 8474468Seric { 84856678Seric /* extend binding and continue */ 84958825Seric mlp->last = avp++; 85056678Seric rvp++; 85158825Seric mlp++; 85256678Seric break; 8534468Seric } 85458825Seric if ((*rp & 0377) == MATCHCLASS) 85556678Seric { 85658814Seric /* extend binding and try again */ 85763397Seric mlp->last = avp; 85858814Seric goto extendclass; 85958814Seric } 8603149Seric } 8613149Seric 86258825Seric if (mlp < mlist) 86356678Seric { 86456678Seric /* total failure to match */ 86556326Seric break; 8663149Seric } 867297Seric } 8683149Seric 8693149Seric /* 87056678Seric ** See if we successfully matched 8713149Seric */ 8723149Seric 87358827Seric if (mlp < mlist || *rvp != NULL) 8743149Seric { 8759374Seric if (tTd(21, 10)) 8769374Seric printf("----- rule fails\n"); 8779374Seric rwr = rwr->r_next; 87858866Seric ruleno++; 87964740Seric loopcount = 0; 8809374Seric continue; 8819374Seric } 8823149Seric 8839374Seric rvp = rwr->r_rhs; 8849374Seric if (tTd(21, 12)) 8859374Seric { 8869374Seric printf("-----rule matches:"); 88756678Seric printav(rvp); 8889374Seric } 8899374Seric 8909374Seric rp = *rvp; 89158050Seric if ((*rp & 0377) == CANONUSER) 8929374Seric { 8939374Seric rvp++; 8949374Seric rwr = rwr->r_next; 89558866Seric ruleno++; 89664740Seric loopcount = 0; 8979374Seric } 89858050Seric else if ((*rp & 0377) == CANONHOST) 8999374Seric { 9009374Seric rvp++; 9019374Seric rwr = NULL; 9029374Seric } 90358050Seric else if ((*rp & 0377) == CANONNET) 9049374Seric rwr = NULL; 9059374Seric 9069374Seric /* substitute */ 9079374Seric for (avp = npvp; *rvp != NULL; rvp++) 9089374Seric { 9099374Seric register struct match *m; 9109374Seric register char **pp; 9119374Seric 9128058Seric rp = *rvp; 91358050Seric if ((*rp & 0377) == MATCHREPL) 9148058Seric { 91516914Seric /* substitute from LHS */ 91616914Seric m = &mlist[rp[1] - '1']; 91756678Seric if (m < mlist || m >= mlp) 9189374Seric { 91958151Seric syserr("554 rewrite: ruleset %d: replacement $%c out of bounds", 92056326Seric ruleset, rp[1]); 92159084Seric return EX_CONFIG; 9229374Seric } 92316914Seric if (tTd(21, 15)) 92416914Seric { 92516914Seric printf("$%c:", rp[1]); 92616914Seric pp = m->first; 92756678Seric while (pp <= m->last) 92816914Seric { 92916914Seric printf(" %x=\"", *pp); 93016914Seric (void) fflush(stdout); 93116914Seric printf("%s\"", *pp++); 93216914Seric } 93316914Seric printf("\n"); 93416914Seric } 9359374Seric pp = m->first; 93656678Seric while (pp <= m->last) 9373149Seric { 93816914Seric if (avp >= &npvp[MAXATOM]) 93956678Seric { 94058151Seric syserr("554 rewrite: expansion too long"); 94159084Seric return EX_DATAERR; 94256678Seric } 94316914Seric *avp++ = *pp++; 9443149Seric } 9453149Seric } 94616914Seric else 9478226Seric { 94816914Seric /* vanilla replacement */ 9499374Seric if (avp >= &npvp[MAXATOM]) 95016889Seric { 95156678Seric toolong: 95258151Seric syserr("554 rewrite: expansion too long"); 95359084Seric return EX_DATAERR; 95416889Seric } 95559027Seric if ((*rp & 0377) != MACRODEXPAND) 95659027Seric *avp++ = rp; 95759027Seric else 95859027Seric { 95959027Seric *avp = macvalue(rp[1], e); 96059027Seric if (tTd(21, 2)) 96159027Seric printf("rewrite: RHS $&%c => \"%s\"\n", 96259027Seric rp[1], 96359027Seric *avp == NULL ? "(NULL)" : *avp); 96459027Seric if (*avp != NULL) 96559027Seric avp++; 96659027Seric } 9678226Seric } 9689374Seric } 9699374Seric *avp++ = NULL; 97016914Seric 97116914Seric /* 97256678Seric ** Check for any hostname/keyword lookups. 97316914Seric */ 97416914Seric 97516914Seric for (rvp = npvp; *rvp != NULL; rvp++) 97616914Seric { 97756678Seric char **hbrvp; 97816914Seric char **xpvp; 97916914Seric int trsize; 98056678Seric char *replac; 98156678Seric int endtoken; 98256678Seric STAB *map; 98356678Seric char *mapname; 98456678Seric char **key_rvp; 98556678Seric char **arg_rvp; 98656678Seric char **default_rvp; 98756678Seric char buf[MAXNAME + 1]; 98816914Seric char *pvpb1[MAXATOM + 1]; 98956823Seric char *argvect[10]; 99017174Seric char pvpbuf[PSBUFSIZE]; 99164404Seric char *nullpvp[1]; 99216914Seric 99358050Seric if ((**rvp & 0377) != HOSTBEGIN && 99458050Seric (**rvp & 0377) != LOOKUPBEGIN) 99516914Seric continue; 99616914Seric 99716914Seric /* 99856678Seric ** Got a hostname/keyword lookup. 99916914Seric ** 100016914Seric ** This could be optimized fairly easily. 100116914Seric */ 100216914Seric 100316914Seric hbrvp = rvp; 100458050Seric if ((**rvp & 0377) == HOSTBEGIN) 100556327Seric { 100656678Seric endtoken = HOSTEND; 100756678Seric mapname = "host"; 100856327Seric } 100956326Seric else 101056327Seric { 101156678Seric endtoken = LOOKUPEND; 101256678Seric mapname = *++rvp; 101356327Seric } 101456678Seric map = stab(mapname, ST_MAP, ST_FIND); 101556678Seric if (map == NULL) 101658151Seric syserr("554 rewrite: map %s not found", mapname); 101756678Seric 101856678Seric /* extract the match part */ 101956678Seric key_rvp = ++rvp; 102056823Seric default_rvp = NULL; 102156823Seric arg_rvp = argvect; 102256823Seric xpvp = NULL; 102356823Seric replac = pvpbuf; 102458050Seric while (*rvp != NULL && (**rvp & 0377) != endtoken) 102553654Seric { 102658050Seric int nodetype = **rvp & 0377; 102756823Seric 102856823Seric if (nodetype != CANONHOST && nodetype != CANONUSER) 102956678Seric { 103056823Seric rvp++; 103156823Seric continue; 103256823Seric } 103356823Seric 103456823Seric *rvp++ = NULL; 103556823Seric 103656823Seric if (xpvp != NULL) 103756823Seric { 103858814Seric cataddr(xpvp, NULL, replac, 103958082Seric &pvpbuf[sizeof pvpbuf] - replac, 104058082Seric '\0'); 104156823Seric *++arg_rvp = replac; 104256823Seric replac += strlen(replac) + 1; 104356823Seric xpvp = NULL; 104456823Seric } 104556823Seric switch (nodetype) 104656823Seric { 104756678Seric case CANONHOST: 104856823Seric xpvp = rvp; 104956678Seric break; 105056678Seric 105156678Seric case CANONUSER: 105256678Seric default_rvp = rvp; 105356678Seric break; 105456678Seric } 105553654Seric } 105616914Seric if (*rvp != NULL) 105716914Seric *rvp++ = NULL; 105856823Seric if (xpvp != NULL) 105956823Seric { 106058814Seric cataddr(xpvp, NULL, replac, 106158082Seric &pvpbuf[sizeof pvpbuf] - replac, 106258082Seric '\0'); 106356823Seric *++arg_rvp = replac; 106456823Seric } 106556823Seric *++arg_rvp = NULL; 106616914Seric 106716914Seric /* save the remainder of the input string */ 106816914Seric trsize = (int) (avp - rvp + 1) * sizeof *rvp; 106916914Seric bcopy((char *) rvp, (char *) pvpb1, trsize); 107016914Seric 107156678Seric /* look it up */ 107258814Seric cataddr(key_rvp, NULL, buf, sizeof buf, '\0'); 107356823Seric argvect[0] = buf; 107460538Seric if (map != NULL && bitset(MF_OPEN, map->s_map.map_mflags)) 107556836Seric { 107659084Seric auto int stat = EX_OK; 107756836Seric 107860215Seric /* XXX should try to auto-open the map here */ 107960215Seric 108058796Seric if (tTd(60, 1)) 108158796Seric printf("map_lookup(%s, %s) => ", 108258796Seric mapname, buf); 108356836Seric replac = (*map->s_map.map_class->map_lookup)(&map->s_map, 108460089Seric buf, argvect, &stat); 108558796Seric if (tTd(60, 1)) 108659084Seric printf("%s (%d)\n", 108759084Seric replac ? replac : "NOT FOUND", 108859084Seric stat); 108959084Seric 109059084Seric /* should recover if stat == EX_TEMPFAIL */ 109159084Seric if (stat == EX_TEMPFAIL) 109259084Seric rstat = stat; 109356836Seric } 109453654Seric else 109556678Seric replac = NULL; 109656678Seric 109756678Seric /* if no replacement, use default */ 109856823Seric if (replac == NULL && default_rvp != NULL) 109956823Seric { 110060089Seric /* create the default */ 110160089Seric cataddr(default_rvp, NULL, buf, sizeof buf, '\0'); 110256823Seric replac = buf; 110356823Seric } 110456823Seric 110556678Seric if (replac == NULL) 110651317Seric { 110756823Seric xpvp = key_rvp; 110853654Seric } 110964404Seric else if (*replac == '\0') 111064404Seric { 111164404Seric /* null replacement */ 111264404Seric nullpvp[0] = NULL; 111364404Seric xpvp = nullpvp; 111464404Seric } 111556678Seric else 111653654Seric { 111756678Seric /* scan the new replacement */ 111865066Seric xpvp = prescan(replac, '\0', pvpbuf, 111965066Seric sizeof pvpbuf, NULL); 112053654Seric if (xpvp == NULL) 112151317Seric { 112258403Seric /* prescan already printed error */ 112359084Seric return EX_DATAERR; 112456678Seric } 112551317Seric } 112651317Seric 112716914Seric /* append it to the token list */ 112856678Seric for (avp = hbrvp; *xpvp != NULL; xpvp++) 112956678Seric { 113017174Seric *avp++ = newstr(*xpvp); 113116920Seric if (avp >= &npvp[MAXATOM]) 113216914Seric goto toolong; 113317174Seric } 113416914Seric 113516914Seric /* restore the old trailing information */ 113656678Seric for (xpvp = pvpb1; (*avp++ = *xpvp++) != NULL; ) 113716920Seric if (avp >= &npvp[MAXATOM]) 113816914Seric goto toolong; 113917174Seric 114056678Seric break; 114116914Seric } 114216914Seric 114316914Seric /* 114416914Seric ** Check for subroutine calls. 114516914Seric */ 114616914Seric 1147*68559Seric if (*npvp != NULL && (**npvp & 0377) == CALLSUBR) 1148*68559Seric { 1149*68559Seric int stat; 115059084Seric 1151*68559Seric if (npvp[1] == NULL) 1152*68559Seric { 1153*68559Seric syserr("parseaddr: NULL subroutine call in ruleset %d, rule %d", 1154*68559Seric ruleset, ruleno); 1155*68559Seric *pvp = NULL; 1156*68559Seric } 1157*68559Seric else 1158*68559Seric { 1159*68559Seric int ruleset; 1160*68559Seric STAB *s; 116168385Seric 1162*68559Seric bcopy((char *) &npvp[2], (char *) pvp, 1163*68559Seric (int) (avp - npvp - 2) * sizeof *avp); 1164*68559Seric if (tTd(21, 3)) 1165*68559Seric printf("-----callsubr %s\n", npvp[1]); 1166*68559Seric s = stab(npvp[1], ST_RULESET, ST_FIND); 1167*68559Seric if (s == NULL) 1168*68559Seric ruleset = atoi(npvp[1]); 1169*68559Seric else 1170*68559Seric ruleset = s->s_ruleset; 1171*68559Seric stat = rewrite(pvp, ruleset, reclevel, e); 1172*68559Seric if (rstat == EX_OK || stat == EX_TEMPFAIL) 1173*68559Seric rstat = stat; 1174*68559Seric if (*pvp != NULL && (**pvp & 0377) == CANONNET) 1175*68559Seric rwr = NULL; 1176*68559Seric } 1177*68559Seric } 1178*68559Seric else 1179*68559Seric { 1180*68559Seric bcopy((char *) npvp, (char *) pvp, 1181*68559Seric (int) (avp - npvp) * sizeof *avp); 1182*68559Seric } 11839374Seric if (tTd(21, 4)) 11849374Seric { 11859374Seric printf("rewritten as:"); 118656678Seric printav(pvp); 11879374Seric } 1188297Seric } 11898069Seric 119067262Seric if (OpMode == MD_TEST || tTd(21, 1)) 11918069Seric { 11928959Seric printf("rewrite: ruleset %2d returns:", ruleset); 119356678Seric printav(pvp); 11948069Seric } 119559084Seric 119659084Seric return rstat; 11973149Seric } 11983149Seric /* 11993149Seric ** BUILDADDR -- build address from token vector. 12003149Seric ** 12013149Seric ** Parameters: 12023149Seric ** tv -- token vector. 12033149Seric ** a -- pointer to address descriptor to fill. 12043149Seric ** If NULL, one will be allocated. 120564284Seric ** flags -- info regarding whether this is a sender or 120664284Seric ** a recipient. 120758966Seric ** e -- the current envelope. 12083149Seric ** 12093149Seric ** Returns: 12104279Seric ** NULL if there was an error. 12114279Seric ** 'a' otherwise. 12123149Seric ** 12133149Seric ** Side Effects: 12143149Seric ** fills in 'a' 12153149Seric */ 12163149Seric 121757249Seric struct errcodes 121857249Seric { 121957249Seric char *ec_name; /* name of error code */ 122057249Seric int ec_code; /* numeric code */ 122157249Seric } ErrorCodes[] = 122257249Seric { 122357249Seric "usage", EX_USAGE, 122457249Seric "nouser", EX_NOUSER, 122557249Seric "nohost", EX_NOHOST, 122657249Seric "unavailable", EX_UNAVAILABLE, 122757249Seric "software", EX_SOFTWARE, 122857249Seric "tempfail", EX_TEMPFAIL, 122957249Seric "protocol", EX_PROTOCOL, 123057249Seric #ifdef EX_CONFIG 123157249Seric "config", EX_CONFIG, 123257249Seric #endif 123357249Seric NULL, EX_UNAVAILABLE, 123457249Seric }; 123557249Seric 123656678Seric ADDRESS * 123764284Seric buildaddr(tv, a, flags, e) 12383149Seric register char **tv; 12393149Seric register ADDRESS *a; 124064284Seric int flags; 124158966Seric register ENVELOPE *e; 12423149Seric { 12433149Seric struct mailer **mp; 12443149Seric register struct mailer *m; 124558008Seric char *bp; 124658008Seric int spaceleft; 124764306Seric static MAILER errormailer; 124864306Seric static char *errorargv[] = { "ERROR", NULL }; 124968528Seric static char buf[MAXNAME + 1]; 12503149Seric 125164791Seric if (tTd(24, 5)) 125264791Seric { 125367693Seric printf("buildaddr, flags=%x, tv=", flags); 125464791Seric printav(tv); 125564791Seric } 125664791Seric 12573149Seric if (a == NULL) 12583149Seric a = (ADDRESS *) xalloc(sizeof *a); 125916889Seric bzero((char *) a, sizeof *a); 12603149Seric 126167880Seric /* set up default error return flags */ 126267963Seric a->q_flags |= QPINGONFAILURE|QPINGONDELAY; 126367880Seric 12643149Seric /* figure out what net/mailer to use */ 126564306Seric if (*tv == NULL || (**tv & 0377) != CANONNET) 12664279Seric { 126758151Seric syserr("554 buildaddr: no net"); 126864306Seric badaddr: 126964306Seric a->q_flags |= QBADADDR; 127064306Seric a->q_mailer = &errormailer; 127164306Seric if (errormailer.m_name == NULL) 127264306Seric { 127364306Seric /* initialize the bogus mailer */ 127464306Seric errormailer.m_name = "*error*"; 127564306Seric errormailer.m_mailer = "ERROR"; 127664306Seric errormailer.m_argv = errorargv; 127764306Seric } 127864306Seric return a; 12794279Seric } 12803149Seric tv++; 128158680Seric if (strcasecmp(*tv, "error") == 0) 12824279Seric { 128358050Seric if ((**++tv & 0377) == CANONHOST) 128410183Seric { 128557249Seric register struct errcodes *ep; 128657249Seric 128758050Seric if (isascii(**++tv) && isdigit(**tv)) 128857249Seric { 128957249Seric setstat(atoi(*tv)); 129057249Seric } 129157249Seric else 129257249Seric { 129357249Seric for (ep = ErrorCodes; ep->ec_name != NULL; ep++) 129457249Seric if (strcasecmp(ep->ec_name, *tv) == 0) 129557249Seric break; 129657249Seric setstat(ep->ec_code); 129757249Seric } 129810183Seric tv++; 129910183Seric } 130064928Seric else 130164928Seric setstat(EX_UNAVAILABLE); 130258050Seric if ((**tv & 0377) != CANONUSER) 130358151Seric syserr("554 buildaddr: error: no user"); 130458814Seric cataddr(++tv, NULL, buf, sizeof buf, ' '); 130558082Seric stripquotes(buf); 130664659Seric if (isascii(buf[0]) && isdigit(buf[0]) && 130764659Seric isascii(buf[1]) && isdigit(buf[1]) && 130864659Seric isascii(buf[2]) && isdigit(buf[2]) && 130964659Seric buf[3] == ' ') 131064659Seric { 131164659Seric char fmt[10]; 131264659Seric 131364659Seric strncpy(fmt, buf, 3); 131464659Seric strcpy(&fmt[3], " %s"); 131564659Seric usrerr(fmt, buf + 4); 131667786Seric 131767786Seric /* 131867786Seric ** If this is a 4xx code and we aren't running 131967786Seric ** SMTP on our input, bounce this message; 132067786Seric ** otherwise it disappears without a trace. 132167786Seric */ 132267786Seric 132367786Seric if (fmt[0] == '4' && OpMode != MD_SMTP && 132467786Seric OpMode != MD_DAEMON) 132567786Seric { 132667786Seric e->e_flags |= EF_FATALERRS; 132767786Seric } 132864659Seric } 132964659Seric else 133064659Seric { 133166039Seric usrerr("553 %s", buf); 133264659Seric } 133364306Seric goto badaddr; 13344279Seric } 133557402Seric 13364598Seric for (mp = Mailer; (m = *mp++) != NULL; ) 13373149Seric { 133858680Seric if (strcasecmp(m->m_name, *tv) == 0) 13393149Seric break; 13403149Seric } 13413149Seric if (m == NULL) 13424279Seric { 134358151Seric syserr("554 buildaddr: unknown mailer %s", *tv); 134464306Seric goto badaddr; 13454279Seric } 13464598Seric a->q_mailer = m; 13473149Seric 13483149Seric /* figure out what host (if any) */ 134956678Seric tv++; 135058509Seric if ((**tv & 0377) == CANONHOST) 13513149Seric { 135258008Seric bp = buf; 135358008Seric spaceleft = sizeof buf - 1; 135458050Seric while (*++tv != NULL && (**tv & 0377) != CANONUSER) 135558008Seric { 135658008Seric int i = strlen(*tv); 135758008Seric 135858008Seric if (i > spaceleft) 135958008Seric { 136058008Seric /* out of space for this address */ 136158008Seric if (spaceleft >= 0) 136258151Seric syserr("554 buildaddr: host too long (%.40s...)", 136358008Seric buf); 136458008Seric i = spaceleft; 136558008Seric spaceleft = 0; 136658008Seric } 136758008Seric if (i <= 0) 136858008Seric continue; 136958008Seric bcopy(*tv, bp, i); 137058008Seric bp += i; 137158008Seric spaceleft -= i; 137258008Seric } 137358010Seric *bp = '\0'; 13745704Seric a->q_host = newstr(buf); 13753149Seric } 137657249Seric else 137758509Seric { 137858509Seric if (!bitnset(M_LOCALMAILER, m->m_flags)) 137958509Seric { 138058509Seric syserr("554 buildaddr: no host"); 138164306Seric goto badaddr; 138258509Seric } 138357249Seric a->q_host = NULL; 138458509Seric } 13853149Seric 13863149Seric /* figure out the user */ 138758050Seric if (*tv == NULL || (**tv & 0377) != CANONUSER) 13884279Seric { 138958151Seric syserr("554 buildaddr: no user"); 139064306Seric goto badaddr; 13914279Seric } 139257402Seric tv++; 139351317Seric 139468098Seric if (bitnset(M_CHECKUDB, m->m_flags) && *tv != NULL && 139568098Seric strcmp(*tv, "@") == 0) 139668098Seric { 139768098Seric tv++; 139868098Seric a->q_flags |= QNOTREMOTE; 139968098Seric } 140068098Seric 140157402Seric /* do special mapping for local mailer */ 140267472Seric if (*tv != NULL) 140357402Seric { 140457454Seric register char *p = *tv; 140557454Seric 140657454Seric if (*p == '"') 140757454Seric p++; 140867472Seric if (*p == '|' && bitnset(M_CHECKPROG, m->m_flags)) 140957402Seric a->q_mailer = m = ProgMailer; 141067472Seric else if (*p == '/' && bitnset(M_CHECKFILE, m->m_flags)) 141157402Seric a->q_mailer = m = FileMailer; 141267472Seric else if (*p == ':' && bitnset(M_CHECKINCLUDE, m->m_flags)) 141357402Seric { 141457402Seric /* may be :include: */ 141558814Seric cataddr(tv, NULL, buf, sizeof buf, '\0'); 141658008Seric stripquotes(buf); 141758008Seric if (strncasecmp(buf, ":include:", 9) == 0) 141858008Seric { 141958008Seric /* if :include:, don't need further rewriting */ 142057402Seric a->q_mailer = m = InclMailer; 142158008Seric a->q_user = &buf[9]; 142258008Seric return (a); 142358008Seric } 142457402Seric } 142557402Seric } 142657402Seric 142764284Seric /* rewrite according recipient mailer rewriting rules */ 142864284Seric define('h', a->q_host, e); 142964284Seric if (!bitset(RF_SENDERADDR|RF_HEADERADDR, flags)) 143064284Seric { 143164284Seric /* sender addresses done later */ 143265071Seric (void) rewrite(tv, 2, 0, e); 143364284Seric if (m->m_re_rwset > 0) 143465071Seric (void) rewrite(tv, m->m_re_rwset, 0, e); 143564284Seric } 143665071Seric (void) rewrite(tv, 4, 0, e); 143719040Seric 143819040Seric /* save the result for the command line/RCPT argument */ 143958814Seric cataddr(tv, NULL, buf, sizeof buf, '\0'); 14403149Seric a->q_user = buf; 14413149Seric 144258670Seric /* 144358670Seric ** Do mapping to lower case as requested by mailer 144458670Seric */ 144558670Seric 144658670Seric if (a->q_host != NULL && !bitnset(M_HST_UPPER, m->m_flags)) 144758670Seric makelower(a->q_host); 144858670Seric if (!bitnset(M_USR_UPPER, m->m_flags)) 144958670Seric makelower(a->q_user); 145058670Seric 14513149Seric return (a); 14523149Seric } 14533188Seric /* 14544228Seric ** CATADDR -- concatenate pieces of addresses (putting in <LWSP> subs) 14554228Seric ** 14564228Seric ** Parameters: 14574228Seric ** pvp -- parameter vector to rebuild. 145858814Seric ** evp -- last parameter to include. Can be NULL to 145958814Seric ** use entire pvp. 14604228Seric ** buf -- buffer to build the string into. 14614228Seric ** sz -- size of buf. 146258082Seric ** spacesub -- the space separator character; if null, 146358082Seric ** use SpaceSub. 14644228Seric ** 14654228Seric ** Returns: 14664228Seric ** none. 14674228Seric ** 14684228Seric ** Side Effects: 14694228Seric ** Destroys buf. 14704228Seric */ 14714228Seric 147258814Seric cataddr(pvp, evp, buf, sz, spacesub) 14734228Seric char **pvp; 147458814Seric char **evp; 14754228Seric char *buf; 14764228Seric register int sz; 147758082Seric char spacesub; 14784228Seric { 14794228Seric bool oatomtok = FALSE; 148056678Seric bool natomtok = FALSE; 14814228Seric register int i; 14824228Seric register char *p; 14834228Seric 148458082Seric if (spacesub == '\0') 148558082Seric spacesub = SpaceSub; 148658082Seric 14878423Seric if (pvp == NULL) 14888423Seric { 148923109Seric (void) strcpy(buf, ""); 14908423Seric return; 14918423Seric } 14924228Seric p = buf; 149311156Seric sz -= 2; 14944228Seric while (*pvp != NULL && (i = strlen(*pvp)) < sz) 14954228Seric { 14968078Seric natomtok = (toktype(**pvp) == ATM); 14974228Seric if (oatomtok && natomtok) 149858082Seric *p++ = spacesub; 14994228Seric (void) strcpy(p, *pvp); 15004228Seric oatomtok = natomtok; 15014228Seric p += i; 150211156Seric sz -= i + 1; 150358814Seric if (pvp++ == evp) 150458814Seric break; 15054228Seric } 15064228Seric *p = '\0'; 15074228Seric } 15084228Seric /* 15093188Seric ** SAMEADDR -- Determine if two addresses are the same 15103188Seric ** 15113188Seric ** This is not just a straight comparison -- if the mailer doesn't 15123188Seric ** care about the host we just ignore it, etc. 15133188Seric ** 15143188Seric ** Parameters: 15153188Seric ** a, b -- pointers to the internal forms to compare. 15163188Seric ** 15173188Seric ** Returns: 15183188Seric ** TRUE -- they represent the same mailbox. 15193188Seric ** FALSE -- they don't. 15203188Seric ** 15213188Seric ** Side Effects: 15223188Seric ** none. 15233188Seric */ 15243188Seric 15253188Seric bool 15269374Seric sameaddr(a, b) 15273188Seric register ADDRESS *a; 15283188Seric register ADDRESS *b; 15293188Seric { 153065093Seric register ADDRESS *ca, *cb; 153165093Seric 15323188Seric /* if they don't have the same mailer, forget it */ 15333188Seric if (a->q_mailer != b->q_mailer) 15343188Seric return (FALSE); 15353188Seric 15363188Seric /* if the user isn't the same, we can drop out */ 153756678Seric if (strcmp(a->q_user, b->q_user) != 0) 15383188Seric return (FALSE); 15393188Seric 154065093Seric /* if we have good uids for both but they differ, these are different */ 154165379Seric if (a->q_mailer == ProgMailer) 154265379Seric { 154365379Seric ca = getctladdr(a); 154465379Seric cb = getctladdr(b); 154565379Seric if (ca != NULL && cb != NULL && 154665379Seric bitset(QGOODUID, ca->q_flags & cb->q_flags) && 154765379Seric ca->q_uid != cb->q_uid) 154865379Seric return (FALSE); 154965379Seric } 155058438Seric 155158509Seric /* otherwise compare hosts (but be careful for NULL ptrs) */ 155258509Seric if (a->q_host == b->q_host) 155358509Seric { 155458509Seric /* probably both null pointers */ 15553188Seric return (TRUE); 155658509Seric } 15573188Seric if (a->q_host == NULL || b->q_host == NULL) 155858509Seric { 155958509Seric /* only one is a null pointer */ 15603188Seric return (FALSE); 156158509Seric } 156256678Seric if (strcmp(a->q_host, b->q_host) != 0) 15633188Seric return (FALSE); 15643188Seric 15653188Seric return (TRUE); 15663188Seric } 15673234Seric /* 15683234Seric ** PRINTADDR -- print address (for debugging) 15693234Seric ** 15703234Seric ** Parameters: 15713234Seric ** a -- the address to print 15723234Seric ** follow -- follow the q_next chain. 15733234Seric ** 15743234Seric ** Returns: 15753234Seric ** none. 15763234Seric ** 15773234Seric ** Side Effects: 15783234Seric ** none. 15793234Seric */ 15803234Seric 158167994Seric struct qflags 158267994Seric { 158367994Seric char *qf_name; 158467994Seric u_long qf_bit; 158567994Seric }; 158667994Seric 158767994Seric struct qflags AddressFlags[] = 158867994Seric { 158967994Seric "QDONTSEND", QDONTSEND, 159067994Seric "QBADADDR", QBADADDR, 159167994Seric "QGOODUID", QGOODUID, 159267994Seric "QPRIMARY", QPRIMARY, 159367994Seric "QQUEUEUP", QQUEUEUP, 159467994Seric "QSENT", QSENT, 159567994Seric "QNOTREMOTE", QNOTREMOTE, 159667994Seric "QSELFREF", QSELFREF, 159767994Seric "QVERIFIED", QVERIFIED, 159867994Seric "QREPORT", QREPORT, 159967994Seric "QBOGUSSHELL", QBOGUSSHELL, 160067994Seric "QUNSAFEADDR", QUNSAFEADDR, 160167994Seric "QPINGONSUCCESS", QPINGONSUCCESS, 160267994Seric "QPINGONFAILURE", QPINGONFAILURE, 160367994Seric "QPINGONDELAY", QPINGONDELAY, 160467994Seric "QRELAYED", QRELAYED, 160567994Seric NULL 160667994Seric }; 160767994Seric 160868433Seric void 16093234Seric printaddr(a, follow) 16103234Seric register ADDRESS *a; 16113234Seric bool follow; 16123234Seric { 161357731Seric register MAILER *m; 161457731Seric MAILER pseudomailer; 161567994Seric register struct qflags *qfp; 161667994Seric bool firstone; 16175001Seric 161867994Seric if (a == NULL) 161967994Seric { 162067994Seric printf("[NULL]\n"); 162167994Seric return; 162267994Seric } 162367994Seric 16243234Seric while (a != NULL) 16253234Seric { 16264443Seric printf("%x=", a); 16274085Seric (void) fflush(stdout); 162857731Seric 162957731Seric /* find the mailer -- carefully */ 163057731Seric m = a->q_mailer; 163157731Seric if (m == NULL) 163257731Seric { 163357731Seric m = &pseudomailer; 163457731Seric m->m_mno = -1; 163557731Seric m->m_name = "NULL"; 163657731Seric } 163757731Seric 163858680Seric printf("%s:\n\tmailer %d (%s), host `%s', user `%s', ruser `%s'\n", 163957731Seric a->q_paddr, m->m_mno, m->m_name, 164067172Seric a->q_host == NULL ? "<null>" : a->q_host, a->q_user, 164167172Seric a->q_ruser == NULL ? "<null>" : a->q_ruser); 164267994Seric printf("\tnext=%x, alias %x, uid %d, gid %d\n", 164367994Seric a->q_next, a->q_alias, a->q_uid, a->q_gid); 164467994Seric printf("\tflags=%lx<", a->q_flags); 164567994Seric firstone = TRUE; 164667994Seric for (qfp = AddressFlags; qfp->qf_name != NULL; qfp++) 164767994Seric { 164867994Seric if (!bitset(qfp->qf_bit, a->q_flags)) 164967994Seric continue; 165067994Seric if (!firstone) 165167994Seric printf(","); 165267994Seric firstone = FALSE; 165367994Seric printf("%s", qfp->qf_name); 165467994Seric } 165567994Seric printf(">\n"); 165659269Seric printf("\towner=%s, home=\"%s\", fullname=\"%s\"\n", 165759269Seric a->q_owner == NULL ? "(none)" : a->q_owner, 165863756Seric a->q_home == NULL ? "(none)" : a->q_home, 165963756Seric a->q_fullname == NULL ? "(none)" : a->q_fullname); 166068228Seric printf("\torcpt=\"%s\", statmta=%s, rstatus=%s\n", 166167987Seric a->q_orcpt == NULL ? "(none)" : a->q_orcpt, 166267987Seric a->q_statmta == NULL ? "(none)" : a->q_statmta, 166367990Seric a->q_rstatus == NULL ? "(none)" : a->q_rstatus); 16644996Seric 16653234Seric if (!follow) 16663234Seric return; 16674996Seric a = a->q_next; 16683234Seric } 16693234Seric } 167067939Seric /* 167167939Seric ** EMPTYADDR -- return TRUE if this address is empty (``<>'') 167267939Seric ** 167367939Seric ** Parameters: 167467939Seric ** a -- pointer to the address 167567939Seric ** 167667939Seric ** Returns: 167767939Seric ** TRUE -- if this address is "empty" (i.e., no one should 167867939Seric ** ever generate replies to it. 167967939Seric ** FALSE -- if it is a "regular" (read: replyable) address. 168067939Seric */ 16814317Seric 168267939Seric bool 168367939Seric emptyaddr(a) 168467939Seric register ADDRESS *a; 168567939Seric { 168667939Seric return strcmp(a->q_paddr, "<>") == 0 || strcmp(a->q_user, "<>") == 0; 168767939Seric } 16887682Seric /* 16897682Seric ** REMOTENAME -- return the name relative to the current mailer 16907682Seric ** 16917682Seric ** Parameters: 16927682Seric ** name -- the name to translate. 16938069Seric ** m -- the mailer that we want to do rewriting relative 16948069Seric ** to. 169559163Seric ** flags -- fine tune operations. 169659163Seric ** pstat -- pointer to status word. 169758020Seric ** e -- the current envelope. 16987682Seric ** 16997682Seric ** Returns: 17007682Seric ** the text string representing this address relative to 17017682Seric ** the receiving mailer. 17027682Seric ** 17037682Seric ** Side Effects: 17047682Seric ** none. 17057682Seric ** 17067682Seric ** Warnings: 17077682Seric ** The text string returned is tucked away locally; 17087682Seric ** copy it if you intend to save it. 17097682Seric */ 17107682Seric 17117682Seric char * 171259163Seric remotename(name, m, flags, pstat, e) 17137682Seric char *name; 171456678Seric struct mailer *m; 171559163Seric int flags; 171659163Seric int *pstat; 171756678Seric register ENVELOPE *e; 17187682Seric { 17198069Seric register char **pvp; 17208069Seric char *fancy; 172156678Seric char *oldg = macvalue('g', e); 172258020Seric int rwset; 172368528Seric static char buf[MAXNAME + 1]; 172468528Seric char lbuf[MAXNAME + 1]; 172516914Seric char pvpbuf[PSBUFSIZE]; 172656678Seric extern char *crackaddr(); 17277682Seric 17287755Seric if (tTd(12, 1)) 17297755Seric printf("remotename(%s)\n", name); 17307755Seric 173110177Seric /* don't do anything if we are tagging it as special */ 173259163Seric if (bitset(RF_SENDERADDR, flags)) 173359163Seric rwset = bitset(RF_HEADERADDR, flags) ? m->m_sh_rwset 173459163Seric : m->m_se_rwset; 173558020Seric else 173659163Seric rwset = bitset(RF_HEADERADDR, flags) ? m->m_rh_rwset 173759163Seric : m->m_re_rwset; 173858020Seric if (rwset < 0) 173910177Seric return (name); 174010177Seric 17417682Seric /* 17428181Seric ** Do a heuristic crack of this name to extract any comment info. 17438181Seric ** This will leave the name as a comment and a $g macro. 17447889Seric */ 17457889Seric 174659163Seric if (bitset(RF_CANONICAL, flags) || bitnset(M_NOCOMMENT, m->m_flags)) 174758050Seric fancy = "\201g"; 174810310Seric else 174910310Seric fancy = crackaddr(name); 17507889Seric 17518181Seric /* 17528181Seric ** Turn the name into canonical form. 17538181Seric ** Normally this will be RFC 822 style, i.e., "user@domain". 17548181Seric ** If this only resolves to "user", and the "C" flag is 17558181Seric ** specified in the sending mailer, then the sender's 17568181Seric ** domain will be appended. 17578181Seric */ 17588181Seric 175965066Seric pvp = prescan(name, '\0', pvpbuf, sizeof pvpbuf, NULL); 17607889Seric if (pvp == NULL) 17617889Seric return (name); 176265071Seric if (rewrite(pvp, 3, 0, e) == EX_TEMPFAIL) 176359163Seric *pstat = EX_TEMPFAIL; 176459163Seric if (bitset(RF_ADDDOMAIN, flags) && e->e_fromdomain != NULL) 17658181Seric { 17668181Seric /* append from domain to this address */ 17678181Seric register char **pxp = pvp; 17688181Seric 17699594Seric /* see if there is an "@domain" in the current name */ 17708181Seric while (*pxp != NULL && strcmp(*pxp, "@") != 0) 17718181Seric pxp++; 17728181Seric if (*pxp == NULL) 17738181Seric { 17749594Seric /* no.... append the "@domain" from the sender */ 177556678Seric register char **qxq = e->e_fromdomain; 17768181Seric 17779594Seric while ((*pxp++ = *qxq++) != NULL) 17789594Seric continue; 177965071Seric if (rewrite(pvp, 3, 0, e) == EX_TEMPFAIL) 178059163Seric *pstat = EX_TEMPFAIL; 17818181Seric } 17828181Seric } 17838181Seric 17848181Seric /* 17858959Seric ** Do more specific rewriting. 178656678Seric ** Rewrite using ruleset 1 or 2 depending on whether this is 178756678Seric ** a sender address or not. 17888181Seric ** Then run it through any receiving-mailer-specific rulesets. 17898181Seric */ 17908181Seric 179159163Seric if (bitset(RF_SENDERADDR, flags)) 179259541Seric { 179365071Seric if (rewrite(pvp, 1, 0, e) == EX_TEMPFAIL) 179459163Seric *pstat = EX_TEMPFAIL; 179559541Seric } 17968069Seric else 179759541Seric { 179865071Seric if (rewrite(pvp, 2, 0, e) == EX_TEMPFAIL) 179959163Seric *pstat = EX_TEMPFAIL; 180059541Seric } 180158020Seric if (rwset > 0) 180259541Seric { 180365071Seric if (rewrite(pvp, rwset, 0, e) == EX_TEMPFAIL) 180459163Seric *pstat = EX_TEMPFAIL; 180559541Seric } 18067682Seric 18078181Seric /* 18088959Seric ** Do any final sanitation the address may require. 18098959Seric ** This will normally be used to turn internal forms 18108959Seric ** (e.g., user@host.LOCAL) into external form. This 18118959Seric ** may be used as a default to the above rules. 18128959Seric */ 18138959Seric 181465071Seric if (rewrite(pvp, 4, 0, e) == EX_TEMPFAIL) 181559163Seric *pstat = EX_TEMPFAIL; 18168959Seric 18178959Seric /* 18188181Seric ** Now restore the comment information we had at the beginning. 18198181Seric */ 18208181Seric 182158825Seric cataddr(pvp, NULL, lbuf, sizeof lbuf, '\0'); 182256678Seric define('g', lbuf, e); 182365494Seric 182465494Seric /* need to make sure route-addrs have <angle brackets> */ 182565494Seric if (bitset(RF_CANONICAL, flags) && lbuf[0] == '@') 182668529Seric expand("<\201g>", buf, sizeof buf, e); 182765494Seric else 182868529Seric expand(fancy, buf, sizeof buf, e); 182965494Seric 183056678Seric define('g', oldg, e); 18317682Seric 18327682Seric if (tTd(12, 1)) 18337755Seric printf("remotename => `%s'\n", buf); 18347682Seric return (buf); 18357682Seric } 183651317Seric /* 183756678Seric ** MAPLOCALUSER -- run local username through ruleset 5 for final redirection 183851317Seric ** 183951317Seric ** Parameters: 184056678Seric ** a -- the address to map (but just the user name part). 184156678Seric ** sendq -- the sendq in which to install any replacement 184256678Seric ** addresses. 184367982Seric ** aliaslevel -- the alias nesting depth. 184467982Seric ** e -- the envelope. 184551317Seric ** 184651317Seric ** Returns: 184751317Seric ** none. 184851317Seric */ 184951317Seric 185067982Seric maplocaluser(a, sendq, aliaslevel, e) 185156678Seric register ADDRESS *a; 185256678Seric ADDRESS **sendq; 185367982Seric int aliaslevel; 185456678Seric ENVELOPE *e; 185551317Seric { 185656678Seric register char **pvp; 185756678Seric register ADDRESS *a1 = NULL; 185858333Seric auto char *delimptr; 185956678Seric char pvpbuf[PSBUFSIZE]; 186051317Seric 186156678Seric if (tTd(29, 1)) 186256678Seric { 186356678Seric printf("maplocaluser: "); 186456678Seric printaddr(a, FALSE); 186556678Seric } 186665066Seric pvp = prescan(a->q_user, '\0', pvpbuf, sizeof pvpbuf, &delimptr); 186756678Seric if (pvp == NULL) 186856678Seric return; 186951317Seric 187065071Seric (void) rewrite(pvp, 5, 0, e); 187158050Seric if (pvp[0] == NULL || (pvp[0][0] & 0377) != CANONNET) 187256678Seric return; 187351317Seric 187456678Seric /* if non-null, mailer destination specified -- has it changed? */ 187564284Seric a1 = buildaddr(pvp, NULL, 0, e); 187656678Seric if (a1 == NULL || sameaddr(a, a1)) 187756678Seric return; 187851317Seric 187956678Seric /* mark old address as dead; insert new address */ 188056678Seric a->q_flags |= QDONTSEND; 188157731Seric if (tTd(29, 5)) 188257731Seric { 188357731Seric printf("maplocaluser: QDONTSEND "); 188457731Seric printaddr(a, FALSE); 188557731Seric } 188656678Seric a1->q_alias = a; 188764348Seric allocaddr(a1, RF_COPYALL, NULL); 188867982Seric (void) recipient(a1, sendq, aliaslevel, e); 188951317Seric } 189058802Seric /* 189158802Seric ** DEQUOTE_INIT -- initialize dequote map 189258802Seric ** 189358802Seric ** This is a no-op. 189458802Seric ** 189558802Seric ** Parameters: 189658802Seric ** map -- the internal map structure. 189758802Seric ** args -- arguments. 189858802Seric ** 189958802Seric ** Returns: 190058802Seric ** TRUE. 190158802Seric */ 190258802Seric 190358802Seric bool 190460219Seric dequote_init(map, args) 190558802Seric MAP *map; 190658802Seric char *args; 190758802Seric { 190858805Seric register char *p = args; 190958805Seric 191058805Seric for (;;) 191158805Seric { 191258805Seric while (isascii(*p) && isspace(*p)) 191358805Seric p++; 191458805Seric if (*p != '-') 191558805Seric break; 191658805Seric switch (*++p) 191758805Seric { 191858805Seric case 'a': 191958805Seric map->map_app = ++p; 192058805Seric break; 192167824Seric 192267824Seric case 's': 192367824Seric map->map_coldelim = *++p; 192467824Seric break; 192558805Seric } 192658805Seric while (*p != '\0' && !(isascii(*p) && isspace(*p))) 192758805Seric p++; 192858805Seric if (*p != '\0') 192958805Seric *p = '\0'; 193058805Seric } 193158805Seric if (map->map_app != NULL) 193258805Seric map->map_app = newstr(map->map_app); 193358805Seric 193458802Seric return TRUE; 193558802Seric } 193658802Seric /* 193758802Seric ** DEQUOTE_MAP -- unquote an address 193858802Seric ** 193958802Seric ** Parameters: 194058802Seric ** map -- the internal map structure (ignored). 194160089Seric ** name -- the name to dequote. 194258802Seric ** av -- arguments (ignored). 194359084Seric ** statp -- pointer to status out-parameter. 194458802Seric ** 194558802Seric ** Returns: 194658802Seric ** NULL -- if there were no quotes, or if the resulting 194758802Seric ** unquoted buffer would not be acceptable to prescan. 194858802Seric ** else -- The dequoted buffer. 194958802Seric */ 195058802Seric 195158802Seric char * 195260089Seric dequote_map(map, name, av, statp) 195358802Seric MAP *map; 195460089Seric char *name; 195558802Seric char **av; 195659084Seric int *statp; 195758802Seric { 195858802Seric register char *p; 195958802Seric register char *q; 196058802Seric register char c; 196167824Seric int anglecnt = 0; 196267824Seric int cmntcnt = 0; 196367824Seric int quotecnt = 0; 196467824Seric int spacecnt = 0; 196567824Seric bool quotemode = FALSE; 196667824Seric bool bslashmode = FALSE; 196767824Seric char spacesub = map->map_coldelim; 196858802Seric 196960089Seric for (p = q = name; (c = *p++) != '\0'; ) 197058802Seric { 197158802Seric if (bslashmode) 197258802Seric { 197358802Seric bslashmode = FALSE; 197458802Seric *q++ = c; 197558802Seric continue; 197658802Seric } 197758802Seric 197867824Seric if (c == ' ' && spacesub != '\0') 197967824Seric c = spacesub; 198067764Seric 198158802Seric switch (c) 198258802Seric { 198358802Seric case '\\': 198458802Seric bslashmode = TRUE; 198558802Seric break; 198658802Seric 198758802Seric case '(': 198858802Seric cmntcnt++; 198958802Seric break; 199058802Seric 199158802Seric case ')': 199258802Seric if (cmntcnt-- <= 0) 199358802Seric return NULL; 199458802Seric break; 199559089Seric 199659089Seric case ' ': 199759089Seric spacecnt++; 199859089Seric break; 199958802Seric } 200058802Seric 200158802Seric if (cmntcnt > 0) 200258802Seric { 200358802Seric *q++ = c; 200458802Seric continue; 200558802Seric } 200658802Seric 200758802Seric switch (c) 200858802Seric { 200958802Seric case '"': 201058802Seric quotemode = !quotemode; 201158802Seric quotecnt++; 201258802Seric continue; 201358802Seric 201458802Seric case '<': 201558802Seric anglecnt++; 201658802Seric break; 201758802Seric 201858802Seric case '>': 201958802Seric if (anglecnt-- <= 0) 202058802Seric return NULL; 202158802Seric break; 202258802Seric } 202358802Seric *q++ = c; 202458802Seric } 202558802Seric 202658802Seric if (anglecnt != 0 || cmntcnt != 0 || bslashmode || 202759089Seric quotemode || quotecnt <= 0 || spacecnt != 0) 202858802Seric return NULL; 202958802Seric *q++ = '\0'; 203060089Seric return name; 203158802Seric } 2032