1 /* 2 * Copyright (c) 1983 Eric P. Allman 3 * Copyright (c) 1988, 1993 4 * The Regents of the University of California. All rights reserved. 5 * 6 * %sccs.include.redist.c% 7 */ 8 9 #ifndef lint 10 static char sccsid[] = "@(#)parseaddr.c 8.3 (Berkeley) 07/11/93"; 11 #endif /* not lint */ 12 13 # include "sendmail.h" 14 15 /* 16 ** PARSEADDR -- Parse an address 17 ** 18 ** Parses an address and breaks it up into three parts: a 19 ** net to transmit the message on, the host to transmit it 20 ** to, and a user on that host. These are loaded into an 21 ** ADDRESS header with the values squirreled away if necessary. 22 ** The "user" part may not be a real user; the process may 23 ** just reoccur on that machine. For example, on a machine 24 ** with an arpanet connection, the address 25 ** csvax.bill@berkeley 26 ** will break up to a "user" of 'csvax.bill' and a host 27 ** of 'berkeley' -- to be transmitted over the arpanet. 28 ** 29 ** Parameters: 30 ** addr -- the address to parse. 31 ** a -- a pointer to the address descriptor buffer. 32 ** If NULL, a header will be created. 33 ** copyf -- determines what shall be copied: 34 ** -1 -- don't copy anything. The printname 35 ** (q_paddr) is just addr, and the 36 ** user & host are allocated internally 37 ** to parse. 38 ** 0 -- copy out the parsed user & host, but 39 ** don't copy the printname. 40 ** +1 -- copy everything. 41 ** delim -- the character to terminate the address, passed 42 ** to prescan. 43 ** delimptr -- if non-NULL, set to the location of the 44 ** delim character that was found. 45 ** e -- the envelope that will contain this address. 46 ** 47 ** Returns: 48 ** A pointer to the address descriptor header (`a' if 49 ** `a' is non-NULL). 50 ** NULL on error. 51 ** 52 ** Side Effects: 53 ** none 54 */ 55 56 /* following delimiters are inherent to the internal algorithms */ 57 # define DELIMCHARS "()<>,;\r\n" /* default word delimiters */ 58 59 ADDRESS * 60 parseaddr(addr, a, copyf, delim, delimptr, e) 61 char *addr; 62 register ADDRESS *a; 63 int copyf; 64 int delim; 65 char **delimptr; 66 register ENVELOPE *e; 67 { 68 register char **pvp; 69 auto char *delimptrbuf; 70 bool queueup; 71 char pvpbuf[PSBUFSIZE]; 72 extern ADDRESS *buildaddr(); 73 extern bool invalidaddr(); 74 75 /* 76 ** Initialize and prescan address. 77 */ 78 79 e->e_to = addr; 80 if (tTd(20, 1)) 81 printf("\n--parseaddr(%s)\n", addr); 82 83 if (invalidaddr(addr)) 84 { 85 if (tTd(20, 1)) 86 printf("parseaddr-->bad address\n"); 87 return NULL; 88 } 89 90 if (delimptr == NULL) 91 delimptr = &delimptrbuf; 92 93 pvp = prescan(addr, delim, pvpbuf, delimptr); 94 if (pvp == NULL) 95 { 96 if (tTd(20, 1)) 97 printf("parseaddr-->NULL\n"); 98 return (NULL); 99 } 100 101 /* 102 ** Apply rewriting rules. 103 ** Ruleset 0 does basic parsing. It must resolve. 104 */ 105 106 queueup = FALSE; 107 if (rewrite(pvp, 3, e) == EX_TEMPFAIL) 108 queueup = TRUE; 109 if (rewrite(pvp, 0, e) == EX_TEMPFAIL) 110 queueup = TRUE; 111 112 /* 113 ** See if we resolved to a real mailer. 114 */ 115 116 if (pvp[0] == NULL || (pvp[0][0] & 0377) != CANONNET) 117 { 118 setstat(EX_USAGE); 119 syserr("554 cannot resolve name %s", addr); 120 return (NULL); 121 } 122 123 /* 124 ** Build canonical address from pvp. 125 */ 126 127 a = buildaddr(pvp, a, e); 128 if (a == NULL) 129 return (NULL); 130 131 /* 132 ** Make local copies of the host & user and then 133 ** transport them out. 134 */ 135 136 allocaddr(a, copyf, addr, *delimptr); 137 138 /* 139 ** If there was a parsing failure, mark it for queueing. 140 */ 141 142 if (queueup) 143 { 144 char *msg = "Transient parse error -- message queued for future delivery"; 145 146 if (tTd(20, 1)) 147 printf("parseaddr: queuing message\n"); 148 message(msg); 149 if (e->e_message == NULL) 150 e->e_message = newstr(msg); 151 a->q_flags |= QQUEUEUP; 152 } 153 154 /* 155 ** Compute return value. 156 */ 157 158 if (tTd(20, 1)) 159 { 160 printf("parseaddr-->"); 161 printaddr(a, FALSE); 162 } 163 164 return (a); 165 } 166 /* 167 ** INVALIDADDR -- check for address containing meta-characters 168 ** 169 ** Parameters: 170 ** addr -- the address to check. 171 ** 172 ** Returns: 173 ** TRUE -- if the address has any "wierd" characters 174 ** FALSE -- otherwise. 175 */ 176 177 bool 178 invalidaddr(addr) 179 register char *addr; 180 { 181 for (; *addr != '\0'; addr++) 182 { 183 if ((*addr & 0340) != 0200) 184 continue; 185 setstat(EX_USAGE); 186 usrerr("553 Address contained invalid control characters"); 187 return TRUE; 188 } 189 return FALSE; 190 } 191 /* 192 ** ALLOCADDR -- do local allocations of address on demand. 193 ** 194 ** Also lowercases the host name if requested. 195 ** 196 ** Parameters: 197 ** a -- the address to reallocate. 198 ** copyf -- the copy flag (see parseaddr for description). 199 ** paddr -- the printname of the address. 200 ** delimptr -- a pointer to the address delimiter. Must be set. 201 ** 202 ** Returns: 203 ** none. 204 ** 205 ** Side Effects: 206 ** Copies portions of a into local buffers as requested. 207 */ 208 209 allocaddr(a, copyf, paddr, delimptr) 210 register ADDRESS *a; 211 int copyf; 212 char *paddr; 213 char *delimptr; 214 { 215 if (tTd(24, 4)) 216 printf("allocaddr(copyf=%d, paddr=%s)\n", copyf, paddr); 217 218 if (copyf > 0 && paddr != NULL) 219 { 220 char savec = *delimptr; 221 222 if (savec != '\0') 223 *delimptr = '\0'; 224 a->q_paddr = newstr(paddr); 225 if (savec != '\0') 226 *delimptr = savec; 227 } 228 else 229 a->q_paddr = paddr; 230 231 if (a->q_user == NULL) 232 a->q_user = ""; 233 if (a->q_host == NULL) 234 a->q_host = ""; 235 236 if (copyf >= 0) 237 { 238 a->q_host = newstr(a->q_host); 239 if (a->q_user != a->q_paddr) 240 a->q_user = newstr(a->q_user); 241 } 242 243 if (a->q_paddr == NULL) 244 a->q_paddr = a->q_user; 245 } 246 /* 247 ** PRESCAN -- Prescan name and make it canonical 248 ** 249 ** Scans a name and turns it into a set of tokens. This process 250 ** deletes blanks and comments (in parentheses). 251 ** 252 ** This routine knows about quoted strings and angle brackets. 253 ** 254 ** There are certain subtleties to this routine. The one that 255 ** comes to mind now is that backslashes on the ends of names 256 ** are silently stripped off; this is intentional. The problem 257 ** is that some versions of sndmsg (like at LBL) set the kill 258 ** character to something other than @ when reading addresses; 259 ** so people type "csvax.eric\@berkeley" -- which screws up the 260 ** berknet mailer. 261 ** 262 ** Parameters: 263 ** addr -- the name to chomp. 264 ** delim -- the delimiter for the address, normally 265 ** '\0' or ','; \0 is accepted in any case. 266 ** If '\t' then we are reading the .cf file. 267 ** pvpbuf -- place to put the saved text -- note that 268 ** the pointers are static. 269 ** delimptr -- if non-NULL, set to the location of the 270 ** terminating delimiter. 271 ** 272 ** Returns: 273 ** A pointer to a vector of tokens. 274 ** NULL on error. 275 */ 276 277 /* states and character types */ 278 # define OPR 0 /* operator */ 279 # define ATM 1 /* atom */ 280 # define QST 2 /* in quoted string */ 281 # define SPC 3 /* chewing up spaces */ 282 # define ONE 4 /* pick up one character */ 283 284 # define NSTATES 5 /* number of states */ 285 # define TYPE 017 /* mask to select state type */ 286 287 /* meta bits for table */ 288 # define M 020 /* meta character; don't pass through */ 289 # define B 040 /* cause a break */ 290 # define MB M|B /* meta-break */ 291 292 static short StateTab[NSTATES][NSTATES] = 293 { 294 /* oldst chtype> OPR ATM QST SPC ONE */ 295 /*OPR*/ OPR|B, ATM|B, QST|B, SPC|MB, ONE|B, 296 /*ATM*/ OPR|B, ATM, QST|B, SPC|MB, ONE|B, 297 /*QST*/ QST, QST, OPR, QST, QST, 298 /*SPC*/ OPR, ATM, QST, SPC|M, ONE, 299 /*ONE*/ OPR, OPR, OPR, OPR, OPR, 300 }; 301 302 # define NOCHAR -1 /* signal nothing in lookahead token */ 303 304 char ** 305 prescan(addr, delim, pvpbuf, delimptr) 306 char *addr; 307 char delim; 308 char pvpbuf[]; 309 char **delimptr; 310 { 311 register char *p; 312 register char *q; 313 register int c; 314 char **avp; 315 bool bslashmode; 316 int cmntcnt; 317 int anglecnt; 318 char *tok; 319 int state; 320 int newstate; 321 char *saveto = CurEnv->e_to; 322 static char *av[MAXATOM+1]; 323 extern int errno; 324 325 /* make sure error messages don't have garbage on them */ 326 errno = 0; 327 328 q = pvpbuf; 329 bslashmode = FALSE; 330 cmntcnt = 0; 331 anglecnt = 0; 332 avp = av; 333 state = ATM; 334 c = NOCHAR; 335 p = addr; 336 CurEnv->e_to = p; 337 if (tTd(22, 11)) 338 { 339 printf("prescan: "); 340 xputs(p); 341 (void) putchar('\n'); 342 } 343 344 do 345 { 346 /* read a token */ 347 tok = q; 348 for (;;) 349 { 350 /* store away any old lookahead character */ 351 if (c != NOCHAR && !bslashmode) 352 { 353 /* see if there is room */ 354 if (q >= &pvpbuf[PSBUFSIZE - 5]) 355 { 356 usrerr("553 Address too long"); 357 if (delimptr != NULL) 358 *delimptr = p; 359 CurEnv->e_to = saveto; 360 return (NULL); 361 } 362 363 /* squirrel it away */ 364 *q++ = c; 365 } 366 367 /* read a new input character */ 368 c = *p++; 369 if (c == '\0') 370 { 371 /* diagnose and patch up bad syntax */ 372 if (state == QST) 373 { 374 usrerr("553 Unbalanced '\"'"); 375 c = '"'; 376 } 377 else if (cmntcnt > 0) 378 { 379 usrerr("553 Unbalanced '('"); 380 c = ')'; 381 } 382 else if (anglecnt > 0) 383 { 384 c = '>'; 385 usrerr("553 Unbalanced '<'"); 386 } 387 else 388 break; 389 390 p--; 391 } 392 else if (c == delim && anglecnt <= 0 && 393 cmntcnt <= 0 && state != QST) 394 break; 395 396 if (tTd(22, 101)) 397 printf("c=%c, s=%d; ", c, state); 398 399 /* chew up special characters */ 400 *q = '\0'; 401 if (bslashmode) 402 { 403 bslashmode = FALSE; 404 405 /* kludge \! for naive users */ 406 if (cmntcnt > 0) 407 { 408 c = NOCHAR; 409 continue; 410 } 411 else if (c != '!' || state == QST) 412 { 413 *q++ = '\\'; 414 continue; 415 } 416 } 417 418 if (c == '\\') 419 { 420 bslashmode = TRUE; 421 } 422 else if (state == QST) 423 { 424 /* do nothing, just avoid next clauses */ 425 } 426 else if (c == '(') 427 { 428 cmntcnt++; 429 c = NOCHAR; 430 } 431 else if (c == ')') 432 { 433 if (cmntcnt <= 0) 434 { 435 usrerr("553 Unbalanced ')'"); 436 if (delimptr != NULL) 437 *delimptr = p; 438 CurEnv->e_to = saveto; 439 return (NULL); 440 } 441 else 442 cmntcnt--; 443 } 444 else if (cmntcnt > 0) 445 c = NOCHAR; 446 else if (c == '<') 447 anglecnt++; 448 else if (c == '>') 449 { 450 if (anglecnt <= 0) 451 { 452 usrerr("553 Unbalanced '>'"); 453 if (delimptr != NULL) 454 *delimptr = p; 455 CurEnv->e_to = saveto; 456 return (NULL); 457 } 458 anglecnt--; 459 } 460 else if (delim == ' ' && isascii(c) && isspace(c)) 461 c = ' '; 462 463 if (c == NOCHAR) 464 continue; 465 466 /* see if this is end of input */ 467 if (c == delim && anglecnt <= 0 && state != QST) 468 break; 469 470 newstate = StateTab[state][toktype(c)]; 471 if (tTd(22, 101)) 472 printf("ns=%02o\n", newstate); 473 state = newstate & TYPE; 474 if (bitset(M, newstate)) 475 c = NOCHAR; 476 if (bitset(B, newstate)) 477 break; 478 } 479 480 /* new token */ 481 if (tok != q) 482 { 483 *q++ = '\0'; 484 if (tTd(22, 36)) 485 { 486 printf("tok="); 487 xputs(tok); 488 (void) putchar('\n'); 489 } 490 if (avp >= &av[MAXATOM]) 491 { 492 syserr("553 prescan: too many tokens"); 493 if (delimptr != NULL) 494 *delimptr = p; 495 CurEnv->e_to = saveto; 496 return (NULL); 497 } 498 *avp++ = tok; 499 } 500 } while (c != '\0' && (c != delim || anglecnt > 0)); 501 *avp = NULL; 502 p--; 503 if (delimptr != NULL) 504 *delimptr = p; 505 if (tTd(22, 12)) 506 { 507 printf("prescan==>"); 508 printav(av); 509 } 510 CurEnv->e_to = saveto; 511 if (av[0] == NULL) 512 return (NULL); 513 return (av); 514 } 515 /* 516 ** TOKTYPE -- return token type 517 ** 518 ** Parameters: 519 ** c -- the character in question. 520 ** 521 ** Returns: 522 ** Its type. 523 ** 524 ** Side Effects: 525 ** none. 526 */ 527 528 toktype(c) 529 register int c; 530 { 531 static char buf[50]; 532 static bool firstime = TRUE; 533 534 if (firstime) 535 { 536 firstime = FALSE; 537 expand("\201o", buf, &buf[sizeof buf - 1], CurEnv); 538 (void) strcat(buf, DELIMCHARS); 539 } 540 c &= 0377; 541 if (c == MATCHCLASS || c == MATCHREPL || c == MATCHNCLASS) 542 return (ONE); 543 if (c == MACRODEXPAND) 544 return (ONE); 545 if (c == '"') 546 return (QST); 547 if ((c & 0340) == 0200) 548 return (OPR); 549 if (!isascii(c)) 550 return (ATM); 551 if (isspace(c) || c == ')') 552 return (SPC); 553 if (strchr(buf, c) != NULL) 554 return (OPR); 555 return (ATM); 556 } 557 /* 558 ** REWRITE -- apply rewrite rules to token vector. 559 ** 560 ** This routine is an ordered production system. Each rewrite 561 ** rule has a LHS (called the pattern) and a RHS (called the 562 ** rewrite); 'rwr' points the the current rewrite rule. 563 ** 564 ** For each rewrite rule, 'avp' points the address vector we 565 ** are trying to match against, and 'pvp' points to the pattern. 566 ** If pvp points to a special match value (MATCHZANY, MATCHANY, 567 ** MATCHONE, MATCHCLASS, MATCHNCLASS) then the address in avp 568 ** matched is saved away in the match vector (pointed to by 'mvp'). 569 ** 570 ** When a match between avp & pvp does not match, we try to 571 ** back out. If we back up over MATCHONE, MATCHCLASS, or MATCHNCLASS 572 ** we must also back out the match in mvp. If we reach a 573 ** MATCHANY or MATCHZANY we just extend the match and start 574 ** over again. 575 ** 576 ** When we finally match, we rewrite the address vector 577 ** and try over again. 578 ** 579 ** Parameters: 580 ** pvp -- pointer to token vector. 581 ** ruleset -- the ruleset to use for rewriting. 582 ** e -- the current envelope. 583 ** 584 ** Returns: 585 ** A status code. If EX_TEMPFAIL, higher level code should 586 ** attempt recovery. 587 ** 588 ** Side Effects: 589 ** pvp is modified. 590 */ 591 592 struct match 593 { 594 char **first; /* first token matched */ 595 char **last; /* last token matched */ 596 char **pattern; /* pointer to pattern */ 597 }; 598 599 # define MAXMATCH 9 /* max params per rewrite */ 600 601 602 int 603 rewrite(pvp, ruleset, e) 604 char **pvp; 605 int ruleset; 606 register ENVELOPE *e; 607 { 608 register char *ap; /* address pointer */ 609 register char *rp; /* rewrite pointer */ 610 register char **avp; /* address vector pointer */ 611 register char **rvp; /* rewrite vector pointer */ 612 register struct match *mlp; /* cur ptr into mlist */ 613 register struct rewrite *rwr; /* pointer to current rewrite rule */ 614 int ruleno; /* current rule number */ 615 int rstat = EX_OK; /* return status */ 616 struct match mlist[MAXMATCH]; /* stores match on LHS */ 617 char *npvp[MAXATOM+1]; /* temporary space for rebuild */ 618 619 if (OpMode == MD_TEST || tTd(21, 2)) 620 { 621 printf("rewrite: ruleset %2d input:", ruleset); 622 printav(pvp); 623 } 624 if (ruleset < 0 || ruleset >= MAXRWSETS) 625 { 626 syserr("554 rewrite: illegal ruleset number %d", ruleset); 627 return EX_CONFIG; 628 } 629 if (pvp == NULL) 630 return EX_USAGE; 631 632 /* 633 ** Run through the list of rewrite rules, applying 634 ** any that match. 635 */ 636 637 ruleno = 1; 638 for (rwr = RewriteRules[ruleset]; rwr != NULL; ) 639 { 640 int loopcount = 0; 641 642 if (tTd(21, 12)) 643 { 644 printf("-----trying rule:"); 645 printav(rwr->r_lhs); 646 } 647 648 /* try to match on this rule */ 649 mlp = mlist; 650 rvp = rwr->r_lhs; 651 avp = pvp; 652 if (++loopcount > 100) 653 { 654 syserr("554 Infinite loop in ruleset %d, rule %d", 655 ruleset, ruleno); 656 if (tTd(21, 1)) 657 { 658 printf("workspace: "); 659 printav(pvp); 660 } 661 break; 662 } 663 664 while ((ap = *avp) != NULL || *rvp != NULL) 665 { 666 rp = *rvp; 667 if (tTd(21, 35)) 668 { 669 printf("ADVANCE rp="); 670 xputs(rp); 671 printf(", ap="); 672 xputs(ap); 673 printf("\n"); 674 } 675 if (rp == NULL) 676 { 677 /* end-of-pattern before end-of-address */ 678 goto backup; 679 } 680 if (ap == NULL && (*rp & 0377) != MATCHZANY && 681 (*rp & 0377) != MATCHZERO) 682 { 683 /* end-of-input with patterns left */ 684 goto backup; 685 } 686 687 switch (*rp & 0377) 688 { 689 register STAB *s; 690 char buf[MAXLINE]; 691 692 case MATCHCLASS: 693 /* match any phrase in a class */ 694 mlp->pattern = rvp; 695 mlp->first = avp; 696 extendclass: 697 ap = *avp; 698 if (ap == NULL) 699 goto backup; 700 mlp->last = avp++; 701 cataddr(mlp->first, mlp->last, buf, sizeof buf, '\0'); 702 s = stab(buf, ST_CLASS, ST_FIND); 703 if (s == NULL || !bitnset(rp[1], s->s_class)) 704 { 705 if (tTd(21, 36)) 706 { 707 printf("EXTEND rp="); 708 xputs(rp); 709 printf(", ap="); 710 xputs(ap); 711 printf("\n"); 712 } 713 goto extendclass; 714 } 715 if (tTd(21, 36)) 716 printf("CLMATCH\n"); 717 mlp++; 718 break; 719 720 case MATCHNCLASS: 721 /* match any token not in a class */ 722 s = stab(ap, ST_CLASS, ST_FIND); 723 if (s != NULL && bitnset(rp[1], s->s_class)) 724 goto backup; 725 726 /* fall through */ 727 728 case MATCHONE: 729 case MATCHANY: 730 /* match exactly one token */ 731 mlp->pattern = rvp; 732 mlp->first = avp; 733 mlp->last = avp++; 734 mlp++; 735 break; 736 737 case MATCHZANY: 738 /* match zero or more tokens */ 739 mlp->pattern = rvp; 740 mlp->first = avp; 741 mlp->last = avp - 1; 742 mlp++; 743 break; 744 745 case MATCHZERO: 746 /* match zero tokens */ 747 break; 748 749 case MACRODEXPAND: 750 /* 751 ** Match against run-time macro. 752 ** This algorithm is broken for the 753 ** general case (no recursive macros, 754 ** improper tokenization) but should 755 ** work for the usual cases. 756 */ 757 758 ap = macvalue(rp[1], e); 759 mlp->first = avp; 760 if (tTd(21, 2)) 761 printf("rewrite: LHS $&%c => \"%s\"\n", 762 rp[1], 763 ap == NULL ? "(NULL)" : ap); 764 765 if (ap == NULL) 766 break; 767 while (*ap != '\0') 768 { 769 if (*avp == NULL || 770 strncasecmp(ap, *avp, strlen(*avp)) != 0) 771 { 772 /* no match */ 773 avp = mlp->first; 774 goto backup; 775 } 776 ap += strlen(*avp++); 777 } 778 779 /* match */ 780 break; 781 782 default: 783 /* must have exact match */ 784 if (strcasecmp(rp, ap)) 785 goto backup; 786 avp++; 787 break; 788 } 789 790 /* successful match on this token */ 791 rvp++; 792 continue; 793 794 backup: 795 /* match failed -- back up */ 796 while (--mlp >= mlist) 797 { 798 rvp = mlp->pattern; 799 rp = *rvp; 800 avp = mlp->last + 1; 801 ap = *avp; 802 803 if (tTd(21, 36)) 804 { 805 printf("BACKUP rp="); 806 xputs(rp); 807 printf(", ap="); 808 xputs(ap); 809 printf("\n"); 810 } 811 812 if (ap == NULL) 813 { 814 /* run off the end -- back up again */ 815 continue; 816 } 817 if ((*rp & 0377) == MATCHANY || 818 (*rp & 0377) == MATCHZANY) 819 { 820 /* extend binding and continue */ 821 mlp->last = avp++; 822 rvp++; 823 mlp++; 824 break; 825 } 826 if ((*rp & 0377) == MATCHCLASS) 827 { 828 /* extend binding and try again */ 829 mlp->last = avp; 830 goto extendclass; 831 } 832 } 833 834 if (mlp < mlist) 835 { 836 /* total failure to match */ 837 break; 838 } 839 } 840 841 /* 842 ** See if we successfully matched 843 */ 844 845 if (mlp < mlist || *rvp != NULL) 846 { 847 if (tTd(21, 10)) 848 printf("----- rule fails\n"); 849 rwr = rwr->r_next; 850 ruleno++; 851 continue; 852 } 853 854 rvp = rwr->r_rhs; 855 if (tTd(21, 12)) 856 { 857 printf("-----rule matches:"); 858 printav(rvp); 859 } 860 861 rp = *rvp; 862 if ((*rp & 0377) == CANONUSER) 863 { 864 rvp++; 865 rwr = rwr->r_next; 866 ruleno++; 867 } 868 else if ((*rp & 0377) == CANONHOST) 869 { 870 rvp++; 871 rwr = NULL; 872 } 873 else if ((*rp & 0377) == CANONNET) 874 rwr = NULL; 875 876 /* substitute */ 877 for (avp = npvp; *rvp != NULL; rvp++) 878 { 879 register struct match *m; 880 register char **pp; 881 882 rp = *rvp; 883 if ((*rp & 0377) == MATCHREPL) 884 { 885 /* substitute from LHS */ 886 m = &mlist[rp[1] - '1']; 887 if (m < mlist || m >= mlp) 888 { 889 syserr("554 rewrite: ruleset %d: replacement $%c out of bounds", 890 ruleset, rp[1]); 891 return EX_CONFIG; 892 } 893 if (tTd(21, 15)) 894 { 895 printf("$%c:", rp[1]); 896 pp = m->first; 897 while (pp <= m->last) 898 { 899 printf(" %x=\"", *pp); 900 (void) fflush(stdout); 901 printf("%s\"", *pp++); 902 } 903 printf("\n"); 904 } 905 pp = m->first; 906 while (pp <= m->last) 907 { 908 if (avp >= &npvp[MAXATOM]) 909 { 910 syserr("554 rewrite: expansion too long"); 911 return EX_DATAERR; 912 } 913 *avp++ = *pp++; 914 } 915 } 916 else 917 { 918 /* vanilla replacement */ 919 if (avp >= &npvp[MAXATOM]) 920 { 921 toolong: 922 syserr("554 rewrite: expansion too long"); 923 return EX_DATAERR; 924 } 925 if ((*rp & 0377) != MACRODEXPAND) 926 *avp++ = rp; 927 else 928 { 929 *avp = macvalue(rp[1], e); 930 if (tTd(21, 2)) 931 printf("rewrite: RHS $&%c => \"%s\"\n", 932 rp[1], 933 *avp == NULL ? "(NULL)" : *avp); 934 if (*avp != NULL) 935 avp++; 936 } 937 } 938 } 939 *avp++ = NULL; 940 941 /* 942 ** Check for any hostname/keyword lookups. 943 */ 944 945 for (rvp = npvp; *rvp != NULL; rvp++) 946 { 947 char **hbrvp; 948 char **xpvp; 949 int trsize; 950 char *replac; 951 int endtoken; 952 STAB *map; 953 char *mapname; 954 char **key_rvp; 955 char **arg_rvp; 956 char **default_rvp; 957 char buf[MAXNAME + 1]; 958 char *pvpb1[MAXATOM + 1]; 959 char *argvect[10]; 960 char pvpbuf[PSBUFSIZE]; 961 962 if ((**rvp & 0377) != HOSTBEGIN && 963 (**rvp & 0377) != LOOKUPBEGIN) 964 continue; 965 966 /* 967 ** Got a hostname/keyword lookup. 968 ** 969 ** This could be optimized fairly easily. 970 */ 971 972 hbrvp = rvp; 973 if ((**rvp & 0377) == HOSTBEGIN) 974 { 975 endtoken = HOSTEND; 976 mapname = "host"; 977 } 978 else 979 { 980 endtoken = LOOKUPEND; 981 mapname = *++rvp; 982 } 983 map = stab(mapname, ST_MAP, ST_FIND); 984 if (map == NULL) 985 syserr("554 rewrite: map %s not found", mapname); 986 987 /* extract the match part */ 988 key_rvp = ++rvp; 989 default_rvp = NULL; 990 arg_rvp = argvect; 991 xpvp = NULL; 992 replac = pvpbuf; 993 while (*rvp != NULL && (**rvp & 0377) != endtoken) 994 { 995 int nodetype = **rvp & 0377; 996 997 if (nodetype != CANONHOST && nodetype != CANONUSER) 998 { 999 rvp++; 1000 continue; 1001 } 1002 1003 *rvp++ = NULL; 1004 1005 if (xpvp != NULL) 1006 { 1007 cataddr(xpvp, NULL, replac, 1008 &pvpbuf[sizeof pvpbuf] - replac, 1009 '\0'); 1010 *++arg_rvp = replac; 1011 replac += strlen(replac) + 1; 1012 xpvp = NULL; 1013 } 1014 switch (nodetype) 1015 { 1016 case CANONHOST: 1017 xpvp = rvp; 1018 break; 1019 1020 case CANONUSER: 1021 default_rvp = rvp; 1022 break; 1023 } 1024 } 1025 if (*rvp != NULL) 1026 *rvp++ = NULL; 1027 if (xpvp != NULL) 1028 { 1029 cataddr(xpvp, NULL, replac, 1030 &pvpbuf[sizeof pvpbuf] - replac, 1031 '\0'); 1032 *++arg_rvp = replac; 1033 } 1034 *++arg_rvp = NULL; 1035 1036 /* save the remainder of the input string */ 1037 trsize = (int) (avp - rvp + 1) * sizeof *rvp; 1038 bcopy((char *) rvp, (char *) pvpb1, trsize); 1039 1040 /* look it up */ 1041 cataddr(key_rvp, NULL, buf, sizeof buf, '\0'); 1042 argvect[0] = buf; 1043 if (map != NULL && bitset(MF_OPEN, map->s_map.map_mflags)) 1044 { 1045 auto int stat = EX_OK; 1046 1047 /* XXX should try to auto-open the map here */ 1048 1049 if (tTd(60, 1)) 1050 printf("map_lookup(%s, %s) => ", 1051 mapname, buf); 1052 replac = (*map->s_map.map_class->map_lookup)(&map->s_map, 1053 buf, argvect, &stat); 1054 if (tTd(60, 1)) 1055 printf("%s (%d)\n", 1056 replac ? replac : "NOT FOUND", 1057 stat); 1058 1059 /* should recover if stat == EX_TEMPFAIL */ 1060 if (stat == EX_TEMPFAIL) 1061 rstat = stat; 1062 } 1063 else 1064 replac = NULL; 1065 1066 /* if no replacement, use default */ 1067 if (replac == NULL && default_rvp != NULL) 1068 { 1069 /* create the default */ 1070 cataddr(default_rvp, NULL, buf, sizeof buf, '\0'); 1071 replac = buf; 1072 } 1073 1074 if (replac == NULL) 1075 { 1076 xpvp = key_rvp; 1077 } 1078 else 1079 { 1080 /* scan the new replacement */ 1081 xpvp = prescan(replac, '\0', pvpbuf, NULL); 1082 if (xpvp == NULL) 1083 { 1084 /* prescan already printed error */ 1085 return EX_DATAERR; 1086 } 1087 } 1088 1089 /* append it to the token list */ 1090 for (avp = hbrvp; *xpvp != NULL; xpvp++) 1091 { 1092 *avp++ = newstr(*xpvp); 1093 if (avp >= &npvp[MAXATOM]) 1094 goto toolong; 1095 } 1096 1097 /* restore the old trailing information */ 1098 for (xpvp = pvpb1; (*avp++ = *xpvp++) != NULL; ) 1099 if (avp >= &npvp[MAXATOM]) 1100 goto toolong; 1101 1102 break; 1103 } 1104 1105 /* 1106 ** Check for subroutine calls. 1107 */ 1108 1109 if (*npvp != NULL && (**npvp & 0377) == CALLSUBR) 1110 { 1111 int stat; 1112 1113 bcopy((char *) &npvp[2], (char *) pvp, 1114 (int) (avp - npvp - 2) * sizeof *avp); 1115 if (tTd(21, 3)) 1116 printf("-----callsubr %s\n", npvp[1]); 1117 stat = rewrite(pvp, atoi(npvp[1]), e); 1118 if (rstat == EX_OK || stat == EX_TEMPFAIL) 1119 rstat = stat; 1120 if ((**pvp & 0377) == CANONNET) 1121 rwr = NULL; 1122 } 1123 else 1124 { 1125 bcopy((char *) npvp, (char *) pvp, 1126 (int) (avp - npvp) * sizeof *avp); 1127 } 1128 if (tTd(21, 4)) 1129 { 1130 printf("rewritten as:"); 1131 printav(pvp); 1132 } 1133 } 1134 1135 if (OpMode == MD_TEST || tTd(21, 2)) 1136 { 1137 printf("rewrite: ruleset %2d returns:", ruleset); 1138 printav(pvp); 1139 } 1140 1141 return rstat; 1142 } 1143 /* 1144 ** BUILDADDR -- build address from token vector. 1145 ** 1146 ** Parameters: 1147 ** tv -- token vector. 1148 ** a -- pointer to address descriptor to fill. 1149 ** If NULL, one will be allocated. 1150 ** e -- the current envelope. 1151 ** 1152 ** Returns: 1153 ** NULL if there was an error. 1154 ** 'a' otherwise. 1155 ** 1156 ** Side Effects: 1157 ** fills in 'a' 1158 */ 1159 1160 struct errcodes 1161 { 1162 char *ec_name; /* name of error code */ 1163 int ec_code; /* numeric code */ 1164 } ErrorCodes[] = 1165 { 1166 "usage", EX_USAGE, 1167 "nouser", EX_NOUSER, 1168 "nohost", EX_NOHOST, 1169 "unavailable", EX_UNAVAILABLE, 1170 "software", EX_SOFTWARE, 1171 "tempfail", EX_TEMPFAIL, 1172 "protocol", EX_PROTOCOL, 1173 #ifdef EX_CONFIG 1174 "config", EX_CONFIG, 1175 #endif 1176 NULL, EX_UNAVAILABLE, 1177 }; 1178 1179 ADDRESS * 1180 buildaddr(tv, a, e) 1181 register char **tv; 1182 register ADDRESS *a; 1183 register ENVELOPE *e; 1184 { 1185 struct mailer **mp; 1186 register struct mailer *m; 1187 char *bp; 1188 int spaceleft; 1189 static char buf[MAXNAME]; 1190 1191 if (a == NULL) 1192 a = (ADDRESS *) xalloc(sizeof *a); 1193 bzero((char *) a, sizeof *a); 1194 1195 /* figure out what net/mailer to use */ 1196 if ((**tv & 0377) != CANONNET) 1197 { 1198 syserr("554 buildaddr: no net"); 1199 return (NULL); 1200 } 1201 tv++; 1202 if (strcasecmp(*tv, "error") == 0) 1203 { 1204 if ((**++tv & 0377) == CANONHOST) 1205 { 1206 register struct errcodes *ep; 1207 1208 if (isascii(**++tv) && isdigit(**tv)) 1209 { 1210 setstat(atoi(*tv)); 1211 } 1212 else 1213 { 1214 for (ep = ErrorCodes; ep->ec_name != NULL; ep++) 1215 if (strcasecmp(ep->ec_name, *tv) == 0) 1216 break; 1217 setstat(ep->ec_code); 1218 } 1219 tv++; 1220 } 1221 if ((**tv & 0377) != CANONUSER) 1222 syserr("554 buildaddr: error: no user"); 1223 cataddr(++tv, NULL, buf, sizeof buf, ' '); 1224 stripquotes(buf); 1225 usrerr(buf); 1226 return (NULL); 1227 } 1228 1229 for (mp = Mailer; (m = *mp++) != NULL; ) 1230 { 1231 if (strcasecmp(m->m_name, *tv) == 0) 1232 break; 1233 } 1234 if (m == NULL) 1235 { 1236 syserr("554 buildaddr: unknown mailer %s", *tv); 1237 return (NULL); 1238 } 1239 a->q_mailer = m; 1240 1241 /* figure out what host (if any) */ 1242 tv++; 1243 if ((**tv & 0377) == CANONHOST) 1244 { 1245 bp = buf; 1246 spaceleft = sizeof buf - 1; 1247 while (*++tv != NULL && (**tv & 0377) != CANONUSER) 1248 { 1249 int i = strlen(*tv); 1250 1251 if (i > spaceleft) 1252 { 1253 /* out of space for this address */ 1254 if (spaceleft >= 0) 1255 syserr("554 buildaddr: host too long (%.40s...)", 1256 buf); 1257 i = spaceleft; 1258 spaceleft = 0; 1259 } 1260 if (i <= 0) 1261 continue; 1262 bcopy(*tv, bp, i); 1263 bp += i; 1264 spaceleft -= i; 1265 } 1266 *bp = '\0'; 1267 a->q_host = newstr(buf); 1268 } 1269 else 1270 { 1271 if (!bitnset(M_LOCALMAILER, m->m_flags)) 1272 { 1273 syserr("554 buildaddr: no host"); 1274 return (NULL); 1275 } 1276 a->q_host = NULL; 1277 } 1278 1279 /* figure out the user */ 1280 if (*tv == NULL || (**tv & 0377) != CANONUSER) 1281 { 1282 syserr("554 buildaddr: no user"); 1283 return (NULL); 1284 } 1285 tv++; 1286 1287 /* do special mapping for local mailer */ 1288 if (m == LocalMailer && *tv != NULL) 1289 { 1290 register char *p = *tv; 1291 1292 if (*p == '"') 1293 p++; 1294 if (*p == '|') 1295 a->q_mailer = m = ProgMailer; 1296 else if (*p == '/') 1297 a->q_mailer = m = FileMailer; 1298 else if (*p == ':') 1299 { 1300 /* may be :include: */ 1301 cataddr(tv, NULL, buf, sizeof buf, '\0'); 1302 stripquotes(buf); 1303 if (strncasecmp(buf, ":include:", 9) == 0) 1304 { 1305 /* if :include:, don't need further rewriting */ 1306 a->q_mailer = m = InclMailer; 1307 a->q_user = &buf[9]; 1308 return (a); 1309 } 1310 } 1311 } 1312 1313 if (m == LocalMailer && *tv != NULL && strcmp(*tv, "@") == 0) 1314 { 1315 tv++; 1316 a->q_flags |= QNOTREMOTE; 1317 } 1318 1319 /* do cleanup of final address */ 1320 (void) rewrite(tv, 4, e); 1321 1322 /* save the result for the command line/RCPT argument */ 1323 cataddr(tv, NULL, buf, sizeof buf, '\0'); 1324 a->q_user = buf; 1325 1326 /* 1327 ** Do mapping to lower case as requested by mailer 1328 */ 1329 1330 if (a->q_host != NULL && !bitnset(M_HST_UPPER, m->m_flags)) 1331 makelower(a->q_host); 1332 if (!bitnset(M_USR_UPPER, m->m_flags)) 1333 makelower(a->q_user); 1334 1335 return (a); 1336 } 1337 /* 1338 ** CATADDR -- concatenate pieces of addresses (putting in <LWSP> subs) 1339 ** 1340 ** Parameters: 1341 ** pvp -- parameter vector to rebuild. 1342 ** evp -- last parameter to include. Can be NULL to 1343 ** use entire pvp. 1344 ** buf -- buffer to build the string into. 1345 ** sz -- size of buf. 1346 ** spacesub -- the space separator character; if null, 1347 ** use SpaceSub. 1348 ** 1349 ** Returns: 1350 ** none. 1351 ** 1352 ** Side Effects: 1353 ** Destroys buf. 1354 */ 1355 1356 cataddr(pvp, evp, buf, sz, spacesub) 1357 char **pvp; 1358 char **evp; 1359 char *buf; 1360 register int sz; 1361 char spacesub; 1362 { 1363 bool oatomtok = FALSE; 1364 bool natomtok = FALSE; 1365 register int i; 1366 register char *p; 1367 1368 if (spacesub == '\0') 1369 spacesub = SpaceSub; 1370 1371 if (pvp == NULL) 1372 { 1373 (void) strcpy(buf, ""); 1374 return; 1375 } 1376 p = buf; 1377 sz -= 2; 1378 while (*pvp != NULL && (i = strlen(*pvp)) < sz) 1379 { 1380 natomtok = (toktype(**pvp) == ATM); 1381 if (oatomtok && natomtok) 1382 *p++ = spacesub; 1383 (void) strcpy(p, *pvp); 1384 oatomtok = natomtok; 1385 p += i; 1386 sz -= i + 1; 1387 if (pvp++ == evp) 1388 break; 1389 } 1390 *p = '\0'; 1391 } 1392 /* 1393 ** SAMEADDR -- Determine if two addresses are the same 1394 ** 1395 ** This is not just a straight comparison -- if the mailer doesn't 1396 ** care about the host we just ignore it, etc. 1397 ** 1398 ** Parameters: 1399 ** a, b -- pointers to the internal forms to compare. 1400 ** 1401 ** Returns: 1402 ** TRUE -- they represent the same mailbox. 1403 ** FALSE -- they don't. 1404 ** 1405 ** Side Effects: 1406 ** none. 1407 */ 1408 1409 bool 1410 sameaddr(a, b) 1411 register ADDRESS *a; 1412 register ADDRESS *b; 1413 { 1414 /* if they don't have the same mailer, forget it */ 1415 if (a->q_mailer != b->q_mailer) 1416 return (FALSE); 1417 1418 /* if the user isn't the same, we can drop out */ 1419 if (strcmp(a->q_user, b->q_user) != 0) 1420 return (FALSE); 1421 1422 /* if we have good uids for both but the differ, these are different */ 1423 if (bitset(QGOODUID, a->q_flags & b->q_flags) && a->q_uid != b->q_uid) 1424 return (FALSE); 1425 1426 /* otherwise compare hosts (but be careful for NULL ptrs) */ 1427 if (a->q_host == b->q_host) 1428 { 1429 /* probably both null pointers */ 1430 return (TRUE); 1431 } 1432 if (a->q_host == NULL || b->q_host == NULL) 1433 { 1434 /* only one is a null pointer */ 1435 return (FALSE); 1436 } 1437 if (strcmp(a->q_host, b->q_host) != 0) 1438 return (FALSE); 1439 1440 return (TRUE); 1441 } 1442 /* 1443 ** PRINTADDR -- print address (for debugging) 1444 ** 1445 ** Parameters: 1446 ** a -- the address to print 1447 ** follow -- follow the q_next chain. 1448 ** 1449 ** Returns: 1450 ** none. 1451 ** 1452 ** Side Effects: 1453 ** none. 1454 */ 1455 1456 printaddr(a, follow) 1457 register ADDRESS *a; 1458 bool follow; 1459 { 1460 bool first = TRUE; 1461 register MAILER *m; 1462 MAILER pseudomailer; 1463 1464 while (a != NULL) 1465 { 1466 first = FALSE; 1467 printf("%x=", a); 1468 (void) fflush(stdout); 1469 1470 /* find the mailer -- carefully */ 1471 m = a->q_mailer; 1472 if (m == NULL) 1473 { 1474 m = &pseudomailer; 1475 m->m_mno = -1; 1476 m->m_name = "NULL"; 1477 } 1478 1479 printf("%s:\n\tmailer %d (%s), host `%s', user `%s', ruser `%s'\n", 1480 a->q_paddr, m->m_mno, m->m_name, 1481 a->q_host, a->q_user, 1482 a->q_ruser ? a->q_ruser : "<null>"); 1483 printf("\tnext=%x, flags=%o, alias %x, uid %d, gid %d\n", 1484 a->q_next, a->q_flags, a->q_alias, a->q_uid, a->q_gid); 1485 printf("\towner=%s, home=\"%s\", fullname=\"%s\"\n", 1486 a->q_owner == NULL ? "(none)" : a->q_owner, 1487 a->q_home == NULL ? "(none)" : a->q_home, 1488 a->q_fullname == NULL ? "(none)" : a->q_fullname); 1489 1490 if (!follow) 1491 return; 1492 a = a->q_next; 1493 } 1494 if (first) 1495 printf("[NULL]\n"); 1496 } 1497 1498 /* 1499 ** REMOTENAME -- return the name relative to the current mailer 1500 ** 1501 ** Parameters: 1502 ** name -- the name to translate. 1503 ** m -- the mailer that we want to do rewriting relative 1504 ** to. 1505 ** flags -- fine tune operations. 1506 ** pstat -- pointer to status word. 1507 ** e -- the current envelope. 1508 ** 1509 ** Returns: 1510 ** the text string representing this address relative to 1511 ** the receiving mailer. 1512 ** 1513 ** Side Effects: 1514 ** none. 1515 ** 1516 ** Warnings: 1517 ** The text string returned is tucked away locally; 1518 ** copy it if you intend to save it. 1519 */ 1520 1521 char * 1522 remotename(name, m, flags, pstat, e) 1523 char *name; 1524 struct mailer *m; 1525 int flags; 1526 int *pstat; 1527 register ENVELOPE *e; 1528 { 1529 register char **pvp; 1530 char *fancy; 1531 char *oldg = macvalue('g', e); 1532 int rwset; 1533 static char buf[MAXNAME]; 1534 char lbuf[MAXNAME]; 1535 char pvpbuf[PSBUFSIZE]; 1536 extern char *crackaddr(); 1537 1538 if (tTd(12, 1)) 1539 printf("remotename(%s)\n", name); 1540 1541 /* don't do anything if we are tagging it as special */ 1542 if (bitset(RF_SENDERADDR, flags)) 1543 rwset = bitset(RF_HEADERADDR, flags) ? m->m_sh_rwset 1544 : m->m_se_rwset; 1545 else 1546 rwset = bitset(RF_HEADERADDR, flags) ? m->m_rh_rwset 1547 : m->m_re_rwset; 1548 if (rwset < 0) 1549 return (name); 1550 1551 /* 1552 ** Do a heuristic crack of this name to extract any comment info. 1553 ** This will leave the name as a comment and a $g macro. 1554 */ 1555 1556 if (bitset(RF_CANONICAL, flags) || bitnset(M_NOCOMMENT, m->m_flags)) 1557 fancy = "\201g"; 1558 else 1559 fancy = crackaddr(name); 1560 1561 /* 1562 ** Turn the name into canonical form. 1563 ** Normally this will be RFC 822 style, i.e., "user@domain". 1564 ** If this only resolves to "user", and the "C" flag is 1565 ** specified in the sending mailer, then the sender's 1566 ** domain will be appended. 1567 */ 1568 1569 pvp = prescan(name, '\0', pvpbuf, NULL); 1570 if (pvp == NULL) 1571 return (name); 1572 if (rewrite(pvp, 3, e) == EX_TEMPFAIL) 1573 *pstat = EX_TEMPFAIL; 1574 if (bitset(RF_ADDDOMAIN, flags) && e->e_fromdomain != NULL) 1575 { 1576 /* append from domain to this address */ 1577 register char **pxp = pvp; 1578 1579 /* see if there is an "@domain" in the current name */ 1580 while (*pxp != NULL && strcmp(*pxp, "@") != 0) 1581 pxp++; 1582 if (*pxp == NULL) 1583 { 1584 /* no.... append the "@domain" from the sender */ 1585 register char **qxq = e->e_fromdomain; 1586 1587 while ((*pxp++ = *qxq++) != NULL) 1588 continue; 1589 if (rewrite(pvp, 3, e) == EX_TEMPFAIL) 1590 *pstat = EX_TEMPFAIL; 1591 } 1592 } 1593 1594 /* 1595 ** Do more specific rewriting. 1596 ** Rewrite using ruleset 1 or 2 depending on whether this is 1597 ** a sender address or not. 1598 ** Then run it through any receiving-mailer-specific rulesets. 1599 */ 1600 1601 if (bitset(RF_SENDERADDR, flags)) 1602 { 1603 if (rewrite(pvp, 1, e) == EX_TEMPFAIL) 1604 *pstat = EX_TEMPFAIL; 1605 } 1606 else 1607 { 1608 if (rewrite(pvp, 2, e) == EX_TEMPFAIL) 1609 *pstat = EX_TEMPFAIL; 1610 } 1611 if (rwset > 0) 1612 { 1613 if (rewrite(pvp, rwset, e) == EX_TEMPFAIL) 1614 *pstat = EX_TEMPFAIL; 1615 } 1616 1617 /* 1618 ** Do any final sanitation the address may require. 1619 ** This will normally be used to turn internal forms 1620 ** (e.g., user@host.LOCAL) into external form. This 1621 ** may be used as a default to the above rules. 1622 */ 1623 1624 if (rewrite(pvp, 4, e) == EX_TEMPFAIL) 1625 *pstat = EX_TEMPFAIL; 1626 1627 /* 1628 ** Now restore the comment information we had at the beginning. 1629 */ 1630 1631 cataddr(pvp, NULL, lbuf, sizeof lbuf, '\0'); 1632 define('g', lbuf, e); 1633 expand(fancy, buf, &buf[sizeof buf - 1], e); 1634 define('g', oldg, e); 1635 1636 if (tTd(12, 1)) 1637 printf("remotename => `%s'\n", buf); 1638 return (buf); 1639 } 1640 /* 1641 ** MAPLOCALUSER -- run local username through ruleset 5 for final redirection 1642 ** 1643 ** Parameters: 1644 ** a -- the address to map (but just the user name part). 1645 ** sendq -- the sendq in which to install any replacement 1646 ** addresses. 1647 ** 1648 ** Returns: 1649 ** none. 1650 */ 1651 1652 maplocaluser(a, sendq, e) 1653 register ADDRESS *a; 1654 ADDRESS **sendq; 1655 ENVELOPE *e; 1656 { 1657 register char **pvp; 1658 register ADDRESS *a1 = NULL; 1659 auto char *delimptr; 1660 char pvpbuf[PSBUFSIZE]; 1661 1662 if (tTd(29, 1)) 1663 { 1664 printf("maplocaluser: "); 1665 printaddr(a, FALSE); 1666 } 1667 pvp = prescan(a->q_user, '\0', pvpbuf, &delimptr); 1668 if (pvp == NULL) 1669 return; 1670 1671 (void) rewrite(pvp, 5, e); 1672 if (pvp[0] == NULL || (pvp[0][0] & 0377) != CANONNET) 1673 return; 1674 1675 /* if non-null, mailer destination specified -- has it changed? */ 1676 a1 = buildaddr(pvp, NULL, e); 1677 if (a1 == NULL || sameaddr(a, a1)) 1678 return; 1679 1680 /* mark old address as dead; insert new address */ 1681 a->q_flags |= QDONTSEND; 1682 if (tTd(29, 5)) 1683 { 1684 printf("maplocaluser: QDONTSEND "); 1685 printaddr(a, FALSE); 1686 } 1687 a1->q_alias = a; 1688 allocaddr(a1, 1, NULL, delimptr); 1689 (void) recipient(a1, sendq, e); 1690 } 1691 /* 1692 ** DEQUOTE_INIT -- initialize dequote map 1693 ** 1694 ** This is a no-op. 1695 ** 1696 ** Parameters: 1697 ** map -- the internal map structure. 1698 ** args -- arguments. 1699 ** 1700 ** Returns: 1701 ** TRUE. 1702 */ 1703 1704 bool 1705 dequote_init(map, args) 1706 MAP *map; 1707 char *args; 1708 { 1709 register char *p = args; 1710 1711 for (;;) 1712 { 1713 while (isascii(*p) && isspace(*p)) 1714 p++; 1715 if (*p != '-') 1716 break; 1717 switch (*++p) 1718 { 1719 case 'a': 1720 map->map_app = ++p; 1721 break; 1722 } 1723 while (*p != '\0' && !(isascii(*p) && isspace(*p))) 1724 p++; 1725 if (*p != '\0') 1726 *p = '\0'; 1727 } 1728 if (map->map_app != NULL) 1729 map->map_app = newstr(map->map_app); 1730 1731 return TRUE; 1732 } 1733 /* 1734 ** DEQUOTE_MAP -- unquote an address 1735 ** 1736 ** Parameters: 1737 ** map -- the internal map structure (ignored). 1738 ** name -- the name to dequote. 1739 ** av -- arguments (ignored). 1740 ** statp -- pointer to status out-parameter. 1741 ** 1742 ** Returns: 1743 ** NULL -- if there were no quotes, or if the resulting 1744 ** unquoted buffer would not be acceptable to prescan. 1745 ** else -- The dequoted buffer. 1746 */ 1747 1748 char * 1749 dequote_map(map, name, av, statp) 1750 MAP *map; 1751 char *name; 1752 char **av; 1753 int *statp; 1754 { 1755 register char *p; 1756 register char *q; 1757 register char c; 1758 int anglecnt; 1759 int cmntcnt; 1760 int quotecnt; 1761 int spacecnt; 1762 bool quotemode; 1763 bool bslashmode; 1764 1765 anglecnt = 0; 1766 cmntcnt = 0; 1767 quotecnt = 0; 1768 spacecnt = 0; 1769 quotemode = FALSE; 1770 bslashmode = FALSE; 1771 1772 for (p = q = name; (c = *p++) != '\0'; ) 1773 { 1774 if (bslashmode) 1775 { 1776 bslashmode = FALSE; 1777 *q++ = c; 1778 continue; 1779 } 1780 1781 switch (c) 1782 { 1783 case '\\': 1784 bslashmode = TRUE; 1785 break; 1786 1787 case '(': 1788 cmntcnt++; 1789 break; 1790 1791 case ')': 1792 if (cmntcnt-- <= 0) 1793 return NULL; 1794 break; 1795 1796 case ' ': 1797 spacecnt++; 1798 break; 1799 } 1800 1801 if (cmntcnt > 0) 1802 { 1803 *q++ = c; 1804 continue; 1805 } 1806 1807 switch (c) 1808 { 1809 case '"': 1810 quotemode = !quotemode; 1811 quotecnt++; 1812 continue; 1813 1814 case '<': 1815 anglecnt++; 1816 break; 1817 1818 case '>': 1819 if (anglecnt-- <= 0) 1820 return NULL; 1821 break; 1822 } 1823 *q++ = c; 1824 } 1825 1826 if (anglecnt != 0 || cmntcnt != 0 || bslashmode || 1827 quotemode || quotecnt <= 0 || spacecnt != 0) 1828 return NULL; 1829 *q++ = '\0'; 1830 return name; 1831 } 1832