1297Seric # include <stdio.h> 2297Seric # include <ctype.h> 33312Seric # include "sendmail.h" 4297Seric 5*4060Seric static char SccsId[] = "@(#)parseaddr.c 3.13 08/08/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(); 612973Seric extern char *newstr(); 622990Seric extern char *strcpy(); 633149Seric extern ADDRESS *buildaddr(); 64297Seric 65297Seric /* 66297Seric ** Initialize and prescan address. 67297Seric */ 68297Seric 69297Seric To = addr; 703188Seric # ifdef DEBUG 713188Seric if (Debug) 723188Seric printf("\n--parse(%s)\n", addr); 733188Seric # endif DEBUG 743188Seric 753149Seric pvp = prescan(addr, '\0'); 763149Seric if (pvp == NULL) 77297Seric return (NULL); 78297Seric 79297Seric /* 803149Seric ** Apply rewriting rules. 81297Seric */ 82297Seric 833149Seric rewrite(pvp); 84297Seric 853149Seric /* 863149Seric ** See if we resolved to a real mailer. 873149Seric */ 88297Seric 893149Seric if (pvp[0][0] != CANONNET) 903149Seric { 913149Seric setstat(EX_USAGE); 923149Seric usrerr("cannot resolve name"); 933149Seric return (NULL); 94297Seric } 95297Seric 96297Seric /* 973149Seric ** Build canonical address from pvp. 98297Seric */ 99297Seric 1003149Seric a = buildaddr(pvp, a); 1013149Seric m = Mailer[a->q_mailer]; 102297Seric 103297Seric /* 1043149Seric ** Make local copies of the host & user and then 1053149Seric ** transport them out. 106297Seric */ 107297Seric 108297Seric if (copyf > 0) 1092973Seric a->q_paddr = newstr(addr); 110297Seric else 111297Seric a->q_paddr = addr; 112297Seric 1133149Seric if (copyf >= 0) 114297Seric { 1153149Seric if (a->q_host != NULL) 1163149Seric a->q_host = newstr(a->q_host); 117297Seric else 1183149Seric a->q_host = ""; 1193149Seric if (a->q_user != a->q_paddr) 1203149Seric a->q_user = newstr(a->q_user); 121297Seric } 122297Seric 123297Seric /* 124297Seric ** Do UPPER->lower case mapping unless inhibited. 125297Seric */ 126297Seric 1273149Seric if (!bitset(M_HST_UPPER, m->m_flags)) 128297Seric makelower(a->q_host); 1293149Seric if (!bitset(M_USR_UPPER, m->m_flags)) 130297Seric makelower(a->q_user); 131297Seric 132297Seric /* 133297Seric ** Compute return value. 134297Seric */ 135297Seric 136297Seric # ifdef DEBUG 1371583Seric if (Debug) 138297Seric printf("parse(\"%s\"): host \"%s\" user \"%s\" mailer %d\n", 1393149Seric addr, a->q_host, a->q_user, a->q_mailer); 140297Seric # endif DEBUG 141297Seric 142297Seric return (a); 143297Seric } 144297Seric /* 145297Seric ** PRESCAN -- Prescan name and make it canonical 146297Seric ** 147297Seric ** Scans a name and turns it into canonical form. This involves 148297Seric ** deleting blanks, comments (in parentheses), and turning the 149297Seric ** word "at" into an at-sign ("@"). The name is copied as this 150297Seric ** is done; it is legal to copy a name onto itself, since this 151297Seric ** process can only make things smaller. 152297Seric ** 153297Seric ** This routine knows about quoted strings and angle brackets. 154297Seric ** 155297Seric ** There are certain subtleties to this routine. The one that 156297Seric ** comes to mind now is that backslashes on the ends of names 157297Seric ** are silently stripped off; this is intentional. The problem 158297Seric ** is that some versions of sndmsg (like at LBL) set the kill 159297Seric ** character to something other than @ when reading addresses; 160297Seric ** so people type "csvax.eric\@berkeley" -- which screws up the 161297Seric ** berknet mailer. 162297Seric ** 163297Seric ** Parameters: 164297Seric ** addr -- the name to chomp. 165297Seric ** delim -- the delimiter for the address, normally 166297Seric ** '\0' or ','; \0 is accepted in any case. 167297Seric ** are moving in place; set buflim to high core. 168297Seric ** 169297Seric ** Returns: 1703149Seric ** A pointer to a vector of tokens. 171297Seric ** NULL on error. 172297Seric ** 173297Seric ** Side Effects: 1743149Seric ** none. 175297Seric */ 176297Seric 1773149Seric # define OPER 1 1783149Seric # define ATOM 2 1793149Seric # define EOTOK 3 1803149Seric # define QSTRING 4 1813149Seric # define SPACE 5 1823149Seric # define DOLLAR 6 1833149Seric # define GETONE 7 1843149Seric 1853149Seric char ** 1863149Seric prescan(addr, delim) 187297Seric char *addr; 188297Seric char delim; 189297Seric { 190297Seric register char *p; 1913149Seric static char buf[MAXNAME+MAXATOM]; 1923149Seric static char *av[MAXATOM+1]; 1933149Seric char **avp; 194297Seric bool space; 195297Seric bool bslashmode; 196297Seric int cmntcnt; 197297Seric int brccnt; 198297Seric register char c; 1993149Seric char *tok; 200297Seric register char *q; 2012973Seric extern char *index(); 2023149Seric register int state; 2033149Seric int nstate; 204297Seric 2052091Seric space = FALSE; 206297Seric q = buf; 2073149Seric bslashmode = FALSE; 208297Seric cmntcnt = brccnt = 0; 2093149Seric avp = av; 2103149Seric state = OPER; 2113149Seric for (p = addr; *p != '\0' && *p != delim; ) 212297Seric { 2133149Seric /* read a token */ 2143149Seric tok = q; 2153149Seric while ((c = *p++) != '\0' && c != delim) 216297Seric { 2173149Seric /* chew up special characters */ 2183149Seric *q = '\0'; 2193149Seric if (bslashmode) 2203149Seric { 2213149Seric c |= 0200; 2223149Seric bslashmode = FALSE; 2233149Seric } 2243149Seric else if (c == '\\') 2253149Seric { 2263149Seric bslashmode = TRUE; 2273149Seric continue; 2283149Seric } 2293149Seric 2303149Seric nstate = toktype(c); 2313149Seric switch (state) 2323149Seric { 2333149Seric case QSTRING: /* in quoted string */ 2343149Seric if (c == '"') 2353149Seric state = OPER; 2363149Seric break; 2373149Seric 2383149Seric case ATOM: /* regular atom */ 2393149Seric state = nstate; 2403149Seric if (state != ATOM) 2413149Seric { 2423149Seric state = EOTOK; 2433149Seric p--; 2443149Seric } 2453149Seric break; 2463149Seric 2473149Seric case GETONE: /* grab one character */ 2483149Seric state = OPER; 2493149Seric break; 2503149Seric 2513149Seric case EOTOK: /* after atom or q-string */ 2523149Seric state = nstate; 2533149Seric if (state == SPACE) 2543149Seric continue; 2553149Seric break; 2563149Seric 2573149Seric case SPACE: /* linear white space */ 2583149Seric state = nstate; 2593149Seric space = TRUE; 2603149Seric continue; 2613149Seric 2623149Seric case OPER: /* operator */ 2633149Seric if (nstate == SPACE) 2643149Seric continue; 2653149Seric state = nstate; 2663149Seric break; 2673149Seric 2683149Seric case DOLLAR: /* $- etc. */ 2693149Seric state = OPER; 2703149Seric switch (c) 2713149Seric { 2723149Seric case '$': /* literal $ */ 2733149Seric break; 2743149Seric 2753149Seric case '+': /* match anything */ 2763149Seric c = MATCHANY; 2773149Seric state = GETONE; 2783149Seric break; 2793149Seric 2803149Seric case '-': /* match one token */ 2813149Seric c = MATCHONE; 2823149Seric state = GETONE; 2833149Seric break; 2843149Seric 285*4060Seric case '=': /* match one token of class */ 286*4060Seric c = MATCHCLASS; 287*4060Seric state = GETONE; 288*4060Seric break; 289*4060Seric 2903149Seric case '#': /* canonical net name */ 2913149Seric c = CANONNET; 2923149Seric break; 2933149Seric 2943149Seric case '@': /* canonical host name */ 2953149Seric c = CANONHOST; 2963149Seric break; 2973149Seric 2983149Seric case ':': /* canonical user name */ 2993149Seric c = CANONUSER; 3003149Seric break; 3013149Seric 3023149Seric default: 3033149Seric c = '$'; 3043149Seric state = OPER; 3053149Seric p--; 3063149Seric break; 3073149Seric } 3083149Seric break; 3093149Seric 3103149Seric default: 3113149Seric syserr("prescan: unknown state %d", state); 3123149Seric } 3133149Seric 3143149Seric if (state == OPER) 3153149Seric space = FALSE; 3163149Seric else if (state == EOTOK) 3173149Seric break; 3183149Seric if (c == '$' && delim == '\t') 3193149Seric { 3203149Seric state = DOLLAR; 3213149Seric continue; 3223149Seric } 3233149Seric 3243149Seric /* squirrel it away */ 3253149Seric if (q >= &buf[sizeof buf - 5]) 3263149Seric { 3273149Seric usrerr("Address too long"); 3283149Seric return (NULL); 3293149Seric } 3303149Seric if (space) 3313149Seric *q++ = SPACESUB; 3323149Seric *q++ = c; 3333149Seric 3343149Seric /* decide whether this represents end of token */ 3353149Seric if (state == OPER) 3363149Seric break; 337297Seric } 3383149Seric if (c == '\0' || c == delim) 3393149Seric p--; 3403149Seric 3413149Seric /* new token */ 3423149Seric if (tok == q) 343297Seric continue; 3443149Seric *q++ = '\0'; 3453149Seric 3463149Seric c = tok[0]; 3473149Seric if (c == '(') 3481378Seric { 349297Seric cmntcnt++; 3501378Seric continue; 3511378Seric } 352297Seric else if (c == ')') 353297Seric { 354297Seric if (cmntcnt <= 0) 355297Seric { 356297Seric usrerr("Unbalanced ')'"); 357297Seric return (NULL); 358297Seric } 359297Seric else 360297Seric { 361297Seric cmntcnt--; 362297Seric continue; 363297Seric } 364297Seric } 3653149Seric else if (cmntcnt > 0) 3662091Seric continue; 3673149Seric 3683149Seric *avp++ = tok; 3693149Seric 3703149Seric /* we prefer <> specs */ 3713149Seric if (c == '<') 372297Seric { 3732092Seric if (brccnt < 0) 3742092Seric { 3752092Seric usrerr("multiple < spec"); 3762092Seric return (NULL); 3772092Seric } 378297Seric brccnt++; 3792091Seric space = FALSE; 380297Seric if (brccnt == 1) 381297Seric { 382297Seric /* we prefer using machine readable name */ 383297Seric q = buf; 384297Seric *q = '\0'; 3853149Seric avp = av; 386297Seric continue; 387297Seric } 388297Seric } 389297Seric else if (c == '>') 390297Seric { 391297Seric if (brccnt <= 0) 392297Seric { 393297Seric usrerr("Unbalanced `>'"); 394297Seric return (NULL); 395297Seric } 396297Seric else 397297Seric brccnt--; 398297Seric if (brccnt <= 0) 3992092Seric { 4002092Seric brccnt = -1; 401297Seric continue; 4022092Seric } 403297Seric } 404297Seric 405297Seric /* 406297Seric ** Turn "at" into "@", 4071378Seric ** but only if "at" is a word. 408297Seric */ 409297Seric 4103149Seric if (lower(tok[0]) == 'a' && lower(tok[1]) == 't' && tok[2] == '\0') 411297Seric { 4123149Seric tok[0] = '@'; 4133149Seric tok[1] = '\0'; 414297Seric } 4153149Seric } 4163149Seric *avp = NULL; 4173149Seric if (cmntcnt > 0) 4183149Seric usrerr("Unbalanced '('"); 4193149Seric else if (brccnt > 0) 4203149Seric usrerr("Unbalanced '<'"); 4213149Seric else if (state == QSTRING) 4223149Seric usrerr("Unbalanced '\"'"); 4233149Seric else if (av[0] != NULL) 4243149Seric return (av); 4253149Seric return (NULL); 4263149Seric } 4273149Seric /* 4283149Seric ** TOKTYPE -- return token type 4293149Seric ** 4303149Seric ** Parameters: 4313149Seric ** c -- the character in question. 4323149Seric ** 4333149Seric ** Returns: 4343149Seric ** Its type. 4353149Seric ** 4363149Seric ** Side Effects: 4373149Seric ** none. 4383149Seric */ 439297Seric 4403149Seric toktype(c) 4413149Seric register char c; 4423149Seric { 4433380Seric static char buf[50]; 4443382Seric static bool firstime = TRUE; 4453380Seric 4463382Seric if (firstime) 4473380Seric { 4483382Seric firstime = FALSE; 4493380Seric expand("$o", buf, &buf[sizeof buf - 1]); 4503380Seric strcat(buf, DELIMCHARS); 4513380Seric } 4523149Seric if (isspace(c)) 4533149Seric return (SPACE); 4543380Seric if (iscntrl(c) || index(buf, c) != NULL) 4553149Seric return (OPER); 4563149Seric return (ATOM); 4573149Seric } 4583149Seric /* 4593149Seric ** REWRITE -- apply rewrite rules to token vector. 4603149Seric ** 4613149Seric ** Parameters: 4623149Seric ** pvp -- pointer to token vector. 4633149Seric ** 4643149Seric ** Returns: 4653149Seric ** none. 4663149Seric ** 4673149Seric ** Side Effects: 4683149Seric ** pvp is modified. 4693149Seric */ 4702091Seric 4713149Seric struct match 4723149Seric { 4733149Seric char **firsttok; /* first token matched */ 4743149Seric char **lasttok; /* last token matched */ 4753149Seric char name; /* name of parameter */ 4763149Seric }; 4773149Seric 4783149Seric # define MAXMATCH 8 /* max params per rewrite */ 4793149Seric 4803149Seric 4813149Seric rewrite(pvp) 4823149Seric char **pvp; 4833149Seric { 4843149Seric register char *ap; /* address pointer */ 4853149Seric register char *rp; /* rewrite pointer */ 4863149Seric register char **avp; /* address vector pointer */ 4873149Seric register char **rvp; /* rewrite vector pointer */ 4883149Seric struct rewrite *rwr; 4893149Seric struct match mlist[MAXMATCH]; 4903149Seric char *npvp[MAXATOM+1]; /* temporary space for rebuild */ 491*4060Seric extern bool sameword(); 4923149Seric 4933188Seric # ifdef DEBUGX 4943149Seric if (Debug) 4953149Seric { 4963149Seric printf("rewrite: original pvp:\n"); 4973149Seric printav(pvp); 4983149Seric } 4993188Seric # endif DEBUGX 5003149Seric 5013149Seric /* 5023149Seric ** Run through the list of rewrite rules, applying 5033149Seric ** any that match. 5043149Seric */ 5053149Seric 5063149Seric for (rwr = RewriteRules; rwr != NULL; ) 5073149Seric { 5083188Seric # ifdef DEBUGX 5093149Seric if (Debug) 510297Seric { 5113149Seric printf("-----trying rule:\n"); 5123149Seric printav(rwr->r_lhs); 5133149Seric } 5143188Seric # endif DEBUGX 5153149Seric 5163149Seric /* try to match on this rule */ 5173149Seric clrmatch(mlist); 5183149Seric for (rvp = rwr->r_lhs, avp = pvp; *avp != NULL; ) 5193149Seric { 5203149Seric ap = *avp; 5213149Seric rp = *rvp; 5223149Seric 5233149Seric if (rp == NULL) 524297Seric { 5253149Seric /* end-of-pattern before end-of-address */ 5263149Seric goto fail; 527297Seric } 5283149Seric 5293149Seric switch (*rp) 5303149Seric { 531*4060Seric register STAB *s; 532*4060Seric register int class; 533*4060Seric 5343149Seric case MATCHONE: 5353149Seric /* match exactly one token */ 5363149Seric setmatch(mlist, rp[1], avp, avp); 5373149Seric break; 5383149Seric 5393149Seric case MATCHANY: 5403149Seric /* match any number of tokens */ 5413149Seric setmatch(mlist, rp[1], NULL, avp); 5423149Seric break; 5433149Seric 544*4060Seric case MATCHCLASS: 545*4060Seric /* match any token in a class */ 546*4060Seric class = rp[1]; 547*4060Seric if (!isalpha(class)) 548*4060Seric goto fail; 549*4060Seric if (isupper(class)) 550*4060Seric class -= 'A'; 551*4060Seric else 552*4060Seric class -= 'a'; 553*4060Seric s = stab(ap, ST_FIND); 554*4060Seric if (s == NULL || (s->s_class & (1 << class)) == 0) 555*4060Seric goto fail; 556*4060Seric break; 557*4060Seric 5583149Seric default: 5593149Seric /* must have exact match */ 560*4060Seric if (!sameword(rp, ap)) 561*4060Seric goto fail; 5623149Seric break; 5633149Seric } 5643149Seric 5653149Seric /* successful match on this token */ 5663149Seric avp++; 5673149Seric rvp++; 5683149Seric continue; 5693149Seric 5703149Seric fail: 5713149Seric /* match failed -- back up */ 5723149Seric while (--rvp >= rwr->r_lhs) 5733149Seric { 5743149Seric rp = *rvp; 5753149Seric if (*rp == MATCHANY) 5763149Seric break; 5773149Seric 5783149Seric /* can't extend match: back up everything */ 5793149Seric avp--; 5803149Seric 5813149Seric if (*rp == MATCHONE) 5823149Seric { 5833149Seric /* undo binding */ 5843149Seric setmatch(mlist, rp[1], NULL, NULL); 5853149Seric } 5863149Seric } 5873149Seric 5883149Seric if (rvp < rwr->r_lhs) 5893149Seric { 5903149Seric /* total failure to match */ 5913149Seric break; 5923149Seric } 593297Seric } 5943149Seric 5953149Seric /* 5963149Seric ** See if we successfully matched 5973149Seric */ 5983149Seric 5993149Seric if (rvp >= rwr->r_lhs && *rvp == NULL) 6003149Seric { 6013188Seric # ifdef DEBUGX 6023149Seric if (Debug) 6033149Seric { 6043149Seric printf("-----rule matches:\n"); 6053149Seric printav(rwr->r_rhs); 6063149Seric } 6073188Seric # endif DEBUGX 6083149Seric 6093149Seric /* substitute */ 6103149Seric for (rvp = rwr->r_rhs, avp = npvp; *rvp != NULL; rvp++) 6113149Seric { 6123149Seric rp = *rvp; 6133149Seric if (*rp == MATCHANY) 6143149Seric { 6153149Seric register struct match *m; 6163149Seric register char **pp; 6173149Seric extern struct match *findmatch(); 6183149Seric 6193149Seric m = findmatch(mlist, rp[1]); 6203149Seric if (m != NULL) 6213149Seric { 6223149Seric pp = m->firsttok; 6233149Seric do 6243149Seric { 6253149Seric *avp++ = *pp; 6263149Seric } while (pp++ != m->lasttok); 6273149Seric } 6283149Seric } 6293149Seric else 6303149Seric *avp++ = rp; 6313149Seric } 6323149Seric *avp++ = NULL; 6333149Seric bmove(npvp, pvp, (avp - npvp) * sizeof *avp); 6343149Seric # ifdef DEBUG 6353149Seric if (Debug) 6363149Seric { 6373188Seric char **vp; 6383188Seric 6393188Seric printf("rewritten as `"); 6403188Seric for (vp = pvp; *vp != NULL; vp++) 6413188Seric xputs(*vp); 6423188Seric printf("'\n"); 6433149Seric } 6443149Seric # endif DEBUG 6453149Seric if (pvp[0][0] == CANONNET) 6463149Seric break; 6473149Seric } 6483149Seric else 6493149Seric { 6503188Seric # ifdef DEBUGX 6513149Seric if (Debug) 6523149Seric printf("----- rule fails\n"); 6533188Seric # endif DEBUGX 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 extern char *xalloc(); 7903149Seric 7913149Seric if (a == NULL) 7923149Seric a = (ADDRESS *) xalloc(sizeof *a); 7933188Seric a->q_flags = 0; 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++; 8103149Seric if (!bitset(M_NOHOST, 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"); 8243149Seric buf[0] = '\0'; 8253149Seric while (**++tv != NULL) 8263149Seric strcat(buf, *tv); 8273149Seric a->q_user = buf; 8283149Seric 8293149Seric return (a); 8303149Seric } 8313188Seric /* 8323188Seric ** SAMEADDR -- Determine if two addresses are the same 8333188Seric ** 8343188Seric ** This is not just a straight comparison -- if the mailer doesn't 8353188Seric ** care about the host we just ignore it, etc. 8363188Seric ** 8373188Seric ** Parameters: 8383188Seric ** a, b -- pointers to the internal forms to compare. 8393188Seric ** wildflg -- if TRUE, 'a' may have no user specified, 8403188Seric ** in which case it is to match anything. 8413188Seric ** 8423188Seric ** Returns: 8433188Seric ** TRUE -- they represent the same mailbox. 8443188Seric ** FALSE -- they don't. 8453188Seric ** 8463188Seric ** Side Effects: 8473188Seric ** none. 8483188Seric */ 8493188Seric 8503188Seric bool 8513188Seric sameaddr(a, b, wildflg) 8523188Seric register ADDRESS *a; 8533188Seric register ADDRESS *b; 8543188Seric bool wildflg; 8553188Seric { 8563188Seric /* if they don't have the same mailer, forget it */ 8573188Seric if (a->q_mailer != b->q_mailer) 8583188Seric return (FALSE); 8593188Seric 8603188Seric /* if the user isn't the same, we can drop out */ 8613188Seric if ((!wildflg || a->q_user[0] != '\0') && strcmp(a->q_user, b->q_user) != 0) 8623188Seric return (FALSE); 8633188Seric 8643188Seric /* if the mailer ignores hosts, we have succeeded! */ 8653188Seric if (bitset(M_NOHOST, Mailer[a->q_mailer]->m_flags)) 8663188Seric return (TRUE); 8673188Seric 8683188Seric /* otherwise compare hosts (but be careful for NULL ptrs) */ 8693188Seric if (a->q_host == NULL || b->q_host == NULL) 8703188Seric return (FALSE); 8713188Seric if (strcmp(a->q_host, b->q_host) != 0) 8723188Seric return (FALSE); 8733188Seric 8743188Seric return (TRUE); 8753188Seric } 8763234Seric /* 8773234Seric ** PRINTADDR -- print address (for debugging) 8783234Seric ** 8793234Seric ** Parameters: 8803234Seric ** a -- the address to print 8813234Seric ** follow -- follow the q_next chain. 8823234Seric ** 8833234Seric ** Returns: 8843234Seric ** none. 8853234Seric ** 8863234Seric ** Side Effects: 8873234Seric ** none. 8883234Seric */ 8893234Seric 8903234Seric printaddr(a, follow) 8913234Seric register ADDRESS *a; 8923234Seric bool follow; 8933234Seric { 8943234Seric while (a != NULL) 8953234Seric { 8963234Seric printf("addr@%x: ", a); 8973234Seric fflush(stdout); 8983234Seric printf("%s: mailer %d (%s), host `%s', user `%s'\n", a->q_paddr, 8993234Seric a->q_mailer, Mailer[a->q_mailer]->m_name, a->q_host, a->q_user); 9003234Seric printf("\tnext=%x flags=%o, rmailer %d\n", a->q_next, 9013234Seric a->q_flags, a->q_rmailer); 9023234Seric 9033234Seric if (!follow) 9043234Seric return; 9053234Seric a = a->q_next; 9063234Seric } 9073234Seric } 908