1: # include "sendmail.h" 2: 3: SCCSID(@(#)parseaddr.c 4.1 7/25/83); 4: 5: /* 6: ** PARSEADDR -- 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: ** delim -- the character to terminate the address, passed 32: ** to prescan. 33: ** 34: ** Returns: 35: ** A pointer to the address descriptor header (`a' if 36: ** `a' is non-NULL). 37: ** NULL on error. 38: ** 39: ** Side Effects: 40: ** none 41: */ 42: 43: /* following delimiters are inherent to the internal algorithms */ 44: # define DELIMCHARS "$()<>,;\\\"\r\n" /* word delimiters */ 45: 46: ADDRESS * 47: parseaddr(addr, a, copyf, delim) 48: char *addr; 49: register ADDRESS *a; 50: int copyf; 51: char delim; 52: { 53: register char **pvp; 54: register struct mailer *m; 55: extern char **prescan(); 56: extern ADDRESS *buildaddr(); 57: 58: /* 59: ** Initialize and prescan address. 60: */ 61: 62: CurEnv->e_to = addr; 63: # ifdef DEBUG 64: if (tTd(20, 1)) 65: printf("\n--parseaddr(%s)\n", addr); 66: # endif DEBUG 67: 68: pvp = prescan(addr, delim); 69: if (pvp == NULL) 70: return (NULL); 71: 72: /* 73: ** Apply rewriting rules. 74: ** Ruleset 0 does basic parsing. It must resolve. 75: */ 76: 77: rewrite(pvp, 3); 78: rewrite(pvp, 0); 79: 80: /* 81: ** See if we resolved to a real mailer. 82: */ 83: 84: if (pvp[0][0] != CANONNET) 85: { 86: setstat(EX_USAGE); 87: usrerr("cannot resolve name"); 88: return (NULL); 89: } 90: 91: /* 92: ** Build canonical address from pvp. 93: */ 94: 95: a = buildaddr(pvp, a); 96: if (a == NULL) 97: return (NULL); 98: m = a->q_mailer; 99: 100: /* 101: ** Make local copies of the host & user and then 102: ** transport them out. 103: */ 104: 105: if (copyf > 0) 106: { 107: extern char *DelimChar; 108: char savec = *DelimChar; 109: 110: *DelimChar = '\0'; 111: a->q_paddr = newstr(addr); 112: *DelimChar = savec; 113: } 114: else 115: a->q_paddr = addr; 116: if (copyf >= 0) 117: { 118: if (a->q_host != NULL) 119: a->q_host = newstr(a->q_host); 120: else 121: a->q_host = ""; 122: if (a->q_user != a->q_paddr) 123: a->q_user = newstr(a->q_user); 124: } 125: 126: /* 127: ** Do UPPER->lower case mapping unless inhibited. 128: */ 129: 130: if (!bitnset(M_HST_UPPER, m->m_flags)) 131: makelower(a->q_host); 132: if (!bitnset(M_USR_UPPER, m->m_flags)) 133: makelower(a->q_user); 134: 135: /* 136: ** Compute return value. 137: */ 138: 139: # ifdef DEBUG 140: if (tTd(20, 1)) 141: { 142: printf("parseaddr-->"); 143: printaddr(a, FALSE); 144: } 145: # endif DEBUG 146: 147: return (a); 148: } 149: /* 150: ** PRESCAN -- Prescan name and make it canonical 151: ** 152: ** Scans a name and turns it into a set of tokens. This process 153: ** deletes blanks and comments (in parentheses). 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|B, SPC|MB, ONE|B, 197: /*ATM*/ OPR|B, ATM, QST|B, SPC|MB, ONE|B, 198: /*QST*/ QST, QST, OPR, 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 int 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: else if (delim == ' ' && isspace(c)) 318: c = ' '; 319: 320: if (c == NOCHAR) 321: continue; 322: 323: /* see if this is end of input */ 324: if (c == delim && anglecnt <= 0 && state != QST) 325: break; 326: 327: newstate = StateTab[state][toktype(c)]; 328: # ifdef DEBUG 329: if (tTd(22, 101)) 330: printf("ns=%02o\n", newstate); 331: # endif DEBUG 332: state = newstate & TYPE; 333: if (bitset(M, newstate)) 334: c = NOCHAR; 335: if (bitset(B, newstate)) 336: break; 337: } 338: 339: /* new token */ 340: if (tok != q) 341: { 342: *q++ = '\0'; 343: # ifdef DEBUG 344: if (tTd(22, 36)) 345: { 346: printf("tok="); 347: xputs(tok); 348: putchar('\n'); 349: } 350: # endif DEBUG 351: if (avp >= &av[MAXATOM]) 352: { 353: syserr("prescan: too many tokens"); 354: DelimChar = p; 355: return (NULL); 356: } 357: *avp++ = tok; 358: } 359: } while (c != '\0' && (c != delim || anglecnt > 0)); 360: *avp = NULL; 361: DelimChar = --p; 362: if (cmntcnt > 0) 363: usrerr("Unbalanced '('"); 364: else if (anglecnt > 0) 365: usrerr("Unbalanced '<'"); 366: else if (state == QST) 367: usrerr("Unbalanced '\"'"); 368: else if (av[0] != NULL) 369: return (av); 370: return (NULL); 371: } 372: /* 373: ** TOKTYPE -- return token type 374: ** 375: ** Parameters: 376: ** c -- the character in question. 377: ** 378: ** Returns: 379: ** Its type. 380: ** 381: ** Side Effects: 382: ** none. 383: */ 384: 385: toktype(c) 386: register char c; 387: { 388: static char buf[50]; 389: static bool firstime = TRUE; 390: 391: if (firstime) 392: { 393: firstime = FALSE; 394: expand("$o", buf, &buf[sizeof buf - 1], CurEnv); 395: (void) strcat(buf, DELIMCHARS); 396: } 397: if (c == MATCHCLASS || c == MATCHREPL || c == MATCHNCLASS) 398: return (ONE); 399: if (c == '"') 400: return (QST); 401: if (!isascii(c)) 402: return (ATM); 403: if (isspace(c) || c == ')') 404: return (SPC); 405: if (iscntrl(c) || index(buf, c) != NULL) 406: return (OPR); 407: return (ATM); 408: } 409: /* 410: ** REWRITE -- apply rewrite rules to token vector. 411: ** 412: ** This routine is an ordered production system. Each rewrite 413: ** rule has a LHS (called the pattern) and a RHS (called the 414: ** rewrite); 'rwr' points the the current rewrite rule. 415: ** 416: ** For each rewrite rule, 'avp' points the address vector we 417: ** are trying to match against, and 'pvp' points to the pattern. 418: ** If pvp points to a special match value (MATCHZANY, MATCHANY, 419: ** MATCHONE, MATCHCLASS, MATCHNCLASS) then the address in avp 420: ** matched is saved away in the match vector (pointed to by 'mvp'). 421: ** 422: ** When a match between avp & pvp does not match, we try to 423: ** back out. If we back up over MATCHONE, MATCHCLASS, or MATCHNCLASS 424: ** we must also back out the match in mvp. If we reach a 425: ** MATCHANY or MATCHZANY we just extend the match and start 426: ** over again. 427: ** 428: ** When we finally match, we rewrite the address vector 429: ** and try over again. 430: ** 431: ** Parameters: 432: ** pvp -- pointer to token vector. 433: ** 434: ** Returns: 435: ** none. 436: ** 437: ** Side Effects: 438: ** pvp is modified. 439: */ 440: 441: struct match 442: { 443: char **first; /* first token matched */ 444: char **last; /* last token matched */ 445: }; 446: 447: # define MAXMATCH 9 /* max params per rewrite */ 448: 449: 450: rewrite(pvp, ruleset) 451: char **pvp; 452: int ruleset; 453: { 454: register char *ap; /* address pointer */ 455: register char *rp; /* rewrite pointer */ 456: register char **avp; /* address vector pointer */ 457: register char **rvp; /* rewrite vector pointer */ 458: register struct match *mlp; /* cur ptr into mlist */ 459: register struct rewrite *rwr; /* pointer to current rewrite rule */ 460: struct match mlist[MAXMATCH]; /* stores match on LHS */ 461: char *npvp[MAXATOM+1]; /* temporary space for rebuild */ 462: extern bool sameword(); 463: 464: if (OpMode == MD_TEST || tTd(21, 2)) 465: { 466: printf("rewrite: ruleset %2d input:", ruleset); 467: printav(pvp); 468: } 469: if (pvp == NULL) 470: return; 471: 472: /* 473: ** Run through the list of rewrite rules, applying 474: ** any that match. 475: */ 476: 477: for (rwr = RewriteRules[ruleset]; rwr != NULL; ) 478: { 479: # ifdef DEBUG 480: if (tTd(21, 12)) 481: { 482: printf("-----trying rule:"); 483: printav(rwr->r_lhs); 484: } 485: # endif DEBUG 486: 487: /* try to match on this rule */ 488: mlp = mlist; 489: rvp = rwr->r_lhs; 490: avp = pvp; 491: while ((ap = *avp) != NULL || *rvp != NULL) 492: { 493: rp = *rvp; 494: # ifdef DEBUG 495: if (tTd(21, 35)) 496: { 497: printf("ap="); 498: xputs(ap); 499: printf(", rp="); 500: xputs(rp); 501: printf("\n"); 502: } 503: # endif DEBUG 504: if (rp == NULL) 505: { 506: /* end-of-pattern before end-of-address */ 507: goto backup; 508: } 509: if (ap == NULL && *rp != MATCHZANY) 510: { 511: /* end-of-input */ 512: break; 513: } 514: 515: switch (*rp) 516: { 517: register STAB *s; 518: 519: case MATCHCLASS: 520: case MATCHNCLASS: 521: /* match any token in (not in) a class */ 522: s = stab(ap, ST_CLASS, ST_FIND); 523: if (s == NULL || !bitnset(rp[1], s->s_class)) 524: { 525: if (*rp == MATCHCLASS) 526: goto backup; 527: } 528: else if (*rp == MATCHNCLASS) 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: *rp == MATCHNCLASS) 576: { 577: /* back out binding */ 578: mlp--; 579: } 580: } 581: 582: if (rvp < rwr->r_lhs) 583: { 584: /* total failure to match */ 585: break; 586: } 587: } 588: 589: /* 590: ** See if we successfully matched 591: */ 592: 593: if (rvp < rwr->r_lhs || *rvp != NULL) 594: { 595: # ifdef DEBUG 596: if (tTd(21, 10)) 597: printf("----- rule fails\n"); 598: # endif DEBUG 599: rwr = rwr->r_next; 600: continue; 601: } 602: 603: rvp = rwr->r_rhs; 604: # ifdef DEBUG 605: if (tTd(21, 12)) 606: { 607: printf("-----rule matches:"); 608: printav(rvp); 609: } 610: # endif DEBUG 611: 612: rp = *rvp; 613: if (*rp == CANONUSER) 614: { 615: rvp++; 616: rwr = rwr->r_next; 617: } 618: else if (*rp == CANONHOST) 619: { 620: rvp++; 621: rwr = NULL; 622: } 623: else if (*rp == CANONNET) 624: rwr = NULL; 625: 626: /* substitute */ 627: for (avp = npvp; *rvp != NULL; rvp++) 628: { 629: register struct match *m; 630: register char **pp; 631: 632: rp = *rvp; 633: if (*rp != MATCHREPL) 634: { 635: if (avp >= &npvp[MAXATOM]) 636: { 637: syserr("rewrite: expansion too long"); 638: return; 639: } 640: *avp++ = rp; 641: continue; 642: } 643: 644: /* substitute from LHS */ 645: m = &mlist[rp[1] - '1']; 646: # ifdef DEBUG 647: if (tTd(21, 15)) 648: { 649: printf("$%c:", rp[1]); 650: pp = m->first; 651: while (pp <= m->last) 652: { 653: printf(" %x=\"", *pp); 654: (void) fflush(stdout); 655: printf("%s\"", *pp++); 656: } 657: printf("\n"); 658: } 659: # endif DEBUG 660: pp = m->first; 661: while (pp <= m->last) 662: { 663: if (avp >= &npvp[MAXATOM]) 664: { 665: syserr("rewrite: expansion too long"); 666: return; 667: } 668: *avp++ = *pp++; 669: } 670: } 671: *avp++ = NULL; 672: if (**npvp == CALLSUBR) 673: { 674: bmove((char *) &npvp[2], (char *) pvp, 675: (avp - npvp - 2) * sizeof *avp); 676: # ifdef DEBUG 677: if (tTd(21, 3)) 678: printf("-----callsubr %s\n", npvp[1]); 679: # endif DEBUG 680: rewrite(pvp, atoi(npvp[1])); 681: } 682: else 683: { 684: bmove((char *) npvp, (char *) pvp, 685: (avp - npvp) * sizeof *avp); 686: } 687: # ifdef DEBUG 688: if (tTd(21, 4)) 689: { 690: printf("rewritten as:"); 691: printav(pvp); 692: } 693: # endif DEBUG 694: } 695: 696: if (OpMode == MD_TEST || tTd(21, 2)) 697: { 698: printf("rewrite: ruleset %2d 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 == CANONHOST) 742: { 743: setstat(atoi(*++tv)); 744: tv++; 745: } 746: if (**tv != CANONUSER) 747: syserr("buildaddr: error: no user"); 748: buf[0] = '\0'; 749: while (*++tv != NULL) 750: { 751: if (buf[0] != '\0') 752: (void) strcat(buf, " "); 753: (void) strcat(buf, *tv); 754: } 755: usrerr(buf); 756: return (NULL); 757: } 758: for (mp = Mailer; (m = *mp++) != NULL; ) 759: { 760: if (sameword(m->m_name, *tv)) 761: break; 762: } 763: if (m == NULL) 764: { 765: syserr("buildaddr: unknown net %s", *tv); 766: return (NULL); 767: } 768: a->q_mailer = m; 769: 770: /* figure out what host (if any) */ 771: tv++; 772: if (!bitnset(M_LOCAL, m->m_flags)) 773: { 774: if (**tv++ != CANONHOST) 775: { 776: syserr("buildaddr: no host"); 777: return (NULL); 778: } 779: buf[0] = '\0'; 780: while (*tv != NULL && **tv != CANONUSER) 781: (void) strcat(buf, *tv++); 782: a->q_host = newstr(buf); 783: } 784: else 785: a->q_host = NULL; 786: 787: /* figure out the user */ 788: if (**tv != CANONUSER) 789: { 790: syserr("buildaddr: no user"); 791: return (NULL); 792: } 793: rewrite(++tv, 4); 794: cataddr(tv, buf, sizeof buf); 795: a->q_user = buf; 796: 797: return (a); 798: } 799: /* 800: ** CATADDR -- concatenate pieces of addresses (putting in <LWSP> subs) 801: ** 802: ** Parameters: 803: ** pvp -- parameter vector to rebuild. 804: ** buf -- buffer to build the string into. 805: ** sz -- size of buf. 806: ** 807: ** Returns: 808: ** none. 809: ** 810: ** Side Effects: 811: ** Destroys buf. 812: */ 813: 814: cataddr(pvp, buf, sz) 815: char **pvp; 816: char *buf; 817: register int sz; 818: { 819: bool oatomtok = FALSE; 820: bool natomtok = FALSE; 821: register int i; 822: register char *p; 823: 824: if (pvp == NULL) 825: { 826: strcpy(buf, ""); 827: return; 828: } 829: p = buf; 830: sz -= 2; 831: while (*pvp != NULL && (i = strlen(*pvp)) < sz) 832: { 833: natomtok = (toktype(**pvp) == ATM); 834: if (oatomtok && natomtok) 835: *p++ = SpaceSub; 836: (void) strcpy(p, *pvp); 837: oatomtok = natomtok; 838: p += i; 839: sz -= i + 1; 840: pvp++; 841: } 842: *p = '\0'; 843: } 844: /* 845: ** SAMEADDR -- Determine if two addresses are the same 846: ** 847: ** This is not just a straight comparison -- if the mailer doesn't 848: ** care about the host we just ignore it, etc. 849: ** 850: ** Parameters: 851: ** a, b -- pointers to the internal forms to compare. 852: ** 853: ** Returns: 854: ** TRUE -- they represent the same mailbox. 855: ** FALSE -- they don't. 856: ** 857: ** Side Effects: 858: ** none. 859: */ 860: 861: bool 862: sameaddr(a, b) 863: register ADDRESS *a; 864: register ADDRESS *b; 865: { 866: /* if they don't have the same mailer, forget it */ 867: if (a->q_mailer != b->q_mailer) 868: return (FALSE); 869: 870: /* if the user isn't the same, we can drop out */ 871: if (strcmp(a->q_user, b->q_user) != 0) 872: return (FALSE); 873: 874: /* if the mailer ignores hosts, we have succeeded! */ 875: if (bitnset(M_LOCAL, a->q_mailer->m_flags)) 876: return (TRUE); 877: 878: /* otherwise compare hosts (but be careful for NULL ptrs) */ 879: if (a->q_host == NULL || b->q_host == NULL) 880: return (FALSE); 881: if (strcmp(a->q_host, b->q_host) != 0) 882: return (FALSE); 883: 884: return (TRUE); 885: } 886: /* 887: ** PRINTADDR -- print address (for debugging) 888: ** 889: ** Parameters: 890: ** a -- the address to print 891: ** follow -- follow the q_next chain. 892: ** 893: ** Returns: 894: ** none. 895: ** 896: ** Side Effects: 897: ** none. 898: */ 899: 900: # ifdef DEBUG 901: 902: printaddr(a, follow) 903: register ADDRESS *a; 904: bool follow; 905: { 906: bool first = TRUE; 907: 908: while (a != NULL) 909: { 910: first = FALSE; 911: printf("%x=", a); 912: (void) fflush(stdout); 913: printf("%s: mailer %d (%s), host `%s', user `%s'\n", a->q_paddr, 914: a->q_mailer->m_mno, a->q_mailer->m_name, a->q_host, 915: a->q_user); 916: printf("\tnext=%x, flags=%o, alias %x\n", a->q_next, a->q_flags, 917: a->q_alias); 918: printf("\thome=\"%s\", fullname=\"%s\"\n", a->q_home, 919: a->q_fullname); 920: 921: if (!follow) 922: return; 923: a = a->q_next; 924: } 925: if (first) 926: printf("[NULL]\n"); 927: } 928: 929: # endif DEBUG 930: /* 931: ** REMOTENAME -- return the name relative to the current mailer 932: ** 933: ** Parameters: 934: ** name -- the name to translate. 935: ** m -- the mailer that we want to do rewriting relative 936: ** to. 937: ** senderaddress -- if set, uses the sender rewriting rules 938: ** rather than the recipient rewriting rules. 939: ** canonical -- if set, strip out any comment information, 940: ** etc. 941: ** 942: ** Returns: 943: ** the text string representing this address relative to 944: ** the receiving mailer. 945: ** 946: ** Side Effects: 947: ** none. 948: ** 949: ** Warnings: 950: ** The text string returned is tucked away locally; 951: ** copy it if you intend to save it. 952: */ 953: 954: char * 955: remotename(name, m, senderaddress, canonical) 956: char *name; 957: struct mailer *m; 958: bool senderaddress; 959: bool canonical; 960: { 961: register char **pvp; 962: char *fancy; 963: extern char *macvalue(); 964: char *oldg = macvalue('g', CurEnv); 965: static char buf[MAXNAME]; 966: char lbuf[MAXNAME]; 967: extern char **prescan(); 968: extern char *crackaddr(); 969: 970: # ifdef DEBUG 971: if (tTd(12, 1)) 972: printf("remotename(%s)\n", name); 973: # endif DEBUG 974: 975: /* don't do anything if we are tagging it as special */ 976: if ((senderaddress ? m->m_s_rwset : m->m_r_rwset) < 0) 977: return (name); 978: 979: /* 980: ** Do a heuristic crack of this name to extract any comment info. 981: ** This will leave the name as a comment and a $g macro. 982: */ 983: 984: if (canonical) 985: fancy = "$g"; 986: else 987: fancy = crackaddr(name); 988: 989: /* 990: ** Turn the name into canonical form. 991: ** Normally this will be RFC 822 style, i.e., "user@domain". 992: ** If this only resolves to "user", and the "C" flag is 993: ** specified in the sending mailer, then the sender's 994: ** domain will be appended. 995: */ 996: 997: pvp = prescan(name, '\0'); 998: if (pvp == NULL) 999: return (name); 1000: rewrite(pvp, 3); 1001: if (CurEnv->e_fromdomain != NULL) 1002: { 1003: /* append from domain to this address */ 1004: register char **pxp = pvp; 1005: 1006: /* see if there is an "@domain" in the current name */ 1007: while (*pxp != NULL && strcmp(*pxp, "@") != 0) 1008: pxp++; 1009: if (*pxp == NULL) 1010: { 1011: /* no.... append the "@domain" from the sender */ 1012: register char **qxq = CurEnv->e_fromdomain; 1013: 1014: while ((*pxp++ = *qxq++) != NULL) 1015: continue; 1016: rewrite(pvp, 3); 1017: } 1018: } 1019: 1020: /* 1021: ** Do more specific rewriting. 1022: ** Rewrite using ruleset 1 or 2 depending on whether this is 1023: ** a sender address or not. 1024: ** Then run it through any receiving-mailer-specific rulesets. 1025: */ 1026: 1027: if (senderaddress) 1028: { 1029: rewrite(pvp, 1); 1030: if (m->m_s_rwset > 0) 1031: rewrite(pvp, m->m_s_rwset); 1032: } 1033: else 1034: { 1035: rewrite(pvp, 2); 1036: if (m->m_r_rwset > 0) 1037: rewrite(pvp, m->m_r_rwset); 1038: } 1039: 1040: /* 1041: ** Do any final sanitation the address may require. 1042: ** This will normally be used to turn internal forms 1043: ** (e.g., user@host.LOCAL) into external form. This 1044: ** may be used as a default to the above rules. 1045: */ 1046: 1047: rewrite(pvp, 4); 1048: 1049: /* 1050: ** Now restore the comment information we had at the beginning. 1051: */ 1052: 1053: cataddr(pvp, lbuf, sizeof lbuf); 1054: define('g', lbuf, CurEnv); 1055: expand(fancy, buf, &buf[sizeof buf - 1], CurEnv); 1056: define('g', oldg, CurEnv); 1057: 1058: # ifdef DEBUG 1059: if (tTd(12, 1)) 1060: printf("remotename => `%s'\n", buf); 1061: # endif DEBUG 1062: return (buf); 1063: }