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*68529Seric static char sccsid[] = "@(#)parseaddr.c 8.58 (Berkeley) 03/14/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; 374*68529Seric 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 114758050Seric if (*npvp != NULL && (**npvp & 0377) == CALLSUBR) 114856678Seric { 114959084Seric int stat; 115059084Seric 115165379Seric if (npvp[1] == NULL) 115265379Seric { 115365379Seric syserr("parseaddr: NULL subroutine call in ruleset %d, rule %d", 115465379Seric ruleset, ruleno); 115565379Seric *pvp = NULL; 115665379Seric } 115765379Seric else 115865379Seric { 115968385Seric int ruleset; 116068385Seric STAB *s; 116168385Seric 116265379Seric bcopy((char *) &npvp[2], (char *) pvp, 116365379Seric (int) (avp - npvp - 2) * sizeof *avp); 116465379Seric if (tTd(21, 3)) 116565379Seric printf("-----callsubr %s\n", npvp[1]); 116668385Seric s = stab(npvp[1], ST_RULESET, ST_FIND); 116768385Seric if (s == NULL) 116868385Seric ruleset = atoi(npvp[1]); 116968385Seric else 117068385Seric ruleset = s->s_ruleset; 117168385Seric stat = rewrite(pvp, ruleset, reclevel, e); 117265379Seric if (rstat == EX_OK || stat == EX_TEMPFAIL) 117365379Seric rstat = stat; 117465379Seric if (*pvp != NULL && (**pvp & 0377) == CANONNET) 117563581Seric rwr = NULL; 117665379Seric } 117756678Seric } 117856678Seric else 117956678Seric { 118017348Seric bcopy((char *) npvp, (char *) pvp, 118116900Seric (int) (avp - npvp) * sizeof *avp); 118256678Seric } 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 "QHAS_RET_PARAM", QHAS_RET_PARAM, 160567994Seric "QRET_HDRS", QRET_HDRS, 160667994Seric "QRELAYED", QRELAYED, 160767994Seric NULL 160867994Seric }; 160967994Seric 161068433Seric void 16113234Seric printaddr(a, follow) 16123234Seric register ADDRESS *a; 16133234Seric bool follow; 16143234Seric { 161557731Seric register MAILER *m; 161657731Seric MAILER pseudomailer; 161767994Seric register struct qflags *qfp; 161867994Seric bool firstone; 16195001Seric 162067994Seric if (a == NULL) 162167994Seric { 162267994Seric printf("[NULL]\n"); 162367994Seric return; 162467994Seric } 162567994Seric 16263234Seric while (a != NULL) 16273234Seric { 16284443Seric printf("%x=", a); 16294085Seric (void) fflush(stdout); 163057731Seric 163157731Seric /* find the mailer -- carefully */ 163257731Seric m = a->q_mailer; 163357731Seric if (m == NULL) 163457731Seric { 163557731Seric m = &pseudomailer; 163657731Seric m->m_mno = -1; 163757731Seric m->m_name = "NULL"; 163857731Seric } 163957731Seric 164058680Seric printf("%s:\n\tmailer %d (%s), host `%s', user `%s', ruser `%s'\n", 164157731Seric a->q_paddr, m->m_mno, m->m_name, 164267172Seric a->q_host == NULL ? "<null>" : a->q_host, a->q_user, 164367172Seric a->q_ruser == NULL ? "<null>" : a->q_ruser); 164467994Seric printf("\tnext=%x, alias %x, uid %d, gid %d\n", 164567994Seric a->q_next, a->q_alias, a->q_uid, a->q_gid); 164667994Seric printf("\tflags=%lx<", a->q_flags); 164767994Seric firstone = TRUE; 164867994Seric for (qfp = AddressFlags; qfp->qf_name != NULL; qfp++) 164967994Seric { 165067994Seric if (!bitset(qfp->qf_bit, a->q_flags)) 165167994Seric continue; 165267994Seric if (!firstone) 165367994Seric printf(","); 165467994Seric firstone = FALSE; 165567994Seric printf("%s", qfp->qf_name); 165667994Seric } 165767994Seric printf(">\n"); 165859269Seric printf("\towner=%s, home=\"%s\", fullname=\"%s\"\n", 165959269Seric a->q_owner == NULL ? "(none)" : a->q_owner, 166063756Seric a->q_home == NULL ? "(none)" : a->q_home, 166163756Seric a->q_fullname == NULL ? "(none)" : a->q_fullname); 166268228Seric printf("\torcpt=\"%s\", statmta=%s, rstatus=%s\n", 166367987Seric a->q_orcpt == NULL ? "(none)" : a->q_orcpt, 166467987Seric a->q_statmta == NULL ? "(none)" : a->q_statmta, 166567990Seric a->q_rstatus == NULL ? "(none)" : a->q_rstatus); 16664996Seric 16673234Seric if (!follow) 16683234Seric return; 16694996Seric a = a->q_next; 16703234Seric } 16713234Seric } 167267939Seric /* 167367939Seric ** EMPTYADDR -- return TRUE if this address is empty (``<>'') 167467939Seric ** 167567939Seric ** Parameters: 167667939Seric ** a -- pointer to the address 167767939Seric ** 167867939Seric ** Returns: 167967939Seric ** TRUE -- if this address is "empty" (i.e., no one should 168067939Seric ** ever generate replies to it. 168167939Seric ** FALSE -- if it is a "regular" (read: replyable) address. 168267939Seric */ 16834317Seric 168467939Seric bool 168567939Seric emptyaddr(a) 168667939Seric register ADDRESS *a; 168767939Seric { 168867939Seric return strcmp(a->q_paddr, "<>") == 0 || strcmp(a->q_user, "<>") == 0; 168967939Seric } 16907682Seric /* 16917682Seric ** REMOTENAME -- return the name relative to the current mailer 16927682Seric ** 16937682Seric ** Parameters: 16947682Seric ** name -- the name to translate. 16958069Seric ** m -- the mailer that we want to do rewriting relative 16968069Seric ** to. 169759163Seric ** flags -- fine tune operations. 169859163Seric ** pstat -- pointer to status word. 169958020Seric ** e -- the current envelope. 17007682Seric ** 17017682Seric ** Returns: 17027682Seric ** the text string representing this address relative to 17037682Seric ** the receiving mailer. 17047682Seric ** 17057682Seric ** Side Effects: 17067682Seric ** none. 17077682Seric ** 17087682Seric ** Warnings: 17097682Seric ** The text string returned is tucked away locally; 17107682Seric ** copy it if you intend to save it. 17117682Seric */ 17127682Seric 17137682Seric char * 171459163Seric remotename(name, m, flags, pstat, e) 17157682Seric char *name; 171656678Seric struct mailer *m; 171759163Seric int flags; 171859163Seric int *pstat; 171956678Seric register ENVELOPE *e; 17207682Seric { 17218069Seric register char **pvp; 17228069Seric char *fancy; 172356678Seric char *oldg = macvalue('g', e); 172458020Seric int rwset; 172568528Seric static char buf[MAXNAME + 1]; 172668528Seric char lbuf[MAXNAME + 1]; 172716914Seric char pvpbuf[PSBUFSIZE]; 172856678Seric extern char *crackaddr(); 17297682Seric 17307755Seric if (tTd(12, 1)) 17317755Seric printf("remotename(%s)\n", name); 17327755Seric 173310177Seric /* don't do anything if we are tagging it as special */ 173459163Seric if (bitset(RF_SENDERADDR, flags)) 173559163Seric rwset = bitset(RF_HEADERADDR, flags) ? m->m_sh_rwset 173659163Seric : m->m_se_rwset; 173758020Seric else 173859163Seric rwset = bitset(RF_HEADERADDR, flags) ? m->m_rh_rwset 173959163Seric : m->m_re_rwset; 174058020Seric if (rwset < 0) 174110177Seric return (name); 174210177Seric 17437682Seric /* 17448181Seric ** Do a heuristic crack of this name to extract any comment info. 17458181Seric ** This will leave the name as a comment and a $g macro. 17467889Seric */ 17477889Seric 174859163Seric if (bitset(RF_CANONICAL, flags) || bitnset(M_NOCOMMENT, m->m_flags)) 174958050Seric fancy = "\201g"; 175010310Seric else 175110310Seric fancy = crackaddr(name); 17527889Seric 17538181Seric /* 17548181Seric ** Turn the name into canonical form. 17558181Seric ** Normally this will be RFC 822 style, i.e., "user@domain". 17568181Seric ** If this only resolves to "user", and the "C" flag is 17578181Seric ** specified in the sending mailer, then the sender's 17588181Seric ** domain will be appended. 17598181Seric */ 17608181Seric 176165066Seric pvp = prescan(name, '\0', pvpbuf, sizeof pvpbuf, NULL); 17627889Seric if (pvp == NULL) 17637889Seric return (name); 176465071Seric if (rewrite(pvp, 3, 0, e) == EX_TEMPFAIL) 176559163Seric *pstat = EX_TEMPFAIL; 176659163Seric if (bitset(RF_ADDDOMAIN, flags) && e->e_fromdomain != NULL) 17678181Seric { 17688181Seric /* append from domain to this address */ 17698181Seric register char **pxp = pvp; 17708181Seric 17719594Seric /* see if there is an "@domain" in the current name */ 17728181Seric while (*pxp != NULL && strcmp(*pxp, "@") != 0) 17738181Seric pxp++; 17748181Seric if (*pxp == NULL) 17758181Seric { 17769594Seric /* no.... append the "@domain" from the sender */ 177756678Seric register char **qxq = e->e_fromdomain; 17788181Seric 17799594Seric while ((*pxp++ = *qxq++) != NULL) 17809594Seric continue; 178165071Seric if (rewrite(pvp, 3, 0, e) == EX_TEMPFAIL) 178259163Seric *pstat = EX_TEMPFAIL; 17838181Seric } 17848181Seric } 17858181Seric 17868181Seric /* 17878959Seric ** Do more specific rewriting. 178856678Seric ** Rewrite using ruleset 1 or 2 depending on whether this is 178956678Seric ** a sender address or not. 17908181Seric ** Then run it through any receiving-mailer-specific rulesets. 17918181Seric */ 17928181Seric 179359163Seric if (bitset(RF_SENDERADDR, flags)) 179459541Seric { 179565071Seric if (rewrite(pvp, 1, 0, e) == EX_TEMPFAIL) 179659163Seric *pstat = EX_TEMPFAIL; 179759541Seric } 17988069Seric else 179959541Seric { 180065071Seric if (rewrite(pvp, 2, 0, e) == EX_TEMPFAIL) 180159163Seric *pstat = EX_TEMPFAIL; 180259541Seric } 180358020Seric if (rwset > 0) 180459541Seric { 180565071Seric if (rewrite(pvp, rwset, 0, e) == EX_TEMPFAIL) 180659163Seric *pstat = EX_TEMPFAIL; 180759541Seric } 18087682Seric 18098181Seric /* 18108959Seric ** Do any final sanitation the address may require. 18118959Seric ** This will normally be used to turn internal forms 18128959Seric ** (e.g., user@host.LOCAL) into external form. This 18138959Seric ** may be used as a default to the above rules. 18148959Seric */ 18158959Seric 181665071Seric if (rewrite(pvp, 4, 0, e) == EX_TEMPFAIL) 181759163Seric *pstat = EX_TEMPFAIL; 18188959Seric 18198959Seric /* 18208181Seric ** Now restore the comment information we had at the beginning. 18218181Seric */ 18228181Seric 182358825Seric cataddr(pvp, NULL, lbuf, sizeof lbuf, '\0'); 182456678Seric define('g', lbuf, e); 182565494Seric 182665494Seric /* need to make sure route-addrs have <angle brackets> */ 182765494Seric if (bitset(RF_CANONICAL, flags) && lbuf[0] == '@') 1828*68529Seric expand("<\201g>", buf, sizeof buf, e); 182965494Seric else 1830*68529Seric expand(fancy, buf, sizeof buf, e); 183165494Seric 183256678Seric define('g', oldg, e); 18337682Seric 18347682Seric if (tTd(12, 1)) 18357755Seric printf("remotename => `%s'\n", buf); 18367682Seric return (buf); 18377682Seric } 183851317Seric /* 183956678Seric ** MAPLOCALUSER -- run local username through ruleset 5 for final redirection 184051317Seric ** 184151317Seric ** Parameters: 184256678Seric ** a -- the address to map (but just the user name part). 184356678Seric ** sendq -- the sendq in which to install any replacement 184456678Seric ** addresses. 184567982Seric ** aliaslevel -- the alias nesting depth. 184667982Seric ** e -- the envelope. 184751317Seric ** 184851317Seric ** Returns: 184951317Seric ** none. 185051317Seric */ 185151317Seric 185267982Seric maplocaluser(a, sendq, aliaslevel, e) 185356678Seric register ADDRESS *a; 185456678Seric ADDRESS **sendq; 185567982Seric int aliaslevel; 185656678Seric ENVELOPE *e; 185751317Seric { 185856678Seric register char **pvp; 185956678Seric register ADDRESS *a1 = NULL; 186058333Seric auto char *delimptr; 186156678Seric char pvpbuf[PSBUFSIZE]; 186251317Seric 186356678Seric if (tTd(29, 1)) 186456678Seric { 186556678Seric printf("maplocaluser: "); 186656678Seric printaddr(a, FALSE); 186756678Seric } 186865066Seric pvp = prescan(a->q_user, '\0', pvpbuf, sizeof pvpbuf, &delimptr); 186956678Seric if (pvp == NULL) 187056678Seric return; 187151317Seric 187265071Seric (void) rewrite(pvp, 5, 0, e); 187358050Seric if (pvp[0] == NULL || (pvp[0][0] & 0377) != CANONNET) 187456678Seric return; 187551317Seric 187656678Seric /* if non-null, mailer destination specified -- has it changed? */ 187764284Seric a1 = buildaddr(pvp, NULL, 0, e); 187856678Seric if (a1 == NULL || sameaddr(a, a1)) 187956678Seric return; 188051317Seric 188156678Seric /* mark old address as dead; insert new address */ 188256678Seric a->q_flags |= QDONTSEND; 188357731Seric if (tTd(29, 5)) 188457731Seric { 188557731Seric printf("maplocaluser: QDONTSEND "); 188657731Seric printaddr(a, FALSE); 188757731Seric } 188856678Seric a1->q_alias = a; 188964348Seric allocaddr(a1, RF_COPYALL, NULL); 189067982Seric (void) recipient(a1, sendq, aliaslevel, e); 189151317Seric } 189258802Seric /* 189358802Seric ** DEQUOTE_INIT -- initialize dequote map 189458802Seric ** 189558802Seric ** This is a no-op. 189658802Seric ** 189758802Seric ** Parameters: 189858802Seric ** map -- the internal map structure. 189958802Seric ** args -- arguments. 190058802Seric ** 190158802Seric ** Returns: 190258802Seric ** TRUE. 190358802Seric */ 190458802Seric 190558802Seric bool 190660219Seric dequote_init(map, args) 190758802Seric MAP *map; 190858802Seric char *args; 190958802Seric { 191058805Seric register char *p = args; 191158805Seric 191258805Seric for (;;) 191358805Seric { 191458805Seric while (isascii(*p) && isspace(*p)) 191558805Seric p++; 191658805Seric if (*p != '-') 191758805Seric break; 191858805Seric switch (*++p) 191958805Seric { 192058805Seric case 'a': 192158805Seric map->map_app = ++p; 192258805Seric break; 192367824Seric 192467824Seric case 's': 192567824Seric map->map_coldelim = *++p; 192667824Seric break; 192758805Seric } 192858805Seric while (*p != '\0' && !(isascii(*p) && isspace(*p))) 192958805Seric p++; 193058805Seric if (*p != '\0') 193158805Seric *p = '\0'; 193258805Seric } 193358805Seric if (map->map_app != NULL) 193458805Seric map->map_app = newstr(map->map_app); 193558805Seric 193658802Seric return TRUE; 193758802Seric } 193858802Seric /* 193958802Seric ** DEQUOTE_MAP -- unquote an address 194058802Seric ** 194158802Seric ** Parameters: 194258802Seric ** map -- the internal map structure (ignored). 194360089Seric ** name -- the name to dequote. 194458802Seric ** av -- arguments (ignored). 194559084Seric ** statp -- pointer to status out-parameter. 194658802Seric ** 194758802Seric ** Returns: 194858802Seric ** NULL -- if there were no quotes, or if the resulting 194958802Seric ** unquoted buffer would not be acceptable to prescan. 195058802Seric ** else -- The dequoted buffer. 195158802Seric */ 195258802Seric 195358802Seric char * 195460089Seric dequote_map(map, name, av, statp) 195558802Seric MAP *map; 195660089Seric char *name; 195758802Seric char **av; 195859084Seric int *statp; 195958802Seric { 196058802Seric register char *p; 196158802Seric register char *q; 196258802Seric register char c; 196367824Seric int anglecnt = 0; 196467824Seric int cmntcnt = 0; 196567824Seric int quotecnt = 0; 196667824Seric int spacecnt = 0; 196767824Seric bool quotemode = FALSE; 196867824Seric bool bslashmode = FALSE; 196967824Seric char spacesub = map->map_coldelim; 197058802Seric 197160089Seric for (p = q = name; (c = *p++) != '\0'; ) 197258802Seric { 197358802Seric if (bslashmode) 197458802Seric { 197558802Seric bslashmode = FALSE; 197658802Seric *q++ = c; 197758802Seric continue; 197858802Seric } 197958802Seric 198067824Seric if (c == ' ' && spacesub != '\0') 198167824Seric c = spacesub; 198267764Seric 198358802Seric switch (c) 198458802Seric { 198558802Seric case '\\': 198658802Seric bslashmode = TRUE; 198758802Seric break; 198858802Seric 198958802Seric case '(': 199058802Seric cmntcnt++; 199158802Seric break; 199258802Seric 199358802Seric case ')': 199458802Seric if (cmntcnt-- <= 0) 199558802Seric return NULL; 199658802Seric break; 199759089Seric 199859089Seric case ' ': 199959089Seric spacecnt++; 200059089Seric break; 200158802Seric } 200258802Seric 200358802Seric if (cmntcnt > 0) 200458802Seric { 200558802Seric *q++ = c; 200658802Seric continue; 200758802Seric } 200858802Seric 200958802Seric switch (c) 201058802Seric { 201158802Seric case '"': 201258802Seric quotemode = !quotemode; 201358802Seric quotecnt++; 201458802Seric continue; 201558802Seric 201658802Seric case '<': 201758802Seric anglecnt++; 201858802Seric break; 201958802Seric 202058802Seric case '>': 202158802Seric if (anglecnt-- <= 0) 202258802Seric return NULL; 202358802Seric break; 202458802Seric } 202558802Seric *q++ = c; 202658802Seric } 202758802Seric 202858802Seric if (anglecnt != 0 || cmntcnt != 0 || bslashmode || 202959089Seric quotemode || quotecnt <= 0 || spacecnt != 0) 203058802Seric return NULL; 203158802Seric *q++ = '\0'; 203260089Seric return name; 203358802Seric } 2034