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