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