13312Seric # include "sendmail.h" 2297Seric 3*8078Seric SCCSID(@(#)parseaddr.c 3.53 09/06/82); 4407Seric 5297Seric /* 6297Seric ** PARSE -- 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. 31297Seric ** 32297Seric ** Returns: 33297Seric ** A pointer to the address descriptor header (`a' if 34297Seric ** `a' is non-NULL). 35297Seric ** NULL on error. 36297Seric ** 37297Seric ** Side Effects: 38297Seric ** none 39297Seric */ 40297Seric 413380Seric # define DELIMCHARS "$()<>,;\\\"\r\n" /* word delimiters */ 422091Seric 432973Seric ADDRESS * 44297Seric parse(addr, a, copyf) 45297Seric char *addr; 462973Seric register ADDRESS *a; 47297Seric int copyf; 48297Seric { 493149Seric register char **pvp; 503149Seric register struct mailer *m; 513149Seric extern char **prescan(); 523149Seric extern ADDRESS *buildaddr(); 537889Seric static char nbuf[MAXNAME]; 54297Seric 55297Seric /* 56297Seric ** Initialize and prescan address. 57297Seric */ 58297Seric 596903Seric CurEnv->e_to = addr; 603188Seric # ifdef DEBUG 617675Seric if (tTd(20, 1)) 623188Seric printf("\n--parse(%s)\n", addr); 633188Seric # endif DEBUG 643188Seric 65*8078Seric pvp = prescan(addr, ','); 663149Seric if (pvp == NULL) 67297Seric return (NULL); 68297Seric 69297Seric /* 703149Seric ** Apply rewriting rules. 717889Seric ** Ruleset 0 does basic parsing. It must resolve. 72297Seric */ 73297Seric 744070Seric rewrite(pvp, 0); 75297Seric 763149Seric /* 773149Seric ** See if we resolved to a real mailer. 783149Seric */ 79297Seric 803149Seric if (pvp[0][0] != CANONNET) 813149Seric { 823149Seric setstat(EX_USAGE); 833149Seric usrerr("cannot resolve name"); 843149Seric return (NULL); 85297Seric } 86297Seric 87297Seric /* 883149Seric ** Build canonical address from pvp. 89297Seric */ 90297Seric 913149Seric a = buildaddr(pvp, a); 924279Seric if (a == NULL) 934279Seric return (NULL); 944598Seric m = a->q_mailer; 95297Seric 96297Seric /* 973149Seric ** Make local copies of the host & user and then 983149Seric ** transport them out. 99297Seric */ 100297Seric 101297Seric if (copyf > 0) 102*8078Seric { 103*8078Seric extern char *DelimChar; 104*8078Seric char savec = *DelimChar; 105*8078Seric 106*8078Seric *DelimChar = '\0'; 1072973Seric a->q_paddr = newstr(addr); 108*8078Seric *DelimChar = savec; 109*8078Seric } 110297Seric else 111297Seric a->q_paddr = addr; 1123149Seric if (copyf >= 0) 113297Seric { 1143149Seric if (a->q_host != NULL) 1153149Seric a->q_host = newstr(a->q_host); 116297Seric else 1173149Seric a->q_host = ""; 1183149Seric if (a->q_user != a->q_paddr) 1193149Seric a->q_user = newstr(a->q_user); 120297Seric } 121297Seric 122297Seric /* 123297Seric ** Do UPPER->lower case mapping unless inhibited. 124297Seric */ 125297Seric 1263149Seric if (!bitset(M_HST_UPPER, m->m_flags)) 127297Seric makelower(a->q_host); 1283149Seric if (!bitset(M_USR_UPPER, m->m_flags)) 129297Seric makelower(a->q_user); 130297Seric 131297Seric /* 132297Seric ** Compute return value. 133297Seric */ 134297Seric 135297Seric # ifdef DEBUG 1367675Seric if (tTd(20, 1)) 1374443Seric { 1384443Seric printf("parse-->"); 1394443Seric printaddr(a, FALSE); 1404443Seric } 141297Seric # endif DEBUG 142297Seric 143297Seric return (a); 144297Seric } 145297Seric /* 146297Seric ** PRESCAN -- Prescan name and make it canonical 147297Seric ** 148297Seric ** Scans a name and turns it into canonical form. This involves 149297Seric ** deleting blanks, comments (in parentheses), and turning the 150297Seric ** word "at" into an at-sign ("@"). The name is copied as this 151297Seric ** is done; it is legal to copy a name onto itself, since this 152297Seric ** process can only make things smaller. 153297Seric ** 154297Seric ** This routine knows about quoted strings and angle brackets. 155297Seric ** 156297Seric ** There are certain subtleties to this routine. The one that 157297Seric ** comes to mind now is that backslashes on the ends of names 158297Seric ** are silently stripped off; this is intentional. The problem 159297Seric ** is that some versions of sndmsg (like at LBL) set the kill 160297Seric ** character to something other than @ when reading addresses; 161297Seric ** so people type "csvax.eric\@berkeley" -- which screws up the 162297Seric ** berknet mailer. 163297Seric ** 164297Seric ** Parameters: 165297Seric ** addr -- the name to chomp. 166297Seric ** delim -- the delimiter for the address, normally 167297Seric ** '\0' or ','; \0 is accepted in any case. 168297Seric ** 169297Seric ** Returns: 1703149Seric ** A pointer to a vector of tokens. 171297Seric ** NULL on error. 172297Seric ** 173297Seric ** Side Effects: 1743149Seric ** none. 175297Seric */ 176297Seric 177*8078Seric /* states and character types */ 178*8078Seric # define OPR 0 /* operator */ 179*8078Seric # define ATM 1 /* atom */ 180*8078Seric # define QST 2 /* in quoted string */ 181*8078Seric # define SPC 3 /* chewing up spaces */ 182*8078Seric # define ONE 4 /* pick up one character */ 1833149Seric 184*8078Seric # define NSTATES 5 /* number of states */ 185*8078Seric # define TYPE 017 /* mask to select state type */ 186*8078Seric 187*8078Seric /* meta bits for table */ 188*8078Seric # define M 020 /* meta character; don't pass through */ 189*8078Seric # define B 040 /* cause a break */ 190*8078Seric # define MB M|B /* meta-break */ 191*8078Seric 192*8078Seric static short StateTab[NSTATES][NSTATES] = 193*8078Seric { 194*8078Seric /* oldst newst> OPR ATM QST SPC ONE */ 195*8078Seric /*OPR*/ OPR|B, ATM|B, QST|MB, SPC|MB, ONE|B, 196*8078Seric /*ATM*/ OPR|B, ATM, QST|MB, SPC|MB, ONE|B, 197*8078Seric /*QST*/ QST, QST, QST|MB, QST, QST, 198*8078Seric /*SPC*/ OPR, ATM, QST, SPC|M, ONE, 199*8078Seric /*ONE*/ OPR, OPR, OPR, OPR, OPR, 200*8078Seric }; 201*8078Seric 202*8078Seric # define NOCHAR -1 /* signal nothing in lookahead token */ 203*8078Seric 204*8078Seric char *DelimChar; /* set to point to the delimiter */ 205*8078Seric 2063149Seric char ** 2073149Seric prescan(addr, delim) 208297Seric char *addr; 209297Seric char delim; 210297Seric { 211297Seric register char *p; 212*8078Seric register char *q; 213*8078Seric register char c; 2143149Seric char **avp; 215297Seric bool bslashmode; 216297Seric int cmntcnt; 2173149Seric char *tok; 218*8078Seric int state; 219*8078Seric int newstate; 220*8078Seric static char buf[MAXNAME+MAXATOM]; 221*8078Seric static char *av[MAXATOM+1]; 222297Seric 223297Seric q = buf; 2243149Seric bslashmode = FALSE; 2257800Seric cmntcnt = 0; 2263149Seric avp = av; 227*8078Seric state = OPR; 228*8078Seric c = NOCHAR; 229*8078Seric p = addr; 230*8078Seric # ifdef DEBUG 231*8078Seric if (tTd(22, 45)) 232297Seric { 233*8078Seric printf("prescan: "); 234*8078Seric xputs(p); 235*8078Seric putchar('\n'); 236*8078Seric } 237*8078Seric # endif DEBUG 238*8078Seric 239*8078Seric do 240*8078Seric { 2413149Seric /* read a token */ 2423149Seric tok = q; 243*8078Seric for (;;) 244297Seric { 245*8078Seric /* store away any old lookahead character */ 246*8078Seric if (c != NOCHAR) 247*8078Seric { 248*8078Seric /* squirrel it away */ 249*8078Seric if (q >= &buf[sizeof buf - 5]) 250*8078Seric { 251*8078Seric usrerr("Address too long"); 252*8078Seric DelimChar = p; 253*8078Seric return (NULL); 254*8078Seric } 255*8078Seric *q++ = c; 256*8078Seric } 257*8078Seric 258*8078Seric /* read a new input character */ 259*8078Seric c = *p++; 260*8078Seric if (c == '\0') 261*8078Seric break; 262*8078Seric # ifdef DEBUG 263*8078Seric if (tTd(22, 101)) 264*8078Seric printf("c=%c, s=%d; ", c, state); 265*8078Seric # endif DEBUG 266*8078Seric 2673149Seric /* chew up special characters */ 2684100Seric c &= ~0200; 2693149Seric *q = '\0'; 2703149Seric if (bslashmode) 2713149Seric { 2723149Seric c |= 0200; 2733149Seric bslashmode = FALSE; 2743149Seric } 2753149Seric else if (c == '\\') 2763149Seric { 2773149Seric bslashmode = TRUE; 278*8078Seric c = NOCHAR; 2793149Seric } 280*8078Seric else if (c == '(') 2814100Seric { 282*8078Seric cmntcnt++; 283*8078Seric c = NOCHAR; 2844100Seric } 285*8078Seric else if (c == ')') 2863149Seric { 287*8078Seric if (cmntcnt <= 0) 2883149Seric { 289*8078Seric usrerr("Unbalanced ')'"); 290*8078Seric DelimChar = p; 291*8078Seric return (NULL); 2923149Seric } 293*8078Seric else 294*8078Seric cmntcnt--; 295*8078Seric } 296*8078Seric else if (cmntcnt > 0) 297*8078Seric c = NOCHAR; 2983149Seric 299*8078Seric if (c == NOCHAR) 300*8078Seric continue; 3013149Seric 302*8078Seric /* see if this is end of input */ 303*8078Seric if (c == delim) 3043149Seric break; 3053149Seric 306*8078Seric newstate = StateTab[state][toktype(c)]; 307*8078Seric # ifdef DEBUG 308*8078Seric if (tTd(22, 101)) 309*8078Seric printf("ns=%02o\n", newstate); 310*8078Seric # endif DEBUG 311*8078Seric state = newstate & TYPE; 312*8078Seric if (bitset(M, newstate)) 313*8078Seric c = NOCHAR; 314*8078Seric if (bitset(B, newstate)) 3154228Seric break; 316297Seric } 3173149Seric 3183149Seric /* new token */ 319*8078Seric if (tok != q) 3201378Seric { 321*8078Seric *q++ = '\0'; 322*8078Seric # ifdef DEBUG 323*8078Seric if (tTd(22, 36)) 324297Seric { 325*8078Seric printf("tok="); 326*8078Seric xputs(tok); 327*8078Seric putchar('\n'); 328297Seric } 329*8078Seric # endif DEBUG 330*8078Seric if (avp >= &av[MAXATOM]) 331297Seric { 332*8078Seric syserr("prescan: too many tokens"); 333*8078Seric DelimChar = p; 334*8078Seric return (NULL); 335297Seric } 336*8078Seric *avp++ = tok; 337297Seric } 338*8078Seric } while (c != '\0' && c != delim); 3393149Seric *avp = NULL; 340*8078Seric DelimChar = --p; 3413149Seric if (cmntcnt > 0) 3423149Seric usrerr("Unbalanced '('"); 343*8078Seric else if (state == QST) 3443149Seric usrerr("Unbalanced '\"'"); 3453149Seric else if (av[0] != NULL) 3463149Seric return (av); 3473149Seric return (NULL); 3483149Seric } 3493149Seric /* 3503149Seric ** TOKTYPE -- return token type 3513149Seric ** 3523149Seric ** Parameters: 3533149Seric ** c -- the character in question. 3543149Seric ** 3553149Seric ** Returns: 3563149Seric ** Its type. 3573149Seric ** 3583149Seric ** Side Effects: 3593149Seric ** none. 3603149Seric */ 361297Seric 3623149Seric toktype(c) 3633149Seric register char c; 3643149Seric { 3653380Seric static char buf[50]; 3663382Seric static bool firstime = TRUE; 3673380Seric 3683382Seric if (firstime) 3693380Seric { 3703382Seric firstime = FALSE; 3716977Seric expand("$o", buf, &buf[sizeof buf - 1], CurEnv); 3727005Seric (void) strcat(buf, DELIMCHARS); 3733380Seric } 3746053Seric if (c == MATCHCLASS || c == MATCHREPL) 375*8078Seric return (ONE); 376*8078Seric if (c == '"') 377*8078Seric return (QST); 3784100Seric if (!isascii(c)) 379*8078Seric return (ATM); 380*8078Seric if (isspace(c) || c == ')') 381*8078Seric return (SPC); 3823380Seric if (iscntrl(c) || index(buf, c) != NULL) 383*8078Seric return (OPR); 384*8078Seric return (ATM); 3853149Seric } 3863149Seric /* 3873149Seric ** REWRITE -- apply rewrite rules to token vector. 3883149Seric ** 3894476Seric ** This routine is an ordered production system. Each rewrite 3904476Seric ** rule has a LHS (called the pattern) and a RHS (called the 3914476Seric ** rewrite); 'rwr' points the the current rewrite rule. 3924476Seric ** 3934476Seric ** For each rewrite rule, 'avp' points the address vector we 3944476Seric ** are trying to match against, and 'pvp' points to the pattern. 3958058Seric ** If pvp points to a special match value (MATCHZANY, MATCHANY, 3968058Seric ** MATCHONE, MATCHCLASS) then the address in avp matched is 3978058Seric ** saved away in the match vector (pointed to by 'mvp'). 3984476Seric ** 3994476Seric ** When a match between avp & pvp does not match, we try to 4004476Seric ** back out. If we back up over a MATCHONE or a MATCHCLASS 4014476Seric ** we must also back out the match in mvp. If we reach a 4028058Seric ** MATCHANY or MATCHZANY we just extend the match and start 4038058Seric ** over again. 4044476Seric ** 4054476Seric ** When we finally match, we rewrite the address vector 4064476Seric ** and try over again. 4074476Seric ** 4083149Seric ** Parameters: 4093149Seric ** pvp -- pointer to token vector. 4103149Seric ** 4113149Seric ** Returns: 4123149Seric ** none. 4133149Seric ** 4143149Seric ** Side Effects: 4153149Seric ** pvp is modified. 4163149Seric */ 4172091Seric 4183149Seric struct match 4193149Seric { 4204468Seric char **first; /* first token matched */ 4214468Seric char **last; /* last token matched */ 4223149Seric }; 4233149Seric 4244468Seric # define MAXMATCH 9 /* max params per rewrite */ 4253149Seric 4263149Seric 4274070Seric rewrite(pvp, ruleset) 4283149Seric char **pvp; 4294070Seric int ruleset; 4303149Seric { 4313149Seric register char *ap; /* address pointer */ 4323149Seric register char *rp; /* rewrite pointer */ 4333149Seric register char **avp; /* address vector pointer */ 4343149Seric register char **rvp; /* rewrite vector pointer */ 4358058Seric register struct match *mlp; /* cur ptr into mlist */ 4368058Seric register struct rewrite *rwr; /* pointer to current rewrite rule */ 4374468Seric struct match mlist[MAXMATCH]; /* stores match on LHS */ 4383149Seric char *npvp[MAXATOM+1]; /* temporary space for rebuild */ 4394060Seric extern bool sameword(); 4403149Seric 4414100Seric # ifdef DEBUG 4428069Seric if (tTd(21, 2)) 4433149Seric { 4448069Seric printf("rewrite: ruleset %d, original pvp:", ruleset); 4453149Seric printav(pvp); 4463149Seric } 4474100Seric # endif DEBUG 4483149Seric 4493149Seric /* 4503149Seric ** Run through the list of rewrite rules, applying 4513149Seric ** any that match. 4523149Seric */ 4533149Seric 4544070Seric for (rwr = RewriteRules[ruleset]; rwr != NULL; ) 4553149Seric { 4564100Seric # ifdef DEBUG 4577675Seric if (tTd(21, 12)) 458297Seric { 4598069Seric printf("-----trying rule:"); 4603149Seric printav(rwr->r_lhs); 4613149Seric } 4624100Seric # endif DEBUG 4633149Seric 4643149Seric /* try to match on this rule */ 4654468Seric mlp = mlist; 4668058Seric rvp = rwr->r_lhs; 4678058Seric avp = pvp; 4688058Seric while ((ap = *avp) != NULL || *rvp != NULL) 4693149Seric { 4703149Seric rp = *rvp; 4718058Seric # ifdef DEBUG 4728058Seric if (tTd(21, 35)) 4738058Seric { 4748069Seric printf("ap="); 4758058Seric xputs(ap); 4768069Seric printf(", rp="); 4778058Seric xputs(rp); 4788069Seric printf("\n"); 4798058Seric } 4808058Seric # endif DEBUG 4813149Seric if (rp == NULL) 482297Seric { 4833149Seric /* end-of-pattern before end-of-address */ 4848058Seric goto backup; 485297Seric } 4868058Seric if (ap == NULL && *rp != MATCHZANY) 4878058Seric { 4888058Seric /* end-of-input */ 4898058Seric break; 4908058Seric } 4913149Seric 4923149Seric switch (*rp) 4933149Seric { 4944060Seric register STAB *s; 4954060Seric register int class; 4964060Seric 4974060Seric case MATCHCLASS: 4984060Seric /* match any token in a class */ 4994060Seric class = rp[1]; 5004060Seric if (!isalpha(class)) 5018058Seric goto backup; 5024060Seric if (isupper(class)) 5034060Seric class -= 'A'; 5044060Seric else 5054060Seric class -= 'a'; 5064100Seric s = stab(ap, ST_CLASS, ST_FIND); 5076273Seric if (s == NULL || (s->s_class & (1L << class)) == 0) 5088058Seric goto backup; 5094468Seric 5104476Seric /* explicit fall-through */ 5114476Seric 5124476Seric case MATCHONE: 5134476Seric case MATCHANY: 5144476Seric /* match exactly one token */ 5158058Seric mlp->first = avp; 5168058Seric mlp->last = avp++; 5174468Seric mlp++; 5184060Seric break; 5194060Seric 5208058Seric case MATCHZANY: 5218058Seric /* match zero or more tokens */ 5228058Seric mlp->first = avp; 5238058Seric mlp->last = avp - 1; 5248058Seric mlp++; 5258058Seric break; 5268058Seric 5273149Seric default: 5283149Seric /* must have exact match */ 5294060Seric if (!sameword(rp, ap)) 5308058Seric goto backup; 5314468Seric avp++; 5323149Seric break; 5333149Seric } 5343149Seric 5353149Seric /* successful match on this token */ 5363149Seric rvp++; 5373149Seric continue; 5383149Seric 5398058Seric backup: 5403149Seric /* match failed -- back up */ 5413149Seric while (--rvp >= rwr->r_lhs) 5423149Seric { 5433149Seric rp = *rvp; 5448058Seric if (*rp == MATCHANY || *rp == MATCHZANY) 5454468Seric { 5464476Seric /* extend binding and continue */ 5478058Seric avp = ++mlp[-1].last; 5488058Seric avp++; 5494476Seric rvp++; 5503149Seric break; 5514468Seric } 5524476Seric avp--; 5534476Seric if (*rp == MATCHONE || *rp == MATCHCLASS) 5543149Seric { 5554468Seric /* back out binding */ 5564468Seric mlp--; 5573149Seric } 5583149Seric } 5593149Seric 5603149Seric if (rvp < rwr->r_lhs) 5613149Seric { 5623149Seric /* total failure to match */ 5633149Seric break; 5643149Seric } 565297Seric } 5663149Seric 5673149Seric /* 5683149Seric ** See if we successfully matched 5693149Seric */ 5703149Seric 5713149Seric if (rvp >= rwr->r_lhs && *rvp == NULL) 5723149Seric { 5738058Seric rvp = rwr->r_rhs; 5744100Seric # ifdef DEBUG 5757675Seric if (tTd(21, 12)) 5763149Seric { 5778069Seric printf("-----rule matches:"); 5788058Seric printav(rvp); 5793149Seric } 5804100Seric # endif DEBUG 5813149Seric 5828058Seric /* see if this is a "subroutine" call */ 5838058Seric rp = *rvp; 5848058Seric if (*rp == CALLSUBR) 5858058Seric { 5868058Seric rp = *++rvp; 5878058Seric # ifdef DEBUG 5888069Seric if (tTd(21, 3)) 5898058Seric printf("-----callsubr %s\n", rp); 5908058Seric # endif DEBUG 5918058Seric rewrite(pvp, atoi(rp)); 5928058Seric rwr = rwr->r_next; 5938058Seric continue; 5948058Seric } 5958069Seric else if (*rp == CANONUSER) 5968069Seric { 5978069Seric rvp++; 5988069Seric rwr = rwr->r_next; 5998069Seric } 6008069Seric else if (*rp == CANONHOST) 6018069Seric { 6028069Seric rvp++; 6038069Seric rwr = NULL; 6048069Seric } 6058069Seric else if (*rp == CANONNET) 6068069Seric rwr = NULL; 6078058Seric 6083149Seric /* substitute */ 6098069Seric for (avp = npvp; *rvp != NULL; rvp++) 6103149Seric { 6113149Seric rp = *rvp; 6124468Seric if (*rp == MATCHREPL) 6133149Seric { 6143149Seric register struct match *m; 6153149Seric register char **pp; 6163149Seric 6174468Seric m = &mlist[rp[1] - '1']; 6184476Seric # ifdef DEBUG 6197675Seric if (tTd(21, 15)) 6204476Seric { 6214476Seric printf("$%c:", rp[1]); 6224476Seric pp = m->first; 6238058Seric while (pp <= m->last) 6244476Seric { 6254476Seric printf(" %x=\"", *pp); 6264625Seric (void) fflush(stdout); 6278058Seric printf("%s\"", *pp++); 6288058Seric } 6294476Seric printf("\n"); 6304476Seric } 6314476Seric # endif DEBUG 6324468Seric pp = m->first; 6338058Seric while (pp <= m->last) 6343149Seric { 6354468Seric if (avp >= &npvp[MAXATOM]) 6363149Seric { 6374468Seric syserr("rewrite: expansion too long"); 6384468Seric return; 6394468Seric } 6408058Seric *avp++ = *pp++; 6418058Seric } 6423149Seric } 6433149Seric else 6444385Seric { 6454385Seric if (avp >= &npvp[MAXATOM]) 6464385Seric { 6474385Seric syserr("rewrite: expansion too long"); 6484385Seric return; 6494385Seric } 6503149Seric *avp++ = rp; 6514385Seric } 6523149Seric } 6533149Seric *avp++ = NULL; 6544085Seric bmove((char *) npvp, (char *) pvp, (avp - npvp) * sizeof *avp); 6553149Seric # ifdef DEBUG 6567675Seric if (tTd(21, 4)) 6573149Seric { 6588069Seric printf("rewritten as:"); 6598069Seric printav(pvp); 6603149Seric } 6613149Seric # endif DEBUG 6623149Seric } 6633149Seric else 6643149Seric { 6654100Seric # ifdef DEBUG 6667675Seric if (tTd(21, 10)) 6673149Seric printf("----- rule fails\n"); 6684100Seric # endif DEBUG 6693149Seric rwr = rwr->r_next; 6703149Seric } 671297Seric } 6728069Seric 6738069Seric # ifdef DEBUG 6748069Seric if (tTd(21, 2)) 6758069Seric { 6768069Seric printf("rewrite: ruleset %d returns:", ruleset); 6778069Seric printav(pvp); 6788069Seric } 6798069Seric # endif DEBUG 6803149Seric } 6813149Seric /* 6823149Seric ** BUILDADDR -- build address from token vector. 6833149Seric ** 6843149Seric ** Parameters: 6853149Seric ** tv -- token vector. 6863149Seric ** a -- pointer to address descriptor to fill. 6873149Seric ** If NULL, one will be allocated. 6883149Seric ** 6893149Seric ** Returns: 6904279Seric ** NULL if there was an error. 6914279Seric ** 'a' otherwise. 6923149Seric ** 6933149Seric ** Side Effects: 6943149Seric ** fills in 'a' 6953149Seric */ 6963149Seric 6973149Seric ADDRESS * 6983149Seric buildaddr(tv, a) 6993149Seric register char **tv; 7003149Seric register ADDRESS *a; 7013149Seric { 7023149Seric static char buf[MAXNAME]; 7033149Seric struct mailer **mp; 7043149Seric register struct mailer *m; 7054635Seric extern bool sameword(); 7063149Seric 7073149Seric if (a == NULL) 7083149Seric a = (ADDRESS *) xalloc(sizeof *a); 7094988Seric clear((char *) a, sizeof *a); 7103149Seric 7113149Seric /* figure out what net/mailer to use */ 7123149Seric if (**tv != CANONNET) 7134279Seric { 7143149Seric syserr("buildaddr: no net"); 7154279Seric return (NULL); 7164279Seric } 7173149Seric tv++; 7184635Seric if (sameword(*tv, "error")) 7194279Seric { 7204279Seric if (**++tv != CANONUSER) 7214279Seric syserr("buildaddr: error: no user"); 7224279Seric buf[0] = '\0'; 7234279Seric while (*++tv != NULL) 7244279Seric { 7254279Seric if (buf[0] != '\0') 7267005Seric (void) strcat(buf, " "); 7277005Seric (void) strcat(buf, *tv); 7284279Seric } 7294279Seric usrerr(buf); 7304279Seric return (NULL); 7314279Seric } 7324598Seric for (mp = Mailer; (m = *mp++) != NULL; ) 7333149Seric { 7344635Seric if (sameword(m->m_name, *tv)) 7353149Seric break; 7363149Seric } 7373149Seric if (m == NULL) 7384279Seric { 7393149Seric syserr("buildaddr: unknown net %s", *tv); 7404279Seric return (NULL); 7414279Seric } 7424598Seric a->q_mailer = m; 7433149Seric 7443149Seric /* figure out what host (if any) */ 7453149Seric tv++; 7464195Seric if (!bitset(M_LOCAL, m->m_flags)) 7473149Seric { 7485704Seric if (**tv++ != CANONHOST) 7494279Seric { 7503149Seric syserr("buildaddr: no host"); 7514279Seric return (NULL); 7524279Seric } 7535704Seric buf[0] = '\0'; 7545704Seric while (*tv != NULL && **tv != CANONUSER) 7557005Seric (void) strcat(buf, *tv++); 7565704Seric a->q_host = newstr(buf); 7573149Seric } 7583149Seric else 7593149Seric a->q_host = NULL; 7603149Seric 7613149Seric /* figure out the user */ 7623149Seric if (**tv != CANONUSER) 7634279Seric { 7643149Seric syserr("buildaddr: no user"); 7654279Seric return (NULL); 7664279Seric } 7674228Seric cataddr(++tv, buf, sizeof buf); 7683149Seric a->q_user = buf; 7693149Seric 7703149Seric return (a); 7713149Seric } 7723188Seric /* 7734228Seric ** CATADDR -- concatenate pieces of addresses (putting in <LWSP> subs) 7744228Seric ** 7754228Seric ** Parameters: 7764228Seric ** pvp -- parameter vector to rebuild. 7774228Seric ** buf -- buffer to build the string into. 7784228Seric ** sz -- size of buf. 7794228Seric ** 7804228Seric ** Returns: 7814228Seric ** none. 7824228Seric ** 7834228Seric ** Side Effects: 7844228Seric ** Destroys buf. 7854228Seric */ 7864228Seric 7874228Seric cataddr(pvp, buf, sz) 7884228Seric char **pvp; 7894228Seric char *buf; 7904228Seric register int sz; 7914228Seric { 7924228Seric bool oatomtok = FALSE; 7934228Seric bool natomtok = FALSE; 7944228Seric register int i; 7954228Seric register char *p; 7964228Seric 7974228Seric p = buf; 7984228Seric sz--; 7994228Seric while (*pvp != NULL && (i = strlen(*pvp)) < sz) 8004228Seric { 801*8078Seric natomtok = (toktype(**pvp) == ATM); 8024228Seric if (oatomtok && natomtok) 8034228Seric *p++ = SPACESUB; 8044228Seric (void) strcpy(p, *pvp); 8054228Seric oatomtok = natomtok; 8064228Seric p += i; 8074228Seric sz -= i; 8084228Seric pvp++; 8094228Seric } 8104228Seric *p = '\0'; 8114228Seric } 8124228Seric /* 8133188Seric ** SAMEADDR -- Determine if two addresses are the same 8143188Seric ** 8153188Seric ** This is not just a straight comparison -- if the mailer doesn't 8163188Seric ** care about the host we just ignore it, etc. 8173188Seric ** 8183188Seric ** Parameters: 8193188Seric ** a, b -- pointers to the internal forms to compare. 8203188Seric ** wildflg -- if TRUE, 'a' may have no user specified, 8213188Seric ** in which case it is to match anything. 8223188Seric ** 8233188Seric ** Returns: 8243188Seric ** TRUE -- they represent the same mailbox. 8253188Seric ** FALSE -- they don't. 8263188Seric ** 8273188Seric ** Side Effects: 8283188Seric ** none. 8293188Seric */ 8303188Seric 8313188Seric bool 8323188Seric sameaddr(a, b, wildflg) 8333188Seric register ADDRESS *a; 8343188Seric register ADDRESS *b; 8353188Seric bool wildflg; 8363188Seric { 8373188Seric /* if they don't have the same mailer, forget it */ 8383188Seric if (a->q_mailer != b->q_mailer) 8393188Seric return (FALSE); 8403188Seric 8413188Seric /* if the user isn't the same, we can drop out */ 8423188Seric if ((!wildflg || a->q_user[0] != '\0') && strcmp(a->q_user, b->q_user) != 0) 8433188Seric return (FALSE); 8443188Seric 8453188Seric /* if the mailer ignores hosts, we have succeeded! */ 8464598Seric if (bitset(M_LOCAL, a->q_mailer->m_flags)) 8473188Seric return (TRUE); 8483188Seric 8493188Seric /* otherwise compare hosts (but be careful for NULL ptrs) */ 8503188Seric if (a->q_host == NULL || b->q_host == NULL) 8513188Seric return (FALSE); 8523188Seric if (strcmp(a->q_host, b->q_host) != 0) 8533188Seric return (FALSE); 8543188Seric 8553188Seric return (TRUE); 8563188Seric } 8573234Seric /* 8583234Seric ** PRINTADDR -- print address (for debugging) 8593234Seric ** 8603234Seric ** Parameters: 8613234Seric ** a -- the address to print 8623234Seric ** follow -- follow the q_next chain. 8633234Seric ** 8643234Seric ** Returns: 8653234Seric ** none. 8663234Seric ** 8673234Seric ** Side Effects: 8683234Seric ** none. 8693234Seric */ 8703234Seric 8714317Seric # ifdef DEBUG 8724317Seric 8733234Seric printaddr(a, follow) 8743234Seric register ADDRESS *a; 8753234Seric bool follow; 8763234Seric { 8775001Seric bool first = TRUE; 8785001Seric 8793234Seric while (a != NULL) 8803234Seric { 8815001Seric first = FALSE; 8824443Seric printf("%x=", a); 8834085Seric (void) fflush(stdout); 8843234Seric printf("%s: mailer %d (%s), host `%s', user `%s'\n", a->q_paddr, 8854598Seric a->q_mailer->m_mno, a->q_mailer->m_name, a->q_host, a->q_user); 8865035Seric printf("\tnext=%x, flags=%o, rmailer %d, alias %x\n", a->q_next, 8875035Seric a->q_flags, a->q_rmailer, a->q_alias); 8885001Seric printf("\thome=\"%s\", fullname=\"%s\"\n", a->q_home, a->q_fullname); 8894996Seric 8903234Seric if (!follow) 8913234Seric return; 8924996Seric a = a->q_next; 8933234Seric } 8945001Seric if (first) 8954443Seric printf("[NULL]\n"); 8963234Seric } 8974317Seric 8984317Seric # endif DEBUG 8997682Seric /* 9007682Seric ** REMOTENAME -- return the name relative to the current mailer 9017682Seric ** 9027682Seric ** Parameters: 9037682Seric ** name -- the name to translate. 9048069Seric ** m -- the mailer that we want to do rewriting relative 9058069Seric ** to. 9068069Seric ** senderaddress -- if set, uses the sender rewriting rules 9078069Seric ** rather than the recipient rewriting rules. 9087682Seric ** 9097682Seric ** Returns: 9107682Seric ** the text string representing this address relative to 9117682Seric ** the receiving mailer. 9127682Seric ** 9137682Seric ** Side Effects: 9147682Seric ** none. 9157682Seric ** 9167682Seric ** Warnings: 9177682Seric ** The text string returned is tucked away locally; 9187682Seric ** copy it if you intend to save it. 9197682Seric */ 9207682Seric 9217682Seric char * 9228069Seric remotename(name, m, senderaddress) 9237682Seric char *name; 9247682Seric struct mailer *m; 9258069Seric bool senderaddress; 9267682Seric { 9278069Seric register char **pvp; 9288069Seric char *fancy; 9298069Seric extern char *macvalue(); 9308069Seric char *oldg = macvalue('g'); 9317682Seric static char buf[MAXNAME]; 9327682Seric char lbuf[MAXNAME]; 9337682Seric extern char **prescan(); 9347889Seric extern char *crackaddr(); 9357682Seric 9367755Seric # ifdef DEBUG 9377755Seric if (tTd(12, 1)) 9387755Seric printf("remotename(%s)\n", name); 9397755Seric # endif DEBUG 9407755Seric 9417682Seric /* 9427889Seric ** First put this address into canonical form. 9437889Seric ** First turn it into a macro. 9448069Seric ** Then run it through ruleset 1 or 2, depending on whether 9458069Seric ** it is a sender or a recipient address. 9468058Seric ** If the mailer defines a rewriting set, run it through 9478058Seric ** there next. 9487889Seric */ 9497889Seric 9507889Seric /* save away the extraneous pretty stuff */ 9517889Seric fancy = crackaddr(name); 9527889Seric 9537889Seric /* now run through ruleset four */ 9547889Seric pvp = prescan(name, '\0'); 9557889Seric if (pvp == NULL) 9567889Seric return (name); 9578069Seric if (senderaddress) 9587755Seric { 9597889Seric rewrite(pvp, 1); 9608069Seric if (m->m_s_rwset > 0) 9618069Seric rewrite(pvp, m->m_s_rwset); 9628069Seric } 9638069Seric else 9648069Seric { 9657889Seric rewrite(pvp, 2); 9668069Seric if (m->m_r_rwset > 0) 9678069Seric rewrite(pvp, m->m_r_rwset); 9687682Seric } 9697682Seric 9707889Seric /* now add any comment info we had before back */ 9717682Seric cataddr(pvp, lbuf, sizeof lbuf); 9727682Seric define('g', lbuf); 9737889Seric expand(fancy, buf, &buf[sizeof buf - 1], CurEnv); 9747682Seric define('g', oldg); 9757682Seric 9767682Seric # ifdef DEBUG 9777682Seric if (tTd(12, 1)) 9787755Seric printf("remotename => `%s'\n", buf); 9797682Seric # endif DEBUG 9807682Seric return (buf); 9817682Seric } 9827682Seric /* 9837682Seric ** CANONNAME -- make name canonical 9847682Seric ** 9857682Seric ** This is used for SMTP and misc. printing. Given a print 9867682Seric ** address, it strips out comments, etc., and puts on exactly 9877682Seric ** one set of brackets. 9887682Seric ** 9897682Seric ** Parameters: 9907682Seric ** name -- the name to make canonical. 9917682Seric ** 9927682Seric ** Returns: 9937682Seric ** pointer to canonical name. 9947682Seric ** 9957682Seric ** Side Effects: 9967682Seric ** none. 9977682Seric ** 9987682Seric ** Warning: 9997682Seric ** result is saved in static buf; future calls will trash it. 10007682Seric */ 10017682Seric 10027682Seric char * 10037682Seric canonname(name) 10047682Seric char *name; 10057682Seric { 10068069Seric static char nbuf[MAXNAME]; 10077940Seric register char **pvp; 10087682Seric 10097940Seric pvp = prescan(name, '\0'); 10108069Seric rewrite(pvp, 3); 10118069Seric cataddr(pvp, nbuf, sizeof nbuf); 10127682Seric return (nbuf); 10137682Seric } 1014