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.45 (Berkeley) 04/26/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 char 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 a->q_flags |= QQUEUEUP; 145 146 /* 147 ** Compute return value. 148 */ 149 150 if (tTd(20, 1)) 151 { 152 printf("parseaddr-->"); 153 printaddr(a, FALSE); 154 } 155 156 return (a); 157 } 158 /* 159 ** INVALIDADDR -- check for address containing meta-characters 160 ** 161 ** Parameters: 162 ** addr -- the address to check. 163 ** 164 ** Returns: 165 ** TRUE -- if the address has any "wierd" characters 166 ** FALSE -- otherwise. 167 */ 168 169 bool 170 invalidaddr(addr) 171 register char *addr; 172 { 173 for (; *addr != '\0'; addr++) 174 { 175 if ((*addr & 0340) != 0200) 176 continue; 177 setstat(EX_USAGE); 178 usrerr("553 Address contained invalid control characters"); 179 return TRUE; 180 } 181 return FALSE; 182 } 183 /* 184 ** ALLOCADDR -- do local allocations of address on demand. 185 ** 186 ** Also lowercases the host name if requested. 187 ** 188 ** Parameters: 189 ** a -- the address to reallocate. 190 ** copyf -- the copy flag (see parseaddr for description). 191 ** paddr -- the printname of the address. 192 ** delimptr -- a pointer to the address delimiter. Must be set. 193 ** 194 ** Returns: 195 ** none. 196 ** 197 ** Side Effects: 198 ** Copies portions of a into local buffers as requested. 199 */ 200 201 allocaddr(a, copyf, paddr, delimptr) 202 register ADDRESS *a; 203 int copyf; 204 char *paddr; 205 char *delimptr; 206 { 207 register MAILER *m = a->q_mailer; 208 209 if (tTd(24, 4)) 210 printf("allocaddr(copyf=%d, paddr=%s)\n", copyf, paddr); 211 212 if (copyf > 0 && paddr != NULL) 213 { 214 char savec = *delimptr; 215 216 *delimptr = '\0'; 217 a->q_paddr = newstr(paddr); 218 *delimptr = savec; 219 } 220 else 221 a->q_paddr = paddr; 222 223 if (a->q_user == NULL) 224 a->q_user = ""; 225 if (a->q_host == NULL) 226 a->q_host = ""; 227 228 if (copyf >= 0) 229 { 230 a->q_host = newstr(a->q_host); 231 if (a->q_user != a->q_paddr) 232 a->q_user = newstr(a->q_user); 233 } 234 235 if (a->q_paddr == NULL) 236 a->q_paddr = a->q_user; 237 } 238 /* 239 ** PRESCAN -- Prescan name and make it canonical 240 ** 241 ** Scans a name and turns it into a set of tokens. This process 242 ** deletes blanks and comments (in parentheses). 243 ** 244 ** This routine knows about quoted strings and angle brackets. 245 ** 246 ** There are certain subtleties to this routine. The one that 247 ** comes to mind now is that backslashes on the ends of names 248 ** are silently stripped off; this is intentional. The problem 249 ** is that some versions of sndmsg (like at LBL) set the kill 250 ** character to something other than @ when reading addresses; 251 ** so people type "csvax.eric\@berkeley" -- which screws up the 252 ** berknet mailer. 253 ** 254 ** Parameters: 255 ** addr -- the name to chomp. 256 ** delim -- the delimiter for the address, normally 257 ** '\0' or ','; \0 is accepted in any case. 258 ** If '\t' then we are reading the .cf file. 259 ** pvpbuf -- place to put the saved text -- note that 260 ** the pointers are static. 261 ** delimptr -- if non-NULL, set to the location of the 262 ** terminating delimiter. 263 ** 264 ** Returns: 265 ** A pointer to a vector of tokens. 266 ** NULL on error. 267 */ 268 269 /* states and character types */ 270 # define OPR 0 /* operator */ 271 # define ATM 1 /* atom */ 272 # define QST 2 /* in quoted string */ 273 # define SPC 3 /* chewing up spaces */ 274 # define ONE 4 /* pick up one character */ 275 276 # define NSTATES 5 /* number of states */ 277 # define TYPE 017 /* mask to select state type */ 278 279 /* meta bits for table */ 280 # define M 020 /* meta character; don't pass through */ 281 # define B 040 /* cause a break */ 282 # define MB M|B /* meta-break */ 283 284 static short StateTab[NSTATES][NSTATES] = 285 { 286 /* oldst chtype> OPR ATM QST SPC ONE */ 287 /*OPR*/ OPR|B, ATM|B, QST|B, SPC|MB, ONE|B, 288 /*ATM*/ OPR|B, ATM, QST|B, SPC|MB, ONE|B, 289 /*QST*/ QST, QST, OPR, QST, QST, 290 /*SPC*/ OPR, ATM, QST, SPC|M, ONE, 291 /*ONE*/ OPR, OPR, OPR, OPR, OPR, 292 }; 293 294 # define NOCHAR -1 /* signal nothing in lookahead token */ 295 296 char ** 297 prescan(addr, delim, pvpbuf, delimptr) 298 char *addr; 299 char delim; 300 char pvpbuf[]; 301 char **delimptr; 302 { 303 register char *p; 304 register char *q; 305 register int c; 306 char **avp; 307 bool bslashmode; 308 int cmntcnt; 309 int anglecnt; 310 char *tok; 311 int state; 312 int newstate; 313 static char *av[MAXATOM+1]; 314 extern int errno; 315 316 /* make sure error messages don't have garbage on them */ 317 errno = 0; 318 319 q = pvpbuf; 320 bslashmode = FALSE; 321 cmntcnt = 0; 322 anglecnt = 0; 323 avp = av; 324 state = ATM; 325 c = NOCHAR; 326 p = addr; 327 if (tTd(22, 11)) 328 { 329 printf("prescan: "); 330 xputs(p); 331 (void) putchar('\n'); 332 } 333 334 do 335 { 336 /* read a token */ 337 tok = q; 338 for (;;) 339 { 340 /* store away any old lookahead character */ 341 if (c != NOCHAR && !bslashmode) 342 { 343 /* see if there is room */ 344 if (q >= &pvpbuf[PSBUFSIZE - 5]) 345 { 346 usrerr("553 Address too long"); 347 if (delimptr != NULL) 348 *delimptr = p; 349 return (NULL); 350 } 351 352 /* squirrel it away */ 353 *q++ = c; 354 } 355 356 /* read a new input character */ 357 c = *p++; 358 if (c == '\0') 359 { 360 /* diagnose and patch up bad syntax */ 361 if (state == QST) 362 { 363 usrerr("553 Unbalanced '\"'"); 364 c = '"'; 365 } 366 else if (cmntcnt > 0) 367 { 368 usrerr("553 Unbalanced '('"); 369 c = ')'; 370 } 371 else if (anglecnt > 0) 372 { 373 c = '>'; 374 usrerr("553 Unbalanced '<'"); 375 } 376 else 377 break; 378 379 p--; 380 } 381 else if (c == delim && anglecnt <= 0 && 382 cmntcnt <= 0 && state != QST) 383 break; 384 385 if (tTd(22, 101)) 386 printf("c=%c, s=%d; ", c, state); 387 388 /* chew up special characters */ 389 *q = '\0'; 390 if (bslashmode) 391 { 392 bslashmode = FALSE; 393 394 /* kludge \! for naive users */ 395 if (cmntcnt > 0) 396 { 397 c = NOCHAR; 398 continue; 399 } 400 else if (c != '!' || state == QST) 401 { 402 *q++ = '\\'; 403 continue; 404 } 405 } 406 407 if (c == '\\') 408 { 409 bslashmode = TRUE; 410 } 411 else if (state == QST) 412 { 413 /* do nothing, just avoid next clauses */ 414 } 415 else if (c == '(') 416 { 417 cmntcnt++; 418 c = NOCHAR; 419 } 420 else if (c == ')') 421 { 422 if (cmntcnt <= 0) 423 { 424 usrerr("553 Unbalanced ')'"); 425 if (delimptr != NULL) 426 *delimptr = p; 427 return (NULL); 428 } 429 else 430 cmntcnt--; 431 } 432 else if (cmntcnt > 0) 433 c = NOCHAR; 434 else if (c == '<') 435 anglecnt++; 436 else if (c == '>') 437 { 438 if (anglecnt <= 0) 439 { 440 usrerr("553 Unbalanced '>'"); 441 if (delimptr != NULL) 442 *delimptr = p; 443 return (NULL); 444 } 445 anglecnt--; 446 } 447 else if (delim == ' ' && isascii(c) && isspace(c)) 448 c = ' '; 449 450 if (c == NOCHAR) 451 continue; 452 453 /* see if this is end of input */ 454 if (c == delim && anglecnt <= 0 && state != QST) 455 break; 456 457 newstate = StateTab[state][toktype(c)]; 458 if (tTd(22, 101)) 459 printf("ns=%02o\n", newstate); 460 state = newstate & TYPE; 461 if (bitset(M, newstate)) 462 c = NOCHAR; 463 if (bitset(B, newstate)) 464 break; 465 } 466 467 /* new token */ 468 if (tok != q) 469 { 470 *q++ = '\0'; 471 if (tTd(22, 36)) 472 { 473 printf("tok="); 474 xputs(tok); 475 (void) putchar('\n'); 476 } 477 if (avp >= &av[MAXATOM]) 478 { 479 syserr("553 prescan: too many tokens"); 480 if (delimptr != NULL) 481 *delimptr = p; 482 return (NULL); 483 } 484 *avp++ = tok; 485 } 486 } while (c != '\0' && (c != delim || anglecnt > 0)); 487 *avp = NULL; 488 p--; 489 if (delimptr != NULL) 490 *delimptr = p; 491 if (tTd(22, 12)) 492 { 493 printf("prescan==>"); 494 printav(av); 495 } 496 if (av[0] == NULL) 497 return (NULL); 498 return (av); 499 } 500 /* 501 ** TOKTYPE -- return token type 502 ** 503 ** Parameters: 504 ** c -- the character in question. 505 ** 506 ** Returns: 507 ** Its type. 508 ** 509 ** Side Effects: 510 ** none. 511 */ 512 513 toktype(c) 514 register int c; 515 { 516 static char buf[50]; 517 static bool firstime = TRUE; 518 519 if (firstime) 520 { 521 firstime = FALSE; 522 expand("\201o", buf, &buf[sizeof buf - 1], CurEnv); 523 (void) strcat(buf, DELIMCHARS); 524 } 525 c &= 0377; 526 if (c == MATCHCLASS || c == MATCHREPL || c == MATCHNCLASS) 527 return (ONE); 528 if (c == MACRODEXPAND) 529 return (ONE); 530 if (c == '"') 531 return (QST); 532 if ((c & 0340) == 0200) 533 return (OPR); 534 if (!isascii(c)) 535 return (ATM); 536 if (isspace(c) || c == ')') 537 return (SPC); 538 if (strchr(buf, c) != NULL) 539 return (OPR); 540 return (ATM); 541 } 542 /* 543 ** REWRITE -- apply rewrite rules to token vector. 544 ** 545 ** This routine is an ordered production system. Each rewrite 546 ** rule has a LHS (called the pattern) and a RHS (called the 547 ** rewrite); 'rwr' points the the current rewrite rule. 548 ** 549 ** For each rewrite rule, 'avp' points the address vector we 550 ** are trying to match against, and 'pvp' points to the pattern. 551 ** If pvp points to a special match value (MATCHZANY, MATCHANY, 552 ** MATCHONE, MATCHCLASS, MATCHNCLASS) then the address in avp 553 ** matched is saved away in the match vector (pointed to by 'mvp'). 554 ** 555 ** When a match between avp & pvp does not match, we try to 556 ** back out. If we back up over MATCHONE, MATCHCLASS, or MATCHNCLASS 557 ** we must also back out the match in mvp. If we reach a 558 ** MATCHANY or MATCHZANY we just extend the match and start 559 ** over again. 560 ** 561 ** When we finally match, we rewrite the address vector 562 ** and try over again. 563 ** 564 ** Parameters: 565 ** pvp -- pointer to token vector. 566 ** ruleset -- the ruleset to use for rewriting. 567 ** e -- the current envelope. 568 ** 569 ** Returns: 570 ** A status code. If EX_TEMPFAIL, higher level code should 571 ** attempt recovery. 572 ** 573 ** Side Effects: 574 ** pvp is modified. 575 */ 576 577 struct match 578 { 579 char **first; /* first token matched */ 580 char **last; /* last token matched */ 581 char **pattern; /* pointer to pattern */ 582 }; 583 584 # define MAXMATCH 9 /* max params per rewrite */ 585 586 587 int 588 rewrite(pvp, ruleset, e) 589 char **pvp; 590 int ruleset; 591 register ENVELOPE *e; 592 { 593 register char *ap; /* address pointer */ 594 register char *rp; /* rewrite pointer */ 595 register char **avp; /* address vector pointer */ 596 register char **rvp; /* rewrite vector pointer */ 597 register struct match *mlp; /* cur ptr into mlist */ 598 register struct rewrite *rwr; /* pointer to current rewrite rule */ 599 int ruleno; /* current rule number */ 600 int rstat = EX_OK; /* return status */ 601 struct match mlist[MAXMATCH]; /* stores match on LHS */ 602 char *npvp[MAXATOM+1]; /* temporary space for rebuild */ 603 extern char *macvalue(); 604 605 if (OpMode == MD_TEST || tTd(21, 2)) 606 { 607 printf("rewrite: ruleset %2d input:", ruleset); 608 printav(pvp); 609 } 610 if (ruleset < 0 || ruleset >= MAXRWSETS) 611 { 612 syserr("554 rewrite: illegal ruleset number %d", ruleset); 613 return EX_CONFIG; 614 } 615 if (pvp == NULL) 616 return EX_USAGE; 617 618 /* 619 ** Run through the list of rewrite rules, applying 620 ** any that match. 621 */ 622 623 ruleno = 1; 624 for (rwr = RewriteRules[ruleset]; rwr != NULL; ) 625 { 626 int loopcount = 0; 627 628 if (tTd(21, 12)) 629 { 630 printf("-----trying rule:"); 631 printav(rwr->r_lhs); 632 } 633 634 /* try to match on this rule */ 635 mlp = mlist; 636 rvp = rwr->r_lhs; 637 avp = pvp; 638 if (++loopcount > 100) 639 { 640 syserr("554 Infinite loop in ruleset %d, rule %d", 641 ruleset, ruleno); 642 if (tTd(21, 1)) 643 { 644 printf("workspace: "); 645 printav(pvp); 646 } 647 break; 648 } 649 650 while ((ap = *avp) != NULL || *rvp != NULL) 651 { 652 rp = *rvp; 653 if (tTd(21, 35)) 654 { 655 printf("ADVANCE rp="); 656 xputs(rp); 657 printf(", ap="); 658 xputs(ap); 659 printf("\n"); 660 } 661 if (rp == NULL) 662 { 663 /* end-of-pattern before end-of-address */ 664 goto backup; 665 } 666 if (ap == NULL && (*rp & 0377) != MATCHZANY && 667 (*rp & 0377) != MATCHZERO) 668 { 669 /* end-of-input with patterns left */ 670 goto backup; 671 } 672 673 switch (*rp & 0377) 674 { 675 register STAB *s; 676 char buf[MAXLINE]; 677 678 case MATCHCLASS: 679 /* match any phrase in a class */ 680 mlp->pattern = rvp; 681 mlp->first = avp; 682 extendclass: 683 ap = *avp; 684 if (ap == NULL) 685 goto backup; 686 mlp->last = avp++; 687 cataddr(mlp->first, mlp->last, buf, sizeof buf, '\0'); 688 s = stab(buf, ST_CLASS, ST_FIND); 689 if (s == NULL || !bitnset(rp[1], s->s_class)) 690 { 691 if (tTd(21, 36)) 692 { 693 printf("EXTEND rp="); 694 xputs(rp); 695 printf(", ap="); 696 xputs(ap); 697 printf("\n"); 698 } 699 goto extendclass; 700 } 701 if (tTd(21, 36)) 702 printf("CLMATCH\n"); 703 mlp++; 704 break; 705 706 case MATCHNCLASS: 707 /* match any token not in a class */ 708 s = stab(ap, ST_CLASS, ST_FIND); 709 if (s != NULL && bitnset(rp[1], s->s_class)) 710 goto backup; 711 712 /* fall through */ 713 714 case MATCHONE: 715 case MATCHANY: 716 /* match exactly one token */ 717 mlp->pattern = rvp; 718 mlp->first = avp; 719 mlp->last = avp++; 720 mlp++; 721 break; 722 723 case MATCHZANY: 724 /* match zero or more tokens */ 725 mlp->pattern = rvp; 726 mlp->first = avp; 727 mlp->last = avp - 1; 728 mlp++; 729 break; 730 731 case MATCHZERO: 732 /* match zero tokens */ 733 break; 734 735 case MACRODEXPAND: 736 /* 737 ** Match against run-time macro. 738 ** This algorithm is broken for the 739 ** general case (no recursive macros, 740 ** improper tokenization) but should 741 ** work for the usual cases. 742 */ 743 744 ap = macvalue(rp[1], e); 745 mlp->first = avp; 746 if (tTd(21, 2)) 747 printf("rewrite: LHS $&%c => \"%s\"\n", 748 rp[1], 749 ap == NULL ? "(NULL)" : ap); 750 751 if (ap == NULL) 752 break; 753 while (*ap != NULL) 754 { 755 if (*avp == NULL || 756 strncasecmp(ap, *avp, strlen(*avp)) != 0) 757 { 758 /* no match */ 759 avp = mlp->first; 760 goto backup; 761 } 762 ap += strlen(*avp++); 763 } 764 765 /* match */ 766 break; 767 768 default: 769 /* must have exact match */ 770 if (strcasecmp(rp, ap)) 771 goto backup; 772 avp++; 773 break; 774 } 775 776 /* successful match on this token */ 777 rvp++; 778 continue; 779 780 backup: 781 /* match failed -- back up */ 782 while (--mlp >= mlist) 783 { 784 rvp = mlp->pattern; 785 rp = *rvp; 786 avp = mlp->last + 1; 787 ap = *avp; 788 789 if (tTd(21, 36)) 790 { 791 printf("BACKUP rp="); 792 xputs(rp); 793 printf(", ap="); 794 xputs(ap); 795 printf("\n"); 796 } 797 798 if (ap == NULL) 799 { 800 /* run off the end -- back up again */ 801 continue; 802 } 803 if ((*rp & 0377) == MATCHANY || 804 (*rp & 0377) == MATCHZANY) 805 { 806 /* extend binding and continue */ 807 mlp->last = avp++; 808 rvp++; 809 mlp++; 810 break; 811 } 812 if ((*rp & 0377) == MATCHCLASS) 813 { 814 /* extend binding and try again */ 815 mlp->last = avp++; 816 goto extendclass; 817 } 818 } 819 820 if (mlp < mlist) 821 { 822 /* total failure to match */ 823 break; 824 } 825 } 826 827 /* 828 ** See if we successfully matched 829 */ 830 831 if (mlp < mlist || *rvp != NULL) 832 { 833 if (tTd(21, 10)) 834 printf("----- rule fails\n"); 835 rwr = rwr->r_next; 836 ruleno++; 837 continue; 838 } 839 840 rvp = rwr->r_rhs; 841 if (tTd(21, 12)) 842 { 843 printf("-----rule matches:"); 844 printav(rvp); 845 } 846 847 rp = *rvp; 848 if ((*rp & 0377) == CANONUSER) 849 { 850 rvp++; 851 rwr = rwr->r_next; 852 ruleno++; 853 } 854 else if ((*rp & 0377) == CANONHOST) 855 { 856 rvp++; 857 rwr = NULL; 858 } 859 else if ((*rp & 0377) == CANONNET) 860 rwr = NULL; 861 862 /* substitute */ 863 for (avp = npvp; *rvp != NULL; rvp++) 864 { 865 register struct match *m; 866 register char **pp; 867 868 rp = *rvp; 869 if ((*rp & 0377) == MATCHREPL) 870 { 871 /* substitute from LHS */ 872 m = &mlist[rp[1] - '1']; 873 if (m < mlist || m >= mlp) 874 { 875 syserr("554 rewrite: ruleset %d: replacement $%c out of bounds", 876 ruleset, rp[1]); 877 return EX_CONFIG; 878 } 879 if (tTd(21, 15)) 880 { 881 printf("$%c:", rp[1]); 882 pp = m->first; 883 while (pp <= m->last) 884 { 885 printf(" %x=\"", *pp); 886 (void) fflush(stdout); 887 printf("%s\"", *pp++); 888 } 889 printf("\n"); 890 } 891 pp = m->first; 892 while (pp <= m->last) 893 { 894 if (avp >= &npvp[MAXATOM]) 895 { 896 syserr("554 rewrite: expansion too long"); 897 return EX_DATAERR; 898 } 899 *avp++ = *pp++; 900 } 901 } 902 else 903 { 904 /* vanilla replacement */ 905 if (avp >= &npvp[MAXATOM]) 906 { 907 toolong: 908 syserr("554 rewrite: expansion too long"); 909 return EX_DATAERR; 910 } 911 if ((*rp & 0377) != MACRODEXPAND) 912 *avp++ = rp; 913 else 914 { 915 *avp = macvalue(rp[1], e); 916 if (tTd(21, 2)) 917 printf("rewrite: RHS $&%c => \"%s\"\n", 918 rp[1], 919 *avp == NULL ? "(NULL)" : *avp); 920 if (*avp != NULL) 921 avp++; 922 } 923 } 924 } 925 *avp++ = NULL; 926 927 /* 928 ** Check for any hostname/keyword lookups. 929 */ 930 931 for (rvp = npvp; *rvp != NULL; rvp++) 932 { 933 char **hbrvp; 934 char **xpvp; 935 int trsize; 936 char *olddelimchar; 937 char *replac; 938 int endtoken; 939 STAB *map; 940 char *mapname; 941 char **key_rvp; 942 char **arg_rvp; 943 char **default_rvp; 944 char buf[MAXNAME + 1]; 945 char *pvpb1[MAXATOM + 1]; 946 char *argvect[10]; 947 char pvpbuf[PSBUFSIZE]; 948 949 if ((**rvp & 0377) != HOSTBEGIN && 950 (**rvp & 0377) != LOOKUPBEGIN) 951 continue; 952 953 /* 954 ** Got a hostname/keyword lookup. 955 ** 956 ** This could be optimized fairly easily. 957 */ 958 959 hbrvp = rvp; 960 if ((**rvp & 0377) == HOSTBEGIN) 961 { 962 endtoken = HOSTEND; 963 mapname = "host"; 964 } 965 else 966 { 967 endtoken = LOOKUPEND; 968 mapname = *++rvp; 969 } 970 map = stab(mapname, ST_MAP, ST_FIND); 971 if (map == NULL) 972 syserr("554 rewrite: map %s not found", mapname); 973 974 /* extract the match part */ 975 key_rvp = ++rvp; 976 default_rvp = NULL; 977 arg_rvp = argvect; 978 xpvp = NULL; 979 replac = pvpbuf; 980 while (*rvp != NULL && (**rvp & 0377) != endtoken) 981 { 982 int nodetype = **rvp & 0377; 983 984 if (nodetype != CANONHOST && nodetype != CANONUSER) 985 { 986 rvp++; 987 continue; 988 } 989 990 *rvp++ = NULL; 991 992 if (xpvp != NULL) 993 { 994 cataddr(xpvp, NULL, replac, 995 &pvpbuf[sizeof pvpbuf] - replac, 996 '\0'); 997 *++arg_rvp = replac; 998 replac += strlen(replac) + 1; 999 xpvp = NULL; 1000 } 1001 switch (nodetype) 1002 { 1003 case CANONHOST: 1004 xpvp = rvp; 1005 break; 1006 1007 case CANONUSER: 1008 default_rvp = rvp; 1009 break; 1010 } 1011 } 1012 if (*rvp != NULL) 1013 *rvp++ = NULL; 1014 if (xpvp != NULL) 1015 { 1016 cataddr(xpvp, NULL, replac, 1017 &pvpbuf[sizeof pvpbuf] - replac, 1018 '\0'); 1019 *++arg_rvp = replac; 1020 } 1021 *++arg_rvp = NULL; 1022 1023 /* save the remainder of the input string */ 1024 trsize = (int) (avp - rvp + 1) * sizeof *rvp; 1025 bcopy((char *) rvp, (char *) pvpb1, trsize); 1026 1027 /* look it up */ 1028 cataddr(key_rvp, NULL, buf, sizeof buf, '\0'); 1029 argvect[0] = buf; 1030 if (map != NULL && bitset(MF_VALID, map->s_map.map_flags)) 1031 { 1032 int bsize = sizeof buf - 1; 1033 auto int stat = EX_OK; 1034 1035 if (map->s_map.map_app != NULL) 1036 bsize -= strlen(map->s_map.map_app); 1037 if (tTd(60, 1)) 1038 printf("map_lookup(%s, %s) => ", 1039 mapname, buf); 1040 replac = (*map->s_map.map_class->map_lookup)(&map->s_map, 1041 buf, sizeof buf - 1, argvect, 1042 &stat); 1043 if (replac != NULL && map->s_map.map_app != NULL) 1044 strcat(replac, map->s_map.map_app); 1045 if (tTd(60, 1)) 1046 printf("%s (%d)\n", 1047 replac ? replac : "NOT FOUND", 1048 stat); 1049 1050 /* should recover if stat == EX_TEMPFAIL */ 1051 if (stat == EX_TEMPFAIL) 1052 rstat = stat; 1053 } 1054 else 1055 replac = NULL; 1056 1057 /* if no replacement, use default */ 1058 if (replac == NULL && default_rvp != NULL) 1059 { 1060 char buf2[sizeof buf]; 1061 1062 /* rewrite the default with % translations */ 1063 cataddr(default_rvp, NULL, buf2, sizeof buf2, '\0'); 1064 map_rewrite(buf2, sizeof buf2, buf, sizeof buf, 1065 argvect); 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 } 1116 else 1117 { 1118 bcopy((char *) npvp, (char *) pvp, 1119 (int) (avp - npvp) * sizeof *avp); 1120 } 1121 if (tTd(21, 4)) 1122 { 1123 printf("rewritten as:"); 1124 printav(pvp); 1125 } 1126 } 1127 1128 if (OpMode == MD_TEST || tTd(21, 2)) 1129 { 1130 printf("rewrite: ruleset %2d returns:", ruleset); 1131 printav(pvp); 1132 } 1133 1134 return rstat; 1135 } 1136 /* 1137 ** BUILDADDR -- build address from token vector. 1138 ** 1139 ** Parameters: 1140 ** tv -- token vector. 1141 ** a -- pointer to address descriptor to fill. 1142 ** If NULL, one will be allocated. 1143 ** e -- the current envelope. 1144 ** 1145 ** Returns: 1146 ** NULL if there was an error. 1147 ** 'a' otherwise. 1148 ** 1149 ** Side Effects: 1150 ** fills in 'a' 1151 */ 1152 1153 struct errcodes 1154 { 1155 char *ec_name; /* name of error code */ 1156 int ec_code; /* numeric code */ 1157 } ErrorCodes[] = 1158 { 1159 "usage", EX_USAGE, 1160 "nouser", EX_NOUSER, 1161 "nohost", EX_NOHOST, 1162 "unavailable", EX_UNAVAILABLE, 1163 "software", EX_SOFTWARE, 1164 "tempfail", EX_TEMPFAIL, 1165 "protocol", EX_PROTOCOL, 1166 #ifdef EX_CONFIG 1167 "config", EX_CONFIG, 1168 #endif 1169 NULL, EX_UNAVAILABLE, 1170 }; 1171 1172 ADDRESS * 1173 buildaddr(tv, a, e) 1174 register char **tv; 1175 register ADDRESS *a; 1176 register ENVELOPE *e; 1177 { 1178 struct mailer **mp; 1179 register struct mailer *m; 1180 char *bp; 1181 int spaceleft; 1182 static char buf[MAXNAME]; 1183 1184 if (a == NULL) 1185 a = (ADDRESS *) xalloc(sizeof *a); 1186 bzero((char *) a, sizeof *a); 1187 1188 /* figure out what net/mailer to use */ 1189 if ((**tv & 0377) != CANONNET) 1190 { 1191 syserr("554 buildaddr: no net"); 1192 return (NULL); 1193 } 1194 tv++; 1195 if (strcasecmp(*tv, "error") == 0) 1196 { 1197 if ((**++tv & 0377) == CANONHOST) 1198 { 1199 register struct errcodes *ep; 1200 1201 if (isascii(**++tv) && isdigit(**tv)) 1202 { 1203 setstat(atoi(*tv)); 1204 } 1205 else 1206 { 1207 for (ep = ErrorCodes; ep->ec_name != NULL; ep++) 1208 if (strcasecmp(ep->ec_name, *tv) == 0) 1209 break; 1210 setstat(ep->ec_code); 1211 } 1212 tv++; 1213 } 1214 if ((**tv & 0377) != CANONUSER) 1215 syserr("554 buildaddr: error: no user"); 1216 cataddr(++tv, NULL, buf, sizeof buf, ' '); 1217 stripquotes(buf); 1218 usrerr(buf); 1219 if (e->e_message == NULL) 1220 e->e_message = newstr(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, a->q_ruser? a->q_ruser: "<null>"); 1477 printf("\tnext=%x, flags=%o, alias %x, uid %d, gid %d\n", 1478 a->q_next, a->q_flags, a->q_alias, a->q_uid, a->q_gid); 1479 printf("\towner=%s, home=\"%s\", fullname=\"%s\"\n", 1480 a->q_owner == NULL ? "(none)" : a->q_owner, 1481 a->q_home, a->q_fullname); 1482 1483 if (!follow) 1484 return; 1485 a = a->q_next; 1486 } 1487 if (first) 1488 printf("[NULL]\n"); 1489 } 1490 1491 /* 1492 ** REMOTENAME -- return the name relative to the current mailer 1493 ** 1494 ** Parameters: 1495 ** name -- the name to translate. 1496 ** m -- the mailer that we want to do rewriting relative 1497 ** to. 1498 ** flags -- fine tune operations. 1499 ** pstat -- pointer to status word. 1500 ** e -- the current envelope. 1501 ** 1502 ** Returns: 1503 ** the text string representing this address relative to 1504 ** the receiving mailer. 1505 ** 1506 ** Side Effects: 1507 ** none. 1508 ** 1509 ** Warnings: 1510 ** The text string returned is tucked away locally; 1511 ** copy it if you intend to save it. 1512 */ 1513 1514 char * 1515 remotename(name, m, flags, pstat, e) 1516 char *name; 1517 struct mailer *m; 1518 int flags; 1519 int *pstat; 1520 register ENVELOPE *e; 1521 { 1522 register char **pvp; 1523 char *fancy; 1524 extern char *macvalue(); 1525 char *oldg = macvalue('g', e); 1526 int rwset; 1527 static char buf[MAXNAME]; 1528 char lbuf[MAXNAME]; 1529 char pvpbuf[PSBUFSIZE]; 1530 extern char **prescan(); 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 if (rewrite(pvp, 1, e) == EX_TEMPFAIL) 1598 *pstat = EX_TEMPFAIL; 1599 else 1600 if (rewrite(pvp, 2, e) == EX_TEMPFAIL) 1601 *pstat = EX_TEMPFAIL; 1602 if (rwset > 0) 1603 if (rewrite(pvp, rwset, e) == EX_TEMPFAIL) 1604 *pstat = EX_TEMPFAIL; 1605 1606 /* 1607 ** Do any final sanitation the address may require. 1608 ** This will normally be used to turn internal forms 1609 ** (e.g., user@host.LOCAL) into external form. This 1610 ** may be used as a default to the above rules. 1611 */ 1612 1613 if (rewrite(pvp, 4, e) == EX_TEMPFAIL) 1614 *pstat = EX_TEMPFAIL; 1615 1616 /* 1617 ** Now restore the comment information we had at the beginning. 1618 */ 1619 1620 cataddr(pvp, NULL, lbuf, sizeof lbuf, '\0'); 1621 define('g', lbuf, e); 1622 expand(fancy, buf, &buf[sizeof buf - 1], e); 1623 define('g', oldg, e); 1624 1625 if (tTd(12, 1)) 1626 printf("remotename => `%s'\n", buf); 1627 return (buf); 1628 } 1629 /* 1630 ** MAPLOCALUSER -- run local username through ruleset 5 for final redirection 1631 ** 1632 ** Parameters: 1633 ** a -- the address to map (but just the user name part). 1634 ** sendq -- the sendq in which to install any replacement 1635 ** addresses. 1636 ** 1637 ** Returns: 1638 ** none. 1639 */ 1640 1641 maplocaluser(a, sendq, e) 1642 register ADDRESS *a; 1643 ADDRESS **sendq; 1644 ENVELOPE *e; 1645 { 1646 register char **pvp; 1647 register ADDRESS *a1 = NULL; 1648 auto char *delimptr; 1649 char pvpbuf[PSBUFSIZE]; 1650 1651 if (tTd(29, 1)) 1652 { 1653 printf("maplocaluser: "); 1654 printaddr(a, FALSE); 1655 } 1656 pvp = prescan(a->q_user, '\0', pvpbuf, &delimptr); 1657 if (pvp == NULL) 1658 return; 1659 1660 (void) rewrite(pvp, 5, e); 1661 if (pvp[0] == NULL || (pvp[0][0] & 0377) != CANONNET) 1662 return; 1663 1664 /* if non-null, mailer destination specified -- has it changed? */ 1665 a1 = buildaddr(pvp, NULL, e); 1666 if (a1 == NULL || sameaddr(a, a1)) 1667 return; 1668 1669 /* mark old address as dead; insert new address */ 1670 a->q_flags |= QDONTSEND; 1671 if (tTd(29, 5)) 1672 { 1673 printf("maplocaluser: QDONTSEND "); 1674 printaddr(a, FALSE); 1675 } 1676 a1->q_alias = a; 1677 allocaddr(a1, 1, NULL, delimptr); 1678 (void) recipient(a1, sendq, e); 1679 } 1680 /* 1681 ** DEQUOTE_INIT -- initialize dequote map 1682 ** 1683 ** This is a no-op. 1684 ** 1685 ** Parameters: 1686 ** map -- the internal map structure. 1687 ** mapname -- the name of the mapl. 1688 ** args -- arguments. 1689 ** 1690 ** Returns: 1691 ** TRUE. 1692 */ 1693 1694 bool 1695 dequote_init(map, mapname, args) 1696 MAP *map; 1697 char *mapname; 1698 char *args; 1699 { 1700 register char *p = args; 1701 1702 for (;;) 1703 { 1704 while (isascii(*p) && isspace(*p)) 1705 p++; 1706 if (*p != '-') 1707 break; 1708 switch (*++p) 1709 { 1710 case 'a': 1711 map->map_app = ++p; 1712 break; 1713 } 1714 while (*p != '\0' && !(isascii(*p) && isspace(*p))) 1715 p++; 1716 if (*p != '\0') 1717 *p = '\0'; 1718 } 1719 if (map->map_app != NULL) 1720 map->map_app = newstr(map->map_app); 1721 1722 return TRUE; 1723 } 1724 /* 1725 ** DEQUOTE_MAP -- unquote an address 1726 ** 1727 ** Parameters: 1728 ** map -- the internal map structure (ignored). 1729 ** buf -- the buffer to dequote. 1730 ** bufsiz -- the size of that buffer. 1731 ** av -- arguments (ignored). 1732 ** statp -- pointer to status out-parameter. 1733 ** 1734 ** Returns: 1735 ** NULL -- if there were no quotes, or if the resulting 1736 ** unquoted buffer would not be acceptable to prescan. 1737 ** else -- The dequoted buffer. 1738 */ 1739 1740 char * 1741 dequote_map(map, buf, bufsiz, av, statp) 1742 MAP *map; 1743 char buf[]; 1744 int bufsiz; 1745 char **av; 1746 int *statp; 1747 { 1748 register char *p; 1749 register char *q; 1750 register char c; 1751 int anglecnt; 1752 int cmntcnt; 1753 int quotecnt; 1754 int spacecnt; 1755 bool quotemode; 1756 bool bslashmode; 1757 1758 anglecnt = 0; 1759 cmntcnt = 0; 1760 quotecnt = 0; 1761 spacecnt = 0; 1762 quotemode = FALSE; 1763 bslashmode = FALSE; 1764 1765 for (p = q = buf; (c = *p++) != '\0'; ) 1766 { 1767 if (bslashmode) 1768 { 1769 bslashmode = FALSE; 1770 *q++ = c; 1771 continue; 1772 } 1773 1774 switch (c) 1775 { 1776 case '\\': 1777 bslashmode = TRUE; 1778 break; 1779 1780 case '(': 1781 cmntcnt++; 1782 break; 1783 1784 case ')': 1785 if (cmntcnt-- <= 0) 1786 return NULL; 1787 break; 1788 1789 case ' ': 1790 spacecnt++; 1791 break; 1792 } 1793 1794 if (cmntcnt > 0) 1795 { 1796 *q++ = c; 1797 continue; 1798 } 1799 1800 switch (c) 1801 { 1802 case '"': 1803 quotemode = !quotemode; 1804 quotecnt++; 1805 continue; 1806 1807 case '<': 1808 anglecnt++; 1809 break; 1810 1811 case '>': 1812 if (anglecnt-- <= 0) 1813 return NULL; 1814 break; 1815 } 1816 *q++ = c; 1817 } 1818 1819 if (anglecnt != 0 || cmntcnt != 0 || bslashmode || 1820 quotemode || quotecnt <= 0 || spacecnt != 0) 1821 return NULL; 1822 *q++ = '\0'; 1823 return buf; 1824 } 1825