13312Seric # include "sendmail.h" 2297Seric 3*4468Seric static char SccsId[] = "@(#)parseaddr.c 3.29 10/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 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) 1294443Seric { 1304443Seric printf("parse-->"); 1314443Seric printaddr(a, FALSE); 1324443Seric } 133297Seric # endif DEBUG 134297Seric 135297Seric return (a); 136297Seric } 137297Seric /* 138297Seric ** PRESCAN -- Prescan name and make it canonical 139297Seric ** 140297Seric ** Scans a name and turns it into canonical form. This involves 141297Seric ** deleting blanks, comments (in parentheses), and turning the 142297Seric ** word "at" into an at-sign ("@"). The name is copied as this 143297Seric ** is done; it is legal to copy a name onto itself, since this 144297Seric ** process can only make things smaller. 145297Seric ** 146297Seric ** This routine knows about quoted strings and angle brackets. 147297Seric ** 148297Seric ** There are certain subtleties to this routine. The one that 149297Seric ** comes to mind now is that backslashes on the ends of names 150297Seric ** are silently stripped off; this is intentional. The problem 151297Seric ** is that some versions of sndmsg (like at LBL) set the kill 152297Seric ** character to something other than @ when reading addresses; 153297Seric ** so people type "csvax.eric\@berkeley" -- which screws up the 154297Seric ** berknet mailer. 155297Seric ** 156297Seric ** Parameters: 157297Seric ** addr -- the name to chomp. 158297Seric ** delim -- the delimiter for the address, normally 159297Seric ** '\0' or ','; \0 is accepted in any case. 160297Seric ** are moving in place; set buflim to high core. 161297Seric ** 162297Seric ** Returns: 1633149Seric ** A pointer to a vector of tokens. 164297Seric ** NULL on error. 165297Seric ** 166297Seric ** Side Effects: 1673149Seric ** none. 168297Seric */ 169297Seric 1703149Seric # define OPER 1 1713149Seric # define ATOM 2 1723149Seric # define EOTOK 3 1733149Seric # define QSTRING 4 1743149Seric # define SPACE 5 1753149Seric # define DOLLAR 6 1763149Seric # define GETONE 7 1774424Seric # define MACRO 8 1783149Seric 1793149Seric char ** 1803149Seric prescan(addr, delim) 181297Seric char *addr; 182297Seric char delim; 183297Seric { 184297Seric register char *p; 1853149Seric static char buf[MAXNAME+MAXATOM]; 1863149Seric static char *av[MAXATOM+1]; 1873149Seric char **avp; 188297Seric bool bslashmode; 189297Seric int cmntcnt; 190297Seric int brccnt; 191297Seric register char c; 1923149Seric char *tok; 193297Seric register char *q; 1943149Seric register int state; 1953149Seric int nstate; 1964085Seric extern char lower(); 197297Seric 198297Seric q = buf; 1993149Seric bslashmode = FALSE; 200297Seric cmntcnt = brccnt = 0; 2013149Seric avp = av; 2023149Seric state = OPER; 2033149Seric for (p = addr; *p != '\0' && *p != delim; ) 204297Seric { 2053149Seric /* read a token */ 2063149Seric tok = q; 2073149Seric while ((c = *p++) != '\0' && c != delim) 208297Seric { 2093149Seric /* chew up special characters */ 2104100Seric c &= ~0200; 2113149Seric *q = '\0'; 2123149Seric if (bslashmode) 2133149Seric { 2143149Seric c |= 0200; 2153149Seric bslashmode = FALSE; 2163149Seric } 2173149Seric else if (c == '\\') 2183149Seric { 2193149Seric bslashmode = TRUE; 2203149Seric continue; 2213149Seric } 2224100Seric else if (c == '"') 2234100Seric { 2244100Seric if (state == QSTRING) 2254100Seric state = OPER; 2264100Seric else 2274100Seric state = QSTRING; 2284100Seric break; 2294100Seric } 2303149Seric 2314424Seric if (c == '$' && delim == '\t') 2324424Seric nstate = DOLLAR; 2334424Seric else 2344424Seric nstate = toktype(c); 2353149Seric switch (state) 2363149Seric { 2373149Seric case QSTRING: /* in quoted string */ 2383149Seric break; 2393149Seric 2403149Seric case ATOM: /* regular atom */ 2414228Seric if (nstate != ATOM) 2423149Seric { 2433149Seric state = EOTOK; 2443149Seric p--; 2453149Seric } 2463149Seric break; 2473149Seric 2483149Seric case GETONE: /* grab one character */ 2493149Seric state = OPER; 2503149Seric break; 2513149Seric 2523149Seric case EOTOK: /* after atom or q-string */ 2533149Seric state = nstate; 2543149Seric if (state == SPACE) 2553149Seric continue; 2563149Seric break; 2573149Seric 2583149Seric case SPACE: /* linear white space */ 2593149Seric state = nstate; 2604228Seric break; 2613149Seric 2623149Seric case OPER: /* operator */ 2633149Seric if (nstate == SPACE) 2643149Seric continue; 2653149Seric state = nstate; 2663149Seric break; 2673149Seric 2683149Seric case DOLLAR: /* $- etc. */ 2693149Seric state = OPER; 270*4468Seric if (isascii(c) && isdigit(c)) 271*4468Seric { 272*4468Seric /* replacement */ 273*4468Seric c = MATCHREPL; 274*4468Seric state = GETONE; 275*4468Seric p--; 276*4468Seric break; 277*4468Seric } 2783149Seric switch (c) 2793149Seric { 2803149Seric case '$': /* literal $ */ 2813149Seric break; 2823149Seric 2833149Seric case '+': /* match anything */ 2843149Seric c = MATCHANY; 2853149Seric break; 2863149Seric 2873149Seric case '-': /* match one token */ 2883149Seric c = MATCHONE; 2893149Seric break; 2903149Seric 2914060Seric case '=': /* match one token of class */ 2924060Seric c = MATCHCLASS; 2934060Seric state = GETONE; 2944060Seric break; 2954060Seric 2963149Seric case '#': /* canonical net name */ 2973149Seric c = CANONNET; 2983149Seric break; 2993149Seric 3003149Seric case '@': /* canonical host name */ 3013149Seric c = CANONHOST; 3023149Seric break; 3033149Seric 3043149Seric case ':': /* canonical user name */ 3053149Seric c = CANONUSER; 3063149Seric break; 3073149Seric 3083149Seric default: 3094424Seric state = MACRO; 3103149Seric break; 3113149Seric } 3123149Seric break; 3133149Seric 3143149Seric default: 3153149Seric syserr("prescan: unknown state %d", state); 3163149Seric } 3173149Seric 3184228Seric if (state == EOTOK || state == SPACE) 3193149Seric break; 3204424Seric if (state == DOLLAR) 3213149Seric continue; 3223149Seric 3233149Seric /* squirrel it away */ 3243149Seric if (q >= &buf[sizeof buf - 5]) 3253149Seric { 3263149Seric usrerr("Address too long"); 3273149Seric return (NULL); 3283149Seric } 3294424Seric if (state == MACRO) 3304424Seric { 3314424Seric char mbuf[3]; 3324424Seric 3334424Seric mbuf[0] = '$'; 3344424Seric mbuf[1] = c; 3354424Seric mbuf[2] = '\0'; 3364424Seric (void) expand(mbuf, q, &buf[sizeof buf - 5]); 3374424Seric q += strlen(q); 3384424Seric state = EOTOK; 3394424Seric break; 3404424Seric } 3413149Seric *q++ = c; 3423149Seric 3433149Seric /* decide whether this represents end of token */ 3443149Seric if (state == OPER) 3453149Seric break; 346297Seric } 3473149Seric if (c == '\0' || c == delim) 3483149Seric p--; 3493149Seric 3503149Seric /* new token */ 3513149Seric if (tok == q) 352297Seric continue; 3533149Seric *q++ = '\0'; 3543149Seric 3553149Seric c = tok[0]; 3563149Seric if (c == '(') 3571378Seric { 358297Seric cmntcnt++; 3591378Seric continue; 3601378Seric } 361297Seric else if (c == ')') 362297Seric { 363297Seric if (cmntcnt <= 0) 364297Seric { 365297Seric usrerr("Unbalanced ')'"); 366297Seric return (NULL); 367297Seric } 368297Seric else 369297Seric { 370297Seric cmntcnt--; 371297Seric continue; 372297Seric } 373297Seric } 3743149Seric else if (cmntcnt > 0) 3752091Seric continue; 3763149Seric 3773149Seric /* we prefer <> specs */ 3783149Seric if (c == '<') 379297Seric { 3802092Seric if (brccnt < 0) 3812092Seric { 3822092Seric usrerr("multiple < spec"); 3832092Seric return (NULL); 3842092Seric } 385297Seric brccnt++; 386297Seric if (brccnt == 1) 387297Seric { 388297Seric /* we prefer using machine readable name */ 389297Seric q = buf; 390297Seric *q = '\0'; 3913149Seric avp = av; 392297Seric continue; 393297Seric } 394297Seric } 395297Seric else if (c == '>') 396297Seric { 397297Seric if (brccnt <= 0) 398297Seric { 399297Seric usrerr("Unbalanced `>'"); 400297Seric return (NULL); 401297Seric } 402297Seric else 403297Seric brccnt--; 404297Seric if (brccnt <= 0) 4052092Seric { 4062092Seric brccnt = -1; 407297Seric continue; 4082092Seric } 409297Seric } 4104448Seric 4114448Seric if (avp >= &av[MAXATOM]) 4124448Seric { 4134448Seric syserr("prescan: too many tokens"); 4144448Seric return (NULL); 4154448Seric } 4164448Seric *avp++ = tok; 4173149Seric } 4183149Seric *avp = NULL; 4193149Seric if (cmntcnt > 0) 4203149Seric usrerr("Unbalanced '('"); 4213149Seric else if (brccnt > 0) 4223149Seric usrerr("Unbalanced '<'"); 4233149Seric else if (state == QSTRING) 4243149Seric usrerr("Unbalanced '\"'"); 4253149Seric else if (av[0] != NULL) 4263149Seric return (av); 4273149Seric return (NULL); 4283149Seric } 4293149Seric /* 4303149Seric ** TOKTYPE -- return token type 4313149Seric ** 4323149Seric ** Parameters: 4333149Seric ** c -- the character in question. 4343149Seric ** 4353149Seric ** Returns: 4363149Seric ** Its type. 4373149Seric ** 4383149Seric ** Side Effects: 4393149Seric ** none. 4403149Seric */ 441297Seric 4423149Seric toktype(c) 4433149Seric register char c; 4443149Seric { 4453380Seric static char buf[50]; 4463382Seric static bool firstime = TRUE; 4473380Seric 4483382Seric if (firstime) 4493380Seric { 4503382Seric firstime = FALSE; 4514085Seric (void) expand("$o", buf, &buf[sizeof buf - 1]); 4523380Seric strcat(buf, DELIMCHARS); 4533380Seric } 4544100Seric if (!isascii(c)) 4554100Seric return (ATOM); 4563149Seric if (isspace(c)) 4573149Seric return (SPACE); 4583380Seric if (iscntrl(c) || index(buf, c) != NULL) 4593149Seric return (OPER); 4603149Seric return (ATOM); 4613149Seric } 4623149Seric /* 4633149Seric ** REWRITE -- apply rewrite rules to token vector. 4643149Seric ** 4653149Seric ** Parameters: 4663149Seric ** pvp -- pointer to token vector. 4673149Seric ** 4683149Seric ** Returns: 4693149Seric ** none. 4703149Seric ** 4713149Seric ** Side Effects: 4723149Seric ** pvp is modified. 4733149Seric */ 4742091Seric 4753149Seric struct match 4763149Seric { 477*4468Seric char **first; /* first token matched */ 478*4468Seric char **last; /* last token matched */ 4793149Seric }; 4803149Seric 481*4468Seric # define MAXMATCH 9 /* max params per rewrite */ 4823149Seric 4833149Seric 4844070Seric rewrite(pvp, ruleset) 4853149Seric char **pvp; 4864070Seric int ruleset; 4873149Seric { 4883149Seric register char *ap; /* address pointer */ 4893149Seric register char *rp; /* rewrite pointer */ 4903149Seric register char **avp; /* address vector pointer */ 491*4468Seric char **avfp; /* first word in current match */ 4923149Seric register char **rvp; /* rewrite vector pointer */ 493*4468Seric struct rewrite *rwr; /* pointer to current rewrite rule */ 494*4468Seric struct match mlist[MAXMATCH]; /* stores match on LHS */ 495*4468Seric struct match *mlp; /* cur ptr into mlist */ 4963149Seric char *npvp[MAXATOM+1]; /* temporary space for rebuild */ 4974060Seric extern bool sameword(); 4983149Seric 4994100Seric # ifdef DEBUG 5004228Seric if (Debug > 9) 5013149Seric { 5023149Seric printf("rewrite: original pvp:\n"); 5033149Seric printav(pvp); 5043149Seric } 5054100Seric # endif DEBUG 5063149Seric 5073149Seric /* 5083149Seric ** Run through the list of rewrite rules, applying 5093149Seric ** any that match. 5103149Seric */ 5113149Seric 5124070Seric for (rwr = RewriteRules[ruleset]; rwr != NULL; ) 5133149Seric { 5144100Seric # ifdef DEBUG 5154100Seric if (Debug > 10) 516297Seric { 5173149Seric printf("-----trying rule:\n"); 5183149Seric printav(rwr->r_lhs); 5193149Seric } 5204100Seric # endif DEBUG 5213149Seric 5223149Seric /* try to match on this rule */ 523*4468Seric mlp = mlist; 524*4468Seric for (rvp = rwr->r_lhs, avfp = avp = pvp; *avp != NULL; ) 5253149Seric { 5263149Seric ap = *avp; 5273149Seric rp = *rvp; 5283149Seric 5293149Seric if (rp == NULL) 530297Seric { 5313149Seric /* end-of-pattern before end-of-address */ 5323149Seric goto fail; 533297Seric } 5343149Seric 5353149Seric switch (*rp) 5363149Seric { 5374060Seric register STAB *s; 5384060Seric register int class; 5394060Seric 5403149Seric case MATCHONE: 5413149Seric /* match exactly one token */ 542*4468Seric mlp->first = mlp->last = avp++; 543*4468Seric mlp++; 544*4468Seric avfp = avp; 5453149Seric break; 5463149Seric 5473149Seric case MATCHANY: 5483149Seric /* match any number of tokens */ 549*4468Seric mlp->first = avfp; 550*4468Seric mlp->last = avp++; 551*4468Seric mlp++; 5523149Seric break; 5533149Seric 5544060Seric case MATCHCLASS: 5554060Seric /* match any token in a class */ 5564060Seric class = rp[1]; 5574060Seric if (!isalpha(class)) 5584060Seric goto fail; 5594060Seric if (isupper(class)) 5604060Seric class -= 'A'; 5614060Seric else 5624060Seric class -= 'a'; 5634100Seric s = stab(ap, ST_CLASS, ST_FIND); 5644060Seric if (s == NULL || (s->s_class & (1 << class)) == 0) 5654060Seric goto fail; 566*4468Seric 567*4468Seric /* mark match */ 568*4468Seric mlp->first = mlp->last = avp++; 569*4468Seric mlp++; 570*4468Seric avfp = avp; 5714060Seric break; 5724060Seric 5733149Seric default: 5743149Seric /* must have exact match */ 5754060Seric if (!sameword(rp, ap)) 5764060Seric goto fail; 577*4468Seric avp++; 578*4468Seric avfp = avp; 5793149Seric break; 5803149Seric } 5813149Seric 5823149Seric /* successful match on this token */ 5833149Seric rvp++; 5843149Seric continue; 5853149Seric 5863149Seric fail: 5873149Seric /* match failed -- back up */ 5883149Seric while (--rvp >= rwr->r_lhs) 5893149Seric { 5903149Seric rp = *rvp; 5913149Seric if (*rp == MATCHANY) 592*4468Seric { 593*4468Seric avfp = mlp->first; 5943149Seric break; 595*4468Seric } 596*4468Seric else if (*rp == MATCHONE || *rp == MATCHCLASS) 5973149Seric { 598*4468Seric /* back out binding */ 599*4468Seric avp--; 600*4468Seric avfp = avp; 601*4468Seric mlp--; 6023149Seric } 6033149Seric } 6043149Seric 6053149Seric if (rvp < rwr->r_lhs) 6063149Seric { 6073149Seric /* total failure to match */ 6083149Seric break; 6093149Seric } 610297Seric } 6113149Seric 6123149Seric /* 6133149Seric ** See if we successfully matched 6143149Seric */ 6153149Seric 6163149Seric if (rvp >= rwr->r_lhs && *rvp == NULL) 6173149Seric { 6184100Seric # ifdef DEBUG 6194100Seric if (Debug > 10) 6203149Seric { 6213149Seric printf("-----rule matches:\n"); 6223149Seric printav(rwr->r_rhs); 6233149Seric } 6244100Seric # endif DEBUG 6253149Seric 6263149Seric /* substitute */ 6273149Seric for (rvp = rwr->r_rhs, avp = npvp; *rvp != NULL; rvp++) 6283149Seric { 6293149Seric rp = *rvp; 630*4468Seric if (*rp == MATCHREPL) 6313149Seric { 6323149Seric register struct match *m; 6333149Seric register char **pp; 6343149Seric 635*4468Seric m = &mlist[rp[1] - '1']; 636*4468Seric pp = m->first; 637*4468Seric do 6383149Seric { 639*4468Seric if (avp >= &npvp[MAXATOM]) 6403149Seric { 641*4468Seric syserr("rewrite: expansion too long"); 642*4468Seric return; 643*4468Seric } 644*4468Seric *avp++ = *pp; 645*4468Seric } while (pp++ != m->last); 6463149Seric } 6473149Seric else 6484385Seric { 6494385Seric if (avp >= &npvp[MAXATOM]) 6504385Seric { 6514385Seric syserr("rewrite: expansion too long"); 6524385Seric return; 6534385Seric } 6543149Seric *avp++ = rp; 6554385Seric } 6563149Seric } 6573149Seric *avp++ = NULL; 6584085Seric bmove((char *) npvp, (char *) pvp, (avp - npvp) * sizeof *avp); 6593149Seric # ifdef DEBUG 6604228Seric if (Debug > 3) 6613149Seric { 6623188Seric char **vp; 6633188Seric 6643188Seric printf("rewritten as `"); 6653188Seric for (vp = pvp; *vp != NULL; vp++) 6664228Seric { 6674228Seric if (vp != pvp) 6684228Seric printf("_"); 6693188Seric xputs(*vp); 6704228Seric } 6713188Seric printf("'\n"); 6723149Seric } 6733149Seric # endif DEBUG 6743149Seric if (pvp[0][0] == CANONNET) 6753149Seric break; 6763149Seric } 6773149Seric else 6783149Seric { 6794100Seric # ifdef DEBUG 6804100Seric if (Debug > 10) 6813149Seric printf("----- rule fails\n"); 6824100Seric # endif DEBUG 6833149Seric rwr = rwr->r_next; 6843149Seric } 685297Seric } 6863149Seric } 6873149Seric /* 6883149Seric ** BUILDADDR -- build address from token vector. 6893149Seric ** 6903149Seric ** Parameters: 6913149Seric ** tv -- token vector. 6923149Seric ** a -- pointer to address descriptor to fill. 6933149Seric ** If NULL, one will be allocated. 6943149Seric ** 6953149Seric ** Returns: 6964279Seric ** NULL if there was an error. 6974279Seric ** 'a' otherwise. 6983149Seric ** 6993149Seric ** Side Effects: 7003149Seric ** fills in 'a' 7013149Seric */ 7023149Seric 7033149Seric ADDRESS * 7043149Seric buildaddr(tv, a) 7053149Seric register char **tv; 7063149Seric register ADDRESS *a; 7073149Seric { 7083149Seric register int i; 7093149Seric static char buf[MAXNAME]; 7103149Seric struct mailer **mp; 7113149Seric register struct mailer *m; 7123149Seric 7133149Seric if (a == NULL) 7143149Seric a = (ADDRESS *) xalloc(sizeof *a); 7153188Seric a->q_flags = 0; 7164079Seric a->q_home = NULL; 7173149Seric 7183149Seric /* figure out what net/mailer to use */ 7193149Seric if (**tv != CANONNET) 7204279Seric { 7213149Seric syserr("buildaddr: no net"); 7224279Seric return (NULL); 7234279Seric } 7243149Seric tv++; 7254279Seric if (strcmp(*tv, "error") == 0) 7264279Seric { 7274279Seric if (**++tv != CANONUSER) 7284279Seric syserr("buildaddr: error: no user"); 7294279Seric buf[0] = '\0'; 7304279Seric while (*++tv != NULL) 7314279Seric { 7324279Seric if (buf[0] != '\0') 7334279Seric strcat(buf, " "); 7344279Seric strcat(buf, *tv); 7354279Seric } 7364279Seric usrerr(buf); 7374279Seric return (NULL); 7384279Seric } 7393154Seric for (mp = Mailer, i = 0; (m = *mp++) != NULL; i++) 7403149Seric { 7413149Seric if (strcmp(m->m_name, *tv) == 0) 7423149Seric break; 7433149Seric } 7443149Seric if (m == NULL) 7454279Seric { 7463149Seric syserr("buildaddr: unknown net %s", *tv); 7474279Seric return (NULL); 7484279Seric } 7493149Seric a->q_mailer = i; 7503149Seric 7513149Seric /* figure out what host (if any) */ 7523149Seric tv++; 7534195Seric if (!bitset(M_LOCAL, m->m_flags)) 7543149Seric { 7553149Seric if (**tv != CANONHOST) 7564279Seric { 7573149Seric syserr("buildaddr: no host"); 7584279Seric return (NULL); 7594279Seric } 7603149Seric tv++; 7613149Seric a->q_host = *tv; 7623149Seric tv++; 7633149Seric } 7643149Seric else 7653149Seric a->q_host = NULL; 7663149Seric 7673149Seric /* figure out the user */ 7683149Seric if (**tv != CANONUSER) 7694279Seric { 7703149Seric syserr("buildaddr: no user"); 7714279Seric return (NULL); 7724279Seric } 7734228Seric cataddr(++tv, buf, sizeof buf); 7743149Seric a->q_user = buf; 7753149Seric 7763149Seric return (a); 7773149Seric } 7783188Seric /* 7794228Seric ** CATADDR -- concatenate pieces of addresses (putting in <LWSP> subs) 7804228Seric ** 7814228Seric ** Parameters: 7824228Seric ** pvp -- parameter vector to rebuild. 7834228Seric ** buf -- buffer to build the string into. 7844228Seric ** sz -- size of buf. 7854228Seric ** 7864228Seric ** Returns: 7874228Seric ** none. 7884228Seric ** 7894228Seric ** Side Effects: 7904228Seric ** Destroys buf. 7914228Seric */ 7924228Seric 7934228Seric cataddr(pvp, buf, sz) 7944228Seric char **pvp; 7954228Seric char *buf; 7964228Seric register int sz; 7974228Seric { 7984228Seric bool oatomtok = FALSE; 7994228Seric bool natomtok = FALSE; 8004228Seric register int i; 8014228Seric register char *p; 8024228Seric 8034228Seric p = buf; 8044228Seric sz--; 8054228Seric while (*pvp != NULL && (i = strlen(*pvp)) < sz) 8064228Seric { 8074228Seric natomtok = (toktype(**pvp) == ATOM); 8084228Seric if (oatomtok && natomtok) 8094228Seric *p++ = SPACESUB; 8104228Seric (void) strcpy(p, *pvp); 8114228Seric oatomtok = natomtok; 8124228Seric p += i; 8134228Seric sz -= i; 8144228Seric pvp++; 8154228Seric } 8164228Seric *p = '\0'; 8174228Seric } 8184228Seric /* 8193188Seric ** SAMEADDR -- Determine if two addresses are the same 8203188Seric ** 8213188Seric ** This is not just a straight comparison -- if the mailer doesn't 8223188Seric ** care about the host we just ignore it, etc. 8233188Seric ** 8243188Seric ** Parameters: 8253188Seric ** a, b -- pointers to the internal forms to compare. 8263188Seric ** wildflg -- if TRUE, 'a' may have no user specified, 8273188Seric ** in which case it is to match anything. 8283188Seric ** 8293188Seric ** Returns: 8303188Seric ** TRUE -- they represent the same mailbox. 8313188Seric ** FALSE -- they don't. 8323188Seric ** 8333188Seric ** Side Effects: 8343188Seric ** none. 8353188Seric */ 8363188Seric 8373188Seric bool 8383188Seric sameaddr(a, b, wildflg) 8393188Seric register ADDRESS *a; 8403188Seric register ADDRESS *b; 8413188Seric bool wildflg; 8423188Seric { 8433188Seric /* if they don't have the same mailer, forget it */ 8443188Seric if (a->q_mailer != b->q_mailer) 8453188Seric return (FALSE); 8463188Seric 8473188Seric /* if the user isn't the same, we can drop out */ 8483188Seric if ((!wildflg || a->q_user[0] != '\0') && strcmp(a->q_user, b->q_user) != 0) 8493188Seric return (FALSE); 8503188Seric 8513188Seric /* if the mailer ignores hosts, we have succeeded! */ 8524195Seric if (bitset(M_LOCAL, Mailer[a->q_mailer]->m_flags)) 8533188Seric return (TRUE); 8543188Seric 8553188Seric /* otherwise compare hosts (but be careful for NULL ptrs) */ 8563188Seric if (a->q_host == NULL || b->q_host == NULL) 8573188Seric return (FALSE); 8583188Seric if (strcmp(a->q_host, b->q_host) != 0) 8593188Seric return (FALSE); 8603188Seric 8613188Seric return (TRUE); 8623188Seric } 8633234Seric /* 8643234Seric ** PRINTADDR -- print address (for debugging) 8653234Seric ** 8663234Seric ** Parameters: 8673234Seric ** a -- the address to print 8683234Seric ** follow -- follow the q_next chain. 8693234Seric ** 8703234Seric ** Returns: 8713234Seric ** none. 8723234Seric ** 8733234Seric ** Side Effects: 8743234Seric ** none. 8753234Seric */ 8763234Seric 8774317Seric # ifdef DEBUG 8784317Seric 8793234Seric printaddr(a, follow) 8803234Seric register ADDRESS *a; 8813234Seric bool follow; 8823234Seric { 8833234Seric while (a != NULL) 8843234Seric { 8854443Seric printf("%x=", a); 8864085Seric (void) fflush(stdout); 8873234Seric printf("%s: mailer %d (%s), host `%s', user `%s'\n", a->q_paddr, 8883234Seric a->q_mailer, Mailer[a->q_mailer]->m_name, a->q_host, a->q_user); 8894443Seric printf("\tnext=%x, flags=%o, rmailer %d\n", a->q_next, 8903234Seric a->q_flags, a->q_rmailer); 8913234Seric 8923234Seric if (!follow) 8933234Seric return; 8943234Seric a = a->q_next; 8953234Seric } 8964443Seric if (!follow) 8974443Seric printf("[NULL]\n"); 8983234Seric } 8994317Seric 9004317Seric # endif DEBUG 901