1 # include "sendmail.h" 2 3 SCCSID(@(#)parseaddr.c 3.67 11/28/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) 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) then the address in avp matched is 415 ** 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 a MATCHONE or a MATCHCLASS 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 /* match any token in a class */ 517 class = rp[1]; 518 if (!isalpha(class)) 519 goto backup; 520 if (isupper(class)) 521 class -= 'A'; 522 else 523 class -= 'a'; 524 s = stab(ap, ST_CLASS, ST_FIND); 525 if (s == NULL || (s->s_class & (1L << class)) == 0) 526 goto backup; 527 528 /* explicit fall-through */ 529 530 case MATCHONE: 531 case MATCHANY: 532 /* match exactly one token */ 533 mlp->first = avp; 534 mlp->last = avp++; 535 mlp++; 536 break; 537 538 case MATCHZANY: 539 /* match zero or more tokens */ 540 mlp->first = avp; 541 mlp->last = avp - 1; 542 mlp++; 543 break; 544 545 default: 546 /* must have exact match */ 547 if (!sameword(rp, ap)) 548 goto backup; 549 avp++; 550 break; 551 } 552 553 /* successful match on this token */ 554 rvp++; 555 continue; 556 557 backup: 558 /* match failed -- back up */ 559 while (--rvp >= rwr->r_lhs) 560 { 561 rp = *rvp; 562 if (*rp == MATCHANY || *rp == MATCHZANY) 563 { 564 /* extend binding and continue */ 565 avp = ++mlp[-1].last; 566 avp++; 567 rvp++; 568 break; 569 } 570 avp--; 571 if (*rp == MATCHONE || *rp == MATCHCLASS) 572 { 573 /* back out binding */ 574 mlp--; 575 } 576 } 577 578 if (rvp < rwr->r_lhs) 579 { 580 /* total failure to match */ 581 break; 582 } 583 } 584 585 /* 586 ** See if we successfully matched 587 */ 588 589 if (rvp < rwr->r_lhs || *rvp != NULL) 590 { 591 # ifdef DEBUG 592 if (tTd(21, 10)) 593 printf("----- rule fails\n"); 594 # endif DEBUG 595 rwr = rwr->r_next; 596 continue; 597 } 598 599 rvp = rwr->r_rhs; 600 # ifdef DEBUG 601 if (tTd(21, 12)) 602 { 603 printf("-----rule matches:"); 604 printav(rvp); 605 } 606 # endif DEBUG 607 608 rp = *rvp; 609 if (*rp == CANONUSER) 610 { 611 rvp++; 612 rwr = rwr->r_next; 613 } 614 else if (*rp == CANONHOST) 615 { 616 rvp++; 617 rwr = NULL; 618 } 619 else if (*rp == CANONNET) 620 rwr = NULL; 621 622 /* substitute */ 623 for (avp = npvp; *rvp != NULL; rvp++) 624 { 625 register struct match *m; 626 register char **pp; 627 628 rp = *rvp; 629 if (*rp != MATCHREPL) 630 { 631 if (avp >= &npvp[MAXATOM]) 632 { 633 syserr("rewrite: expansion too long"); 634 return; 635 } 636 *avp++ = rp; 637 continue; 638 } 639 640 /* substitute from LHS */ 641 m = &mlist[rp[1] - '1']; 642 # ifdef DEBUG 643 if (tTd(21, 15)) 644 { 645 printf("$%c:", rp[1]); 646 pp = m->first; 647 while (pp <= m->last) 648 { 649 printf(" %x=\"", *pp); 650 (void) fflush(stdout); 651 printf("%s\"", *pp++); 652 } 653 printf("\n"); 654 } 655 # endif DEBUG 656 pp = m->first; 657 while (pp <= m->last) 658 { 659 if (avp >= &npvp[MAXATOM]) 660 { 661 syserr("rewrite: expansion too long"); 662 return; 663 } 664 *avp++ = *pp++; 665 } 666 } 667 *avp++ = NULL; 668 if (**npvp == CALLSUBR) 669 { 670 bmove((char *) &npvp[2], (char *) pvp, 671 (avp - npvp - 2) * sizeof *avp); 672 # ifdef DEBUG 673 if (tTd(21, 3)) 674 printf("-----callsubr %s\n", npvp[1]); 675 # endif DEBUG 676 rewrite(pvp, atoi(npvp[1])); 677 } 678 else 679 { 680 bmove((char *) npvp, (char *) pvp, 681 (avp - npvp) * sizeof *avp); 682 } 683 # ifdef DEBUG 684 if (tTd(21, 4)) 685 { 686 printf("rewritten as:"); 687 printav(pvp); 688 } 689 # endif DEBUG 690 } 691 692 if (OpMode == MD_TEST || tTd(21, 2)) 693 { 694 printf("rewrite: ruleset %2d returns:", ruleset); 695 printav(pvp); 696 } 697 } 698 /* 699 ** BUILDADDR -- build address from token vector. 700 ** 701 ** Parameters: 702 ** tv -- token vector. 703 ** a -- pointer to address descriptor to fill. 704 ** If NULL, one will be allocated. 705 ** 706 ** Returns: 707 ** NULL if there was an error. 708 ** 'a' otherwise. 709 ** 710 ** Side Effects: 711 ** fills in 'a' 712 */ 713 714 ADDRESS * 715 buildaddr(tv, a) 716 register char **tv; 717 register ADDRESS *a; 718 { 719 static char buf[MAXNAME]; 720 struct mailer **mp; 721 register struct mailer *m; 722 extern bool sameword(); 723 724 if (a == NULL) 725 a = (ADDRESS *) xalloc(sizeof *a); 726 clear((char *) a, sizeof *a); 727 728 /* figure out what net/mailer to use */ 729 if (**tv != CANONNET) 730 { 731 syserr("buildaddr: no net"); 732 return (NULL); 733 } 734 tv++; 735 if (sameword(*tv, "error")) 736 { 737 if (**++tv != CANONUSER) 738 syserr("buildaddr: error: no user"); 739 buf[0] = '\0'; 740 while (*++tv != NULL) 741 { 742 if (buf[0] != '\0') 743 (void) strcat(buf, " "); 744 (void) strcat(buf, *tv); 745 } 746 usrerr(buf); 747 return (NULL); 748 } 749 for (mp = Mailer; (m = *mp++) != NULL; ) 750 { 751 if (sameword(m->m_name, *tv)) 752 break; 753 } 754 if (m == NULL) 755 { 756 syserr("buildaddr: unknown net %s", *tv); 757 return (NULL); 758 } 759 a->q_mailer = m; 760 761 /* figure out what host (if any) */ 762 tv++; 763 if (!bitset(M_LOCAL, m->m_flags)) 764 { 765 if (**tv++ != CANONHOST) 766 { 767 syserr("buildaddr: no host"); 768 return (NULL); 769 } 770 buf[0] = '\0'; 771 while (*tv != NULL && **tv != CANONUSER) 772 (void) strcat(buf, *tv++); 773 a->q_host = newstr(buf); 774 } 775 else 776 a->q_host = NULL; 777 778 /* figure out the user */ 779 if (**tv != CANONUSER) 780 { 781 syserr("buildaddr: no user"); 782 return (NULL); 783 } 784 cataddr(++tv, buf, sizeof buf); 785 a->q_user = buf; 786 787 return (a); 788 } 789 /* 790 ** CATADDR -- concatenate pieces of addresses (putting in <LWSP> subs) 791 ** 792 ** Parameters: 793 ** pvp -- parameter vector to rebuild. 794 ** buf -- buffer to build the string into. 795 ** sz -- size of buf. 796 ** 797 ** Returns: 798 ** none. 799 ** 800 ** Side Effects: 801 ** Destroys buf. 802 */ 803 804 cataddr(pvp, buf, sz) 805 char **pvp; 806 char *buf; 807 register int sz; 808 { 809 bool oatomtok = FALSE; 810 bool natomtok = FALSE; 811 register int i; 812 register char *p; 813 814 if (pvp == NULL) 815 { 816 strcpy(buf, ""); 817 return; 818 } 819 p = buf; 820 sz--; 821 while (*pvp != NULL && (i = strlen(*pvp)) < sz) 822 { 823 natomtok = (toktype(**pvp) == ATM); 824 if (oatomtok && natomtok) 825 *p++ = SpaceSub; 826 (void) strcpy(p, *pvp); 827 oatomtok = natomtok; 828 p += i; 829 sz -= i; 830 pvp++; 831 } 832 *p = '\0'; 833 } 834 /* 835 ** SAMEADDR -- Determine if two addresses are the same 836 ** 837 ** This is not just a straight comparison -- if the mailer doesn't 838 ** care about the host we just ignore it, etc. 839 ** 840 ** Parameters: 841 ** a, b -- pointers to the internal forms to compare. 842 ** 843 ** Returns: 844 ** TRUE -- they represent the same mailbox. 845 ** FALSE -- they don't. 846 ** 847 ** Side Effects: 848 ** none. 849 */ 850 851 bool 852 sameaddr(a, b) 853 register ADDRESS *a; 854 register ADDRESS *b; 855 { 856 /* if they don't have the same mailer, forget it */ 857 if (a->q_mailer != b->q_mailer) 858 return (FALSE); 859 860 /* if the user isn't the same, we can drop out */ 861 if (strcmp(a->q_user, b->q_user) != 0) 862 return (FALSE); 863 864 /* if the mailer ignores hosts, we have succeeded! */ 865 if (bitset(M_LOCAL, a->q_mailer->m_flags)) 866 return (TRUE); 867 868 /* otherwise compare hosts (but be careful for NULL ptrs) */ 869 if (a->q_host == NULL || b->q_host == NULL) 870 return (FALSE); 871 if (strcmp(a->q_host, b->q_host) != 0) 872 return (FALSE); 873 874 return (TRUE); 875 } 876 /* 877 ** PRINTADDR -- print address (for debugging) 878 ** 879 ** Parameters: 880 ** a -- the address to print 881 ** follow -- follow the q_next chain. 882 ** 883 ** Returns: 884 ** none. 885 ** 886 ** Side Effects: 887 ** none. 888 */ 889 890 # ifdef DEBUG 891 892 printaddr(a, follow) 893 register ADDRESS *a; 894 bool follow; 895 { 896 bool first = TRUE; 897 898 while (a != NULL) 899 { 900 first = FALSE; 901 printf("%x=", a); 902 (void) fflush(stdout); 903 printf("%s: mailer %d (%s), host `%s', user `%s'\n", a->q_paddr, 904 a->q_mailer->m_mno, a->q_mailer->m_name, a->q_host, 905 a->q_user); 906 printf("\tnext=%x, flags=%o, alias %x\n", a->q_next, a->q_flags, 907 a->q_alias); 908 printf("\thome=\"%s\", fullname=\"%s\"\n", a->q_home, 909 a->q_fullname); 910 911 if (!follow) 912 return; 913 a = a->q_next; 914 } 915 if (first) 916 printf("[NULL]\n"); 917 } 918 919 # endif DEBUG 920 /* 921 ** REMOTENAME -- return the name relative to the current mailer 922 ** 923 ** Parameters: 924 ** name -- the name to translate. 925 ** m -- the mailer that we want to do rewriting relative 926 ** to. 927 ** senderaddress -- if set, uses the sender rewriting rules 928 ** rather than the recipient rewriting rules. 929 ** 930 ** Returns: 931 ** the text string representing this address relative to 932 ** the receiving mailer. 933 ** 934 ** Side Effects: 935 ** none. 936 ** 937 ** Warnings: 938 ** The text string returned is tucked away locally; 939 ** copy it if you intend to save it. 940 */ 941 942 char * 943 remotename(name, m, senderaddress) 944 char *name; 945 struct mailer *m; 946 bool senderaddress; 947 { 948 register char **pvp; 949 char *fancy; 950 extern char *macvalue(); 951 char *oldg = macvalue('g', CurEnv); 952 static char buf[MAXNAME]; 953 char lbuf[MAXNAME]; 954 extern char **prescan(); 955 extern char *crackaddr(); 956 957 # ifdef DEBUG 958 if (tTd(12, 1)) 959 printf("remotename(%s)\n", name); 960 # endif DEBUG 961 962 /* 963 ** Do a heuristic crack of this name to extract any comment info. 964 ** This will leave the name as a comment and a $g macro. 965 */ 966 967 fancy = crackaddr(name); 968 969 /* 970 ** Turn the name into canonical form. 971 ** Normally this will be RFC 822 style, i.e., "user@domain". 972 ** If this only resolves to "user", and the "C" flag is 973 ** specified in the sending mailer, then the sender's 974 ** domain will be appended. 975 */ 976 977 pvp = prescan(name, '\0'); 978 if (pvp == NULL) 979 return (name); 980 rewrite(pvp, 3); 981 if (CurEnv->e_fromdomain != NULL) 982 { 983 /* append from domain to this address */ 984 register char **pxp = pvp; 985 986 while (*pxp != NULL && strcmp(*pxp, "@") != 0) 987 pxp++; 988 if (*pxp == NULL) 989 { 990 register char **qxq = CurEnv->e_fromdomain; 991 992 while (*qxq != NULL) 993 *pxp++ = *qxq++; 994 } 995 } 996 997 /* 998 ** Do more specific rewriting. 999 ** Rewrite using ruleset 1 or 2 depending on whether this is 1000 ** a sender address or not. 1001 ** Then run it through any receiving-mailer-specific rulesets. 1002 */ 1003 1004 if (senderaddress) 1005 { 1006 rewrite(pvp, 1); 1007 if (m->m_s_rwset > 0) 1008 rewrite(pvp, m->m_s_rwset); 1009 } 1010 else 1011 { 1012 rewrite(pvp, 2); 1013 if (m->m_r_rwset > 0) 1014 rewrite(pvp, m->m_r_rwset); 1015 } 1016 1017 /* 1018 ** Do any final sanitation the address may require. 1019 ** This will normally be used to turn internal forms 1020 ** (e.g., user@host.LOCAL) into external form. This 1021 ** may be used as a default to the above rules. 1022 */ 1023 1024 rewrite(pvp, 4); 1025 1026 /* 1027 ** Now restore the comment information we had at the beginning. 1028 */ 1029 1030 cataddr(pvp, lbuf, sizeof lbuf); 1031 define('g', lbuf, CurEnv); 1032 expand(fancy, buf, &buf[sizeof buf - 1], CurEnv); 1033 define('g', oldg, CurEnv); 1034 1035 # ifdef DEBUG 1036 if (tTd(12, 1)) 1037 printf("remotename => `%s'\n", buf); 1038 # endif DEBUG 1039 return (buf); 1040 } 1041 /* 1042 ** CANONNAME -- make name canonical 1043 ** 1044 ** This is used for SMTP and misc. printing. Given a print 1045 ** address, it strips out comments, etc. 1046 ** 1047 ** Parameters: 1048 ** name -- the name to make canonical. 1049 ** ruleset -- the canonicalizing ruleset. 1050 ** 1051 ** Returns: 1052 ** pointer to canonical name. 1053 ** 1054 ** Side Effects: 1055 ** none. 1056 ** 1057 ** Warning: 1058 ** result is saved in static buf; future calls will trash it. 1059 */ 1060 1061 char * 1062 canonname(name, ruleset) 1063 char *name; 1064 int ruleset; 1065 { 1066 static char nbuf[MAXNAME]; 1067 register char **pvp; 1068 1069 pvp = prescan(name, '\0'); 1070 rewrite(pvp, 3); 1071 rewrite(pvp, ruleset); 1072 cataddr(pvp, nbuf, sizeof nbuf); 1073 return (nbuf); 1074 } 1075