13312Seric # include "sendmail.h" 2297Seric 3*16162Seric SCCSID(@(#)parseaddr.c 4.5 03/11/84); 4407Seric 5297Seric /* 69888Seric ** PARSEADDR -- Parse an address 7297Seric ** 8297Seric ** Parses an address and breaks it up into three parts: a 9297Seric ** net to transmit the message on, the host to transmit it 10297Seric ** to, and a user on that host. These are loaded into an 112973Seric ** ADDRESS header with the values squirreled away if necessary. 12297Seric ** The "user" part may not be a real user; the process may 13297Seric ** just reoccur on that machine. For example, on a machine 14297Seric ** with an arpanet connection, the address 15297Seric ** csvax.bill@berkeley 16297Seric ** will break up to a "user" of 'csvax.bill' and a host 17297Seric ** of 'berkeley' -- to be transmitted over the arpanet. 18297Seric ** 19297Seric ** Parameters: 20297Seric ** addr -- the address to parse. 21297Seric ** a -- a pointer to the address descriptor buffer. 22297Seric ** If NULL, a header will be created. 23297Seric ** copyf -- determines what shall be copied: 24297Seric ** -1 -- don't copy anything. The printname 25297Seric ** (q_paddr) is just addr, and the 26297Seric ** user & host are allocated internally 27297Seric ** to parse. 28297Seric ** 0 -- copy out the parsed user & host, but 29297Seric ** don't copy the printname. 30297Seric ** +1 -- copy everything. 3111445Seric ** delim -- the character to terminate the address, passed 3211445Seric ** to prescan. 33297Seric ** 34297Seric ** Returns: 35297Seric ** A pointer to the address descriptor header (`a' if 36297Seric ** `a' is non-NULL). 37297Seric ** NULL on error. 38297Seric ** 39297Seric ** Side Effects: 40297Seric ** none 41297Seric */ 42297Seric 439374Seric /* following delimiters are inherent to the internal algorithms */ 4416155Seric # define DELIMCHARS "\001()<>,;\\\"\r\n" /* word delimiters */ 452091Seric 462973Seric ADDRESS * 4711445Seric parseaddr(addr, a, copyf, delim) 48297Seric char *addr; 492973Seric register ADDRESS *a; 50297Seric int copyf; 5111445Seric char delim; 52297Seric { 533149Seric register char **pvp; 543149Seric register struct mailer *m; 553149Seric extern char **prescan(); 563149Seric extern ADDRESS *buildaddr(); 57297Seric 58297Seric /* 59297Seric ** Initialize and prescan address. 60297Seric */ 61297Seric 626903Seric CurEnv->e_to = addr; 633188Seric # ifdef DEBUG 647675Seric if (tTd(20, 1)) 659888Seric printf("\n--parseaddr(%s)\n", addr); 663188Seric # endif DEBUG 673188Seric 6811445Seric pvp = prescan(addr, delim); 693149Seric if (pvp == NULL) 70297Seric return (NULL); 71297Seric 72297Seric /* 733149Seric ** Apply rewriting rules. 747889Seric ** Ruleset 0 does basic parsing. It must resolve. 75297Seric */ 76297Seric 778181Seric rewrite(pvp, 3); 784070Seric rewrite(pvp, 0); 79297Seric 803149Seric /* 813149Seric ** See if we resolved to a real mailer. 823149Seric */ 83297Seric 843149Seric if (pvp[0][0] != CANONNET) 853149Seric { 863149Seric setstat(EX_USAGE); 873149Seric usrerr("cannot resolve name"); 883149Seric return (NULL); 89297Seric } 90297Seric 91297Seric /* 923149Seric ** Build canonical address from pvp. 93297Seric */ 94297Seric 953149Seric a = buildaddr(pvp, a); 964279Seric if (a == NULL) 974279Seric return (NULL); 984598Seric m = a->q_mailer; 99297Seric 100297Seric /* 1013149Seric ** Make local copies of the host & user and then 1023149Seric ** transport them out. 103297Seric */ 104297Seric 105297Seric if (copyf > 0) 1068078Seric { 1078078Seric extern char *DelimChar; 1088078Seric char savec = *DelimChar; 1098078Seric 1108078Seric *DelimChar = '\0'; 1112973Seric a->q_paddr = newstr(addr); 1128078Seric *DelimChar = savec; 1138078Seric } 114297Seric else 115297Seric a->q_paddr = addr; 1163149Seric if (copyf >= 0) 117297Seric { 1183149Seric if (a->q_host != NULL) 1193149Seric a->q_host = newstr(a->q_host); 120297Seric else 1213149Seric a->q_host = ""; 1223149Seric if (a->q_user != a->q_paddr) 1233149Seric a->q_user = newstr(a->q_user); 124297Seric } 125297Seric 126297Seric /* 127297Seric ** Compute return value. 128297Seric */ 129297Seric 130297Seric # ifdef DEBUG 1317675Seric if (tTd(20, 1)) 1324443Seric { 1339888Seric printf("parseaddr-->"); 1344443Seric printaddr(a, FALSE); 1354443Seric } 136297Seric # endif DEBUG 137297Seric 138297Seric return (a); 139297Seric } 140297Seric /* 141*16162Seric ** LOWERADDR -- map UPPER->lower case on addresses as requested. 142*16162Seric ** 143*16162Seric ** Parameters: 144*16162Seric ** a -- address to be mapped. 145*16162Seric ** 146*16162Seric ** Returns: 147*16162Seric ** none. 148*16162Seric ** 149*16162Seric ** Side Effects: 150*16162Seric ** none. 151*16162Seric */ 152*16162Seric 153*16162Seric loweraddr(a) 154*16162Seric register ADDRESS *a; 155*16162Seric { 156*16162Seric register MAILER *m = a->q_mailer; 157*16162Seric 158*16162Seric if (!bitnset(M_HST_UPPER, m->m_flags)) 159*16162Seric makelower(a->q_host); 160*16162Seric if (!bitnset(M_USR_UPPER, m->m_flags)) 161*16162Seric makelower(a->q_user); 162*16162Seric } 163*16162Seric /* 164297Seric ** PRESCAN -- Prescan name and make it canonical 165297Seric ** 1669374Seric ** Scans a name and turns it into a set of tokens. This process 1679374Seric ** deletes blanks and comments (in parentheses). 168297Seric ** 169297Seric ** This routine knows about quoted strings and angle brackets. 170297Seric ** 171297Seric ** There are certain subtleties to this routine. The one that 172297Seric ** comes to mind now is that backslashes on the ends of names 173297Seric ** are silently stripped off; this is intentional. The problem 174297Seric ** is that some versions of sndmsg (like at LBL) set the kill 175297Seric ** character to something other than @ when reading addresses; 176297Seric ** so people type "csvax.eric\@berkeley" -- which screws up the 177297Seric ** berknet mailer. 178297Seric ** 179297Seric ** Parameters: 180297Seric ** addr -- the name to chomp. 181297Seric ** delim -- the delimiter for the address, normally 182297Seric ** '\0' or ','; \0 is accepted in any case. 18315284Seric ** If '\t' then we are reading the .cf file. 184297Seric ** 185297Seric ** Returns: 1863149Seric ** A pointer to a vector of tokens. 187297Seric ** NULL on error. 188297Seric ** 189297Seric ** Side Effects: 1903149Seric ** none. 191297Seric */ 192297Seric 1938078Seric /* states and character types */ 1948078Seric # define OPR 0 /* operator */ 1958078Seric # define ATM 1 /* atom */ 1968078Seric # define QST 2 /* in quoted string */ 1978078Seric # define SPC 3 /* chewing up spaces */ 1988078Seric # define ONE 4 /* pick up one character */ 1993149Seric 2008078Seric # define NSTATES 5 /* number of states */ 2018078Seric # define TYPE 017 /* mask to select state type */ 2028078Seric 2038078Seric /* meta bits for table */ 2048078Seric # define M 020 /* meta character; don't pass through */ 2058078Seric # define B 040 /* cause a break */ 2068078Seric # define MB M|B /* meta-break */ 2078078Seric 2088078Seric static short StateTab[NSTATES][NSTATES] = 2098078Seric { 2108087Seric /* oldst chtype> OPR ATM QST SPC ONE */ 2119051Seric /*OPR*/ OPR|B, ATM|B, QST|B, SPC|MB, ONE|B, 2129051Seric /*ATM*/ OPR|B, ATM, QST|B, SPC|MB, ONE|B, 2139051Seric /*QST*/ QST, QST, OPR, QST, QST, 2148078Seric /*SPC*/ OPR, ATM, QST, SPC|M, ONE, 2158078Seric /*ONE*/ OPR, OPR, OPR, OPR, OPR, 2168078Seric }; 2178078Seric 2188078Seric # define NOCHAR -1 /* signal nothing in lookahead token */ 2198078Seric 2208078Seric char *DelimChar; /* set to point to the delimiter */ 2218078Seric 2223149Seric char ** 2233149Seric prescan(addr, delim) 224297Seric char *addr; 225297Seric char delim; 226297Seric { 227297Seric register char *p; 2288078Seric register char *q; 2299346Seric register int c; 2303149Seric char **avp; 231297Seric bool bslashmode; 232297Seric int cmntcnt; 2338423Seric int anglecnt; 2343149Seric char *tok; 2358078Seric int state; 2368078Seric int newstate; 2378078Seric static char buf[MAXNAME+MAXATOM]; 2388078Seric static char *av[MAXATOM+1]; 23915253Seric extern int errno; 240297Seric 24115253Seric /* make sure error messages don't have garbage on them */ 24215253Seric errno = 0; 24315253Seric 244297Seric q = buf; 2453149Seric bslashmode = FALSE; 2467800Seric cmntcnt = 0; 2478423Seric anglecnt = 0; 2483149Seric avp = av; 2498078Seric state = OPR; 2508078Seric c = NOCHAR; 2518078Seric p = addr; 2528078Seric # ifdef DEBUG 2538078Seric if (tTd(22, 45)) 254297Seric { 2558078Seric printf("prescan: "); 2568078Seric xputs(p); 2578078Seric putchar('\n'); 2588078Seric } 2598078Seric # endif DEBUG 2608078Seric 2618078Seric do 2628078Seric { 2633149Seric /* read a token */ 2643149Seric tok = q; 2658078Seric for (;;) 266297Seric { 2678078Seric /* store away any old lookahead character */ 2688078Seric if (c != NOCHAR) 2698078Seric { 27015284Seric /* see if there is room */ 2718078Seric if (q >= &buf[sizeof buf - 5]) 2728078Seric { 2738078Seric usrerr("Address too long"); 2748078Seric DelimChar = p; 2758078Seric return (NULL); 2768078Seric } 27715284Seric 27815284Seric /* squirrel it away */ 2798078Seric *q++ = c; 2808078Seric } 2818078Seric 2828078Seric /* read a new input character */ 2838078Seric c = *p++; 2848078Seric if (c == '\0') 2858078Seric break; 28615284Seric c &= ~0200; 28715284Seric 2888078Seric # ifdef DEBUG 2898078Seric if (tTd(22, 101)) 2908078Seric printf("c=%c, s=%d; ", c, state); 2918078Seric # endif DEBUG 2928078Seric 2933149Seric /* chew up special characters */ 2943149Seric *q = '\0'; 2953149Seric if (bslashmode) 2963149Seric { 2973149Seric c |= 0200; 2983149Seric bslashmode = FALSE; 2993149Seric } 3003149Seric else if (c == '\\') 3013149Seric { 3023149Seric bslashmode = TRUE; 3038078Seric c = NOCHAR; 3043149Seric } 3058514Seric else if (state == QST) 3068514Seric { 3078514Seric /* do nothing, just avoid next clauses */ 3088514Seric } 3098078Seric else if (c == '(') 3104100Seric { 3118078Seric cmntcnt++; 3128078Seric c = NOCHAR; 3134100Seric } 3148078Seric else if (c == ')') 3153149Seric { 3168078Seric if (cmntcnt <= 0) 3173149Seric { 3188078Seric usrerr("Unbalanced ')'"); 3198078Seric DelimChar = p; 3208078Seric return (NULL); 3213149Seric } 3228078Seric else 3238078Seric cmntcnt--; 3248078Seric } 3258078Seric else if (cmntcnt > 0) 3268078Seric c = NOCHAR; 3278423Seric else if (c == '<') 3288423Seric anglecnt++; 3298423Seric else if (c == '>') 3308423Seric { 3318423Seric if (anglecnt <= 0) 3328423Seric { 3338423Seric usrerr("Unbalanced '>'"); 3348423Seric DelimChar = p; 3358423Seric return (NULL); 3368423Seric } 3378423Seric anglecnt--; 3388423Seric } 33911423Seric else if (delim == ' ' && isspace(c)) 34011423Seric c = ' '; 3413149Seric 3428078Seric if (c == NOCHAR) 3438078Seric continue; 3443149Seric 3458078Seric /* see if this is end of input */ 34611405Seric if (c == delim && anglecnt <= 0 && state != QST) 3473149Seric break; 3483149Seric 3498078Seric newstate = StateTab[state][toktype(c)]; 3508078Seric # ifdef DEBUG 3518078Seric if (tTd(22, 101)) 3528078Seric printf("ns=%02o\n", newstate); 3538078Seric # endif DEBUG 3548078Seric state = newstate & TYPE; 3558078Seric if (bitset(M, newstate)) 3568078Seric c = NOCHAR; 3578078Seric if (bitset(B, newstate)) 3584228Seric break; 359297Seric } 3603149Seric 3613149Seric /* new token */ 3628078Seric if (tok != q) 3631378Seric { 3648078Seric *q++ = '\0'; 3658078Seric # ifdef DEBUG 3668078Seric if (tTd(22, 36)) 367297Seric { 3688078Seric printf("tok="); 3698078Seric xputs(tok); 3708078Seric putchar('\n'); 371297Seric } 3728078Seric # endif DEBUG 3738078Seric if (avp >= &av[MAXATOM]) 374297Seric { 3758078Seric syserr("prescan: too many tokens"); 3768078Seric DelimChar = p; 3778078Seric return (NULL); 378297Seric } 3798078Seric *avp++ = tok; 380297Seric } 3818423Seric } while (c != '\0' && (c != delim || anglecnt > 0)); 3823149Seric *avp = NULL; 3838078Seric DelimChar = --p; 3843149Seric if (cmntcnt > 0) 3853149Seric usrerr("Unbalanced '('"); 3868423Seric else if (anglecnt > 0) 3878423Seric usrerr("Unbalanced '<'"); 3888078Seric else if (state == QST) 3893149Seric usrerr("Unbalanced '\"'"); 3903149Seric else if (av[0] != NULL) 3913149Seric return (av); 3923149Seric return (NULL); 3933149Seric } 3943149Seric /* 3953149Seric ** TOKTYPE -- return token type 3963149Seric ** 3973149Seric ** Parameters: 3983149Seric ** c -- the character in question. 3993149Seric ** 4003149Seric ** Returns: 4013149Seric ** Its type. 4023149Seric ** 4033149Seric ** Side Effects: 4043149Seric ** none. 4053149Seric */ 406297Seric 4073149Seric toktype(c) 4083149Seric register char c; 4093149Seric { 4103380Seric static char buf[50]; 4113382Seric static bool firstime = TRUE; 4123380Seric 4133382Seric if (firstime) 4143380Seric { 4153382Seric firstime = FALSE; 41616155Seric expand("\001o", buf, &buf[sizeof buf - 1], CurEnv); 4177005Seric (void) strcat(buf, DELIMCHARS); 4183380Seric } 4199585Seric if (c == MATCHCLASS || c == MATCHREPL || c == MATCHNCLASS) 4208078Seric return (ONE); 4218078Seric if (c == '"') 4228078Seric return (QST); 4234100Seric if (!isascii(c)) 4248078Seric return (ATM); 4258078Seric if (isspace(c) || c == ')') 4268078Seric return (SPC); 4273380Seric if (iscntrl(c) || index(buf, c) != NULL) 4288078Seric return (OPR); 4298078Seric return (ATM); 4303149Seric } 4313149Seric /* 4323149Seric ** REWRITE -- apply rewrite rules to token vector. 4333149Seric ** 4344476Seric ** This routine is an ordered production system. Each rewrite 4354476Seric ** rule has a LHS (called the pattern) and a RHS (called the 4364476Seric ** rewrite); 'rwr' points the the current rewrite rule. 4374476Seric ** 4384476Seric ** For each rewrite rule, 'avp' points the address vector we 4394476Seric ** are trying to match against, and 'pvp' points to the pattern. 4408058Seric ** If pvp points to a special match value (MATCHZANY, MATCHANY, 4419585Seric ** MATCHONE, MATCHCLASS, MATCHNCLASS) then the address in avp 4429585Seric ** matched is saved away in the match vector (pointed to by 'mvp'). 4434476Seric ** 4444476Seric ** When a match between avp & pvp does not match, we try to 4459585Seric ** back out. If we back up over MATCHONE, MATCHCLASS, or MATCHNCLASS 4464476Seric ** we must also back out the match in mvp. If we reach a 4478058Seric ** MATCHANY or MATCHZANY we just extend the match and start 4488058Seric ** over again. 4494476Seric ** 4504476Seric ** When we finally match, we rewrite the address vector 4514476Seric ** and try over again. 4524476Seric ** 4533149Seric ** Parameters: 4543149Seric ** pvp -- pointer to token vector. 4553149Seric ** 4563149Seric ** Returns: 4573149Seric ** none. 4583149Seric ** 4593149Seric ** Side Effects: 4603149Seric ** pvp is modified. 4613149Seric */ 4622091Seric 4633149Seric struct match 4643149Seric { 4654468Seric char **first; /* first token matched */ 4664468Seric char **last; /* last token matched */ 4673149Seric }; 4683149Seric 4694468Seric # define MAXMATCH 9 /* max params per rewrite */ 4703149Seric 4713149Seric 4724070Seric rewrite(pvp, ruleset) 4733149Seric char **pvp; 4744070Seric int ruleset; 4753149Seric { 4763149Seric register char *ap; /* address pointer */ 4773149Seric register char *rp; /* rewrite pointer */ 4783149Seric register char **avp; /* address vector pointer */ 4793149Seric register char **rvp; /* rewrite vector pointer */ 4808058Seric register struct match *mlp; /* cur ptr into mlist */ 4818058Seric register struct rewrite *rwr; /* pointer to current rewrite rule */ 4824468Seric struct match mlist[MAXMATCH]; /* stores match on LHS */ 4833149Seric char *npvp[MAXATOM+1]; /* temporary space for rebuild */ 4844060Seric extern bool sameword(); 4853149Seric 4869279Seric if (OpMode == MD_TEST || tTd(21, 2)) 4873149Seric { 4888959Seric printf("rewrite: ruleset %2d input:", ruleset); 4893149Seric printav(pvp); 4903149Seric } 4918423Seric if (pvp == NULL) 4928423Seric return; 4933149Seric 4943149Seric /* 4953149Seric ** Run through the list of rewrite rules, applying 4963149Seric ** any that match. 4973149Seric */ 4983149Seric 4994070Seric for (rwr = RewriteRules[ruleset]; rwr != NULL; ) 5003149Seric { 5014100Seric # ifdef DEBUG 5027675Seric if (tTd(21, 12)) 503297Seric { 5048069Seric printf("-----trying rule:"); 5053149Seric printav(rwr->r_lhs); 5063149Seric } 5074100Seric # endif DEBUG 5083149Seric 5093149Seric /* try to match on this rule */ 5104468Seric mlp = mlist; 5118058Seric rvp = rwr->r_lhs; 5128058Seric avp = pvp; 5138058Seric while ((ap = *avp) != NULL || *rvp != NULL) 5143149Seric { 5153149Seric rp = *rvp; 5168058Seric # ifdef DEBUG 5178058Seric if (tTd(21, 35)) 5188058Seric { 5198069Seric printf("ap="); 5208058Seric xputs(ap); 5218069Seric printf(", rp="); 5228058Seric xputs(rp); 5238069Seric printf("\n"); 5248058Seric } 5258058Seric # endif DEBUG 5263149Seric if (rp == NULL) 527297Seric { 5283149Seric /* end-of-pattern before end-of-address */ 5298058Seric goto backup; 530297Seric } 5318058Seric if (ap == NULL && *rp != MATCHZANY) 5328058Seric { 5338058Seric /* end-of-input */ 5348058Seric break; 5358058Seric } 5363149Seric 5373149Seric switch (*rp) 5383149Seric { 5394060Seric register STAB *s; 5404060Seric 5414060Seric case MATCHCLASS: 5429585Seric case MATCHNCLASS: 5439585Seric /* match any token in (not in) a class */ 5444100Seric s = stab(ap, ST_CLASS, ST_FIND); 54510690Seric if (s == NULL || !bitnset(rp[1], s->s_class)) 5469585Seric { 5479585Seric if (*rp == MATCHCLASS) 5489585Seric goto backup; 5499585Seric } 5509585Seric else if (*rp == MATCHNCLASS) 5518058Seric goto backup; 5524468Seric 5534476Seric /* explicit fall-through */ 5544476Seric 5554476Seric case MATCHONE: 5564476Seric case MATCHANY: 5574476Seric /* match exactly one token */ 5588058Seric mlp->first = avp; 5598058Seric mlp->last = avp++; 5604468Seric mlp++; 5614060Seric break; 5624060Seric 5638058Seric case MATCHZANY: 5648058Seric /* match zero or more tokens */ 5658058Seric mlp->first = avp; 5668058Seric mlp->last = avp - 1; 5678058Seric mlp++; 5688058Seric break; 5698058Seric 5703149Seric default: 5713149Seric /* must have exact match */ 5724060Seric if (!sameword(rp, ap)) 5738058Seric goto backup; 5744468Seric avp++; 5753149Seric break; 5763149Seric } 5773149Seric 5783149Seric /* successful match on this token */ 5793149Seric rvp++; 5803149Seric continue; 5813149Seric 5828058Seric backup: 5833149Seric /* match failed -- back up */ 5843149Seric while (--rvp >= rwr->r_lhs) 5853149Seric { 5863149Seric rp = *rvp; 5878058Seric if (*rp == MATCHANY || *rp == MATCHZANY) 5884468Seric { 5894476Seric /* extend binding and continue */ 5908058Seric avp = ++mlp[-1].last; 5918058Seric avp++; 5924476Seric rvp++; 5933149Seric break; 5944468Seric } 5954476Seric avp--; 5969585Seric if (*rp == MATCHONE || *rp == MATCHCLASS || 5979585Seric *rp == MATCHNCLASS) 5983149Seric { 5994468Seric /* back out binding */ 6004468Seric mlp--; 6013149Seric } 6023149Seric } 6033149Seric 6043149Seric if (rvp < rwr->r_lhs) 6053149Seric { 6063149Seric /* total failure to match */ 6073149Seric break; 6083149Seric } 609297Seric } 6103149Seric 6113149Seric /* 6123149Seric ** See if we successfully matched 6133149Seric */ 6143149Seric 6159374Seric if (rvp < rwr->r_lhs || *rvp != NULL) 6163149Seric { 6174100Seric # ifdef DEBUG 6189374Seric if (tTd(21, 10)) 6199374Seric printf("----- rule fails\n"); 6204100Seric # endif DEBUG 6219374Seric rwr = rwr->r_next; 6229374Seric continue; 6239374Seric } 6243149Seric 6259374Seric rvp = rwr->r_rhs; 6269374Seric # ifdef DEBUG 6279374Seric if (tTd(21, 12)) 6289374Seric { 6299374Seric printf("-----rule matches:"); 6309374Seric printav(rvp); 6319374Seric } 6329374Seric # endif DEBUG 6339374Seric 6349374Seric rp = *rvp; 6359374Seric if (*rp == CANONUSER) 6369374Seric { 6379374Seric rvp++; 6389374Seric rwr = rwr->r_next; 6399374Seric } 6409374Seric else if (*rp == CANONHOST) 6419374Seric { 6429374Seric rvp++; 6439374Seric rwr = NULL; 6449374Seric } 6459374Seric else if (*rp == CANONNET) 6469374Seric rwr = NULL; 6479374Seric 6489374Seric /* substitute */ 6499374Seric for (avp = npvp; *rvp != NULL; rvp++) 6509374Seric { 6519374Seric register struct match *m; 6529374Seric register char **pp; 6539374Seric 6548058Seric rp = *rvp; 6559374Seric if (*rp != MATCHREPL) 6568058Seric { 6579374Seric if (avp >= &npvp[MAXATOM]) 6589374Seric { 6599374Seric syserr("rewrite: expansion too long"); 6609374Seric return; 6619374Seric } 6629374Seric *avp++ = rp; 6639374Seric continue; 6648069Seric } 6658058Seric 6669374Seric /* substitute from LHS */ 6679374Seric m = &mlist[rp[1] - '1']; 6689374Seric # ifdef DEBUG 6699374Seric if (tTd(21, 15)) 6703149Seric { 6719374Seric printf("$%c:", rp[1]); 6729374Seric pp = m->first; 6739374Seric while (pp <= m->last) 6743149Seric { 6759374Seric printf(" %x=\"", *pp); 6769374Seric (void) fflush(stdout); 6779374Seric printf("%s\"", *pp++); 6783149Seric } 6799374Seric printf("\n"); 6803149Seric } 6818226Seric # endif DEBUG 6829374Seric pp = m->first; 6839374Seric while (pp <= m->last) 6848226Seric { 6859374Seric if (avp >= &npvp[MAXATOM]) 6869374Seric { 6879374Seric syserr("rewrite: expansion too long"); 6889374Seric return; 6899374Seric } 6909374Seric *avp++ = *pp++; 6918226Seric } 6929374Seric } 6939374Seric *avp++ = NULL; 6949374Seric if (**npvp == CALLSUBR) 6959374Seric { 6969374Seric bmove((char *) &npvp[2], (char *) pvp, 6979374Seric (avp - npvp - 2) * sizeof *avp); 6988226Seric # ifdef DEBUG 6999374Seric if (tTd(21, 3)) 7009374Seric printf("-----callsubr %s\n", npvp[1]); 7013149Seric # endif DEBUG 7029374Seric rewrite(pvp, atoi(npvp[1])); 7033149Seric } 7043149Seric else 7053149Seric { 7069374Seric bmove((char *) npvp, (char *) pvp, 7079374Seric (avp - npvp) * sizeof *avp); 7089374Seric } 7094100Seric # ifdef DEBUG 7109374Seric if (tTd(21, 4)) 7119374Seric { 7129374Seric printf("rewritten as:"); 7139374Seric printav(pvp); 7149374Seric } 7154100Seric # endif DEBUG 716297Seric } 7178069Seric 7189279Seric if (OpMode == MD_TEST || tTd(21, 2)) 7198069Seric { 7208959Seric printf("rewrite: ruleset %2d returns:", ruleset); 7218069Seric printav(pvp); 7228069Seric } 7233149Seric } 7243149Seric /* 7253149Seric ** BUILDADDR -- build address from token vector. 7263149Seric ** 7273149Seric ** Parameters: 7283149Seric ** tv -- token vector. 7293149Seric ** a -- pointer to address descriptor to fill. 7303149Seric ** If NULL, one will be allocated. 7313149Seric ** 7323149Seric ** Returns: 7334279Seric ** NULL if there was an error. 7344279Seric ** 'a' otherwise. 7353149Seric ** 7363149Seric ** Side Effects: 7373149Seric ** fills in 'a' 7383149Seric */ 7393149Seric 7403149Seric ADDRESS * 7413149Seric buildaddr(tv, a) 7423149Seric register char **tv; 7433149Seric register ADDRESS *a; 7443149Seric { 7453149Seric static char buf[MAXNAME]; 7463149Seric struct mailer **mp; 7473149Seric register struct mailer *m; 7484635Seric extern bool sameword(); 7493149Seric 7503149Seric if (a == NULL) 7513149Seric a = (ADDRESS *) xalloc(sizeof *a); 7524988Seric clear((char *) a, sizeof *a); 7533149Seric 7543149Seric /* figure out what net/mailer to use */ 7553149Seric if (**tv != CANONNET) 7564279Seric { 7573149Seric syserr("buildaddr: no net"); 7584279Seric return (NULL); 7594279Seric } 7603149Seric tv++; 7614635Seric if (sameword(*tv, "error")) 7624279Seric { 76310183Seric if (**++tv == CANONHOST) 76410183Seric { 76510183Seric setstat(atoi(*++tv)); 76610183Seric tv++; 76710183Seric } 76810183Seric if (**tv != CANONUSER) 7694279Seric syserr("buildaddr: error: no user"); 7704279Seric buf[0] = '\0'; 7714279Seric while (*++tv != NULL) 7724279Seric { 7734279Seric if (buf[0] != '\0') 7747005Seric (void) strcat(buf, " "); 7757005Seric (void) strcat(buf, *tv); 7764279Seric } 7774279Seric usrerr(buf); 7784279Seric return (NULL); 7794279Seric } 7804598Seric for (mp = Mailer; (m = *mp++) != NULL; ) 7813149Seric { 7824635Seric if (sameword(m->m_name, *tv)) 7833149Seric break; 7843149Seric } 7853149Seric if (m == NULL) 7864279Seric { 7873149Seric syserr("buildaddr: unknown net %s", *tv); 7884279Seric return (NULL); 7894279Seric } 7904598Seric a->q_mailer = m; 7913149Seric 7923149Seric /* figure out what host (if any) */ 7933149Seric tv++; 79410690Seric if (!bitnset(M_LOCAL, m->m_flags)) 7953149Seric { 7965704Seric if (**tv++ != CANONHOST) 7974279Seric { 7983149Seric syserr("buildaddr: no host"); 7994279Seric return (NULL); 8004279Seric } 8015704Seric buf[0] = '\0'; 8025704Seric while (*tv != NULL && **tv != CANONUSER) 8037005Seric (void) strcat(buf, *tv++); 8045704Seric a->q_host = newstr(buf); 8053149Seric } 8063149Seric else 8073149Seric a->q_host = NULL; 8083149Seric 8093149Seric /* figure out the user */ 8103149Seric if (**tv != CANONUSER) 8114279Seric { 8123149Seric syserr("buildaddr: no user"); 8134279Seric return (NULL); 8144279Seric } 81511278Seric rewrite(++tv, 4); 81611278Seric cataddr(tv, buf, sizeof buf); 8173149Seric a->q_user = buf; 8183149Seric 8193149Seric return (a); 8203149Seric } 8213188Seric /* 8224228Seric ** CATADDR -- concatenate pieces of addresses (putting in <LWSP> subs) 8234228Seric ** 8244228Seric ** Parameters: 8254228Seric ** pvp -- parameter vector to rebuild. 8264228Seric ** buf -- buffer to build the string into. 8274228Seric ** sz -- size of buf. 8284228Seric ** 8294228Seric ** Returns: 8304228Seric ** none. 8314228Seric ** 8324228Seric ** Side Effects: 8334228Seric ** Destroys buf. 8344228Seric */ 8354228Seric 8364228Seric cataddr(pvp, buf, sz) 8374228Seric char **pvp; 8384228Seric char *buf; 8394228Seric register int sz; 8404228Seric { 8414228Seric bool oatomtok = FALSE; 8424228Seric bool natomtok = FALSE; 8434228Seric register int i; 8444228Seric register char *p; 8454228Seric 8468423Seric if (pvp == NULL) 8478423Seric { 8488423Seric strcpy(buf, ""); 8498423Seric return; 8508423Seric } 8514228Seric p = buf; 85211156Seric sz -= 2; 8534228Seric while (*pvp != NULL && (i = strlen(*pvp)) < sz) 8544228Seric { 8558078Seric natomtok = (toktype(**pvp) == ATM); 8564228Seric if (oatomtok && natomtok) 8579042Seric *p++ = SpaceSub; 8584228Seric (void) strcpy(p, *pvp); 8594228Seric oatomtok = natomtok; 8604228Seric p += i; 86111156Seric sz -= i + 1; 8624228Seric pvp++; 8634228Seric } 8644228Seric *p = '\0'; 8654228Seric } 8664228Seric /* 8673188Seric ** SAMEADDR -- Determine if two addresses are the same 8683188Seric ** 8693188Seric ** This is not just a straight comparison -- if the mailer doesn't 8703188Seric ** care about the host we just ignore it, etc. 8713188Seric ** 8723188Seric ** Parameters: 8733188Seric ** a, b -- pointers to the internal forms to compare. 8743188Seric ** 8753188Seric ** Returns: 8763188Seric ** TRUE -- they represent the same mailbox. 8773188Seric ** FALSE -- they don't. 8783188Seric ** 8793188Seric ** Side Effects: 8803188Seric ** none. 8813188Seric */ 8823188Seric 8833188Seric bool 8849374Seric sameaddr(a, b) 8853188Seric register ADDRESS *a; 8863188Seric register ADDRESS *b; 8873188Seric { 8883188Seric /* if they don't have the same mailer, forget it */ 8893188Seric if (a->q_mailer != b->q_mailer) 8903188Seric return (FALSE); 8913188Seric 8923188Seric /* if the user isn't the same, we can drop out */ 8939374Seric if (strcmp(a->q_user, b->q_user) != 0) 8943188Seric return (FALSE); 8953188Seric 8963188Seric /* if the mailer ignores hosts, we have succeeded! */ 89710690Seric if (bitnset(M_LOCAL, a->q_mailer->m_flags)) 8983188Seric return (TRUE); 8993188Seric 9003188Seric /* otherwise compare hosts (but be careful for NULL ptrs) */ 9013188Seric if (a->q_host == NULL || b->q_host == NULL) 9023188Seric return (FALSE); 9033188Seric if (strcmp(a->q_host, b->q_host) != 0) 9043188Seric return (FALSE); 9053188Seric 9063188Seric return (TRUE); 9073188Seric } 9083234Seric /* 9093234Seric ** PRINTADDR -- print address (for debugging) 9103234Seric ** 9113234Seric ** Parameters: 9123234Seric ** a -- the address to print 9133234Seric ** follow -- follow the q_next chain. 9143234Seric ** 9153234Seric ** Returns: 9163234Seric ** none. 9173234Seric ** 9183234Seric ** Side Effects: 9193234Seric ** none. 9203234Seric */ 9213234Seric 9224317Seric # ifdef DEBUG 9234317Seric 9243234Seric printaddr(a, follow) 9253234Seric register ADDRESS *a; 9263234Seric bool follow; 9273234Seric { 9285001Seric bool first = TRUE; 9295001Seric 9303234Seric while (a != NULL) 9313234Seric { 9325001Seric first = FALSE; 9334443Seric printf("%x=", a); 9344085Seric (void) fflush(stdout); 9353234Seric printf("%s: mailer %d (%s), host `%s', user `%s'\n", a->q_paddr, 9368181Seric a->q_mailer->m_mno, a->q_mailer->m_name, a->q_host, 9378181Seric a->q_user); 9388181Seric printf("\tnext=%x, flags=%o, alias %x\n", a->q_next, a->q_flags, 9398181Seric a->q_alias); 9408181Seric printf("\thome=\"%s\", fullname=\"%s\"\n", a->q_home, 9418181Seric a->q_fullname); 9424996Seric 9433234Seric if (!follow) 9443234Seric return; 9454996Seric a = a->q_next; 9463234Seric } 9475001Seric if (first) 9484443Seric printf("[NULL]\n"); 9493234Seric } 9504317Seric 9514317Seric # endif DEBUG 9527682Seric /* 9537682Seric ** REMOTENAME -- return the name relative to the current mailer 9547682Seric ** 9557682Seric ** Parameters: 9567682Seric ** name -- the name to translate. 9578069Seric ** m -- the mailer that we want to do rewriting relative 9588069Seric ** to. 9598069Seric ** senderaddress -- if set, uses the sender rewriting rules 9608069Seric ** rather than the recipient rewriting rules. 96110310Seric ** canonical -- if set, strip out any comment information, 96210310Seric ** etc. 9637682Seric ** 9647682Seric ** Returns: 9657682Seric ** the text string representing this address relative to 9667682Seric ** the receiving mailer. 9677682Seric ** 9687682Seric ** Side Effects: 9697682Seric ** none. 9707682Seric ** 9717682Seric ** Warnings: 9727682Seric ** The text string returned is tucked away locally; 9737682Seric ** copy it if you intend to save it. 9747682Seric */ 9757682Seric 9767682Seric char * 97710310Seric remotename(name, m, senderaddress, canonical) 9787682Seric char *name; 9797682Seric struct mailer *m; 9808069Seric bool senderaddress; 98110310Seric bool canonical; 9827682Seric { 9838069Seric register char **pvp; 9848069Seric char *fancy; 98515284Seric register char *p; 9868069Seric extern char *macvalue(); 9878181Seric char *oldg = macvalue('g', CurEnv); 9887682Seric static char buf[MAXNAME]; 9897682Seric char lbuf[MAXNAME]; 9907682Seric extern char **prescan(); 9917889Seric extern char *crackaddr(); 9927682Seric 9937755Seric # ifdef DEBUG 9947755Seric if (tTd(12, 1)) 9957755Seric printf("remotename(%s)\n", name); 9967755Seric # endif DEBUG 9977755Seric 99810177Seric /* don't do anything if we are tagging it as special */ 99910177Seric if ((senderaddress ? m->m_s_rwset : m->m_r_rwset) < 0) 100010177Seric return (name); 100110177Seric 10027682Seric /* 10038181Seric ** Do a heuristic crack of this name to extract any comment info. 10048181Seric ** This will leave the name as a comment and a $g macro. 10057889Seric */ 10067889Seric 100710310Seric if (canonical) 100816155Seric fancy = "\001g"; 100910310Seric else 101010310Seric fancy = crackaddr(name); 10117889Seric 10128181Seric /* 10138181Seric ** Turn the name into canonical form. 10148181Seric ** Normally this will be RFC 822 style, i.e., "user@domain". 10158181Seric ** If this only resolves to "user", and the "C" flag is 10168181Seric ** specified in the sending mailer, then the sender's 10178181Seric ** domain will be appended. 10188181Seric */ 10198181Seric 10207889Seric pvp = prescan(name, '\0'); 10217889Seric if (pvp == NULL) 10227889Seric return (name); 10238181Seric rewrite(pvp, 3); 10248181Seric if (CurEnv->e_fromdomain != NULL) 10258181Seric { 10268181Seric /* append from domain to this address */ 10278181Seric register char **pxp = pvp; 10288181Seric 10299594Seric /* see if there is an "@domain" in the current name */ 10308181Seric while (*pxp != NULL && strcmp(*pxp, "@") != 0) 10318181Seric pxp++; 10328181Seric if (*pxp == NULL) 10338181Seric { 10349594Seric /* no.... append the "@domain" from the sender */ 10358181Seric register char **qxq = CurEnv->e_fromdomain; 10368181Seric 10379594Seric while ((*pxp++ = *qxq++) != NULL) 10389594Seric continue; 103911726Seric rewrite(pvp, 3); 10408181Seric } 10418181Seric } 10428181Seric 10438181Seric /* 10448959Seric ** Do more specific rewriting. 10458181Seric ** Rewrite using ruleset 1 or 2 depending on whether this is 10468181Seric ** a sender address or not. 10478181Seric ** Then run it through any receiving-mailer-specific rulesets. 10488181Seric */ 10498181Seric 10508069Seric if (senderaddress) 10517755Seric { 10527889Seric rewrite(pvp, 1); 10538069Seric if (m->m_s_rwset > 0) 10548069Seric rewrite(pvp, m->m_s_rwset); 10558069Seric } 10568069Seric else 10578069Seric { 10587889Seric rewrite(pvp, 2); 10598069Seric if (m->m_r_rwset > 0) 10608069Seric rewrite(pvp, m->m_r_rwset); 10617682Seric } 10627682Seric 10638181Seric /* 10648959Seric ** Do any final sanitation the address may require. 10658959Seric ** This will normally be used to turn internal forms 10668959Seric ** (e.g., user@host.LOCAL) into external form. This 10678959Seric ** may be used as a default to the above rules. 10688959Seric */ 10698959Seric 10708959Seric rewrite(pvp, 4); 10718959Seric 10728959Seric /* 10738181Seric ** Now restore the comment information we had at the beginning. 10748181Seric */ 10758181Seric 10767682Seric cataddr(pvp, lbuf, sizeof lbuf); 10779374Seric define('g', lbuf, CurEnv); 10787889Seric expand(fancy, buf, &buf[sizeof buf - 1], CurEnv); 10799374Seric define('g', oldg, CurEnv); 10807682Seric 10817682Seric # ifdef DEBUG 10827682Seric if (tTd(12, 1)) 10837755Seric printf("remotename => `%s'\n", buf); 10847682Seric # endif DEBUG 10857682Seric return (buf); 10867682Seric } 1087