13312Seric # include "sendmail.h" 2297Seric 3*6977Seric SCCSID(@(#)parseaddr.c 3.41.1.1 05/29/82); 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 586903Seric CurEnv->e_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); 924598Seric 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 1756053Seric # define ONEMORE 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 2316053Seric nstate = toktype(c); 2323149Seric switch (state) 2333149Seric { 2343149Seric case QSTRING: /* in quoted string */ 2353149Seric break; 2363149Seric 2373149Seric case ATOM: /* regular atom */ 2384228Seric if (nstate != ATOM) 2393149Seric { 2403149Seric state = EOTOK; 2413149Seric p--; 2423149Seric } 2433149Seric break; 2443149Seric 2453149Seric case GETONE: /* grab one character */ 2463149Seric state = OPER; 2473149Seric break; 2483149Seric 2493149Seric case EOTOK: /* after atom or q-string */ 2503149Seric state = nstate; 2513149Seric if (state == SPACE) 2523149Seric continue; 2533149Seric break; 2543149Seric 2553149Seric case SPACE: /* linear white space */ 2563149Seric state = nstate; 2574228Seric break; 2583149Seric 2593149Seric case OPER: /* operator */ 2603149Seric if (nstate == SPACE) 2613149Seric continue; 2623149Seric state = nstate; 2633149Seric break; 2643149Seric 2656053Seric case ONEMORE: /* $- etc. */ 2666053Seric state = GETONE; 2673149Seric break; 2683149Seric 2693149Seric default: 2703149Seric syserr("prescan: unknown state %d", state); 2713149Seric } 2723149Seric 2734228Seric if (state == EOTOK || state == SPACE) 2743149Seric break; 2753149Seric 2763149Seric /* squirrel it away */ 2773149Seric if (q >= &buf[sizeof buf - 5]) 2783149Seric { 2793149Seric usrerr("Address too long"); 2803149Seric return (NULL); 2813149Seric } 2823149Seric *q++ = c; 2833149Seric 2843149Seric /* decide whether this represents end of token */ 2856053Seric if (state == OPER || state == GETONE) 2863149Seric break; 287297Seric } 2883149Seric if (c == '\0' || c == delim) 2893149Seric p--; 2903149Seric 2913149Seric /* new token */ 2923149Seric if (tok == q) 293297Seric continue; 2943149Seric *q++ = '\0'; 2953149Seric 2963149Seric c = tok[0]; 2973149Seric if (c == '(') 2981378Seric { 299297Seric cmntcnt++; 3001378Seric continue; 3011378Seric } 302297Seric else if (c == ')') 303297Seric { 304297Seric if (cmntcnt <= 0) 305297Seric { 306297Seric usrerr("Unbalanced ')'"); 307297Seric return (NULL); 308297Seric } 309297Seric else 310297Seric { 311297Seric cmntcnt--; 312297Seric continue; 313297Seric } 314297Seric } 3153149Seric else if (cmntcnt > 0) 3162091Seric continue; 3173149Seric 3183149Seric /* we prefer <> specs */ 3193149Seric if (c == '<') 320297Seric { 3212092Seric if (brccnt < 0) 3222092Seric { 3232092Seric usrerr("multiple < spec"); 3242092Seric return (NULL); 3252092Seric } 326297Seric brccnt++; 327297Seric if (brccnt == 1) 328297Seric { 329297Seric /* we prefer using machine readable name */ 330297Seric q = buf; 331297Seric *q = '\0'; 3323149Seric avp = av; 333297Seric continue; 334297Seric } 335297Seric } 336297Seric else if (c == '>') 337297Seric { 338297Seric if (brccnt <= 0) 339297Seric { 340297Seric usrerr("Unbalanced `>'"); 341297Seric return (NULL); 342297Seric } 343297Seric else 344297Seric brccnt--; 345297Seric if (brccnt <= 0) 3462092Seric { 3472092Seric brccnt = -1; 348297Seric continue; 3492092Seric } 350297Seric } 3514448Seric 3524448Seric if (avp >= &av[MAXATOM]) 3534448Seric { 3544448Seric syserr("prescan: too many tokens"); 3554448Seric return (NULL); 3564448Seric } 3574448Seric *avp++ = tok; 3583149Seric } 3593149Seric *avp = NULL; 3603149Seric if (cmntcnt > 0) 3613149Seric usrerr("Unbalanced '('"); 3623149Seric else if (brccnt > 0) 3633149Seric usrerr("Unbalanced '<'"); 3643149Seric else if (state == QSTRING) 3653149Seric usrerr("Unbalanced '\"'"); 3663149Seric else if (av[0] != NULL) 3673149Seric return (av); 3683149Seric return (NULL); 3693149Seric } 3703149Seric /* 3713149Seric ** TOKTYPE -- return token type 3723149Seric ** 3733149Seric ** Parameters: 3743149Seric ** c -- the character in question. 3753149Seric ** 3763149Seric ** Returns: 3773149Seric ** Its type. 3783149Seric ** 3793149Seric ** Side Effects: 3803149Seric ** none. 3813149Seric */ 382297Seric 3833149Seric toktype(c) 3843149Seric register char c; 3853149Seric { 3863380Seric static char buf[50]; 3873382Seric static bool firstime = TRUE; 3883380Seric 3893382Seric if (firstime) 3903380Seric { 3913382Seric firstime = FALSE; 392*6977Seric expand("$o", buf, &buf[sizeof buf - 1], CurEnv); 3933380Seric strcat(buf, DELIMCHARS); 3943380Seric } 3956053Seric if (c == MATCHCLASS || c == MATCHREPL) 3966053Seric return (ONEMORE); 3974100Seric if (!isascii(c)) 3984100Seric return (ATOM); 3993149Seric if (isspace(c)) 4003149Seric return (SPACE); 4013380Seric if (iscntrl(c) || index(buf, c) != NULL) 4023149Seric return (OPER); 4033149Seric return (ATOM); 4043149Seric } 4053149Seric /* 4063149Seric ** REWRITE -- apply rewrite rules to token vector. 4073149Seric ** 4084476Seric ** This routine is an ordered production system. Each rewrite 4094476Seric ** rule has a LHS (called the pattern) and a RHS (called the 4104476Seric ** rewrite); 'rwr' points the the current rewrite rule. 4114476Seric ** 4124476Seric ** For each rewrite rule, 'avp' points the address vector we 4134476Seric ** are trying to match against, and 'pvp' points to the pattern. 4144476Seric ** If pvp points to a special match value (MATCHANY, MATCHONE, 4154476Seric ** MATCHCLASS) then the address in avp matched is saved away 4164476Seric ** in the match vector (pointed to by 'mvp'). 4174476Seric ** 4184476Seric ** When a match between avp & pvp does not match, we try to 4194476Seric ** back out. If we back up over a MATCHONE or a MATCHCLASS 4204476Seric ** we must also back out the match in mvp. If we reach a 4214476Seric ** MATCHANY we just extend the match and start over again. 4224476Seric ** 4234476Seric ** When we finally match, we rewrite the address vector 4244476Seric ** and try over again. 4254476Seric ** 4263149Seric ** Parameters: 4273149Seric ** pvp -- pointer to token vector. 4283149Seric ** 4293149Seric ** Returns: 4303149Seric ** none. 4313149Seric ** 4323149Seric ** Side Effects: 4333149Seric ** pvp is modified. 4343149Seric */ 4352091Seric 4363149Seric struct match 4373149Seric { 4384468Seric char **first; /* first token matched */ 4394468Seric char **last; /* last token matched */ 4403149Seric }; 4413149Seric 4424468Seric # define MAXMATCH 9 /* max params per rewrite */ 4433149Seric 4443149Seric 4454070Seric rewrite(pvp, ruleset) 4463149Seric char **pvp; 4474070Seric int ruleset; 4483149Seric { 4493149Seric register char *ap; /* address pointer */ 4503149Seric register char *rp; /* rewrite pointer */ 4513149Seric register char **avp; /* address vector pointer */ 4523149Seric register char **rvp; /* rewrite vector pointer */ 4534468Seric struct rewrite *rwr; /* pointer to current rewrite rule */ 4544468Seric struct match mlist[MAXMATCH]; /* stores match on LHS */ 4554468Seric struct match *mlp; /* cur ptr into mlist */ 4563149Seric char *npvp[MAXATOM+1]; /* temporary space for rebuild */ 4574060Seric extern bool sameword(); 4583149Seric 4594100Seric # ifdef DEBUG 4604228Seric if (Debug > 9) 4613149Seric { 4623149Seric printf("rewrite: original pvp:\n"); 4633149Seric printav(pvp); 4643149Seric } 4654100Seric # endif DEBUG 4663149Seric 4673149Seric /* 4683149Seric ** Run through the list of rewrite rules, applying 4693149Seric ** any that match. 4703149Seric */ 4713149Seric 4724070Seric for (rwr = RewriteRules[ruleset]; rwr != NULL; ) 4733149Seric { 4744100Seric # ifdef DEBUG 4754100Seric if (Debug > 10) 476297Seric { 4773149Seric printf("-----trying rule:\n"); 4783149Seric printav(rwr->r_lhs); 4793149Seric } 4804100Seric # endif DEBUG 4813149Seric 4823149Seric /* try to match on this rule */ 4834468Seric mlp = mlist; 4844476Seric for (rvp = rwr->r_lhs, avp = pvp; *avp != NULL; ) 4853149Seric { 4863149Seric ap = *avp; 4873149Seric rp = *rvp; 4883149Seric 4893149Seric if (rp == NULL) 490297Seric { 4913149Seric /* end-of-pattern before end-of-address */ 4923149Seric goto fail; 493297Seric } 4943149Seric 4953149Seric switch (*rp) 4963149Seric { 4974060Seric register STAB *s; 4984060Seric register int class; 4994060Seric 5004060Seric case MATCHCLASS: 5014060Seric /* match any token in a class */ 5024060Seric class = rp[1]; 5034060Seric if (!isalpha(class)) 5044060Seric goto fail; 5054060Seric if (isupper(class)) 5064060Seric class -= 'A'; 5074060Seric else 5084060Seric class -= 'a'; 5094100Seric s = stab(ap, ST_CLASS, ST_FIND); 5106273Seric if (s == NULL || (s->s_class & (1L << class)) == 0) 5114060Seric goto fail; 5124468Seric 5134476Seric /* explicit fall-through */ 5144476Seric 5154476Seric case MATCHONE: 5164476Seric case MATCHANY: 5174476Seric /* match exactly one token */ 5184468Seric mlp->first = mlp->last = avp++; 5194468Seric mlp++; 5204060Seric break; 5214060Seric 5223149Seric default: 5233149Seric /* must have exact match */ 5244060Seric if (!sameword(rp, ap)) 5254060Seric goto fail; 5264468Seric avp++; 5273149Seric break; 5283149Seric } 5293149Seric 5303149Seric /* successful match on this token */ 5313149Seric rvp++; 5323149Seric continue; 5333149Seric 5343149Seric fail: 5353149Seric /* match failed -- back up */ 5363149Seric while (--rvp >= rwr->r_lhs) 5373149Seric { 5383149Seric rp = *rvp; 5393149Seric if (*rp == MATCHANY) 5404468Seric { 5414476Seric /* extend binding and continue */ 5424476Seric mlp[-1].last = avp++; 5434476Seric rvp++; 5443149Seric break; 5454468Seric } 5464476Seric avp--; 5474476Seric if (*rp == MATCHONE || *rp == MATCHCLASS) 5483149Seric { 5494468Seric /* back out binding */ 5504468Seric mlp--; 5513149Seric } 5523149Seric } 5533149Seric 5543149Seric if (rvp < rwr->r_lhs) 5553149Seric { 5563149Seric /* total failure to match */ 5573149Seric break; 5583149Seric } 559297Seric } 5603149Seric 5613149Seric /* 5623149Seric ** See if we successfully matched 5633149Seric */ 5643149Seric 5653149Seric if (rvp >= rwr->r_lhs && *rvp == NULL) 5663149Seric { 5674100Seric # ifdef DEBUG 5684100Seric if (Debug > 10) 5693149Seric { 5703149Seric printf("-----rule matches:\n"); 5713149Seric printav(rwr->r_rhs); 5723149Seric } 5734100Seric # endif DEBUG 5743149Seric 5753149Seric /* substitute */ 5763149Seric for (rvp = rwr->r_rhs, avp = npvp; *rvp != NULL; rvp++) 5773149Seric { 5783149Seric rp = *rvp; 5794468Seric if (*rp == MATCHREPL) 5803149Seric { 5813149Seric register struct match *m; 5823149Seric register char **pp; 5833149Seric 5844468Seric m = &mlist[rp[1] - '1']; 5854476Seric # ifdef DEBUG 5864476Seric if (Debug > 13) 5874476Seric { 5884476Seric printf("$%c:", rp[1]); 5894476Seric pp = m->first; 5904476Seric do 5914476Seric { 5924476Seric printf(" %x=\"", *pp); 5934625Seric (void) fflush(stdout); 5944476Seric printf("%s\"", *pp); 5954476Seric } while (pp++ != m->last); 5964476Seric printf("\n"); 5974476Seric } 5984476Seric # endif DEBUG 5994468Seric pp = m->first; 6004468Seric do 6013149Seric { 6024468Seric if (avp >= &npvp[MAXATOM]) 6033149Seric { 6044468Seric syserr("rewrite: expansion too long"); 6054468Seric return; 6064468Seric } 6074468Seric *avp++ = *pp; 6084468Seric } while (pp++ != m->last); 6093149Seric } 6103149Seric else 6114385Seric { 6124385Seric if (avp >= &npvp[MAXATOM]) 6134385Seric { 6144385Seric syserr("rewrite: expansion too long"); 6154385Seric return; 6164385Seric } 6173149Seric *avp++ = rp; 6184385Seric } 6193149Seric } 6203149Seric *avp++ = NULL; 6214085Seric bmove((char *) npvp, (char *) pvp, (avp - npvp) * sizeof *avp); 6223149Seric # ifdef DEBUG 6234228Seric if (Debug > 3) 6243149Seric { 6253188Seric char **vp; 6263188Seric 6273188Seric printf("rewritten as `"); 6283188Seric for (vp = pvp; *vp != NULL; vp++) 6294228Seric { 6304228Seric if (vp != pvp) 6314228Seric printf("_"); 6323188Seric xputs(*vp); 6334228Seric } 6343188Seric printf("'\n"); 6353149Seric } 6363149Seric # endif DEBUG 6373149Seric if (pvp[0][0] == CANONNET) 6383149Seric break; 6393149Seric } 6403149Seric else 6413149Seric { 6424100Seric # ifdef DEBUG 6434100Seric if (Debug > 10) 6443149Seric printf("----- rule fails\n"); 6454100Seric # endif DEBUG 6463149Seric rwr = rwr->r_next; 6473149Seric } 648297Seric } 6493149Seric } 6503149Seric /* 6513149Seric ** BUILDADDR -- build address from token vector. 6523149Seric ** 6533149Seric ** Parameters: 6543149Seric ** tv -- token vector. 6553149Seric ** a -- pointer to address descriptor to fill. 6563149Seric ** If NULL, one will be allocated. 6573149Seric ** 6583149Seric ** Returns: 6594279Seric ** NULL if there was an error. 6604279Seric ** 'a' otherwise. 6613149Seric ** 6623149Seric ** Side Effects: 6633149Seric ** fills in 'a' 6643149Seric */ 6653149Seric 6663149Seric ADDRESS * 6673149Seric buildaddr(tv, a) 6683149Seric register char **tv; 6693149Seric register ADDRESS *a; 6703149Seric { 6713149Seric static char buf[MAXNAME]; 6723149Seric struct mailer **mp; 6733149Seric register struct mailer *m; 6744635Seric extern bool sameword(); 6753149Seric 6763149Seric if (a == NULL) 6773149Seric a = (ADDRESS *) xalloc(sizeof *a); 6784988Seric clear((char *) a, sizeof *a); 6793149Seric 6803149Seric /* figure out what net/mailer to use */ 6813149Seric if (**tv != CANONNET) 6824279Seric { 6833149Seric syserr("buildaddr: no net"); 6844279Seric return (NULL); 6854279Seric } 6863149Seric tv++; 6874635Seric if (sameword(*tv, "error")) 6884279Seric { 6894279Seric if (**++tv != CANONUSER) 6904279Seric syserr("buildaddr: error: no user"); 6914279Seric buf[0] = '\0'; 6924279Seric while (*++tv != NULL) 6934279Seric { 6944279Seric if (buf[0] != '\0') 6954279Seric strcat(buf, " "); 6964279Seric strcat(buf, *tv); 6974279Seric } 6984279Seric usrerr(buf); 6994279Seric return (NULL); 7004279Seric } 7014598Seric for (mp = Mailer; (m = *mp++) != NULL; ) 7023149Seric { 7034635Seric if (sameword(m->m_name, *tv)) 7043149Seric break; 7053149Seric } 7063149Seric if (m == NULL) 7074279Seric { 7083149Seric syserr("buildaddr: unknown net %s", *tv); 7094279Seric return (NULL); 7104279Seric } 7114598Seric a->q_mailer = m; 7123149Seric 7133149Seric /* figure out what host (if any) */ 7143149Seric tv++; 7154195Seric if (!bitset(M_LOCAL, m->m_flags)) 7163149Seric { 7175704Seric if (**tv++ != CANONHOST) 7184279Seric { 7193149Seric syserr("buildaddr: no host"); 7204279Seric return (NULL); 7214279Seric } 7225704Seric buf[0] = '\0'; 7235704Seric while (*tv != NULL && **tv != CANONUSER) 7245704Seric strcat(buf, *tv++); 7255704Seric a->q_host = newstr(buf); 7263149Seric } 7273149Seric else 7283149Seric a->q_host = NULL; 7293149Seric 7303149Seric /* figure out the user */ 7313149Seric if (**tv != CANONUSER) 7324279Seric { 7333149Seric syserr("buildaddr: no user"); 7344279Seric return (NULL); 7354279Seric } 7364228Seric cataddr(++tv, buf, sizeof buf); 7373149Seric a->q_user = buf; 7383149Seric 7393149Seric return (a); 7403149Seric } 7413188Seric /* 7424228Seric ** CATADDR -- concatenate pieces of addresses (putting in <LWSP> subs) 7434228Seric ** 7444228Seric ** Parameters: 7454228Seric ** pvp -- parameter vector to rebuild. 7464228Seric ** buf -- buffer to build the string into. 7474228Seric ** sz -- size of buf. 7484228Seric ** 7494228Seric ** Returns: 7504228Seric ** none. 7514228Seric ** 7524228Seric ** Side Effects: 7534228Seric ** Destroys buf. 7544228Seric */ 7554228Seric 7564228Seric cataddr(pvp, buf, sz) 7574228Seric char **pvp; 7584228Seric char *buf; 7594228Seric register int sz; 7604228Seric { 7614228Seric bool oatomtok = FALSE; 7624228Seric bool natomtok = FALSE; 7634228Seric register int i; 7644228Seric register char *p; 7654228Seric 7664228Seric p = buf; 7674228Seric sz--; 7684228Seric while (*pvp != NULL && (i = strlen(*pvp)) < sz) 7694228Seric { 7704228Seric natomtok = (toktype(**pvp) == ATOM); 7714228Seric if (oatomtok && natomtok) 7724228Seric *p++ = SPACESUB; 7734228Seric (void) strcpy(p, *pvp); 7744228Seric oatomtok = natomtok; 7754228Seric p += i; 7764228Seric sz -= i; 7774228Seric pvp++; 7784228Seric } 7794228Seric *p = '\0'; 7804228Seric } 7814228Seric /* 7823188Seric ** SAMEADDR -- Determine if two addresses are the same 7833188Seric ** 7843188Seric ** This is not just a straight comparison -- if the mailer doesn't 7853188Seric ** care about the host we just ignore it, etc. 7863188Seric ** 7873188Seric ** Parameters: 7883188Seric ** a, b -- pointers to the internal forms to compare. 7893188Seric ** wildflg -- if TRUE, 'a' may have no user specified, 7903188Seric ** in which case it is to match anything. 7913188Seric ** 7923188Seric ** Returns: 7933188Seric ** TRUE -- they represent the same mailbox. 7943188Seric ** FALSE -- they don't. 7953188Seric ** 7963188Seric ** Side Effects: 7973188Seric ** none. 7983188Seric */ 7993188Seric 8003188Seric bool 8013188Seric sameaddr(a, b, wildflg) 8023188Seric register ADDRESS *a; 8033188Seric register ADDRESS *b; 8043188Seric bool wildflg; 8053188Seric { 8063188Seric /* if they don't have the same mailer, forget it */ 8073188Seric if (a->q_mailer != b->q_mailer) 8083188Seric return (FALSE); 8093188Seric 8103188Seric /* if the user isn't the same, we can drop out */ 8113188Seric if ((!wildflg || a->q_user[0] != '\0') && strcmp(a->q_user, b->q_user) != 0) 8123188Seric return (FALSE); 8133188Seric 8143188Seric /* if the mailer ignores hosts, we have succeeded! */ 8154598Seric if (bitset(M_LOCAL, a->q_mailer->m_flags)) 8163188Seric return (TRUE); 8173188Seric 8183188Seric /* otherwise compare hosts (but be careful for NULL ptrs) */ 8193188Seric if (a->q_host == NULL || b->q_host == NULL) 8203188Seric return (FALSE); 8213188Seric if (strcmp(a->q_host, b->q_host) != 0) 8223188Seric return (FALSE); 8233188Seric 8243188Seric return (TRUE); 8253188Seric } 8263234Seric /* 8273234Seric ** PRINTADDR -- print address (for debugging) 8283234Seric ** 8293234Seric ** Parameters: 8303234Seric ** a -- the address to print 8313234Seric ** follow -- follow the q_next chain. 8323234Seric ** 8333234Seric ** Returns: 8343234Seric ** none. 8353234Seric ** 8363234Seric ** Side Effects: 8373234Seric ** none. 8383234Seric */ 8393234Seric 8404317Seric # ifdef DEBUG 8414317Seric 8423234Seric printaddr(a, follow) 8433234Seric register ADDRESS *a; 8443234Seric bool follow; 8453234Seric { 8465001Seric bool first = TRUE; 8475001Seric 8483234Seric while (a != NULL) 8493234Seric { 8505001Seric first = FALSE; 8514443Seric printf("%x=", a); 8524085Seric (void) fflush(stdout); 8533234Seric printf("%s: mailer %d (%s), host `%s', user `%s'\n", a->q_paddr, 8544598Seric a->q_mailer->m_mno, a->q_mailer->m_name, a->q_host, a->q_user); 8555035Seric printf("\tnext=%x, flags=%o, rmailer %d, alias %x\n", a->q_next, 8565035Seric a->q_flags, a->q_rmailer, a->q_alias); 8575001Seric printf("\thome=\"%s\", fullname=\"%s\"\n", a->q_home, a->q_fullname); 8584996Seric 8593234Seric if (!follow) 8603234Seric return; 8614996Seric a = a->q_next; 8623234Seric } 8635001Seric if (first) 8644443Seric printf("[NULL]\n"); 8653234Seric } 8664317Seric 8674317Seric # endif DEBUG 868