|
|
1.1 ! root 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., [email protected]) 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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.