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