13312Seric # include "sendmail.h" 2297Seric 3*4598Seric static char SccsId[] = "@(#)parseaddr.c 3.31 10/23/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); 92*4598Seric m = 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; 2704468Seric if (isascii(c) && isdigit(c)) 2714468Seric { 2724468Seric /* replacement */ 2734468Seric c = MATCHREPL; 2744468Seric state = GETONE; 2754468Seric p--; 2764468Seric break; 2774468Seric } 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 ** 4654476Seric ** This routine is an ordered production system. Each rewrite 4664476Seric ** rule has a LHS (called the pattern) and a RHS (called the 4674476Seric ** rewrite); 'rwr' points the the current rewrite rule. 4684476Seric ** 4694476Seric ** For each rewrite rule, 'avp' points the address vector we 4704476Seric ** are trying to match against, and 'pvp' points to the pattern. 4714476Seric ** If pvp points to a special match value (MATCHANY, MATCHONE, 4724476Seric ** MATCHCLASS) then the address in avp matched is saved away 4734476Seric ** in the match vector (pointed to by 'mvp'). 4744476Seric ** 4754476Seric ** When a match between avp & pvp does not match, we try to 4764476Seric ** back out. If we back up over a MATCHONE or a MATCHCLASS 4774476Seric ** we must also back out the match in mvp. If we reach a 4784476Seric ** MATCHANY we just extend the match and start over again. 4794476Seric ** 4804476Seric ** When we finally match, we rewrite the address vector 4814476Seric ** and try over again. 4824476Seric ** 4833149Seric ** Parameters: 4843149Seric ** pvp -- pointer to token vector. 4853149Seric ** 4863149Seric ** Returns: 4873149Seric ** none. 4883149Seric ** 4893149Seric ** Side Effects: 4903149Seric ** pvp is modified. 4913149Seric */ 4922091Seric 4933149Seric struct match 4943149Seric { 4954468Seric char **first; /* first token matched */ 4964468Seric char **last; /* last token matched */ 4973149Seric }; 4983149Seric 4994468Seric # define MAXMATCH 9 /* max params per rewrite */ 5003149Seric 5013149Seric 5024070Seric rewrite(pvp, ruleset) 5033149Seric char **pvp; 5044070Seric int ruleset; 5053149Seric { 5063149Seric register char *ap; /* address pointer */ 5073149Seric register char *rp; /* rewrite pointer */ 5083149Seric register char **avp; /* address vector pointer */ 5093149Seric register char **rvp; /* rewrite vector pointer */ 5104468Seric struct rewrite *rwr; /* pointer to current rewrite rule */ 5114468Seric struct match mlist[MAXMATCH]; /* stores match on LHS */ 5124468Seric struct match *mlp; /* cur ptr into mlist */ 5133149Seric char *npvp[MAXATOM+1]; /* temporary space for rebuild */ 5144060Seric extern bool sameword(); 5153149Seric 5164100Seric # ifdef DEBUG 5174228Seric if (Debug > 9) 5183149Seric { 5193149Seric printf("rewrite: original pvp:\n"); 5203149Seric printav(pvp); 5213149Seric } 5224100Seric # endif DEBUG 5233149Seric 5243149Seric /* 5253149Seric ** Run through the list of rewrite rules, applying 5263149Seric ** any that match. 5273149Seric */ 5283149Seric 5294070Seric for (rwr = RewriteRules[ruleset]; rwr != NULL; ) 5303149Seric { 5314100Seric # ifdef DEBUG 5324100Seric if (Debug > 10) 533297Seric { 5343149Seric printf("-----trying rule:\n"); 5353149Seric printav(rwr->r_lhs); 5363149Seric } 5374100Seric # endif DEBUG 5383149Seric 5393149Seric /* try to match on this rule */ 5404468Seric mlp = mlist; 5414476Seric for (rvp = rwr->r_lhs, avp = pvp; *avp != NULL; ) 5423149Seric { 5433149Seric ap = *avp; 5443149Seric rp = *rvp; 5453149Seric 5463149Seric if (rp == NULL) 547297Seric { 5483149Seric /* end-of-pattern before end-of-address */ 5493149Seric goto fail; 550297Seric } 5513149Seric 5523149Seric switch (*rp) 5533149Seric { 5544060Seric register STAB *s; 5554060Seric register int class; 5564060Seric 5574060Seric case MATCHCLASS: 5584060Seric /* match any token in a class */ 5594060Seric class = rp[1]; 5604060Seric if (!isalpha(class)) 5614060Seric goto fail; 5624060Seric if (isupper(class)) 5634060Seric class -= 'A'; 5644060Seric else 5654060Seric class -= 'a'; 5664100Seric s = stab(ap, ST_CLASS, ST_FIND); 5674060Seric if (s == NULL || (s->s_class & (1 << class)) == 0) 5684060Seric goto fail; 5694468Seric 5704476Seric /* explicit fall-through */ 5714476Seric 5724476Seric case MATCHONE: 5734476Seric case MATCHANY: 5744476Seric /* match exactly one token */ 5754468Seric mlp->first = mlp->last = avp++; 5764468Seric mlp++; 5774060Seric break; 5784060Seric 5793149Seric default: 5803149Seric /* must have exact match */ 5814060Seric if (!sameword(rp, ap)) 5824060Seric goto fail; 5834468Seric avp++; 5843149Seric break; 5853149Seric } 5863149Seric 5873149Seric /* successful match on this token */ 5883149Seric rvp++; 5893149Seric continue; 5903149Seric 5913149Seric fail: 5923149Seric /* match failed -- back up */ 5933149Seric while (--rvp >= rwr->r_lhs) 5943149Seric { 5953149Seric rp = *rvp; 5963149Seric if (*rp == MATCHANY) 5974468Seric { 5984476Seric /* extend binding and continue */ 5994476Seric mlp[-1].last = avp++; 6004476Seric rvp++; 6013149Seric break; 6024468Seric } 6034476Seric avp--; 6044476Seric if (*rp == MATCHONE || *rp == MATCHCLASS) 6053149Seric { 6064468Seric /* back out binding */ 6074468Seric mlp--; 6083149Seric } 6093149Seric } 6103149Seric 6113149Seric if (rvp < rwr->r_lhs) 6123149Seric { 6133149Seric /* total failure to match */ 6143149Seric break; 6153149Seric } 616297Seric } 6173149Seric 6183149Seric /* 6193149Seric ** See if we successfully matched 6203149Seric */ 6213149Seric 6223149Seric if (rvp >= rwr->r_lhs && *rvp == NULL) 6233149Seric { 6244100Seric # ifdef DEBUG 6254100Seric if (Debug > 10) 6263149Seric { 6273149Seric printf("-----rule matches:\n"); 6283149Seric printav(rwr->r_rhs); 6293149Seric } 6304100Seric # endif DEBUG 6313149Seric 6323149Seric /* substitute */ 6333149Seric for (rvp = rwr->r_rhs, avp = npvp; *rvp != NULL; rvp++) 6343149Seric { 6353149Seric rp = *rvp; 6364468Seric if (*rp == MATCHREPL) 6373149Seric { 6383149Seric register struct match *m; 6393149Seric register char **pp; 6403149Seric 6414468Seric m = &mlist[rp[1] - '1']; 6424476Seric # ifdef DEBUG 6434476Seric if (Debug > 13) 6444476Seric { 6454476Seric printf("$%c:", rp[1]); 6464476Seric pp = m->first; 6474476Seric do 6484476Seric { 6494476Seric printf(" %x=\"", *pp); 6504476Seric fflush(stdout); 6514476Seric printf("%s\"", *pp); 6524476Seric } while (pp++ != m->last); 6534476Seric printf("\n"); 6544476Seric } 6554476Seric # endif DEBUG 6564468Seric pp = m->first; 6574468Seric do 6583149Seric { 6594468Seric if (avp >= &npvp[MAXATOM]) 6603149Seric { 6614468Seric syserr("rewrite: expansion too long"); 6624468Seric return; 6634468Seric } 6644468Seric *avp++ = *pp; 6654468Seric } while (pp++ != m->last); 6663149Seric } 6673149Seric else 6684385Seric { 6694385Seric if (avp >= &npvp[MAXATOM]) 6704385Seric { 6714385Seric syserr("rewrite: expansion too long"); 6724385Seric return; 6734385Seric } 6743149Seric *avp++ = rp; 6754385Seric } 6763149Seric } 6773149Seric *avp++ = NULL; 6784085Seric bmove((char *) npvp, (char *) pvp, (avp - npvp) * sizeof *avp); 6793149Seric # ifdef DEBUG 6804228Seric if (Debug > 3) 6813149Seric { 6823188Seric char **vp; 6833188Seric 6843188Seric printf("rewritten as `"); 6853188Seric for (vp = pvp; *vp != NULL; vp++) 6864228Seric { 6874228Seric if (vp != pvp) 6884228Seric printf("_"); 6893188Seric xputs(*vp); 6904228Seric } 6913188Seric printf("'\n"); 6923149Seric } 6933149Seric # endif DEBUG 6943149Seric if (pvp[0][0] == CANONNET) 6953149Seric break; 6963149Seric } 6973149Seric else 6983149Seric { 6994100Seric # ifdef DEBUG 7004100Seric if (Debug > 10) 7013149Seric printf("----- rule fails\n"); 7024100Seric # endif DEBUG 7033149Seric rwr = rwr->r_next; 7043149Seric } 705297Seric } 7063149Seric } 7073149Seric /* 7083149Seric ** BUILDADDR -- build address from token vector. 7093149Seric ** 7103149Seric ** Parameters: 7113149Seric ** tv -- token vector. 7123149Seric ** a -- pointer to address descriptor to fill. 7133149Seric ** If NULL, one will be allocated. 7143149Seric ** 7153149Seric ** Returns: 7164279Seric ** NULL if there was an error. 7174279Seric ** 'a' otherwise. 7183149Seric ** 7193149Seric ** Side Effects: 7203149Seric ** fills in 'a' 7213149Seric */ 7223149Seric 7233149Seric ADDRESS * 7243149Seric buildaddr(tv, a) 7253149Seric register char **tv; 7263149Seric register ADDRESS *a; 7273149Seric { 7283149Seric register int i; 7293149Seric static char buf[MAXNAME]; 7303149Seric struct mailer **mp; 7313149Seric register struct mailer *m; 7323149Seric 7333149Seric if (a == NULL) 7343149Seric a = (ADDRESS *) xalloc(sizeof *a); 7353188Seric a->q_flags = 0; 7364079Seric a->q_home = NULL; 7373149Seric 7383149Seric /* figure out what net/mailer to use */ 7393149Seric if (**tv != CANONNET) 7404279Seric { 7413149Seric syserr("buildaddr: no net"); 7424279Seric return (NULL); 7434279Seric } 7443149Seric tv++; 7454279Seric if (strcmp(*tv, "error") == 0) 7464279Seric { 7474279Seric if (**++tv != CANONUSER) 7484279Seric syserr("buildaddr: error: no user"); 7494279Seric buf[0] = '\0'; 7504279Seric while (*++tv != NULL) 7514279Seric { 7524279Seric if (buf[0] != '\0') 7534279Seric strcat(buf, " "); 7544279Seric strcat(buf, *tv); 7554279Seric } 7564279Seric usrerr(buf); 7574279Seric return (NULL); 7584279Seric } 759*4598Seric for (mp = Mailer; (m = *mp++) != NULL; ) 7603149Seric { 7613149Seric if (strcmp(m->m_name, *tv) == 0) 7623149Seric break; 7633149Seric } 7643149Seric if (m == NULL) 7654279Seric { 7663149Seric syserr("buildaddr: unknown net %s", *tv); 7674279Seric return (NULL); 7684279Seric } 769*4598Seric a->q_mailer = m; 7703149Seric 7713149Seric /* figure out what host (if any) */ 7723149Seric tv++; 7734195Seric if (!bitset(M_LOCAL, m->m_flags)) 7743149Seric { 7753149Seric if (**tv != CANONHOST) 7764279Seric { 7773149Seric syserr("buildaddr: no host"); 7784279Seric return (NULL); 7794279Seric } 7803149Seric tv++; 7813149Seric a->q_host = *tv; 7823149Seric tv++; 7833149Seric } 7843149Seric else 7853149Seric a->q_host = NULL; 7863149Seric 7873149Seric /* figure out the user */ 7883149Seric if (**tv != CANONUSER) 7894279Seric { 7903149Seric syserr("buildaddr: no user"); 7914279Seric return (NULL); 7924279Seric } 7934228Seric cataddr(++tv, buf, sizeof buf); 7943149Seric a->q_user = buf; 7953149Seric 7963149Seric return (a); 7973149Seric } 7983188Seric /* 7994228Seric ** CATADDR -- concatenate pieces of addresses (putting in <LWSP> subs) 8004228Seric ** 8014228Seric ** Parameters: 8024228Seric ** pvp -- parameter vector to rebuild. 8034228Seric ** buf -- buffer to build the string into. 8044228Seric ** sz -- size of buf. 8054228Seric ** 8064228Seric ** Returns: 8074228Seric ** none. 8084228Seric ** 8094228Seric ** Side Effects: 8104228Seric ** Destroys buf. 8114228Seric */ 8124228Seric 8134228Seric cataddr(pvp, buf, sz) 8144228Seric char **pvp; 8154228Seric char *buf; 8164228Seric register int sz; 8174228Seric { 8184228Seric bool oatomtok = FALSE; 8194228Seric bool natomtok = FALSE; 8204228Seric register int i; 8214228Seric register char *p; 8224228Seric 8234228Seric p = buf; 8244228Seric sz--; 8254228Seric while (*pvp != NULL && (i = strlen(*pvp)) < sz) 8264228Seric { 8274228Seric natomtok = (toktype(**pvp) == ATOM); 8284228Seric if (oatomtok && natomtok) 8294228Seric *p++ = SPACESUB; 8304228Seric (void) strcpy(p, *pvp); 8314228Seric oatomtok = natomtok; 8324228Seric p += i; 8334228Seric sz -= i; 8344228Seric pvp++; 8354228Seric } 8364228Seric *p = '\0'; 8374228Seric } 8384228Seric /* 8393188Seric ** SAMEADDR -- Determine if two addresses are the same 8403188Seric ** 8413188Seric ** This is not just a straight comparison -- if the mailer doesn't 8423188Seric ** care about the host we just ignore it, etc. 8433188Seric ** 8443188Seric ** Parameters: 8453188Seric ** a, b -- pointers to the internal forms to compare. 8463188Seric ** wildflg -- if TRUE, 'a' may have no user specified, 8473188Seric ** in which case it is to match anything. 8483188Seric ** 8493188Seric ** Returns: 8503188Seric ** TRUE -- they represent the same mailbox. 8513188Seric ** FALSE -- they don't. 8523188Seric ** 8533188Seric ** Side Effects: 8543188Seric ** none. 8553188Seric */ 8563188Seric 8573188Seric bool 8583188Seric sameaddr(a, b, wildflg) 8593188Seric register ADDRESS *a; 8603188Seric register ADDRESS *b; 8613188Seric bool wildflg; 8623188Seric { 8633188Seric /* if they don't have the same mailer, forget it */ 8643188Seric if (a->q_mailer != b->q_mailer) 8653188Seric return (FALSE); 8663188Seric 8673188Seric /* if the user isn't the same, we can drop out */ 8683188Seric if ((!wildflg || a->q_user[0] != '\0') && strcmp(a->q_user, b->q_user) != 0) 8693188Seric return (FALSE); 8703188Seric 8713188Seric /* if the mailer ignores hosts, we have succeeded! */ 872*4598Seric if (bitset(M_LOCAL, a->q_mailer->m_flags)) 8733188Seric return (TRUE); 8743188Seric 8753188Seric /* otherwise compare hosts (but be careful for NULL ptrs) */ 8763188Seric if (a->q_host == NULL || b->q_host == NULL) 8773188Seric return (FALSE); 8783188Seric if (strcmp(a->q_host, b->q_host) != 0) 8793188Seric return (FALSE); 8803188Seric 8813188Seric return (TRUE); 8823188Seric } 8833234Seric /* 8843234Seric ** PRINTADDR -- print address (for debugging) 8853234Seric ** 8863234Seric ** Parameters: 8873234Seric ** a -- the address to print 8883234Seric ** follow -- follow the q_next chain. 8893234Seric ** 8903234Seric ** Returns: 8913234Seric ** none. 8923234Seric ** 8933234Seric ** Side Effects: 8943234Seric ** none. 8953234Seric */ 8963234Seric 8974317Seric # ifdef DEBUG 8984317Seric 8993234Seric printaddr(a, follow) 9003234Seric register ADDRESS *a; 9013234Seric bool follow; 9023234Seric { 9033234Seric while (a != NULL) 9043234Seric { 9054443Seric printf("%x=", a); 9064085Seric (void) fflush(stdout); 9073234Seric printf("%s: mailer %d (%s), host `%s', user `%s'\n", a->q_paddr, 908*4598Seric a->q_mailer->m_mno, a->q_mailer->m_name, a->q_host, a->q_user); 9094443Seric printf("\tnext=%x, flags=%o, rmailer %d\n", a->q_next, 9103234Seric a->q_flags, a->q_rmailer); 9113234Seric 9123234Seric if (!follow) 9133234Seric return; 9143234Seric a = a->q_next; 9153234Seric } 9164443Seric if (!follow) 9174443Seric printf("[NULL]\n"); 9183234Seric } 9194317Seric 9204317Seric # endif DEBUG 921