1297Seric # include <stdio.h> 2297Seric # include <ctype.h> 32973Seric # include "postbox.h" 4297Seric 5*3154Seric static char SccsId[] = "@(#)parseaddr.c 3.7 03/09/81"; 6407Seric 7297Seric /* 8297Seric ** PARSE -- Parse an address 9297Seric ** 10297Seric ** Parses an address and breaks it up into three parts: a 11297Seric ** net to transmit the message on, the host to transmit it 12297Seric ** to, and a user on that host. These are loaded into an 132973Seric ** ADDRESS header with the values squirreled away if necessary. 14297Seric ** The "user" part may not be a real user; the process may 15297Seric ** just reoccur on that machine. For example, on a machine 16297Seric ** with an arpanet connection, the address 17297Seric ** csvax.bill@berkeley 18297Seric ** will break up to a "user" of 'csvax.bill' and a host 19297Seric ** of 'berkeley' -- to be transmitted over the arpanet. 20297Seric ** 21297Seric ** Parameters: 22297Seric ** addr -- the address to parse. 23297Seric ** a -- a pointer to the address descriptor buffer. 24297Seric ** If NULL, a header will be created. 25297Seric ** copyf -- determines what shall be copied: 26297Seric ** -1 -- don't copy anything. The printname 27297Seric ** (q_paddr) is just addr, and the 28297Seric ** user & host are allocated internally 29297Seric ** to parse. 30297Seric ** 0 -- copy out the parsed user & host, but 31297Seric ** don't copy the printname. 32297Seric ** +1 -- copy everything. 33297Seric ** 34297Seric ** Returns: 35297Seric ** A pointer to the address descriptor header (`a' if 36297Seric ** `a' is non-NULL). 37297Seric ** NULL on error. 38297Seric ** 39297Seric ** Side Effects: 40297Seric ** none 41297Seric ** 42297Seric ** Called By: 43297Seric ** main 44297Seric ** sendto 45297Seric ** alias 46297Seric ** savemail 47297Seric */ 48297Seric 493149Seric # define DELIMCHARS "$()<>@!.,;:\\\" \t\r\n" /* word delimiters */ 502091Seric # define SPACESUB ('.'|0200) /* substitution for <lwsp> */ 512091Seric 522973Seric ADDRESS * 53297Seric parse(addr, a, copyf) 54297Seric char *addr; 552973Seric register ADDRESS *a; 56297Seric int copyf; 57297Seric { 583149Seric register char **pvp; 593149Seric register struct mailer *m; 603149Seric extern char **prescan(); 61297Seric extern char *xalloc(); 622973Seric extern char *newstr(); 632990Seric extern char *strcpy(); 643149Seric extern ADDRESS *buildaddr(); 65297Seric 66297Seric /* 67297Seric ** Initialize and prescan address. 68297Seric */ 69297Seric 70297Seric To = addr; 713149Seric pvp = prescan(addr, '\0'); 723149Seric if (pvp == NULL) 73297Seric return (NULL); 74297Seric 75297Seric /* 763149Seric ** Apply rewriting rules. 77297Seric */ 78297Seric 793149Seric rewrite(pvp); 80297Seric 813149Seric /* 823149Seric ** See if we resolved to a real mailer. 833149Seric */ 84297Seric 853149Seric if (pvp[0][0] != CANONNET) 863149Seric { 873149Seric setstat(EX_USAGE); 883149Seric usrerr("cannot resolve name"); 893149Seric return (NULL); 90297Seric } 91297Seric 92297Seric /* 933149Seric ** Build canonical address from pvp. 94297Seric */ 95297Seric 963149Seric a = buildaddr(pvp, a); 973149Seric m = Mailer[a->q_mailer]; 98297Seric 99297Seric /* 1003149Seric ** Make local copies of the host & user and then 1013149Seric ** transport them out. 102297Seric */ 103297Seric 104297Seric if (copyf > 0) 1052973Seric a->q_paddr = newstr(addr); 106297Seric else 107297Seric a->q_paddr = addr; 108297Seric 1093149Seric if (copyf >= 0) 110297Seric { 1113149Seric if (a->q_host != NULL) 1123149Seric a->q_host = newstr(a->q_host); 113297Seric else 1143149Seric a->q_host = ""; 1153149Seric if (a->q_user != a->q_paddr) 1163149Seric a->q_user = newstr(a->q_user); 117297Seric } 118297Seric 119297Seric /* 120297Seric ** Do UPPER->lower case mapping unless inhibited. 121297Seric */ 122297Seric 1233149Seric if (!bitset(M_HST_UPPER, m->m_flags)) 124297Seric makelower(a->q_host); 1253149Seric if (!bitset(M_USR_UPPER, m->m_flags)) 126297Seric makelower(a->q_user); 127297Seric 128297Seric /* 129297Seric ** Compute return value. 130297Seric */ 131297Seric 132297Seric # ifdef DEBUG 1331583Seric if (Debug) 134297Seric printf("parse(\"%s\"): host \"%s\" user \"%s\" mailer %d\n", 1353149Seric addr, a->q_host, a->q_user, a->q_mailer); 136297Seric # endif DEBUG 137297Seric 138297Seric return (a); 139297Seric } 140297Seric /* 141297Seric ** PRESCAN -- Prescan name and make it canonical 142297Seric ** 143297Seric ** Scans a name and turns it into canonical form. This involves 144297Seric ** deleting blanks, comments (in parentheses), and turning the 145297Seric ** word "at" into an at-sign ("@"). The name is copied as this 146297Seric ** is done; it is legal to copy a name onto itself, since this 147297Seric ** process can only make things smaller. 148297Seric ** 149297Seric ** This routine knows about quoted strings and angle brackets. 150297Seric ** 151297Seric ** There are certain subtleties to this routine. The one that 152297Seric ** comes to mind now is that backslashes on the ends of names 153297Seric ** are silently stripped off; this is intentional. The problem 154297Seric ** is that some versions of sndmsg (like at LBL) set the kill 155297Seric ** character to something other than @ when reading addresses; 156297Seric ** so people type "csvax.eric\@berkeley" -- which screws up the 157297Seric ** berknet mailer. 158297Seric ** 159297Seric ** Parameters: 160297Seric ** addr -- the name to chomp. 161297Seric ** delim -- the delimiter for the address, normally 162297Seric ** '\0' or ','; \0 is accepted in any case. 163297Seric ** are moving in place; set buflim to high core. 164297Seric ** 165297Seric ** Returns: 1663149Seric ** A pointer to a vector of tokens. 167297Seric ** NULL on error. 168297Seric ** 169297Seric ** Side Effects: 1703149Seric ** none. 171297Seric */ 172297Seric 1733149Seric # define OPER 1 1743149Seric # define ATOM 2 1753149Seric # define EOTOK 3 1763149Seric # define QSTRING 4 1773149Seric # define SPACE 5 1783149Seric # define DOLLAR 6 1793149Seric # define GETONE 7 1803149Seric 1813149Seric char ** 1823149Seric prescan(addr, delim) 183297Seric char *addr; 184297Seric char delim; 185297Seric { 186297Seric register char *p; 1873149Seric static char buf[MAXNAME+MAXATOM]; 1883149Seric static char *av[MAXATOM+1]; 1893149Seric char **avp; 190297Seric bool space; 191297Seric bool bslashmode; 192297Seric int cmntcnt; 193297Seric int brccnt; 194297Seric register char c; 1953149Seric char *tok; 196297Seric register char *q; 1972973Seric extern char *index(); 1983149Seric register int state; 1993149Seric int nstate; 200297Seric 2012091Seric space = FALSE; 202297Seric q = buf; 2033149Seric bslashmode = FALSE; 204297Seric cmntcnt = brccnt = 0; 2053149Seric avp = av; 2063149Seric state = OPER; 2073149Seric for (p = addr; *p != '\0' && *p != delim; ) 208297Seric { 2093149Seric /* read a token */ 2103149Seric tok = q; 2113149Seric while ((c = *p++) != '\0' && c != delim) 212297Seric { 2133149Seric /* chew up special characters */ 2143149Seric *q = '\0'; 2153149Seric if (bslashmode) 2163149Seric { 2173149Seric c |= 0200; 2183149Seric bslashmode = FALSE; 2193149Seric } 2203149Seric else if (c == '\\') 2213149Seric { 2223149Seric bslashmode = TRUE; 2233149Seric continue; 2243149Seric } 2253149Seric 2263149Seric nstate = toktype(c); 2273149Seric switch (state) 2283149Seric { 2293149Seric case QSTRING: /* in quoted string */ 2303149Seric if (c == '"') 2313149Seric state = OPER; 2323149Seric break; 2333149Seric 2343149Seric case ATOM: /* regular atom */ 2353149Seric state = nstate; 2363149Seric if (state != ATOM) 2373149Seric { 2383149Seric state = EOTOK; 2393149Seric p--; 2403149Seric } 2413149Seric break; 2423149Seric 2433149Seric case GETONE: /* grab one character */ 2443149Seric state = OPER; 2453149Seric break; 2463149Seric 2473149Seric case EOTOK: /* after atom or q-string */ 2483149Seric state = nstate; 2493149Seric if (state == SPACE) 2503149Seric continue; 2513149Seric break; 2523149Seric 2533149Seric case SPACE: /* linear white space */ 2543149Seric state = nstate; 2553149Seric space = TRUE; 2563149Seric continue; 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 2813149Seric case '#': /* canonical net name */ 2823149Seric c = CANONNET; 2833149Seric break; 2843149Seric 2853149Seric case '@': /* canonical host name */ 2863149Seric c = CANONHOST; 2873149Seric break; 2883149Seric 2893149Seric case ':': /* canonical user name */ 2903149Seric c = CANONUSER; 2913149Seric break; 2923149Seric 2933149Seric default: 2943149Seric c = '$'; 2953149Seric state = OPER; 2963149Seric p--; 2973149Seric break; 2983149Seric } 2993149Seric break; 3003149Seric 3013149Seric default: 3023149Seric syserr("prescan: unknown state %d", state); 3033149Seric } 3043149Seric 3053149Seric if (state == OPER) 3063149Seric space = FALSE; 3073149Seric else if (state == EOTOK) 3083149Seric break; 3093149Seric if (c == '$' && delim == '\t') 3103149Seric { 3113149Seric state = DOLLAR; 3123149Seric continue; 3133149Seric } 3143149Seric 3153149Seric /* squirrel it away */ 3163149Seric if (q >= &buf[sizeof buf - 5]) 3173149Seric { 3183149Seric usrerr("Address too long"); 3193149Seric return (NULL); 3203149Seric } 3213149Seric if (space) 3223149Seric *q++ = SPACESUB; 3233149Seric *q++ = c; 3243149Seric 3253149Seric /* decide whether this represents end of token */ 3263149Seric if (state == OPER) 3273149Seric break; 328297Seric } 3293149Seric if (c == '\0' || c == delim) 3303149Seric p--; 3313149Seric 3323149Seric /* new token */ 3333149Seric if (tok == q) 334297Seric continue; 3353149Seric *q++ = '\0'; 3363149Seric 3373149Seric c = tok[0]; 3383149Seric if (c == '(') 3391378Seric { 340297Seric cmntcnt++; 3411378Seric continue; 3421378Seric } 343297Seric else if (c == ')') 344297Seric { 345297Seric if (cmntcnt <= 0) 346297Seric { 347297Seric usrerr("Unbalanced ')'"); 348297Seric return (NULL); 349297Seric } 350297Seric else 351297Seric { 352297Seric cmntcnt--; 353297Seric continue; 354297Seric } 355297Seric } 3563149Seric else if (cmntcnt > 0) 3572091Seric continue; 3583149Seric 3593149Seric *avp++ = tok; 3603149Seric 3613149Seric /* we prefer <> specs */ 3623149Seric if (c == '<') 363297Seric { 3642092Seric if (brccnt < 0) 3652092Seric { 3662092Seric usrerr("multiple < spec"); 3672092Seric return (NULL); 3682092Seric } 369297Seric brccnt++; 3702091Seric space = FALSE; 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 } 395297Seric 396297Seric /* 397297Seric ** Turn "at" into "@", 3981378Seric ** but only if "at" is a word. 399297Seric */ 400297Seric 4013149Seric if (lower(tok[0]) == 'a' && lower(tok[1]) == 't' && tok[2] == '\0') 402297Seric { 4033149Seric tok[0] = '@'; 4043149Seric tok[1] = '\0'; 405297Seric } 4063149Seric } 4073149Seric *avp = NULL; 4083149Seric if (cmntcnt > 0) 4093149Seric usrerr("Unbalanced '('"); 4103149Seric else if (brccnt > 0) 4113149Seric usrerr("Unbalanced '<'"); 4123149Seric else if (state == QSTRING) 4133149Seric usrerr("Unbalanced '\"'"); 4143149Seric else if (av[0] != NULL) 4153149Seric return (av); 4163149Seric return (NULL); 4173149Seric } 4183149Seric /* 4193149Seric ** TOKTYPE -- return token type 4203149Seric ** 4213149Seric ** Parameters: 4223149Seric ** c -- the character in question. 4233149Seric ** 4243149Seric ** Returns: 4253149Seric ** Its type. 4263149Seric ** 4273149Seric ** Side Effects: 4283149Seric ** none. 4293149Seric */ 430297Seric 4313149Seric toktype(c) 4323149Seric register char c; 4333149Seric { 4343149Seric if (isspace(c)) 4353149Seric return (SPACE); 4363149Seric if (index(DELIMCHARS, c) != NULL || iscntrl(c)) 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 4633149Seric rewrite(pvp) 4643149Seric char **pvp; 4653149Seric { 4663149Seric register char *ap; /* address pointer */ 4673149Seric register char *rp; /* rewrite pointer */ 4683149Seric register char **avp; /* address vector pointer */ 4693149Seric register char **rvp; /* rewrite vector pointer */ 4703149Seric struct rewrite *rwr; 4713149Seric struct match mlist[MAXMATCH]; 4723149Seric char *npvp[MAXATOM+1]; /* temporary space for rebuild */ 4733149Seric 4743149Seric # ifdef DEBUG 4753149Seric if (Debug) 4763149Seric { 4773149Seric printf("rewrite: original pvp:\n"); 4783149Seric printav(pvp); 4793149Seric } 4803149Seric # endif DEBUG 4813149Seric 4823149Seric /* 4833149Seric ** Run through the list of rewrite rules, applying 4843149Seric ** any that match. 4853149Seric */ 4863149Seric 4873149Seric for (rwr = RewriteRules; rwr != NULL; ) 4883149Seric { 4893149Seric # ifdef DEBUG 4903149Seric if (Debug) 491297Seric { 4923149Seric printf("-----trying rule:\n"); 4933149Seric printav(rwr->r_lhs); 4943149Seric } 4953149Seric # endif DEBUG 4963149Seric 4973149Seric /* try to match on this rule */ 4983149Seric clrmatch(mlist); 4993149Seric for (rvp = rwr->r_lhs, avp = pvp; *avp != NULL; ) 5003149Seric { 5013149Seric ap = *avp; 5023149Seric rp = *rvp; 5033149Seric 5043149Seric if (rp == NULL) 505297Seric { 5063149Seric /* end-of-pattern before end-of-address */ 5073149Seric goto fail; 508297Seric } 5093149Seric 5103149Seric switch (*rp) 5113149Seric { 5123149Seric case MATCHONE: 5133149Seric /* match exactly one token */ 5143149Seric setmatch(mlist, rp[1], avp, avp); 5153149Seric break; 5163149Seric 5173149Seric case MATCHANY: 5183149Seric /* match any number of tokens */ 5193149Seric setmatch(mlist, rp[1], NULL, avp); 5203149Seric break; 5213149Seric 5223149Seric default: 5233149Seric /* must have exact match */ 5243149Seric /* can scribble rp & ap here safely */ 525*3154Seric while (*rp != '\0' || *ap != '\0') 5263149Seric { 5273149Seric if (*rp++ != lower(*ap++)) 5283149Seric goto fail; 5293149Seric } 5303149Seric break; 5313149Seric } 5323149Seric 5333149Seric /* successful match on this token */ 5343149Seric avp++; 5353149Seric rvp++; 5363149Seric continue; 5373149Seric 5383149Seric fail: 5393149Seric /* match failed -- back up */ 5403149Seric while (--rvp >= rwr->r_lhs) 5413149Seric { 5423149Seric rp = *rvp; 5433149Seric if (*rp == MATCHANY) 5443149Seric break; 5453149Seric 5463149Seric /* can't extend match: back up everything */ 5473149Seric avp--; 5483149Seric 5493149Seric if (*rp == MATCHONE) 5503149Seric { 5513149Seric /* undo binding */ 5523149Seric setmatch(mlist, rp[1], NULL, NULL); 5533149Seric } 5543149Seric } 5553149Seric 5563149Seric if (rvp < rwr->r_lhs) 5573149Seric { 5583149Seric /* total failure to match */ 5593149Seric break; 5603149Seric } 561297Seric } 5623149Seric 5633149Seric /* 5643149Seric ** See if we successfully matched 5653149Seric */ 5663149Seric 5673149Seric if (rvp >= rwr->r_lhs && *rvp == NULL) 5683149Seric { 5693149Seric # ifdef DEBUG 5703149Seric if (Debug) 5713149Seric { 5723149Seric printf("-----rule matches:\n"); 5733149Seric printav(rwr->r_rhs); 5743149Seric } 5753149Seric # endif DEBUG 5763149Seric 5773149Seric /* substitute */ 5783149Seric for (rvp = rwr->r_rhs, avp = npvp; *rvp != NULL; rvp++) 5793149Seric { 5803149Seric rp = *rvp; 5813149Seric if (*rp == MATCHANY) 5823149Seric { 5833149Seric register struct match *m; 5843149Seric register char **pp; 5853149Seric extern struct match *findmatch(); 5863149Seric 5873149Seric m = findmatch(mlist, rp[1]); 5883149Seric if (m != NULL) 5893149Seric { 5903149Seric pp = m->firsttok; 5913149Seric do 5923149Seric { 5933149Seric *avp++ = *pp; 5943149Seric } while (pp++ != m->lasttok); 5953149Seric } 5963149Seric } 5973149Seric else 5983149Seric *avp++ = rp; 5993149Seric } 6003149Seric *avp++ = NULL; 6013149Seric bmove(npvp, pvp, (avp - npvp) * sizeof *avp); 6023149Seric # ifdef DEBUG 6033149Seric if (Debug) 6043149Seric { 6053149Seric printf("rewritten as:\n"); 6063149Seric printav(pvp); 6073149Seric } 6083149Seric # endif DEBUG 6093149Seric if (pvp[0][0] == CANONNET) 6103149Seric break; 6113149Seric } 6123149Seric else 6133149Seric { 6143149Seric # ifdef DEBUG 6153149Seric if (Debug) 6163149Seric printf("----- rule fails\n"); 6173149Seric # endif DEBUG 6183149Seric rwr = rwr->r_next; 6193149Seric } 620297Seric } 6213149Seric } 6223149Seric /* 6233149Seric ** SETMATCH -- set parameter value in match vector 6243149Seric ** 6253149Seric ** Parameters: 6263149Seric ** mlist -- list of match values. 6273149Seric ** name -- the character name of this parameter. 6283149Seric ** first -- the first location of the replacement. 6293149Seric ** last -- the last location of the replacement. 6303149Seric ** 6313149Seric ** If last == NULL, delete this entry. 6323149Seric ** If first == NULL, extend this entry (or add it if 6333149Seric ** it does not exist). 6343149Seric ** 6353149Seric ** Returns: 6363149Seric ** nothing. 6373149Seric ** 6383149Seric ** Side Effects: 6393149Seric ** munges with mlist. 6403149Seric */ 6413149Seric 6423149Seric setmatch(mlist, name, first, last) 6433149Seric struct match *mlist; 6443149Seric char name; 6453149Seric char **first; 6463149Seric char **last; 6473149Seric { 6483149Seric register struct match *m; 6493149Seric struct match *nullm = NULL; 6503149Seric 6513149Seric for (m = mlist; m < &mlist[MAXMATCH]; m++) 6523149Seric { 6533149Seric if (m->name == name) 6543149Seric break; 6553149Seric if (m->name == '\0') 6563149Seric nullm = m; 6573149Seric } 6583149Seric 6593149Seric if (m >= &mlist[MAXMATCH]) 6603149Seric m = nullm; 6613149Seric 6623149Seric if (last == NULL) 6633149Seric { 6643149Seric m->name = '\0'; 6653149Seric return; 6663149Seric } 6673149Seric 6683149Seric if (m->name == '\0') 6693149Seric { 6703149Seric if (first == NULL) 6713149Seric m->firsttok = last; 6723149Seric else 6733149Seric m->firsttok = first; 6743149Seric } 6753149Seric m->name = name; 6763149Seric m->lasttok = last; 6773149Seric } 6783149Seric /* 6793149Seric ** FINDMATCH -- find match in mlist 6803149Seric ** 6813149Seric ** Parameters: 6823149Seric ** mlist -- list to search. 6833149Seric ** name -- name to find. 6843149Seric ** 6853149Seric ** Returns: 6863149Seric ** pointer to match structure. 6873149Seric ** NULL if no match. 6883149Seric ** 6893149Seric ** Side Effects: 6903149Seric ** none. 6913149Seric */ 6923149Seric 6933149Seric struct match * 6943149Seric findmatch(mlist, name) 6953149Seric struct match *mlist; 6963149Seric char name; 6973149Seric { 6983149Seric register struct match *m; 6993149Seric 7003149Seric for (m = mlist; m < &mlist[MAXMATCH]; m++) 7013149Seric { 7023149Seric if (m->name == name) 7033149Seric return (m); 7043149Seric } 7053149Seric 706297Seric return (NULL); 707297Seric } 7083149Seric /* 7093149Seric ** CLRMATCH -- clear match list 7103149Seric ** 7113149Seric ** Parameters: 7123149Seric ** mlist -- list to clear. 7133149Seric ** 7143149Seric ** Returns: 7153149Seric ** none. 7163149Seric ** 7173149Seric ** Side Effects: 7183149Seric ** mlist is cleared. 7193149Seric */ 7203149Seric 7213149Seric clrmatch(mlist) 7223149Seric struct match *mlist; 7233149Seric { 7243149Seric register struct match *m; 7253149Seric 7263149Seric for (m = mlist; m < &mlist[MAXMATCH]; m++) 7273149Seric m->name = '\0'; 7283149Seric } 7293149Seric /* 7303149Seric ** BUILDADDR -- build address from token vector. 7313149Seric ** 7323149Seric ** Parameters: 7333149Seric ** tv -- token vector. 7343149Seric ** a -- pointer to address descriptor to fill. 7353149Seric ** If NULL, one will be allocated. 7363149Seric ** 7373149Seric ** Returns: 7383149Seric ** 'a' 7393149Seric ** 7403149Seric ** Side Effects: 7413149Seric ** fills in 'a' 7423149Seric */ 7433149Seric 7443149Seric ADDRESS * 7453149Seric buildaddr(tv, a) 7463149Seric register char **tv; 7473149Seric register ADDRESS *a; 7483149Seric { 7493149Seric register int i; 7503149Seric static char buf[MAXNAME]; 7513149Seric struct mailer **mp; 7523149Seric register struct mailer *m; 7533149Seric extern char *xalloc(); 7543149Seric 7553149Seric if (a == NULL) 7563149Seric a = (ADDRESS *) xalloc(sizeof *a); 7573149Seric 7583149Seric /* figure out what net/mailer to use */ 7593149Seric if (**tv != CANONNET) 7603149Seric syserr("buildaddr: no net"); 7613149Seric tv++; 762*3154Seric for (mp = Mailer, i = 0; (m = *mp++) != NULL; i++) 7633149Seric { 7643149Seric if (strcmp(m->m_name, *tv) == 0) 7653149Seric break; 7663149Seric } 7673149Seric if (m == NULL) 7683149Seric syserr("buildaddr: unknown net %s", *tv); 7693149Seric a->q_mailer = i; 7703149Seric 7713149Seric /* figure out what host (if any) */ 7723149Seric tv++; 7733149Seric if (!bitset(M_NOHOST, m->m_flags)) 7743149Seric { 7753149Seric if (**tv != CANONHOST) 7763149Seric syserr("buildaddr: no host"); 7773149Seric tv++; 7783149Seric a->q_host = *tv; 7793149Seric tv++; 7803149Seric } 7813149Seric else 7823149Seric a->q_host = NULL; 7833149Seric 7843149Seric /* figure out the user */ 7853149Seric if (**tv != CANONUSER) 7863149Seric syserr("buildaddr: no user"); 7873149Seric buf[0] = '\0'; 7883149Seric while (**++tv != NULL) 7893149Seric strcat(buf, *tv); 7903149Seric a->q_user = buf; 7913149Seric 7923149Seric return (a); 7933149Seric } 794