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.53 (Berkeley) 05/17/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_flags)) 1049 { 1050 auto int stat = EX_OK; 1051 1052 if (tTd(60, 1)) 1053 printf("map_lookup(%s, %s) => ", 1054 mapname, buf); 1055 replac = (*map->s_map.map_class->map_lookup)(&map->s_map, 1056 buf, argvect, &stat); 1057 if (tTd(60, 1)) 1058 printf("%s (%d)\n", 1059 replac ? replac : "NOT FOUND", 1060 stat); 1061 1062 /* should recover if stat == EX_TEMPFAIL */ 1063 if (stat == EX_TEMPFAIL) 1064 rstat = stat; 1065 } 1066 else 1067 replac = NULL; 1068 1069 /* if no replacement, use default */ 1070 if (replac == NULL && default_rvp != NULL) 1071 { 1072 /* create the default */ 1073 cataddr(default_rvp, NULL, buf, sizeof buf, '\0'); 1074 replac = buf; 1075 } 1076 1077 if (replac == NULL) 1078 { 1079 xpvp = key_rvp; 1080 } 1081 else 1082 { 1083 /* scan the new replacement */ 1084 xpvp = prescan(replac, '\0', pvpbuf, NULL); 1085 if (xpvp == NULL) 1086 { 1087 /* prescan already printed error */ 1088 return EX_DATAERR; 1089 } 1090 } 1091 1092 /* append it to the token list */ 1093 for (avp = hbrvp; *xpvp != NULL; xpvp++) 1094 { 1095 *avp++ = newstr(*xpvp); 1096 if (avp >= &npvp[MAXATOM]) 1097 goto toolong; 1098 } 1099 1100 /* restore the old trailing information */ 1101 for (xpvp = pvpb1; (*avp++ = *xpvp++) != NULL; ) 1102 if (avp >= &npvp[MAXATOM]) 1103 goto toolong; 1104 1105 break; 1106 } 1107 1108 /* 1109 ** Check for subroutine calls. 1110 */ 1111 1112 if (*npvp != NULL && (**npvp & 0377) == CALLSUBR) 1113 { 1114 int stat; 1115 1116 bcopy((char *) &npvp[2], (char *) pvp, 1117 (int) (avp - npvp - 2) * sizeof *avp); 1118 if (tTd(21, 3)) 1119 printf("-----callsubr %s\n", npvp[1]); 1120 stat = rewrite(pvp, atoi(npvp[1]), e); 1121 if (rstat == EX_OK || stat == EX_TEMPFAIL) 1122 rstat = stat; 1123 } 1124 else 1125 { 1126 bcopy((char *) npvp, (char *) pvp, 1127 (int) (avp - npvp) * sizeof *avp); 1128 } 1129 if (tTd(21, 4)) 1130 { 1131 printf("rewritten as:"); 1132 printav(pvp); 1133 } 1134 } 1135 1136 if (OpMode == MD_TEST || tTd(21, 2)) 1137 { 1138 printf("rewrite: ruleset %2d returns:", ruleset); 1139 printav(pvp); 1140 } 1141 1142 return rstat; 1143 } 1144 /* 1145 ** BUILDADDR -- build address from token vector. 1146 ** 1147 ** Parameters: 1148 ** tv -- token vector. 1149 ** a -- pointer to address descriptor to fill. 1150 ** If NULL, one will be allocated. 1151 ** e -- the current envelope. 1152 ** 1153 ** Returns: 1154 ** NULL if there was an error. 1155 ** 'a' otherwise. 1156 ** 1157 ** Side Effects: 1158 ** fills in 'a' 1159 */ 1160 1161 struct errcodes 1162 { 1163 char *ec_name; /* name of error code */ 1164 int ec_code; /* numeric code */ 1165 } ErrorCodes[] = 1166 { 1167 "usage", EX_USAGE, 1168 "nouser", EX_NOUSER, 1169 "nohost", EX_NOHOST, 1170 "unavailable", EX_UNAVAILABLE, 1171 "software", EX_SOFTWARE, 1172 "tempfail", EX_TEMPFAIL, 1173 "protocol", EX_PROTOCOL, 1174 #ifdef EX_CONFIG 1175 "config", EX_CONFIG, 1176 #endif 1177 NULL, EX_UNAVAILABLE, 1178 }; 1179 1180 ADDRESS * 1181 buildaddr(tv, a, e) 1182 register char **tv; 1183 register ADDRESS *a; 1184 register ENVELOPE *e; 1185 { 1186 struct mailer **mp; 1187 register struct mailer *m; 1188 char *bp; 1189 int spaceleft; 1190 static char buf[MAXNAME]; 1191 1192 if (a == NULL) 1193 a = (ADDRESS *) xalloc(sizeof *a); 1194 bzero((char *) a, sizeof *a); 1195 1196 /* figure out what net/mailer to use */ 1197 if ((**tv & 0377) != CANONNET) 1198 { 1199 syserr("554 buildaddr: no net"); 1200 return (NULL); 1201 } 1202 tv++; 1203 if (strcasecmp(*tv, "error") == 0) 1204 { 1205 if ((**++tv & 0377) == CANONHOST) 1206 { 1207 register struct errcodes *ep; 1208 1209 if (isascii(**++tv) && isdigit(**tv)) 1210 { 1211 setstat(atoi(*tv)); 1212 } 1213 else 1214 { 1215 for (ep = ErrorCodes; ep->ec_name != NULL; ep++) 1216 if (strcasecmp(ep->ec_name, *tv) == 0) 1217 break; 1218 setstat(ep->ec_code); 1219 } 1220 tv++; 1221 } 1222 if ((**tv & 0377) != CANONUSER) 1223 syserr("554 buildaddr: error: no user"); 1224 cataddr(++tv, NULL, buf, sizeof buf, ' '); 1225 stripquotes(buf); 1226 usrerr(buf); 1227 return (NULL); 1228 } 1229 1230 for (mp = Mailer; (m = *mp++) != NULL; ) 1231 { 1232 if (strcasecmp(m->m_name, *tv) == 0) 1233 break; 1234 } 1235 if (m == NULL) 1236 { 1237 syserr("554 buildaddr: unknown mailer %s", *tv); 1238 return (NULL); 1239 } 1240 a->q_mailer = m; 1241 1242 /* figure out what host (if any) */ 1243 tv++; 1244 if ((**tv & 0377) == CANONHOST) 1245 { 1246 bp = buf; 1247 spaceleft = sizeof buf - 1; 1248 while (*++tv != NULL && (**tv & 0377) != CANONUSER) 1249 { 1250 int i = strlen(*tv); 1251 1252 if (i > spaceleft) 1253 { 1254 /* out of space for this address */ 1255 if (spaceleft >= 0) 1256 syserr("554 buildaddr: host too long (%.40s...)", 1257 buf); 1258 i = spaceleft; 1259 spaceleft = 0; 1260 } 1261 if (i <= 0) 1262 continue; 1263 bcopy(*tv, bp, i); 1264 bp += i; 1265 spaceleft -= i; 1266 } 1267 *bp = '\0'; 1268 a->q_host = newstr(buf); 1269 } 1270 else 1271 { 1272 if (!bitnset(M_LOCALMAILER, m->m_flags)) 1273 { 1274 syserr("554 buildaddr: no host"); 1275 return (NULL); 1276 } 1277 a->q_host = NULL; 1278 } 1279 1280 /* figure out the user */ 1281 if (*tv == NULL || (**tv & 0377) != CANONUSER) 1282 { 1283 syserr("554 buildaddr: no user"); 1284 return (NULL); 1285 } 1286 tv++; 1287 1288 /* do special mapping for local mailer */ 1289 if (m == LocalMailer && *tv != NULL) 1290 { 1291 register char *p = *tv; 1292 1293 if (*p == '"') 1294 p++; 1295 if (*p == '|') 1296 a->q_mailer = m = ProgMailer; 1297 else if (*p == '/') 1298 a->q_mailer = m = FileMailer; 1299 else if (*p == ':') 1300 { 1301 /* may be :include: */ 1302 cataddr(tv, NULL, buf, sizeof buf, '\0'); 1303 stripquotes(buf); 1304 if (strncasecmp(buf, ":include:", 9) == 0) 1305 { 1306 /* if :include:, don't need further rewriting */ 1307 a->q_mailer = m = InclMailer; 1308 a->q_user = &buf[9]; 1309 return (a); 1310 } 1311 } 1312 } 1313 1314 if (m == LocalMailer && *tv != NULL && strcmp(*tv, "@") == 0) 1315 { 1316 tv++; 1317 a->q_flags |= QNOTREMOTE; 1318 } 1319 1320 /* do cleanup of final address */ 1321 (void) rewrite(tv, 4, e); 1322 1323 /* save the result for the command line/RCPT argument */ 1324 cataddr(tv, NULL, buf, sizeof buf, '\0'); 1325 a->q_user = buf; 1326 1327 /* 1328 ** Do mapping to lower case as requested by mailer 1329 */ 1330 1331 if (a->q_host != NULL && !bitnset(M_HST_UPPER, m->m_flags)) 1332 makelower(a->q_host); 1333 if (!bitnset(M_USR_UPPER, m->m_flags)) 1334 makelower(a->q_user); 1335 1336 return (a); 1337 } 1338 /* 1339 ** CATADDR -- concatenate pieces of addresses (putting in <LWSP> subs) 1340 ** 1341 ** Parameters: 1342 ** pvp -- parameter vector to rebuild. 1343 ** evp -- last parameter to include. Can be NULL to 1344 ** use entire pvp. 1345 ** buf -- buffer to build the string into. 1346 ** sz -- size of buf. 1347 ** spacesub -- the space separator character; if null, 1348 ** use SpaceSub. 1349 ** 1350 ** Returns: 1351 ** none. 1352 ** 1353 ** Side Effects: 1354 ** Destroys buf. 1355 */ 1356 1357 cataddr(pvp, evp, buf, sz, spacesub) 1358 char **pvp; 1359 char **evp; 1360 char *buf; 1361 register int sz; 1362 char spacesub; 1363 { 1364 bool oatomtok = FALSE; 1365 bool natomtok = FALSE; 1366 register int i; 1367 register char *p; 1368 1369 if (spacesub == '\0') 1370 spacesub = SpaceSub; 1371 1372 if (pvp == NULL) 1373 { 1374 (void) strcpy(buf, ""); 1375 return; 1376 } 1377 p = buf; 1378 sz -= 2; 1379 while (*pvp != NULL && (i = strlen(*pvp)) < sz) 1380 { 1381 natomtok = (toktype(**pvp) == ATM); 1382 if (oatomtok && natomtok) 1383 *p++ = spacesub; 1384 (void) strcpy(p, *pvp); 1385 oatomtok = natomtok; 1386 p += i; 1387 sz -= i + 1; 1388 if (pvp++ == evp) 1389 break; 1390 } 1391 *p = '\0'; 1392 } 1393 /* 1394 ** SAMEADDR -- Determine if two addresses are the same 1395 ** 1396 ** This is not just a straight comparison -- if the mailer doesn't 1397 ** care about the host we just ignore it, etc. 1398 ** 1399 ** Parameters: 1400 ** a, b -- pointers to the internal forms to compare. 1401 ** 1402 ** Returns: 1403 ** TRUE -- they represent the same mailbox. 1404 ** FALSE -- they don't. 1405 ** 1406 ** Side Effects: 1407 ** none. 1408 */ 1409 1410 bool 1411 sameaddr(a, b) 1412 register ADDRESS *a; 1413 register ADDRESS *b; 1414 { 1415 /* if they don't have the same mailer, forget it */ 1416 if (a->q_mailer != b->q_mailer) 1417 return (FALSE); 1418 1419 /* if the user isn't the same, we can drop out */ 1420 if (strcmp(a->q_user, b->q_user) != 0) 1421 return (FALSE); 1422 1423 /* if we have good uids for both but the differ, these are different */ 1424 if (bitset(QGOODUID, a->q_flags & b->q_flags) && a->q_uid != b->q_uid) 1425 return (FALSE); 1426 1427 /* otherwise compare hosts (but be careful for NULL ptrs) */ 1428 if (a->q_host == b->q_host) 1429 { 1430 /* probably both null pointers */ 1431 return (TRUE); 1432 } 1433 if (a->q_host == NULL || b->q_host == NULL) 1434 { 1435 /* only one is a null pointer */ 1436 return (FALSE); 1437 } 1438 if (strcmp(a->q_host, b->q_host) != 0) 1439 return (FALSE); 1440 1441 return (TRUE); 1442 } 1443 /* 1444 ** PRINTADDR -- print address (for debugging) 1445 ** 1446 ** Parameters: 1447 ** a -- the address to print 1448 ** follow -- follow the q_next chain. 1449 ** 1450 ** Returns: 1451 ** none. 1452 ** 1453 ** Side Effects: 1454 ** none. 1455 */ 1456 1457 printaddr(a, follow) 1458 register ADDRESS *a; 1459 bool follow; 1460 { 1461 bool first = TRUE; 1462 register MAILER *m; 1463 MAILER pseudomailer; 1464 1465 while (a != NULL) 1466 { 1467 first = FALSE; 1468 printf("%x=", a); 1469 (void) fflush(stdout); 1470 1471 /* find the mailer -- carefully */ 1472 m = a->q_mailer; 1473 if (m == NULL) 1474 { 1475 m = &pseudomailer; 1476 m->m_mno = -1; 1477 m->m_name = "NULL"; 1478 } 1479 1480 printf("%s:\n\tmailer %d (%s), host `%s', user `%s', ruser `%s'\n", 1481 a->q_paddr, m->m_mno, m->m_name, 1482 a->q_host, a->q_user, 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, a->q_fullname); 1488 1489 if (!follow) 1490 return; 1491 a = a->q_next; 1492 } 1493 if (first) 1494 printf("[NULL]\n"); 1495 } 1496 1497 /* 1498 ** REMOTENAME -- return the name relative to the current mailer 1499 ** 1500 ** Parameters: 1501 ** name -- the name to translate. 1502 ** m -- the mailer that we want to do rewriting relative 1503 ** to. 1504 ** flags -- fine tune operations. 1505 ** pstat -- pointer to status word. 1506 ** e -- the current envelope. 1507 ** 1508 ** Returns: 1509 ** the text string representing this address relative to 1510 ** the receiving mailer. 1511 ** 1512 ** Side Effects: 1513 ** none. 1514 ** 1515 ** Warnings: 1516 ** The text string returned is tucked away locally; 1517 ** copy it if you intend to save it. 1518 */ 1519 1520 char * 1521 remotename(name, m, flags, pstat, e) 1522 char *name; 1523 struct mailer *m; 1524 int flags; 1525 int *pstat; 1526 register ENVELOPE *e; 1527 { 1528 register char **pvp; 1529 char *fancy; 1530 extern char *macvalue(); 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 **prescan(); 1537 extern char *crackaddr(); 1538 1539 if (tTd(12, 1)) 1540 printf("remotename(%s)\n", name); 1541 1542 /* don't do anything if we are tagging it as special */ 1543 if (bitset(RF_SENDERADDR, flags)) 1544 rwset = bitset(RF_HEADERADDR, flags) ? m->m_sh_rwset 1545 : m->m_se_rwset; 1546 else 1547 rwset = bitset(RF_HEADERADDR, flags) ? m->m_rh_rwset 1548 : m->m_re_rwset; 1549 if (rwset < 0) 1550 return (name); 1551 1552 /* 1553 ** Do a heuristic crack of this name to extract any comment info. 1554 ** This will leave the name as a comment and a $g macro. 1555 */ 1556 1557 if (bitset(RF_CANONICAL, flags) || bitnset(M_NOCOMMENT, m->m_flags)) 1558 fancy = "\201g"; 1559 else 1560 fancy = crackaddr(name); 1561 1562 /* 1563 ** Turn the name into canonical form. 1564 ** Normally this will be RFC 822 style, i.e., "user@domain". 1565 ** If this only resolves to "user", and the "C" flag is 1566 ** specified in the sending mailer, then the sender's 1567 ** domain will be appended. 1568 */ 1569 1570 pvp = prescan(name, '\0', pvpbuf, NULL); 1571 if (pvp == NULL) 1572 return (name); 1573 if (rewrite(pvp, 3, e) == EX_TEMPFAIL) 1574 *pstat = EX_TEMPFAIL; 1575 if (bitset(RF_ADDDOMAIN, flags) && e->e_fromdomain != NULL) 1576 { 1577 /* append from domain to this address */ 1578 register char **pxp = pvp; 1579 1580 /* see if there is an "@domain" in the current name */ 1581 while (*pxp != NULL && strcmp(*pxp, "@") != 0) 1582 pxp++; 1583 if (*pxp == NULL) 1584 { 1585 /* no.... append the "@domain" from the sender */ 1586 register char **qxq = e->e_fromdomain; 1587 1588 while ((*pxp++ = *qxq++) != NULL) 1589 continue; 1590 if (rewrite(pvp, 3, e) == EX_TEMPFAIL) 1591 *pstat = EX_TEMPFAIL; 1592 } 1593 } 1594 1595 /* 1596 ** Do more specific rewriting. 1597 ** Rewrite using ruleset 1 or 2 depending on whether this is 1598 ** a sender address or not. 1599 ** Then run it through any receiving-mailer-specific rulesets. 1600 */ 1601 1602 if (bitset(RF_SENDERADDR, flags)) 1603 { 1604 if (rewrite(pvp, 1, e) == EX_TEMPFAIL) 1605 *pstat = EX_TEMPFAIL; 1606 } 1607 else 1608 { 1609 if (rewrite(pvp, 2, e) == EX_TEMPFAIL) 1610 *pstat = EX_TEMPFAIL; 1611 } 1612 if (rwset > 0) 1613 { 1614 if (rewrite(pvp, rwset, e) == EX_TEMPFAIL) 1615 *pstat = EX_TEMPFAIL; 1616 } 1617 1618 /* 1619 ** Do any final sanitation the address may require. 1620 ** This will normally be used to turn internal forms 1621 ** (e.g., user@host.LOCAL) into external form. This 1622 ** may be used as a default to the above rules. 1623 */ 1624 1625 if (rewrite(pvp, 4, e) == EX_TEMPFAIL) 1626 *pstat = EX_TEMPFAIL; 1627 1628 /* 1629 ** Now restore the comment information we had at the beginning. 1630 */ 1631 1632 cataddr(pvp, NULL, lbuf, sizeof lbuf, '\0'); 1633 define('g', lbuf, e); 1634 expand(fancy, buf, &buf[sizeof buf - 1], e); 1635 define('g', oldg, e); 1636 1637 if (tTd(12, 1)) 1638 printf("remotename => `%s'\n", buf); 1639 return (buf); 1640 } 1641 /* 1642 ** MAPLOCALUSER -- run local username through ruleset 5 for final redirection 1643 ** 1644 ** Parameters: 1645 ** a -- the address to map (but just the user name part). 1646 ** sendq -- the sendq in which to install any replacement 1647 ** addresses. 1648 ** 1649 ** Returns: 1650 ** none. 1651 */ 1652 1653 maplocaluser(a, sendq, e) 1654 register ADDRESS *a; 1655 ADDRESS **sendq; 1656 ENVELOPE *e; 1657 { 1658 register char **pvp; 1659 register ADDRESS *a1 = NULL; 1660 auto char *delimptr; 1661 char pvpbuf[PSBUFSIZE]; 1662 1663 if (tTd(29, 1)) 1664 { 1665 printf("maplocaluser: "); 1666 printaddr(a, FALSE); 1667 } 1668 pvp = prescan(a->q_user, '\0', pvpbuf, &delimptr); 1669 if (pvp == NULL) 1670 return; 1671 1672 (void) rewrite(pvp, 5, e); 1673 if (pvp[0] == NULL || (pvp[0][0] & 0377) != CANONNET) 1674 return; 1675 1676 /* if non-null, mailer destination specified -- has it changed? */ 1677 a1 = buildaddr(pvp, NULL, e); 1678 if (a1 == NULL || sameaddr(a, a1)) 1679 return; 1680 1681 /* mark old address as dead; insert new address */ 1682 a->q_flags |= QDONTSEND; 1683 if (tTd(29, 5)) 1684 { 1685 printf("maplocaluser: QDONTSEND "); 1686 printaddr(a, FALSE); 1687 } 1688 a1->q_alias = a; 1689 allocaddr(a1, 1, NULL, delimptr); 1690 (void) recipient(a1, sendq, e); 1691 } 1692 /* 1693 ** DEQUOTE_INIT -- initialize dequote map 1694 ** 1695 ** This is a no-op. 1696 ** 1697 ** Parameters: 1698 ** map -- the internal map structure. 1699 ** mapname -- the name of the mapl. 1700 ** args -- arguments. 1701 ** 1702 ** Returns: 1703 ** TRUE. 1704 */ 1705 1706 bool 1707 dequote_init(map, mapname, args) 1708 MAP *map; 1709 char *mapname; 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