1*1242Skas # 2*1242Skas 3*1242Skas /* 4*1242Skas * Mail -- a program for sending and receiving mail. 5*1242Skas * 6*1242Skas * Network name modification routines. 7*1242Skas */ 8*1242Skas 9*1242Skas #include "rcv.h" 10*1242Skas #include <ctype.h> 11*1242Skas 12*1242Skas static char *SccsId = "@(#)optim.c 1.1 10/08/80"; 13*1242Skas 14*1242Skas /* 15*1242Skas * Map a name into the correct network "view" of the 16*1242Skas * name. This is done by prepending the name with the 17*1242Skas * network address of the sender, then optimizing away 18*1242Skas * nonsense. 19*1242Skas */ 20*1242Skas 21*1242Skas char *metanet = "!^:%@."; 22*1242Skas 23*1242Skas char * 24*1242Skas netmap(name, from) 25*1242Skas char name[], from[]; 26*1242Skas { 27*1242Skas char nbuf[BUFSIZ], ret[BUFSIZ]; 28*1242Skas register char *cp; 29*1242Skas 30*1242Skas if (strlen(from) == 0) 31*1242Skas return(name); 32*1242Skas if (any('@', name) || any('%', name)) 33*1242Skas return(arpafix(name, from)); 34*1242Skas cp = revarpa(from); 35*1242Skas if (cp == NOSTR) 36*1242Skas return(name); 37*1242Skas strcpy(nbuf, cp); 38*1242Skas cp = &nbuf[strlen(nbuf) - 1]; 39*1242Skas while (!any(*cp, metanet) && cp > nbuf) 40*1242Skas cp--; 41*1242Skas if (cp == nbuf) 42*1242Skas return(name); 43*1242Skas *++cp = 0; 44*1242Skas strcat(nbuf, revarpa(name)); 45*1242Skas optim(nbuf, ret); 46*1242Skas cp = revarpa(ret); 47*1242Skas if (!icequal(name, cp)) 48*1242Skas return((char *) savestr(cp)); 49*1242Skas return(name); 50*1242Skas } 51*1242Skas 52*1242Skas /* 53*1242Skas * Rename the given network path to use 54*1242Skas * the kinds of names that we would right here. 55*1242Skas */ 56*1242Skas 57*1242Skas char * 58*1242Skas rename(str) 59*1242Skas char str[]; 60*1242Skas { 61*1242Skas register char *cp, *cp2; 62*1242Skas char buf[BUFSIZ], path[BUFSIZ]; 63*1242Skas register int c, host; 64*1242Skas 65*1242Skas strcpy(path, ""); 66*1242Skas for (;;) { 67*1242Skas if ((c = *cp++) == 0) 68*1242Skas break; 69*1242Skas cp2 = buf; 70*1242Skas while (!any(c, metanet) && c != 0) { 71*1242Skas *cp2++ = c; 72*1242Skas c = *cp++; 73*1242Skas } 74*1242Skas *cp2 = 0; 75*1242Skas if (c == 0) { 76*1242Skas strcat(path, buf); 77*1242Skas break; 78*1242Skas } 79*1242Skas host = netlook(buf, ntype(c)); 80*1242Skas strcat(path, netname(host)); 81*1242Skas stradd(path, c); 82*1242Skas } 83*1242Skas if (strcmp(str, path) != 0) 84*1242Skas return(savestr(path)); 85*1242Skas return(str); 86*1242Skas } 87*1242Skas /* 88*1242Skas * Turn a network machine name into a unique character 89*1242Skas * + give connection-to status. BN -- connected to Bell Net. 90*1242Skas * AN -- connected to ARPA net, SN -- connected to Schmidt net. 91*1242Skas * CN -- connected to COCANET. 92*1242Skas */ 93*1242Skas 94*1242Skas #define AN 1 /* Connected to ARPA net */ 95*1242Skas #define BN 2 /* Connected to BTL net */ 96*1242Skas #define CN 4 /* Connected to COCANET */ 97*1242Skas #define SN 8 /* Connected to Schmidt net */ 98*1242Skas 99*1242Skas struct netmach { 100*1242Skas char *nt_machine; 101*1242Skas char nt_mid; 102*1242Skas short nt_type; 103*1242Skas } netmach[] = { 104*1242Skas "a", 'a', SN, 105*1242Skas "b", 'b', SN, 106*1242Skas "c", 'c', SN, 107*1242Skas "d", 'd', SN, 108*1242Skas "e", 'e', SN, 109*1242Skas "f", 'f', SN, 110*1242Skas "g", 'g', SN, 111*1242Skas "ingres", 'i', AN|SN, 112*1242Skas "ing70", 'i', AN|SN, 113*1242Skas "berkeley", 'i', AN|SN, 114*1242Skas "ingvax", 'j', SN, 115*1242Skas "virus", 'k', SN, 116*1242Skas "vlsi", 'l', SN, 117*1242Skas "image", 'm', SN, 118*1242Skas "esvax", 'o', SN, 119*1242Skas "sesm", 'o', SN, 120*1242Skas "q", 'q', SN, 121*1242Skas "research", 'R', BN, 122*1242Skas "arpavax", 'r', SN, 123*1242Skas "src", 's', SN, 124*1242Skas "mathstat", 't', SN, 125*1242Skas "csvax", 'v', BN|SN, 126*1242Skas "vax", 'v', BN|SN, 127*1242Skas "ucb", 'v', BN|SN, 128*1242Skas "ucbvax", 'v', BN|SN, 129*1242Skas "vax135", 'x', BN, 130*1242Skas "cory", 'y', SN, 131*1242Skas "eecs40", 'z', SN, 132*1242Skas 0, 0, 0 133*1242Skas }; 134*1242Skas 135*1242Skas netlook(machine, attnet) 136*1242Skas char machine[]; 137*1242Skas { 138*1242Skas register struct netmach *np; 139*1242Skas register char *cp, *cp2; 140*1242Skas char nbuf[20]; 141*1242Skas 142*1242Skas /* 143*1242Skas * Make into lower case. 144*1242Skas */ 145*1242Skas 146*1242Skas for (cp = machine, cp2 = nbuf; *cp; *cp2++ = little(*cp++)) 147*1242Skas ; 148*1242Skas *cp2 = 0; 149*1242Skas 150*1242Skas /* 151*1242Skas * If a single letter machine, look through those first. 152*1242Skas */ 153*1242Skas 154*1242Skas if (strlen(nbuf) == 1) 155*1242Skas for (np = netmach; np->nt_mid != 0; np++) 156*1242Skas if (np->nt_mid == nbuf[0]) 157*1242Skas return(nbuf[0]); 158*1242Skas 159*1242Skas /* 160*1242Skas * Look for usual name 161*1242Skas */ 162*1242Skas 163*1242Skas for (np = netmach; np->nt_mid != 0; np++) 164*1242Skas if (strcmp(np->nt_machine, nbuf) == 0) 165*1242Skas return(np->nt_mid); 166*1242Skas 167*1242Skas /* 168*1242Skas * Look in side hash table. 169*1242Skas */ 170*1242Skas 171*1242Skas return(mstash(nbuf, attnet)); 172*1242Skas } 173*1242Skas 174*1242Skas /* 175*1242Skas * Make a little character. 176*1242Skas */ 177*1242Skas 178*1242Skas little(c) 179*1242Skas register int c; 180*1242Skas { 181*1242Skas 182*1242Skas if (c >= 'A' && c <= 'Z') 183*1242Skas c += 'a' - 'A'; 184*1242Skas return(c); 185*1242Skas } 186*1242Skas 187*1242Skas /* 188*1242Skas * Turn a network unique character identifier into a network name. 189*1242Skas */ 190*1242Skas 191*1242Skas char * 192*1242Skas netname(mid) 193*1242Skas { 194*1242Skas register struct netmach *np; 195*1242Skas char *mlook(); 196*1242Skas 197*1242Skas if (mid & 0200) 198*1242Skas return(mlook(mid)); 199*1242Skas for (np = netmach; np->nt_mid != 0; np++) 200*1242Skas if (np->nt_mid == mid) 201*1242Skas return(np->nt_machine); 202*1242Skas return(NOSTR); 203*1242Skas } 204*1242Skas 205*1242Skas /* 206*1242Skas * Deal with arpa net addresses. The way this is done is strange. 207*1242Skas * In particular, if the destination arpa net host is not Berkeley, 208*1242Skas * then the address is correct as stands. Otherwise, we strip off 209*1242Skas * the trailing @Berkeley, then cook up a phony person for it to 210*1242Skas * be from and optimize the result. 211*1242Skas */ 212*1242Skas char * 213*1242Skas arpafix(name, from) 214*1242Skas char name[]; 215*1242Skas char from[]; 216*1242Skas { 217*1242Skas register char *cp; 218*1242Skas register int arpamach; 219*1242Skas char newname[BUFSIZ]; 220*1242Skas char fake[5]; 221*1242Skas char fakepath[20]; 222*1242Skas 223*1242Skas if (debug) { 224*1242Skas fprintf(stderr, "arpafix(%s, %s)\n", name, from); 225*1242Skas } 226*1242Skas cp = rindex(name, '@'); 227*1242Skas if (cp == NOSTR) 228*1242Skas cp = rindex(name, '%'); 229*1242Skas if (cp == NOSTR) { 230*1242Skas fprintf(stderr, "Somethings amiss -- no @ or % in arpafix\n"); 231*1242Skas return(name); 232*1242Skas } 233*1242Skas cp++; 234*1242Skas arpamach = netlook(cp, '@'); 235*1242Skas if (arpamach == 0) { 236*1242Skas if (debug) 237*1242Skas fprintf(stderr, "machine %s unknown, uses: %s\n", cp, name); 238*1242Skas return(name); 239*1242Skas } 240*1242Skas if (((nettype(arpamach) & nettype(LOCAL)) & ~AN) == 0) { 241*1242Skas if (debug) 242*1242Skas fprintf(stderr, "machine %s known but remote, uses: %s\n", 243*1242Skas cp, name); 244*1242Skas return(name); 245*1242Skas } 246*1242Skas strcpy(newname, name); 247*1242Skas cp = rindex(newname, '@'); 248*1242Skas if (cp == NOSTR) 249*1242Skas cp = rindex(newname, '%'); 250*1242Skas *cp = 0; 251*1242Skas fake[0] = arpamach; 252*1242Skas fake[1] = ':'; 253*1242Skas fake[2] = LOCAL; 254*1242Skas fake[3] = ':'; 255*1242Skas fake[4] = 0; 256*1242Skas prefer(fake); 257*1242Skas strcpy(fakepath, netname(fake[0])); 258*1242Skas stradd(fakepath, fake[1]); 259*1242Skas strcat(fakepath, "daemon"); 260*1242Skas if (debug) 261*1242Skas fprintf(stderr, "machine local, call netmap(%s, %s)\n", 262*1242Skas newname, fakepath); 263*1242Skas return(netmap(newname, fakepath)); 264*1242Skas } 265*1242Skas 266*1242Skas /* 267*1242Skas * Take a network machine descriptor and find the types of connected 268*1242Skas * nets and return it. 269*1242Skas */ 270*1242Skas 271*1242Skas nettype(mid) 272*1242Skas { 273*1242Skas register struct netmach *np; 274*1242Skas 275*1242Skas if (mid & 0200) 276*1242Skas return(mtype(mid)); 277*1242Skas for (np = netmach; np->nt_mid != 0; np++) 278*1242Skas if (np->nt_mid == mid) 279*1242Skas return(np->nt_type); 280*1242Skas return(0); 281*1242Skas } 282*1242Skas 283*1242Skas /* 284*1242Skas * Hashing routines to salt away machines seen scanning 285*1242Skas * networks paths that we don't know about. 286*1242Skas */ 287*1242Skas 288*1242Skas #define XHSIZE 19 /* Size of extra hash table */ 289*1242Skas #define NXMID (XHSIZE*3/4) /* Max extra machines */ 290*1242Skas 291*1242Skas struct xtrahash { 292*1242Skas char *xh_name; /* Name of machine */ 293*1242Skas short xh_mid; /* Machine ID */ 294*1242Skas short xh_attnet; /* Attached networks */ 295*1242Skas } xtrahash[XHSIZE]; 296*1242Skas 297*1242Skas struct xtrahash *xtab[XHSIZE]; /* F: mid-->machine name */ 298*1242Skas 299*1242Skas short midfree; /* Next free machine id */ 300*1242Skas 301*1242Skas /* 302*1242Skas * Initialize the extra host hash table. 303*1242Skas * Called by sreset. 304*1242Skas */ 305*1242Skas 306*1242Skas minit() 307*1242Skas { 308*1242Skas register struct xtrahash *xp, **tp; 309*1242Skas register int i; 310*1242Skas 311*1242Skas midfree = 0; 312*1242Skas tp = &xtab[0]; 313*1242Skas for (xp = &xtrahash[0]; xp < &xtrahash[XHSIZE]; xp++) { 314*1242Skas xp->xh_name = NOSTR; 315*1242Skas xp->xh_mid = 0; 316*1242Skas xp->xh_attnet = 0; 317*1242Skas *tp++ = (struct xtrahash *) 0; 318*1242Skas } 319*1242Skas } 320*1242Skas 321*1242Skas /* 322*1242Skas * Stash a net name in the extra host hash table. 323*1242Skas * If a new entry is put in the hash table, deduce what 324*1242Skas * net the machine is attached to from the net character. 325*1242Skas * 326*1242Skas * If the machine is already known, add the given attached 327*1242Skas * net to those already known. 328*1242Skas */ 329*1242Skas 330*1242Skas mstash(name, attnet) 331*1242Skas char name[]; 332*1242Skas { 333*1242Skas register struct xtrahash *xp; 334*1242Skas struct xtrahash *xlocate(); 335*1242Skas 336*1242Skas xp = xlocate(name); 337*1242Skas if (xp == (struct xtrahash *) 0) { 338*1242Skas printf("Ran out of machine id spots\n"); 339*1242Skas return(0); 340*1242Skas } 341*1242Skas if (xp->xh_name == NOSTR) { 342*1242Skas if (midfree >= XHSIZE) { 343*1242Skas printf("Out of machine ids\n"); 344*1242Skas return(0); 345*1242Skas } 346*1242Skas xtab[midfree] = xp; 347*1242Skas xp->xh_name = savestr(name); 348*1242Skas xp->xh_mid = 0200 + midfree++; 349*1242Skas } 350*1242Skas switch (attnet) { 351*1242Skas case '!': 352*1242Skas case '^': 353*1242Skas xp->xh_attnet |= BN; 354*1242Skas break; 355*1242Skas 356*1242Skas default: 357*1242Skas case ':': 358*1242Skas xp->xh_attnet |= SN; 359*1242Skas break; 360*1242Skas 361*1242Skas case '@': 362*1242Skas case '%': 363*1242Skas xp->xh_attnet |= AN; 364*1242Skas break; 365*1242Skas } 366*1242Skas return(xp->xh_mid); 367*1242Skas } 368*1242Skas 369*1242Skas /* 370*1242Skas * Search for the given name in the hash table 371*1242Skas * and return the pointer to it if found, or to the first 372*1242Skas * empty slot if not found. 373*1242Skas * 374*1242Skas * If no free slots can be found, return 0. 375*1242Skas */ 376*1242Skas 377*1242Skas struct xtrahash * 378*1242Skas xlocate(name) 379*1242Skas char name[]; 380*1242Skas { 381*1242Skas register int h, q, i; 382*1242Skas register char *cp; 383*1242Skas register struct xtrahash *xp; 384*1242Skas 385*1242Skas for (h = 0, cp = name; *cp; h = (h << 2) + *cp++) 386*1242Skas ; 387*1242Skas if (h < 0 && (h = -h) < 0) 388*1242Skas h = 0; 389*1242Skas h = h % XHSIZE; 390*1242Skas cp = name; 391*1242Skas for (i = 0, q = 0; q < XHSIZE; i++, q = i * i) { 392*1242Skas xp = &xtrahash[(h + q) % XHSIZE]; 393*1242Skas if (xp->xh_name == NOSTR) 394*1242Skas return(xp); 395*1242Skas if (strcmp(cp, xp->xh_name) == 0) 396*1242Skas return(xp); 397*1242Skas if (h - q < 0) 398*1242Skas q += XHSIZE; 399*1242Skas xp = &xtrahash[(h - q) % XHSIZE]; 400*1242Skas if (xp->xh_name == NOSTR) 401*1242Skas return(xp); 402*1242Skas if (strcmp(cp, xp->xh_name) == 0) 403*1242Skas return(xp); 404*1242Skas } 405*1242Skas return((struct xtrahash *) 0); 406*1242Skas } 407*1242Skas 408*1242Skas /* 409*1242Skas * Return the name from the extra host hash table corresponding 410*1242Skas * to the passed machine id. 411*1242Skas */ 412*1242Skas 413*1242Skas char * 414*1242Skas mlook(mid) 415*1242Skas { 416*1242Skas register int m; 417*1242Skas 418*1242Skas if ((mid & 0200) == 0) 419*1242Skas return(NOSTR); 420*1242Skas m = mid & 0177; 421*1242Skas if (m >= midfree) { 422*1242Skas printf("Use made of undefined machine id\n"); 423*1242Skas return(NOSTR); 424*1242Skas } 425*1242Skas return(xtab[m]->xh_name); 426*1242Skas } 427*1242Skas 428*1242Skas /* 429*1242Skas * Return the bit mask of net's that the given extra host machine 430*1242Skas * id has so far. 431*1242Skas */ 432*1242Skas 433*1242Skas mtype(mid) 434*1242Skas { 435*1242Skas register int m; 436*1242Skas 437*1242Skas if ((mid & 0200) == 0) 438*1242Skas return(0); 439*1242Skas m = mid & 0177; 440*1242Skas if (m >= midfree) { 441*1242Skas printf("Use made of undefined machine id\n"); 442*1242Skas return(0); 443*1242Skas } 444*1242Skas return(xtab[m]->xh_attnet); 445*1242Skas } 446*1242Skas 447*1242Skas /* 448*1242Skas * Take a network name and optimize it. This gloriously messy 449*1242Skas * opertions takes place as follows: the name with machine names 450*1242Skas * in it is tokenized by mapping each machine name into a single 451*1242Skas * character machine id (netlook). The separator characters (network 452*1242Skas * metacharacters) are left intact. The last component of the network 453*1242Skas * name is stripped off and assumed to be the destination user name -- 454*1242Skas * it does not participate in the optimization. As an example, the 455*1242Skas * name "research!vax135!research!ucbvax!bill" becomes, tokenized, 456*1242Skas * "r!x!r!v!" and "bill" A low level routine, optim1, fixes up the 457*1242Skas * network part (eg, "r!x!r!v!"), then we convert back to network 458*1242Skas * machine names and tack the user name on the end. 459*1242Skas * 460*1242Skas * The result of this is copied into the parameter "name" 461*1242Skas */ 462*1242Skas 463*1242Skas optim(net, name) 464*1242Skas char net[], name[]; 465*1242Skas { 466*1242Skas char netcomp[BUFSIZ], netstr[40], xfstr[40]; 467*1242Skas register char *cp, *cp2; 468*1242Skas register int c; 469*1242Skas 470*1242Skas strcpy(netstr, ""); 471*1242Skas cp = net; 472*1242Skas for (;;) { 473*1242Skas /* 474*1242Skas * Rip off next path component into netcomp 475*1242Skas */ 476*1242Skas cp2 = netcomp; 477*1242Skas while (*cp && !any(*cp, metanet)) 478*1242Skas *cp2++ = *cp++; 479*1242Skas *cp2 = 0; 480*1242Skas /* 481*1242Skas * If we hit null byte, then we just scanned 482*1242Skas * the destination user name. Go off and optimize 483*1242Skas * if its so. 484*1242Skas */ 485*1242Skas if (*cp == 0) 486*1242Skas break; 487*1242Skas if ((c = netlook(netcomp, *cp)) == 0) { 488*1242Skas printf("No host named \"%s\"\n", netcomp); 489*1242Skas err: 490*1242Skas strcpy(name, net); 491*1242Skas return; 492*1242Skas } 493*1242Skas stradd(netstr, c); 494*1242Skas stradd(netstr, *cp++); 495*1242Skas /* 496*1242Skas * If multiple network separators given, 497*1242Skas * throw away the extras. 498*1242Skas */ 499*1242Skas while (any(*cp, metanet)) 500*1242Skas cp++; 501*1242Skas } 502*1242Skas if (strlen(netcomp) == 0) { 503*1242Skas printf("net name syntax\n"); 504*1242Skas goto err; 505*1242Skas } 506*1242Skas optim1(netstr, xfstr); 507*1242Skas 508*1242Skas /* 509*1242Skas * Convert back to machine names. 510*1242Skas */ 511*1242Skas 512*1242Skas cp = xfstr; 513*1242Skas strcpy(name, ""); 514*1242Skas while (*cp) { 515*1242Skas if ((cp2 = netname(*cp++)) == NOSTR) { 516*1242Skas printf("Made up bad net name\n"); 517*1242Skas goto err; 518*1242Skas } 519*1242Skas strcat(name, cp2); 520*1242Skas stradd(name, *cp++); 521*1242Skas } 522*1242Skas strcat(name, netcomp); 523*1242Skas } 524*1242Skas 525*1242Skas /* 526*1242Skas * Take a string of network machine id's and separators and 527*1242Skas * optimize them. We process these by pulling off maximal 528*1242Skas * leading strings of the same type, passing these to the appropriate 529*1242Skas * optimizer and concatenating the results. 530*1242Skas */ 531*1242Skas 532*1242Skas #define IMPLICIT 1 533*1242Skas #define EXPLICIT 2 534*1242Skas 535*1242Skas optim1(netstr, name) 536*1242Skas char netstr[], name[]; 537*1242Skas { 538*1242Skas char path[40], rpath[40]; 539*1242Skas register char *cp, *cp2; 540*1242Skas register int tp, nc; 541*1242Skas 542*1242Skas cp = netstr; 543*1242Skas prefer(cp); 544*1242Skas strcpy(name, ""); 545*1242Skas while (*cp != 0) { 546*1242Skas strcpy(path, ""); 547*1242Skas tp = ntype(cp[1]); 548*1242Skas nc = cp[1]; 549*1242Skas while (*cp && tp == ntype(cp[1])) { 550*1242Skas stradd(path, *cp++); 551*1242Skas cp++; 552*1242Skas } 553*1242Skas switch (netkind(tp)) { 554*1242Skas default: 555*1242Skas strcpy(rpath, path); 556*1242Skas break; 557*1242Skas 558*1242Skas case IMPLICIT: 559*1242Skas optimimp(path, rpath); 560*1242Skas break; 561*1242Skas 562*1242Skas case EXPLICIT: 563*1242Skas optimex(path, rpath); 564*1242Skas break; 565*1242Skas } 566*1242Skas for (cp2 = rpath; *cp2 != 0; cp2++) { 567*1242Skas stradd(name, *cp2); 568*1242Skas stradd(name, nc); 569*1242Skas } 570*1242Skas } 571*1242Skas optiboth(name); 572*1242Skas prefer(name); 573*1242Skas } 574*1242Skas 575*1242Skas /* 576*1242Skas * Return the network of the separator -- 577*1242Skas * AN for arpa net 578*1242Skas * BN for Bell labs net 579*1242Skas * SN for Schmidt (berkeley net) 580*1242Skas * 0 if we don't know. 581*1242Skas */ 582*1242Skas 583*1242Skas ntype(nc) 584*1242Skas register int nc; 585*1242Skas { 586*1242Skas 587*1242Skas switch (nc) { 588*1242Skas case '^': 589*1242Skas case '!': 590*1242Skas return(BN); 591*1242Skas 592*1242Skas case ':': 593*1242Skas case '.': 594*1242Skas return(SN); 595*1242Skas 596*1242Skas case '@': 597*1242Skas case '%': 598*1242Skas return(AN); 599*1242Skas 600*1242Skas default: 601*1242Skas return(0); 602*1242Skas } 603*1242Skas /* NOTREACHED */ 604*1242Skas } 605*1242Skas 606*1242Skas /* 607*1242Skas * Return the kind of routing used for the particular net 608*1242Skas * EXPLICIT means explicitly routed 609*1242Skas * IMPLICIT means implicitly routed 610*1242Skas * 0 means don't know 611*1242Skas */ 612*1242Skas 613*1242Skas netkind(nt) 614*1242Skas register int nt; 615*1242Skas { 616*1242Skas 617*1242Skas switch (nt) { 618*1242Skas case BN: 619*1242Skas return(EXPLICIT); 620*1242Skas 621*1242Skas case AN: 622*1242Skas case SN: 623*1242Skas return(IMPLICIT); 624*1242Skas 625*1242Skas default: 626*1242Skas return(0); 627*1242Skas } 628*1242Skas /* NOTREACHED */ 629*1242Skas } 630*1242Skas 631*1242Skas /* 632*1242Skas * Do name optimization for an explicitly routed network (eg BTL network). 633*1242Skas */ 634*1242Skas 635*1242Skas optimex(net, name) 636*1242Skas char net[], name[]; 637*1242Skas { 638*1242Skas register char *cp, *rp; 639*1242Skas register int m; 640*1242Skas char *rindex(); 641*1242Skas 642*1242Skas strcpy(name, net); 643*1242Skas cp = name; 644*1242Skas if (strlen(cp) == 0) 645*1242Skas return(-1); 646*1242Skas if (cp[strlen(cp)-1] == LOCAL) { 647*1242Skas name[0] = 0; 648*1242Skas return(0); 649*1242Skas } 650*1242Skas for (cp = name; *cp; cp++) { 651*1242Skas m = *cp; 652*1242Skas rp = rindex(cp+1, m); 653*1242Skas if (rp != NOSTR) 654*1242Skas strcpy(cp, rp); 655*1242Skas } 656*1242Skas return(0); 657*1242Skas } 658*1242Skas 659*1242Skas /* 660*1242Skas * Do name optimization for implicitly routed network (eg, arpanet, 661*1242Skas * Berkeley network) 662*1242Skas */ 663*1242Skas 664*1242Skas optimimp(net, name) 665*1242Skas char net[], name[]; 666*1242Skas { 667*1242Skas register char *cp; 668*1242Skas register int m; 669*1242Skas 670*1242Skas cp = net; 671*1242Skas if (strlen(cp) == 0) 672*1242Skas return(-1); 673*1242Skas m = cp[strlen(cp) - 1]; 674*1242Skas if (m == LOCAL) { 675*1242Skas strcpy(name, ""); 676*1242Skas return(0); 677*1242Skas } 678*1242Skas name[0] = m; 679*1242Skas name[1] = 0; 680*1242Skas return(0); 681*1242Skas } 682*1242Skas 683*1242Skas /* 684*1242Skas 685*1242Skas * Perform global optimization on the given network path. 686*1242Skas * The trick here is to look ahead to see if there are any loops 687*1242Skas * in the path and remove them. The interpretation of loops is 688*1242Skas * more strict here than in optimex since both the machine and net 689*1242Skas * type must match. 690*1242Skas */ 691*1242Skas 692*1242Skas optiboth(net) 693*1242Skas char net[]; 694*1242Skas { 695*1242Skas register char *cp, *cp2; 696*1242Skas char *rpair(); 697*1242Skas 698*1242Skas cp = net; 699*1242Skas if (strlen(cp) == 0) 700*1242Skas return; 701*1242Skas if ((strlen(cp) % 2) != 0) { 702*1242Skas printf("Strange arg to optiboth\n"); 703*1242Skas return; 704*1242Skas } 705*1242Skas while (*cp) { 706*1242Skas cp2 = rpair(cp+2, *cp); 707*1242Skas if (cp2 != NOSTR) 708*1242Skas strcpy(cp, cp2); 709*1242Skas cp += 2; 710*1242Skas } 711*1242Skas } 712*1242Skas 713*1242Skas /* 714*1242Skas * Find the rightmost instance of the given (machine, type) pair. 715*1242Skas */ 716*1242Skas 717*1242Skas char * 718*1242Skas rpair(str, mach) 719*1242Skas char str[]; 720*1242Skas { 721*1242Skas register char *cp, *last; 722*1242Skas 723*1242Skas last = NOSTR; 724*1242Skas while (*cp) { 725*1242Skas if (*cp == mach) 726*1242Skas last = cp; 727*1242Skas cp += 2; 728*1242Skas } 729*1242Skas return(last); 730*1242Skas } 731*1242Skas 732*1242Skas /* 733*1242Skas * Change the network separators in the given network path 734*1242Skas * to the preferred network transmission means. 735*1242Skas */ 736*1242Skas 737*1242Skas prefer(name) 738*1242Skas char name[]; 739*1242Skas { 740*1242Skas register char *cp; 741*1242Skas register int state, n; 742*1242Skas 743*1242Skas state = LOCAL; 744*1242Skas for (cp = name; *cp; cp += 2) { 745*1242Skas n = best(state, *cp); 746*1242Skas if (n) 747*1242Skas cp[1] = n; 748*1242Skas state = *cp; 749*1242Skas } 750*1242Skas } 751*1242Skas 752*1242Skas /* 753*1242Skas * Return the best network separator for the given machine pair. 754*1242Skas */ 755*1242Skas 756*1242Skas struct netorder { 757*1242Skas short no_stat; 758*1242Skas char no_char; 759*1242Skas } netorder[] = { 760*1242Skas CN, ':', 761*1242Skas AN, '@', 762*1242Skas AN, '%', 763*1242Skas SN, ':', 764*1242Skas BN, '!', 765*1242Skas -1, 0 766*1242Skas }; 767*1242Skas 768*1242Skas best(src, dest) 769*1242Skas { 770*1242Skas register int dtype, stype; 771*1242Skas register struct netorder *np; 772*1242Skas 773*1242Skas stype = nettype(src); 774*1242Skas dtype = nettype(dest); 775*1242Skas if (stype == 0 || dtype == 0) { 776*1242Skas printf("ERROR: unknown internal machine id\n"); 777*1242Skas return(0); 778*1242Skas } 779*1242Skas if ((stype & dtype) == 0) { 780*1242Skas #ifdef DELIVERMAIL 781*1242Skas if (src != LOCAL) 782*1242Skas #endif 783*1242Skas printf("No way to get from \"%s\" to \"%s\"\n", 784*1242Skas netname(src), netname(dest)); 785*1242Skas return(0); 786*1242Skas } 787*1242Skas np = &netorder[0]; 788*1242Skas while ((np->no_stat & stype & dtype) == 0) 789*1242Skas np++; 790*1242Skas return(np->no_char); 791*1242Skas } 792*1242Skas 793*1242Skas /* 794*1242Skas * Code to twist around arpa net names. 795*1242Skas */ 796*1242Skas 797*1242Skas #define WORD 257 /* Token for a string */ 798*1242Skas 799*1242Skas static char netbuf[256]; 800*1242Skas static char *yylval; 801*1242Skas 802*1242Skas /* 803*1242Skas * Reverse all of the arpa net addresses in the given name to 804*1242Skas * be of the form "host @ user" instead of "user @ host" 805*1242Skas * This function is its own inverse. 806*1242Skas */ 807*1242Skas 808*1242Skas char * 809*1242Skas revarpa(str) 810*1242Skas char str[]; 811*1242Skas { 812*1242Skas 813*1242Skas if (yyinit(str) < 0) 814*1242Skas return(NOSTR); 815*1242Skas if (name()) 816*1242Skas return(NOSTR); 817*1242Skas if (strcmp(str, netbuf) == 0) 818*1242Skas return(str); 819*1242Skas return(savestr(netbuf)); 820*1242Skas } 821*1242Skas 822*1242Skas /* 823*1242Skas * Parse (by recursive descent) network names, using the following grammar: 824*1242Skas * name: 825*1242Skas * term {':' term} 826*1242Skas * term {'^' term} 827*1242Skas * term {'!' term} 828*1242Skas * term '@' name 829*1242Skas * term '%' name 830*1242Skas * 831*1242Skas * term: 832*1242Skas * string of characters. 833*1242Skas */ 834*1242Skas 835*1242Skas name() 836*1242Skas { 837*1242Skas register int t; 838*1242Skas register char *cp; 839*1242Skas 840*1242Skas for (;;) { 841*1242Skas t = yylex(); 842*1242Skas if (t != WORD) 843*1242Skas return(-1); 844*1242Skas cp = yylval; 845*1242Skas t = yylex(); 846*1242Skas switch (t) { 847*1242Skas case 0: 848*1242Skas strcat(netbuf, cp); 849*1242Skas return(0); 850*1242Skas 851*1242Skas case '@': 852*1242Skas case '%': 853*1242Skas if (name()) 854*1242Skas return(-1); 855*1242Skas stradd(netbuf, '@'); 856*1242Skas strcat(netbuf, cp); 857*1242Skas return(0); 858*1242Skas 859*1242Skas case WORD: 860*1242Skas return(-1); 861*1242Skas 862*1242Skas default: 863*1242Skas strcat(netbuf, cp); 864*1242Skas stradd(netbuf, t); 865*1242Skas } 866*1242Skas } 867*1242Skas } 868*1242Skas 869*1242Skas /* 870*1242Skas * Scanner for network names. 871*1242Skas */ 872*1242Skas 873*1242Skas static char *charp; /* Current input pointer */ 874*1242Skas static int nexttok; /* Salted away next token */ 875*1242Skas 876*1242Skas /* 877*1242Skas * Initialize the network name scanner. 878*1242Skas */ 879*1242Skas 880*1242Skas yyinit(str) 881*1242Skas char str[]; 882*1242Skas { 883*1242Skas static char lexbuf[BUFSIZ]; 884*1242Skas 885*1242Skas netbuf[0] = 0; 886*1242Skas if (strlen(str) >= sizeof lexbuf - 1) 887*1242Skas return(-1); 888*1242Skas nexttok = 0; 889*1242Skas strcpy(lexbuf, str); 890*1242Skas charp = lexbuf; 891*1242Skas return(0); 892*1242Skas } 893*1242Skas 894*1242Skas /* 895*1242Skas * Scan and return a single token. 896*1242Skas * yylval is set to point to a scanned string. 897*1242Skas */ 898*1242Skas 899*1242Skas yylex() 900*1242Skas { 901*1242Skas register char *cp, *dot; 902*1242Skas register int s; 903*1242Skas 904*1242Skas if (nexttok) { 905*1242Skas s = nexttok; 906*1242Skas nexttok = 0; 907*1242Skas return(s); 908*1242Skas } 909*1242Skas cp = charp; 910*1242Skas while (*cp && isspace(*cp)) 911*1242Skas cp++; 912*1242Skas if (*cp == 0) 913*1242Skas return(0); 914*1242Skas if (any(*cp, "!^@:%")) { 915*1242Skas charp = cp+1; 916*1242Skas return(*cp); 917*1242Skas } 918*1242Skas dot = cp; 919*1242Skas while (*cp && !any(*cp, " \t!^@:%")) 920*1242Skas cp++; 921*1242Skas if (any(*cp, "!^@:%")) 922*1242Skas nexttok = *cp; 923*1242Skas if (*cp == 0) 924*1242Skas charp = cp; 925*1242Skas else 926*1242Skas charp = cp+1; 927*1242Skas *cp = 0; 928*1242Skas yylval = dot; 929*1242Skas return(WORD); 930*1242Skas } 931*1242Skas 932*1242Skas /* 933*1242Skas * Add a single character onto a string. 934*1242Skas */ 935*1242Skas 936*1242Skas stradd(str, c) 937*1242Skas register char *str; 938*1242Skas register int c; 939*1242Skas { 940*1242Skas 941*1242Skas str += strlen(str); 942*1242Skas *str++ = c; 943*1242Skas *str = 0; 944*1242Skas } 945