1 # include "sendmail.h" 2 3 SCCSID(@(#)parseaddr.c 3.60 10/09/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 int anglecnt; 219 char *tok; 220 int state; 221 int newstate; 222 static char buf[MAXNAME+MAXATOM]; 223 static char *av[MAXATOM+1]; 224 225 q = buf; 226 bslashmode = FALSE; 227 cmntcnt = 0; 228 anglecnt = 0; 229 avp = av; 230 state = OPR; 231 c = NOCHAR; 232 p = addr; 233 # ifdef DEBUG 234 if (tTd(22, 45)) 235 { 236 printf("prescan: "); 237 xputs(p); 238 putchar('\n'); 239 } 240 # endif DEBUG 241 242 do 243 { 244 /* read a token */ 245 tok = q; 246 for (;;) 247 { 248 /* store away any old lookahead character */ 249 if (c != NOCHAR) 250 { 251 /* squirrel it away */ 252 if (q >= &buf[sizeof buf - 5]) 253 { 254 usrerr("Address too long"); 255 DelimChar = p; 256 return (NULL); 257 } 258 *q++ = c; 259 } 260 261 /* read a new input character */ 262 c = *p++; 263 if (c == '\0') 264 break; 265 # ifdef DEBUG 266 if (tTd(22, 101)) 267 printf("c=%c, s=%d; ", c, state); 268 # endif DEBUG 269 270 /* chew up special characters */ 271 c &= ~0200; 272 *q = '\0'; 273 if (bslashmode) 274 { 275 c |= 0200; 276 bslashmode = FALSE; 277 } 278 else if (c == '\\') 279 { 280 bslashmode = TRUE; 281 c = NOCHAR; 282 } 283 else if (c == '(') 284 { 285 cmntcnt++; 286 c = NOCHAR; 287 } 288 else if (c == ')') 289 { 290 if (cmntcnt <= 0) 291 { 292 usrerr("Unbalanced ')'"); 293 DelimChar = p; 294 return (NULL); 295 } 296 else 297 cmntcnt--; 298 } 299 else if (cmntcnt > 0) 300 c = NOCHAR; 301 else if (c == '<') 302 anglecnt++; 303 else if (c == '>') 304 { 305 if (anglecnt <= 0) 306 { 307 usrerr("Unbalanced '>'"); 308 DelimChar = p; 309 return (NULL); 310 } 311 anglecnt--; 312 } 313 314 if (c == NOCHAR) 315 continue; 316 317 /* see if this is end of input */ 318 if (c == delim && anglecnt <= 0) 319 break; 320 321 newstate = StateTab[state][toktype(c)]; 322 # ifdef DEBUG 323 if (tTd(22, 101)) 324 printf("ns=%02o\n", newstate); 325 # endif DEBUG 326 state = newstate & TYPE; 327 if (bitset(M, newstate)) 328 c = NOCHAR; 329 if (bitset(B, newstate)) 330 break; 331 } 332 333 /* new token */ 334 if (tok != q) 335 { 336 *q++ = '\0'; 337 # ifdef DEBUG 338 if (tTd(22, 36)) 339 { 340 printf("tok="); 341 xputs(tok); 342 putchar('\n'); 343 } 344 # endif DEBUG 345 if (avp >= &av[MAXATOM]) 346 { 347 syserr("prescan: too many tokens"); 348 DelimChar = p; 349 return (NULL); 350 } 351 *avp++ = tok; 352 } 353 } while (c != '\0' && (c != delim || anglecnt > 0)); 354 *avp = NULL; 355 DelimChar = --p; 356 if (cmntcnt > 0) 357 usrerr("Unbalanced '('"); 358 else if (anglecnt > 0) 359 usrerr("Unbalanced '<'"); 360 else if (state == QST) 361 usrerr("Unbalanced '\"'"); 362 else if (av[0] != NULL) 363 return (av); 364 return (NULL); 365 } 366 /* 367 ** TOKTYPE -- return token type 368 ** 369 ** Parameters: 370 ** c -- the character in question. 371 ** 372 ** Returns: 373 ** Its type. 374 ** 375 ** Side Effects: 376 ** none. 377 */ 378 379 toktype(c) 380 register char c; 381 { 382 static char buf[50]; 383 static bool firstime = TRUE; 384 385 if (firstime) 386 { 387 firstime = FALSE; 388 expand("$o", buf, &buf[sizeof buf - 1], CurEnv); 389 (void) strcat(buf, DELIMCHARS); 390 } 391 if (c == MATCHCLASS || c == MATCHREPL) 392 return (ONE); 393 if (c == '"') 394 return (QST); 395 if (!isascii(c)) 396 return (ATM); 397 if (isspace(c) || c == ')') 398 return (SPC); 399 if (iscntrl(c) || index(buf, c) != NULL) 400 return (OPR); 401 return (ATM); 402 } 403 /* 404 ** REWRITE -- apply rewrite rules to token vector. 405 ** 406 ** This routine is an ordered production system. Each rewrite 407 ** rule has a LHS (called the pattern) and a RHS (called the 408 ** rewrite); 'rwr' points the the current rewrite rule. 409 ** 410 ** For each rewrite rule, 'avp' points the address vector we 411 ** are trying to match against, and 'pvp' points to the pattern. 412 ** If pvp points to a special match value (MATCHZANY, MATCHANY, 413 ** MATCHONE, MATCHCLASS) then the address in avp matched is 414 ** saved away in the match vector (pointed to by 'mvp'). 415 ** 416 ** When a match between avp & pvp does not match, we try to 417 ** back out. If we back up over a MATCHONE or a MATCHCLASS 418 ** we must also back out the match in mvp. If we reach a 419 ** MATCHANY or MATCHZANY we just extend the match and start 420 ** over again. 421 ** 422 ** When we finally match, we rewrite the address vector 423 ** and try over again. 424 ** 425 ** Parameters: 426 ** pvp -- pointer to token vector. 427 ** 428 ** Returns: 429 ** none. 430 ** 431 ** Side Effects: 432 ** pvp is modified. 433 */ 434 435 struct match 436 { 437 char **first; /* first token matched */ 438 char **last; /* last token matched */ 439 }; 440 441 # define MAXMATCH 9 /* max params per rewrite */ 442 443 444 rewrite(pvp, ruleset) 445 char **pvp; 446 int ruleset; 447 { 448 register char *ap; /* address pointer */ 449 register char *rp; /* rewrite pointer */ 450 register char **avp; /* address vector pointer */ 451 register char **rvp; /* rewrite vector pointer */ 452 register struct match *mlp; /* cur ptr into mlist */ 453 register struct rewrite *rwr; /* pointer to current rewrite rule */ 454 struct match mlist[MAXMATCH]; /* stores match on LHS */ 455 char *npvp[MAXATOM+1]; /* temporary space for rebuild */ 456 extern bool sameword(); 457 458 if (Mode == MD_TEST || tTd(21, 2)) 459 { 460 printf("rewrite: ruleset %d, original pvp:", ruleset); 461 printav(pvp); 462 } 463 if (pvp == NULL) 464 return; 465 466 /* 467 ** Run through the list of rewrite rules, applying 468 ** any that match. 469 */ 470 471 for (rwr = RewriteRules[ruleset]; rwr != NULL; ) 472 { 473 # ifdef DEBUG 474 if (tTd(21, 12)) 475 { 476 printf("-----trying rule:"); 477 printav(rwr->r_lhs); 478 } 479 # endif DEBUG 480 481 /* try to match on this rule */ 482 mlp = mlist; 483 rvp = rwr->r_lhs; 484 avp = pvp; 485 while ((ap = *avp) != NULL || *rvp != NULL) 486 { 487 rp = *rvp; 488 # ifdef DEBUG 489 if (tTd(21, 35)) 490 { 491 printf("ap="); 492 xputs(ap); 493 printf(", rp="); 494 xputs(rp); 495 printf("\n"); 496 } 497 # endif DEBUG 498 if (rp == NULL) 499 { 500 /* end-of-pattern before end-of-address */ 501 goto backup; 502 } 503 if (ap == NULL && *rp != MATCHZANY) 504 { 505 /* end-of-input */ 506 break; 507 } 508 509 switch (*rp) 510 { 511 register STAB *s; 512 register int class; 513 514 case MATCHCLASS: 515 /* match any token in a class */ 516 class = rp[1]; 517 if (!isalpha(class)) 518 goto backup; 519 if (isupper(class)) 520 class -= 'A'; 521 else 522 class -= 'a'; 523 s = stab(ap, ST_CLASS, ST_FIND); 524 if (s == NULL || (s->s_class & (1L << class)) == 0) 525 goto backup; 526 527 /* explicit fall-through */ 528 529 case MATCHONE: 530 case MATCHANY: 531 /* match exactly one token */ 532 mlp->first = avp; 533 mlp->last = avp++; 534 mlp++; 535 break; 536 537 case MATCHZANY: 538 /* match zero or more tokens */ 539 mlp->first = avp; 540 mlp->last = avp - 1; 541 mlp++; 542 break; 543 544 default: 545 /* must have exact match */ 546 if (!sameword(rp, ap)) 547 goto backup; 548 avp++; 549 break; 550 } 551 552 /* successful match on this token */ 553 rvp++; 554 continue; 555 556 backup: 557 /* match failed -- back up */ 558 while (--rvp >= rwr->r_lhs) 559 { 560 rp = *rvp; 561 if (*rp == MATCHANY || *rp == MATCHZANY) 562 { 563 /* extend binding and continue */ 564 avp = ++mlp[-1].last; 565 avp++; 566 rvp++; 567 break; 568 } 569 avp--; 570 if (*rp == MATCHONE || *rp == MATCHCLASS) 571 { 572 /* back out binding */ 573 mlp--; 574 } 575 } 576 577 if (rvp < rwr->r_lhs) 578 { 579 /* total failure to match */ 580 break; 581 } 582 } 583 584 /* 585 ** See if we successfully matched 586 */ 587 588 if (rvp >= rwr->r_lhs && *rvp == NULL) 589 { 590 rvp = rwr->r_rhs; 591 # ifdef DEBUG 592 if (tTd(21, 12)) 593 { 594 printf("-----rule matches:"); 595 printav(rvp); 596 } 597 # endif DEBUG 598 599 rp = *rvp; 600 if (*rp == CANONUSER) 601 { 602 rvp++; 603 rwr = rwr->r_next; 604 } 605 else if (*rp == CANONHOST) 606 { 607 rvp++; 608 rwr = NULL; 609 } 610 else if (*rp == CANONNET) 611 rwr = NULL; 612 613 /* substitute */ 614 for (avp = npvp; *rvp != NULL; rvp++) 615 { 616 rp = *rvp; 617 if (*rp == MATCHREPL) 618 { 619 register struct match *m; 620 register char **pp; 621 622 m = &mlist[rp[1] - '1']; 623 # ifdef DEBUG 624 if (tTd(21, 15)) 625 { 626 printf("$%c:", rp[1]); 627 pp = m->first; 628 while (pp <= m->last) 629 { 630 printf(" %x=\"", *pp); 631 (void) fflush(stdout); 632 printf("%s\"", *pp++); 633 } 634 printf("\n"); 635 } 636 # endif DEBUG 637 pp = m->first; 638 while (pp <= m->last) 639 { 640 if (avp >= &npvp[MAXATOM]) 641 { 642 syserr("rewrite: expansion too long"); 643 return; 644 } 645 *avp++ = *pp++; 646 } 647 } 648 else 649 { 650 if (avp >= &npvp[MAXATOM]) 651 { 652 syserr("rewrite: expansion too long"); 653 return; 654 } 655 *avp++ = rp; 656 } 657 } 658 *avp++ = NULL; 659 if (**npvp == CALLSUBR) 660 { 661 bmove((char *) &npvp[2], (char *) pvp, 662 (avp - npvp - 2) * sizeof *avp); 663 # ifdef DEBUG 664 if (tTd(21, 3)) 665 printf("-----callsubr %s\n", npvp[1]); 666 # endif DEBUG 667 rewrite(pvp, atoi(npvp[1])); 668 } 669 else 670 { 671 bmove((char *) npvp, (char *) pvp, 672 (avp - npvp) * sizeof *avp); 673 } 674 # ifdef DEBUG 675 if (tTd(21, 4)) 676 { 677 printf("rewritten as:"); 678 printav(pvp); 679 } 680 # endif DEBUG 681 } 682 else 683 { 684 # ifdef DEBUG 685 if (tTd(21, 10)) 686 printf("----- rule fails\n"); 687 # endif DEBUG 688 rwr = rwr->r_next; 689 } 690 } 691 692 if (Mode == MD_TEST || tTd(21, 2)) 693 { 694 printf("rewrite: ruleset %d 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 ** wildflg -- if TRUE, 'a' may have no user specified, 843 ** in which case it is to match anything. 844 ** 845 ** Returns: 846 ** TRUE -- they represent the same mailbox. 847 ** FALSE -- they don't. 848 ** 849 ** Side Effects: 850 ** none. 851 */ 852 853 bool 854 sameaddr(a, b, wildflg) 855 register ADDRESS *a; 856 register ADDRESS *b; 857 bool wildflg; 858 { 859 /* if they don't have the same mailer, forget it */ 860 if (a->q_mailer != b->q_mailer) 861 return (FALSE); 862 863 /* if the user isn't the same, we can drop out */ 864 if ((!wildflg || a->q_user[0] != '\0') && strcmp(a->q_user, b->q_user) != 0) 865 return (FALSE); 866 867 /* if the mailer ignores hosts, we have succeeded! */ 868 if (bitset(M_LOCAL, a->q_mailer->m_flags)) 869 return (TRUE); 870 871 /* otherwise compare hosts (but be careful for NULL ptrs) */ 872 if (a->q_host == NULL || b->q_host == NULL) 873 return (FALSE); 874 if (strcmp(a->q_host, b->q_host) != 0) 875 return (FALSE); 876 877 return (TRUE); 878 } 879 /* 880 ** PRINTADDR -- print address (for debugging) 881 ** 882 ** Parameters: 883 ** a -- the address to print 884 ** follow -- follow the q_next chain. 885 ** 886 ** Returns: 887 ** none. 888 ** 889 ** Side Effects: 890 ** none. 891 */ 892 893 # ifdef DEBUG 894 895 printaddr(a, follow) 896 register ADDRESS *a; 897 bool follow; 898 { 899 bool first = TRUE; 900 901 while (a != NULL) 902 { 903 first = FALSE; 904 printf("%x=", a); 905 (void) fflush(stdout); 906 printf("%s: mailer %d (%s), host `%s', user `%s'\n", a->q_paddr, 907 a->q_mailer->m_mno, a->q_mailer->m_name, a->q_host, 908 a->q_user); 909 printf("\tnext=%x, flags=%o, alias %x\n", a->q_next, a->q_flags, 910 a->q_alias); 911 printf("\thome=\"%s\", fullname=\"%s\"\n", a->q_home, 912 a->q_fullname); 913 914 if (!follow) 915 return; 916 a = a->q_next; 917 } 918 if (first) 919 printf("[NULL]\n"); 920 } 921 922 # endif DEBUG 923 /* 924 ** REMOTENAME -- return the name relative to the current mailer 925 ** 926 ** Parameters: 927 ** name -- the name to translate. 928 ** m -- the mailer that we want to do rewriting relative 929 ** to. 930 ** senderaddress -- if set, uses the sender rewriting rules 931 ** rather than the recipient rewriting rules. 932 ** 933 ** Returns: 934 ** the text string representing this address relative to 935 ** the receiving mailer. 936 ** 937 ** Side Effects: 938 ** none. 939 ** 940 ** Warnings: 941 ** The text string returned is tucked away locally; 942 ** copy it if you intend to save it. 943 */ 944 945 char * 946 remotename(name, m, senderaddress) 947 char *name; 948 struct mailer *m; 949 bool senderaddress; 950 { 951 register char **pvp; 952 char *fancy; 953 extern char *macvalue(); 954 char *oldg = macvalue('g', CurEnv); 955 static char buf[MAXNAME]; 956 char lbuf[MAXNAME]; 957 extern char **prescan(); 958 extern char *crackaddr(); 959 960 # ifdef DEBUG 961 if (tTd(12, 1)) 962 printf("remotename(%s)\n", name); 963 # endif DEBUG 964 965 /* 966 ** Do a heuristic crack of this name to extract any comment info. 967 ** This will leave the name as a comment and a $g macro. 968 */ 969 970 fancy = crackaddr(name); 971 972 /* 973 ** Turn the name into canonical form. 974 ** Normally this will be RFC 822 style, i.e., "user@domain". 975 ** If this only resolves to "user", and the "C" flag is 976 ** specified in the sending mailer, then the sender's 977 ** domain will be appended. 978 */ 979 980 pvp = prescan(name, '\0'); 981 if (pvp == NULL) 982 return (name); 983 rewrite(pvp, 3); 984 if (CurEnv->e_fromdomain != NULL) 985 { 986 /* append from domain to this address */ 987 register char **pxp = pvp; 988 989 while (*pxp != NULL && strcmp(*pxp, "@") != 0) 990 pxp++; 991 if (*pxp == NULL) 992 { 993 register char **qxq = CurEnv->e_fromdomain; 994 995 while (*qxq != NULL) 996 *pxp++ = *qxq++; 997 } 998 } 999 1000 /* 1001 ** Now do more specific rewriting. 1002 ** Rewrite using ruleset 1 or 2 depending on whether this is 1003 ** a sender address or not. 1004 ** Then run it through any receiving-mailer-specific rulesets. 1005 */ 1006 1007 if (senderaddress) 1008 { 1009 rewrite(pvp, 1); 1010 if (m->m_s_rwset > 0) 1011 rewrite(pvp, m->m_s_rwset); 1012 } 1013 else 1014 { 1015 rewrite(pvp, 2); 1016 if (m->m_r_rwset > 0) 1017 rewrite(pvp, m->m_r_rwset); 1018 } 1019 1020 /* 1021 ** Now restore the comment information we had at the beginning. 1022 */ 1023 1024 cataddr(pvp, lbuf, sizeof lbuf); 1025 define('g', lbuf); 1026 expand(fancy, buf, &buf[sizeof buf - 1], CurEnv); 1027 define('g', oldg); 1028 1029 # ifdef DEBUG 1030 if (tTd(12, 1)) 1031 printf("remotename => `%s'\n", buf); 1032 # endif DEBUG 1033 return (buf); 1034 } 1035 /* 1036 ** CANONNAME -- make name canonical 1037 ** 1038 ** This is used for SMTP and misc. printing. Given a print 1039 ** address, it strips out comments, etc. 1040 ** 1041 ** Parameters: 1042 ** name -- the name to make canonical. 1043 ** ruleset -- the canonicalizing ruleset. 1044 ** 1045 ** Returns: 1046 ** pointer to canonical name. 1047 ** 1048 ** Side Effects: 1049 ** none. 1050 ** 1051 ** Warning: 1052 ** result is saved in static buf; future calls will trash it. 1053 */ 1054 1055 char * 1056 canonname(name, ruleset) 1057 char *name; 1058 int ruleset; 1059 { 1060 static char nbuf[MAXNAME]; 1061 register char **pvp; 1062 1063 pvp = prescan(name, '\0'); 1064 rewrite(pvp, 3); 1065 rewrite(pvp, ruleset); 1066 cataddr(pvp, nbuf, sizeof nbuf); 1067 return (nbuf); 1068 } 1069