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*68708Seric static char sccsid[] = "@(#)parseaddr.c 8.63 (Berkeley) 03/31/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 */ 109168706Seric if (stat == EX_TEMPFAIL || stat == EX_UNAVAILABLE) 109268706Seric { 109368706Seric rstat = EX_TEMPFAIL; 1094*68708Seric if (tTd(50, 1)) 109568706Seric printf("map_lookup(%s, %s) failed (stat = %d)\n", 109668706Seric mapname, buf, stat); 109768706Seric if (e->e_message == NULL) 109868706Seric { 109968706Seric char mbuf[300]; 110068706Seric 110168706Seric sprintf(mbuf, "map %s: lookup (%s) failed", 110268706Seric mapname, buf); 110368706Seric e->e_message = newstr(mbuf); 110468706Seric } 110568706Seric } 110656836Seric } 110753654Seric else 110856678Seric replac = NULL; 110956678Seric 111056678Seric /* if no replacement, use default */ 111156823Seric if (replac == NULL && default_rvp != NULL) 111256823Seric { 111360089Seric /* create the default */ 111460089Seric cataddr(default_rvp, NULL, buf, sizeof buf, '\0'); 111556823Seric replac = buf; 111656823Seric } 111756823Seric 111856678Seric if (replac == NULL) 111951317Seric { 112056823Seric xpvp = key_rvp; 112153654Seric } 112264404Seric else if (*replac == '\0') 112364404Seric { 112464404Seric /* null replacement */ 112564404Seric nullpvp[0] = NULL; 112664404Seric xpvp = nullpvp; 112764404Seric } 112856678Seric else 112953654Seric { 113056678Seric /* scan the new replacement */ 113165066Seric xpvp = prescan(replac, '\0', pvpbuf, 113265066Seric sizeof pvpbuf, NULL); 113353654Seric if (xpvp == NULL) 113451317Seric { 113558403Seric /* prescan already printed error */ 113659084Seric return EX_DATAERR; 113756678Seric } 113851317Seric } 113951317Seric 114016914Seric /* append it to the token list */ 114156678Seric for (avp = hbrvp; *xpvp != NULL; xpvp++) 114256678Seric { 114317174Seric *avp++ = newstr(*xpvp); 114416920Seric if (avp >= &npvp[MAXATOM]) 114516914Seric goto toolong; 114617174Seric } 114716914Seric 114816914Seric /* restore the old trailing information */ 114956678Seric for (xpvp = pvpb1; (*avp++ = *xpvp++) != NULL; ) 115016920Seric if (avp >= &npvp[MAXATOM]) 115116914Seric goto toolong; 115217174Seric 115356678Seric break; 115416914Seric } 115516914Seric 115616914Seric /* 115716914Seric ** Check for subroutine calls. 115816914Seric */ 115916914Seric 116068559Seric if (*npvp != NULL && (**npvp & 0377) == CALLSUBR) 116168559Seric { 116268559Seric int stat; 116359084Seric 116468559Seric if (npvp[1] == NULL) 116568559Seric { 116668559Seric syserr("parseaddr: NULL subroutine call in ruleset %d, rule %d", 116768559Seric ruleset, ruleno); 116868559Seric *pvp = NULL; 116968559Seric } 117068559Seric else 117168559Seric { 117268559Seric int ruleset; 117368559Seric STAB *s; 117468385Seric 117568559Seric bcopy((char *) &npvp[2], (char *) pvp, 117668559Seric (int) (avp - npvp - 2) * sizeof *avp); 117768559Seric if (tTd(21, 3)) 117868559Seric printf("-----callsubr %s\n", npvp[1]); 117968559Seric s = stab(npvp[1], ST_RULESET, ST_FIND); 118068559Seric if (s == NULL) 118168559Seric ruleset = atoi(npvp[1]); 118268559Seric else 118368559Seric ruleset = s->s_ruleset; 118468559Seric stat = rewrite(pvp, ruleset, reclevel, e); 118568559Seric if (rstat == EX_OK || stat == EX_TEMPFAIL) 118668559Seric rstat = stat; 118768559Seric if (*pvp != NULL && (**pvp & 0377) == CANONNET) 118868559Seric rwr = NULL; 118968559Seric } 119068559Seric } 119168559Seric else 119268559Seric { 119368559Seric bcopy((char *) npvp, (char *) pvp, 119468559Seric (int) (avp - npvp) * sizeof *avp); 119568559Seric } 11969374Seric if (tTd(21, 4)) 11979374Seric { 11989374Seric printf("rewritten as:"); 119956678Seric printav(pvp); 12009374Seric } 1201297Seric } 12028069Seric 120367262Seric if (OpMode == MD_TEST || tTd(21, 1)) 12048069Seric { 12058959Seric printf("rewrite: ruleset %2d returns:", ruleset); 120656678Seric printav(pvp); 12078069Seric } 120859084Seric 120959084Seric return rstat; 12103149Seric } 12113149Seric /* 12123149Seric ** BUILDADDR -- build address from token vector. 12133149Seric ** 12143149Seric ** Parameters: 12153149Seric ** tv -- token vector. 12163149Seric ** a -- pointer to address descriptor to fill. 12173149Seric ** If NULL, one will be allocated. 121864284Seric ** flags -- info regarding whether this is a sender or 121964284Seric ** a recipient. 122058966Seric ** e -- the current envelope. 12213149Seric ** 12223149Seric ** Returns: 12234279Seric ** NULL if there was an error. 12244279Seric ** 'a' otherwise. 12253149Seric ** 12263149Seric ** Side Effects: 12273149Seric ** fills in 'a' 12283149Seric */ 12293149Seric 123057249Seric struct errcodes 123157249Seric { 123257249Seric char *ec_name; /* name of error code */ 123357249Seric int ec_code; /* numeric code */ 123457249Seric } ErrorCodes[] = 123557249Seric { 123657249Seric "usage", EX_USAGE, 123757249Seric "nouser", EX_NOUSER, 123857249Seric "nohost", EX_NOHOST, 123957249Seric "unavailable", EX_UNAVAILABLE, 124057249Seric "software", EX_SOFTWARE, 124157249Seric "tempfail", EX_TEMPFAIL, 124257249Seric "protocol", EX_PROTOCOL, 124357249Seric #ifdef EX_CONFIG 124457249Seric "config", EX_CONFIG, 124557249Seric #endif 124657249Seric NULL, EX_UNAVAILABLE, 124757249Seric }; 124857249Seric 124956678Seric ADDRESS * 125064284Seric buildaddr(tv, a, flags, e) 12513149Seric register char **tv; 12523149Seric register ADDRESS *a; 125364284Seric int flags; 125458966Seric register ENVELOPE *e; 12553149Seric { 12563149Seric struct mailer **mp; 12573149Seric register struct mailer *m; 125858008Seric char *bp; 125958008Seric int spaceleft; 126064306Seric static MAILER errormailer; 126164306Seric static char *errorargv[] = { "ERROR", NULL }; 126268528Seric static char buf[MAXNAME + 1]; 12633149Seric 126464791Seric if (tTd(24, 5)) 126564791Seric { 126667693Seric printf("buildaddr, flags=%x, tv=", flags); 126764791Seric printav(tv); 126864791Seric } 126964791Seric 12703149Seric if (a == NULL) 12713149Seric a = (ADDRESS *) xalloc(sizeof *a); 127216889Seric bzero((char *) a, sizeof *a); 12733149Seric 127467880Seric /* set up default error return flags */ 127567963Seric a->q_flags |= QPINGONFAILURE|QPINGONDELAY; 127667880Seric 12773149Seric /* figure out what net/mailer to use */ 127864306Seric if (*tv == NULL || (**tv & 0377) != CANONNET) 12794279Seric { 128058151Seric syserr("554 buildaddr: no net"); 128164306Seric badaddr: 128264306Seric a->q_flags |= QBADADDR; 128364306Seric a->q_mailer = &errormailer; 128464306Seric if (errormailer.m_name == NULL) 128564306Seric { 128664306Seric /* initialize the bogus mailer */ 128764306Seric errormailer.m_name = "*error*"; 128864306Seric errormailer.m_mailer = "ERROR"; 128964306Seric errormailer.m_argv = errorargv; 129064306Seric } 129164306Seric return a; 12924279Seric } 12933149Seric tv++; 129458680Seric if (strcasecmp(*tv, "error") == 0) 12954279Seric { 129658050Seric if ((**++tv & 0377) == CANONHOST) 129710183Seric { 129857249Seric register struct errcodes *ep; 129957249Seric 130058050Seric if (isascii(**++tv) && isdigit(**tv)) 130157249Seric { 130257249Seric setstat(atoi(*tv)); 130357249Seric } 130457249Seric else 130557249Seric { 130657249Seric for (ep = ErrorCodes; ep->ec_name != NULL; ep++) 130757249Seric if (strcasecmp(ep->ec_name, *tv) == 0) 130857249Seric break; 130957249Seric setstat(ep->ec_code); 131057249Seric } 131110183Seric tv++; 131210183Seric } 131364928Seric else 131464928Seric setstat(EX_UNAVAILABLE); 131558050Seric if ((**tv & 0377) != CANONUSER) 131658151Seric syserr("554 buildaddr: error: no user"); 131758814Seric cataddr(++tv, NULL, buf, sizeof buf, ' '); 131858082Seric stripquotes(buf); 131964659Seric if (isascii(buf[0]) && isdigit(buf[0]) && 132064659Seric isascii(buf[1]) && isdigit(buf[1]) && 132164659Seric isascii(buf[2]) && isdigit(buf[2]) && 132264659Seric buf[3] == ' ') 132364659Seric { 132464659Seric char fmt[10]; 132564659Seric 132664659Seric strncpy(fmt, buf, 3); 132764659Seric strcpy(&fmt[3], " %s"); 132864659Seric usrerr(fmt, buf + 4); 132967786Seric 133067786Seric /* 133167786Seric ** If this is a 4xx code and we aren't running 133267786Seric ** SMTP on our input, bounce this message; 133367786Seric ** otherwise it disappears without a trace. 133467786Seric */ 133567786Seric 133667786Seric if (fmt[0] == '4' && OpMode != MD_SMTP && 133767786Seric OpMode != MD_DAEMON) 133867786Seric { 133967786Seric e->e_flags |= EF_FATALERRS; 134067786Seric } 134164659Seric } 134264659Seric else 134364659Seric { 134466039Seric usrerr("553 %s", buf); 134564659Seric } 134664306Seric goto badaddr; 13474279Seric } 134857402Seric 13494598Seric for (mp = Mailer; (m = *mp++) != NULL; ) 13503149Seric { 135158680Seric if (strcasecmp(m->m_name, *tv) == 0) 13523149Seric break; 13533149Seric } 13543149Seric if (m == NULL) 13554279Seric { 135658151Seric syserr("554 buildaddr: unknown mailer %s", *tv); 135764306Seric goto badaddr; 13584279Seric } 13594598Seric a->q_mailer = m; 13603149Seric 13613149Seric /* figure out what host (if any) */ 136256678Seric tv++; 136358509Seric if ((**tv & 0377) == CANONHOST) 13643149Seric { 136558008Seric bp = buf; 136658008Seric spaceleft = sizeof buf - 1; 136758050Seric while (*++tv != NULL && (**tv & 0377) != CANONUSER) 136858008Seric { 136958008Seric int i = strlen(*tv); 137058008Seric 137158008Seric if (i > spaceleft) 137258008Seric { 137358008Seric /* out of space for this address */ 137458008Seric if (spaceleft >= 0) 137558151Seric syserr("554 buildaddr: host too long (%.40s...)", 137658008Seric buf); 137758008Seric i = spaceleft; 137858008Seric spaceleft = 0; 137958008Seric } 138058008Seric if (i <= 0) 138158008Seric continue; 138258008Seric bcopy(*tv, bp, i); 138358008Seric bp += i; 138458008Seric spaceleft -= i; 138558008Seric } 138658010Seric *bp = '\0'; 13875704Seric a->q_host = newstr(buf); 13883149Seric } 138957249Seric else 139058509Seric { 139158509Seric if (!bitnset(M_LOCALMAILER, m->m_flags)) 139258509Seric { 139358509Seric syserr("554 buildaddr: no host"); 139464306Seric goto badaddr; 139558509Seric } 139657249Seric a->q_host = NULL; 139758509Seric } 13983149Seric 13993149Seric /* figure out the user */ 140058050Seric if (*tv == NULL || (**tv & 0377) != CANONUSER) 14014279Seric { 140258151Seric syserr("554 buildaddr: no user"); 140364306Seric goto badaddr; 14044279Seric } 140557402Seric tv++; 140651317Seric 140768098Seric if (bitnset(M_CHECKUDB, m->m_flags) && *tv != NULL && 140868098Seric strcmp(*tv, "@") == 0) 140968098Seric { 141068098Seric tv++; 141168098Seric a->q_flags |= QNOTREMOTE; 141268098Seric } 141368098Seric 141457402Seric /* do special mapping for local mailer */ 141567472Seric if (*tv != NULL) 141657402Seric { 141757454Seric register char *p = *tv; 141857454Seric 141957454Seric if (*p == '"') 142057454Seric p++; 142167472Seric if (*p == '|' && bitnset(M_CHECKPROG, m->m_flags)) 142257402Seric a->q_mailer = m = ProgMailer; 142367472Seric else if (*p == '/' && bitnset(M_CHECKFILE, m->m_flags)) 142457402Seric a->q_mailer = m = FileMailer; 142567472Seric else if (*p == ':' && bitnset(M_CHECKINCLUDE, m->m_flags)) 142657402Seric { 142757402Seric /* may be :include: */ 142858814Seric cataddr(tv, NULL, buf, sizeof buf, '\0'); 142958008Seric stripquotes(buf); 143058008Seric if (strncasecmp(buf, ":include:", 9) == 0) 143158008Seric { 143258008Seric /* if :include:, don't need further rewriting */ 143357402Seric a->q_mailer = m = InclMailer; 143458008Seric a->q_user = &buf[9]; 143558008Seric return (a); 143658008Seric } 143757402Seric } 143857402Seric } 143957402Seric 144064284Seric /* rewrite according recipient mailer rewriting rules */ 144164284Seric define('h', a->q_host, e); 144264284Seric if (!bitset(RF_SENDERADDR|RF_HEADERADDR, flags)) 144364284Seric { 144464284Seric /* sender addresses done later */ 144565071Seric (void) rewrite(tv, 2, 0, e); 144664284Seric if (m->m_re_rwset > 0) 144765071Seric (void) rewrite(tv, m->m_re_rwset, 0, e); 144864284Seric } 144965071Seric (void) rewrite(tv, 4, 0, e); 145019040Seric 145119040Seric /* save the result for the command line/RCPT argument */ 145258814Seric cataddr(tv, NULL, buf, sizeof buf, '\0'); 14533149Seric a->q_user = buf; 14543149Seric 145558670Seric /* 145658670Seric ** Do mapping to lower case as requested by mailer 145758670Seric */ 145858670Seric 145958670Seric if (a->q_host != NULL && !bitnset(M_HST_UPPER, m->m_flags)) 146058670Seric makelower(a->q_host); 146158670Seric if (!bitnset(M_USR_UPPER, m->m_flags)) 146258670Seric makelower(a->q_user); 146358670Seric 14643149Seric return (a); 14653149Seric } 14663188Seric /* 14674228Seric ** CATADDR -- concatenate pieces of addresses (putting in <LWSP> subs) 14684228Seric ** 14694228Seric ** Parameters: 14704228Seric ** pvp -- parameter vector to rebuild. 147158814Seric ** evp -- last parameter to include. Can be NULL to 147258814Seric ** use entire pvp. 14734228Seric ** buf -- buffer to build the string into. 14744228Seric ** sz -- size of buf. 147558082Seric ** spacesub -- the space separator character; if null, 147658082Seric ** use SpaceSub. 14774228Seric ** 14784228Seric ** Returns: 14794228Seric ** none. 14804228Seric ** 14814228Seric ** Side Effects: 14824228Seric ** Destroys buf. 14834228Seric */ 14844228Seric 148558814Seric cataddr(pvp, evp, buf, sz, spacesub) 14864228Seric char **pvp; 148758814Seric char **evp; 14884228Seric char *buf; 14894228Seric register int sz; 149058082Seric char spacesub; 14914228Seric { 14924228Seric bool oatomtok = FALSE; 149356678Seric bool natomtok = FALSE; 14944228Seric register int i; 14954228Seric register char *p; 14964228Seric 149758082Seric if (spacesub == '\0') 149858082Seric spacesub = SpaceSub; 149958082Seric 15008423Seric if (pvp == NULL) 15018423Seric { 150223109Seric (void) strcpy(buf, ""); 15038423Seric return; 15048423Seric } 15054228Seric p = buf; 150611156Seric sz -= 2; 15074228Seric while (*pvp != NULL && (i = strlen(*pvp)) < sz) 15084228Seric { 15098078Seric natomtok = (toktype(**pvp) == ATM); 15104228Seric if (oatomtok && natomtok) 151158082Seric *p++ = spacesub; 15124228Seric (void) strcpy(p, *pvp); 15134228Seric oatomtok = natomtok; 15144228Seric p += i; 151511156Seric sz -= i + 1; 151658814Seric if (pvp++ == evp) 151758814Seric break; 15184228Seric } 15194228Seric *p = '\0'; 15204228Seric } 15214228Seric /* 15223188Seric ** SAMEADDR -- Determine if two addresses are the same 15233188Seric ** 15243188Seric ** This is not just a straight comparison -- if the mailer doesn't 15253188Seric ** care about the host we just ignore it, etc. 15263188Seric ** 15273188Seric ** Parameters: 15283188Seric ** a, b -- pointers to the internal forms to compare. 15293188Seric ** 15303188Seric ** Returns: 15313188Seric ** TRUE -- they represent the same mailbox. 15323188Seric ** FALSE -- they don't. 15333188Seric ** 15343188Seric ** Side Effects: 15353188Seric ** none. 15363188Seric */ 15373188Seric 15383188Seric bool 15399374Seric sameaddr(a, b) 15403188Seric register ADDRESS *a; 15413188Seric register ADDRESS *b; 15423188Seric { 154365093Seric register ADDRESS *ca, *cb; 154465093Seric 15453188Seric /* if they don't have the same mailer, forget it */ 15463188Seric if (a->q_mailer != b->q_mailer) 15473188Seric return (FALSE); 15483188Seric 15493188Seric /* if the user isn't the same, we can drop out */ 155056678Seric if (strcmp(a->q_user, b->q_user) != 0) 15513188Seric return (FALSE); 15523188Seric 155365093Seric /* if we have good uids for both but they differ, these are different */ 155465379Seric if (a->q_mailer == ProgMailer) 155565379Seric { 155665379Seric ca = getctladdr(a); 155765379Seric cb = getctladdr(b); 155865379Seric if (ca != NULL && cb != NULL && 155965379Seric bitset(QGOODUID, ca->q_flags & cb->q_flags) && 156065379Seric ca->q_uid != cb->q_uid) 156165379Seric return (FALSE); 156265379Seric } 156358438Seric 156458509Seric /* otherwise compare hosts (but be careful for NULL ptrs) */ 156558509Seric if (a->q_host == b->q_host) 156658509Seric { 156758509Seric /* probably both null pointers */ 15683188Seric return (TRUE); 156958509Seric } 15703188Seric if (a->q_host == NULL || b->q_host == NULL) 157158509Seric { 157258509Seric /* only one is a null pointer */ 15733188Seric return (FALSE); 157458509Seric } 157556678Seric if (strcmp(a->q_host, b->q_host) != 0) 15763188Seric return (FALSE); 15773188Seric 15783188Seric return (TRUE); 15793188Seric } 15803234Seric /* 15813234Seric ** PRINTADDR -- print address (for debugging) 15823234Seric ** 15833234Seric ** Parameters: 15843234Seric ** a -- the address to print 15853234Seric ** follow -- follow the q_next chain. 15863234Seric ** 15873234Seric ** Returns: 15883234Seric ** none. 15893234Seric ** 15903234Seric ** Side Effects: 15913234Seric ** none. 15923234Seric */ 15933234Seric 159467994Seric struct qflags 159567994Seric { 159667994Seric char *qf_name; 159767994Seric u_long qf_bit; 159867994Seric }; 159967994Seric 160067994Seric struct qflags AddressFlags[] = 160167994Seric { 160267994Seric "QDONTSEND", QDONTSEND, 160367994Seric "QBADADDR", QBADADDR, 160467994Seric "QGOODUID", QGOODUID, 160567994Seric "QPRIMARY", QPRIMARY, 160667994Seric "QQUEUEUP", QQUEUEUP, 160767994Seric "QSENT", QSENT, 160867994Seric "QNOTREMOTE", QNOTREMOTE, 160967994Seric "QSELFREF", QSELFREF, 161067994Seric "QVERIFIED", QVERIFIED, 161167994Seric "QREPORT", QREPORT, 161267994Seric "QBOGUSSHELL", QBOGUSSHELL, 161367994Seric "QUNSAFEADDR", QUNSAFEADDR, 161467994Seric "QPINGONSUCCESS", QPINGONSUCCESS, 161567994Seric "QPINGONFAILURE", QPINGONFAILURE, 161667994Seric "QPINGONDELAY", QPINGONDELAY, 161768595Seric "QHASNOTIFY", QHASNOTIFY, 161867994Seric "QRELAYED", QRELAYED, 161968603Seric "QEXPLODED", QEXPLODED, 162068603Seric "QTHISPASS", QTHISPASS, 162167994Seric NULL 162267994Seric }; 162367994Seric 162468433Seric void 16253234Seric printaddr(a, follow) 16263234Seric register ADDRESS *a; 16273234Seric bool follow; 16283234Seric { 162957731Seric register MAILER *m; 163057731Seric MAILER pseudomailer; 163167994Seric register struct qflags *qfp; 163267994Seric bool firstone; 16335001Seric 163467994Seric if (a == NULL) 163567994Seric { 163667994Seric printf("[NULL]\n"); 163767994Seric return; 163867994Seric } 163967994Seric 16403234Seric while (a != NULL) 16413234Seric { 16424443Seric printf("%x=", a); 16434085Seric (void) fflush(stdout); 164457731Seric 164557731Seric /* find the mailer -- carefully */ 164657731Seric m = a->q_mailer; 164757731Seric if (m == NULL) 164857731Seric { 164957731Seric m = &pseudomailer; 165057731Seric m->m_mno = -1; 165157731Seric m->m_name = "NULL"; 165257731Seric } 165357731Seric 165468603Seric printf("%s:\n\tmailer %d (%s), host `%s'\n", 165557731Seric a->q_paddr, m->m_mno, m->m_name, 165668603Seric a->q_host == NULL ? "<null>" : a->q_host); 165768603Seric printf("\tuser `%s', ruser `%s'\n", 165868603Seric a->q_user, 165967172Seric a->q_ruser == NULL ? "<null>" : a->q_ruser); 166067994Seric printf("\tnext=%x, alias %x, uid %d, gid %d\n", 166167994Seric a->q_next, a->q_alias, a->q_uid, a->q_gid); 166267994Seric printf("\tflags=%lx<", a->q_flags); 166367994Seric firstone = TRUE; 166467994Seric for (qfp = AddressFlags; qfp->qf_name != NULL; qfp++) 166567994Seric { 166667994Seric if (!bitset(qfp->qf_bit, a->q_flags)) 166767994Seric continue; 166867994Seric if (!firstone) 166967994Seric printf(","); 167067994Seric firstone = FALSE; 167167994Seric printf("%s", qfp->qf_name); 167267994Seric } 167367994Seric printf(">\n"); 167459269Seric printf("\towner=%s, home=\"%s\", fullname=\"%s\"\n", 167559269Seric a->q_owner == NULL ? "(none)" : a->q_owner, 167663756Seric a->q_home == NULL ? "(none)" : a->q_home, 167763756Seric a->q_fullname == NULL ? "(none)" : a->q_fullname); 167868228Seric printf("\torcpt=\"%s\", statmta=%s, rstatus=%s\n", 167967987Seric a->q_orcpt == NULL ? "(none)" : a->q_orcpt, 168067987Seric a->q_statmta == NULL ? "(none)" : a->q_statmta, 168167990Seric a->q_rstatus == NULL ? "(none)" : a->q_rstatus); 16824996Seric 16833234Seric if (!follow) 16843234Seric return; 16854996Seric a = a->q_next; 16863234Seric } 16873234Seric } 168867939Seric /* 168967939Seric ** EMPTYADDR -- return TRUE if this address is empty (``<>'') 169067939Seric ** 169167939Seric ** Parameters: 169267939Seric ** a -- pointer to the address 169367939Seric ** 169467939Seric ** Returns: 169567939Seric ** TRUE -- if this address is "empty" (i.e., no one should 169667939Seric ** ever generate replies to it. 169767939Seric ** FALSE -- if it is a "regular" (read: replyable) address. 169867939Seric */ 16994317Seric 170067939Seric bool 170167939Seric emptyaddr(a) 170267939Seric register ADDRESS *a; 170367939Seric { 170467939Seric return strcmp(a->q_paddr, "<>") == 0 || strcmp(a->q_user, "<>") == 0; 170567939Seric } 17067682Seric /* 17077682Seric ** REMOTENAME -- return the name relative to the current mailer 17087682Seric ** 17097682Seric ** Parameters: 17107682Seric ** name -- the name to translate. 17118069Seric ** m -- the mailer that we want to do rewriting relative 17128069Seric ** to. 171359163Seric ** flags -- fine tune operations. 171459163Seric ** pstat -- pointer to status word. 171558020Seric ** e -- the current envelope. 17167682Seric ** 17177682Seric ** Returns: 17187682Seric ** the text string representing this address relative to 17197682Seric ** the receiving mailer. 17207682Seric ** 17217682Seric ** Side Effects: 17227682Seric ** none. 17237682Seric ** 17247682Seric ** Warnings: 17257682Seric ** The text string returned is tucked away locally; 17267682Seric ** copy it if you intend to save it. 17277682Seric */ 17287682Seric 17297682Seric char * 173059163Seric remotename(name, m, flags, pstat, e) 17317682Seric char *name; 173256678Seric struct mailer *m; 173359163Seric int flags; 173459163Seric int *pstat; 173556678Seric register ENVELOPE *e; 17367682Seric { 17378069Seric register char **pvp; 17388069Seric char *fancy; 173956678Seric char *oldg = macvalue('g', e); 174058020Seric int rwset; 174168528Seric static char buf[MAXNAME + 1]; 174268528Seric char lbuf[MAXNAME + 1]; 174316914Seric char pvpbuf[PSBUFSIZE]; 174456678Seric extern char *crackaddr(); 17457682Seric 17467755Seric if (tTd(12, 1)) 17477755Seric printf("remotename(%s)\n", name); 17487755Seric 174910177Seric /* don't do anything if we are tagging it as special */ 175059163Seric if (bitset(RF_SENDERADDR, flags)) 175159163Seric rwset = bitset(RF_HEADERADDR, flags) ? m->m_sh_rwset 175259163Seric : m->m_se_rwset; 175358020Seric else 175459163Seric rwset = bitset(RF_HEADERADDR, flags) ? m->m_rh_rwset 175559163Seric : m->m_re_rwset; 175658020Seric if (rwset < 0) 175710177Seric return (name); 175810177Seric 17597682Seric /* 17608181Seric ** Do a heuristic crack of this name to extract any comment info. 17618181Seric ** This will leave the name as a comment and a $g macro. 17627889Seric */ 17637889Seric 176459163Seric if (bitset(RF_CANONICAL, flags) || bitnset(M_NOCOMMENT, m->m_flags)) 176558050Seric fancy = "\201g"; 176610310Seric else 176710310Seric fancy = crackaddr(name); 17687889Seric 17698181Seric /* 17708181Seric ** Turn the name into canonical form. 17718181Seric ** Normally this will be RFC 822 style, i.e., "user@domain". 17728181Seric ** If this only resolves to "user", and the "C" flag is 17738181Seric ** specified in the sending mailer, then the sender's 17748181Seric ** domain will be appended. 17758181Seric */ 17768181Seric 177765066Seric pvp = prescan(name, '\0', pvpbuf, sizeof pvpbuf, NULL); 17787889Seric if (pvp == NULL) 17797889Seric return (name); 178065071Seric if (rewrite(pvp, 3, 0, e) == EX_TEMPFAIL) 178159163Seric *pstat = EX_TEMPFAIL; 178259163Seric if (bitset(RF_ADDDOMAIN, flags) && e->e_fromdomain != NULL) 17838181Seric { 17848181Seric /* append from domain to this address */ 17858181Seric register char **pxp = pvp; 17868181Seric 17879594Seric /* see if there is an "@domain" in the current name */ 17888181Seric while (*pxp != NULL && strcmp(*pxp, "@") != 0) 17898181Seric pxp++; 17908181Seric if (*pxp == NULL) 17918181Seric { 17929594Seric /* no.... append the "@domain" from the sender */ 179356678Seric register char **qxq = e->e_fromdomain; 17948181Seric 17959594Seric while ((*pxp++ = *qxq++) != NULL) 17969594Seric continue; 179765071Seric if (rewrite(pvp, 3, 0, e) == EX_TEMPFAIL) 179859163Seric *pstat = EX_TEMPFAIL; 17998181Seric } 18008181Seric } 18018181Seric 18028181Seric /* 18038959Seric ** Do more specific rewriting. 180456678Seric ** Rewrite using ruleset 1 or 2 depending on whether this is 180556678Seric ** a sender address or not. 18068181Seric ** Then run it through any receiving-mailer-specific rulesets. 18078181Seric */ 18088181Seric 180959163Seric if (bitset(RF_SENDERADDR, flags)) 181059541Seric { 181165071Seric if (rewrite(pvp, 1, 0, e) == EX_TEMPFAIL) 181259163Seric *pstat = EX_TEMPFAIL; 181359541Seric } 18148069Seric else 181559541Seric { 181665071Seric if (rewrite(pvp, 2, 0, e) == EX_TEMPFAIL) 181759163Seric *pstat = EX_TEMPFAIL; 181859541Seric } 181958020Seric if (rwset > 0) 182059541Seric { 182165071Seric if (rewrite(pvp, rwset, 0, e) == EX_TEMPFAIL) 182259163Seric *pstat = EX_TEMPFAIL; 182359541Seric } 18247682Seric 18258181Seric /* 18268959Seric ** Do any final sanitation the address may require. 18278959Seric ** This will normally be used to turn internal forms 18288959Seric ** (e.g., user@host.LOCAL) into external form. This 18298959Seric ** may be used as a default to the above rules. 18308959Seric */ 18318959Seric 183265071Seric if (rewrite(pvp, 4, 0, e) == EX_TEMPFAIL) 183359163Seric *pstat = EX_TEMPFAIL; 18348959Seric 18358959Seric /* 18368181Seric ** Now restore the comment information we had at the beginning. 18378181Seric */ 18388181Seric 183958825Seric cataddr(pvp, NULL, lbuf, sizeof lbuf, '\0'); 184056678Seric define('g', lbuf, e); 184165494Seric 184265494Seric /* need to make sure route-addrs have <angle brackets> */ 184365494Seric if (bitset(RF_CANONICAL, flags) && lbuf[0] == '@') 184468529Seric expand("<\201g>", buf, sizeof buf, e); 184565494Seric else 184668529Seric expand(fancy, buf, sizeof buf, e); 184765494Seric 184856678Seric define('g', oldg, e); 18497682Seric 18507682Seric if (tTd(12, 1)) 18517755Seric printf("remotename => `%s'\n", buf); 18527682Seric return (buf); 18537682Seric } 185451317Seric /* 185556678Seric ** MAPLOCALUSER -- run local username through ruleset 5 for final redirection 185651317Seric ** 185751317Seric ** Parameters: 185856678Seric ** a -- the address to map (but just the user name part). 185956678Seric ** sendq -- the sendq in which to install any replacement 186056678Seric ** addresses. 186167982Seric ** aliaslevel -- the alias nesting depth. 186267982Seric ** e -- the envelope. 186351317Seric ** 186451317Seric ** Returns: 186551317Seric ** none. 186651317Seric */ 186751317Seric 186867982Seric maplocaluser(a, sendq, aliaslevel, e) 186956678Seric register ADDRESS *a; 187056678Seric ADDRESS **sendq; 187167982Seric int aliaslevel; 187256678Seric ENVELOPE *e; 187351317Seric { 187456678Seric register char **pvp; 187556678Seric register ADDRESS *a1 = NULL; 187658333Seric auto char *delimptr; 187756678Seric char pvpbuf[PSBUFSIZE]; 187851317Seric 187956678Seric if (tTd(29, 1)) 188056678Seric { 188156678Seric printf("maplocaluser: "); 188256678Seric printaddr(a, FALSE); 188356678Seric } 188465066Seric pvp = prescan(a->q_user, '\0', pvpbuf, sizeof pvpbuf, &delimptr); 188556678Seric if (pvp == NULL) 188656678Seric return; 188751317Seric 188865071Seric (void) rewrite(pvp, 5, 0, e); 188958050Seric if (pvp[0] == NULL || (pvp[0][0] & 0377) != CANONNET) 189056678Seric return; 189151317Seric 189256678Seric /* if non-null, mailer destination specified -- has it changed? */ 189364284Seric a1 = buildaddr(pvp, NULL, 0, e); 189456678Seric if (a1 == NULL || sameaddr(a, a1)) 189556678Seric return; 189651317Seric 189756678Seric /* mark old address as dead; insert new address */ 189856678Seric a->q_flags |= QDONTSEND; 189957731Seric if (tTd(29, 5)) 190057731Seric { 190157731Seric printf("maplocaluser: QDONTSEND "); 190257731Seric printaddr(a, FALSE); 190357731Seric } 190456678Seric a1->q_alias = a; 190564348Seric allocaddr(a1, RF_COPYALL, NULL); 190667982Seric (void) recipient(a1, sendq, aliaslevel, e); 190751317Seric } 190858802Seric /* 190958802Seric ** DEQUOTE_INIT -- initialize dequote map 191058802Seric ** 191158802Seric ** This is a no-op. 191258802Seric ** 191358802Seric ** Parameters: 191458802Seric ** map -- the internal map structure. 191558802Seric ** args -- arguments. 191658802Seric ** 191758802Seric ** Returns: 191858802Seric ** TRUE. 191958802Seric */ 192058802Seric 192158802Seric bool 192260219Seric dequote_init(map, args) 192358802Seric MAP *map; 192458802Seric char *args; 192558802Seric { 192658805Seric register char *p = args; 192758805Seric 192858805Seric for (;;) 192958805Seric { 193058805Seric while (isascii(*p) && isspace(*p)) 193158805Seric p++; 193258805Seric if (*p != '-') 193358805Seric break; 193458805Seric switch (*++p) 193558805Seric { 193658805Seric case 'a': 193758805Seric map->map_app = ++p; 193858805Seric break; 193967824Seric 194067824Seric case 's': 194167824Seric map->map_coldelim = *++p; 194267824Seric break; 194358805Seric } 194458805Seric while (*p != '\0' && !(isascii(*p) && isspace(*p))) 194558805Seric p++; 194658805Seric if (*p != '\0') 194758805Seric *p = '\0'; 194858805Seric } 194958805Seric if (map->map_app != NULL) 195058805Seric map->map_app = newstr(map->map_app); 195158805Seric 195258802Seric return TRUE; 195358802Seric } 195458802Seric /* 195558802Seric ** DEQUOTE_MAP -- unquote an address 195658802Seric ** 195758802Seric ** Parameters: 195858802Seric ** map -- the internal map structure (ignored). 195960089Seric ** name -- the name to dequote. 196058802Seric ** av -- arguments (ignored). 196159084Seric ** statp -- pointer to status out-parameter. 196258802Seric ** 196358802Seric ** Returns: 196458802Seric ** NULL -- if there were no quotes, or if the resulting 196558802Seric ** unquoted buffer would not be acceptable to prescan. 196658802Seric ** else -- The dequoted buffer. 196758802Seric */ 196858802Seric 196958802Seric char * 197060089Seric dequote_map(map, name, av, statp) 197158802Seric MAP *map; 197260089Seric char *name; 197358802Seric char **av; 197459084Seric int *statp; 197558802Seric { 197658802Seric register char *p; 197758802Seric register char *q; 197858802Seric register char c; 197967824Seric int anglecnt = 0; 198067824Seric int cmntcnt = 0; 198167824Seric int quotecnt = 0; 198267824Seric int spacecnt = 0; 198367824Seric bool quotemode = FALSE; 198467824Seric bool bslashmode = FALSE; 198567824Seric char spacesub = map->map_coldelim; 198658802Seric 198760089Seric for (p = q = name; (c = *p++) != '\0'; ) 198858802Seric { 198958802Seric if (bslashmode) 199058802Seric { 199158802Seric bslashmode = FALSE; 199258802Seric *q++ = c; 199358802Seric continue; 199458802Seric } 199558802Seric 199667824Seric if (c == ' ' && spacesub != '\0') 199767824Seric c = spacesub; 199867764Seric 199958802Seric switch (c) 200058802Seric { 200158802Seric case '\\': 200258802Seric bslashmode = TRUE; 200358802Seric break; 200458802Seric 200558802Seric case '(': 200658802Seric cmntcnt++; 200758802Seric break; 200858802Seric 200958802Seric case ')': 201058802Seric if (cmntcnt-- <= 0) 201158802Seric return NULL; 201258802Seric break; 201359089Seric 201459089Seric case ' ': 201559089Seric spacecnt++; 201659089Seric break; 201758802Seric } 201858802Seric 201958802Seric if (cmntcnt > 0) 202058802Seric { 202158802Seric *q++ = c; 202258802Seric continue; 202358802Seric } 202458802Seric 202558802Seric switch (c) 202658802Seric { 202758802Seric case '"': 202858802Seric quotemode = !quotemode; 202958802Seric quotecnt++; 203058802Seric continue; 203158802Seric 203258802Seric case '<': 203358802Seric anglecnt++; 203458802Seric break; 203558802Seric 203658802Seric case '>': 203758802Seric if (anglecnt-- <= 0) 203858802Seric return NULL; 203958802Seric break; 204058802Seric } 204158802Seric *q++ = c; 204258802Seric } 204358802Seric 204458802Seric if (anglecnt != 0 || cmntcnt != 0 || bslashmode || 204559089Seric quotemode || quotecnt <= 0 || spacecnt != 0) 204658802Seric return NULL; 204758802Seric *q++ = '\0'; 204860089Seric return name; 204958802Seric } 2050