1297Seric # include <stdio.h> 2297Seric # include <ctype.h> 33312Seric # include "sendmail.h" 4297Seric 5*4100Seric static char SccsId[] = "@(#)parseaddr.c 3.17 08/10/81"; 6407Seric 7297Seric /* 8297Seric ** PARSE -- Parse an address 9297Seric ** 10297Seric ** Parses an address and breaks it up into three parts: a 11297Seric ** net to transmit the message on, the host to transmit it 12297Seric ** to, and a user on that host. These are loaded into an 132973Seric ** ADDRESS header with the values squirreled away if necessary. 14297Seric ** The "user" part may not be a real user; the process may 15297Seric ** just reoccur on that machine. For example, on a machine 16297Seric ** with an arpanet connection, the address 17297Seric ** csvax.bill@berkeley 18297Seric ** will break up to a "user" of 'csvax.bill' and a host 19297Seric ** of 'berkeley' -- to be transmitted over the arpanet. 20297Seric ** 21297Seric ** Parameters: 22297Seric ** addr -- the address to parse. 23297Seric ** a -- a pointer to the address descriptor buffer. 24297Seric ** If NULL, a header will be created. 25297Seric ** copyf -- determines what shall be copied: 26297Seric ** -1 -- don't copy anything. The printname 27297Seric ** (q_paddr) is just addr, and the 28297Seric ** user & host are allocated internally 29297Seric ** to parse. 30297Seric ** 0 -- copy out the parsed user & host, but 31297Seric ** don't copy the printname. 32297Seric ** +1 -- copy everything. 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 ** Called By: 43297Seric ** main 44297Seric ** sendto 45297Seric ** alias 46297Seric ** savemail 47297Seric */ 48297Seric 493380Seric # define DELIMCHARS "$()<>,;\\\"\r\n" /* word delimiters */ 502091Seric # define SPACESUB ('.'|0200) /* substitution for <lwsp> */ 512091Seric 522973Seric ADDRESS * 53297Seric parse(addr, a, copyf) 54297Seric char *addr; 552973Seric register ADDRESS *a; 56297Seric int copyf; 57297Seric { 583149Seric register char **pvp; 593149Seric register struct mailer *m; 603149Seric extern char **prescan(); 613149Seric extern ADDRESS *buildaddr(); 62297Seric 63297Seric /* 64297Seric ** Initialize and prescan address. 65297Seric */ 66297Seric 67297Seric To = addr; 683188Seric # ifdef DEBUG 693188Seric if (Debug) 703188Seric printf("\n--parse(%s)\n", addr); 713188Seric # endif DEBUG 723188Seric 733149Seric pvp = prescan(addr, '\0'); 743149Seric if (pvp == NULL) 75297Seric return (NULL); 76297Seric 77297Seric /* 783149Seric ** Apply rewriting rules. 79297Seric */ 80297Seric 814070Seric rewrite(pvp, 0); 82297Seric 833149Seric /* 843149Seric ** See if we resolved to a real mailer. 853149Seric */ 86297Seric 873149Seric if (pvp[0][0] != CANONNET) 883149Seric { 893149Seric setstat(EX_USAGE); 903149Seric usrerr("cannot resolve name"); 913149Seric return (NULL); 92297Seric } 93297Seric 94297Seric /* 953149Seric ** Build canonical address from pvp. 96297Seric */ 97297Seric 983149Seric a = buildaddr(pvp, a); 993149Seric m = Mailer[a->q_mailer]; 100297Seric 101297Seric /* 1023149Seric ** Make local copies of the host & user and then 1033149Seric ** transport them out. 104297Seric */ 105297Seric 106297Seric if (copyf > 0) 1072973Seric a->q_paddr = newstr(addr); 108297Seric else 109297Seric a->q_paddr = addr; 110297Seric 1113149Seric if (copyf >= 0) 112297Seric { 1133149Seric if (a->q_host != NULL) 1143149Seric a->q_host = newstr(a->q_host); 115297Seric else 1163149Seric a->q_host = ""; 1173149Seric if (a->q_user != a->q_paddr) 1183149Seric a->q_user = newstr(a->q_user); 119297Seric } 120297Seric 121297Seric /* 122297Seric ** Do UPPER->lower case mapping unless inhibited. 123297Seric */ 124297Seric 1253149Seric if (!bitset(M_HST_UPPER, m->m_flags)) 126297Seric makelower(a->q_host); 1273149Seric if (!bitset(M_USR_UPPER, m->m_flags)) 128297Seric makelower(a->q_user); 129297Seric 130297Seric /* 131297Seric ** Compute return value. 132297Seric */ 133297Seric 134297Seric # ifdef DEBUG 1351583Seric if (Debug) 136297Seric printf("parse(\"%s\"): host \"%s\" user \"%s\" mailer %d\n", 1373149Seric addr, a->q_host, a->q_user, a->q_mailer); 138297Seric # endif DEBUG 139297Seric 140297Seric return (a); 141297Seric } 142297Seric /* 143297Seric ** PRESCAN -- Prescan name and make it canonical 144297Seric ** 145297Seric ** Scans a name and turns it into canonical form. This involves 146297Seric ** deleting blanks, comments (in parentheses), and turning the 147297Seric ** word "at" into an at-sign ("@"). The name is copied as this 148297Seric ** is done; it is legal to copy a name onto itself, since this 149297Seric ** process can only make things smaller. 150297Seric ** 151297Seric ** This routine knows about quoted strings and angle brackets. 152297Seric ** 153297Seric ** There are certain subtleties to this routine. The one that 154297Seric ** comes to mind now is that backslashes on the ends of names 155297Seric ** are silently stripped off; this is intentional. The problem 156297Seric ** is that some versions of sndmsg (like at LBL) set the kill 157297Seric ** character to something other than @ when reading addresses; 158297Seric ** so people type "csvax.eric\@berkeley" -- which screws up the 159297Seric ** berknet mailer. 160297Seric ** 161297Seric ** Parameters: 162297Seric ** addr -- the name to chomp. 163297Seric ** delim -- the delimiter for the address, normally 164297Seric ** '\0' or ','; \0 is accepted in any case. 165297Seric ** are moving in place; set buflim to high core. 166297Seric ** 167297Seric ** Returns: 1683149Seric ** A pointer to a vector of tokens. 169297Seric ** NULL on error. 170297Seric ** 171297Seric ** Side Effects: 1723149Seric ** none. 173297Seric */ 174297Seric 1753149Seric # define OPER 1 1763149Seric # define ATOM 2 1773149Seric # define EOTOK 3 1783149Seric # define QSTRING 4 1793149Seric # define SPACE 5 1803149Seric # define DOLLAR 6 1813149Seric # define GETONE 7 1823149Seric 1833149Seric char ** 1843149Seric prescan(addr, delim) 185297Seric char *addr; 186297Seric char delim; 187297Seric { 188297Seric register char *p; 1893149Seric static char buf[MAXNAME+MAXATOM]; 1903149Seric static char *av[MAXATOM+1]; 1913149Seric char **avp; 192297Seric bool space; 193297Seric bool bslashmode; 194297Seric int cmntcnt; 195297Seric int brccnt; 196297Seric register char c; 1973149Seric char *tok; 198297Seric register char *q; 1993149Seric register int state; 2003149Seric int nstate; 2014085Seric extern char lower(); 202297Seric 2032091Seric space = FALSE; 204297Seric q = buf; 2053149Seric bslashmode = FALSE; 206297Seric cmntcnt = brccnt = 0; 2073149Seric avp = av; 2083149Seric state = OPER; 2093149Seric for (p = addr; *p != '\0' && *p != delim; ) 210297Seric { 2113149Seric /* read a token */ 2123149Seric tok = q; 2133149Seric while ((c = *p++) != '\0' && c != delim) 214297Seric { 2153149Seric /* chew up special characters */ 216*4100Seric c &= ~0200; 2173149Seric *q = '\0'; 2183149Seric if (bslashmode) 2193149Seric { 2203149Seric c |= 0200; 2213149Seric bslashmode = FALSE; 2223149Seric } 2233149Seric else if (c == '\\') 2243149Seric { 2253149Seric bslashmode = TRUE; 2263149Seric continue; 2273149Seric } 228*4100Seric else if (c == '"') 229*4100Seric { 230*4100Seric if (state == QSTRING) 231*4100Seric state = OPER; 232*4100Seric else 233*4100Seric state = QSTRING; 234*4100Seric break; 235*4100Seric } 2363149Seric 2373149Seric nstate = toktype(c); 2383149Seric switch (state) 2393149Seric { 2403149Seric case QSTRING: /* in quoted string */ 2413149Seric break; 2423149Seric 2433149Seric case ATOM: /* regular atom */ 2443149Seric state = nstate; 2453149Seric if (state != ATOM) 2463149Seric { 2473149Seric state = EOTOK; 2483149Seric p--; 2493149Seric } 2503149Seric break; 2513149Seric 2523149Seric case GETONE: /* grab one character */ 2533149Seric state = OPER; 2543149Seric break; 2553149Seric 2563149Seric case EOTOK: /* after atom or q-string */ 2573149Seric state = nstate; 2583149Seric if (state == SPACE) 2593149Seric continue; 2603149Seric break; 2613149Seric 2623149Seric case SPACE: /* linear white space */ 2633149Seric state = nstate; 2643149Seric space = TRUE; 2653149Seric continue; 2663149Seric 2673149Seric case OPER: /* operator */ 2683149Seric if (nstate == SPACE) 2693149Seric continue; 2703149Seric state = nstate; 2713149Seric break; 2723149Seric 2733149Seric case DOLLAR: /* $- etc. */ 2743149Seric state = OPER; 2753149Seric switch (c) 2763149Seric { 2773149Seric case '$': /* literal $ */ 2783149Seric break; 2793149Seric 2803149Seric case '+': /* match anything */ 2813149Seric c = MATCHANY; 2823149Seric state = GETONE; 2833149Seric break; 2843149Seric 2853149Seric case '-': /* match one token */ 2863149Seric c = MATCHONE; 2873149Seric state = GETONE; 2883149Seric break; 2893149Seric 2904060Seric case '=': /* match one token of class */ 2914060Seric c = MATCHCLASS; 2924060Seric state = GETONE; 2934060Seric break; 2944060Seric 2953149Seric case '#': /* canonical net name */ 2963149Seric c = CANONNET; 2973149Seric break; 2983149Seric 2993149Seric case '@': /* canonical host name */ 3003149Seric c = CANONHOST; 3013149Seric break; 3023149Seric 3033149Seric case ':': /* canonical user name */ 3043149Seric c = CANONUSER; 3053149Seric break; 3063149Seric 3073149Seric default: 3083149Seric c = '$'; 3093149Seric state = OPER; 3103149Seric p--; 3113149Seric break; 3123149Seric } 3133149Seric break; 3143149Seric 3153149Seric default: 3163149Seric syserr("prescan: unknown state %d", state); 3173149Seric } 3183149Seric 3193149Seric if (state == OPER) 3203149Seric space = FALSE; 3213149Seric else if (state == EOTOK) 3223149Seric break; 3233149Seric if (c == '$' && delim == '\t') 3243149Seric { 3253149Seric state = DOLLAR; 3263149Seric continue; 3273149Seric } 3283149Seric 3293149Seric /* squirrel it away */ 3303149Seric if (q >= &buf[sizeof buf - 5]) 3313149Seric { 3323149Seric usrerr("Address too long"); 3333149Seric return (NULL); 3343149Seric } 3353149Seric if (space) 3363149Seric *q++ = SPACESUB; 3373149Seric *q++ = c; 3383149Seric 3393149Seric /* decide whether this represents end of token */ 3403149Seric if (state == OPER) 3413149Seric break; 342297Seric } 3433149Seric if (c == '\0' || c == delim) 3443149Seric p--; 3453149Seric 3463149Seric /* new token */ 3473149Seric if (tok == q) 348297Seric continue; 3493149Seric *q++ = '\0'; 3503149Seric 3513149Seric c = tok[0]; 3523149Seric if (c == '(') 3531378Seric { 354297Seric cmntcnt++; 3551378Seric continue; 3561378Seric } 357297Seric else if (c == ')') 358297Seric { 359297Seric if (cmntcnt <= 0) 360297Seric { 361297Seric usrerr("Unbalanced ')'"); 362297Seric return (NULL); 363297Seric } 364297Seric else 365297Seric { 366297Seric cmntcnt--; 367297Seric continue; 368297Seric } 369297Seric } 3703149Seric else if (cmntcnt > 0) 3712091Seric continue; 3723149Seric 3733149Seric *avp++ = tok; 3743149Seric 3753149Seric /* we prefer <> specs */ 3763149Seric if (c == '<') 377297Seric { 3782092Seric if (brccnt < 0) 3792092Seric { 3802092Seric usrerr("multiple < spec"); 3812092Seric return (NULL); 3822092Seric } 383297Seric brccnt++; 3842091Seric space = FALSE; 385297Seric if (brccnt == 1) 386297Seric { 387297Seric /* we prefer using machine readable name */ 388297Seric q = buf; 389297Seric *q = '\0'; 3903149Seric avp = av; 391297Seric continue; 392297Seric } 393297Seric } 394297Seric else if (c == '>') 395297Seric { 396297Seric if (brccnt <= 0) 397297Seric { 398297Seric usrerr("Unbalanced `>'"); 399297Seric return (NULL); 400297Seric } 401297Seric else 402297Seric brccnt--; 403297Seric if (brccnt <= 0) 4042092Seric { 4052092Seric brccnt = -1; 406297Seric continue; 4072092Seric } 408297Seric } 409297Seric 410297Seric /* 411297Seric ** Turn "at" into "@", 4121378Seric ** but only if "at" is a word. 413297Seric */ 414297Seric 4153149Seric if (lower(tok[0]) == 'a' && lower(tok[1]) == 't' && tok[2] == '\0') 416297Seric { 4173149Seric tok[0] = '@'; 4183149Seric tok[1] = '\0'; 419297Seric } 4203149Seric } 4213149Seric *avp = NULL; 4223149Seric if (cmntcnt > 0) 4233149Seric usrerr("Unbalanced '('"); 4243149Seric else if (brccnt > 0) 4253149Seric usrerr("Unbalanced '<'"); 4263149Seric else if (state == QSTRING) 4273149Seric usrerr("Unbalanced '\"'"); 4283149Seric else if (av[0] != NULL) 4293149Seric return (av); 4303149Seric return (NULL); 4313149Seric } 4323149Seric /* 4333149Seric ** TOKTYPE -- return token type 4343149Seric ** 4353149Seric ** Parameters: 4363149Seric ** c -- the character in question. 4373149Seric ** 4383149Seric ** Returns: 4393149Seric ** Its type. 4403149Seric ** 4413149Seric ** Side Effects: 4423149Seric ** none. 4433149Seric */ 444297Seric 4453149Seric toktype(c) 4463149Seric register char c; 4473149Seric { 4483380Seric static char buf[50]; 4493382Seric static bool firstime = TRUE; 4503380Seric 4513382Seric if (firstime) 4523380Seric { 4533382Seric firstime = FALSE; 4544085Seric (void) expand("$o", buf, &buf[sizeof buf - 1]); 4553380Seric strcat(buf, DELIMCHARS); 4563380Seric } 457*4100Seric if (!isascii(c)) 458*4100Seric return (ATOM); 4593149Seric if (isspace(c)) 4603149Seric return (SPACE); 4613380Seric if (iscntrl(c) || index(buf, c) != NULL) 4623149Seric return (OPER); 4633149Seric return (ATOM); 4643149Seric } 4653149Seric /* 4663149Seric ** REWRITE -- apply rewrite rules to token vector. 4673149Seric ** 4683149Seric ** Parameters: 4693149Seric ** pvp -- pointer to token vector. 4703149Seric ** 4713149Seric ** Returns: 4723149Seric ** none. 4733149Seric ** 4743149Seric ** Side Effects: 4753149Seric ** pvp is modified. 4763149Seric */ 4772091Seric 4783149Seric struct match 4793149Seric { 4803149Seric char **firsttok; /* first token matched */ 4813149Seric char **lasttok; /* last token matched */ 4823149Seric char name; /* name of parameter */ 4833149Seric }; 4843149Seric 4853149Seric # define MAXMATCH 8 /* max params per rewrite */ 4863149Seric 4873149Seric 4884070Seric rewrite(pvp, ruleset) 4893149Seric char **pvp; 4904070Seric int ruleset; 4913149Seric { 4923149Seric register char *ap; /* address pointer */ 4933149Seric register char *rp; /* rewrite pointer */ 4943149Seric register char **avp; /* address vector pointer */ 4953149Seric register char **rvp; /* rewrite vector pointer */ 4963149Seric struct rewrite *rwr; 4973149Seric struct match mlist[MAXMATCH]; 4983149Seric char *npvp[MAXATOM+1]; /* temporary space for rebuild */ 4994060Seric extern bool sameword(); 5003149Seric 501*4100Seric # ifdef DEBUG 502*4100Seric if (Debug > 10) 5033149Seric { 5043149Seric printf("rewrite: original pvp:\n"); 5053149Seric printav(pvp); 5063149Seric } 507*4100Seric # endif DEBUG 5083149Seric 5093149Seric /* 5103149Seric ** Run through the list of rewrite rules, applying 5113149Seric ** any that match. 5123149Seric */ 5133149Seric 5144070Seric for (rwr = RewriteRules[ruleset]; rwr != NULL; ) 5153149Seric { 516*4100Seric # ifdef DEBUG 517*4100Seric if (Debug > 10) 518297Seric { 5193149Seric printf("-----trying rule:\n"); 5203149Seric printav(rwr->r_lhs); 5213149Seric } 522*4100Seric # endif DEBUG 5233149Seric 5243149Seric /* try to match on this rule */ 5253149Seric clrmatch(mlist); 5263149Seric for (rvp = rwr->r_lhs, avp = pvp; *avp != NULL; ) 5273149Seric { 5283149Seric ap = *avp; 5293149Seric rp = *rvp; 5303149Seric 5313149Seric if (rp == NULL) 532297Seric { 5333149Seric /* end-of-pattern before end-of-address */ 5343149Seric goto fail; 535297Seric } 5363149Seric 5373149Seric switch (*rp) 5383149Seric { 5394060Seric register STAB *s; 5404060Seric register int class; 5414060Seric 5423149Seric case MATCHONE: 5433149Seric /* match exactly one token */ 5443149Seric setmatch(mlist, rp[1], avp, avp); 5453149Seric break; 5463149Seric 5473149Seric case MATCHANY: 5483149Seric /* match any number of tokens */ 5494085Seric setmatch(mlist, rp[1], (char **) NULL, avp); 5503149Seric break; 5513149Seric 5524060Seric case MATCHCLASS: 5534060Seric /* match any token in a class */ 5544060Seric class = rp[1]; 5554060Seric if (!isalpha(class)) 5564060Seric goto fail; 5574060Seric if (isupper(class)) 5584060Seric class -= 'A'; 5594060Seric else 5604060Seric class -= 'a'; 561*4100Seric s = stab(ap, ST_CLASS, ST_FIND); 5624060Seric if (s == NULL || (s->s_class & (1 << class)) == 0) 5634060Seric goto fail; 5644060Seric break; 5654060Seric 5663149Seric default: 5673149Seric /* must have exact match */ 5684060Seric if (!sameword(rp, ap)) 5694060Seric goto fail; 5703149Seric break; 5713149Seric } 5723149Seric 5733149Seric /* successful match on this token */ 5743149Seric avp++; 5753149Seric rvp++; 5763149Seric continue; 5773149Seric 5783149Seric fail: 5793149Seric /* match failed -- back up */ 5803149Seric while (--rvp >= rwr->r_lhs) 5813149Seric { 5823149Seric rp = *rvp; 5833149Seric if (*rp == MATCHANY) 5843149Seric break; 5853149Seric 5863149Seric /* can't extend match: back up everything */ 5873149Seric avp--; 5883149Seric 5893149Seric if (*rp == MATCHONE) 5903149Seric { 5913149Seric /* undo binding */ 5924085Seric setmatch(mlist, rp[1], (char **) NULL, (char **) NULL); 5933149Seric } 5943149Seric } 5953149Seric 5963149Seric if (rvp < rwr->r_lhs) 5973149Seric { 5983149Seric /* total failure to match */ 5993149Seric break; 6003149Seric } 601297Seric } 6023149Seric 6033149Seric /* 6043149Seric ** See if we successfully matched 6053149Seric */ 6063149Seric 6073149Seric if (rvp >= rwr->r_lhs && *rvp == NULL) 6083149Seric { 609*4100Seric # ifdef DEBUG 610*4100Seric if (Debug > 10) 6113149Seric { 6123149Seric printf("-----rule matches:\n"); 6133149Seric printav(rwr->r_rhs); 6143149Seric } 615*4100Seric # endif DEBUG 6163149Seric 6173149Seric /* substitute */ 6183149Seric for (rvp = rwr->r_rhs, avp = npvp; *rvp != NULL; rvp++) 6193149Seric { 6203149Seric rp = *rvp; 6213149Seric if (*rp == MATCHANY) 6223149Seric { 6233149Seric register struct match *m; 6243149Seric register char **pp; 6253149Seric extern struct match *findmatch(); 6263149Seric 6273149Seric m = findmatch(mlist, rp[1]); 6283149Seric if (m != NULL) 6293149Seric { 6303149Seric pp = m->firsttok; 6313149Seric do 6323149Seric { 6333149Seric *avp++ = *pp; 6343149Seric } while (pp++ != m->lasttok); 6353149Seric } 6363149Seric } 6373149Seric else 6383149Seric *avp++ = rp; 6393149Seric } 6403149Seric *avp++ = NULL; 6414085Seric bmove((char *) npvp, (char *) pvp, (avp - npvp) * sizeof *avp); 6423149Seric # ifdef DEBUG 6433149Seric if (Debug) 6443149Seric { 6453188Seric char **vp; 6463188Seric 6473188Seric printf("rewritten as `"); 6483188Seric for (vp = pvp; *vp != NULL; vp++) 6493188Seric xputs(*vp); 6503188Seric printf("'\n"); 6513149Seric } 6523149Seric # endif DEBUG 6533149Seric if (pvp[0][0] == CANONNET) 6543149Seric break; 6553149Seric } 6563149Seric else 6573149Seric { 658*4100Seric # ifdef DEBUG 659*4100Seric if (Debug > 10) 6603149Seric printf("----- rule fails\n"); 661*4100Seric # endif DEBUG 6623149Seric rwr = rwr->r_next; 6633149Seric } 664297Seric } 6653149Seric } 6663149Seric /* 6673149Seric ** SETMATCH -- set parameter value in match vector 6683149Seric ** 6693149Seric ** Parameters: 6703149Seric ** mlist -- list of match values. 6713149Seric ** name -- the character name of this parameter. 6723149Seric ** first -- the first location of the replacement. 6733149Seric ** last -- the last location of the replacement. 6743149Seric ** 6753149Seric ** If last == NULL, delete this entry. 6763149Seric ** If first == NULL, extend this entry (or add it if 6773149Seric ** it does not exist). 6783149Seric ** 6793149Seric ** Returns: 6803149Seric ** nothing. 6813149Seric ** 6823149Seric ** Side Effects: 6833149Seric ** munges with mlist. 6843149Seric */ 6853149Seric 6863149Seric setmatch(mlist, name, first, last) 6873149Seric struct match *mlist; 6883149Seric char name; 6893149Seric char **first; 6903149Seric char **last; 6913149Seric { 6923149Seric register struct match *m; 6933149Seric struct match *nullm = NULL; 6943149Seric 6953149Seric for (m = mlist; m < &mlist[MAXMATCH]; m++) 6963149Seric { 6973149Seric if (m->name == name) 6983149Seric break; 6993149Seric if (m->name == '\0') 7003149Seric nullm = m; 7013149Seric } 7023149Seric 7033149Seric if (m >= &mlist[MAXMATCH]) 7043149Seric m = nullm; 7053149Seric 7063149Seric if (last == NULL) 7073149Seric { 7083149Seric m->name = '\0'; 7093149Seric return; 7103149Seric } 7113149Seric 7123149Seric if (m->name == '\0') 7133149Seric { 7143149Seric if (first == NULL) 7153149Seric m->firsttok = last; 7163149Seric else 7173149Seric m->firsttok = first; 7183149Seric } 7193149Seric m->name = name; 7203149Seric m->lasttok = last; 7213149Seric } 7223149Seric /* 7233149Seric ** FINDMATCH -- find match in mlist 7243149Seric ** 7253149Seric ** Parameters: 7263149Seric ** mlist -- list to search. 7273149Seric ** name -- name to find. 7283149Seric ** 7293149Seric ** Returns: 7303149Seric ** pointer to match structure. 7313149Seric ** NULL if no match. 7323149Seric ** 7333149Seric ** Side Effects: 7343149Seric ** none. 7353149Seric */ 7363149Seric 7373149Seric struct match * 7383149Seric findmatch(mlist, name) 7393149Seric struct match *mlist; 7403149Seric char name; 7413149Seric { 7423149Seric register struct match *m; 7433149Seric 7443149Seric for (m = mlist; m < &mlist[MAXMATCH]; m++) 7453149Seric { 7463149Seric if (m->name == name) 7473149Seric return (m); 7483149Seric } 7493149Seric 750297Seric return (NULL); 751297Seric } 7523149Seric /* 7533149Seric ** CLRMATCH -- clear match list 7543149Seric ** 7553149Seric ** Parameters: 7563149Seric ** mlist -- list to clear. 7573149Seric ** 7583149Seric ** Returns: 7593149Seric ** none. 7603149Seric ** 7613149Seric ** Side Effects: 7623149Seric ** mlist is cleared. 7633149Seric */ 7643149Seric 7653149Seric clrmatch(mlist) 7663149Seric struct match *mlist; 7673149Seric { 7683149Seric register struct match *m; 7693149Seric 7703149Seric for (m = mlist; m < &mlist[MAXMATCH]; m++) 7713149Seric m->name = '\0'; 7723149Seric } 7733149Seric /* 7743149Seric ** BUILDADDR -- build address from token vector. 7753149Seric ** 7763149Seric ** Parameters: 7773149Seric ** tv -- token vector. 7783149Seric ** a -- pointer to address descriptor to fill. 7793149Seric ** If NULL, one will be allocated. 7803149Seric ** 7813149Seric ** Returns: 7823149Seric ** 'a' 7833149Seric ** 7843149Seric ** Side Effects: 7853149Seric ** fills in 'a' 7863149Seric */ 7873149Seric 7883149Seric ADDRESS * 7893149Seric buildaddr(tv, a) 7903149Seric register char **tv; 7913149Seric register ADDRESS *a; 7923149Seric { 7933149Seric register int i; 7943149Seric static char buf[MAXNAME]; 7953149Seric struct mailer **mp; 7963149Seric register struct mailer *m; 7973149Seric 7983149Seric if (a == NULL) 7993149Seric a = (ADDRESS *) xalloc(sizeof *a); 8003188Seric a->q_flags = 0; 8014079Seric a->q_home = NULL; 8023149Seric 8033149Seric /* figure out what net/mailer to use */ 8043149Seric if (**tv != CANONNET) 8053149Seric syserr("buildaddr: no net"); 8063149Seric tv++; 8073154Seric for (mp = Mailer, i = 0; (m = *mp++) != NULL; i++) 8083149Seric { 8093149Seric if (strcmp(m->m_name, *tv) == 0) 8103149Seric break; 8113149Seric } 8123149Seric if (m == NULL) 8133149Seric syserr("buildaddr: unknown net %s", *tv); 8143149Seric a->q_mailer = i; 8153149Seric 8163149Seric /* figure out what host (if any) */ 8173149Seric tv++; 8183149Seric if (!bitset(M_NOHOST, m->m_flags)) 8193149Seric { 8203149Seric if (**tv != CANONHOST) 8213149Seric syserr("buildaddr: no host"); 8223149Seric tv++; 8233149Seric a->q_host = *tv; 8243149Seric tv++; 8253149Seric } 8263149Seric else 8273149Seric a->q_host = NULL; 8283149Seric 8293149Seric /* figure out the user */ 8303149Seric if (**tv != CANONUSER) 8313149Seric syserr("buildaddr: no user"); 8323149Seric buf[0] = '\0'; 8333149Seric while (**++tv != NULL) 8344085Seric (void) strcat(buf, *tv); 8353149Seric a->q_user = buf; 8363149Seric 8373149Seric return (a); 8383149Seric } 8393188Seric /* 8403188Seric ** SAMEADDR -- Determine if two addresses are the same 8413188Seric ** 8423188Seric ** This is not just a straight comparison -- if the mailer doesn't 8433188Seric ** care about the host we just ignore it, etc. 8443188Seric ** 8453188Seric ** Parameters: 8463188Seric ** a, b -- pointers to the internal forms to compare. 8473188Seric ** wildflg -- if TRUE, 'a' may have no user specified, 8483188Seric ** in which case it is to match anything. 8493188Seric ** 8503188Seric ** Returns: 8513188Seric ** TRUE -- they represent the same mailbox. 8523188Seric ** FALSE -- they don't. 8533188Seric ** 8543188Seric ** Side Effects: 8553188Seric ** none. 8563188Seric */ 8573188Seric 8583188Seric bool 8593188Seric sameaddr(a, b, wildflg) 8603188Seric register ADDRESS *a; 8613188Seric register ADDRESS *b; 8623188Seric bool wildflg; 8633188Seric { 8643188Seric /* if they don't have the same mailer, forget it */ 8653188Seric if (a->q_mailer != b->q_mailer) 8663188Seric return (FALSE); 8673188Seric 8683188Seric /* if the user isn't the same, we can drop out */ 8693188Seric if ((!wildflg || a->q_user[0] != '\0') && strcmp(a->q_user, b->q_user) != 0) 8703188Seric return (FALSE); 8713188Seric 8723188Seric /* if the mailer ignores hosts, we have succeeded! */ 8733188Seric if (bitset(M_NOHOST, Mailer[a->q_mailer]->m_flags)) 8743188Seric return (TRUE); 8753188Seric 8763188Seric /* otherwise compare hosts (but be careful for NULL ptrs) */ 8773188Seric if (a->q_host == NULL || b->q_host == NULL) 8783188Seric return (FALSE); 8793188Seric if (strcmp(a->q_host, b->q_host) != 0) 8803188Seric return (FALSE); 8813188Seric 8823188Seric return (TRUE); 8833188Seric } 8843234Seric /* 8853234Seric ** PRINTADDR -- print address (for debugging) 8863234Seric ** 8873234Seric ** Parameters: 8883234Seric ** a -- the address to print 8893234Seric ** follow -- follow the q_next chain. 8903234Seric ** 8913234Seric ** Returns: 8923234Seric ** none. 8933234Seric ** 8943234Seric ** Side Effects: 8953234Seric ** none. 8963234Seric */ 8973234Seric 8983234Seric printaddr(a, follow) 8993234Seric register ADDRESS *a; 9003234Seric bool follow; 9013234Seric { 9023234Seric while (a != NULL) 9033234Seric { 9043234Seric printf("addr@%x: ", a); 9054085Seric (void) fflush(stdout); 9063234Seric printf("%s: mailer %d (%s), host `%s', user `%s'\n", a->q_paddr, 9073234Seric a->q_mailer, Mailer[a->q_mailer]->m_name, a->q_host, a->q_user); 9083234Seric printf("\tnext=%x flags=%o, rmailer %d\n", a->q_next, 9093234Seric a->q_flags, a->q_rmailer); 9103234Seric 9113234Seric if (!follow) 9123234Seric return; 9133234Seric a = a->q_next; 9143234Seric } 9153234Seric } 916