13312Seric # include "sendmail.h" 2297Seric 3*4195Seric static char SccsId[] = "@(#)parseaddr.c 3.19 08/21/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 ** Called By: 41297Seric ** main 42297Seric ** sendto 43297Seric ** alias 44297Seric ** savemail 45297Seric */ 46297Seric 473380Seric # define DELIMCHARS "$()<>,;\\\"\r\n" /* word delimiters */ 482091Seric # define SPACESUB ('.'|0200) /* substitution for <lwsp> */ 492091Seric 502973Seric ADDRESS * 51297Seric parse(addr, a, copyf) 52297Seric char *addr; 532973Seric register ADDRESS *a; 54297Seric int copyf; 55297Seric { 563149Seric register char **pvp; 573149Seric register struct mailer *m; 583149Seric extern char **prescan(); 593149Seric extern ADDRESS *buildaddr(); 60297Seric 61297Seric /* 62297Seric ** Initialize and prescan address. 63297Seric */ 64297Seric 65297Seric To = addr; 663188Seric # ifdef DEBUG 673188Seric if (Debug) 683188Seric printf("\n--parse(%s)\n", addr); 693188Seric # endif DEBUG 703188Seric 713149Seric pvp = prescan(addr, '\0'); 723149Seric if (pvp == NULL) 73297Seric return (NULL); 74297Seric 75297Seric /* 763149Seric ** Apply rewriting rules. 77297Seric */ 78297Seric 794070Seric rewrite(pvp, 0); 80297Seric 813149Seric /* 823149Seric ** See if we resolved to a real mailer. 833149Seric */ 84297Seric 853149Seric if (pvp[0][0] != CANONNET) 863149Seric { 873149Seric setstat(EX_USAGE); 883149Seric usrerr("cannot resolve name"); 893149Seric return (NULL); 90297Seric } 91297Seric 92297Seric /* 933149Seric ** Build canonical address from pvp. 94297Seric */ 95297Seric 963149Seric a = buildaddr(pvp, a); 973149Seric m = Mailer[a->q_mailer]; 98297Seric 99297Seric /* 1003149Seric ** Make local copies of the host & user and then 1013149Seric ** transport them out. 102297Seric */ 103297Seric 104297Seric if (copyf > 0) 1052973Seric a->q_paddr = newstr(addr); 106297Seric else 107297Seric a->q_paddr = addr; 108297Seric 1093149Seric if (copyf >= 0) 110297Seric { 1113149Seric if (a->q_host != NULL) 1123149Seric a->q_host = newstr(a->q_host); 113297Seric else 1143149Seric a->q_host = ""; 1153149Seric if (a->q_user != a->q_paddr) 1163149Seric a->q_user = newstr(a->q_user); 117297Seric } 118297Seric 119297Seric /* 120297Seric ** Do UPPER->lower case mapping unless inhibited. 121297Seric */ 122297Seric 1233149Seric if (!bitset(M_HST_UPPER, m->m_flags)) 124297Seric makelower(a->q_host); 1253149Seric if (!bitset(M_USR_UPPER, m->m_flags)) 126297Seric makelower(a->q_user); 127297Seric 128297Seric /* 129297Seric ** Compute return value. 130297Seric */ 131297Seric 132297Seric # ifdef DEBUG 1331583Seric if (Debug) 134297Seric printf("parse(\"%s\"): host \"%s\" user \"%s\" mailer %d\n", 1353149Seric addr, a->q_host, a->q_user, a->q_mailer); 136297Seric # endif DEBUG 137297Seric 138297Seric return (a); 139297Seric } 140297Seric /* 141297Seric ** PRESCAN -- Prescan name and make it canonical 142297Seric ** 143297Seric ** Scans a name and turns it into canonical form. This involves 144297Seric ** deleting blanks, comments (in parentheses), and turning the 145297Seric ** word "at" into an at-sign ("@"). The name is copied as this 146297Seric ** is done; it is legal to copy a name onto itself, since this 147297Seric ** process can only make things smaller. 148297Seric ** 149297Seric ** This routine knows about quoted strings and angle brackets. 150297Seric ** 151297Seric ** There are certain subtleties to this routine. The one that 152297Seric ** comes to mind now is that backslashes on the ends of names 153297Seric ** are silently stripped off; this is intentional. The problem 154297Seric ** is that some versions of sndmsg (like at LBL) set the kill 155297Seric ** character to something other than @ when reading addresses; 156297Seric ** so people type "csvax.eric\@berkeley" -- which screws up the 157297Seric ** berknet mailer. 158297Seric ** 159297Seric ** Parameters: 160297Seric ** addr -- the name to chomp. 161297Seric ** delim -- the delimiter for the address, normally 162297Seric ** '\0' or ','; \0 is accepted in any case. 163297Seric ** are moving in place; set buflim to high core. 164297Seric ** 165297Seric ** Returns: 1663149Seric ** A pointer to a vector of tokens. 167297Seric ** NULL on error. 168297Seric ** 169297Seric ** Side Effects: 1703149Seric ** none. 171297Seric */ 172297Seric 1733149Seric # define OPER 1 1743149Seric # define ATOM 2 1753149Seric # define EOTOK 3 1763149Seric # define QSTRING 4 1773149Seric # define SPACE 5 1783149Seric # define DOLLAR 6 1793149Seric # define GETONE 7 1803149Seric 1813149Seric char ** 1823149Seric prescan(addr, delim) 183297Seric char *addr; 184297Seric char delim; 185297Seric { 186297Seric register char *p; 1873149Seric static char buf[MAXNAME+MAXATOM]; 1883149Seric static char *av[MAXATOM+1]; 1893149Seric char **avp; 190297Seric bool space; 191297Seric bool bslashmode; 192297Seric int cmntcnt; 193297Seric int brccnt; 194297Seric register char c; 1953149Seric char *tok; 196297Seric register char *q; 1973149Seric register int state; 1983149Seric int nstate; 1994085Seric extern char lower(); 200297Seric 2012091Seric space = FALSE; 202297Seric q = buf; 2033149Seric bslashmode = FALSE; 204297Seric cmntcnt = brccnt = 0; 2053149Seric avp = av; 2063149Seric state = OPER; 2073149Seric for (p = addr; *p != '\0' && *p != delim; ) 208297Seric { 2093149Seric /* read a token */ 2103149Seric tok = q; 2113149Seric while ((c = *p++) != '\0' && c != delim) 212297Seric { 2133149Seric /* chew up special characters */ 2144100Seric c &= ~0200; 2153149Seric *q = '\0'; 2163149Seric if (bslashmode) 2173149Seric { 2183149Seric c |= 0200; 2193149Seric bslashmode = FALSE; 2203149Seric } 2213149Seric else if (c == '\\') 2223149Seric { 2233149Seric bslashmode = TRUE; 2243149Seric continue; 2253149Seric } 2264100Seric else if (c == '"') 2274100Seric { 2284100Seric if (state == QSTRING) 2294100Seric state = OPER; 2304100Seric else 2314100Seric state = QSTRING; 2324100Seric break; 2334100Seric } 2343149Seric 2353149Seric nstate = toktype(c); 2363149Seric switch (state) 2373149Seric { 2383149Seric case QSTRING: /* in quoted string */ 2393149Seric break; 2403149Seric 2413149Seric case ATOM: /* regular atom */ 2423149Seric state = nstate; 2433149Seric if (state != ATOM) 2443149Seric { 2453149Seric state = EOTOK; 2463149Seric p--; 2473149Seric } 2483149Seric break; 2493149Seric 2503149Seric case GETONE: /* grab one character */ 2513149Seric state = OPER; 2523149Seric break; 2533149Seric 2543149Seric case EOTOK: /* after atom or q-string */ 2553149Seric state = nstate; 2563149Seric if (state == SPACE) 2573149Seric continue; 2583149Seric break; 2593149Seric 2603149Seric case SPACE: /* linear white space */ 2613149Seric state = nstate; 2623149Seric space = TRUE; 2633149Seric continue; 2643149Seric 2653149Seric case OPER: /* operator */ 2663149Seric if (nstate == SPACE) 2673149Seric continue; 2683149Seric state = nstate; 2693149Seric break; 2703149Seric 2713149Seric case DOLLAR: /* $- etc. */ 2723149Seric state = OPER; 2733149Seric switch (c) 2743149Seric { 2753149Seric case '$': /* literal $ */ 2763149Seric break; 2773149Seric 2783149Seric case '+': /* match anything */ 2793149Seric c = MATCHANY; 2803149Seric state = GETONE; 2813149Seric break; 2823149Seric 2833149Seric case '-': /* match one token */ 2843149Seric c = MATCHONE; 2853149Seric state = GETONE; 2863149Seric break; 2873149Seric 2884060Seric case '=': /* match one token of class */ 2894060Seric c = MATCHCLASS; 2904060Seric state = GETONE; 2914060Seric break; 2924060Seric 2933149Seric case '#': /* canonical net name */ 2943149Seric c = CANONNET; 2953149Seric break; 2963149Seric 2973149Seric case '@': /* canonical host name */ 2983149Seric c = CANONHOST; 2993149Seric break; 3003149Seric 3013149Seric case ':': /* canonical user name */ 3023149Seric c = CANONUSER; 3033149Seric break; 3043149Seric 3053149Seric default: 3063149Seric c = '$'; 3073149Seric state = OPER; 3083149Seric p--; 3093149Seric break; 3103149Seric } 3113149Seric break; 3123149Seric 3133149Seric default: 3143149Seric syserr("prescan: unknown state %d", state); 3153149Seric } 3163149Seric 3173149Seric if (state == OPER) 3183149Seric space = FALSE; 3193149Seric else if (state == EOTOK) 3203149Seric break; 3213149Seric if (c == '$' && delim == '\t') 3223149Seric { 3233149Seric state = DOLLAR; 3243149Seric continue; 3253149Seric } 3263149Seric 3273149Seric /* squirrel it away */ 3283149Seric if (q >= &buf[sizeof buf - 5]) 3293149Seric { 3303149Seric usrerr("Address too long"); 3313149Seric return (NULL); 3323149Seric } 3333149Seric if (space) 3343149Seric *q++ = SPACESUB; 3353149Seric *q++ = c; 3363149Seric 3373149Seric /* decide whether this represents end of token */ 3383149Seric if (state == OPER) 3393149Seric break; 340297Seric } 3413149Seric if (c == '\0' || c == delim) 3423149Seric p--; 3433149Seric 3443149Seric /* new token */ 3453149Seric if (tok == q) 346297Seric continue; 3473149Seric *q++ = '\0'; 3483149Seric 3493149Seric c = tok[0]; 3503149Seric if (c == '(') 3511378Seric { 352297Seric cmntcnt++; 3531378Seric continue; 3541378Seric } 355297Seric else if (c == ')') 356297Seric { 357297Seric if (cmntcnt <= 0) 358297Seric { 359297Seric usrerr("Unbalanced ')'"); 360297Seric return (NULL); 361297Seric } 362297Seric else 363297Seric { 364297Seric cmntcnt--; 365297Seric continue; 366297Seric } 367297Seric } 3683149Seric else if (cmntcnt > 0) 3692091Seric continue; 3703149Seric 3713149Seric *avp++ = tok; 3723149Seric 3733149Seric /* we prefer <> specs */ 3743149Seric if (c == '<') 375297Seric { 3762092Seric if (brccnt < 0) 3772092Seric { 3782092Seric usrerr("multiple < spec"); 3792092Seric return (NULL); 3802092Seric } 381297Seric brccnt++; 3822091Seric space = FALSE; 383297Seric if (brccnt == 1) 384297Seric { 385297Seric /* we prefer using machine readable name */ 386297Seric q = buf; 387297Seric *q = '\0'; 3883149Seric avp = av; 389297Seric continue; 390297Seric } 391297Seric } 392297Seric else if (c == '>') 393297Seric { 394297Seric if (brccnt <= 0) 395297Seric { 396297Seric usrerr("Unbalanced `>'"); 397297Seric return (NULL); 398297Seric } 399297Seric else 400297Seric brccnt--; 401297Seric if (brccnt <= 0) 4022092Seric { 4032092Seric brccnt = -1; 404297Seric continue; 4052092Seric } 406297Seric } 407297Seric 408297Seric /* 409297Seric ** Turn "at" into "@", 4101378Seric ** but only if "at" is a word. 411297Seric */ 412297Seric 4133149Seric if (lower(tok[0]) == 'a' && lower(tok[1]) == 't' && tok[2] == '\0') 414297Seric { 4153149Seric tok[0] = '@'; 4163149Seric tok[1] = '\0'; 417297Seric } 4183149Seric } 4193149Seric *avp = NULL; 4203149Seric if (cmntcnt > 0) 4213149Seric usrerr("Unbalanced '('"); 4223149Seric else if (brccnt > 0) 4233149Seric usrerr("Unbalanced '<'"); 4243149Seric else if (state == QSTRING) 4253149Seric usrerr("Unbalanced '\"'"); 4263149Seric else if (av[0] != NULL) 4273149Seric return (av); 4283149Seric return (NULL); 4293149Seric } 4303149Seric /* 4313149Seric ** TOKTYPE -- return token type 4323149Seric ** 4333149Seric ** Parameters: 4343149Seric ** c -- the character in question. 4353149Seric ** 4363149Seric ** Returns: 4373149Seric ** Its type. 4383149Seric ** 4393149Seric ** Side Effects: 4403149Seric ** none. 4413149Seric */ 442297Seric 4433149Seric toktype(c) 4443149Seric register char c; 4453149Seric { 4463380Seric static char buf[50]; 4473382Seric static bool firstime = TRUE; 4483380Seric 4493382Seric if (firstime) 4503380Seric { 4513382Seric firstime = FALSE; 4524085Seric (void) expand("$o", buf, &buf[sizeof buf - 1]); 4533380Seric strcat(buf, DELIMCHARS); 4543380Seric } 4554100Seric if (!isascii(c)) 4564100Seric return (ATOM); 4573149Seric if (isspace(c)) 4583149Seric return (SPACE); 4593380Seric if (iscntrl(c) || index(buf, c) != NULL) 4603149Seric return (OPER); 4613149Seric return (ATOM); 4623149Seric } 4633149Seric /* 4643149Seric ** REWRITE -- apply rewrite rules to token vector. 4653149Seric ** 4663149Seric ** Parameters: 4673149Seric ** pvp -- pointer to token vector. 4683149Seric ** 4693149Seric ** Returns: 4703149Seric ** none. 4713149Seric ** 4723149Seric ** Side Effects: 4733149Seric ** pvp is modified. 4743149Seric */ 4752091Seric 4763149Seric struct match 4773149Seric { 4783149Seric char **firsttok; /* first token matched */ 4793149Seric char **lasttok; /* last token matched */ 4803149Seric char name; /* name of parameter */ 4813149Seric }; 4823149Seric 4833149Seric # define MAXMATCH 8 /* max params per rewrite */ 4843149Seric 4853149Seric 4864070Seric rewrite(pvp, ruleset) 4873149Seric char **pvp; 4884070Seric int ruleset; 4893149Seric { 4903149Seric register char *ap; /* address pointer */ 4913149Seric register char *rp; /* rewrite pointer */ 4923149Seric register char **avp; /* address vector pointer */ 4933149Seric register char **rvp; /* rewrite vector pointer */ 4943149Seric struct rewrite *rwr; 4953149Seric struct match mlist[MAXMATCH]; 4963149Seric char *npvp[MAXATOM+1]; /* temporary space for rebuild */ 4974060Seric extern bool sameword(); 4983149Seric 4994100Seric # ifdef DEBUG 5004100Seric if (Debug > 10) 5013149Seric { 5023149Seric printf("rewrite: original pvp:\n"); 5033149Seric printav(pvp); 5043149Seric } 5054100Seric # endif DEBUG 5063149Seric 5073149Seric /* 5083149Seric ** Run through the list of rewrite rules, applying 5093149Seric ** any that match. 5103149Seric */ 5113149Seric 5124070Seric for (rwr = RewriteRules[ruleset]; rwr != NULL; ) 5133149Seric { 5144100Seric # ifdef DEBUG 5154100Seric if (Debug > 10) 516297Seric { 5173149Seric printf("-----trying rule:\n"); 5183149Seric printav(rwr->r_lhs); 5193149Seric } 5204100Seric # endif DEBUG 5213149Seric 5223149Seric /* try to match on this rule */ 5233149Seric clrmatch(mlist); 5243149Seric for (rvp = rwr->r_lhs, avp = pvp; *avp != NULL; ) 5253149Seric { 5263149Seric ap = *avp; 5273149Seric rp = *rvp; 5283149Seric 5293149Seric if (rp == NULL) 530297Seric { 5313149Seric /* end-of-pattern before end-of-address */ 5323149Seric goto fail; 533297Seric } 5343149Seric 5353149Seric switch (*rp) 5363149Seric { 5374060Seric register STAB *s; 5384060Seric register int class; 5394060Seric 5403149Seric case MATCHONE: 5413149Seric /* match exactly one token */ 5423149Seric setmatch(mlist, rp[1], avp, avp); 5433149Seric break; 5443149Seric 5453149Seric case MATCHANY: 5463149Seric /* match any number of tokens */ 5474085Seric setmatch(mlist, rp[1], (char **) NULL, avp); 5483149Seric break; 5493149Seric 5504060Seric case MATCHCLASS: 5514060Seric /* match any token in a class */ 5524060Seric class = rp[1]; 5534060Seric if (!isalpha(class)) 5544060Seric goto fail; 5554060Seric if (isupper(class)) 5564060Seric class -= 'A'; 5574060Seric else 5584060Seric class -= 'a'; 5594100Seric s = stab(ap, ST_CLASS, ST_FIND); 5604060Seric if (s == NULL || (s->s_class & (1 << class)) == 0) 5614060Seric goto fail; 5624060Seric break; 5634060Seric 5643149Seric default: 5653149Seric /* must have exact match */ 5664060Seric if (!sameword(rp, ap)) 5674060Seric goto fail; 5683149Seric break; 5693149Seric } 5703149Seric 5713149Seric /* successful match on this token */ 5723149Seric avp++; 5733149Seric rvp++; 5743149Seric continue; 5753149Seric 5763149Seric fail: 5773149Seric /* match failed -- back up */ 5783149Seric while (--rvp >= rwr->r_lhs) 5793149Seric { 5803149Seric rp = *rvp; 5813149Seric if (*rp == MATCHANY) 5823149Seric break; 5833149Seric 5843149Seric /* can't extend match: back up everything */ 5853149Seric avp--; 5863149Seric 5873149Seric if (*rp == MATCHONE) 5883149Seric { 5893149Seric /* undo binding */ 5904085Seric setmatch(mlist, rp[1], (char **) NULL, (char **) NULL); 5913149Seric } 5923149Seric } 5933149Seric 5943149Seric if (rvp < rwr->r_lhs) 5953149Seric { 5963149Seric /* total failure to match */ 5973149Seric break; 5983149Seric } 599297Seric } 6003149Seric 6013149Seric /* 6023149Seric ** See if we successfully matched 6033149Seric */ 6043149Seric 6053149Seric if (rvp >= rwr->r_lhs && *rvp == NULL) 6063149Seric { 6074100Seric # ifdef DEBUG 6084100Seric if (Debug > 10) 6093149Seric { 6103149Seric printf("-----rule matches:\n"); 6113149Seric printav(rwr->r_rhs); 6123149Seric } 6134100Seric # endif DEBUG 6143149Seric 6153149Seric /* substitute */ 6163149Seric for (rvp = rwr->r_rhs, avp = npvp; *rvp != NULL; rvp++) 6173149Seric { 6183149Seric rp = *rvp; 6193149Seric if (*rp == MATCHANY) 6203149Seric { 6213149Seric register struct match *m; 6223149Seric register char **pp; 6233149Seric extern struct match *findmatch(); 6243149Seric 6253149Seric m = findmatch(mlist, rp[1]); 6263149Seric if (m != NULL) 6273149Seric { 6283149Seric pp = m->firsttok; 6293149Seric do 6303149Seric { 6313149Seric *avp++ = *pp; 6323149Seric } while (pp++ != m->lasttok); 6333149Seric } 6343149Seric } 6353149Seric else 6363149Seric *avp++ = rp; 6373149Seric } 6383149Seric *avp++ = NULL; 6394085Seric bmove((char *) npvp, (char *) pvp, (avp - npvp) * sizeof *avp); 6403149Seric # ifdef DEBUG 6413149Seric if (Debug) 6423149Seric { 6433188Seric char **vp; 6443188Seric 6453188Seric printf("rewritten as `"); 6463188Seric for (vp = pvp; *vp != NULL; vp++) 6473188Seric xputs(*vp); 6483188Seric printf("'\n"); 6493149Seric } 6503149Seric # endif DEBUG 6513149Seric if (pvp[0][0] == CANONNET) 6523149Seric break; 6533149Seric } 6543149Seric else 6553149Seric { 6564100Seric # ifdef DEBUG 6574100Seric if (Debug > 10) 6583149Seric printf("----- rule fails\n"); 6594100Seric # endif DEBUG 6603149Seric rwr = rwr->r_next; 6613149Seric } 662297Seric } 6633149Seric } 6643149Seric /* 6653149Seric ** SETMATCH -- set parameter value in match vector 6663149Seric ** 6673149Seric ** Parameters: 6683149Seric ** mlist -- list of match values. 6693149Seric ** name -- the character name of this parameter. 6703149Seric ** first -- the first location of the replacement. 6713149Seric ** last -- the last location of the replacement. 6723149Seric ** 6733149Seric ** If last == NULL, delete this entry. 6743149Seric ** If first == NULL, extend this entry (or add it if 6753149Seric ** it does not exist). 6763149Seric ** 6773149Seric ** Returns: 6783149Seric ** nothing. 6793149Seric ** 6803149Seric ** Side Effects: 6813149Seric ** munges with mlist. 6823149Seric */ 6833149Seric 6843149Seric setmatch(mlist, name, first, last) 6853149Seric struct match *mlist; 6863149Seric char name; 6873149Seric char **first; 6883149Seric char **last; 6893149Seric { 6903149Seric register struct match *m; 6913149Seric struct match *nullm = NULL; 6923149Seric 6933149Seric for (m = mlist; m < &mlist[MAXMATCH]; m++) 6943149Seric { 6953149Seric if (m->name == name) 6963149Seric break; 6973149Seric if (m->name == '\0') 6983149Seric nullm = m; 6993149Seric } 7003149Seric 7013149Seric if (m >= &mlist[MAXMATCH]) 7023149Seric m = nullm; 7033149Seric 7043149Seric if (last == NULL) 7053149Seric { 7063149Seric m->name = '\0'; 7073149Seric return; 7083149Seric } 7093149Seric 7103149Seric if (m->name == '\0') 7113149Seric { 7123149Seric if (first == NULL) 7133149Seric m->firsttok = last; 7143149Seric else 7153149Seric m->firsttok = first; 7163149Seric } 7173149Seric m->name = name; 7183149Seric m->lasttok = last; 7193149Seric } 7203149Seric /* 7213149Seric ** FINDMATCH -- find match in mlist 7223149Seric ** 7233149Seric ** Parameters: 7243149Seric ** mlist -- list to search. 7253149Seric ** name -- name to find. 7263149Seric ** 7273149Seric ** Returns: 7283149Seric ** pointer to match structure. 7293149Seric ** NULL if no match. 7303149Seric ** 7313149Seric ** Side Effects: 7323149Seric ** none. 7333149Seric */ 7343149Seric 7353149Seric struct match * 7363149Seric findmatch(mlist, name) 7373149Seric struct match *mlist; 7383149Seric char name; 7393149Seric { 7403149Seric register struct match *m; 7413149Seric 7423149Seric for (m = mlist; m < &mlist[MAXMATCH]; m++) 7433149Seric { 7443149Seric if (m->name == name) 7453149Seric return (m); 7463149Seric } 7473149Seric 748297Seric return (NULL); 749297Seric } 7503149Seric /* 7513149Seric ** CLRMATCH -- clear match list 7523149Seric ** 7533149Seric ** Parameters: 7543149Seric ** mlist -- list to clear. 7553149Seric ** 7563149Seric ** Returns: 7573149Seric ** none. 7583149Seric ** 7593149Seric ** Side Effects: 7603149Seric ** mlist is cleared. 7613149Seric */ 7623149Seric 7633149Seric clrmatch(mlist) 7643149Seric struct match *mlist; 7653149Seric { 7663149Seric register struct match *m; 7673149Seric 7683149Seric for (m = mlist; m < &mlist[MAXMATCH]; m++) 7693149Seric m->name = '\0'; 7703149Seric } 7713149Seric /* 7723149Seric ** BUILDADDR -- build address from token vector. 7733149Seric ** 7743149Seric ** Parameters: 7753149Seric ** tv -- token vector. 7763149Seric ** a -- pointer to address descriptor to fill. 7773149Seric ** If NULL, one will be allocated. 7783149Seric ** 7793149Seric ** Returns: 7803149Seric ** 'a' 7813149Seric ** 7823149Seric ** Side Effects: 7833149Seric ** fills in 'a' 7843149Seric */ 7853149Seric 7863149Seric ADDRESS * 7873149Seric buildaddr(tv, a) 7883149Seric register char **tv; 7893149Seric register ADDRESS *a; 7903149Seric { 7913149Seric register int i; 7923149Seric static char buf[MAXNAME]; 7933149Seric struct mailer **mp; 7943149Seric register struct mailer *m; 7953149Seric 7963149Seric if (a == NULL) 7973149Seric a = (ADDRESS *) xalloc(sizeof *a); 7983188Seric a->q_flags = 0; 7994079Seric a->q_home = NULL; 8003149Seric 8013149Seric /* figure out what net/mailer to use */ 8023149Seric if (**tv != CANONNET) 8033149Seric syserr("buildaddr: no net"); 8043149Seric tv++; 8053154Seric for (mp = Mailer, i = 0; (m = *mp++) != NULL; i++) 8063149Seric { 8073149Seric if (strcmp(m->m_name, *tv) == 0) 8083149Seric break; 8093149Seric } 8103149Seric if (m == NULL) 8113149Seric syserr("buildaddr: unknown net %s", *tv); 8123149Seric a->q_mailer = i; 8133149Seric 8143149Seric /* figure out what host (if any) */ 8153149Seric tv++; 816*4195Seric if (!bitset(M_LOCAL, m->m_flags)) 8173149Seric { 8183149Seric if (**tv != CANONHOST) 8193149Seric syserr("buildaddr: no host"); 8203149Seric tv++; 8213149Seric a->q_host = *tv; 8223149Seric tv++; 8233149Seric } 8243149Seric else 8253149Seric a->q_host = NULL; 8263149Seric 8273149Seric /* figure out the user */ 8283149Seric if (**tv != CANONUSER) 8293149Seric syserr("buildaddr: no user"); 8303149Seric buf[0] = '\0'; 8313149Seric while (**++tv != NULL) 8324085Seric (void) strcat(buf, *tv); 8333149Seric a->q_user = buf; 8343149Seric 8353149Seric return (a); 8363149Seric } 8373188Seric /* 8383188Seric ** SAMEADDR -- Determine if two addresses are the same 8393188Seric ** 8403188Seric ** This is not just a straight comparison -- if the mailer doesn't 8413188Seric ** care about the host we just ignore it, etc. 8423188Seric ** 8433188Seric ** Parameters: 8443188Seric ** a, b -- pointers to the internal forms to compare. 8453188Seric ** wildflg -- if TRUE, 'a' may have no user specified, 8463188Seric ** in which case it is to match anything. 8473188Seric ** 8483188Seric ** Returns: 8493188Seric ** TRUE -- they represent the same mailbox. 8503188Seric ** FALSE -- they don't. 8513188Seric ** 8523188Seric ** Side Effects: 8533188Seric ** none. 8543188Seric */ 8553188Seric 8563188Seric bool 8573188Seric sameaddr(a, b, wildflg) 8583188Seric register ADDRESS *a; 8593188Seric register ADDRESS *b; 8603188Seric bool wildflg; 8613188Seric { 8623188Seric /* if they don't have the same mailer, forget it */ 8633188Seric if (a->q_mailer != b->q_mailer) 8643188Seric return (FALSE); 8653188Seric 8663188Seric /* if the user isn't the same, we can drop out */ 8673188Seric if ((!wildflg || a->q_user[0] != '\0') && strcmp(a->q_user, b->q_user) != 0) 8683188Seric return (FALSE); 8693188Seric 8703188Seric /* if the mailer ignores hosts, we have succeeded! */ 871*4195Seric if (bitset(M_LOCAL, Mailer[a->q_mailer]->m_flags)) 8723188Seric return (TRUE); 8733188Seric 8743188Seric /* otherwise compare hosts (but be careful for NULL ptrs) */ 8753188Seric if (a->q_host == NULL || b->q_host == NULL) 8763188Seric return (FALSE); 8773188Seric if (strcmp(a->q_host, b->q_host) != 0) 8783188Seric return (FALSE); 8793188Seric 8803188Seric return (TRUE); 8813188Seric } 8823234Seric /* 8833234Seric ** PRINTADDR -- print address (for debugging) 8843234Seric ** 8853234Seric ** Parameters: 8863234Seric ** a -- the address to print 8873234Seric ** follow -- follow the q_next chain. 8883234Seric ** 8893234Seric ** Returns: 8903234Seric ** none. 8913234Seric ** 8923234Seric ** Side Effects: 8933234Seric ** none. 8943234Seric */ 8953234Seric 8963234Seric printaddr(a, follow) 8973234Seric register ADDRESS *a; 8983234Seric bool follow; 8993234Seric { 9003234Seric while (a != NULL) 9013234Seric { 9023234Seric printf("addr@%x: ", a); 9034085Seric (void) fflush(stdout); 9043234Seric printf("%s: mailer %d (%s), host `%s', user `%s'\n", a->q_paddr, 9053234Seric a->q_mailer, Mailer[a->q_mailer]->m_name, a->q_host, a->q_user); 9063234Seric printf("\tnext=%x flags=%o, rmailer %d\n", a->q_next, 9073234Seric a->q_flags, a->q_rmailer); 9083234Seric 9093234Seric if (!follow) 9103234Seric return; 9113234Seric a = a->q_next; 9123234Seric } 9133234Seric } 914