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