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.58 (Berkeley) 05/27/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"); 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 register MAILER *m = a->q_mailer; 216 217 if (tTd(24, 4)) 218 printf("allocaddr(copyf=%d, paddr=%s)\n", copyf, paddr); 219 220 if (copyf > 0 && paddr != NULL) 221 { 222 char savec = *delimptr; 223 224 if (savec != '\0') 225 *delimptr = '\0'; 226 a->q_paddr = newstr(paddr); 227 if (savec != '\0') 228 *delimptr = savec; 229 } 230 else 231 a->q_paddr = paddr; 232 233 if (a->q_user == NULL) 234 a->q_user = ""; 235 if (a->q_host == NULL) 236 a->q_host = ""; 237 238 if (copyf >= 0) 239 { 240 a->q_host = newstr(a->q_host); 241 if (a->q_user != a->q_paddr) 242 a->q_user = newstr(a->q_user); 243 } 244 245 if (a->q_paddr == NULL) 246 a->q_paddr = a->q_user; 247 } 248 /* 249 ** PRESCAN -- Prescan name and make it canonical 250 ** 251 ** Scans a name and turns it into a set of tokens. This process 252 ** deletes blanks and comments (in parentheses). 253 ** 254 ** This routine knows about quoted strings and angle brackets. 255 ** 256 ** There are certain subtleties to this routine. The one that 257 ** comes to mind now is that backslashes on the ends of names 258 ** are silently stripped off; this is intentional. The problem 259 ** is that some versions of sndmsg (like at LBL) set the kill 260 ** character to something other than @ when reading addresses; 261 ** so people type "csvax.eric\@berkeley" -- which screws up the 262 ** berknet mailer. 263 ** 264 ** Parameters: 265 ** addr -- the name to chomp. 266 ** delim -- the delimiter for the address, normally 267 ** '\0' or ','; \0 is accepted in any case. 268 ** If '\t' then we are reading the .cf file. 269 ** pvpbuf -- place to put the saved text -- note that 270 ** the pointers are static. 271 ** delimptr -- if non-NULL, set to the location of the 272 ** terminating delimiter. 273 ** 274 ** Returns: 275 ** A pointer to a vector of tokens. 276 ** NULL on error. 277 */ 278 279 /* states and character types */ 280 # define OPR 0 /* operator */ 281 # define ATM 1 /* atom */ 282 # define QST 2 /* in quoted string */ 283 # define SPC 3 /* chewing up spaces */ 284 # define ONE 4 /* pick up one character */ 285 286 # define NSTATES 5 /* number of states */ 287 # define TYPE 017 /* mask to select state type */ 288 289 /* meta bits for table */ 290 # define M 020 /* meta character; don't pass through */ 291 # define B 040 /* cause a break */ 292 # define MB M|B /* meta-break */ 293 294 static short StateTab[NSTATES][NSTATES] = 295 { 296 /* oldst chtype> OPR ATM QST SPC ONE */ 297 /*OPR*/ OPR|B, ATM|B, QST|B, SPC|MB, ONE|B, 298 /*ATM*/ OPR|B, ATM, QST|B, SPC|MB, ONE|B, 299 /*QST*/ QST, QST, OPR, QST, QST, 300 /*SPC*/ OPR, ATM, QST, SPC|M, ONE, 301 /*ONE*/ OPR, OPR, OPR, OPR, OPR, 302 }; 303 304 # define NOCHAR -1 /* signal nothing in lookahead token */ 305 306 char ** 307 prescan(addr, delim, pvpbuf, delimptr) 308 char *addr; 309 char delim; 310 char pvpbuf[]; 311 char **delimptr; 312 { 313 register char *p; 314 register char *q; 315 register int c; 316 char **avp; 317 bool bslashmode; 318 int cmntcnt; 319 int anglecnt; 320 char *tok; 321 int state; 322 int newstate; 323 char *saveto = CurEnv->e_to; 324 static char *av[MAXATOM+1]; 325 extern int errno; 326 327 /* make sure error messages don't have garbage on them */ 328 errno = 0; 329 330 q = pvpbuf; 331 bslashmode = FALSE; 332 cmntcnt = 0; 333 anglecnt = 0; 334 avp = av; 335 state = ATM; 336 c = NOCHAR; 337 p = addr; 338 CurEnv->e_to = p; 339 if (tTd(22, 11)) 340 { 341 printf("prescan: "); 342 xputs(p); 343 (void) putchar('\n'); 344 } 345 346 do 347 { 348 /* read a token */ 349 tok = q; 350 for (;;) 351 { 352 /* store away any old lookahead character */ 353 if (c != NOCHAR && !bslashmode) 354 { 355 /* see if there is room */ 356 if (q >= &pvpbuf[PSBUFSIZE - 5]) 357 { 358 usrerr("553 Address too long"); 359 if (delimptr != NULL) 360 *delimptr = p; 361 CurEnv->e_to = saveto; 362 return (NULL); 363 } 364 365 /* squirrel it away */ 366 *q++ = c; 367 } 368 369 /* read a new input character */ 370 c = *p++; 371 if (c == '\0') 372 { 373 /* diagnose and patch up bad syntax */ 374 if (state == QST) 375 { 376 usrerr("553 Unbalanced '\"'"); 377 c = '"'; 378 } 379 else if (cmntcnt > 0) 380 { 381 usrerr("553 Unbalanced '('"); 382 c = ')'; 383 } 384 else if (anglecnt > 0) 385 { 386 c = '>'; 387 usrerr("553 Unbalanced '<'"); 388 } 389 else 390 break; 391 392 p--; 393 } 394 else if (c == delim && anglecnt <= 0 && 395 cmntcnt <= 0 && state != QST) 396 break; 397 398 if (tTd(22, 101)) 399 printf("c=%c, s=%d; ", c, state); 400 401 /* chew up special characters */ 402 *q = '\0'; 403 if (bslashmode) 404 { 405 bslashmode = FALSE; 406 407 /* kludge \! for naive users */ 408 if (cmntcnt > 0) 409 { 410 c = NOCHAR; 411 continue; 412 } 413 else if (c != '!' || state == QST) 414 { 415 *q++ = '\\'; 416 continue; 417 } 418 } 419 420 if (c == '\\') 421 { 422 bslashmode = TRUE; 423 } 424 else if (state == QST) 425 { 426 /* do nothing, just avoid next clauses */ 427 } 428 else if (c == '(') 429 { 430 cmntcnt++; 431 c = NOCHAR; 432 } 433 else if (c == ')') 434 { 435 if (cmntcnt <= 0) 436 { 437 usrerr("553 Unbalanced ')'"); 438 if (delimptr != NULL) 439 *delimptr = p; 440 CurEnv->e_to = saveto; 441 return (NULL); 442 } 443 else 444 cmntcnt--; 445 } 446 else if (cmntcnt > 0) 447 c = NOCHAR; 448 else if (c == '<') 449 anglecnt++; 450 else if (c == '>') 451 { 452 if (anglecnt <= 0) 453 { 454 usrerr("553 Unbalanced '>'"); 455 if (delimptr != NULL) 456 *delimptr = p; 457 CurEnv->e_to = saveto; 458 return (NULL); 459 } 460 anglecnt--; 461 } 462 else if (delim == ' ' && isascii(c) && isspace(c)) 463 c = ' '; 464 465 if (c == NOCHAR) 466 continue; 467 468 /* see if this is end of input */ 469 if (c == delim && anglecnt <= 0 && state != QST) 470 break; 471 472 newstate = StateTab[state][toktype(c)]; 473 if (tTd(22, 101)) 474 printf("ns=%02o\n", newstate); 475 state = newstate & TYPE; 476 if (bitset(M, newstate)) 477 c = NOCHAR; 478 if (bitset(B, newstate)) 479 break; 480 } 481 482 /* new token */ 483 if (tok != q) 484 { 485 *q++ = '\0'; 486 if (tTd(22, 36)) 487 { 488 printf("tok="); 489 xputs(tok); 490 (void) putchar('\n'); 491 } 492 if (avp >= &av[MAXATOM]) 493 { 494 syserr("553 prescan: too many tokens"); 495 if (delimptr != NULL) 496 *delimptr = p; 497 CurEnv->e_to = saveto; 498 return (NULL); 499 } 500 *avp++ = tok; 501 } 502 } while (c != '\0' && (c != delim || anglecnt > 0)); 503 *avp = NULL; 504 p--; 505 if (delimptr != NULL) 506 *delimptr = p; 507 if (tTd(22, 12)) 508 { 509 printf("prescan==>"); 510 printav(av); 511 } 512 CurEnv->e_to = saveto; 513 if (av[0] == NULL) 514 return (NULL); 515 return (av); 516 } 517 /* 518 ** TOKTYPE -- return token type 519 ** 520 ** Parameters: 521 ** c -- the character in question. 522 ** 523 ** Returns: 524 ** Its type. 525 ** 526 ** Side Effects: 527 ** none. 528 */ 529 530 toktype(c) 531 register int c; 532 { 533 static char buf[50]; 534 static bool firstime = TRUE; 535 536 if (firstime) 537 { 538 firstime = FALSE; 539 expand("\201o", buf, &buf[sizeof buf - 1], CurEnv); 540 (void) strcat(buf, DELIMCHARS); 541 } 542 c &= 0377; 543 if (c == MATCHCLASS || c == MATCHREPL || c == MATCHNCLASS) 544 return (ONE); 545 if (c == MACRODEXPAND) 546 return (ONE); 547 if (c == '"') 548 return (QST); 549 if ((c & 0340) == 0200) 550 return (OPR); 551 if (!isascii(c)) 552 return (ATM); 553 if (isspace(c) || c == ')') 554 return (SPC); 555 if (strchr(buf, c) != NULL) 556 return (OPR); 557 return (ATM); 558 } 559 /* 560 ** REWRITE -- apply rewrite rules to token vector. 561 ** 562 ** This routine is an ordered production system. Each rewrite 563 ** rule has a LHS (called the pattern) and a RHS (called the 564 ** rewrite); 'rwr' points the the current rewrite rule. 565 ** 566 ** For each rewrite rule, 'avp' points the address vector we 567 ** are trying to match against, and 'pvp' points to the pattern. 568 ** If pvp points to a special match value (MATCHZANY, MATCHANY, 569 ** MATCHONE, MATCHCLASS, MATCHNCLASS) then the address in avp 570 ** matched is saved away in the match vector (pointed to by 'mvp'). 571 ** 572 ** When a match between avp & pvp does not match, we try to 573 ** back out. If we back up over MATCHONE, MATCHCLASS, or MATCHNCLASS 574 ** we must also back out the match in mvp. If we reach a 575 ** MATCHANY or MATCHZANY we just extend the match and start 576 ** over again. 577 ** 578 ** When we finally match, we rewrite the address vector 579 ** and try over again. 580 ** 581 ** Parameters: 582 ** pvp -- pointer to token vector. 583 ** ruleset -- the ruleset to use for rewriting. 584 ** e -- the current envelope. 585 ** 586 ** Returns: 587 ** A status code. If EX_TEMPFAIL, higher level code should 588 ** attempt recovery. 589 ** 590 ** Side Effects: 591 ** pvp is modified. 592 */ 593 594 struct match 595 { 596 char **first; /* first token matched */ 597 char **last; /* last token matched */ 598 char **pattern; /* pointer to pattern */ 599 }; 600 601 # define MAXMATCH 9 /* max params per rewrite */ 602 603 604 int 605 rewrite(pvp, ruleset, e) 606 char **pvp; 607 int ruleset; 608 register ENVELOPE *e; 609 { 610 register char *ap; /* address pointer */ 611 register char *rp; /* rewrite pointer */ 612 register char **avp; /* address vector pointer */ 613 register char **rvp; /* rewrite vector pointer */ 614 register struct match *mlp; /* cur ptr into mlist */ 615 register struct rewrite *rwr; /* pointer to current rewrite rule */ 616 int ruleno; /* current rule number */ 617 int rstat = EX_OK; /* return status */ 618 struct match mlist[MAXMATCH]; /* stores match on LHS */ 619 char *npvp[MAXATOM+1]; /* temporary space for rebuild */ 620 621 if (OpMode == MD_TEST || tTd(21, 2)) 622 { 623 printf("rewrite: ruleset %2d input:", ruleset); 624 printav(pvp); 625 } 626 if (ruleset < 0 || ruleset >= MAXRWSETS) 627 { 628 syserr("554 rewrite: illegal ruleset number %d", ruleset); 629 return EX_CONFIG; 630 } 631 if (pvp == NULL) 632 return EX_USAGE; 633 634 /* 635 ** Run through the list of rewrite rules, applying 636 ** any that match. 637 */ 638 639 ruleno = 1; 640 for (rwr = RewriteRules[ruleset]; rwr != NULL; ) 641 { 642 int loopcount = 0; 643 644 if (tTd(21, 12)) 645 { 646 printf("-----trying rule:"); 647 printav(rwr->r_lhs); 648 } 649 650 /* try to match on this rule */ 651 mlp = mlist; 652 rvp = rwr->r_lhs; 653 avp = pvp; 654 if (++loopcount > 100) 655 { 656 syserr("554 Infinite loop in ruleset %d, rule %d", 657 ruleset, ruleno); 658 if (tTd(21, 1)) 659 { 660 printf("workspace: "); 661 printav(pvp); 662 } 663 break; 664 } 665 666 while ((ap = *avp) != NULL || *rvp != NULL) 667 { 668 rp = *rvp; 669 if (tTd(21, 35)) 670 { 671 printf("ADVANCE rp="); 672 xputs(rp); 673 printf(", ap="); 674 xputs(ap); 675 printf("\n"); 676 } 677 if (rp == NULL) 678 { 679 /* end-of-pattern before end-of-address */ 680 goto backup; 681 } 682 if (ap == NULL && (*rp & 0377) != MATCHZANY && 683 (*rp & 0377) != MATCHZERO) 684 { 685 /* end-of-input with patterns left */ 686 goto backup; 687 } 688 689 switch (*rp & 0377) 690 { 691 register STAB *s; 692 char buf[MAXLINE]; 693 694 case MATCHCLASS: 695 /* match any phrase in a class */ 696 mlp->pattern = rvp; 697 mlp->first = avp; 698 extendclass: 699 ap = *avp; 700 if (ap == NULL) 701 goto backup; 702 mlp->last = avp++; 703 cataddr(mlp->first, mlp->last, buf, sizeof buf, '\0'); 704 s = stab(buf, ST_CLASS, ST_FIND); 705 if (s == NULL || !bitnset(rp[1], s->s_class)) 706 { 707 if (tTd(21, 36)) 708 { 709 printf("EXTEND rp="); 710 xputs(rp); 711 printf(", ap="); 712 xputs(ap); 713 printf("\n"); 714 } 715 goto extendclass; 716 } 717 if (tTd(21, 36)) 718 printf("CLMATCH\n"); 719 mlp++; 720 break; 721 722 case MATCHNCLASS: 723 /* match any token not in a class */ 724 s = stab(ap, ST_CLASS, ST_FIND); 725 if (s != NULL && bitnset(rp[1], s->s_class)) 726 goto backup; 727 728 /* fall through */ 729 730 case MATCHONE: 731 case MATCHANY: 732 /* match exactly one token */ 733 mlp->pattern = rvp; 734 mlp->first = avp; 735 mlp->last = avp++; 736 mlp++; 737 break; 738 739 case MATCHZANY: 740 /* match zero or more tokens */ 741 mlp->pattern = rvp; 742 mlp->first = avp; 743 mlp->last = avp - 1; 744 mlp++; 745 break; 746 747 case MATCHZERO: 748 /* match zero tokens */ 749 break; 750 751 case MACRODEXPAND: 752 /* 753 ** Match against run-time macro. 754 ** This algorithm is broken for the 755 ** general case (no recursive macros, 756 ** improper tokenization) but should 757 ** work for the usual cases. 758 */ 759 760 ap = macvalue(rp[1], e); 761 mlp->first = avp; 762 if (tTd(21, 2)) 763 printf("rewrite: LHS $&%c => \"%s\"\n", 764 rp[1], 765 ap == NULL ? "(NULL)" : ap); 766 767 if (ap == NULL) 768 break; 769 while (*ap != '\0') 770 { 771 if (*avp == NULL || 772 strncasecmp(ap, *avp, strlen(*avp)) != 0) 773 { 774 /* no match */ 775 avp = mlp->first; 776 goto backup; 777 } 778 ap += strlen(*avp++); 779 } 780 781 /* match */ 782 break; 783 784 default: 785 /* must have exact match */ 786 if (strcasecmp(rp, ap)) 787 goto backup; 788 avp++; 789 break; 790 } 791 792 /* successful match on this token */ 793 rvp++; 794 continue; 795 796 backup: 797 /* match failed -- back up */ 798 while (--mlp >= mlist) 799 { 800 rvp = mlp->pattern; 801 rp = *rvp; 802 avp = mlp->last + 1; 803 ap = *avp; 804 805 if (tTd(21, 36)) 806 { 807 printf("BACKUP rp="); 808 xputs(rp); 809 printf(", ap="); 810 xputs(ap); 811 printf("\n"); 812 } 813 814 if (ap == NULL) 815 { 816 /* run off the end -- back up again */ 817 continue; 818 } 819 if ((*rp & 0377) == MATCHANY || 820 (*rp & 0377) == MATCHZANY) 821 { 822 /* extend binding and continue */ 823 mlp->last = avp++; 824 rvp++; 825 mlp++; 826 break; 827 } 828 if ((*rp & 0377) == MATCHCLASS) 829 { 830 /* extend binding and try again */ 831 mlp->last = avp++; 832 goto extendclass; 833 } 834 } 835 836 if (mlp < mlist) 837 { 838 /* total failure to match */ 839 break; 840 } 841 } 842 843 /* 844 ** See if we successfully matched 845 */ 846 847 if (mlp < mlist || *rvp != NULL) 848 { 849 if (tTd(21, 10)) 850 printf("----- rule fails\n"); 851 rwr = rwr->r_next; 852 ruleno++; 853 continue; 854 } 855 856 rvp = rwr->r_rhs; 857 if (tTd(21, 12)) 858 { 859 printf("-----rule matches:"); 860 printav(rvp); 861 } 862 863 rp = *rvp; 864 if ((*rp & 0377) == CANONUSER) 865 { 866 rvp++; 867 rwr = rwr->r_next; 868 ruleno++; 869 } 870 else if ((*rp & 0377) == CANONHOST) 871 { 872 rvp++; 873 rwr = NULL; 874 } 875 else if ((*rp & 0377) == CANONNET) 876 rwr = NULL; 877 878 /* substitute */ 879 for (avp = npvp; *rvp != NULL; rvp++) 880 { 881 register struct match *m; 882 register char **pp; 883 884 rp = *rvp; 885 if ((*rp & 0377) == MATCHREPL) 886 { 887 /* substitute from LHS */ 888 m = &mlist[rp[1] - '1']; 889 if (m < mlist || m >= mlp) 890 { 891 syserr("554 rewrite: ruleset %d: replacement $%c out of bounds", 892 ruleset, rp[1]); 893 return EX_CONFIG; 894 } 895 if (tTd(21, 15)) 896 { 897 printf("$%c:", rp[1]); 898 pp = m->first; 899 while (pp <= m->last) 900 { 901 printf(" %x=\"", *pp); 902 (void) fflush(stdout); 903 printf("%s\"", *pp++); 904 } 905 printf("\n"); 906 } 907 pp = m->first; 908 while (pp <= m->last) 909 { 910 if (avp >= &npvp[MAXATOM]) 911 { 912 syserr("554 rewrite: expansion too long"); 913 return EX_DATAERR; 914 } 915 *avp++ = *pp++; 916 } 917 } 918 else 919 { 920 /* vanilla replacement */ 921 if (avp >= &npvp[MAXATOM]) 922 { 923 toolong: 924 syserr("554 rewrite: expansion too long"); 925 return EX_DATAERR; 926 } 927 if ((*rp & 0377) != MACRODEXPAND) 928 *avp++ = rp; 929 else 930 { 931 *avp = macvalue(rp[1], e); 932 if (tTd(21, 2)) 933 printf("rewrite: RHS $&%c => \"%s\"\n", 934 rp[1], 935 *avp == NULL ? "(NULL)" : *avp); 936 if (*avp != NULL) 937 avp++; 938 } 939 } 940 } 941 *avp++ = NULL; 942 943 /* 944 ** Check for any hostname/keyword lookups. 945 */ 946 947 for (rvp = npvp; *rvp != NULL; rvp++) 948 { 949 char **hbrvp; 950 char **xpvp; 951 int trsize; 952 char *olddelimchar; 953 char *replac; 954 int endtoken; 955 STAB *map; 956 char *mapname; 957 char **key_rvp; 958 char **arg_rvp; 959 char **default_rvp; 960 char buf[MAXNAME + 1]; 961 char *pvpb1[MAXATOM + 1]; 962 char *argvect[10]; 963 char pvpbuf[PSBUFSIZE]; 964 965 if ((**rvp & 0377) != HOSTBEGIN && 966 (**rvp & 0377) != LOOKUPBEGIN) 967 continue; 968 969 /* 970 ** Got a hostname/keyword lookup. 971 ** 972 ** This could be optimized fairly easily. 973 */ 974 975 hbrvp = rvp; 976 if ((**rvp & 0377) == HOSTBEGIN) 977 { 978 endtoken = HOSTEND; 979 mapname = "host"; 980 } 981 else 982 { 983 endtoken = LOOKUPEND; 984 mapname = *++rvp; 985 } 986 map = stab(mapname, ST_MAP, ST_FIND); 987 if (map == NULL) 988 syserr("554 rewrite: map %s not found", mapname); 989 990 /* extract the match part */ 991 key_rvp = ++rvp; 992 default_rvp = NULL; 993 arg_rvp = argvect; 994 xpvp = NULL; 995 replac = pvpbuf; 996 while (*rvp != NULL && (**rvp & 0377) != endtoken) 997 { 998 int nodetype = **rvp & 0377; 999 1000 if (nodetype != CANONHOST && nodetype != CANONUSER) 1001 { 1002 rvp++; 1003 continue; 1004 } 1005 1006 *rvp++ = NULL; 1007 1008 if (xpvp != NULL) 1009 { 1010 cataddr(xpvp, NULL, replac, 1011 &pvpbuf[sizeof pvpbuf] - replac, 1012 '\0'); 1013 *++arg_rvp = replac; 1014 replac += strlen(replac) + 1; 1015 xpvp = NULL; 1016 } 1017 switch (nodetype) 1018 { 1019 case CANONHOST: 1020 xpvp = rvp; 1021 break; 1022 1023 case CANONUSER: 1024 default_rvp = rvp; 1025 break; 1026 } 1027 } 1028 if (*rvp != NULL) 1029 *rvp++ = NULL; 1030 if (xpvp != NULL) 1031 { 1032 cataddr(xpvp, NULL, replac, 1033 &pvpbuf[sizeof pvpbuf] - replac, 1034 '\0'); 1035 *++arg_rvp = replac; 1036 } 1037 *++arg_rvp = NULL; 1038 1039 /* save the remainder of the input string */ 1040 trsize = (int) (avp - rvp + 1) * sizeof *rvp; 1041 bcopy((char *) rvp, (char *) pvpb1, trsize); 1042 1043 /* look it up */ 1044 cataddr(key_rvp, NULL, buf, sizeof buf, '\0'); 1045 argvect[0] = buf; 1046 if (map != NULL && bitset(MF_VALID, map->s_map.map_mflags)) 1047 { 1048 auto int stat = EX_OK; 1049 1050 /* XXX should try to auto-open the map here */ 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 char *oldg = macvalue('g', e); 1531 int rwset; 1532 static char buf[MAXNAME]; 1533 char lbuf[MAXNAME]; 1534 char pvpbuf[PSBUFSIZE]; 1535 extern char *crackaddr(); 1536 1537 if (tTd(12, 1)) 1538 printf("remotename(%s)\n", name); 1539 1540 /* don't do anything if we are tagging it as special */ 1541 if (bitset(RF_SENDERADDR, flags)) 1542 rwset = bitset(RF_HEADERADDR, flags) ? m->m_sh_rwset 1543 : m->m_se_rwset; 1544 else 1545 rwset = bitset(RF_HEADERADDR, flags) ? m->m_rh_rwset 1546 : m->m_re_rwset; 1547 if (rwset < 0) 1548 return (name); 1549 1550 /* 1551 ** Do a heuristic crack of this name to extract any comment info. 1552 ** This will leave the name as a comment and a $g macro. 1553 */ 1554 1555 if (bitset(RF_CANONICAL, flags) || bitnset(M_NOCOMMENT, m->m_flags)) 1556 fancy = "\201g"; 1557 else 1558 fancy = crackaddr(name); 1559 1560 /* 1561 ** Turn the name into canonical form. 1562 ** Normally this will be RFC 822 style, i.e., "user@domain". 1563 ** If this only resolves to "user", and the "C" flag is 1564 ** specified in the sending mailer, then the sender's 1565 ** domain will be appended. 1566 */ 1567 1568 pvp = prescan(name, '\0', pvpbuf, NULL); 1569 if (pvp == NULL) 1570 return (name); 1571 if (rewrite(pvp, 3, e) == EX_TEMPFAIL) 1572 *pstat = EX_TEMPFAIL; 1573 if (bitset(RF_ADDDOMAIN, flags) && e->e_fromdomain != NULL) 1574 { 1575 /* append from domain to this address */ 1576 register char **pxp = pvp; 1577 1578 /* see if there is an "@domain" in the current name */ 1579 while (*pxp != NULL && strcmp(*pxp, "@") != 0) 1580 pxp++; 1581 if (*pxp == NULL) 1582 { 1583 /* no.... append the "@domain" from the sender */ 1584 register char **qxq = e->e_fromdomain; 1585 1586 while ((*pxp++ = *qxq++) != NULL) 1587 continue; 1588 if (rewrite(pvp, 3, e) == EX_TEMPFAIL) 1589 *pstat = EX_TEMPFAIL; 1590 } 1591 } 1592 1593 /* 1594 ** Do more specific rewriting. 1595 ** Rewrite using ruleset 1 or 2 depending on whether this is 1596 ** a sender address or not. 1597 ** Then run it through any receiving-mailer-specific rulesets. 1598 */ 1599 1600 if (bitset(RF_SENDERADDR, flags)) 1601 { 1602 if (rewrite(pvp, 1, e) == EX_TEMPFAIL) 1603 *pstat = EX_TEMPFAIL; 1604 } 1605 else 1606 { 1607 if (rewrite(pvp, 2, e) == EX_TEMPFAIL) 1608 *pstat = EX_TEMPFAIL; 1609 } 1610 if (rwset > 0) 1611 { 1612 if (rewrite(pvp, rwset, e) == EX_TEMPFAIL) 1613 *pstat = EX_TEMPFAIL; 1614 } 1615 1616 /* 1617 ** Do any final sanitation the address may require. 1618 ** This will normally be used to turn internal forms 1619 ** (e.g., user@host.LOCAL) into external form. This 1620 ** may be used as a default to the above rules. 1621 */ 1622 1623 if (rewrite(pvp, 4, e) == EX_TEMPFAIL) 1624 *pstat = EX_TEMPFAIL; 1625 1626 /* 1627 ** Now restore the comment information we had at the beginning. 1628 */ 1629 1630 cataddr(pvp, NULL, lbuf, sizeof lbuf, '\0'); 1631 define('g', lbuf, e); 1632 expand(fancy, buf, &buf[sizeof buf - 1], e); 1633 define('g', oldg, e); 1634 1635 if (tTd(12, 1)) 1636 printf("remotename => `%s'\n", buf); 1637 return (buf); 1638 } 1639 /* 1640 ** MAPLOCALUSER -- run local username through ruleset 5 for final redirection 1641 ** 1642 ** Parameters: 1643 ** a -- the address to map (but just the user name part). 1644 ** sendq -- the sendq in which to install any replacement 1645 ** addresses. 1646 ** 1647 ** Returns: 1648 ** none. 1649 */ 1650 1651 maplocaluser(a, sendq, e) 1652 register ADDRESS *a; 1653 ADDRESS **sendq; 1654 ENVELOPE *e; 1655 { 1656 register char **pvp; 1657 register ADDRESS *a1 = NULL; 1658 auto char *delimptr; 1659 char pvpbuf[PSBUFSIZE]; 1660 1661 if (tTd(29, 1)) 1662 { 1663 printf("maplocaluser: "); 1664 printaddr(a, FALSE); 1665 } 1666 pvp = prescan(a->q_user, '\0', pvpbuf, &delimptr); 1667 if (pvp == NULL) 1668 return; 1669 1670 (void) rewrite(pvp, 5, e); 1671 if (pvp[0] == NULL || (pvp[0][0] & 0377) != CANONNET) 1672 return; 1673 1674 /* if non-null, mailer destination specified -- has it changed? */ 1675 a1 = buildaddr(pvp, NULL, e); 1676 if (a1 == NULL || sameaddr(a, a1)) 1677 return; 1678 1679 /* mark old address as dead; insert new address */ 1680 a->q_flags |= QDONTSEND; 1681 if (tTd(29, 5)) 1682 { 1683 printf("maplocaluser: QDONTSEND "); 1684 printaddr(a, FALSE); 1685 } 1686 a1->q_alias = a; 1687 allocaddr(a1, 1, NULL, delimptr); 1688 (void) recipient(a1, sendq, e); 1689 } 1690 /* 1691 ** DEQUOTE_INIT -- initialize dequote map 1692 ** 1693 ** This is a no-op. 1694 ** 1695 ** Parameters: 1696 ** map -- the internal map structure. 1697 ** args -- arguments. 1698 ** 1699 ** Returns: 1700 ** TRUE. 1701 */ 1702 1703 bool 1704 dequote_init(map, args) 1705 MAP *map; 1706 char *args; 1707 { 1708 register char *p = args; 1709 1710 for (;;) 1711 { 1712 while (isascii(*p) && isspace(*p)) 1713 p++; 1714 if (*p != '-') 1715 break; 1716 switch (*++p) 1717 { 1718 case 'a': 1719 map->map_app = ++p; 1720 break; 1721 } 1722 while (*p != '\0' && !(isascii(*p) && isspace(*p))) 1723 p++; 1724 if (*p != '\0') 1725 *p = '\0'; 1726 } 1727 if (map->map_app != NULL) 1728 map->map_app = newstr(map->map_app); 1729 1730 return TRUE; 1731 } 1732 /* 1733 ** DEQUOTE_MAP -- unquote an address 1734 ** 1735 ** Parameters: 1736 ** map -- the internal map structure (ignored). 1737 ** name -- the name to dequote. 1738 ** av -- arguments (ignored). 1739 ** statp -- pointer to status out-parameter. 1740 ** 1741 ** Returns: 1742 ** NULL -- if there were no quotes, or if the resulting 1743 ** unquoted buffer would not be acceptable to prescan. 1744 ** else -- The dequoted buffer. 1745 */ 1746 1747 char * 1748 dequote_map(map, name, av, statp) 1749 MAP *map; 1750 char *name; 1751 char **av; 1752 int *statp; 1753 { 1754 register char *p; 1755 register char *q; 1756 register char c; 1757 int anglecnt; 1758 int cmntcnt; 1759 int quotecnt; 1760 int spacecnt; 1761 bool quotemode; 1762 bool bslashmode; 1763 1764 anglecnt = 0; 1765 cmntcnt = 0; 1766 quotecnt = 0; 1767 spacecnt = 0; 1768 quotemode = FALSE; 1769 bslashmode = FALSE; 1770 1771 for (p = q = name; (c = *p++) != '\0'; ) 1772 { 1773 if (bslashmode) 1774 { 1775 bslashmode = FALSE; 1776 *q++ = c; 1777 continue; 1778 } 1779 1780 switch (c) 1781 { 1782 case '\\': 1783 bslashmode = TRUE; 1784 break; 1785 1786 case '(': 1787 cmntcnt++; 1788 break; 1789 1790 case ')': 1791 if (cmntcnt-- <= 0) 1792 return NULL; 1793 break; 1794 1795 case ' ': 1796 spacecnt++; 1797 break; 1798 } 1799 1800 if (cmntcnt > 0) 1801 { 1802 *q++ = c; 1803 continue; 1804 } 1805 1806 switch (c) 1807 { 1808 case '"': 1809 quotemode = !quotemode; 1810 quotecnt++; 1811 continue; 1812 1813 case '<': 1814 anglecnt++; 1815 break; 1816 1817 case '>': 1818 if (anglecnt-- <= 0) 1819 return NULL; 1820 break; 1821 } 1822 *q++ = c; 1823 } 1824 1825 if (anglecnt != 0 || cmntcnt != 0 || bslashmode || 1826 quotemode || quotecnt <= 0 || spacecnt != 0) 1827 return NULL; 1828 *q++ = '\0'; 1829 return name; 1830 } 1831