13312Seric # include "sendmail.h" 2297Seric 3*4317Seric static char SccsId[] = "@(#)parseaddr.c 3.23 09/06/81"; 4407Seric 5297Seric /* 6297Seric ** PARSE -- Parse an address 7297Seric ** 8297Seric ** Parses an address and breaks it up into three parts: a 9297Seric ** net to transmit the message on, the host to transmit it 10297Seric ** to, and a user on that host. These are loaded into an 112973Seric ** ADDRESS header with the values squirreled away if necessary. 12297Seric ** The "user" part may not be a real user; the process may 13297Seric ** just reoccur on that machine. For example, on a machine 14297Seric ** with an arpanet connection, the address 15297Seric ** csvax.bill@berkeley 16297Seric ** will break up to a "user" of 'csvax.bill' and a host 17297Seric ** of 'berkeley' -- to be transmitted over the arpanet. 18297Seric ** 19297Seric ** Parameters: 20297Seric ** addr -- the address to parse. 21297Seric ** a -- a pointer to the address descriptor buffer. 22297Seric ** If NULL, a header will be created. 23297Seric ** copyf -- determines what shall be copied: 24297Seric ** -1 -- don't copy anything. The printname 25297Seric ** (q_paddr) is just addr, and the 26297Seric ** user & host are allocated internally 27297Seric ** to parse. 28297Seric ** 0 -- copy out the parsed user & host, but 29297Seric ** don't copy the printname. 30297Seric ** +1 -- copy everything. 31297Seric ** 32297Seric ** Returns: 33297Seric ** A pointer to the address descriptor header (`a' if 34297Seric ** `a' is non-NULL). 35297Seric ** NULL on error. 36297Seric ** 37297Seric ** Side Effects: 38297Seric ** none 39297Seric */ 40297Seric 413380Seric # define DELIMCHARS "$()<>,;\\\"\r\n" /* word delimiters */ 422091Seric # define SPACESUB ('.'|0200) /* substitution for <lwsp> */ 432091Seric 442973Seric ADDRESS * 45297Seric parse(addr, a, copyf) 46297Seric char *addr; 472973Seric register ADDRESS *a; 48297Seric int copyf; 49297Seric { 503149Seric register char **pvp; 513149Seric register struct mailer *m; 523149Seric extern char **prescan(); 533149Seric extern ADDRESS *buildaddr(); 54297Seric 55297Seric /* 56297Seric ** Initialize and prescan address. 57297Seric */ 58297Seric 59297Seric To = addr; 603188Seric # ifdef DEBUG 613188Seric if (Debug) 623188Seric printf("\n--parse(%s)\n", addr); 633188Seric # endif DEBUG 643188Seric 653149Seric pvp = prescan(addr, '\0'); 663149Seric if (pvp == NULL) 67297Seric return (NULL); 68297Seric 69297Seric /* 703149Seric ** Apply rewriting rules. 71297Seric */ 72297Seric 734070Seric rewrite(pvp, 0); 74297Seric 753149Seric /* 763149Seric ** See if we resolved to a real mailer. 773149Seric */ 78297Seric 793149Seric if (pvp[0][0] != CANONNET) 803149Seric { 813149Seric setstat(EX_USAGE); 823149Seric usrerr("cannot resolve name"); 833149Seric return (NULL); 84297Seric } 85297Seric 86297Seric /* 873149Seric ** Build canonical address from pvp. 88297Seric */ 89297Seric 903149Seric a = buildaddr(pvp, a); 914279Seric if (a == NULL) 924279Seric return (NULL); 933149Seric m = Mailer[a->q_mailer]; 94297Seric 95297Seric /* 963149Seric ** Make local copies of the host & user and then 973149Seric ** transport them out. 98297Seric */ 99297Seric 100297Seric if (copyf > 0) 1012973Seric a->q_paddr = newstr(addr); 102297Seric else 103297Seric a->q_paddr = addr; 104297Seric 1053149Seric if (copyf >= 0) 106297Seric { 1073149Seric if (a->q_host != NULL) 1083149Seric a->q_host = newstr(a->q_host); 109297Seric else 1103149Seric a->q_host = ""; 1113149Seric if (a->q_user != a->q_paddr) 1123149Seric a->q_user = newstr(a->q_user); 113297Seric } 114297Seric 115297Seric /* 116297Seric ** Do UPPER->lower case mapping unless inhibited. 117297Seric */ 118297Seric 1193149Seric if (!bitset(M_HST_UPPER, m->m_flags)) 120297Seric makelower(a->q_host); 1213149Seric if (!bitset(M_USR_UPPER, m->m_flags)) 122297Seric makelower(a->q_user); 123297Seric 124297Seric /* 125297Seric ** Compute return value. 126297Seric */ 127297Seric 128297Seric # ifdef DEBUG 1291583Seric if (Debug) 130297Seric printf("parse(\"%s\"): host \"%s\" user \"%s\" mailer %d\n", 1313149Seric addr, a->q_host, a->q_user, a->q_mailer); 132297Seric # endif DEBUG 133297Seric 134297Seric return (a); 135297Seric } 136297Seric /* 137297Seric ** PRESCAN -- Prescan name and make it canonical 138297Seric ** 139297Seric ** Scans a name and turns it into canonical form. This involves 140297Seric ** deleting blanks, comments (in parentheses), and turning the 141297Seric ** word "at" into an at-sign ("@"). The name is copied as this 142297Seric ** is done; it is legal to copy a name onto itself, since this 143297Seric ** process can only make things smaller. 144297Seric ** 145297Seric ** This routine knows about quoted strings and angle brackets. 146297Seric ** 147297Seric ** There are certain subtleties to this routine. The one that 148297Seric ** comes to mind now is that backslashes on the ends of names 149297Seric ** are silently stripped off; this is intentional. The problem 150297Seric ** is that some versions of sndmsg (like at LBL) set the kill 151297Seric ** character to something other than @ when reading addresses; 152297Seric ** so people type "csvax.eric\@berkeley" -- which screws up the 153297Seric ** berknet mailer. 154297Seric ** 155297Seric ** Parameters: 156297Seric ** addr -- the name to chomp. 157297Seric ** delim -- the delimiter for the address, normally 158297Seric ** '\0' or ','; \0 is accepted in any case. 159297Seric ** are moving in place; set buflim to high core. 160297Seric ** 161297Seric ** Returns: 1623149Seric ** A pointer to a vector of tokens. 163297Seric ** NULL on error. 164297Seric ** 165297Seric ** Side Effects: 1663149Seric ** none. 167297Seric */ 168297Seric 1693149Seric # define OPER 1 1703149Seric # define ATOM 2 1713149Seric # define EOTOK 3 1723149Seric # define QSTRING 4 1733149Seric # define SPACE 5 1743149Seric # define DOLLAR 6 1753149Seric # define GETONE 7 1763149Seric 1773149Seric char ** 1783149Seric prescan(addr, delim) 179297Seric char *addr; 180297Seric char delim; 181297Seric { 182297Seric register char *p; 1833149Seric static char buf[MAXNAME+MAXATOM]; 1843149Seric static char *av[MAXATOM+1]; 1853149Seric char **avp; 186297Seric bool bslashmode; 187297Seric int cmntcnt; 188297Seric int brccnt; 189297Seric register char c; 1903149Seric char *tok; 191297Seric register char *q; 1923149Seric register int state; 1933149Seric int nstate; 1944085Seric extern char lower(); 195297Seric 196297Seric q = buf; 1973149Seric bslashmode = FALSE; 198297Seric cmntcnt = brccnt = 0; 1993149Seric avp = av; 2003149Seric state = OPER; 2013149Seric for (p = addr; *p != '\0' && *p != delim; ) 202297Seric { 2033149Seric /* read a token */ 2043149Seric tok = q; 2053149Seric while ((c = *p++) != '\0' && c != delim) 206297Seric { 2073149Seric /* chew up special characters */ 2084100Seric c &= ~0200; 2093149Seric *q = '\0'; 2103149Seric if (bslashmode) 2113149Seric { 2123149Seric c |= 0200; 2133149Seric bslashmode = FALSE; 2143149Seric } 2153149Seric else if (c == '\\') 2163149Seric { 2173149Seric bslashmode = TRUE; 2183149Seric continue; 2193149Seric } 2204100Seric else if (c == '"') 2214100Seric { 2224100Seric if (state == QSTRING) 2234100Seric state = OPER; 2244100Seric else 2254100Seric state = QSTRING; 2264100Seric break; 2274100Seric } 2283149Seric 2293149Seric nstate = toktype(c); 2303149Seric switch (state) 2313149Seric { 2323149Seric case QSTRING: /* in quoted string */ 2333149Seric break; 2343149Seric 2353149Seric case ATOM: /* regular atom */ 2364228Seric /* state = nstate; */ 2374228Seric if (nstate != ATOM) 2383149Seric { 2393149Seric state = EOTOK; 2403149Seric p--; 2413149Seric } 2423149Seric break; 2433149Seric 2443149Seric case GETONE: /* grab one character */ 2453149Seric state = OPER; 2463149Seric break; 2473149Seric 2483149Seric case EOTOK: /* after atom or q-string */ 2493149Seric state = nstate; 2503149Seric if (state == SPACE) 2513149Seric continue; 2523149Seric break; 2533149Seric 2543149Seric case SPACE: /* linear white space */ 2553149Seric state = nstate; 2564228Seric break; 2573149Seric 2583149Seric case OPER: /* operator */ 2593149Seric if (nstate == SPACE) 2603149Seric continue; 2613149Seric state = nstate; 2623149Seric break; 2633149Seric 2643149Seric case DOLLAR: /* $- etc. */ 2653149Seric state = OPER; 2663149Seric switch (c) 2673149Seric { 2683149Seric case '$': /* literal $ */ 2693149Seric break; 2703149Seric 2713149Seric case '+': /* match anything */ 2723149Seric c = MATCHANY; 2733149Seric state = GETONE; 2743149Seric break; 2753149Seric 2763149Seric case '-': /* match one token */ 2773149Seric c = MATCHONE; 2783149Seric state = GETONE; 2793149Seric break; 2803149Seric 2814060Seric case '=': /* match one token of class */ 2824060Seric c = MATCHCLASS; 2834060Seric state = GETONE; 2844060Seric break; 2854060Seric 2863149Seric case '#': /* canonical net name */ 2873149Seric c = CANONNET; 2883149Seric break; 2893149Seric 2903149Seric case '@': /* canonical host name */ 2913149Seric c = CANONHOST; 2923149Seric break; 2933149Seric 2943149Seric case ':': /* canonical user name */ 2953149Seric c = CANONUSER; 2963149Seric break; 2973149Seric 2983149Seric default: 2993149Seric c = '$'; 3003149Seric state = OPER; 3013149Seric p--; 3023149Seric break; 3033149Seric } 3043149Seric break; 3053149Seric 3063149Seric default: 3073149Seric syserr("prescan: unknown state %d", state); 3083149Seric } 3093149Seric 3104228Seric if (state == EOTOK || state == SPACE) 3113149Seric break; 3123149Seric if (c == '$' && delim == '\t') 3133149Seric { 3143149Seric state = DOLLAR; 3153149Seric continue; 3163149Seric } 3173149Seric 3183149Seric /* squirrel it away */ 3193149Seric if (q >= &buf[sizeof buf - 5]) 3203149Seric { 3213149Seric usrerr("Address too long"); 3223149Seric return (NULL); 3233149Seric } 3243149Seric *q++ = c; 3253149Seric 3263149Seric /* decide whether this represents end of token */ 3273149Seric if (state == OPER) 3283149Seric break; 329297Seric } 3303149Seric if (c == '\0' || c == delim) 3313149Seric p--; 3323149Seric 3333149Seric /* new token */ 3343149Seric if (tok == q) 335297Seric continue; 3363149Seric *q++ = '\0'; 3373149Seric 3383149Seric c = tok[0]; 3393149Seric if (c == '(') 3401378Seric { 341297Seric cmntcnt++; 3421378Seric continue; 3431378Seric } 344297Seric else if (c == ')') 345297Seric { 346297Seric if (cmntcnt <= 0) 347297Seric { 348297Seric usrerr("Unbalanced ')'"); 349297Seric return (NULL); 350297Seric } 351297Seric else 352297Seric { 353297Seric cmntcnt--; 354297Seric continue; 355297Seric } 356297Seric } 3573149Seric else if (cmntcnt > 0) 3582091Seric continue; 3593149Seric 3603149Seric *avp++ = tok; 3613149Seric 3623149Seric /* we prefer <> specs */ 3633149Seric if (c == '<') 364297Seric { 3652092Seric if (brccnt < 0) 3662092Seric { 3672092Seric usrerr("multiple < spec"); 3682092Seric return (NULL); 3692092Seric } 370297Seric brccnt++; 371297Seric if (brccnt == 1) 372297Seric { 373297Seric /* we prefer using machine readable name */ 374297Seric q = buf; 375297Seric *q = '\0'; 3763149Seric avp = av; 377297Seric continue; 378297Seric } 379297Seric } 380297Seric else if (c == '>') 381297Seric { 382297Seric if (brccnt <= 0) 383297Seric { 384297Seric usrerr("Unbalanced `>'"); 385297Seric return (NULL); 386297Seric } 387297Seric else 388297Seric brccnt--; 389297Seric if (brccnt <= 0) 3902092Seric { 3912092Seric brccnt = -1; 392297Seric continue; 3932092Seric } 394297Seric } 3953149Seric } 3963149Seric *avp = NULL; 3973149Seric if (cmntcnt > 0) 3983149Seric usrerr("Unbalanced '('"); 3993149Seric else if (brccnt > 0) 4003149Seric usrerr("Unbalanced '<'"); 4013149Seric else if (state == QSTRING) 4023149Seric usrerr("Unbalanced '\"'"); 4033149Seric else if (av[0] != NULL) 4043149Seric return (av); 4053149Seric return (NULL); 4063149Seric } 4073149Seric /* 4083149Seric ** TOKTYPE -- return token type 4093149Seric ** 4103149Seric ** Parameters: 4113149Seric ** c -- the character in question. 4123149Seric ** 4133149Seric ** Returns: 4143149Seric ** Its type. 4153149Seric ** 4163149Seric ** Side Effects: 4173149Seric ** none. 4183149Seric */ 419297Seric 4203149Seric toktype(c) 4213149Seric register char c; 4223149Seric { 4233380Seric static char buf[50]; 4243382Seric static bool firstime = TRUE; 4253380Seric 4263382Seric if (firstime) 4273380Seric { 4283382Seric firstime = FALSE; 4294085Seric (void) expand("$o", buf, &buf[sizeof buf - 1]); 4303380Seric strcat(buf, DELIMCHARS); 4313380Seric } 4324100Seric if (!isascii(c)) 4334100Seric return (ATOM); 4343149Seric if (isspace(c)) 4353149Seric return (SPACE); 4363380Seric if (iscntrl(c) || index(buf, c) != NULL) 4373149Seric return (OPER); 4383149Seric return (ATOM); 4393149Seric } 4403149Seric /* 4413149Seric ** REWRITE -- apply rewrite rules to token vector. 4423149Seric ** 4433149Seric ** Parameters: 4443149Seric ** pvp -- pointer to token vector. 4453149Seric ** 4463149Seric ** Returns: 4473149Seric ** none. 4483149Seric ** 4493149Seric ** Side Effects: 4503149Seric ** pvp is modified. 4513149Seric */ 4522091Seric 4533149Seric struct match 4543149Seric { 4553149Seric char **firsttok; /* first token matched */ 4563149Seric char **lasttok; /* last token matched */ 4573149Seric char name; /* name of parameter */ 4583149Seric }; 4593149Seric 4603149Seric # define MAXMATCH 8 /* max params per rewrite */ 4613149Seric 4623149Seric 4634070Seric rewrite(pvp, ruleset) 4643149Seric char **pvp; 4654070Seric int ruleset; 4663149Seric { 4673149Seric register char *ap; /* address pointer */ 4683149Seric register char *rp; /* rewrite pointer */ 4693149Seric register char **avp; /* address vector pointer */ 4703149Seric register char **rvp; /* rewrite vector pointer */ 4713149Seric struct rewrite *rwr; 4723149Seric struct match mlist[MAXMATCH]; 4733149Seric char *npvp[MAXATOM+1]; /* temporary space for rebuild */ 4744060Seric extern bool sameword(); 4753149Seric 4764100Seric # ifdef DEBUG 4774228Seric if (Debug > 9) 4783149Seric { 4793149Seric printf("rewrite: original pvp:\n"); 4803149Seric printav(pvp); 4813149Seric } 4824100Seric # endif DEBUG 4833149Seric 4843149Seric /* 4853149Seric ** Run through the list of rewrite rules, applying 4863149Seric ** any that match. 4873149Seric */ 4883149Seric 4894070Seric for (rwr = RewriteRules[ruleset]; rwr != NULL; ) 4903149Seric { 4914100Seric # ifdef DEBUG 4924100Seric if (Debug > 10) 493297Seric { 4943149Seric printf("-----trying rule:\n"); 4953149Seric printav(rwr->r_lhs); 4963149Seric } 4974100Seric # endif DEBUG 4983149Seric 4993149Seric /* try to match on this rule */ 5003149Seric clrmatch(mlist); 5013149Seric for (rvp = rwr->r_lhs, avp = pvp; *avp != NULL; ) 5023149Seric { 5033149Seric ap = *avp; 5043149Seric rp = *rvp; 5053149Seric 5063149Seric if (rp == NULL) 507297Seric { 5083149Seric /* end-of-pattern before end-of-address */ 5093149Seric goto fail; 510297Seric } 5113149Seric 5123149Seric switch (*rp) 5133149Seric { 5144060Seric register STAB *s; 5154060Seric register int class; 5164060Seric 5173149Seric case MATCHONE: 5183149Seric /* match exactly one token */ 5193149Seric setmatch(mlist, rp[1], avp, avp); 5203149Seric break; 5213149Seric 5223149Seric case MATCHANY: 5233149Seric /* match any number of tokens */ 5244085Seric setmatch(mlist, rp[1], (char **) NULL, avp); 5253149Seric break; 5263149Seric 5274060Seric case MATCHCLASS: 5284060Seric /* match any token in a class */ 5294060Seric class = rp[1]; 5304060Seric if (!isalpha(class)) 5314060Seric goto fail; 5324060Seric if (isupper(class)) 5334060Seric class -= 'A'; 5344060Seric else 5354060Seric class -= 'a'; 5364100Seric s = stab(ap, ST_CLASS, ST_FIND); 5374060Seric if (s == NULL || (s->s_class & (1 << class)) == 0) 5384060Seric goto fail; 5394060Seric break; 5404060Seric 5413149Seric default: 5423149Seric /* must have exact match */ 5434060Seric if (!sameword(rp, ap)) 5444060Seric goto fail; 5453149Seric break; 5463149Seric } 5473149Seric 5483149Seric /* successful match on this token */ 5493149Seric avp++; 5503149Seric rvp++; 5513149Seric continue; 5523149Seric 5533149Seric fail: 5543149Seric /* match failed -- back up */ 5553149Seric while (--rvp >= rwr->r_lhs) 5563149Seric { 5573149Seric rp = *rvp; 5583149Seric if (*rp == MATCHANY) 5593149Seric break; 5603149Seric 5613149Seric /* can't extend match: back up everything */ 5623149Seric avp--; 5633149Seric 5643149Seric if (*rp == MATCHONE) 5653149Seric { 5663149Seric /* undo binding */ 5674085Seric setmatch(mlist, rp[1], (char **) NULL, (char **) NULL); 5683149Seric } 5693149Seric } 5703149Seric 5713149Seric if (rvp < rwr->r_lhs) 5723149Seric { 5733149Seric /* total failure to match */ 5743149Seric break; 5753149Seric } 576297Seric } 5773149Seric 5783149Seric /* 5793149Seric ** See if we successfully matched 5803149Seric */ 5813149Seric 5823149Seric if (rvp >= rwr->r_lhs && *rvp == NULL) 5833149Seric { 5844100Seric # ifdef DEBUG 5854100Seric if (Debug > 10) 5863149Seric { 5873149Seric printf("-----rule matches:\n"); 5883149Seric printav(rwr->r_rhs); 5893149Seric } 5904100Seric # endif DEBUG 5913149Seric 5923149Seric /* substitute */ 5933149Seric for (rvp = rwr->r_rhs, avp = npvp; *rvp != NULL; rvp++) 5943149Seric { 5953149Seric rp = *rvp; 5963149Seric if (*rp == MATCHANY) 5973149Seric { 5983149Seric register struct match *m; 5993149Seric register char **pp; 6003149Seric extern struct match *findmatch(); 6013149Seric 6023149Seric m = findmatch(mlist, rp[1]); 6033149Seric if (m != NULL) 6043149Seric { 6053149Seric pp = m->firsttok; 6063149Seric do 6073149Seric { 6083149Seric *avp++ = *pp; 6093149Seric } while (pp++ != m->lasttok); 6103149Seric } 6113149Seric } 6123149Seric else 6133149Seric *avp++ = rp; 6143149Seric } 6153149Seric *avp++ = NULL; 6164085Seric bmove((char *) npvp, (char *) pvp, (avp - npvp) * sizeof *avp); 6173149Seric # ifdef DEBUG 6184228Seric if (Debug > 3) 6193149Seric { 6203188Seric char **vp; 6213188Seric 6223188Seric printf("rewritten as `"); 6233188Seric for (vp = pvp; *vp != NULL; vp++) 6244228Seric { 6254228Seric if (vp != pvp) 6264228Seric printf("_"); 6273188Seric xputs(*vp); 6284228Seric } 6293188Seric printf("'\n"); 6303149Seric } 6313149Seric # endif DEBUG 6323149Seric if (pvp[0][0] == CANONNET) 6333149Seric break; 6343149Seric } 6353149Seric else 6363149Seric { 6374100Seric # ifdef DEBUG 6384100Seric if (Debug > 10) 6393149Seric printf("----- rule fails\n"); 6404100Seric # endif DEBUG 6413149Seric rwr = rwr->r_next; 6423149Seric } 643297Seric } 6443149Seric } 6453149Seric /* 6463149Seric ** SETMATCH -- set parameter value in match vector 6473149Seric ** 6483149Seric ** Parameters: 6493149Seric ** mlist -- list of match values. 6503149Seric ** name -- the character name of this parameter. 6513149Seric ** first -- the first location of the replacement. 6523149Seric ** last -- the last location of the replacement. 6533149Seric ** 6543149Seric ** If last == NULL, delete this entry. 6553149Seric ** If first == NULL, extend this entry (or add it if 6563149Seric ** it does not exist). 6573149Seric ** 6583149Seric ** Returns: 6593149Seric ** nothing. 6603149Seric ** 6613149Seric ** Side Effects: 6623149Seric ** munges with mlist. 6633149Seric */ 6643149Seric 6653149Seric setmatch(mlist, name, first, last) 6663149Seric struct match *mlist; 6673149Seric char name; 6683149Seric char **first; 6693149Seric char **last; 6703149Seric { 6713149Seric register struct match *m; 6723149Seric struct match *nullm = NULL; 6733149Seric 6743149Seric for (m = mlist; m < &mlist[MAXMATCH]; m++) 6753149Seric { 6763149Seric if (m->name == name) 6773149Seric break; 6783149Seric if (m->name == '\0') 6793149Seric nullm = m; 6803149Seric } 6813149Seric 6823149Seric if (m >= &mlist[MAXMATCH]) 6833149Seric m = nullm; 6843149Seric 6853149Seric if (last == NULL) 6863149Seric { 6873149Seric m->name = '\0'; 6883149Seric return; 6893149Seric } 6903149Seric 6913149Seric if (m->name == '\0') 6923149Seric { 6933149Seric if (first == NULL) 6943149Seric m->firsttok = last; 6953149Seric else 6963149Seric m->firsttok = first; 6973149Seric } 6983149Seric m->name = name; 6993149Seric m->lasttok = last; 7003149Seric } 7013149Seric /* 7023149Seric ** FINDMATCH -- find match in mlist 7033149Seric ** 7043149Seric ** Parameters: 7053149Seric ** mlist -- list to search. 7063149Seric ** name -- name to find. 7073149Seric ** 7083149Seric ** Returns: 7093149Seric ** pointer to match structure. 7103149Seric ** NULL if no match. 7113149Seric ** 7123149Seric ** Side Effects: 7133149Seric ** none. 7143149Seric */ 7153149Seric 7163149Seric struct match * 7173149Seric findmatch(mlist, name) 7183149Seric struct match *mlist; 7193149Seric char name; 7203149Seric { 7213149Seric register struct match *m; 7223149Seric 7233149Seric for (m = mlist; m < &mlist[MAXMATCH]; m++) 7243149Seric { 7253149Seric if (m->name == name) 7263149Seric return (m); 7273149Seric } 7283149Seric 729297Seric return (NULL); 730297Seric } 7313149Seric /* 7323149Seric ** CLRMATCH -- clear match list 7333149Seric ** 7343149Seric ** Parameters: 7353149Seric ** mlist -- list to clear. 7363149Seric ** 7373149Seric ** Returns: 7383149Seric ** none. 7393149Seric ** 7403149Seric ** Side Effects: 7413149Seric ** mlist is cleared. 7423149Seric */ 7433149Seric 7443149Seric clrmatch(mlist) 7453149Seric struct match *mlist; 7463149Seric { 7473149Seric register struct match *m; 7483149Seric 7493149Seric for (m = mlist; m < &mlist[MAXMATCH]; m++) 7503149Seric m->name = '\0'; 7513149Seric } 7523149Seric /* 7533149Seric ** BUILDADDR -- build address from token vector. 7543149Seric ** 7553149Seric ** Parameters: 7563149Seric ** tv -- token vector. 7573149Seric ** a -- pointer to address descriptor to fill. 7583149Seric ** If NULL, one will be allocated. 7593149Seric ** 7603149Seric ** Returns: 7614279Seric ** NULL if there was an error. 7624279Seric ** 'a' otherwise. 7633149Seric ** 7643149Seric ** Side Effects: 7653149Seric ** fills in 'a' 7663149Seric */ 7673149Seric 7683149Seric ADDRESS * 7693149Seric buildaddr(tv, a) 7703149Seric register char **tv; 7713149Seric register ADDRESS *a; 7723149Seric { 7733149Seric register int i; 7743149Seric static char buf[MAXNAME]; 7753149Seric struct mailer **mp; 7763149Seric register struct mailer *m; 7773149Seric 7783149Seric if (a == NULL) 7793149Seric a = (ADDRESS *) xalloc(sizeof *a); 7803188Seric a->q_flags = 0; 7814079Seric a->q_home = NULL; 7823149Seric 7833149Seric /* figure out what net/mailer to use */ 7843149Seric if (**tv != CANONNET) 7854279Seric { 7863149Seric syserr("buildaddr: no net"); 7874279Seric return (NULL); 7884279Seric } 7893149Seric tv++; 7904279Seric if (strcmp(*tv, "error") == 0) 7914279Seric { 7924279Seric if (**++tv != CANONUSER) 7934279Seric syserr("buildaddr: error: no user"); 7944279Seric buf[0] = '\0'; 7954279Seric while (*++tv != NULL) 7964279Seric { 7974279Seric if (buf[0] != '\0') 7984279Seric strcat(buf, " "); 7994279Seric strcat(buf, *tv); 8004279Seric } 8014279Seric usrerr(buf); 8024279Seric return (NULL); 8034279Seric } 8043154Seric for (mp = Mailer, i = 0; (m = *mp++) != NULL; i++) 8053149Seric { 8063149Seric if (strcmp(m->m_name, *tv) == 0) 8073149Seric break; 8083149Seric } 8093149Seric if (m == NULL) 8104279Seric { 8113149Seric syserr("buildaddr: unknown net %s", *tv); 8124279Seric return (NULL); 8134279Seric } 8143149Seric a->q_mailer = i; 8153149Seric 8163149Seric /* figure out what host (if any) */ 8173149Seric tv++; 8184195Seric if (!bitset(M_LOCAL, m->m_flags)) 8193149Seric { 8203149Seric if (**tv != CANONHOST) 8214279Seric { 8223149Seric syserr("buildaddr: no host"); 8234279Seric return (NULL); 8244279Seric } 8253149Seric tv++; 8263149Seric a->q_host = *tv; 8273149Seric tv++; 8283149Seric } 8293149Seric else 8303149Seric a->q_host = NULL; 8313149Seric 8323149Seric /* figure out the user */ 8333149Seric if (**tv != CANONUSER) 8344279Seric { 8353149Seric syserr("buildaddr: no user"); 8364279Seric return (NULL); 8374279Seric } 8384228Seric cataddr(++tv, buf, sizeof buf); 8393149Seric a->q_user = buf; 8403149Seric 8413149Seric return (a); 8423149Seric } 8433188Seric /* 8444228Seric ** CATADDR -- concatenate pieces of addresses (putting in <LWSP> subs) 8454228Seric ** 8464228Seric ** Parameters: 8474228Seric ** pvp -- parameter vector to rebuild. 8484228Seric ** buf -- buffer to build the string into. 8494228Seric ** sz -- size of buf. 8504228Seric ** 8514228Seric ** Returns: 8524228Seric ** none. 8534228Seric ** 8544228Seric ** Side Effects: 8554228Seric ** Destroys buf. 8564228Seric */ 8574228Seric 8584228Seric cataddr(pvp, buf, sz) 8594228Seric char **pvp; 8604228Seric char *buf; 8614228Seric register int sz; 8624228Seric { 8634228Seric bool oatomtok = FALSE; 8644228Seric bool natomtok = FALSE; 8654228Seric register int i; 8664228Seric register char *p; 8674228Seric 8684228Seric p = buf; 8694228Seric sz--; 8704228Seric while (*pvp != NULL && (i = strlen(*pvp)) < sz) 8714228Seric { 8724228Seric natomtok = (toktype(**pvp) == ATOM); 8734228Seric if (oatomtok && natomtok) 8744228Seric *p++ = SPACESUB; 8754228Seric (void) strcpy(p, *pvp); 8764228Seric oatomtok = natomtok; 8774228Seric p += i; 8784228Seric sz -= i; 8794228Seric pvp++; 8804228Seric } 8814228Seric *p = '\0'; 8824228Seric } 8834228Seric /* 8843188Seric ** SAMEADDR -- Determine if two addresses are the same 8853188Seric ** 8863188Seric ** This is not just a straight comparison -- if the mailer doesn't 8873188Seric ** care about the host we just ignore it, etc. 8883188Seric ** 8893188Seric ** Parameters: 8903188Seric ** a, b -- pointers to the internal forms to compare. 8913188Seric ** wildflg -- if TRUE, 'a' may have no user specified, 8923188Seric ** in which case it is to match anything. 8933188Seric ** 8943188Seric ** Returns: 8953188Seric ** TRUE -- they represent the same mailbox. 8963188Seric ** FALSE -- they don't. 8973188Seric ** 8983188Seric ** Side Effects: 8993188Seric ** none. 9003188Seric */ 9013188Seric 9023188Seric bool 9033188Seric sameaddr(a, b, wildflg) 9043188Seric register ADDRESS *a; 9053188Seric register ADDRESS *b; 9063188Seric bool wildflg; 9073188Seric { 9083188Seric /* if they don't have the same mailer, forget it */ 9093188Seric if (a->q_mailer != b->q_mailer) 9103188Seric return (FALSE); 9113188Seric 9123188Seric /* if the user isn't the same, we can drop out */ 9133188Seric if ((!wildflg || a->q_user[0] != '\0') && strcmp(a->q_user, b->q_user) != 0) 9143188Seric return (FALSE); 9153188Seric 9163188Seric /* if the mailer ignores hosts, we have succeeded! */ 9174195Seric if (bitset(M_LOCAL, Mailer[a->q_mailer]->m_flags)) 9183188Seric return (TRUE); 9193188Seric 9203188Seric /* otherwise compare hosts (but be careful for NULL ptrs) */ 9213188Seric if (a->q_host == NULL || b->q_host == NULL) 9223188Seric return (FALSE); 9233188Seric if (strcmp(a->q_host, b->q_host) != 0) 9243188Seric return (FALSE); 9253188Seric 9263188Seric return (TRUE); 9273188Seric } 9283234Seric /* 9293234Seric ** PRINTADDR -- print address (for debugging) 9303234Seric ** 9313234Seric ** Parameters: 9323234Seric ** a -- the address to print 9333234Seric ** follow -- follow the q_next chain. 9343234Seric ** 9353234Seric ** Returns: 9363234Seric ** none. 9373234Seric ** 9383234Seric ** Side Effects: 9393234Seric ** none. 9403234Seric */ 9413234Seric 942*4317Seric # ifdef DEBUG 943*4317Seric 9443234Seric printaddr(a, follow) 9453234Seric register ADDRESS *a; 9463234Seric bool follow; 9473234Seric { 9483234Seric while (a != NULL) 9493234Seric { 9503234Seric printf("addr@%x: ", a); 9514085Seric (void) fflush(stdout); 9523234Seric printf("%s: mailer %d (%s), host `%s', user `%s'\n", a->q_paddr, 9533234Seric a->q_mailer, Mailer[a->q_mailer]->m_name, a->q_host, a->q_user); 9543234Seric printf("\tnext=%x flags=%o, rmailer %d\n", a->q_next, 9553234Seric a->q_flags, a->q_rmailer); 9563234Seric 9573234Seric if (!follow) 9583234Seric return; 9593234Seric a = a->q_next; 9603234Seric } 9613234Seric } 962*4317Seric 963*4317Seric # endif DEBUG 964