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