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.6 (Berkeley) 07/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 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("653 Unbalanced '\"' (fixed)"); 375 c = '"'; 376 } 377 else if (cmntcnt > 0) 378 { 379 usrerr("653 Unbalanced '(' (fixed)"); 380 c = ')'; 381 } 382 else if (anglecnt > 0) 383 { 384 c = '>'; 385 usrerr("653 Unbalanced '<' (fixed)"); 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("653 Unbalanced ')' (fixed)"); 436 c = NOCHAR; 437 } 438 else 439 cmntcnt--; 440 } 441 else if (cmntcnt > 0) 442 c = NOCHAR; 443 else if (c == '<') 444 anglecnt++; 445 else if (c == '>') 446 { 447 if (anglecnt <= 0) 448 { 449 usrerr("653 Unbalanced '>' (fixed)"); 450 c = NOCHAR; 451 } 452 else 453 anglecnt--; 454 } 455 else if (delim == ' ' && isascii(c) && isspace(c)) 456 c = ' '; 457 458 if (c == NOCHAR) 459 continue; 460 461 /* see if this is end of input */ 462 if (c == delim && anglecnt <= 0 && state != QST) 463 break; 464 465 newstate = StateTab[state][toktype(c)]; 466 if (tTd(22, 101)) 467 printf("ns=%02o\n", newstate); 468 state = newstate & TYPE; 469 if (bitset(M, newstate)) 470 c = NOCHAR; 471 if (bitset(B, newstate)) 472 break; 473 } 474 475 /* new token */ 476 if (tok != q) 477 { 478 *q++ = '\0'; 479 if (tTd(22, 36)) 480 { 481 printf("tok="); 482 xputs(tok); 483 (void) putchar('\n'); 484 } 485 if (avp >= &av[MAXATOM]) 486 { 487 syserr("553 prescan: too many tokens"); 488 if (delimptr != NULL) 489 *delimptr = p; 490 CurEnv->e_to = saveto; 491 return (NULL); 492 } 493 *avp++ = tok; 494 } 495 } while (c != '\0' && (c != delim || anglecnt > 0)); 496 *avp = NULL; 497 p--; 498 if (delimptr != NULL) 499 *delimptr = p; 500 if (tTd(22, 12)) 501 { 502 printf("prescan==>"); 503 printav(av); 504 } 505 CurEnv->e_to = saveto; 506 if (av[0] == NULL) 507 return (NULL); 508 return (av); 509 } 510 /* 511 ** TOKTYPE -- return token type 512 ** 513 ** Parameters: 514 ** c -- the character in question. 515 ** 516 ** Returns: 517 ** Its type. 518 ** 519 ** Side Effects: 520 ** none. 521 */ 522 523 toktype(c) 524 register int c; 525 { 526 static char buf[50]; 527 static bool firstime = TRUE; 528 529 if (firstime) 530 { 531 firstime = FALSE; 532 expand("\201o", buf, &buf[sizeof buf - 1], CurEnv); 533 (void) strcat(buf, DELIMCHARS); 534 } 535 c &= 0377; 536 if (c == MATCHCLASS || c == MATCHREPL || c == MATCHNCLASS) 537 return (ONE); 538 if (c == MACRODEXPAND) 539 return (ONE); 540 if (c == '"') 541 return (QST); 542 if ((c & 0340) == 0200) 543 return (OPR); 544 if (!isascii(c)) 545 return (ATM); 546 if (isspace(c) || c == ')') 547 return (SPC); 548 if (strchr(buf, c) != NULL) 549 return (OPR); 550 return (ATM); 551 } 552 /* 553 ** REWRITE -- apply rewrite rules to token vector. 554 ** 555 ** This routine is an ordered production system. Each rewrite 556 ** rule has a LHS (called the pattern) and a RHS (called the 557 ** rewrite); 'rwr' points the the current rewrite rule. 558 ** 559 ** For each rewrite rule, 'avp' points the address vector we 560 ** are trying to match against, and 'pvp' points to the pattern. 561 ** If pvp points to a special match value (MATCHZANY, MATCHANY, 562 ** MATCHONE, MATCHCLASS, MATCHNCLASS) then the address in avp 563 ** matched is saved away in the match vector (pointed to by 'mvp'). 564 ** 565 ** When a match between avp & pvp does not match, we try to 566 ** back out. If we back up over MATCHONE, MATCHCLASS, or MATCHNCLASS 567 ** we must also back out the match in mvp. If we reach a 568 ** MATCHANY or MATCHZANY we just extend the match and start 569 ** over again. 570 ** 571 ** When we finally match, we rewrite the address vector 572 ** and try over again. 573 ** 574 ** Parameters: 575 ** pvp -- pointer to token vector. 576 ** ruleset -- the ruleset to use for rewriting. 577 ** e -- the current envelope. 578 ** 579 ** Returns: 580 ** A status code. If EX_TEMPFAIL, higher level code should 581 ** attempt recovery. 582 ** 583 ** Side Effects: 584 ** pvp is modified. 585 */ 586 587 struct match 588 { 589 char **first; /* first token matched */ 590 char **last; /* last token matched */ 591 char **pattern; /* pointer to pattern */ 592 }; 593 594 # define MAXMATCH 9 /* max params per rewrite */ 595 596 597 int 598 rewrite(pvp, ruleset, e) 599 char **pvp; 600 int ruleset; 601 register ENVELOPE *e; 602 { 603 register char *ap; /* address pointer */ 604 register char *rp; /* rewrite pointer */ 605 register char **avp; /* address vector pointer */ 606 register char **rvp; /* rewrite vector pointer */ 607 register struct match *mlp; /* cur ptr into mlist */ 608 register struct rewrite *rwr; /* pointer to current rewrite rule */ 609 int ruleno; /* current rule number */ 610 int rstat = EX_OK; /* return status */ 611 struct match mlist[MAXMATCH]; /* stores match on LHS */ 612 char *npvp[MAXATOM+1]; /* temporary space for rebuild */ 613 614 if (OpMode == MD_TEST || tTd(21, 2)) 615 { 616 printf("rewrite: ruleset %2d input:", ruleset); 617 printav(pvp); 618 } 619 if (ruleset < 0 || ruleset >= MAXRWSETS) 620 { 621 syserr("554 rewrite: illegal ruleset number %d", ruleset); 622 return EX_CONFIG; 623 } 624 if (pvp == NULL) 625 return EX_USAGE; 626 627 /* 628 ** Run through the list of rewrite rules, applying 629 ** any that match. 630 */ 631 632 ruleno = 1; 633 for (rwr = RewriteRules[ruleset]; rwr != NULL; ) 634 { 635 int loopcount = 0; 636 637 if (tTd(21, 12)) 638 { 639 printf("-----trying rule:"); 640 printav(rwr->r_lhs); 641 } 642 643 /* try to match on this rule */ 644 mlp = mlist; 645 rvp = rwr->r_lhs; 646 avp = pvp; 647 if (++loopcount > 100) 648 { 649 syserr("554 Infinite loop in ruleset %d, rule %d", 650 ruleset, ruleno); 651 if (tTd(21, 1)) 652 { 653 printf("workspace: "); 654 printav(pvp); 655 } 656 break; 657 } 658 659 while ((ap = *avp) != NULL || *rvp != NULL) 660 { 661 rp = *rvp; 662 if (tTd(21, 35)) 663 { 664 printf("ADVANCE rp="); 665 xputs(rp); 666 printf(", ap="); 667 xputs(ap); 668 printf("\n"); 669 } 670 if (rp == NULL) 671 { 672 /* end-of-pattern before end-of-address */ 673 goto backup; 674 } 675 if (ap == NULL && (*rp & 0377) != MATCHZANY && 676 (*rp & 0377) != MATCHZERO) 677 { 678 /* end-of-input with patterns left */ 679 goto backup; 680 } 681 682 switch (*rp & 0377) 683 { 684 register STAB *s; 685 char buf[MAXLINE]; 686 687 case MATCHCLASS: 688 /* match any phrase in a class */ 689 mlp->pattern = rvp; 690 mlp->first = avp; 691 extendclass: 692 ap = *avp; 693 if (ap == NULL) 694 goto backup; 695 mlp->last = avp++; 696 cataddr(mlp->first, mlp->last, buf, sizeof buf, '\0'); 697 s = stab(buf, ST_CLASS, ST_FIND); 698 if (s == NULL || !bitnset(rp[1], s->s_class)) 699 { 700 if (tTd(21, 36)) 701 { 702 printf("EXTEND rp="); 703 xputs(rp); 704 printf(", ap="); 705 xputs(ap); 706 printf("\n"); 707 } 708 goto extendclass; 709 } 710 if (tTd(21, 36)) 711 printf("CLMATCH\n"); 712 mlp++; 713 break; 714 715 case MATCHNCLASS: 716 /* match any token not in a class */ 717 s = stab(ap, ST_CLASS, ST_FIND); 718 if (s != NULL && bitnset(rp[1], s->s_class)) 719 goto backup; 720 721 /* fall through */ 722 723 case MATCHONE: 724 case MATCHANY: 725 /* match exactly one token */ 726 mlp->pattern = rvp; 727 mlp->first = avp; 728 mlp->last = avp++; 729 mlp++; 730 break; 731 732 case MATCHZANY: 733 /* match zero or more tokens */ 734 mlp->pattern = rvp; 735 mlp->first = avp; 736 mlp->last = avp - 1; 737 mlp++; 738 break; 739 740 case MATCHZERO: 741 /* match zero tokens */ 742 break; 743 744 case MACRODEXPAND: 745 /* 746 ** Match against run-time macro. 747 ** This algorithm is broken for the 748 ** general case (no recursive macros, 749 ** improper tokenization) but should 750 ** work for the usual cases. 751 */ 752 753 ap = macvalue(rp[1], e); 754 mlp->first = avp; 755 if (tTd(21, 2)) 756 printf("rewrite: LHS $&%c => \"%s\"\n", 757 rp[1], 758 ap == NULL ? "(NULL)" : ap); 759 760 if (ap == NULL) 761 break; 762 while (*ap != '\0') 763 { 764 if (*avp == NULL || 765 strncasecmp(ap, *avp, strlen(*avp)) != 0) 766 { 767 /* no match */ 768 avp = mlp->first; 769 goto backup; 770 } 771 ap += strlen(*avp++); 772 } 773 774 /* match */ 775 break; 776 777 default: 778 /* must have exact match */ 779 if (strcasecmp(rp, ap)) 780 goto backup; 781 avp++; 782 break; 783 } 784 785 /* successful match on this token */ 786 rvp++; 787 continue; 788 789 backup: 790 /* match failed -- back up */ 791 while (--mlp >= mlist) 792 { 793 rvp = mlp->pattern; 794 rp = *rvp; 795 avp = mlp->last + 1; 796 ap = *avp; 797 798 if (tTd(21, 36)) 799 { 800 printf("BACKUP rp="); 801 xputs(rp); 802 printf(", ap="); 803 xputs(ap); 804 printf("\n"); 805 } 806 807 if (ap == NULL) 808 { 809 /* run off the end -- back up again */ 810 continue; 811 } 812 if ((*rp & 0377) == MATCHANY || 813 (*rp & 0377) == MATCHZANY) 814 { 815 /* extend binding and continue */ 816 mlp->last = avp++; 817 rvp++; 818 mlp++; 819 break; 820 } 821 if ((*rp & 0377) == MATCHCLASS) 822 { 823 /* extend binding and try again */ 824 mlp->last = avp; 825 goto extendclass; 826 } 827 } 828 829 if (mlp < mlist) 830 { 831 /* total failure to match */ 832 break; 833 } 834 } 835 836 /* 837 ** See if we successfully matched 838 */ 839 840 if (mlp < mlist || *rvp != NULL) 841 { 842 if (tTd(21, 10)) 843 printf("----- rule fails\n"); 844 rwr = rwr->r_next; 845 ruleno++; 846 continue; 847 } 848 849 rvp = rwr->r_rhs; 850 if (tTd(21, 12)) 851 { 852 printf("-----rule matches:"); 853 printav(rvp); 854 } 855 856 rp = *rvp; 857 if ((*rp & 0377) == CANONUSER) 858 { 859 rvp++; 860 rwr = rwr->r_next; 861 ruleno++; 862 } 863 else if ((*rp & 0377) == CANONHOST) 864 { 865 rvp++; 866 rwr = NULL; 867 } 868 else if ((*rp & 0377) == CANONNET) 869 rwr = NULL; 870 871 /* substitute */ 872 for (avp = npvp; *rvp != NULL; rvp++) 873 { 874 register struct match *m; 875 register char **pp; 876 877 rp = *rvp; 878 if ((*rp & 0377) == MATCHREPL) 879 { 880 /* substitute from LHS */ 881 m = &mlist[rp[1] - '1']; 882 if (m < mlist || m >= mlp) 883 { 884 syserr("554 rewrite: ruleset %d: replacement $%c out of bounds", 885 ruleset, rp[1]); 886 return EX_CONFIG; 887 } 888 if (tTd(21, 15)) 889 { 890 printf("$%c:", rp[1]); 891 pp = m->first; 892 while (pp <= m->last) 893 { 894 printf(" %x=\"", *pp); 895 (void) fflush(stdout); 896 printf("%s\"", *pp++); 897 } 898 printf("\n"); 899 } 900 pp = m->first; 901 while (pp <= m->last) 902 { 903 if (avp >= &npvp[MAXATOM]) 904 { 905 syserr("554 rewrite: expansion too long"); 906 return EX_DATAERR; 907 } 908 *avp++ = *pp++; 909 } 910 } 911 else 912 { 913 /* vanilla replacement */ 914 if (avp >= &npvp[MAXATOM]) 915 { 916 toolong: 917 syserr("554 rewrite: expansion too long"); 918 return EX_DATAERR; 919 } 920 if ((*rp & 0377) != MACRODEXPAND) 921 *avp++ = rp; 922 else 923 { 924 *avp = macvalue(rp[1], e); 925 if (tTd(21, 2)) 926 printf("rewrite: RHS $&%c => \"%s\"\n", 927 rp[1], 928 *avp == NULL ? "(NULL)" : *avp); 929 if (*avp != NULL) 930 avp++; 931 } 932 } 933 } 934 *avp++ = NULL; 935 936 /* 937 ** Check for any hostname/keyword lookups. 938 */ 939 940 for (rvp = npvp; *rvp != NULL; rvp++) 941 { 942 char **hbrvp; 943 char **xpvp; 944 int trsize; 945 char *replac; 946 int endtoken; 947 STAB *map; 948 char *mapname; 949 char **key_rvp; 950 char **arg_rvp; 951 char **default_rvp; 952 char buf[MAXNAME + 1]; 953 char *pvpb1[MAXATOM + 1]; 954 char *argvect[10]; 955 char pvpbuf[PSBUFSIZE]; 956 957 if ((**rvp & 0377) != HOSTBEGIN && 958 (**rvp & 0377) != LOOKUPBEGIN) 959 continue; 960 961 /* 962 ** Got a hostname/keyword lookup. 963 ** 964 ** This could be optimized fairly easily. 965 */ 966 967 hbrvp = rvp; 968 if ((**rvp & 0377) == HOSTBEGIN) 969 { 970 endtoken = HOSTEND; 971 mapname = "host"; 972 } 973 else 974 { 975 endtoken = LOOKUPEND; 976 mapname = *++rvp; 977 } 978 map = stab(mapname, ST_MAP, ST_FIND); 979 if (map == NULL) 980 syserr("554 rewrite: map %s not found", mapname); 981 982 /* extract the match part */ 983 key_rvp = ++rvp; 984 default_rvp = NULL; 985 arg_rvp = argvect; 986 xpvp = NULL; 987 replac = pvpbuf; 988 while (*rvp != NULL && (**rvp & 0377) != endtoken) 989 { 990 int nodetype = **rvp & 0377; 991 992 if (nodetype != CANONHOST && nodetype != CANONUSER) 993 { 994 rvp++; 995 continue; 996 } 997 998 *rvp++ = NULL; 999 1000 if (xpvp != NULL) 1001 { 1002 cataddr(xpvp, NULL, replac, 1003 &pvpbuf[sizeof pvpbuf] - replac, 1004 '\0'); 1005 *++arg_rvp = replac; 1006 replac += strlen(replac) + 1; 1007 xpvp = NULL; 1008 } 1009 switch (nodetype) 1010 { 1011 case CANONHOST: 1012 xpvp = rvp; 1013 break; 1014 1015 case CANONUSER: 1016 default_rvp = rvp; 1017 break; 1018 } 1019 } 1020 if (*rvp != NULL) 1021 *rvp++ = NULL; 1022 if (xpvp != NULL) 1023 { 1024 cataddr(xpvp, NULL, replac, 1025 &pvpbuf[sizeof pvpbuf] - replac, 1026 '\0'); 1027 *++arg_rvp = replac; 1028 } 1029 *++arg_rvp = NULL; 1030 1031 /* save the remainder of the input string */ 1032 trsize = (int) (avp - rvp + 1) * sizeof *rvp; 1033 bcopy((char *) rvp, (char *) pvpb1, trsize); 1034 1035 /* look it up */ 1036 cataddr(key_rvp, NULL, buf, sizeof buf, '\0'); 1037 argvect[0] = buf; 1038 if (map != NULL && bitset(MF_OPEN, map->s_map.map_mflags)) 1039 { 1040 auto int stat = EX_OK; 1041 1042 /* XXX should try to auto-open the map here */ 1043 1044 if (tTd(60, 1)) 1045 printf("map_lookup(%s, %s) => ", 1046 mapname, buf); 1047 replac = (*map->s_map.map_class->map_lookup)(&map->s_map, 1048 buf, argvect, &stat); 1049 if (tTd(60, 1)) 1050 printf("%s (%d)\n", 1051 replac ? replac : "NOT FOUND", 1052 stat); 1053 1054 /* should recover if stat == EX_TEMPFAIL */ 1055 if (stat == EX_TEMPFAIL) 1056 rstat = stat; 1057 } 1058 else 1059 replac = NULL; 1060 1061 /* if no replacement, use default */ 1062 if (replac == NULL && default_rvp != NULL) 1063 { 1064 /* create the default */ 1065 cataddr(default_rvp, NULL, buf, sizeof buf, '\0'); 1066 replac = buf; 1067 } 1068 1069 if (replac == NULL) 1070 { 1071 xpvp = key_rvp; 1072 } 1073 else 1074 { 1075 /* scan the new replacement */ 1076 xpvp = prescan(replac, '\0', pvpbuf, NULL); 1077 if (xpvp == NULL) 1078 { 1079 /* prescan already printed error */ 1080 return EX_DATAERR; 1081 } 1082 } 1083 1084 /* append it to the token list */ 1085 for (avp = hbrvp; *xpvp != NULL; xpvp++) 1086 { 1087 *avp++ = newstr(*xpvp); 1088 if (avp >= &npvp[MAXATOM]) 1089 goto toolong; 1090 } 1091 1092 /* restore the old trailing information */ 1093 for (xpvp = pvpb1; (*avp++ = *xpvp++) != NULL; ) 1094 if (avp >= &npvp[MAXATOM]) 1095 goto toolong; 1096 1097 break; 1098 } 1099 1100 /* 1101 ** Check for subroutine calls. 1102 */ 1103 1104 if (*npvp != NULL && (**npvp & 0377) == CALLSUBR) 1105 { 1106 int stat; 1107 1108 bcopy((char *) &npvp[2], (char *) pvp, 1109 (int) (avp - npvp - 2) * sizeof *avp); 1110 if (tTd(21, 3)) 1111 printf("-----callsubr %s\n", npvp[1]); 1112 stat = rewrite(pvp, atoi(npvp[1]), e); 1113 if (rstat == EX_OK || stat == EX_TEMPFAIL) 1114 rstat = stat; 1115 if ((**pvp & 0377) == CANONNET) 1116 rwr = NULL; 1117 } 1118 else 1119 { 1120 bcopy((char *) npvp, (char *) pvp, 1121 (int) (avp - npvp) * sizeof *avp); 1122 } 1123 if (tTd(21, 4)) 1124 { 1125 printf("rewritten as:"); 1126 printav(pvp); 1127 } 1128 } 1129 1130 if (OpMode == MD_TEST || tTd(21, 2)) 1131 { 1132 printf("rewrite: ruleset %2d returns:", ruleset); 1133 printav(pvp); 1134 } 1135 1136 return rstat; 1137 } 1138 /* 1139 ** BUILDADDR -- build address from token vector. 1140 ** 1141 ** Parameters: 1142 ** tv -- token vector. 1143 ** a -- pointer to address descriptor to fill. 1144 ** If NULL, one will be allocated. 1145 ** e -- the current envelope. 1146 ** 1147 ** Returns: 1148 ** NULL if there was an error. 1149 ** 'a' otherwise. 1150 ** 1151 ** Side Effects: 1152 ** fills in 'a' 1153 */ 1154 1155 struct errcodes 1156 { 1157 char *ec_name; /* name of error code */ 1158 int ec_code; /* numeric code */ 1159 } ErrorCodes[] = 1160 { 1161 "usage", EX_USAGE, 1162 "nouser", EX_NOUSER, 1163 "nohost", EX_NOHOST, 1164 "unavailable", EX_UNAVAILABLE, 1165 "software", EX_SOFTWARE, 1166 "tempfail", EX_TEMPFAIL, 1167 "protocol", EX_PROTOCOL, 1168 #ifdef EX_CONFIG 1169 "config", EX_CONFIG, 1170 #endif 1171 NULL, EX_UNAVAILABLE, 1172 }; 1173 1174 ADDRESS * 1175 buildaddr(tv, a, e) 1176 register char **tv; 1177 register ADDRESS *a; 1178 register ENVELOPE *e; 1179 { 1180 struct mailer **mp; 1181 register struct mailer *m; 1182 char *bp; 1183 int spaceleft; 1184 static char buf[MAXNAME]; 1185 1186 if (a == NULL) 1187 a = (ADDRESS *) xalloc(sizeof *a); 1188 bzero((char *) a, sizeof *a); 1189 1190 /* figure out what net/mailer to use */ 1191 if ((**tv & 0377) != CANONNET) 1192 { 1193 syserr("554 buildaddr: no net"); 1194 return (NULL); 1195 } 1196 tv++; 1197 if (strcasecmp(*tv, "error") == 0) 1198 { 1199 if ((**++tv & 0377) == CANONHOST) 1200 { 1201 register struct errcodes *ep; 1202 1203 if (isascii(**++tv) && isdigit(**tv)) 1204 { 1205 setstat(atoi(*tv)); 1206 } 1207 else 1208 { 1209 for (ep = ErrorCodes; ep->ec_name != NULL; ep++) 1210 if (strcasecmp(ep->ec_name, *tv) == 0) 1211 break; 1212 setstat(ep->ec_code); 1213 } 1214 tv++; 1215 } 1216 if ((**tv & 0377) != CANONUSER) 1217 syserr("554 buildaddr: error: no user"); 1218 cataddr(++tv, NULL, buf, sizeof buf, ' '); 1219 stripquotes(buf); 1220 usrerr(buf); 1221 return (NULL); 1222 } 1223 1224 for (mp = Mailer; (m = *mp++) != NULL; ) 1225 { 1226 if (strcasecmp(m->m_name, *tv) == 0) 1227 break; 1228 } 1229 if (m == NULL) 1230 { 1231 syserr("554 buildaddr: unknown mailer %s", *tv); 1232 return (NULL); 1233 } 1234 a->q_mailer = m; 1235 1236 /* figure out what host (if any) */ 1237 tv++; 1238 if ((**tv & 0377) == CANONHOST) 1239 { 1240 bp = buf; 1241 spaceleft = sizeof buf - 1; 1242 while (*++tv != NULL && (**tv & 0377) != CANONUSER) 1243 { 1244 int i = strlen(*tv); 1245 1246 if (i > spaceleft) 1247 { 1248 /* out of space for this address */ 1249 if (spaceleft >= 0) 1250 syserr("554 buildaddr: host too long (%.40s...)", 1251 buf); 1252 i = spaceleft; 1253 spaceleft = 0; 1254 } 1255 if (i <= 0) 1256 continue; 1257 bcopy(*tv, bp, i); 1258 bp += i; 1259 spaceleft -= i; 1260 } 1261 *bp = '\0'; 1262 a->q_host = newstr(buf); 1263 } 1264 else 1265 { 1266 if (!bitnset(M_LOCALMAILER, m->m_flags)) 1267 { 1268 syserr("554 buildaddr: no host"); 1269 return (NULL); 1270 } 1271 a->q_host = NULL; 1272 } 1273 1274 /* figure out the user */ 1275 if (*tv == NULL || (**tv & 0377) != CANONUSER) 1276 { 1277 syserr("554 buildaddr: no user"); 1278 return (NULL); 1279 } 1280 tv++; 1281 1282 /* do special mapping for local mailer */ 1283 if (m == LocalMailer && *tv != NULL) 1284 { 1285 register char *p = *tv; 1286 1287 if (*p == '"') 1288 p++; 1289 if (*p == '|') 1290 a->q_mailer = m = ProgMailer; 1291 else if (*p == '/') 1292 a->q_mailer = m = FileMailer; 1293 else if (*p == ':') 1294 { 1295 /* may be :include: */ 1296 cataddr(tv, NULL, buf, sizeof buf, '\0'); 1297 stripquotes(buf); 1298 if (strncasecmp(buf, ":include:", 9) == 0) 1299 { 1300 /* if :include:, don't need further rewriting */ 1301 a->q_mailer = m = InclMailer; 1302 a->q_user = &buf[9]; 1303 return (a); 1304 } 1305 } 1306 } 1307 1308 if (m == LocalMailer && *tv != NULL && strcmp(*tv, "@") == 0) 1309 { 1310 tv++; 1311 a->q_flags |= QNOTREMOTE; 1312 } 1313 1314 /* do cleanup of final address */ 1315 (void) rewrite(tv, 4, e); 1316 1317 /* save the result for the command line/RCPT argument */ 1318 cataddr(tv, NULL, buf, sizeof buf, '\0'); 1319 a->q_user = buf; 1320 1321 /* 1322 ** Do mapping to lower case as requested by mailer 1323 */ 1324 1325 if (a->q_host != NULL && !bitnset(M_HST_UPPER, m->m_flags)) 1326 makelower(a->q_host); 1327 if (!bitnset(M_USR_UPPER, m->m_flags)) 1328 makelower(a->q_user); 1329 1330 return (a); 1331 } 1332 /* 1333 ** CATADDR -- concatenate pieces of addresses (putting in <LWSP> subs) 1334 ** 1335 ** Parameters: 1336 ** pvp -- parameter vector to rebuild. 1337 ** evp -- last parameter to include. Can be NULL to 1338 ** use entire pvp. 1339 ** buf -- buffer to build the string into. 1340 ** sz -- size of buf. 1341 ** spacesub -- the space separator character; if null, 1342 ** use SpaceSub. 1343 ** 1344 ** Returns: 1345 ** none. 1346 ** 1347 ** Side Effects: 1348 ** Destroys buf. 1349 */ 1350 1351 cataddr(pvp, evp, buf, sz, spacesub) 1352 char **pvp; 1353 char **evp; 1354 char *buf; 1355 register int sz; 1356 char spacesub; 1357 { 1358 bool oatomtok = FALSE; 1359 bool natomtok = FALSE; 1360 register int i; 1361 register char *p; 1362 1363 if (spacesub == '\0') 1364 spacesub = SpaceSub; 1365 1366 if (pvp == NULL) 1367 { 1368 (void) strcpy(buf, ""); 1369 return; 1370 } 1371 p = buf; 1372 sz -= 2; 1373 while (*pvp != NULL && (i = strlen(*pvp)) < sz) 1374 { 1375 natomtok = (toktype(**pvp) == ATM); 1376 if (oatomtok && natomtok) 1377 *p++ = spacesub; 1378 (void) strcpy(p, *pvp); 1379 oatomtok = natomtok; 1380 p += i; 1381 sz -= i + 1; 1382 if (pvp++ == evp) 1383 break; 1384 } 1385 *p = '\0'; 1386 } 1387 /* 1388 ** SAMEADDR -- Determine if two addresses are the same 1389 ** 1390 ** This is not just a straight comparison -- if the mailer doesn't 1391 ** care about the host we just ignore it, etc. 1392 ** 1393 ** Parameters: 1394 ** a, b -- pointers to the internal forms to compare. 1395 ** 1396 ** Returns: 1397 ** TRUE -- they represent the same mailbox. 1398 ** FALSE -- they don't. 1399 ** 1400 ** Side Effects: 1401 ** none. 1402 */ 1403 1404 bool 1405 sameaddr(a, b) 1406 register ADDRESS *a; 1407 register ADDRESS *b; 1408 { 1409 /* if they don't have the same mailer, forget it */ 1410 if (a->q_mailer != b->q_mailer) 1411 return (FALSE); 1412 1413 /* if the user isn't the same, we can drop out */ 1414 if (strcmp(a->q_user, b->q_user) != 0) 1415 return (FALSE); 1416 1417 /* if we have good uids for both but the differ, these are different */ 1418 if (bitset(QGOODUID, a->q_flags & b->q_flags) && a->q_uid != b->q_uid) 1419 return (FALSE); 1420 1421 /* otherwise compare hosts (but be careful for NULL ptrs) */ 1422 if (a->q_host == b->q_host) 1423 { 1424 /* probably both null pointers */ 1425 return (TRUE); 1426 } 1427 if (a->q_host == NULL || b->q_host == NULL) 1428 { 1429 /* only one is a null pointer */ 1430 return (FALSE); 1431 } 1432 if (strcmp(a->q_host, b->q_host) != 0) 1433 return (FALSE); 1434 1435 return (TRUE); 1436 } 1437 /* 1438 ** PRINTADDR -- print address (for debugging) 1439 ** 1440 ** Parameters: 1441 ** a -- the address to print 1442 ** follow -- follow the q_next chain. 1443 ** 1444 ** Returns: 1445 ** none. 1446 ** 1447 ** Side Effects: 1448 ** none. 1449 */ 1450 1451 printaddr(a, follow) 1452 register ADDRESS *a; 1453 bool follow; 1454 { 1455 bool first = TRUE; 1456 register MAILER *m; 1457 MAILER pseudomailer; 1458 1459 while (a != NULL) 1460 { 1461 first = FALSE; 1462 printf("%x=", a); 1463 (void) fflush(stdout); 1464 1465 /* find the mailer -- carefully */ 1466 m = a->q_mailer; 1467 if (m == NULL) 1468 { 1469 m = &pseudomailer; 1470 m->m_mno = -1; 1471 m->m_name = "NULL"; 1472 } 1473 1474 printf("%s:\n\tmailer %d (%s), host `%s', user `%s', ruser `%s'\n", 1475 a->q_paddr, m->m_mno, m->m_name, 1476 a->q_host, a->q_user, 1477 a->q_ruser ? a->q_ruser : "<null>"); 1478 printf("\tnext=%x, flags=%o, alias %x, uid %d, gid %d\n", 1479 a->q_next, a->q_flags, a->q_alias, a->q_uid, a->q_gid); 1480 printf("\towner=%s, home=\"%s\", fullname=\"%s\"\n", 1481 a->q_owner == NULL ? "(none)" : a->q_owner, 1482 a->q_home == NULL ? "(none)" : a->q_home, 1483 a->q_fullname == NULL ? "(none)" : a->q_fullname); 1484 1485 if (!follow) 1486 return; 1487 a = a->q_next; 1488 } 1489 if (first) 1490 printf("[NULL]\n"); 1491 } 1492 1493 /* 1494 ** REMOTENAME -- return the name relative to the current mailer 1495 ** 1496 ** Parameters: 1497 ** name -- the name to translate. 1498 ** m -- the mailer that we want to do rewriting relative 1499 ** to. 1500 ** flags -- fine tune operations. 1501 ** pstat -- pointer to status word. 1502 ** e -- the current envelope. 1503 ** 1504 ** Returns: 1505 ** the text string representing this address relative to 1506 ** the receiving mailer. 1507 ** 1508 ** Side Effects: 1509 ** none. 1510 ** 1511 ** Warnings: 1512 ** The text string returned is tucked away locally; 1513 ** copy it if you intend to save it. 1514 */ 1515 1516 char * 1517 remotename(name, m, flags, pstat, e) 1518 char *name; 1519 struct mailer *m; 1520 int flags; 1521 int *pstat; 1522 register ENVELOPE *e; 1523 { 1524 register char **pvp; 1525 char *fancy; 1526 char *oldg = macvalue('g', e); 1527 int rwset; 1528 static char buf[MAXNAME]; 1529 char lbuf[MAXNAME]; 1530 char pvpbuf[PSBUFSIZE]; 1531 extern char *crackaddr(); 1532 1533 if (tTd(12, 1)) 1534 printf("remotename(%s)\n", name); 1535 1536 /* don't do anything if we are tagging it as special */ 1537 if (bitset(RF_SENDERADDR, flags)) 1538 rwset = bitset(RF_HEADERADDR, flags) ? m->m_sh_rwset 1539 : m->m_se_rwset; 1540 else 1541 rwset = bitset(RF_HEADERADDR, flags) ? m->m_rh_rwset 1542 : m->m_re_rwset; 1543 if (rwset < 0) 1544 return (name); 1545 1546 /* 1547 ** Do a heuristic crack of this name to extract any comment info. 1548 ** This will leave the name as a comment and a $g macro. 1549 */ 1550 1551 if (bitset(RF_CANONICAL, flags) || bitnset(M_NOCOMMENT, m->m_flags)) 1552 fancy = "\201g"; 1553 else 1554 fancy = crackaddr(name); 1555 1556 /* 1557 ** Turn the name into canonical form. 1558 ** Normally this will be RFC 822 style, i.e., "user@domain". 1559 ** If this only resolves to "user", and the "C" flag is 1560 ** specified in the sending mailer, then the sender's 1561 ** domain will be appended. 1562 */ 1563 1564 pvp = prescan(name, '\0', pvpbuf, NULL); 1565 if (pvp == NULL) 1566 return (name); 1567 if (rewrite(pvp, 3, e) == EX_TEMPFAIL) 1568 *pstat = EX_TEMPFAIL; 1569 if (bitset(RF_ADDDOMAIN, flags) && e->e_fromdomain != NULL) 1570 { 1571 /* append from domain to this address */ 1572 register char **pxp = pvp; 1573 1574 /* see if there is an "@domain" in the current name */ 1575 while (*pxp != NULL && strcmp(*pxp, "@") != 0) 1576 pxp++; 1577 if (*pxp == NULL) 1578 { 1579 /* no.... append the "@domain" from the sender */ 1580 register char **qxq = e->e_fromdomain; 1581 1582 while ((*pxp++ = *qxq++) != NULL) 1583 continue; 1584 if (rewrite(pvp, 3, e) == EX_TEMPFAIL) 1585 *pstat = EX_TEMPFAIL; 1586 } 1587 } 1588 1589 /* 1590 ** Do more specific rewriting. 1591 ** Rewrite using ruleset 1 or 2 depending on whether this is 1592 ** a sender address or not. 1593 ** Then run it through any receiving-mailer-specific rulesets. 1594 */ 1595 1596 if (bitset(RF_SENDERADDR, flags)) 1597 { 1598 if (rewrite(pvp, 1, e) == EX_TEMPFAIL) 1599 *pstat = EX_TEMPFAIL; 1600 } 1601 else 1602 { 1603 if (rewrite(pvp, 2, e) == EX_TEMPFAIL) 1604 *pstat = EX_TEMPFAIL; 1605 } 1606 if (rwset > 0) 1607 { 1608 if (rewrite(pvp, rwset, e) == EX_TEMPFAIL) 1609 *pstat = EX_TEMPFAIL; 1610 } 1611 1612 /* 1613 ** Do any final sanitation the address may require. 1614 ** This will normally be used to turn internal forms 1615 ** (e.g., user@host.LOCAL) into external form. This 1616 ** may be used as a default to the above rules. 1617 */ 1618 1619 if (rewrite(pvp, 4, e) == EX_TEMPFAIL) 1620 *pstat = EX_TEMPFAIL; 1621 1622 /* 1623 ** Now restore the comment information we had at the beginning. 1624 */ 1625 1626 cataddr(pvp, NULL, lbuf, sizeof lbuf, '\0'); 1627 define('g', lbuf, e); 1628 expand(fancy, buf, &buf[sizeof buf - 1], e); 1629 define('g', oldg, e); 1630 1631 if (tTd(12, 1)) 1632 printf("remotename => `%s'\n", buf); 1633 return (buf); 1634 } 1635 /* 1636 ** MAPLOCALUSER -- run local username through ruleset 5 for final redirection 1637 ** 1638 ** Parameters: 1639 ** a -- the address to map (but just the user name part). 1640 ** sendq -- the sendq in which to install any replacement 1641 ** addresses. 1642 ** 1643 ** Returns: 1644 ** none. 1645 */ 1646 1647 maplocaluser(a, sendq, e) 1648 register ADDRESS *a; 1649 ADDRESS **sendq; 1650 ENVELOPE *e; 1651 { 1652 register char **pvp; 1653 register ADDRESS *a1 = NULL; 1654 auto char *delimptr; 1655 char pvpbuf[PSBUFSIZE]; 1656 1657 if (tTd(29, 1)) 1658 { 1659 printf("maplocaluser: "); 1660 printaddr(a, FALSE); 1661 } 1662 pvp = prescan(a->q_user, '\0', pvpbuf, &delimptr); 1663 if (pvp == NULL) 1664 return; 1665 1666 (void) rewrite(pvp, 5, e); 1667 if (pvp[0] == NULL || (pvp[0][0] & 0377) != CANONNET) 1668 return; 1669 1670 /* if non-null, mailer destination specified -- has it changed? */ 1671 a1 = buildaddr(pvp, NULL, e); 1672 if (a1 == NULL || sameaddr(a, a1)) 1673 return; 1674 1675 /* mark old address as dead; insert new address */ 1676 a->q_flags |= QDONTSEND; 1677 if (tTd(29, 5)) 1678 { 1679 printf("maplocaluser: QDONTSEND "); 1680 printaddr(a, FALSE); 1681 } 1682 a1->q_alias = a; 1683 allocaddr(a1, 1, NULL, delimptr); 1684 (void) recipient(a1, sendq, e); 1685 } 1686 /* 1687 ** DEQUOTE_INIT -- initialize dequote map 1688 ** 1689 ** This is a no-op. 1690 ** 1691 ** Parameters: 1692 ** map -- the internal map structure. 1693 ** args -- arguments. 1694 ** 1695 ** Returns: 1696 ** TRUE. 1697 */ 1698 1699 bool 1700 dequote_init(map, args) 1701 MAP *map; 1702 char *args; 1703 { 1704 register char *p = args; 1705 1706 for (;;) 1707 { 1708 while (isascii(*p) && isspace(*p)) 1709 p++; 1710 if (*p != '-') 1711 break; 1712 switch (*++p) 1713 { 1714 case 'a': 1715 map->map_app = ++p; 1716 break; 1717 } 1718 while (*p != '\0' && !(isascii(*p) && isspace(*p))) 1719 p++; 1720 if (*p != '\0') 1721 *p = '\0'; 1722 } 1723 if (map->map_app != NULL) 1724 map->map_app = newstr(map->map_app); 1725 1726 return TRUE; 1727 } 1728 /* 1729 ** DEQUOTE_MAP -- unquote an address 1730 ** 1731 ** Parameters: 1732 ** map -- the internal map structure (ignored). 1733 ** name -- the name to dequote. 1734 ** av -- arguments (ignored). 1735 ** statp -- pointer to status out-parameter. 1736 ** 1737 ** Returns: 1738 ** NULL -- if there were no quotes, or if the resulting 1739 ** unquoted buffer would not be acceptable to prescan. 1740 ** else -- The dequoted buffer. 1741 */ 1742 1743 char * 1744 dequote_map(map, name, av, statp) 1745 MAP *map; 1746 char *name; 1747 char **av; 1748 int *statp; 1749 { 1750 register char *p; 1751 register char *q; 1752 register char c; 1753 int anglecnt; 1754 int cmntcnt; 1755 int quotecnt; 1756 int spacecnt; 1757 bool quotemode; 1758 bool bslashmode; 1759 1760 anglecnt = 0; 1761 cmntcnt = 0; 1762 quotecnt = 0; 1763 spacecnt = 0; 1764 quotemode = FALSE; 1765 bslashmode = FALSE; 1766 1767 for (p = q = name; (c = *p++) != '\0'; ) 1768 { 1769 if (bslashmode) 1770 { 1771 bslashmode = FALSE; 1772 *q++ = c; 1773 continue; 1774 } 1775 1776 switch (c) 1777 { 1778 case '\\': 1779 bslashmode = TRUE; 1780 break; 1781 1782 case '(': 1783 cmntcnt++; 1784 break; 1785 1786 case ')': 1787 if (cmntcnt-- <= 0) 1788 return NULL; 1789 break; 1790 1791 case ' ': 1792 spacecnt++; 1793 break; 1794 } 1795 1796 if (cmntcnt > 0) 1797 { 1798 *q++ = c; 1799 continue; 1800 } 1801 1802 switch (c) 1803 { 1804 case '"': 1805 quotemode = !quotemode; 1806 quotecnt++; 1807 continue; 1808 1809 case '<': 1810 anglecnt++; 1811 break; 1812 1813 case '>': 1814 if (anglecnt-- <= 0) 1815 return NULL; 1816 break; 1817 } 1818 *q++ = c; 1819 } 1820 1821 if (anglecnt != 0 || cmntcnt != 0 || bslashmode || 1822 quotemode || quotecnt <= 0 || spacecnt != 0) 1823 return NULL; 1824 *q++ = '\0'; 1825 return name; 1826 } 1827