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