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