|
|
1.1 ! root 1: #ident "@(#)optim.c 1.4 'attmail mail(1) command'" ! 2: #ident "@(#)mailx:optim.c 1.5.2.1" ! 3: /* Copyright (c) 1984 AT&T */ ! 4: /* All Rights Reserved */ ! 5: ! 6: /* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T */ ! 7: /* The copyright notice above does not evidence any */ ! 8: /* actual or intended publication of such source code. */ ! 9: ! 10: #ident "@(#)mailx:optim.c 1.5" ! 11: ! 12: /* ! 13: * mailx -- a modified version of a University of California at Berkeley ! 14: * mail program ! 15: * ! 16: * Network name modification routines. ! 17: */ ! 18: ! 19: #include "rcv.h" ! 20: #include "configdefs.h" ! 21: ! 22: static char *arpafix(); ! 23: static char *lasthost(); ! 24: static char *makeremote(); ! 25: static int mstash(); ! 26: static int mtype(); ! 27: static int netlook(); ! 28: static int nettype(); ! 29: static int ntype(); ! 30: static char *revarpa(); ! 31: static char *tackon(); ! 32: static struct xtrahash *xlocate(); ! 33: static int yyinit(); ! 34: static int yylex(); ! 35: ! 36: /* ! 37: * Map a name into the correct network "view" of the ! 38: * name. This is done by prepending the name with the ! 39: * network address of the sender, then optimizing away ! 40: * nonsense. ! 41: */ ! 42: ! 43: char * ! 44: netmap(name, from) ! 45: char name[], from[]; ! 46: { ! 47: char nbuf[BUFSIZ], ret[BUFSIZ]; ! 48: register char *cp, *oname; ! 49: ! 50: if (debug) fprintf(stderr, "netmap(name '%s', from '%s')\n", name, from); ! 51: if (strlen(from) == 0) ! 52: return(name); ! 53: if (any('@', name) || any('%', name)) ! 54: return(arpafix(name, from)); ! 55: if (any('@', from) || any('%', from)) ! 56: return(unuucp(makeremote(name, from))); ! 57: if (value("onehop") && (cp = strchr(name, '!')) && cp > name) ! 58: strcpy(nbuf, name); ! 59: else { ! 60: from = tackon(host, from); ! 61: *strrchr(from, '!') = 0; ! 62: name = tackon(lasthost(from), name); ! 63: while (((cp = lasthost(from)) != 0) && ishost(cp, name)) { ! 64: oname = name; ! 65: name = strchr(name, '!') + 1; ! 66: if (cp == from) { ! 67: from[strlen(from)] = '!'; ! 68: if (value("mustbang") && !strchr(name, '!')) ! 69: name = oname; ! 70: return(unuucp(name)); ! 71: } ! 72: *--cp = 0; ! 73: } ! 74: from[strlen(from)] = '!'; ! 75: from = strchr(from, '!') + 1; ! 76: sprintf(nbuf, "%s!%s", from, name); ! 77: } ! 78: strcpy(ret, nbuf); ! 79: cp = revarpa(ret); ! 80: if (debug) fprintf(stderr, "wind up with '%s'\n", name); ! 81: if (!icequal(name, cp)) ! 82: return(unuucp(savestr(cp))); ! 83: return(unuucp(name)); ! 84: } ! 85: ! 86: /* ! 87: * Stick a host on the beginning of a uucp ! 88: * address if it isn't there already. ! 89: */ ! 90: static char * ! 91: tackon(sys, rest) ! 92: char *sys, *rest; ! 93: { ! 94: while (*rest == '!') ! 95: rest++; ! 96: if (!ishost(sys, rest)) { ! 97: char *r = salloc(strlen(sys) + strlen(rest) + 2); ! 98: sprintf(r, "%s!%s", sys, rest); ! 99: rest = r; ! 100: } ! 101: return rest; ! 102: } ! 103: ! 104: /* ! 105: * Check equality of the first host in a uucp address. ! 106: */ ! 107: ishost(sys, rest) ! 108: char *sys, *rest; ! 109: { ! 110: while (*sys && *sys == *rest) ! 111: sys++, rest++; ! 112: return(*sys == 0 && *rest == '!'); ! 113: } ! 114: ! 115: /* ! 116: * Return last host in a uucp address. ! 117: */ ! 118: static char * ! 119: lasthost(addr) ! 120: char *addr; ! 121: { ! 122: char *r = strrchr(addr, '!'); ! 123: return r ? ++r : addr; ! 124: } ! 125: ! 126: /* ! 127: * Optionally translate an old format uucp name into a new one, e.g. ! 128: * "mach1!mach2!user" becomes "[email protected]". This optional because ! 129: * some information is necessarily lost (e.g. the route it got here ! 130: * via) and if we don't have the host in our routing tables, we lose. ! 131: */ ! 132: char * ! 133: unuucp(name) ! 134: char *name; ! 135: { ! 136: register char *np, *hp, *cp; ! 137: char result[100]; ! 138: char tname[300]; ! 139: ! 140: if (UnUUCP==0 && ! 141: ((cp = value("conv"))==NOSTR || strcmp(cp, "internet"))) ! 142: return name; ! 143: if (debug) fprintf(stderr, "unuucp(%s)\n", name); ! 144: strcpy(tname, name); ! 145: np = strrchr(tname, '!'); ! 146: if (np == NOSTR) ! 147: return name; ! 148: *np++ = 0; ! 149: hp = strrchr(tname, '!'); ! 150: if (hp == NOSTR) ! 151: hp = tname; ! 152: else ! 153: *hp++ = 0; ! 154: cp = strchr(np, '@'); ! 155: if (cp == NOSTR) ! 156: cp = strchr(np, '%'); ! 157: if (cp) ! 158: *cp = 0; ! 159: if (debug) fprintf(stderr, "host %s, name %s\n", hp, np); ! 160: sprintf(result, "%s@%s.UUCP", np, hp); ! 161: if (debug) fprintf(stderr, "unuucp returns %s\n", result); ! 162: return savestr(result); ! 163: } ! 164: ! 165: /* ! 166: * Turn a network machine name into a unique character ! 167: */ ! 168: static int ! 169: netlook(machine, attnet) ! 170: char machine[]; ! 171: { ! 172: register struct netmach *np; ! 173: register char *cp, *cp2; ! 174: char nbuf[BUFSIZ]; ! 175: ! 176: /* ! 177: * Make into lower case. ! 178: */ ! 179: for (cp = machine, cp2 = nbuf; ! 180: *cp && cp2 < &nbuf[BUFSIZ-1]; ! 181: *cp2++ = tolower(*cp++)) ! 182: /*nothing*/; ! 183: *cp2 = 0; ! 184: ! 185: /* ! 186: * If a single letter machine, look through those first. ! 187: */ ! 188: ! 189: if (strlen(nbuf) == 1) ! 190: for (np = netmach; np->nt_mid != 0; np++) ! 191: if (np->nt_mid == nbuf[0]) ! 192: return(nbuf[0]); ! 193: ! 194: /* ! 195: * Look for usual name ! 196: */ ! 197: ! 198: for (np = netmach; np->nt_mid != 0; np++) ! 199: if (strcmp(np->nt_machine, nbuf) == 0) ! 200: return(np->nt_mid); ! 201: ! 202: /* ! 203: * Look in side hash table. ! 204: */ ! 205: ! 206: return(mstash(nbuf, attnet)); ! 207: } ! 208: ! 209: /* ! 210: * Deal with arpa net addresses. The way this is done is strange. ! 211: * In particular, if the destination arpa net host is not Berkeley, ! 212: * then the address is correct as stands. Otherwise, we strip off ! 213: * the trailing @Berkeley, then cook up a phony person for it to ! 214: * be from and optimize the result. ! 215: */ ! 216: static char * ! 217: arpafix(name, from) ! 218: char name[]; ! 219: char from[]; ! 220: { ! 221: register char *cp; ! 222: register int arpamach; ! 223: char newname[BUFSIZ]; ! 224: ! 225: if (debug) { ! 226: fprintf(stderr, "arpafix(%s, %s)\n", name, from); ! 227: } ! 228: cp = strrchr(name, '@'); ! 229: if (cp == NOSTR) ! 230: cp = strrchr(name, '%'); ! 231: if (cp == NOSTR) { ! 232: fprintf(stderr, "Somethings amiss -- no @ or %% in arpafix\n"); ! 233: return(name); ! 234: } ! 235: cp++; ! 236: arpamach = netlook(cp, '@'); ! 237: if (debug) fprintf(stderr, "cp '%s', arpamach %o, nettypes arpamach %o LOCAL %o\n", cp, arpamach, nettype(arpamach), nettype(LOCAL)); ! 238: if (arpamach == 0) { ! 239: if (debug) ! 240: fprintf(stderr, "machine %s unknown, uses: %s\n", cp, name); ! 241: return(name); ! 242: } ! 243: if (((nettype(arpamach) & nettype(LOCAL)) & ~AN) == 0) { ! 244: if (debug) ! 245: fprintf(stderr, "machine %s known but remote, uses: %s\n", ! 246: cp, name); ! 247: return(name); ! 248: } ! 249: strcpy(newname, name); ! 250: cp = strrchr(newname, '@'); ! 251: if (cp == NOSTR) ! 252: cp = strrchr(newname, '%'); ! 253: *cp = 0; ! 254: if (debug) fprintf(stderr, "local address, return '%s'\n", newname); ! 255: return(savestr(newname)); ! 256: } ! 257: ! 258: /* ! 259: * We have name with no @'s in it, and from with @'s. ! 260: * Assume that name is meaningful only on the site in from. ! 261: */ ! 262: static char * ! 263: makeremote(name, from) ! 264: char name[]; ! 265: char from[]; ! 266: { ! 267: register char *cp; ! 268: static char rbuf[200]; ! 269: ! 270: if (debug) fprintf(stderr, "makeremote(%s, %s) returns ", name, from); ! 271: strcpy(rbuf, name); ! 272: cp = strrchr(from, '@'); ! 273: if (cp == NOSTR) ! 274: cp = strrchr(from, '%'); ! 275: strcat(rbuf, cp); ! 276: if (debug) fprintf(stderr, "%s\n", rbuf); ! 277: return rbuf; ! 278: } ! 279: ! 280: /* ! 281: * Take a network machine descriptor and find the types of connected ! 282: * nets and return it. ! 283: */ ! 284: static int ! 285: nettype(mid) ! 286: { ! 287: register struct netmach *np; ! 288: ! 289: if (mid & 0200) ! 290: return(mtype(mid)); ! 291: for (np = netmach; np->nt_mid != 0; np++) ! 292: if (np->nt_mid == mid) ! 293: return(np->nt_type); ! 294: return(0); ! 295: } ! 296: ! 297: /* ! 298: * Hashing routines to salt away machines seen scanning ! 299: * networks paths that we don't know about. ! 300: */ ! 301: ! 302: #define XHSIZE 19 /* Size of extra hash table */ ! 303: #define NXMID (XHSIZE*3/4) /* Max extra machines */ ! 304: ! 305: struct xtrahash { ! 306: char *xh_name; /* Name of machine */ ! 307: short xh_mid; /* Machine ID */ ! 308: short xh_attnet; /* Attached networks */ ! 309: } xtrahash[XHSIZE]; ! 310: ! 311: static struct xtrahash *xtab[XHSIZE]; /* F: mid-->machine name */ ! 312: ! 313: static short midfree; /* Next free machine id */ ! 314: ! 315: /* ! 316: * Initialize the extra host hash table. ! 317: * Called by sreset. ! 318: */ ! 319: void ! 320: minit() ! 321: { ! 322: register struct xtrahash *xp, **tp; ! 323: ! 324: midfree = 0; ! 325: tp = &xtab[0]; ! 326: for (xp = &xtrahash[0]; xp < &xtrahash[XHSIZE]; xp++) { ! 327: xp->xh_name = NOSTR; ! 328: xp->xh_mid = 0; ! 329: xp->xh_attnet = 0; ! 330: *tp++ = (struct xtrahash *) 0; ! 331: } ! 332: } ! 333: ! 334: /* ! 335: * Stash a net name in the extra host hash table. ! 336: * If a new entry is put in the hash table, deduce what ! 337: * net the machine is attached to from the net character. ! 338: * ! 339: * If the machine is already known, add the given attached ! 340: * net to those already known. ! 341: */ ! 342: static int ! 343: mstash(name, attnet) ! 344: char name[]; ! 345: { ! 346: register struct xtrahash *xp; ! 347: int x; ! 348: ! 349: xp = xlocate(name); ! 350: if (xp == (struct xtrahash *) 0) { ! 351: printf("Ran out of machine id spots\n"); ! 352: return(0); ! 353: } ! 354: if (xp->xh_name == NOSTR) { ! 355: if (midfree >= XHSIZE) { ! 356: printf("Out of machine ids\n"); ! 357: return(0); ! 358: } ! 359: xtab[midfree] = xp; ! 360: xp->xh_name = savestr(name); ! 361: xp->xh_mid = 0200 + midfree++; ! 362: } ! 363: x = ntype(attnet); ! 364: if (x == 0) ! 365: xp->xh_attnet |= AN; ! 366: else ! 367: xp->xh_attnet |= x; ! 368: return(xp->xh_mid); ! 369: } ! 370: ! 371: /* ! 372: * Search for the given name in the hash table ! 373: * and return the pointer to it if found, or to the first ! 374: * empty slot if not found. ! 375: * ! 376: * If no free slots can be found, return 0. ! 377: */ ! 378: ! 379: static struct xtrahash * ! 380: xlocate(name) ! 381: char name[]; ! 382: { ! 383: register int h, q, i; ! 384: register char *cp; ! 385: register struct xtrahash *xp; ! 386: ! 387: for (h = 0, cp = name; *cp; h = (h << 2) + *cp++) ! 388: ; ! 389: if (h < 0 && (h = -h) < 0) ! 390: h = 0; ! 391: h = h % XHSIZE; ! 392: cp = name; ! 393: for (i = 0, q = 0; q < XHSIZE; i++, q = i * i) { ! 394: xp = &xtrahash[(h + q) % XHSIZE]; ! 395: if (xp->xh_name == NOSTR) ! 396: return(xp); ! 397: if (strcmp(cp, xp->xh_name) == 0) ! 398: return(xp); ! 399: if (h - q < 0) ! 400: q += XHSIZE; ! 401: xp = &xtrahash[(h - q) % XHSIZE]; ! 402: if (xp->xh_name == NOSTR) ! 403: return(xp); ! 404: if (strcmp(cp, xp->xh_name) == 0) ! 405: return(xp); ! 406: } ! 407: return((struct xtrahash *) 0); ! 408: } ! 409: ! 410: /* ! 411: * Return the bit mask of net's that the given extra host machine ! 412: * id has so far. ! 413: */ ! 414: static int ! 415: mtype(mid) ! 416: { ! 417: register int m; ! 418: ! 419: if ((mid & 0200) == 0) ! 420: return(0); ! 421: m = mid & 0177; ! 422: if (m >= midfree) { ! 423: printf("Use made of undefined machine id\n"); ! 424: return(0); ! 425: } ! 426: return(xtab[m]->xh_attnet); ! 427: } ! 428: ! 429: /* ! 430: * Return the network of the separator -- ! 431: * AN for arpa net ! 432: * BN for Bell labs net (e.g. UUCP, NOT Berknet) ! 433: * SN for Schmidt net (Berknet) ! 434: * 0 if we don't know. ! 435: */ ! 436: static int ! 437: ntype(nc) ! 438: register int nc; ! 439: { ! 440: register struct ntypetab *np; ! 441: ! 442: for (np = ntypetab; np->nt_char != 0; np++) ! 443: if (np->nt_char == nc) ! 444: return(np->nt_bcode); ! 445: return(0); ! 446: } ! 447: ! 448: ! 449: /* ! 450: * Code to twist around arpa net names. ! 451: */ ! 452: ! 453: #define WORD 257 /* Token for a string */ ! 454: ! 455: static char netbuf[256]; ! 456: static char *yylval; ! 457: ! 458: /* ! 459: * Reverse all of the arpa net addresses in the given name to ! 460: * be of the form "host @ user" instead of "user @ host" ! 461: * This function is its own inverse. ! 462: */ ! 463: ! 464: static char * ! 465: revarpa(str) ! 466: char str[]; ! 467: { ! 468: ! 469: if (yyinit(str) < 0) ! 470: return(NOSTR); ! 471: if (name()) ! 472: return(NOSTR); ! 473: if (strcmp(str, netbuf) == 0) ! 474: return(str); ! 475: return(savestr(netbuf)); ! 476: } ! 477: ! 478: /* ! 479: * Parse (by recursive descent) network names, using the following grammar: ! 480: * name: ! 481: * term {':' term} ! 482: * term {'^' term} ! 483: * term {'!' term} ! 484: * term '@' name ! 485: * term '%' name ! 486: * ! 487: * term: ! 488: * string of characters. ! 489: */ ! 490: ! 491: name() ! 492: { ! 493: register int t; ! 494: register char *cp; ! 495: ! 496: for (;;) { ! 497: t = yylex(); ! 498: if (t != WORD) ! 499: return(-1); ! 500: cp = yylval; ! 501: t = yylex(); ! 502: switch (t) { ! 503: case 0: ! 504: strcat(netbuf, cp); ! 505: return(0); ! 506: ! 507: case '@': ! 508: case '%': ! 509: if (name()) ! 510: return(-1); ! 511: strcat(netbuf, "@"); ! 512: strcat(netbuf, cp); ! 513: return(0); ! 514: ! 515: case WORD: ! 516: return(-1); ! 517: ! 518: default: ! 519: strcat(netbuf, cp); ! 520: stradd(netbuf, t); ! 521: } ! 522: } ! 523: } ! 524: ! 525: /* ! 526: * Scanner for network names. ! 527: */ ! 528: ! 529: static char *charp; /* Current input pointer */ ! 530: static int nexttok; /* Salted away next token */ ! 531: ! 532: /* ! 533: * Initialize the network name scanner. ! 534: */ ! 535: static int ! 536: yyinit(str) ! 537: char str[]; ! 538: { ! 539: static char lexbuf[BUFSIZ]; ! 540: ! 541: netbuf[0] = 0; ! 542: if (strlen(str) >= sizeof lexbuf - 1) ! 543: return(-1); ! 544: nexttok = 0; ! 545: strcpy(lexbuf, str); ! 546: charp = lexbuf; ! 547: return(0); ! 548: } ! 549: ! 550: /* ! 551: * Scan and return a single token. ! 552: * yylval is set to point to a scanned string. ! 553: */ ! 554: static int ! 555: yylex() ! 556: { ! 557: register char *cp, *dot; ! 558: register int s; ! 559: ! 560: if (nexttok) { ! 561: s = nexttok; ! 562: nexttok = 0; ! 563: return(s); ! 564: } ! 565: cp = charp; ! 566: while (*cp && isspace(*cp)) ! 567: cp++; ! 568: if (*cp == 0) ! 569: return(0); ! 570: if (any(*cp, metanet)) { ! 571: charp = cp+1; ! 572: return(*cp); ! 573: } ! 574: dot = cp; ! 575: while (*cp && !any(*cp, metanet) && !any(*cp, " \t")) ! 576: cp++; ! 577: if (any(*cp, metanet)) ! 578: nexttok = *cp; ! 579: if (*cp == 0) ! 580: charp = cp; ! 581: else ! 582: charp = cp+1; ! 583: *cp = 0; ! 584: yylval = dot; ! 585: return(WORD); ! 586: } ! 587: ! 588: /* ! 589: * Add a single character onto a string. ! 590: */ ! 591: ! 592: void ! 593: stradd(str, c) ! 594: register char *str; ! 595: register int c; ! 596: { ! 597: while (*str) ! 598: str++; ! 599: *str++ = (char)c; ! 600: *str = '\0'; ! 601: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.