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