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