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 5.13 (Berkeley) 06/01/90"; 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 ** 44 ** Returns: 45 ** A pointer to the address descriptor header (`a' if 46 ** `a' is non-NULL). 47 ** NULL on error. 48 ** 49 ** Side Effects: 50 ** none 51 */ 52 53 /* following delimiters are inherent to the internal algorithms */ 54 # define DELIMCHARS "\001()<>,;\\\"\r\n" /* word delimiters */ 55 56 ADDRESS * 57 parseaddr(addr, a, copyf, delim) 58 char *addr; 59 register ADDRESS *a; 60 int copyf; 61 char delim; 62 { 63 register char **pvp; 64 register struct mailer *m; 65 char pvpbuf[PSBUFSIZE]; 66 extern char **prescan(); 67 extern ADDRESS *buildaddr(); 68 69 /* 70 ** Initialize and prescan address. 71 */ 72 73 CurEnv->e_to = addr; 74 if (tTd(20, 1)) 75 printf("\n--parseaddr(%s)\n", addr); 76 77 pvp = prescan(addr, delim, pvpbuf); 78 if (pvp == NULL) 79 return (NULL); 80 81 /* 82 ** Apply rewriting rules. 83 ** Ruleset 0 does basic parsing. It must resolve. 84 */ 85 86 rewrite(pvp, 3); 87 rewrite(pvp, 0); 88 89 /* 90 ** See if we resolved to a real mailer. 91 */ 92 93 if (pvp[0][0] != CANONNET) 94 { 95 setstat(EX_USAGE); 96 usrerr("cannot resolve name"); 97 return (NULL); 98 } 99 100 /* 101 ** Build canonical address from pvp. 102 */ 103 104 a = buildaddr(pvp, a); 105 if (a == NULL) 106 return (NULL); 107 m = a->q_mailer; 108 109 /* 110 ** Make local copies of the host & user and then 111 ** transport them out. 112 */ 113 114 if (copyf > 0) 115 { 116 extern char *DelimChar; 117 char savec = *DelimChar; 118 119 *DelimChar = '\0'; 120 a->q_paddr = newstr(addr); 121 *DelimChar = savec; 122 } 123 else 124 a->q_paddr = addr; 125 126 if (a->q_user == NULL) 127 a->q_user = ""; 128 if (a->q_host == NULL) 129 a->q_host = ""; 130 131 if (copyf >= 0) 132 { 133 a->q_host = newstr(a->q_host); 134 if (a->q_user != a->q_paddr) 135 a->q_user = newstr(a->q_user); 136 } 137 138 /* 139 ** Convert host name to lower case if requested. 140 ** User name will be done later. 141 */ 142 143 if (!bitnset(M_HST_UPPER, m->m_flags)) 144 makelower(a->q_host); 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 ** LOWERADDR -- map UPPER->lower case on addresses as requested. 160 ** 161 ** Parameters: 162 ** a -- address to be mapped. 163 ** 164 ** Returns: 165 ** none. 166 ** 167 ** Side Effects: 168 ** none. 169 */ 170 171 loweraddr(a) 172 register ADDRESS *a; 173 { 174 register MAILER *m = a->q_mailer; 175 176 if (!bitnset(M_USR_UPPER, m->m_flags)) 177 makelower(a->q_user); 178 } 179 /* 180 ** PRESCAN -- Prescan name and make it canonical 181 ** 182 ** Scans a name and turns it into a set of tokens. This process 183 ** deletes blanks and comments (in parentheses). 184 ** 185 ** This routine knows about quoted strings and angle brackets. 186 ** 187 ** There are certain subtleties to this routine. The one that 188 ** comes to mind now is that backslashes on the ends of names 189 ** are silently stripped off; this is intentional. The problem 190 ** is that some versions of sndmsg (like at LBL) set the kill 191 ** character to something other than @ when reading addresses; 192 ** so people type "csvax.eric\@berkeley" -- which screws up the 193 ** berknet mailer. 194 ** 195 ** Parameters: 196 ** addr -- the name to chomp. 197 ** delim -- the delimiter for the address, normally 198 ** '\0' or ','; \0 is accepted in any case. 199 ** If '\t' then we are reading the .cf file. 200 ** pvpbuf -- place to put the saved text -- note that 201 ** the pointers are static. 202 ** 203 ** Returns: 204 ** A pointer to a vector of tokens. 205 ** NULL on error. 206 ** 207 ** Side Effects: 208 ** sets DelimChar to point to the character matching 'delim'. 209 */ 210 211 /* states and character types */ 212 # define OPR 0 /* operator */ 213 # define ATM 1 /* atom */ 214 # define QST 2 /* in quoted string */ 215 # define SPC 3 /* chewing up spaces */ 216 # define ONE 4 /* pick up one character */ 217 218 # define NSTATES 5 /* number of states */ 219 # define TYPE 017 /* mask to select state type */ 220 221 /* meta bits for table */ 222 # define M 020 /* meta character; don't pass through */ 223 # define B 040 /* cause a break */ 224 # define MB M|B /* meta-break */ 225 226 static short StateTab[NSTATES][NSTATES] = 227 { 228 /* oldst chtype> OPR ATM QST SPC ONE */ 229 /*OPR*/ OPR|B, ATM|B, QST|B, SPC|MB, ONE|B, 230 /*ATM*/ OPR|B, ATM, QST|B, SPC|MB, ONE|B, 231 /*QST*/ QST, QST, OPR, QST, QST, 232 /*SPC*/ OPR, ATM, QST, SPC|M, ONE, 233 /*ONE*/ OPR, OPR, OPR, OPR, OPR, 234 }; 235 236 # define NOCHAR -1 /* signal nothing in lookahead token */ 237 238 char *DelimChar; /* set to point to the delimiter */ 239 240 char ** 241 prescan(addr, delim, pvpbuf) 242 char *addr; 243 char delim; 244 char pvpbuf[]; 245 { 246 register char *p; 247 register char *q; 248 register int c; 249 char **avp; 250 bool bslashmode; 251 int cmntcnt; 252 int anglecnt; 253 char *tok; 254 int state; 255 int newstate; 256 static char *av[MAXATOM+1]; 257 extern int errno; 258 259 /* make sure error messages don't have garbage on them */ 260 errno = 0; 261 262 q = pvpbuf; 263 bslashmode = FALSE; 264 cmntcnt = 0; 265 anglecnt = 0; 266 avp = av; 267 state = OPR; 268 c = NOCHAR; 269 p = addr; 270 if (tTd(22, 45)) 271 { 272 printf("prescan: "); 273 xputs(p); 274 (void) putchar('\n'); 275 } 276 277 do 278 { 279 /* read a token */ 280 tok = q; 281 for (;;) 282 { 283 /* store away any old lookahead character */ 284 if (c != NOCHAR) 285 { 286 /* see if there is room */ 287 if (q >= &pvpbuf[PSBUFSIZE - 5]) 288 { 289 usrerr("Address too long"); 290 DelimChar = p; 291 return (NULL); 292 } 293 294 /* squirrel it away */ 295 *q++ = c; 296 } 297 298 /* read a new input character */ 299 c = *p++; 300 if (c == '\0') 301 break; 302 c &= ~0200; 303 304 if (tTd(22, 101)) 305 printf("c=%c, s=%d; ", c, state); 306 307 /* chew up special characters */ 308 *q = '\0'; 309 if (bslashmode) 310 { 311 /* kludge \! for naive users */ 312 if (c != '!') 313 c |= 0200; 314 bslashmode = FALSE; 315 } 316 else if (c == '\\') 317 { 318 bslashmode = TRUE; 319 c = NOCHAR; 320 } 321 else if (state == QST) 322 { 323 /* do nothing, just avoid next clauses */ 324 } 325 else if (c == '(') 326 { 327 cmntcnt++; 328 c = NOCHAR; 329 } 330 else if (c == ')') 331 { 332 if (cmntcnt <= 0) 333 { 334 usrerr("Unbalanced ')'"); 335 DelimChar = p; 336 return (NULL); 337 } 338 else 339 cmntcnt--; 340 } 341 else if (cmntcnt > 0) 342 c = NOCHAR; 343 else if (c == '<') 344 anglecnt++; 345 else if (c == '>') 346 { 347 if (anglecnt <= 0) 348 { 349 usrerr("Unbalanced '>'"); 350 DelimChar = p; 351 return (NULL); 352 } 353 anglecnt--; 354 } 355 else if (delim == ' ' && isspace(c)) 356 c = ' '; 357 358 if (c == NOCHAR) 359 continue; 360 361 /* see if this is end of input */ 362 if (c == delim && anglecnt <= 0 && state != QST) 363 break; 364 365 newstate = StateTab[state][toktype(c)]; 366 if (tTd(22, 101)) 367 printf("ns=%02o\n", newstate); 368 state = newstate & TYPE; 369 if (bitset(M, newstate)) 370 c = NOCHAR; 371 if (bitset(B, newstate)) 372 break; 373 } 374 375 /* new token */ 376 if (tok != q) 377 { 378 *q++ = '\0'; 379 if (tTd(22, 36)) 380 { 381 printf("tok="); 382 xputs(tok); 383 (void) putchar('\n'); 384 } 385 if (avp >= &av[MAXATOM]) 386 { 387 syserr("prescan: too many tokens"); 388 DelimChar = p; 389 return (NULL); 390 } 391 *avp++ = tok; 392 } 393 } while (c != '\0' && (c != delim || anglecnt > 0)); 394 *avp = NULL; 395 DelimChar = --p; 396 if (cmntcnt > 0) 397 usrerr("Unbalanced '('"); 398 else if (anglecnt > 0) 399 usrerr("Unbalanced '<'"); 400 else if (state == QST) 401 usrerr("Unbalanced '\"'"); 402 else if (av[0] != NULL) 403 return (av); 404 return (NULL); 405 } 406 /* 407 ** TOKTYPE -- return token type 408 ** 409 ** Parameters: 410 ** c -- the character in question. 411 ** 412 ** Returns: 413 ** Its type. 414 ** 415 ** Side Effects: 416 ** none. 417 */ 418 419 toktype(c) 420 register char c; 421 { 422 static char buf[50]; 423 static bool firstime = TRUE; 424 425 if (firstime) 426 { 427 firstime = FALSE; 428 expand("\001o", buf, &buf[sizeof buf - 1], CurEnv); 429 (void) strcat(buf, DELIMCHARS); 430 } 431 if (c == MATCHCLASS || c == MATCHREPL || c == MATCHNCLASS) 432 return (ONE); 433 if (c == '"') 434 return (QST); 435 if (!isascii(c)) 436 return (ATM); 437 if (isspace(c) || c == ')') 438 return (SPC); 439 if (iscntrl(c) || index(buf, c) != NULL) 440 return (OPR); 441 return (ATM); 442 } 443 /* 444 ** REWRITE -- apply rewrite rules to token vector. 445 ** 446 ** This routine is an ordered production system. Each rewrite 447 ** rule has a LHS (called the pattern) and a RHS (called the 448 ** rewrite); 'rwr' points the the current rewrite rule. 449 ** 450 ** For each rewrite rule, 'avp' points the address vector we 451 ** are trying to match against, and 'pvp' points to the pattern. 452 ** If pvp points to a special match value (MATCHZANY, MATCHANY, 453 ** MATCHONE, MATCHCLASS, MATCHNCLASS) then the address in avp 454 ** matched is saved away in the match vector (pointed to by 'mvp'). 455 ** 456 ** When a match between avp & pvp does not match, we try to 457 ** back out. If we back up over MATCHONE, MATCHCLASS, or MATCHNCLASS 458 ** we must also back out the match in mvp. If we reach a 459 ** MATCHANY or MATCHZANY we just extend the match and start 460 ** over again. 461 ** 462 ** When we finally match, we rewrite the address vector 463 ** and try over again. 464 ** 465 ** Parameters: 466 ** pvp -- pointer to token vector. 467 ** 468 ** Returns: 469 ** none. 470 ** 471 ** Side Effects: 472 ** pvp is modified. 473 */ 474 475 struct match 476 { 477 char **first; /* first token matched */ 478 char **last; /* last token matched */ 479 }; 480 481 # define MAXMATCH 9 /* max params per rewrite */ 482 483 484 rewrite(pvp, ruleset) 485 char **pvp; 486 int ruleset; 487 { 488 register char *ap; /* address pointer */ 489 register char *rp; /* rewrite pointer */ 490 register char **avp; /* address vector pointer */ 491 register char **rvp; /* rewrite vector pointer */ 492 register struct match *mlp; /* cur ptr into mlist */ 493 register struct rewrite *rwr; /* pointer to current rewrite rule */ 494 struct match mlist[MAXMATCH]; /* stores match on LHS */ 495 char *npvp[MAXATOM+1]; /* temporary space for rebuild */ 496 497 if (OpMode == MD_TEST || tTd(21, 2)) 498 { 499 printf("rewrite: ruleset %2d input:", ruleset); 500 printav(pvp); 501 } 502 if (pvp == NULL) 503 return; 504 505 /* 506 ** Run through the list of rewrite rules, applying 507 ** any that match. 508 */ 509 510 for (rwr = RewriteRules[ruleset]; rwr != NULL; ) 511 { 512 if (tTd(21, 12)) 513 { 514 printf("-----trying rule:"); 515 printav(rwr->r_lhs); 516 } 517 518 /* try to match on this rule */ 519 mlp = mlist; 520 rvp = rwr->r_lhs; 521 avp = pvp; 522 while ((ap = *avp) != NULL || *rvp != NULL) 523 { 524 rp = *rvp; 525 if (tTd(21, 35)) 526 { 527 printf("ap="); 528 xputs(ap); 529 printf(", rp="); 530 xputs(rp); 531 printf("\n"); 532 } 533 if (rp == NULL) 534 { 535 /* end-of-pattern before end-of-address */ 536 goto backup; 537 } 538 if (ap == NULL && *rp != MATCHZANY) 539 { 540 /* end-of-input */ 541 break; 542 } 543 544 switch (*rp) 545 { 546 register STAB *s; 547 548 case MATCHCLASS: 549 case MATCHNCLASS: 550 /* match any token in (not in) a class */ 551 s = stab(ap, ST_CLASS, ST_FIND); 552 if (s == NULL || !bitnset(rp[1], s->s_class)) 553 { 554 if (*rp == MATCHCLASS) 555 goto backup; 556 } 557 else if (*rp == MATCHNCLASS) 558 goto backup; 559 560 /* explicit fall-through */ 561 562 case MATCHONE: 563 case MATCHANY: 564 /* match exactly one token */ 565 mlp->first = avp; 566 mlp->last = avp++; 567 mlp++; 568 break; 569 570 case MATCHZANY: 571 /* match zero or more tokens */ 572 mlp->first = avp; 573 mlp->last = avp - 1; 574 mlp++; 575 break; 576 577 default: 578 /* must have exact match */ 579 if (strcasecmp(rp, ap)) 580 goto backup; 581 avp++; 582 break; 583 } 584 585 /* successful match on this token */ 586 rvp++; 587 continue; 588 589 backup: 590 /* match failed -- back up */ 591 while (--rvp >= rwr->r_lhs) 592 { 593 rp = *rvp; 594 if (*rp == MATCHANY || *rp == MATCHZANY) 595 { 596 /* extend binding and continue */ 597 avp = ++mlp[-1].last; 598 avp++; 599 rvp++; 600 break; 601 } 602 avp--; 603 if (*rp == MATCHONE || *rp == MATCHCLASS || 604 *rp == MATCHNCLASS) 605 { 606 /* back out binding */ 607 mlp--; 608 } 609 } 610 611 if (rvp < rwr->r_lhs) 612 { 613 /* total failure to match */ 614 break; 615 } 616 } 617 618 /* 619 ** See if we successfully matched 620 */ 621 622 if (rvp < rwr->r_lhs || *rvp != NULL) 623 { 624 if (tTd(21, 10)) 625 printf("----- rule fails\n"); 626 rwr = rwr->r_next; 627 continue; 628 } 629 630 rvp = rwr->r_rhs; 631 if (tTd(21, 12)) 632 { 633 printf("-----rule matches:"); 634 printav(rvp); 635 } 636 637 rp = *rvp; 638 if (*rp == CANONUSER) 639 { 640 rvp++; 641 rwr = rwr->r_next; 642 } 643 else if (*rp == CANONHOST) 644 { 645 rvp++; 646 rwr = NULL; 647 } 648 else if (*rp == CANONNET) 649 rwr = NULL; 650 651 /* substitute */ 652 for (avp = npvp; *rvp != NULL; rvp++) 653 { 654 register struct match *m; 655 register char **pp; 656 657 rp = *rvp; 658 if (*rp == MATCHREPL) 659 { 660 /* substitute from LHS */ 661 m = &mlist[rp[1] - '1']; 662 if (m >= mlp) 663 { 664 syserr("rewrite: ruleset %d: replacement out of bounds", ruleset); 665 return; 666 } 667 if (tTd(21, 15)) 668 { 669 printf("$%c:", rp[1]); 670 pp = m->first; 671 while (pp <= m->last) 672 { 673 printf(" %x=\"", *pp); 674 (void) fflush(stdout); 675 printf("%s\"", *pp++); 676 } 677 printf("\n"); 678 } 679 pp = m->first; 680 while (pp <= m->last) 681 { 682 if (avp >= &npvp[MAXATOM]) 683 { 684 syserr("rewrite: expansion too long"); 685 return; 686 } 687 *avp++ = *pp++; 688 } 689 } 690 else 691 { 692 /* vanilla replacement */ 693 if (avp >= &npvp[MAXATOM]) 694 { 695 toolong: 696 syserr("rewrite: expansion too long"); 697 return; 698 } 699 *avp++ = rp; 700 } 701 } 702 *avp++ = NULL; 703 704 /* 705 ** Check for any hostname lookups. 706 */ 707 708 for (rvp = npvp; *rvp != NULL; rvp++) 709 { 710 char **hbrvp; 711 char **xpvp; 712 int trsize; 713 char *olddelimchar; 714 char buf[MAXNAME + 1]; 715 char *pvpb1[MAXATOM + 1]; 716 char pvpbuf[PSBUFSIZE]; 717 extern char *DelimChar; 718 719 if (**rvp != HOSTBEGIN) 720 continue; 721 722 /* 723 ** Got a hostname lookup. 724 ** 725 ** This could be optimized fairly easily. 726 */ 727 728 hbrvp = rvp; 729 730 /* extract the match part */ 731 while (*++rvp != NULL && **rvp != HOSTEND) 732 continue; 733 if (*rvp != NULL) 734 *rvp++ = NULL; 735 736 /* save the remainder of the input string */ 737 trsize = (int) (avp - rvp + 1) * sizeof *rvp; 738 bcopy((char *) rvp, (char *) pvpb1, trsize); 739 740 /* look it up */ 741 cataddr(++hbrvp, buf, sizeof buf); 742 maphostname(buf, sizeof buf); 743 744 /* scan the new host name */ 745 olddelimchar = DelimChar; 746 xpvp = prescan(buf, '\0', pvpbuf); 747 DelimChar = olddelimchar; 748 if (xpvp == NULL) 749 { 750 syserr("rewrite: cannot prescan canonical hostname: %s", buf); 751 return; 752 } 753 754 /* append it to the token list */ 755 for (avp = --hbrvp; *xpvp != NULL; xpvp++) 756 { 757 *avp++ = newstr(*xpvp); 758 if (avp >= &npvp[MAXATOM]) 759 goto toolong; 760 } 761 762 /* restore the old trailing information */ 763 for (xpvp = pvpb1; (*avp++ = *xpvp++) != NULL; ) 764 if (avp >= &npvp[MAXATOM]) 765 goto toolong; 766 767 break; 768 } 769 770 /* 771 ** Check for subroutine calls. 772 */ 773 774 if (*npvp != NULL && **npvp == CALLSUBR) 775 { 776 bcopy((char *) &npvp[2], (char *) pvp, 777 (int) (avp - npvp - 2) * sizeof *avp); 778 if (tTd(21, 3)) 779 printf("-----callsubr %s\n", npvp[1]); 780 rewrite(pvp, atoi(npvp[1])); 781 } 782 else 783 { 784 bcopy((char *) npvp, (char *) pvp, 785 (int) (avp - npvp) * sizeof *avp); 786 } 787 if (tTd(21, 4)) 788 { 789 printf("rewritten as:"); 790 printav(pvp); 791 } 792 } 793 794 if (OpMode == MD_TEST || tTd(21, 2)) 795 { 796 printf("rewrite: ruleset %2d returns:", ruleset); 797 printav(pvp); 798 } 799 } 800 /* 801 ** BUILDADDR -- build address from token vector. 802 ** 803 ** Parameters: 804 ** tv -- token vector. 805 ** a -- pointer to address descriptor to fill. 806 ** If NULL, one will be allocated. 807 ** 808 ** Returns: 809 ** NULL if there was an error. 810 ** 'a' otherwise. 811 ** 812 ** Side Effects: 813 ** fills in 'a' 814 */ 815 816 ADDRESS * 817 buildaddr(tv, a) 818 register char **tv; 819 register ADDRESS *a; 820 { 821 static char buf[MAXNAME]; 822 struct mailer **mp; 823 register struct mailer *m; 824 825 if (a == NULL) 826 a = (ADDRESS *) xalloc(sizeof *a); 827 bzero((char *) a, sizeof *a); 828 829 /* figure out what net/mailer to use */ 830 if (**tv != CANONNET) 831 { 832 syserr("buildaddr: no net"); 833 return (NULL); 834 } 835 tv++; 836 if (!strcasecmp(*tv, "error")) 837 { 838 if (**++tv == CANONHOST) 839 { 840 setstat(atoi(*++tv)); 841 tv++; 842 } 843 if (**tv != CANONUSER) 844 syserr("buildaddr: error: no user"); 845 buf[0] = '\0'; 846 while (*++tv != NULL) 847 { 848 if (buf[0] != '\0') 849 (void) strcat(buf, " "); 850 (void) strcat(buf, *tv); 851 } 852 usrerr(buf); 853 return (NULL); 854 } 855 for (mp = Mailer; (m = *mp++) != NULL; ) 856 { 857 if (!strcasecmp(m->m_name, *tv)) 858 break; 859 } 860 if (m == NULL) 861 { 862 syserr("buildaddr: unknown mailer %s", *tv); 863 return (NULL); 864 } 865 a->q_mailer = m; 866 867 /* figure out what host (if any) */ 868 tv++; 869 if (!bitnset(M_LOCAL, m->m_flags)) 870 { 871 if (**tv++ != CANONHOST) 872 { 873 syserr("buildaddr: no host"); 874 return (NULL); 875 } 876 buf[0] = '\0'; 877 while (*tv != NULL && **tv != CANONUSER) 878 (void) strcat(buf, *tv++); 879 a->q_host = newstr(buf); 880 } 881 else 882 a->q_host = NULL; 883 884 /* figure out the user */ 885 if (*tv == NULL || **tv != CANONUSER) 886 { 887 syserr("buildaddr: no user"); 888 return (NULL); 889 } 890 891 /* rewrite according recipient mailer rewriting rules */ 892 rewrite(++tv, 2); 893 if (m->m_r_rwset > 0) 894 rewrite(tv, m->m_r_rwset); 895 rewrite(tv, 4); 896 897 /* save the result for the command line/RCPT argument */ 898 cataddr(tv, buf, sizeof buf); 899 a->q_user = buf; 900 901 return (a); 902 } 903 /* 904 ** CATADDR -- concatenate pieces of addresses (putting in <LWSP> subs) 905 ** 906 ** Parameters: 907 ** pvp -- parameter vector to rebuild. 908 ** buf -- buffer to build the string into. 909 ** sz -- size of buf. 910 ** 911 ** Returns: 912 ** none. 913 ** 914 ** Side Effects: 915 ** Destroys buf. 916 */ 917 918 cataddr(pvp, buf, sz) 919 char **pvp; 920 char *buf; 921 register int sz; 922 { 923 bool oatomtok = FALSE; 924 bool natomtok = FALSE; 925 register int i; 926 register char *p; 927 928 if (pvp == NULL) 929 { 930 (void) strcpy(buf, ""); 931 return; 932 } 933 p = buf; 934 sz -= 2; 935 while (*pvp != NULL && (i = strlen(*pvp)) < sz) 936 { 937 natomtok = (toktype(**pvp) == ATM); 938 if (oatomtok && natomtok) 939 *p++ = SpaceSub; 940 (void) strcpy(p, *pvp); 941 oatomtok = natomtok; 942 p += i; 943 sz -= i + 1; 944 pvp++; 945 } 946 *p = '\0'; 947 } 948 /* 949 ** SAMEADDR -- Determine if two addresses are the same 950 ** 951 ** This is not just a straight comparison -- if the mailer doesn't 952 ** care about the host we just ignore it, etc. 953 ** 954 ** Parameters: 955 ** a, b -- pointers to the internal forms to compare. 956 ** 957 ** Returns: 958 ** TRUE -- they represent the same mailbox. 959 ** FALSE -- they don't. 960 ** 961 ** Side Effects: 962 ** none. 963 */ 964 965 bool 966 sameaddr(a, b) 967 register ADDRESS *a; 968 register ADDRESS *b; 969 { 970 /* if they don't have the same mailer, forget it */ 971 if (a->q_mailer != b->q_mailer) 972 return (FALSE); 973 974 /* if the user isn't the same, we can drop out */ 975 if (strcmp(a->q_user, b->q_user) != 0) 976 return (FALSE); 977 978 /* if the mailer ignores hosts, we have succeeded! */ 979 if (bitnset(M_LOCAL, a->q_mailer->m_flags)) 980 return (TRUE); 981 982 /* otherwise compare hosts (but be careful for NULL ptrs) */ 983 if (a->q_host == NULL || b->q_host == NULL) 984 return (FALSE); 985 if (strcmp(a->q_host, b->q_host) != 0) 986 return (FALSE); 987 988 return (TRUE); 989 } 990 /* 991 ** PRINTADDR -- print address (for debugging) 992 ** 993 ** Parameters: 994 ** a -- the address to print 995 ** follow -- follow the q_next chain. 996 ** 997 ** Returns: 998 ** none. 999 ** 1000 ** Side Effects: 1001 ** none. 1002 */ 1003 1004 printaddr(a, follow) 1005 register ADDRESS *a; 1006 bool follow; 1007 { 1008 bool first = TRUE; 1009 1010 while (a != NULL) 1011 { 1012 first = FALSE; 1013 printf("%x=", a); 1014 (void) fflush(stdout); 1015 printf("%s: mailer %d (%s), host `%s', user `%s', ruser `%s'\n", 1016 a->q_paddr, a->q_mailer->m_mno, a->q_mailer->m_name, 1017 a->q_host, a->q_user, a->q_ruser? a->q_ruser: "<null>"); 1018 printf("\tnext=%x, flags=%o, alias %x\n", a->q_next, a->q_flags, 1019 a->q_alias); 1020 printf("\thome=\"%s\", fullname=\"%s\"\n", a->q_home, 1021 a->q_fullname); 1022 1023 if (!follow) 1024 return; 1025 a = a->q_next; 1026 } 1027 if (first) 1028 printf("[NULL]\n"); 1029 } 1030 1031 /* 1032 ** REMOTENAME -- return the name relative to the current mailer 1033 ** 1034 ** Parameters: 1035 ** name -- the name to translate. 1036 ** m -- the mailer that we want to do rewriting relative 1037 ** to. 1038 ** senderaddress -- if set, uses the sender rewriting rules 1039 ** rather than the recipient rewriting rules. 1040 ** canonical -- if set, strip out any comment information, 1041 ** etc. 1042 ** 1043 ** Returns: 1044 ** the text string representing this address relative to 1045 ** the receiving mailer. 1046 ** 1047 ** Side Effects: 1048 ** none. 1049 ** 1050 ** Warnings: 1051 ** The text string returned is tucked away locally; 1052 ** copy it if you intend to save it. 1053 */ 1054 1055 char * 1056 remotename(name, m, senderaddress, canonical) 1057 char *name; 1058 struct mailer *m; 1059 bool senderaddress; 1060 bool canonical; 1061 { 1062 register char **pvp; 1063 char *fancy; 1064 extern char *macvalue(); 1065 char *oldg = macvalue('g', CurEnv); 1066 static char buf[MAXNAME]; 1067 char lbuf[MAXNAME]; 1068 char pvpbuf[PSBUFSIZE]; 1069 extern char **prescan(); 1070 extern char *crackaddr(); 1071 1072 if (tTd(12, 1)) 1073 printf("remotename(%s)\n", name); 1074 1075 /* don't do anything if we are tagging it as special */ 1076 if ((senderaddress ? m->m_s_rwset : m->m_r_rwset) < 0) 1077 return (name); 1078 1079 /* 1080 ** Do a heuristic crack of this name to extract any comment info. 1081 ** This will leave the name as a comment and a $g macro. 1082 */ 1083 1084 if (canonical) 1085 fancy = "\001g"; 1086 else 1087 fancy = crackaddr(name); 1088 1089 /* 1090 ** Turn the name into canonical form. 1091 ** Normally this will be RFC 822 style, i.e., "user@domain". 1092 ** If this only resolves to "user", and the "C" flag is 1093 ** specified in the sending mailer, then the sender's 1094 ** domain will be appended. 1095 */ 1096 1097 pvp = prescan(name, '\0', pvpbuf); 1098 if (pvp == NULL) 1099 return (name); 1100 rewrite(pvp, 3); 1101 if (CurEnv->e_fromdomain != NULL) 1102 { 1103 /* append from domain to this address */ 1104 register char **pxp = pvp; 1105 1106 /* see if there is an "@domain" in the current name */ 1107 while (*pxp != NULL && strcmp(*pxp, "@") != 0) 1108 pxp++; 1109 if (*pxp == NULL) 1110 { 1111 /* no.... append the "@domain" from the sender */ 1112 register char **qxq = CurEnv->e_fromdomain; 1113 1114 while ((*pxp++ = *qxq++) != NULL) 1115 continue; 1116 rewrite(pvp, 3); 1117 } 1118 } 1119 1120 /* 1121 ** Do more specific rewriting. 1122 ** Rewrite using ruleset 1 or 2 depending on whether this is 1123 ** a sender address or not. 1124 ** Then run it through any receiving-mailer-specific rulesets. 1125 */ 1126 1127 if (senderaddress) 1128 { 1129 rewrite(pvp, 1); 1130 if (m->m_s_rwset > 0) 1131 rewrite(pvp, m->m_s_rwset); 1132 } 1133 else 1134 { 1135 rewrite(pvp, 2); 1136 if (m->m_r_rwset > 0) 1137 rewrite(pvp, m->m_r_rwset); 1138 } 1139 1140 /* 1141 ** Do any final sanitation the address may require. 1142 ** This will normally be used to turn internal forms 1143 ** (e.g., user@host.LOCAL) into external form. This 1144 ** may be used as a default to the above rules. 1145 */ 1146 1147 rewrite(pvp, 4); 1148 1149 /* 1150 ** Now restore the comment information we had at the beginning. 1151 */ 1152 1153 cataddr(pvp, lbuf, sizeof lbuf); 1154 define('g', lbuf, CurEnv); 1155 expand(fancy, buf, &buf[sizeof buf - 1], CurEnv); 1156 define('g', oldg, CurEnv); 1157 1158 if (tTd(12, 1)) 1159 printf("remotename => `%s'\n", buf); 1160 return (buf); 1161 } 1162