13312Seric # include "sendmail.h" 2297Seric 3*4228Seric static char SccsId[] = "@(#)parseaddr.c 3.20 08/25/81"; 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 # define SPACESUB ('.'|0200) /* substitution for <lwsp> */ 432091Seric 442973Seric ADDRESS * 45297Seric parse(addr, a, copyf) 46297Seric char *addr; 472973Seric register ADDRESS *a; 48297Seric int copyf; 49297Seric { 503149Seric register char **pvp; 513149Seric register struct mailer *m; 523149Seric extern char **prescan(); 533149Seric extern ADDRESS *buildaddr(); 54297Seric 55297Seric /* 56297Seric ** Initialize and prescan address. 57297Seric */ 58297Seric 59297Seric To = addr; 603188Seric # ifdef DEBUG 613188Seric if (Debug) 623188Seric printf("\n--parse(%s)\n", addr); 633188Seric # endif DEBUG 643188Seric 653149Seric pvp = prescan(addr, '\0'); 663149Seric if (pvp == NULL) 67297Seric return (NULL); 68297Seric 69297Seric /* 703149Seric ** Apply rewriting rules. 71297Seric */ 72297Seric 734070Seric rewrite(pvp, 0); 74297Seric 753149Seric /* 763149Seric ** See if we resolved to a real mailer. 773149Seric */ 78297Seric 793149Seric if (pvp[0][0] != CANONNET) 803149Seric { 813149Seric setstat(EX_USAGE); 823149Seric usrerr("cannot resolve name"); 833149Seric return (NULL); 84297Seric } 85297Seric 86297Seric /* 873149Seric ** Build canonical address from pvp. 88297Seric */ 89297Seric 903149Seric a = buildaddr(pvp, a); 913149Seric m = Mailer[a->q_mailer]; 92297Seric 93297Seric /* 943149Seric ** Make local copies of the host & user and then 953149Seric ** transport them out. 96297Seric */ 97297Seric 98297Seric if (copyf > 0) 992973Seric a->q_paddr = newstr(addr); 100297Seric else 101297Seric a->q_paddr = addr; 102297Seric 1033149Seric if (copyf >= 0) 104297Seric { 1053149Seric if (a->q_host != NULL) 1063149Seric a->q_host = newstr(a->q_host); 107297Seric else 1083149Seric a->q_host = ""; 1093149Seric if (a->q_user != a->q_paddr) 1103149Seric a->q_user = newstr(a->q_user); 111297Seric } 112297Seric 113297Seric /* 114297Seric ** Do UPPER->lower case mapping unless inhibited. 115297Seric */ 116297Seric 1173149Seric if (!bitset(M_HST_UPPER, m->m_flags)) 118297Seric makelower(a->q_host); 1193149Seric if (!bitset(M_USR_UPPER, m->m_flags)) 120297Seric makelower(a->q_user); 121297Seric 122297Seric /* 123297Seric ** Compute return value. 124297Seric */ 125297Seric 126297Seric # ifdef DEBUG 1271583Seric if (Debug) 128297Seric printf("parse(\"%s\"): host \"%s\" user \"%s\" mailer %d\n", 1293149Seric addr, a->q_host, a->q_user, a->q_mailer); 130297Seric # endif DEBUG 131297Seric 132297Seric return (a); 133297Seric } 134297Seric /* 135297Seric ** PRESCAN -- Prescan name and make it canonical 136297Seric ** 137297Seric ** Scans a name and turns it into canonical form. This involves 138297Seric ** deleting blanks, comments (in parentheses), and turning the 139297Seric ** word "at" into an at-sign ("@"). The name is copied as this 140297Seric ** is done; it is legal to copy a name onto itself, since this 141297Seric ** process can only make things smaller. 142297Seric ** 143297Seric ** This routine knows about quoted strings and angle brackets. 144297Seric ** 145297Seric ** There are certain subtleties to this routine. The one that 146297Seric ** comes to mind now is that backslashes on the ends of names 147297Seric ** are silently stripped off; this is intentional. The problem 148297Seric ** is that some versions of sndmsg (like at LBL) set the kill 149297Seric ** character to something other than @ when reading addresses; 150297Seric ** so people type "csvax.eric\@berkeley" -- which screws up the 151297Seric ** berknet mailer. 152297Seric ** 153297Seric ** Parameters: 154297Seric ** addr -- the name to chomp. 155297Seric ** delim -- the delimiter for the address, normally 156297Seric ** '\0' or ','; \0 is accepted in any case. 157297Seric ** are moving in place; set buflim to high core. 158297Seric ** 159297Seric ** Returns: 1603149Seric ** A pointer to a vector of tokens. 161297Seric ** NULL on error. 162297Seric ** 163297Seric ** Side Effects: 1643149Seric ** none. 165297Seric */ 166297Seric 1673149Seric # define OPER 1 1683149Seric # define ATOM 2 1693149Seric # define EOTOK 3 1703149Seric # define QSTRING 4 1713149Seric # define SPACE 5 1723149Seric # define DOLLAR 6 1733149Seric # define GETONE 7 1743149Seric 1753149Seric char ** 1763149Seric prescan(addr, delim) 177297Seric char *addr; 178297Seric char delim; 179297Seric { 180297Seric register char *p; 1813149Seric static char buf[MAXNAME+MAXATOM]; 1823149Seric static char *av[MAXATOM+1]; 1833149Seric char **avp; 184297Seric bool space; 185297Seric bool bslashmode; 186297Seric int cmntcnt; 187297Seric int brccnt; 188297Seric register char c; 1893149Seric char *tok; 190297Seric register char *q; 1913149Seric register int state; 1923149Seric int nstate; 1934085Seric extern char lower(); 194297Seric 1952091Seric space = FALSE; 196297Seric q = buf; 1973149Seric bslashmode = FALSE; 198297Seric cmntcnt = brccnt = 0; 1993149Seric avp = av; 2003149Seric state = OPER; 2013149Seric for (p = addr; *p != '\0' && *p != delim; ) 202297Seric { 2033149Seric /* read a token */ 2043149Seric tok = q; 2053149Seric while ((c = *p++) != '\0' && c != delim) 206297Seric { 2073149Seric /* chew up special characters */ 2084100Seric c &= ~0200; 2093149Seric *q = '\0'; 2103149Seric if (bslashmode) 2113149Seric { 2123149Seric c |= 0200; 2133149Seric bslashmode = FALSE; 2143149Seric } 2153149Seric else if (c == '\\') 2163149Seric { 2173149Seric bslashmode = TRUE; 2183149Seric continue; 2193149Seric } 2204100Seric else if (c == '"') 2214100Seric { 2224100Seric if (state == QSTRING) 2234100Seric state = OPER; 2244100Seric else 2254100Seric state = QSTRING; 2264100Seric break; 2274100Seric } 2283149Seric 2293149Seric nstate = toktype(c); 2303149Seric switch (state) 2313149Seric { 2323149Seric case QSTRING: /* in quoted string */ 2333149Seric break; 2343149Seric 2353149Seric case ATOM: /* regular atom */ 236*4228Seric /* state = nstate; */ 237*4228Seric if (nstate != ATOM) 2383149Seric { 2393149Seric state = EOTOK; 2403149Seric p--; 2413149Seric } 2423149Seric break; 2433149Seric 2443149Seric case GETONE: /* grab one character */ 2453149Seric state = OPER; 2463149Seric break; 2473149Seric 2483149Seric case EOTOK: /* after atom or q-string */ 2493149Seric state = nstate; 2503149Seric if (state == SPACE) 2513149Seric continue; 2523149Seric break; 2533149Seric 2543149Seric case SPACE: /* linear white space */ 2553149Seric state = nstate; 2563149Seric space = TRUE; 257*4228Seric break; 2583149Seric 2593149Seric case OPER: /* operator */ 2603149Seric if (nstate == SPACE) 2613149Seric continue; 2623149Seric state = nstate; 2633149Seric break; 2643149Seric 2653149Seric case DOLLAR: /* $- etc. */ 2663149Seric state = OPER; 2673149Seric switch (c) 2683149Seric { 2693149Seric case '$': /* literal $ */ 2703149Seric break; 2713149Seric 2723149Seric case '+': /* match anything */ 2733149Seric c = MATCHANY; 2743149Seric state = GETONE; 2753149Seric break; 2763149Seric 2773149Seric case '-': /* match one token */ 2783149Seric c = MATCHONE; 2793149Seric state = GETONE; 2803149Seric break; 2813149Seric 2824060Seric case '=': /* match one token of class */ 2834060Seric c = MATCHCLASS; 2844060Seric state = GETONE; 2854060Seric break; 2864060Seric 2873149Seric case '#': /* canonical net name */ 2883149Seric c = CANONNET; 2893149Seric break; 2903149Seric 2913149Seric case '@': /* canonical host name */ 2923149Seric c = CANONHOST; 2933149Seric break; 2943149Seric 2953149Seric case ':': /* canonical user name */ 2963149Seric c = CANONUSER; 2973149Seric break; 2983149Seric 2993149Seric default: 3003149Seric c = '$'; 3013149Seric state = OPER; 3023149Seric p--; 3033149Seric break; 3043149Seric } 3053149Seric break; 3063149Seric 3073149Seric default: 3083149Seric syserr("prescan: unknown state %d", state); 3093149Seric } 3103149Seric 311*4228Seric if (state == EOTOK || state == SPACE) 3123149Seric break; 3133149Seric if (c == '$' && delim == '\t') 3143149Seric { 3153149Seric state = DOLLAR; 3163149Seric continue; 3173149Seric } 3183149Seric 3193149Seric /* squirrel it away */ 3203149Seric if (q >= &buf[sizeof buf - 5]) 3213149Seric { 3223149Seric usrerr("Address too long"); 3233149Seric return (NULL); 3243149Seric } 3253149Seric *q++ = c; 3263149Seric 3273149Seric /* decide whether this represents end of token */ 3283149Seric if (state == OPER) 3293149Seric break; 330297Seric } 3313149Seric if (c == '\0' || c == delim) 3323149Seric p--; 3333149Seric 3343149Seric /* new token */ 3353149Seric if (tok == q) 336297Seric continue; 3373149Seric *q++ = '\0'; 3383149Seric 3393149Seric c = tok[0]; 3403149Seric if (c == '(') 3411378Seric { 342297Seric cmntcnt++; 3431378Seric continue; 3441378Seric } 345297Seric else if (c == ')') 346297Seric { 347297Seric if (cmntcnt <= 0) 348297Seric { 349297Seric usrerr("Unbalanced ')'"); 350297Seric return (NULL); 351297Seric } 352297Seric else 353297Seric { 354297Seric cmntcnt--; 355297Seric continue; 356297Seric } 357297Seric } 3583149Seric else if (cmntcnt > 0) 3592091Seric continue; 3603149Seric 3613149Seric *avp++ = tok; 3623149Seric 3633149Seric /* we prefer <> specs */ 3643149Seric if (c == '<') 365297Seric { 3662092Seric if (brccnt < 0) 3672092Seric { 3682092Seric usrerr("multiple < spec"); 3692092Seric return (NULL); 3702092Seric } 371297Seric brccnt++; 3722091Seric space = FALSE; 373297Seric if (brccnt == 1) 374297Seric { 375297Seric /* we prefer using machine readable name */ 376297Seric q = buf; 377297Seric *q = '\0'; 3783149Seric avp = av; 379297Seric continue; 380297Seric } 381297Seric } 382297Seric else if (c == '>') 383297Seric { 384297Seric if (brccnt <= 0) 385297Seric { 386297Seric usrerr("Unbalanced `>'"); 387297Seric return (NULL); 388297Seric } 389297Seric else 390297Seric brccnt--; 391297Seric if (brccnt <= 0) 3922092Seric { 3932092Seric brccnt = -1; 394297Seric continue; 3952092Seric } 396297Seric } 397*4228Seric 398*4228Seric /* 399*4228Seric ** Turn "at" into "@", 400*4228Seric ** but only if "at" is a word. 401*4228Seric */ 402*4228Seric 403*4228Seric if (lower(tok[0]) == 'a' && lower(tok[1]) == 't' && tok[2] == '\0') 404*4228Seric { 405*4228Seric tok[0] = '@'; 406*4228Seric tok[1] = '\0'; 407*4228Seric } 4083149Seric } 4093149Seric *avp = NULL; 4103149Seric if (cmntcnt > 0) 4113149Seric usrerr("Unbalanced '('"); 4123149Seric else if (brccnt > 0) 4133149Seric usrerr("Unbalanced '<'"); 4143149Seric else if (state == QSTRING) 4153149Seric usrerr("Unbalanced '\"'"); 4163149Seric else if (av[0] != NULL) 4173149Seric return (av); 4183149Seric return (NULL); 4193149Seric } 4203149Seric /* 4213149Seric ** TOKTYPE -- return token type 4223149Seric ** 4233149Seric ** Parameters: 4243149Seric ** c -- the character in question. 4253149Seric ** 4263149Seric ** Returns: 4273149Seric ** Its type. 4283149Seric ** 4293149Seric ** Side Effects: 4303149Seric ** none. 4313149Seric */ 432297Seric 4333149Seric toktype(c) 4343149Seric register char c; 4353149Seric { 4363380Seric static char buf[50]; 4373382Seric static bool firstime = TRUE; 4383380Seric 4393382Seric if (firstime) 4403380Seric { 4413382Seric firstime = FALSE; 4424085Seric (void) expand("$o", buf, &buf[sizeof buf - 1]); 4433380Seric strcat(buf, DELIMCHARS); 4443380Seric } 4454100Seric if (!isascii(c)) 4464100Seric return (ATOM); 4473149Seric if (isspace(c)) 4483149Seric return (SPACE); 4493380Seric if (iscntrl(c) || index(buf, c) != NULL) 4503149Seric return (OPER); 4513149Seric return (ATOM); 4523149Seric } 4533149Seric /* 4543149Seric ** REWRITE -- apply rewrite rules to token vector. 4553149Seric ** 4563149Seric ** Parameters: 4573149Seric ** pvp -- pointer to token vector. 4583149Seric ** 4593149Seric ** Returns: 4603149Seric ** none. 4613149Seric ** 4623149Seric ** Side Effects: 4633149Seric ** pvp is modified. 4643149Seric */ 4652091Seric 4663149Seric struct match 4673149Seric { 4683149Seric char **firsttok; /* first token matched */ 4693149Seric char **lasttok; /* last token matched */ 4703149Seric char name; /* name of parameter */ 4713149Seric }; 4723149Seric 4733149Seric # define MAXMATCH 8 /* max params per rewrite */ 4743149Seric 4753149Seric 4764070Seric rewrite(pvp, ruleset) 4773149Seric char **pvp; 4784070Seric int ruleset; 4793149Seric { 4803149Seric register char *ap; /* address pointer */ 4813149Seric register char *rp; /* rewrite pointer */ 4823149Seric register char **avp; /* address vector pointer */ 4833149Seric register char **rvp; /* rewrite vector pointer */ 4843149Seric struct rewrite *rwr; 4853149Seric struct match mlist[MAXMATCH]; 4863149Seric char *npvp[MAXATOM+1]; /* temporary space for rebuild */ 4874060Seric extern bool sameword(); 4883149Seric 4894100Seric # ifdef DEBUG 490*4228Seric if (Debug > 9) 4913149Seric { 4923149Seric printf("rewrite: original pvp:\n"); 4933149Seric printav(pvp); 4943149Seric } 4954100Seric # endif DEBUG 4963149Seric 4973149Seric /* 4983149Seric ** Run through the list of rewrite rules, applying 4993149Seric ** any that match. 5003149Seric */ 5013149Seric 5024070Seric for (rwr = RewriteRules[ruleset]; rwr != NULL; ) 5033149Seric { 5044100Seric # ifdef DEBUG 5054100Seric if (Debug > 10) 506297Seric { 5073149Seric printf("-----trying rule:\n"); 5083149Seric printav(rwr->r_lhs); 5093149Seric } 5104100Seric # endif DEBUG 5113149Seric 5123149Seric /* try to match on this rule */ 5133149Seric clrmatch(mlist); 5143149Seric for (rvp = rwr->r_lhs, avp = pvp; *avp != NULL; ) 5153149Seric { 5163149Seric ap = *avp; 5173149Seric rp = *rvp; 5183149Seric 5193149Seric if (rp == NULL) 520297Seric { 5213149Seric /* end-of-pattern before end-of-address */ 5223149Seric goto fail; 523297Seric } 5243149Seric 5253149Seric switch (*rp) 5263149Seric { 5274060Seric register STAB *s; 5284060Seric register int class; 5294060Seric 5303149Seric case MATCHONE: 5313149Seric /* match exactly one token */ 5323149Seric setmatch(mlist, rp[1], avp, avp); 5333149Seric break; 5343149Seric 5353149Seric case MATCHANY: 5363149Seric /* match any number of tokens */ 5374085Seric setmatch(mlist, rp[1], (char **) NULL, avp); 5383149Seric break; 5393149Seric 5404060Seric case MATCHCLASS: 5414060Seric /* match any token in a class */ 5424060Seric class = rp[1]; 5434060Seric if (!isalpha(class)) 5444060Seric goto fail; 5454060Seric if (isupper(class)) 5464060Seric class -= 'A'; 5474060Seric else 5484060Seric class -= 'a'; 5494100Seric s = stab(ap, ST_CLASS, ST_FIND); 5504060Seric if (s == NULL || (s->s_class & (1 << class)) == 0) 5514060Seric goto fail; 5524060Seric break; 5534060Seric 5543149Seric default: 5553149Seric /* must have exact match */ 5564060Seric if (!sameword(rp, ap)) 5574060Seric goto fail; 5583149Seric break; 5593149Seric } 5603149Seric 5613149Seric /* successful match on this token */ 5623149Seric avp++; 5633149Seric rvp++; 5643149Seric continue; 5653149Seric 5663149Seric fail: 5673149Seric /* match failed -- back up */ 5683149Seric while (--rvp >= rwr->r_lhs) 5693149Seric { 5703149Seric rp = *rvp; 5713149Seric if (*rp == MATCHANY) 5723149Seric break; 5733149Seric 5743149Seric /* can't extend match: back up everything */ 5753149Seric avp--; 5763149Seric 5773149Seric if (*rp == MATCHONE) 5783149Seric { 5793149Seric /* undo binding */ 5804085Seric setmatch(mlist, rp[1], (char **) NULL, (char **) NULL); 5813149Seric } 5823149Seric } 5833149Seric 5843149Seric if (rvp < rwr->r_lhs) 5853149Seric { 5863149Seric /* total failure to match */ 5873149Seric break; 5883149Seric } 589297Seric } 5903149Seric 5913149Seric /* 5923149Seric ** See if we successfully matched 5933149Seric */ 5943149Seric 5953149Seric if (rvp >= rwr->r_lhs && *rvp == NULL) 5963149Seric { 5974100Seric # ifdef DEBUG 5984100Seric if (Debug > 10) 5993149Seric { 6003149Seric printf("-----rule matches:\n"); 6013149Seric printav(rwr->r_rhs); 6023149Seric } 6034100Seric # endif DEBUG 6043149Seric 6053149Seric /* substitute */ 6063149Seric for (rvp = rwr->r_rhs, avp = npvp; *rvp != NULL; rvp++) 6073149Seric { 6083149Seric rp = *rvp; 6093149Seric if (*rp == MATCHANY) 6103149Seric { 6113149Seric register struct match *m; 6123149Seric register char **pp; 6133149Seric extern struct match *findmatch(); 6143149Seric 6153149Seric m = findmatch(mlist, rp[1]); 6163149Seric if (m != NULL) 6173149Seric { 6183149Seric pp = m->firsttok; 6193149Seric do 6203149Seric { 6213149Seric *avp++ = *pp; 6223149Seric } while (pp++ != m->lasttok); 6233149Seric } 6243149Seric } 6253149Seric else 6263149Seric *avp++ = rp; 6273149Seric } 6283149Seric *avp++ = NULL; 6294085Seric bmove((char *) npvp, (char *) pvp, (avp - npvp) * sizeof *avp); 6303149Seric # ifdef DEBUG 631*4228Seric if (Debug > 3) 6323149Seric { 6333188Seric char **vp; 6343188Seric 6353188Seric printf("rewritten as `"); 6363188Seric for (vp = pvp; *vp != NULL; vp++) 637*4228Seric { 638*4228Seric if (vp != pvp) 639*4228Seric printf("_"); 6403188Seric xputs(*vp); 641*4228Seric } 6423188Seric printf("'\n"); 6433149Seric } 6443149Seric # endif DEBUG 6453149Seric if (pvp[0][0] == CANONNET) 6463149Seric break; 6473149Seric } 6483149Seric else 6493149Seric { 6504100Seric # ifdef DEBUG 6514100Seric if (Debug > 10) 6523149Seric printf("----- rule fails\n"); 6534100Seric # endif DEBUG 6543149Seric rwr = rwr->r_next; 6553149Seric } 656297Seric } 6573149Seric } 6583149Seric /* 6593149Seric ** SETMATCH -- set parameter value in match vector 6603149Seric ** 6613149Seric ** Parameters: 6623149Seric ** mlist -- list of match values. 6633149Seric ** name -- the character name of this parameter. 6643149Seric ** first -- the first location of the replacement. 6653149Seric ** last -- the last location of the replacement. 6663149Seric ** 6673149Seric ** If last == NULL, delete this entry. 6683149Seric ** If first == NULL, extend this entry (or add it if 6693149Seric ** it does not exist). 6703149Seric ** 6713149Seric ** Returns: 6723149Seric ** nothing. 6733149Seric ** 6743149Seric ** Side Effects: 6753149Seric ** munges with mlist. 6763149Seric */ 6773149Seric 6783149Seric setmatch(mlist, name, first, last) 6793149Seric struct match *mlist; 6803149Seric char name; 6813149Seric char **first; 6823149Seric char **last; 6833149Seric { 6843149Seric register struct match *m; 6853149Seric struct match *nullm = NULL; 6863149Seric 6873149Seric for (m = mlist; m < &mlist[MAXMATCH]; m++) 6883149Seric { 6893149Seric if (m->name == name) 6903149Seric break; 6913149Seric if (m->name == '\0') 6923149Seric nullm = m; 6933149Seric } 6943149Seric 6953149Seric if (m >= &mlist[MAXMATCH]) 6963149Seric m = nullm; 6973149Seric 6983149Seric if (last == NULL) 6993149Seric { 7003149Seric m->name = '\0'; 7013149Seric return; 7023149Seric } 7033149Seric 7043149Seric if (m->name == '\0') 7053149Seric { 7063149Seric if (first == NULL) 7073149Seric m->firsttok = last; 7083149Seric else 7093149Seric m->firsttok = first; 7103149Seric } 7113149Seric m->name = name; 7123149Seric m->lasttok = last; 7133149Seric } 7143149Seric /* 7153149Seric ** FINDMATCH -- find match in mlist 7163149Seric ** 7173149Seric ** Parameters: 7183149Seric ** mlist -- list to search. 7193149Seric ** name -- name to find. 7203149Seric ** 7213149Seric ** Returns: 7223149Seric ** pointer to match structure. 7233149Seric ** NULL if no match. 7243149Seric ** 7253149Seric ** Side Effects: 7263149Seric ** none. 7273149Seric */ 7283149Seric 7293149Seric struct match * 7303149Seric findmatch(mlist, name) 7313149Seric struct match *mlist; 7323149Seric char name; 7333149Seric { 7343149Seric register struct match *m; 7353149Seric 7363149Seric for (m = mlist; m < &mlist[MAXMATCH]; m++) 7373149Seric { 7383149Seric if (m->name == name) 7393149Seric return (m); 7403149Seric } 7413149Seric 742297Seric return (NULL); 743297Seric } 7443149Seric /* 7453149Seric ** CLRMATCH -- clear match list 7463149Seric ** 7473149Seric ** Parameters: 7483149Seric ** mlist -- list to clear. 7493149Seric ** 7503149Seric ** Returns: 7513149Seric ** none. 7523149Seric ** 7533149Seric ** Side Effects: 7543149Seric ** mlist is cleared. 7553149Seric */ 7563149Seric 7573149Seric clrmatch(mlist) 7583149Seric struct match *mlist; 7593149Seric { 7603149Seric register struct match *m; 7613149Seric 7623149Seric for (m = mlist; m < &mlist[MAXMATCH]; m++) 7633149Seric m->name = '\0'; 7643149Seric } 7653149Seric /* 7663149Seric ** BUILDADDR -- build address from token vector. 7673149Seric ** 7683149Seric ** Parameters: 7693149Seric ** tv -- token vector. 7703149Seric ** a -- pointer to address descriptor to fill. 7713149Seric ** If NULL, one will be allocated. 7723149Seric ** 7733149Seric ** Returns: 7743149Seric ** 'a' 7753149Seric ** 7763149Seric ** Side Effects: 7773149Seric ** fills in 'a' 7783149Seric */ 7793149Seric 7803149Seric ADDRESS * 7813149Seric buildaddr(tv, a) 7823149Seric register char **tv; 7833149Seric register ADDRESS *a; 7843149Seric { 7853149Seric register int i; 7863149Seric static char buf[MAXNAME]; 7873149Seric struct mailer **mp; 7883149Seric register struct mailer *m; 7893149Seric 7903149Seric if (a == NULL) 7913149Seric a = (ADDRESS *) xalloc(sizeof *a); 7923188Seric a->q_flags = 0; 7934079Seric a->q_home = NULL; 7943149Seric 7953149Seric /* figure out what net/mailer to use */ 7963149Seric if (**tv != CANONNET) 7973149Seric syserr("buildaddr: no net"); 7983149Seric tv++; 7993154Seric for (mp = Mailer, i = 0; (m = *mp++) != NULL; i++) 8003149Seric { 8013149Seric if (strcmp(m->m_name, *tv) == 0) 8023149Seric break; 8033149Seric } 8043149Seric if (m == NULL) 8053149Seric syserr("buildaddr: unknown net %s", *tv); 8063149Seric a->q_mailer = i; 8073149Seric 8083149Seric /* figure out what host (if any) */ 8093149Seric tv++; 8104195Seric if (!bitset(M_LOCAL, m->m_flags)) 8113149Seric { 8123149Seric if (**tv != CANONHOST) 8133149Seric syserr("buildaddr: no host"); 8143149Seric tv++; 8153149Seric a->q_host = *tv; 8163149Seric tv++; 8173149Seric } 8183149Seric else 8193149Seric a->q_host = NULL; 8203149Seric 8213149Seric /* figure out the user */ 8223149Seric if (**tv != CANONUSER) 8233149Seric syserr("buildaddr: no user"); 824*4228Seric cataddr(++tv, buf, sizeof buf); 8253149Seric a->q_user = buf; 8263149Seric 8273149Seric return (a); 8283149Seric } 8293188Seric /* 830*4228Seric ** CATADDR -- concatenate pieces of addresses (putting in <LWSP> subs) 831*4228Seric ** 832*4228Seric ** Parameters: 833*4228Seric ** pvp -- parameter vector to rebuild. 834*4228Seric ** buf -- buffer to build the string into. 835*4228Seric ** sz -- size of buf. 836*4228Seric ** 837*4228Seric ** Returns: 838*4228Seric ** none. 839*4228Seric ** 840*4228Seric ** Side Effects: 841*4228Seric ** Destroys buf. 842*4228Seric */ 843*4228Seric 844*4228Seric cataddr(pvp, buf, sz) 845*4228Seric char **pvp; 846*4228Seric char *buf; 847*4228Seric register int sz; 848*4228Seric { 849*4228Seric bool oatomtok = FALSE; 850*4228Seric bool natomtok = FALSE; 851*4228Seric register int i; 852*4228Seric register char *p; 853*4228Seric 854*4228Seric p = buf; 855*4228Seric sz--; 856*4228Seric while (*pvp != NULL && (i = strlen(*pvp)) < sz) 857*4228Seric { 858*4228Seric natomtok = (toktype(**pvp) == ATOM); 859*4228Seric if (oatomtok && natomtok) 860*4228Seric *p++ = SPACESUB; 861*4228Seric (void) strcpy(p, *pvp); 862*4228Seric oatomtok = natomtok; 863*4228Seric p += i; 864*4228Seric sz -= i; 865*4228Seric pvp++; 866*4228Seric } 867*4228Seric *p = '\0'; 868*4228Seric } 869*4228Seric /* 8703188Seric ** SAMEADDR -- Determine if two addresses are the same 8713188Seric ** 8723188Seric ** This is not just a straight comparison -- if the mailer doesn't 8733188Seric ** care about the host we just ignore it, etc. 8743188Seric ** 8753188Seric ** Parameters: 8763188Seric ** a, b -- pointers to the internal forms to compare. 8773188Seric ** wildflg -- if TRUE, 'a' may have no user specified, 8783188Seric ** in which case it is to match anything. 8793188Seric ** 8803188Seric ** Returns: 8813188Seric ** TRUE -- they represent the same mailbox. 8823188Seric ** FALSE -- they don't. 8833188Seric ** 8843188Seric ** Side Effects: 8853188Seric ** none. 8863188Seric */ 8873188Seric 8883188Seric bool 8893188Seric sameaddr(a, b, wildflg) 8903188Seric register ADDRESS *a; 8913188Seric register ADDRESS *b; 8923188Seric bool wildflg; 8933188Seric { 8943188Seric /* if they don't have the same mailer, forget it */ 8953188Seric if (a->q_mailer != b->q_mailer) 8963188Seric return (FALSE); 8973188Seric 8983188Seric /* if the user isn't the same, we can drop out */ 8993188Seric if ((!wildflg || a->q_user[0] != '\0') && strcmp(a->q_user, b->q_user) != 0) 9003188Seric return (FALSE); 9013188Seric 9023188Seric /* if the mailer ignores hosts, we have succeeded! */ 9034195Seric if (bitset(M_LOCAL, Mailer[a->q_mailer]->m_flags)) 9043188Seric return (TRUE); 9053188Seric 9063188Seric /* otherwise compare hosts (but be careful for NULL ptrs) */ 9073188Seric if (a->q_host == NULL || b->q_host == NULL) 9083188Seric return (FALSE); 9093188Seric if (strcmp(a->q_host, b->q_host) != 0) 9103188Seric return (FALSE); 9113188Seric 9123188Seric return (TRUE); 9133188Seric } 9143234Seric /* 9153234Seric ** PRINTADDR -- print address (for debugging) 9163234Seric ** 9173234Seric ** Parameters: 9183234Seric ** a -- the address to print 9193234Seric ** follow -- follow the q_next chain. 9203234Seric ** 9213234Seric ** Returns: 9223234Seric ** none. 9233234Seric ** 9243234Seric ** Side Effects: 9253234Seric ** none. 9263234Seric */ 9273234Seric 9283234Seric printaddr(a, follow) 9293234Seric register ADDRESS *a; 9303234Seric bool follow; 9313234Seric { 9323234Seric while (a != NULL) 9333234Seric { 9343234Seric printf("addr@%x: ", a); 9354085Seric (void) fflush(stdout); 9363234Seric printf("%s: mailer %d (%s), host `%s', user `%s'\n", a->q_paddr, 9373234Seric a->q_mailer, Mailer[a->q_mailer]->m_name, a->q_host, a->q_user); 9383234Seric printf("\tnext=%x flags=%o, rmailer %d\n", a->q_next, 9393234Seric a->q_flags, a->q_rmailer); 9403234Seric 9413234Seric if (!follow) 9423234Seric return; 9433234Seric a = a->q_next; 9443234Seric } 9453234Seric } 946