1297Seric # include <stdio.h> 2297Seric # include <ctype.h> 32973Seric # include "postbox.h" 4297Seric 5*3149Seric static char SccsId[] = "@(#)parseaddr.c 3.6 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 49*3149Seric # 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 { 58*3149Seric register char **pvp; 59*3149Seric register struct mailer *m; 60*3149Seric extern char **prescan(); 61297Seric extern char *xalloc(); 622973Seric extern char *newstr(); 632990Seric extern char *strcpy(); 64*3149Seric extern ADDRESS *buildaddr(); 65297Seric 66297Seric /* 67297Seric ** Initialize and prescan address. 68297Seric */ 69297Seric 70297Seric To = addr; 71*3149Seric pvp = prescan(addr, '\0'); 72*3149Seric if (pvp == NULL) 73297Seric return (NULL); 74297Seric 75297Seric /* 76*3149Seric ** Apply rewriting rules. 77297Seric */ 78297Seric 79*3149Seric rewrite(pvp); 80297Seric 81*3149Seric /* 82*3149Seric ** See if we resolved to a real mailer. 83*3149Seric */ 84297Seric 85*3149Seric if (pvp[0][0] != CANONNET) 86*3149Seric { 87*3149Seric setstat(EX_USAGE); 88*3149Seric usrerr("cannot resolve name"); 89*3149Seric return (NULL); 90297Seric } 91297Seric 92297Seric /* 93*3149Seric ** Build canonical address from pvp. 94297Seric */ 95297Seric 96*3149Seric a = buildaddr(pvp, a); 97*3149Seric m = Mailer[a->q_mailer]; 98297Seric 99297Seric /* 100*3149Seric ** Make local copies of the host & user and then 101*3149Seric ** transport them out. 102297Seric */ 103297Seric 104297Seric if (copyf > 0) 1052973Seric a->q_paddr = newstr(addr); 106297Seric else 107297Seric a->q_paddr = addr; 108297Seric 109*3149Seric if (copyf >= 0) 110297Seric { 111*3149Seric if (a->q_host != NULL) 112*3149Seric a->q_host = newstr(a->q_host); 113297Seric else 114*3149Seric a->q_host = ""; 115*3149Seric if (a->q_user != a->q_paddr) 116*3149Seric a->q_user = newstr(a->q_user); 117297Seric } 118297Seric 119297Seric /* 120297Seric ** Do UPPER->lower case mapping unless inhibited. 121297Seric */ 122297Seric 123*3149Seric if (!bitset(M_HST_UPPER, m->m_flags)) 124297Seric makelower(a->q_host); 125*3149Seric 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", 135*3149Seric 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: 166*3149Seric ** A pointer to a vector of tokens. 167297Seric ** NULL on error. 168297Seric ** 169297Seric ** Side Effects: 170*3149Seric ** none. 171297Seric */ 172297Seric 173*3149Seric # define OPER 1 174*3149Seric # define ATOM 2 175*3149Seric # define EOTOK 3 176*3149Seric # define QSTRING 4 177*3149Seric # define SPACE 5 178*3149Seric # define DOLLAR 6 179*3149Seric # define GETONE 7 180*3149Seric 181*3149Seric char ** 182*3149Seric prescan(addr, delim) 183297Seric char *addr; 184297Seric char delim; 185297Seric { 186297Seric register char *p; 187*3149Seric static char buf[MAXNAME+MAXATOM]; 188*3149Seric static char *av[MAXATOM+1]; 189*3149Seric char **avp; 190297Seric bool space; 191297Seric bool bslashmode; 192297Seric int cmntcnt; 193297Seric int brccnt; 194297Seric register char c; 195*3149Seric char *tok; 196297Seric register char *q; 1972973Seric extern char *index(); 198*3149Seric register int state; 199*3149Seric int nstate; 200297Seric 2012091Seric space = FALSE; 202297Seric q = buf; 203*3149Seric bslashmode = FALSE; 204297Seric cmntcnt = brccnt = 0; 205*3149Seric avp = av; 206*3149Seric state = OPER; 207*3149Seric for (p = addr; *p != '\0' && *p != delim; ) 208297Seric { 209*3149Seric /* read a token */ 210*3149Seric tok = q; 211*3149Seric while ((c = *p++) != '\0' && c != delim) 212297Seric { 213*3149Seric /* chew up special characters */ 214*3149Seric *q = '\0'; 215*3149Seric if (bslashmode) 216*3149Seric { 217*3149Seric c |= 0200; 218*3149Seric bslashmode = FALSE; 219*3149Seric } 220*3149Seric else if (c == '\\') 221*3149Seric { 222*3149Seric bslashmode = TRUE; 223*3149Seric continue; 224*3149Seric } 225*3149Seric 226*3149Seric nstate = toktype(c); 227*3149Seric switch (state) 228*3149Seric { 229*3149Seric case QSTRING: /* in quoted string */ 230*3149Seric if (c == '"') 231*3149Seric state = OPER; 232*3149Seric break; 233*3149Seric 234*3149Seric case ATOM: /* regular atom */ 235*3149Seric state = nstate; 236*3149Seric if (state != ATOM) 237*3149Seric { 238*3149Seric state = EOTOK; 239*3149Seric p--; 240*3149Seric } 241*3149Seric break; 242*3149Seric 243*3149Seric case GETONE: /* grab one character */ 244*3149Seric state = OPER; 245*3149Seric break; 246*3149Seric 247*3149Seric case EOTOK: /* after atom or q-string */ 248*3149Seric state = nstate; 249*3149Seric if (state == SPACE) 250*3149Seric continue; 251*3149Seric break; 252*3149Seric 253*3149Seric case SPACE: /* linear white space */ 254*3149Seric state = nstate; 255*3149Seric space = TRUE; 256*3149Seric continue; 257*3149Seric 258*3149Seric case OPER: /* operator */ 259*3149Seric if (nstate == SPACE) 260*3149Seric continue; 261*3149Seric state = nstate; 262*3149Seric break; 263*3149Seric 264*3149Seric case DOLLAR: /* $- etc. */ 265*3149Seric state = OPER; 266*3149Seric switch (c) 267*3149Seric { 268*3149Seric case '$': /* literal $ */ 269*3149Seric break; 270*3149Seric 271*3149Seric case '+': /* match anything */ 272*3149Seric c = MATCHANY; 273*3149Seric state = GETONE; 274*3149Seric break; 275*3149Seric 276*3149Seric case '-': /* match one token */ 277*3149Seric c = MATCHONE; 278*3149Seric state = GETONE; 279*3149Seric break; 280*3149Seric 281*3149Seric case '#': /* canonical net name */ 282*3149Seric c = CANONNET; 283*3149Seric break; 284*3149Seric 285*3149Seric case '@': /* canonical host name */ 286*3149Seric c = CANONHOST; 287*3149Seric break; 288*3149Seric 289*3149Seric case ':': /* canonical user name */ 290*3149Seric c = CANONUSER; 291*3149Seric break; 292*3149Seric 293*3149Seric default: 294*3149Seric c = '$'; 295*3149Seric state = OPER; 296*3149Seric p--; 297*3149Seric break; 298*3149Seric } 299*3149Seric break; 300*3149Seric 301*3149Seric default: 302*3149Seric syserr("prescan: unknown state %d", state); 303*3149Seric } 304*3149Seric 305*3149Seric if (state == OPER) 306*3149Seric space = FALSE; 307*3149Seric else if (state == EOTOK) 308*3149Seric break; 309*3149Seric if (c == '$' && delim == '\t') 310*3149Seric { 311*3149Seric state = DOLLAR; 312*3149Seric continue; 313*3149Seric } 314*3149Seric 315*3149Seric /* squirrel it away */ 316*3149Seric if (q >= &buf[sizeof buf - 5]) 317*3149Seric { 318*3149Seric usrerr("Address too long"); 319*3149Seric return (NULL); 320*3149Seric } 321*3149Seric if (space) 322*3149Seric *q++ = SPACESUB; 323*3149Seric *q++ = c; 324*3149Seric 325*3149Seric /* decide whether this represents end of token */ 326*3149Seric if (state == OPER) 327*3149Seric break; 328297Seric } 329*3149Seric if (c == '\0' || c == delim) 330*3149Seric p--; 331*3149Seric 332*3149Seric /* new token */ 333*3149Seric if (tok == q) 334297Seric continue; 335*3149Seric *q++ = '\0'; 336*3149Seric 337*3149Seric c = tok[0]; 338*3149Seric 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 } 356*3149Seric else if (cmntcnt > 0) 3572091Seric continue; 358*3149Seric 359*3149Seric *avp++ = tok; 360*3149Seric 361*3149Seric /* we prefer <> specs */ 362*3149Seric 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'; 376*3149Seric 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 401*3149Seric if (lower(tok[0]) == 'a' && lower(tok[1]) == 't' && tok[2] == '\0') 402297Seric { 403*3149Seric tok[0] = '@'; 404*3149Seric tok[1] = '\0'; 405297Seric } 406*3149Seric } 407*3149Seric *avp = NULL; 408*3149Seric if (cmntcnt > 0) 409*3149Seric usrerr("Unbalanced '('"); 410*3149Seric else if (brccnt > 0) 411*3149Seric usrerr("Unbalanced '<'"); 412*3149Seric else if (state == QSTRING) 413*3149Seric usrerr("Unbalanced '\"'"); 414*3149Seric else if (av[0] != NULL) 415*3149Seric return (av); 416*3149Seric return (NULL); 417*3149Seric } 418*3149Seric /* 419*3149Seric ** TOKTYPE -- return token type 420*3149Seric ** 421*3149Seric ** Parameters: 422*3149Seric ** c -- the character in question. 423*3149Seric ** 424*3149Seric ** Returns: 425*3149Seric ** Its type. 426*3149Seric ** 427*3149Seric ** Side Effects: 428*3149Seric ** none. 429*3149Seric */ 430297Seric 431*3149Seric toktype(c) 432*3149Seric register char c; 433*3149Seric { 434*3149Seric if (isspace(c)) 435*3149Seric return (SPACE); 436*3149Seric if (index(DELIMCHARS, c) != NULL || iscntrl(c)) 437*3149Seric return (OPER); 438*3149Seric return (ATOM); 439*3149Seric } 440*3149Seric /* 441*3149Seric ** REWRITE -- apply rewrite rules to token vector. 442*3149Seric ** 443*3149Seric ** Parameters: 444*3149Seric ** pvp -- pointer to token vector. 445*3149Seric ** 446*3149Seric ** Returns: 447*3149Seric ** none. 448*3149Seric ** 449*3149Seric ** Side Effects: 450*3149Seric ** pvp is modified. 451*3149Seric */ 4522091Seric 453*3149Seric struct match 454*3149Seric { 455*3149Seric char **firsttok; /* first token matched */ 456*3149Seric char **lasttok; /* last token matched */ 457*3149Seric char name; /* name of parameter */ 458*3149Seric }; 459*3149Seric 460*3149Seric # define MAXMATCH 8 /* max params per rewrite */ 461*3149Seric 462*3149Seric 463*3149Seric rewrite(pvp) 464*3149Seric char **pvp; 465*3149Seric { 466*3149Seric register char *ap; /* address pointer */ 467*3149Seric register char *rp; /* rewrite pointer */ 468*3149Seric register char **avp; /* address vector pointer */ 469*3149Seric register char **rvp; /* rewrite vector pointer */ 470*3149Seric struct rewrite *rwr; 471*3149Seric struct match mlist[MAXMATCH]; 472*3149Seric char *npvp[MAXATOM+1]; /* temporary space for rebuild */ 473*3149Seric 474*3149Seric # ifdef DEBUG 475*3149Seric if (Debug) 476*3149Seric { 477*3149Seric printf("rewrite: original pvp:\n"); 478*3149Seric printav(pvp); 479*3149Seric } 480*3149Seric # endif DEBUG 481*3149Seric 482*3149Seric /* 483*3149Seric ** Run through the list of rewrite rules, applying 484*3149Seric ** any that match. 485*3149Seric */ 486*3149Seric 487*3149Seric for (rwr = RewriteRules; rwr != NULL; ) 488*3149Seric { 489*3149Seric # ifdef DEBUG 490*3149Seric if (Debug) 491297Seric { 492*3149Seric printf("-----trying rule:\n"); 493*3149Seric printav(rwr->r_lhs); 494*3149Seric } 495*3149Seric # endif DEBUG 496*3149Seric 497*3149Seric /* try to match on this rule */ 498*3149Seric clrmatch(mlist); 499*3149Seric for (rvp = rwr->r_lhs, avp = pvp; *avp != NULL; ) 500*3149Seric { 501*3149Seric ap = *avp; 502*3149Seric rp = *rvp; 503*3149Seric 504*3149Seric if (rp == NULL) 505297Seric { 506*3149Seric /* end-of-pattern before end-of-address */ 507*3149Seric goto fail; 508297Seric } 509*3149Seric 510*3149Seric switch (*rp) 511*3149Seric { 512*3149Seric case MATCHONE: 513*3149Seric /* match exactly one token */ 514*3149Seric setmatch(mlist, rp[1], avp, avp); 515*3149Seric break; 516*3149Seric 517*3149Seric case MATCHANY: 518*3149Seric /* match any number of tokens */ 519*3149Seric setmatch(mlist, rp[1], NULL, avp); 520*3149Seric break; 521*3149Seric 522*3149Seric default: 523*3149Seric /* must have exact match */ 524*3149Seric /* can scribble rp & ap here safely */ 525*3149Seric while (*rp != '\0' && *ap != '\0') 526*3149Seric { 527*3149Seric if (*rp++ != lower(*ap++)) 528*3149Seric goto fail; 529*3149Seric } 530*3149Seric break; 531*3149Seric } 532*3149Seric 533*3149Seric /* successful match on this token */ 534*3149Seric avp++; 535*3149Seric rvp++; 536*3149Seric continue; 537*3149Seric 538*3149Seric fail: 539*3149Seric /* match failed -- back up */ 540*3149Seric while (--rvp >= rwr->r_lhs) 541*3149Seric { 542*3149Seric rp = *rvp; 543*3149Seric if (*rp == MATCHANY) 544*3149Seric break; 545*3149Seric 546*3149Seric /* can't extend match: back up everything */ 547*3149Seric avp--; 548*3149Seric 549*3149Seric if (*rp == MATCHONE) 550*3149Seric { 551*3149Seric /* undo binding */ 552*3149Seric setmatch(mlist, rp[1], NULL, NULL); 553*3149Seric } 554*3149Seric } 555*3149Seric 556*3149Seric if (rvp < rwr->r_lhs) 557*3149Seric { 558*3149Seric /* total failure to match */ 559*3149Seric break; 560*3149Seric } 561297Seric } 562*3149Seric 563*3149Seric /* 564*3149Seric ** See if we successfully matched 565*3149Seric */ 566*3149Seric 567*3149Seric if (rvp >= rwr->r_lhs && *rvp == NULL) 568*3149Seric { 569*3149Seric # ifdef DEBUG 570*3149Seric if (Debug) 571*3149Seric { 572*3149Seric printf("-----rule matches:\n"); 573*3149Seric printav(rwr->r_rhs); 574*3149Seric } 575*3149Seric # endif DEBUG 576*3149Seric 577*3149Seric /* substitute */ 578*3149Seric for (rvp = rwr->r_rhs, avp = npvp; *rvp != NULL; rvp++) 579*3149Seric { 580*3149Seric rp = *rvp; 581*3149Seric if (*rp == MATCHANY) 582*3149Seric { 583*3149Seric register struct match *m; 584*3149Seric register char **pp; 585*3149Seric extern struct match *findmatch(); 586*3149Seric 587*3149Seric m = findmatch(mlist, rp[1]); 588*3149Seric if (m != NULL) 589*3149Seric { 590*3149Seric pp = m->firsttok; 591*3149Seric do 592*3149Seric { 593*3149Seric *avp++ = *pp; 594*3149Seric } while (pp++ != m->lasttok); 595*3149Seric } 596*3149Seric } 597*3149Seric else 598*3149Seric *avp++ = rp; 599*3149Seric } 600*3149Seric *avp++ = NULL; 601*3149Seric bmove(npvp, pvp, (avp - npvp) * sizeof *avp); 602*3149Seric # ifdef DEBUG 603*3149Seric if (Debug) 604*3149Seric { 605*3149Seric printf("rewritten as:\n"); 606*3149Seric printav(pvp); 607*3149Seric } 608*3149Seric # endif DEBUG 609*3149Seric if (pvp[0][0] == CANONNET) 610*3149Seric break; 611*3149Seric } 612*3149Seric else 613*3149Seric { 614*3149Seric # ifdef DEBUG 615*3149Seric if (Debug) 616*3149Seric printf("----- rule fails\n"); 617*3149Seric # endif DEBUG 618*3149Seric rwr = rwr->r_next; 619*3149Seric } 620297Seric } 621*3149Seric } 622*3149Seric /* 623*3149Seric ** SETMATCH -- set parameter value in match vector 624*3149Seric ** 625*3149Seric ** Parameters: 626*3149Seric ** mlist -- list of match values. 627*3149Seric ** name -- the character name of this parameter. 628*3149Seric ** first -- the first location of the replacement. 629*3149Seric ** last -- the last location of the replacement. 630*3149Seric ** 631*3149Seric ** If last == NULL, delete this entry. 632*3149Seric ** If first == NULL, extend this entry (or add it if 633*3149Seric ** it does not exist). 634*3149Seric ** 635*3149Seric ** Returns: 636*3149Seric ** nothing. 637*3149Seric ** 638*3149Seric ** Side Effects: 639*3149Seric ** munges with mlist. 640*3149Seric */ 641*3149Seric 642*3149Seric setmatch(mlist, name, first, last) 643*3149Seric struct match *mlist; 644*3149Seric char name; 645*3149Seric char **first; 646*3149Seric char **last; 647*3149Seric { 648*3149Seric register struct match *m; 649*3149Seric struct match *nullm = NULL; 650*3149Seric 651*3149Seric for (m = mlist; m < &mlist[MAXMATCH]; m++) 652*3149Seric { 653*3149Seric if (m->name == name) 654*3149Seric break; 655*3149Seric if (m->name == '\0') 656*3149Seric nullm = m; 657*3149Seric } 658*3149Seric 659*3149Seric if (m >= &mlist[MAXMATCH]) 660*3149Seric m = nullm; 661*3149Seric 662*3149Seric if (last == NULL) 663*3149Seric { 664*3149Seric m->name = '\0'; 665*3149Seric return; 666*3149Seric } 667*3149Seric 668*3149Seric if (m->name == '\0') 669*3149Seric { 670*3149Seric if (first == NULL) 671*3149Seric m->firsttok = last; 672*3149Seric else 673*3149Seric m->firsttok = first; 674*3149Seric } 675*3149Seric m->name = name; 676*3149Seric m->lasttok = last; 677*3149Seric } 678*3149Seric /* 679*3149Seric ** FINDMATCH -- find match in mlist 680*3149Seric ** 681*3149Seric ** Parameters: 682*3149Seric ** mlist -- list to search. 683*3149Seric ** name -- name to find. 684*3149Seric ** 685*3149Seric ** Returns: 686*3149Seric ** pointer to match structure. 687*3149Seric ** NULL if no match. 688*3149Seric ** 689*3149Seric ** Side Effects: 690*3149Seric ** none. 691*3149Seric */ 692*3149Seric 693*3149Seric struct match * 694*3149Seric findmatch(mlist, name) 695*3149Seric struct match *mlist; 696*3149Seric char name; 697*3149Seric { 698*3149Seric register struct match *m; 699*3149Seric 700*3149Seric for (m = mlist; m < &mlist[MAXMATCH]; m++) 701*3149Seric { 702*3149Seric if (m->name == name) 703*3149Seric return (m); 704*3149Seric } 705*3149Seric 706297Seric return (NULL); 707297Seric } 708*3149Seric /* 709*3149Seric ** CLRMATCH -- clear match list 710*3149Seric ** 711*3149Seric ** Parameters: 712*3149Seric ** mlist -- list to clear. 713*3149Seric ** 714*3149Seric ** Returns: 715*3149Seric ** none. 716*3149Seric ** 717*3149Seric ** Side Effects: 718*3149Seric ** mlist is cleared. 719*3149Seric */ 720*3149Seric 721*3149Seric clrmatch(mlist) 722*3149Seric struct match *mlist; 723*3149Seric { 724*3149Seric register struct match *m; 725*3149Seric 726*3149Seric for (m = mlist; m < &mlist[MAXMATCH]; m++) 727*3149Seric m->name = '\0'; 728*3149Seric } 729*3149Seric /* 730*3149Seric ** BUILDADDR -- build address from token vector. 731*3149Seric ** 732*3149Seric ** Parameters: 733*3149Seric ** tv -- token vector. 734*3149Seric ** a -- pointer to address descriptor to fill. 735*3149Seric ** If NULL, one will be allocated. 736*3149Seric ** 737*3149Seric ** Returns: 738*3149Seric ** 'a' 739*3149Seric ** 740*3149Seric ** Side Effects: 741*3149Seric ** fills in 'a' 742*3149Seric */ 743*3149Seric 744*3149Seric ADDRESS * 745*3149Seric buildaddr(tv, a) 746*3149Seric register char **tv; 747*3149Seric register ADDRESS *a; 748*3149Seric { 749*3149Seric register int i; 750*3149Seric static char buf[MAXNAME]; 751*3149Seric struct mailer **mp; 752*3149Seric register struct mailer *m; 753*3149Seric extern char *xalloc(); 754*3149Seric 755*3149Seric if (a == NULL) 756*3149Seric a = (ADDRESS *) xalloc(sizeof *a); 757*3149Seric 758*3149Seric /* figure out what net/mailer to use */ 759*3149Seric if (**tv != CANONNET) 760*3149Seric syserr("buildaddr: no net"); 761*3149Seric tv++; 762*3149Seric for (mp = Mailer, i = 0; (m = *mp) != NULL; m++, i++) 763*3149Seric { 764*3149Seric if (strcmp(m->m_name, *tv) == 0) 765*3149Seric break; 766*3149Seric } 767*3149Seric if (m == NULL) 768*3149Seric syserr("buildaddr: unknown net %s", *tv); 769*3149Seric a->q_mailer = i; 770*3149Seric 771*3149Seric /* figure out what host (if any) */ 772*3149Seric tv++; 773*3149Seric if (!bitset(M_NOHOST, m->m_flags)) 774*3149Seric { 775*3149Seric if (**tv != CANONHOST) 776*3149Seric syserr("buildaddr: no host"); 777*3149Seric tv++; 778*3149Seric a->q_host = *tv; 779*3149Seric tv++; 780*3149Seric } 781*3149Seric else 782*3149Seric a->q_host = NULL; 783*3149Seric 784*3149Seric /* figure out the user */ 785*3149Seric if (**tv != CANONUSER) 786*3149Seric syserr("buildaddr: no user"); 787*3149Seric buf[0] = '\0'; 788*3149Seric while (**++tv != NULL) 789*3149Seric strcat(buf, *tv); 790*3149Seric a->q_user = buf; 791*3149Seric 792*3149Seric return (a); 793*3149Seric } 794