13312Seric # include "sendmail.h" 2297Seric 3*4385Seric static char SccsId[] = "@(#)parseaddr.c 3.25 09/14/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 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(); 53297Seric 54297Seric /* 55297Seric ** Initialize and prescan address. 56297Seric */ 57297Seric 58297Seric To = addr; 593188Seric # ifdef DEBUG 603188Seric if (Debug) 613188Seric printf("\n--parse(%s)\n", addr); 623188Seric # endif DEBUG 633188Seric 643149Seric pvp = prescan(addr, '\0'); 653149Seric if (pvp == NULL) 66297Seric return (NULL); 67297Seric 68297Seric /* 693149Seric ** Apply rewriting rules. 70297Seric */ 71297Seric 724070Seric rewrite(pvp, 0); 73297Seric 743149Seric /* 753149Seric ** See if we resolved to a real mailer. 763149Seric */ 77297Seric 783149Seric if (pvp[0][0] != CANONNET) 793149Seric { 803149Seric setstat(EX_USAGE); 813149Seric usrerr("cannot resolve name"); 823149Seric return (NULL); 83297Seric } 84297Seric 85297Seric /* 863149Seric ** Build canonical address from pvp. 87297Seric */ 88297Seric 893149Seric a = buildaddr(pvp, a); 904279Seric if (a == NULL) 914279Seric return (NULL); 923149Seric m = Mailer[a->q_mailer]; 93297Seric 94297Seric /* 953149Seric ** Make local copies of the host & user and then 963149Seric ** transport them out. 97297Seric */ 98297Seric 99297Seric if (copyf > 0) 1002973Seric a->q_paddr = newstr(addr); 101297Seric else 102297Seric a->q_paddr = addr; 103297Seric 1043149Seric if (copyf >= 0) 105297Seric { 1063149Seric if (a->q_host != NULL) 1073149Seric a->q_host = newstr(a->q_host); 108297Seric else 1093149Seric a->q_host = ""; 1103149Seric if (a->q_user != a->q_paddr) 1113149Seric a->q_user = newstr(a->q_user); 112297Seric } 113297Seric 114297Seric /* 115297Seric ** Do UPPER->lower case mapping unless inhibited. 116297Seric */ 117297Seric 1183149Seric if (!bitset(M_HST_UPPER, m->m_flags)) 119297Seric makelower(a->q_host); 1203149Seric if (!bitset(M_USR_UPPER, m->m_flags)) 121297Seric makelower(a->q_user); 122297Seric 123297Seric /* 124297Seric ** Compute return value. 125297Seric */ 126297Seric 127297Seric # ifdef DEBUG 1281583Seric if (Debug) 129297Seric printf("parse(\"%s\"): host \"%s\" user \"%s\" mailer %d\n", 1303149Seric addr, a->q_host, a->q_user, a->q_mailer); 131297Seric # endif DEBUG 132297Seric 133297Seric return (a); 134297Seric } 135297Seric /* 136297Seric ** PRESCAN -- Prescan name and make it canonical 137297Seric ** 138297Seric ** Scans a name and turns it into canonical form. This involves 139297Seric ** deleting blanks, comments (in parentheses), and turning the 140297Seric ** word "at" into an at-sign ("@"). The name is copied as this 141297Seric ** is done; it is legal to copy a name onto itself, since this 142297Seric ** process can only make things smaller. 143297Seric ** 144297Seric ** This routine knows about quoted strings and angle brackets. 145297Seric ** 146297Seric ** There are certain subtleties to this routine. The one that 147297Seric ** comes to mind now is that backslashes on the ends of names 148297Seric ** are silently stripped off; this is intentional. The problem 149297Seric ** is that some versions of sndmsg (like at LBL) set the kill 150297Seric ** character to something other than @ when reading addresses; 151297Seric ** so people type "csvax.eric\@berkeley" -- which screws up the 152297Seric ** berknet mailer. 153297Seric ** 154297Seric ** Parameters: 155297Seric ** addr -- the name to chomp. 156297Seric ** delim -- the delimiter for the address, normally 157297Seric ** '\0' or ','; \0 is accepted in any case. 158297Seric ** are moving in place; set buflim to high core. 159297Seric ** 160297Seric ** Returns: 1613149Seric ** A pointer to a vector of tokens. 162297Seric ** NULL on error. 163297Seric ** 164297Seric ** Side Effects: 1653149Seric ** none. 166297Seric */ 167297Seric 1683149Seric # define OPER 1 1693149Seric # define ATOM 2 1703149Seric # define EOTOK 3 1713149Seric # define QSTRING 4 1723149Seric # define SPACE 5 1733149Seric # define DOLLAR 6 1743149Seric # define GETONE 7 1753149Seric 1763149Seric char ** 1773149Seric prescan(addr, delim) 178297Seric char *addr; 179297Seric char delim; 180297Seric { 181297Seric register char *p; 1823149Seric static char buf[MAXNAME+MAXATOM]; 1833149Seric static char *av[MAXATOM+1]; 1843149Seric char **avp; 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 195297Seric q = buf; 1963149Seric bslashmode = FALSE; 197297Seric cmntcnt = brccnt = 0; 1983149Seric avp = av; 1993149Seric state = OPER; 2003149Seric for (p = addr; *p != '\0' && *p != delim; ) 201297Seric { 2023149Seric /* read a token */ 2033149Seric tok = q; 2043149Seric while ((c = *p++) != '\0' && c != delim) 205297Seric { 2063149Seric /* chew up special characters */ 2074100Seric c &= ~0200; 2083149Seric *q = '\0'; 2093149Seric if (bslashmode) 2103149Seric { 2113149Seric c |= 0200; 2123149Seric bslashmode = FALSE; 2133149Seric } 2143149Seric else if (c == '\\') 2153149Seric { 2163149Seric bslashmode = TRUE; 2173149Seric continue; 2183149Seric } 2194100Seric else if (c == '"') 2204100Seric { 2214100Seric if (state == QSTRING) 2224100Seric state = OPER; 2234100Seric else 2244100Seric state = QSTRING; 2254100Seric break; 2264100Seric } 2273149Seric 2283149Seric nstate = toktype(c); 2293149Seric switch (state) 2303149Seric { 2313149Seric case QSTRING: /* in quoted string */ 2323149Seric break; 2333149Seric 2343149Seric case ATOM: /* regular atom */ 2354228Seric /* state = nstate; */ 2364228Seric if (nstate != ATOM) 2373149Seric { 2383149Seric state = EOTOK; 2393149Seric p--; 2403149Seric } 2413149Seric break; 2423149Seric 2433149Seric case GETONE: /* grab one character */ 2443149Seric state = OPER; 2453149Seric break; 2463149Seric 2473149Seric case EOTOK: /* after atom or q-string */ 2483149Seric state = nstate; 2493149Seric if (state == SPACE) 2503149Seric continue; 2513149Seric break; 2523149Seric 2533149Seric case SPACE: /* linear white space */ 2543149Seric state = nstate; 2554228Seric break; 2563149Seric 2573149Seric case OPER: /* operator */ 2583149Seric if (nstate == SPACE) 2593149Seric continue; 2603149Seric state = nstate; 2613149Seric break; 2623149Seric 2633149Seric case DOLLAR: /* $- etc. */ 2643149Seric state = OPER; 2653149Seric switch (c) 2663149Seric { 2673149Seric case '$': /* literal $ */ 2683149Seric break; 2693149Seric 2703149Seric case '+': /* match anything */ 2713149Seric c = MATCHANY; 2723149Seric state = GETONE; 2733149Seric break; 2743149Seric 2753149Seric case '-': /* match one token */ 2763149Seric c = MATCHONE; 2773149Seric state = GETONE; 2783149Seric break; 2793149Seric 2804060Seric case '=': /* match one token of class */ 2814060Seric c = MATCHCLASS; 2824060Seric state = GETONE; 2834060Seric break; 2844060Seric 2853149Seric case '#': /* canonical net name */ 2863149Seric c = CANONNET; 2873149Seric break; 2883149Seric 2893149Seric case '@': /* canonical host name */ 2903149Seric c = CANONHOST; 2913149Seric break; 2923149Seric 2933149Seric case ':': /* canonical user name */ 2943149Seric c = CANONUSER; 2953149Seric break; 2963149Seric 2973149Seric default: 2983149Seric c = '$'; 2993149Seric state = OPER; 3003149Seric p--; 3013149Seric break; 3023149Seric } 3033149Seric break; 3043149Seric 3053149Seric default: 3063149Seric syserr("prescan: unknown state %d", state); 3073149Seric } 3083149Seric 3094228Seric if (state == EOTOK || state == SPACE) 3103149Seric break; 3113149Seric if (c == '$' && delim == '\t') 3123149Seric { 3133149Seric state = DOLLAR; 3143149Seric continue; 3153149Seric } 3163149Seric 3173149Seric /* squirrel it away */ 3183149Seric if (q >= &buf[sizeof buf - 5]) 3193149Seric { 3203149Seric usrerr("Address too long"); 3213149Seric return (NULL); 3223149Seric } 3233149Seric *q++ = c; 3243149Seric 3253149Seric /* decide whether this represents end of token */ 3263149Seric if (state == OPER) 3273149Seric break; 328297Seric } 3293149Seric if (c == '\0' || c == delim) 3303149Seric p--; 3313149Seric 3323149Seric /* new token */ 3333149Seric if (tok == q) 334297Seric continue; 3353149Seric *q++ = '\0'; 3363149Seric 3373149Seric c = tok[0]; 3383149Seric if (c == '(') 3391378Seric { 340297Seric cmntcnt++; 3411378Seric continue; 3421378Seric } 343297Seric else if (c == ')') 344297Seric { 345297Seric if (cmntcnt <= 0) 346297Seric { 347297Seric usrerr("Unbalanced ')'"); 348297Seric return (NULL); 349297Seric } 350297Seric else 351297Seric { 352297Seric cmntcnt--; 353297Seric continue; 354297Seric } 355297Seric } 3563149Seric else if (cmntcnt > 0) 3572091Seric continue; 3583149Seric 359*4385Seric if (avp >= &av[MAXATOM]) 360*4385Seric { 361*4385Seric syserr("prescan: too many tokens"); 362*4385Seric return (NULL); 363*4385Seric } 3643149Seric *avp++ = tok; 3653149Seric 3663149Seric /* we prefer <> specs */ 3673149Seric if (c == '<') 368297Seric { 3692092Seric if (brccnt < 0) 3702092Seric { 3712092Seric usrerr("multiple < spec"); 3722092Seric return (NULL); 3732092Seric } 374297Seric brccnt++; 375297Seric if (brccnt == 1) 376297Seric { 377297Seric /* we prefer using machine readable name */ 378297Seric q = buf; 379297Seric *q = '\0'; 3803149Seric avp = av; 381297Seric continue; 382297Seric } 383297Seric } 384297Seric else if (c == '>') 385297Seric { 386297Seric if (brccnt <= 0) 387297Seric { 388297Seric usrerr("Unbalanced `>'"); 389297Seric return (NULL); 390297Seric } 391297Seric else 392297Seric brccnt--; 393297Seric if (brccnt <= 0) 3942092Seric { 3952092Seric brccnt = -1; 396297Seric continue; 3972092Seric } 398297Seric } 3993149Seric } 4003149Seric *avp = NULL; 4013149Seric if (cmntcnt > 0) 4023149Seric usrerr("Unbalanced '('"); 4033149Seric else if (brccnt > 0) 4043149Seric usrerr("Unbalanced '<'"); 4053149Seric else if (state == QSTRING) 4063149Seric usrerr("Unbalanced '\"'"); 4073149Seric else if (av[0] != NULL) 4083149Seric return (av); 4093149Seric return (NULL); 4103149Seric } 4113149Seric /* 4123149Seric ** TOKTYPE -- return token type 4133149Seric ** 4143149Seric ** Parameters: 4153149Seric ** c -- the character in question. 4163149Seric ** 4173149Seric ** Returns: 4183149Seric ** Its type. 4193149Seric ** 4203149Seric ** Side Effects: 4213149Seric ** none. 4223149Seric */ 423297Seric 4243149Seric toktype(c) 4253149Seric register char c; 4263149Seric { 4273380Seric static char buf[50]; 4283382Seric static bool firstime = TRUE; 4293380Seric 4303382Seric if (firstime) 4313380Seric { 4323382Seric firstime = FALSE; 4334085Seric (void) expand("$o", buf, &buf[sizeof buf - 1]); 4343380Seric strcat(buf, DELIMCHARS); 4353380Seric } 4364100Seric if (!isascii(c)) 4374100Seric return (ATOM); 4383149Seric if (isspace(c)) 4393149Seric return (SPACE); 4403380Seric if (iscntrl(c) || index(buf, c) != NULL) 4413149Seric return (OPER); 4423149Seric return (ATOM); 4433149Seric } 4443149Seric /* 4453149Seric ** REWRITE -- apply rewrite rules to token vector. 4463149Seric ** 4473149Seric ** Parameters: 4483149Seric ** pvp -- pointer to token vector. 4493149Seric ** 4503149Seric ** Returns: 4513149Seric ** none. 4523149Seric ** 4533149Seric ** Side Effects: 4543149Seric ** pvp is modified. 4553149Seric */ 4562091Seric 4573149Seric struct match 4583149Seric { 4593149Seric char **firsttok; /* first token matched */ 4603149Seric char **lasttok; /* last token matched */ 4613149Seric char name; /* name of parameter */ 4623149Seric }; 4633149Seric 4643149Seric # define MAXMATCH 8 /* max params per rewrite */ 4653149Seric 4663149Seric 4674070Seric rewrite(pvp, ruleset) 4683149Seric char **pvp; 4694070Seric int ruleset; 4703149Seric { 4713149Seric register char *ap; /* address pointer */ 4723149Seric register char *rp; /* rewrite pointer */ 4733149Seric register char **avp; /* address vector pointer */ 4743149Seric register char **rvp; /* rewrite vector pointer */ 4753149Seric struct rewrite *rwr; 4763149Seric struct match mlist[MAXMATCH]; 4773149Seric char *npvp[MAXATOM+1]; /* temporary space for rebuild */ 4784060Seric extern bool sameword(); 4793149Seric 4804100Seric # ifdef DEBUG 4814228Seric if (Debug > 9) 4823149Seric { 4833149Seric printf("rewrite: original pvp:\n"); 4843149Seric printav(pvp); 4853149Seric } 4864100Seric # endif DEBUG 4873149Seric 4883149Seric /* 4893149Seric ** Run through the list of rewrite rules, applying 4903149Seric ** any that match. 4913149Seric */ 4923149Seric 4934070Seric for (rwr = RewriteRules[ruleset]; rwr != NULL; ) 4943149Seric { 4954100Seric # ifdef DEBUG 4964100Seric if (Debug > 10) 497297Seric { 4983149Seric printf("-----trying rule:\n"); 4993149Seric printav(rwr->r_lhs); 5003149Seric } 5014100Seric # endif DEBUG 5023149Seric 5033149Seric /* try to match on this rule */ 5043149Seric clrmatch(mlist); 5053149Seric for (rvp = rwr->r_lhs, avp = pvp; *avp != NULL; ) 5063149Seric { 5073149Seric ap = *avp; 5083149Seric rp = *rvp; 5093149Seric 5103149Seric if (rp == NULL) 511297Seric { 5123149Seric /* end-of-pattern before end-of-address */ 5133149Seric goto fail; 514297Seric } 5153149Seric 5163149Seric switch (*rp) 5173149Seric { 5184060Seric register STAB *s; 5194060Seric register int class; 5204060Seric 5213149Seric case MATCHONE: 5223149Seric /* match exactly one token */ 5233149Seric setmatch(mlist, rp[1], avp, avp); 5243149Seric break; 5253149Seric 5263149Seric case MATCHANY: 5273149Seric /* match any number of tokens */ 5284085Seric setmatch(mlist, rp[1], (char **) NULL, avp); 5293149Seric break; 5303149Seric 5314060Seric case MATCHCLASS: 5324060Seric /* match any token in a class */ 5334060Seric class = rp[1]; 5344060Seric if (!isalpha(class)) 5354060Seric goto fail; 5364060Seric if (isupper(class)) 5374060Seric class -= 'A'; 5384060Seric else 5394060Seric class -= 'a'; 5404100Seric s = stab(ap, ST_CLASS, ST_FIND); 5414060Seric if (s == NULL || (s->s_class & (1 << class)) == 0) 5424060Seric goto fail; 5434060Seric break; 5444060Seric 5453149Seric default: 5463149Seric /* must have exact match */ 5474060Seric if (!sameword(rp, ap)) 5484060Seric goto fail; 5493149Seric break; 5503149Seric } 5513149Seric 5523149Seric /* successful match on this token */ 5533149Seric avp++; 5543149Seric rvp++; 5553149Seric continue; 5563149Seric 5573149Seric fail: 5583149Seric /* match failed -- back up */ 5593149Seric while (--rvp >= rwr->r_lhs) 5603149Seric { 5613149Seric rp = *rvp; 5623149Seric if (*rp == MATCHANY) 5633149Seric break; 5643149Seric 5653149Seric /* can't extend match: back up everything */ 5663149Seric avp--; 5673149Seric 5683149Seric if (*rp == MATCHONE) 5693149Seric { 5703149Seric /* undo binding */ 5714085Seric setmatch(mlist, rp[1], (char **) NULL, (char **) NULL); 5723149Seric } 5733149Seric } 5743149Seric 5753149Seric if (rvp < rwr->r_lhs) 5763149Seric { 5773149Seric /* total failure to match */ 5783149Seric break; 5793149Seric } 580297Seric } 5813149Seric 5823149Seric /* 5833149Seric ** See if we successfully matched 5843149Seric */ 5853149Seric 5863149Seric if (rvp >= rwr->r_lhs && *rvp == NULL) 5873149Seric { 5884100Seric # ifdef DEBUG 5894100Seric if (Debug > 10) 5903149Seric { 5913149Seric printf("-----rule matches:\n"); 5923149Seric printav(rwr->r_rhs); 5933149Seric } 5944100Seric # endif DEBUG 5953149Seric 5963149Seric /* substitute */ 5973149Seric for (rvp = rwr->r_rhs, avp = npvp; *rvp != NULL; rvp++) 5983149Seric { 5993149Seric rp = *rvp; 6003149Seric if (*rp == MATCHANY) 6013149Seric { 6023149Seric register struct match *m; 6033149Seric register char **pp; 6043149Seric extern struct match *findmatch(); 6053149Seric 6063149Seric m = findmatch(mlist, rp[1]); 6073149Seric if (m != NULL) 6083149Seric { 6093149Seric pp = m->firsttok; 6103149Seric do 6113149Seric { 612*4385Seric if (avp >= &npvp[MAXATOM]) 613*4385Seric { 614*4385Seric syserr("rewrite: expansion too long"); 615*4385Seric return; 616*4385Seric } 6173149Seric *avp++ = *pp; 6183149Seric } while (pp++ != m->lasttok); 6193149Seric } 6203149Seric } 6213149Seric else 622*4385Seric { 623*4385Seric if (avp >= &npvp[MAXATOM]) 624*4385Seric { 625*4385Seric syserr("rewrite: expansion too long"); 626*4385Seric return; 627*4385Seric } 6283149Seric *avp++ = rp; 629*4385Seric } 6303149Seric } 6313149Seric *avp++ = NULL; 6324085Seric bmove((char *) npvp, (char *) pvp, (avp - npvp) * sizeof *avp); 6333149Seric # ifdef DEBUG 6344228Seric if (Debug > 3) 6353149Seric { 6363188Seric char **vp; 6373188Seric 6383188Seric printf("rewritten as `"); 6393188Seric for (vp = pvp; *vp != NULL; vp++) 6404228Seric { 6414228Seric if (vp != pvp) 6424228Seric printf("_"); 6433188Seric xputs(*vp); 6444228Seric } 6453188Seric printf("'\n"); 6463149Seric } 6473149Seric # endif DEBUG 6483149Seric if (pvp[0][0] == CANONNET) 6493149Seric break; 6503149Seric } 6513149Seric else 6523149Seric { 6534100Seric # ifdef DEBUG 6544100Seric if (Debug > 10) 6553149Seric printf("----- rule fails\n"); 6564100Seric # endif DEBUG 6573149Seric rwr = rwr->r_next; 6583149Seric } 659297Seric } 6603149Seric } 6613149Seric /* 6623149Seric ** SETMATCH -- set parameter value in match vector 6633149Seric ** 6643149Seric ** Parameters: 6653149Seric ** mlist -- list of match values. 6663149Seric ** name -- the character name of this parameter. 6673149Seric ** first -- the first location of the replacement. 6683149Seric ** last -- the last location of the replacement. 6693149Seric ** 6703149Seric ** If last == NULL, delete this entry. 6713149Seric ** If first == NULL, extend this entry (or add it if 6723149Seric ** it does not exist). 6733149Seric ** 6743149Seric ** Returns: 6753149Seric ** nothing. 6763149Seric ** 6773149Seric ** Side Effects: 6783149Seric ** munges with mlist. 6793149Seric */ 6803149Seric 6813149Seric setmatch(mlist, name, first, last) 6823149Seric struct match *mlist; 6833149Seric char name; 6843149Seric char **first; 6853149Seric char **last; 6863149Seric { 6873149Seric register struct match *m; 6883149Seric struct match *nullm = NULL; 6893149Seric 6903149Seric for (m = mlist; m < &mlist[MAXMATCH]; m++) 6913149Seric { 6923149Seric if (m->name == name) 6933149Seric break; 6943149Seric if (m->name == '\0') 6953149Seric nullm = m; 6963149Seric } 6973149Seric 6983149Seric if (m >= &mlist[MAXMATCH]) 6993149Seric m = nullm; 7003149Seric 7013149Seric if (last == NULL) 7023149Seric { 7033149Seric m->name = '\0'; 7043149Seric return; 7053149Seric } 7063149Seric 7073149Seric if (m->name == '\0') 7083149Seric { 7093149Seric if (first == NULL) 7103149Seric m->firsttok = last; 7113149Seric else 7123149Seric m->firsttok = first; 7133149Seric } 7143149Seric m->name = name; 7153149Seric m->lasttok = last; 7163149Seric } 7173149Seric /* 7183149Seric ** FINDMATCH -- find match in mlist 7193149Seric ** 7203149Seric ** Parameters: 7213149Seric ** mlist -- list to search. 7223149Seric ** name -- name to find. 7233149Seric ** 7243149Seric ** Returns: 7253149Seric ** pointer to match structure. 7263149Seric ** NULL if no match. 7273149Seric ** 7283149Seric ** Side Effects: 7293149Seric ** none. 7303149Seric */ 7313149Seric 7323149Seric struct match * 7333149Seric findmatch(mlist, name) 7343149Seric struct match *mlist; 7353149Seric char name; 7363149Seric { 7373149Seric register struct match *m; 7383149Seric 7393149Seric for (m = mlist; m < &mlist[MAXMATCH]; m++) 7403149Seric { 7413149Seric if (m->name == name) 7423149Seric return (m); 7433149Seric } 7443149Seric 745297Seric return (NULL); 746297Seric } 7473149Seric /* 7483149Seric ** CLRMATCH -- clear match list 7493149Seric ** 7503149Seric ** Parameters: 7513149Seric ** mlist -- list to clear. 7523149Seric ** 7533149Seric ** Returns: 7543149Seric ** none. 7553149Seric ** 7563149Seric ** Side Effects: 7573149Seric ** mlist is cleared. 7583149Seric */ 7593149Seric 7603149Seric clrmatch(mlist) 7613149Seric struct match *mlist; 7623149Seric { 7633149Seric register struct match *m; 7643149Seric 7653149Seric for (m = mlist; m < &mlist[MAXMATCH]; m++) 7663149Seric m->name = '\0'; 7673149Seric } 7683149Seric /* 7693149Seric ** BUILDADDR -- build address from token vector. 7703149Seric ** 7713149Seric ** Parameters: 7723149Seric ** tv -- token vector. 7733149Seric ** a -- pointer to address descriptor to fill. 7743149Seric ** If NULL, one will be allocated. 7753149Seric ** 7763149Seric ** Returns: 7774279Seric ** NULL if there was an error. 7784279Seric ** 'a' otherwise. 7793149Seric ** 7803149Seric ** Side Effects: 7813149Seric ** fills in 'a' 7823149Seric */ 7833149Seric 7843149Seric ADDRESS * 7853149Seric buildaddr(tv, a) 7863149Seric register char **tv; 7873149Seric register ADDRESS *a; 7883149Seric { 7893149Seric register int i; 7903149Seric static char buf[MAXNAME]; 7913149Seric struct mailer **mp; 7923149Seric register struct mailer *m; 7933149Seric 7943149Seric if (a == NULL) 7953149Seric a = (ADDRESS *) xalloc(sizeof *a); 7963188Seric a->q_flags = 0; 7974079Seric a->q_home = NULL; 7983149Seric 7993149Seric /* figure out what net/mailer to use */ 8003149Seric if (**tv != CANONNET) 8014279Seric { 8023149Seric syserr("buildaddr: no net"); 8034279Seric return (NULL); 8044279Seric } 8053149Seric tv++; 8064279Seric if (strcmp(*tv, "error") == 0) 8074279Seric { 8084279Seric if (**++tv != CANONUSER) 8094279Seric syserr("buildaddr: error: no user"); 8104279Seric buf[0] = '\0'; 8114279Seric while (*++tv != NULL) 8124279Seric { 8134279Seric if (buf[0] != '\0') 8144279Seric strcat(buf, " "); 8154279Seric strcat(buf, *tv); 8164279Seric } 8174279Seric usrerr(buf); 8184279Seric return (NULL); 8194279Seric } 8203154Seric for (mp = Mailer, i = 0; (m = *mp++) != NULL; i++) 8213149Seric { 8223149Seric if (strcmp(m->m_name, *tv) == 0) 8233149Seric break; 8243149Seric } 8253149Seric if (m == NULL) 8264279Seric { 8273149Seric syserr("buildaddr: unknown net %s", *tv); 8284279Seric return (NULL); 8294279Seric } 8303149Seric a->q_mailer = i; 8313149Seric 8323149Seric /* figure out what host (if any) */ 8333149Seric tv++; 8344195Seric if (!bitset(M_LOCAL, m->m_flags)) 8353149Seric { 8363149Seric if (**tv != CANONHOST) 8374279Seric { 8383149Seric syserr("buildaddr: no host"); 8394279Seric return (NULL); 8404279Seric } 8413149Seric tv++; 8423149Seric a->q_host = *tv; 8433149Seric tv++; 8443149Seric } 8453149Seric else 8463149Seric a->q_host = NULL; 8473149Seric 8483149Seric /* figure out the user */ 8493149Seric if (**tv != CANONUSER) 8504279Seric { 8513149Seric syserr("buildaddr: no user"); 8524279Seric return (NULL); 8534279Seric } 8544228Seric cataddr(++tv, buf, sizeof buf); 8553149Seric a->q_user = buf; 8563149Seric 8573149Seric return (a); 8583149Seric } 8593188Seric /* 8604228Seric ** CATADDR -- concatenate pieces of addresses (putting in <LWSP> subs) 8614228Seric ** 8624228Seric ** Parameters: 8634228Seric ** pvp -- parameter vector to rebuild. 8644228Seric ** buf -- buffer to build the string into. 8654228Seric ** sz -- size of buf. 8664228Seric ** 8674228Seric ** Returns: 8684228Seric ** none. 8694228Seric ** 8704228Seric ** Side Effects: 8714228Seric ** Destroys buf. 8724228Seric */ 8734228Seric 8744228Seric cataddr(pvp, buf, sz) 8754228Seric char **pvp; 8764228Seric char *buf; 8774228Seric register int sz; 8784228Seric { 8794228Seric bool oatomtok = FALSE; 8804228Seric bool natomtok = FALSE; 8814228Seric register int i; 8824228Seric register char *p; 8834228Seric 8844228Seric p = buf; 8854228Seric sz--; 8864228Seric while (*pvp != NULL && (i = strlen(*pvp)) < sz) 8874228Seric { 8884228Seric natomtok = (toktype(**pvp) == ATOM); 8894228Seric if (oatomtok && natomtok) 8904228Seric *p++ = SPACESUB; 8914228Seric (void) strcpy(p, *pvp); 8924228Seric oatomtok = natomtok; 8934228Seric p += i; 8944228Seric sz -= i; 8954228Seric pvp++; 8964228Seric } 8974228Seric *p = '\0'; 8984228Seric } 8994228Seric /* 9003188Seric ** SAMEADDR -- Determine if two addresses are the same 9013188Seric ** 9023188Seric ** This is not just a straight comparison -- if the mailer doesn't 9033188Seric ** care about the host we just ignore it, etc. 9043188Seric ** 9053188Seric ** Parameters: 9063188Seric ** a, b -- pointers to the internal forms to compare. 9073188Seric ** wildflg -- if TRUE, 'a' may have no user specified, 9083188Seric ** in which case it is to match anything. 9093188Seric ** 9103188Seric ** Returns: 9113188Seric ** TRUE -- they represent the same mailbox. 9123188Seric ** FALSE -- they don't. 9133188Seric ** 9143188Seric ** Side Effects: 9153188Seric ** none. 9163188Seric */ 9173188Seric 9183188Seric bool 9193188Seric sameaddr(a, b, wildflg) 9203188Seric register ADDRESS *a; 9213188Seric register ADDRESS *b; 9223188Seric bool wildflg; 9233188Seric { 9243188Seric /* if they don't have the same mailer, forget it */ 9253188Seric if (a->q_mailer != b->q_mailer) 9263188Seric return (FALSE); 9273188Seric 9283188Seric /* if the user isn't the same, we can drop out */ 9293188Seric if ((!wildflg || a->q_user[0] != '\0') && strcmp(a->q_user, b->q_user) != 0) 9303188Seric return (FALSE); 9313188Seric 9323188Seric /* if the mailer ignores hosts, we have succeeded! */ 9334195Seric if (bitset(M_LOCAL, Mailer[a->q_mailer]->m_flags)) 9343188Seric return (TRUE); 9353188Seric 9363188Seric /* otherwise compare hosts (but be careful for NULL ptrs) */ 9373188Seric if (a->q_host == NULL || b->q_host == NULL) 9383188Seric return (FALSE); 9393188Seric if (strcmp(a->q_host, b->q_host) != 0) 9403188Seric return (FALSE); 9413188Seric 9423188Seric return (TRUE); 9433188Seric } 9443234Seric /* 9453234Seric ** PRINTADDR -- print address (for debugging) 9463234Seric ** 9473234Seric ** Parameters: 9483234Seric ** a -- the address to print 9493234Seric ** follow -- follow the q_next chain. 9503234Seric ** 9513234Seric ** Returns: 9523234Seric ** none. 9533234Seric ** 9543234Seric ** Side Effects: 9553234Seric ** none. 9563234Seric */ 9573234Seric 9584317Seric # ifdef DEBUG 9594317Seric 9603234Seric printaddr(a, follow) 9613234Seric register ADDRESS *a; 9623234Seric bool follow; 9633234Seric { 9643234Seric while (a != NULL) 9653234Seric { 9663234Seric printf("addr@%x: ", a); 9674085Seric (void) fflush(stdout); 9683234Seric printf("%s: mailer %d (%s), host `%s', user `%s'\n", a->q_paddr, 9693234Seric a->q_mailer, Mailer[a->q_mailer]->m_name, a->q_host, a->q_user); 9703234Seric printf("\tnext=%x flags=%o, rmailer %d\n", a->q_next, 9713234Seric a->q_flags, a->q_rmailer); 9723234Seric 9733234Seric if (!follow) 9743234Seric return; 9753234Seric a = a->q_next; 9763234Seric } 9773234Seric } 9784317Seric 9794317Seric # endif DEBUG 980