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