1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 1998 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 28 /* All Rights Reserved */ 29 30 /* 31 * mailx -- a modified version of a University of California at Berkeley 32 * mail program 33 * 34 * Network name modification routines. 35 */ 36 37 #include "rcv.h" 38 #include "configdefs.h" 39 #include <locale.h> 40 41 static char *arpafix(char name[], char from[]); 42 static char *lasthost(char *addr); 43 static char *makeremote(char name[], char from[]); 44 static int mstash(char name[], int attnet); 45 static int mtype(int mid); 46 static int netlook(char machine[], int attnet); 47 static int nettype(int mid); 48 static int ntype(register int nc); 49 static void stradd(register char *str, int n, register int c); 50 static char *tackon(char *sys, char *rest); 51 static struct xtrahash *xlocate(char name[]); 52 #ifdef OPTIM 53 static char best(int src, int dest); 54 static char *mlook(int mid); 55 static int netkind(register int nt); 56 static void optiboth(char net[]); 57 static void optim(char net[], char name[]); 58 static void optim1(char netstr[], char name[]); 59 static int optimex(char net[], char name[]); 60 static int optimimp(char net[], char name[]); 61 static void prefer(char name[]); 62 static char *rpair(char str[], int mach); 63 #endif 64 65 /* 66 * Map a name into the correct network "view" of the 67 * name. This is done by prepending the name with the 68 * network address of the sender, then optimizing away 69 * nonsense. 70 */ 71 72 char * 73 netmap(char name[], char from[]) 74 { 75 char nbuf[BUFSIZ], ret[BUFSIZ]; 76 register char *cp, *oname; 77 78 if (debug) fprintf(stderr, "netmap(name '%s', from '%s')\n", name, from); 79 if (strlen(from) == 0) 80 return(name); /* "from" is empty - can't do anything */ 81 82 if (strcmp(from, name) == 0) 83 return(name); /* "from" and "name" are the same, do nothing */ 84 85 /* 86 * If the name contains an "@" or a "%", remove it and the host 87 * following it if that host is "known". 88 */ 89 if (any('@', name) || any('%', name)) 90 return(arpafix(name, from)); 91 92 /* 93 * If the sender contains a "@" or a "%", make "name" into an 94 * address on that host, on the presumption that it should 95 * really have read "name@from" when we received the message 96 * rather than just "name". 97 */ 98 if (any('@', from) || any('%', from)) 99 return(unuucp(makeremote(name, from))); 100 if (value("onehop") && (cp = strchr(name, '!')) && cp > name) { 101 /* 102 * "onehop" is set, meaning all machines are one UUCP 103 * hop away (fat chance, in this day and age), and "name" 104 * is a UUCP path rather than just a name. Leave it alone. 105 */ 106 nstrcpy(nbuf, sizeof (nbuf), name); 107 } else { 108 from = tackon(host, from); 109 *strrchr(from, '!') = 0; 110 name = tackon(lasthost(from), name); 111 while (((cp = lasthost(from)) != 0) && ishost(cp, name)) { 112 oname = name; 113 name = strchr(name, '!') + 1; 114 if (cp == from) { 115 from[strlen(from)] = '!'; 116 if (value("mustbang") && !strchr(name, '!')) 117 name = oname; 118 return(unuucp(name)); 119 } 120 *--cp = 0; 121 } 122 from[strlen(from)] = '!'; 123 from = strchr(from, '!') + 1; 124 snprintf(nbuf, sizeof (nbuf), "%s!%s", from, name); 125 } 126 if (debug) fprintf(stderr, "before optim, nbuf '%s'\n", name); 127 #ifdef OPTIM 128 if ((cp = value("conv"))==NOSTR || strcmp(cp, "optimize") != 0) 129 nstrcpy(ret, sizeof (ret), nbuf); 130 else 131 optim(nbuf, ret); 132 #else 133 nstrcpy(ret, sizeof (ret), nbuf); 134 #endif /* OPTIM */ 135 if (debug) fprintf(stderr, "after optim, nbuf '%s', ret '%s'\n", nbuf, ret); 136 cp = ret; 137 if (debug) fprintf(stderr, "wind up with '%s'\n", name); 138 if (!icequal(name, cp)) 139 return(unuucp((char *) savestr(cp))); 140 return(unuucp(name)); 141 } 142 143 /* 144 * Stick a host on the beginning of a uucp 145 * address if it isn't there already. 146 */ 147 static char * 148 tackon(char *sys, char *rest) 149 { 150 while (*rest == '!') 151 rest++; 152 if (!ishost(sys, rest)) { 153 char *r = (char *)salloc(strlen(sys) + strlen(rest) + 2); 154 sprintf(r, "%s!%s", sys, rest); 155 rest = r; 156 } 157 return rest; 158 } 159 160 /* 161 * Check equality of the first host in a uucp address. 162 */ 163 int 164 ishost(char *sys, char *rest) 165 { 166 while (*sys && *sys == *rest) 167 sys++, rest++; 168 return(*sys == 0 && *rest == '!'); 169 } 170 171 /* 172 * Return last host in a uucp address. 173 */ 174 static char * 175 lasthost(char *addr) 176 { 177 char *r = strrchr(addr, '!'); 178 return r ? ++r : addr; 179 } 180 181 /* 182 * Optionally translate an old format uucp name into a new one, e.g. 183 * "mach1!mach2!user" becomes "user@mach2.UUCP". This optional because 184 * some information is necessarily lost (e.g. the route it got here 185 * via) and if we don't have the host in our routing tables, we lose. 186 * XXX THIS IS NO LONGER VALID WITH THE NEW UUCP PROJECT PLANS TO 187 * REGISTER UUCP HOSTS IN THE STANDARD INTERNET NAMESPACE, E.G. 188 * ihnp4 BECOMES "ihnp4.att.com". 189 */ 190 char * 191 unuucp(char *name) 192 { 193 register char *np, *hp, *cp; 194 char result[100]; 195 char tname[300]; 196 197 if (UnUUCP==0 && 198 ((cp = value("conv"))==NOSTR || strcmp(cp, "internet"))) 199 return name; 200 if (debug) fprintf(stderr, "unuucp(%s)\n", name); 201 nstrcpy(tname, sizeof (tname), name); 202 np = strrchr(tname, '!'); 203 if (np == NOSTR) 204 return name; 205 *np++ = 0; 206 hp = strrchr(tname, '!'); 207 if (hp == NOSTR) 208 hp = tname; 209 else 210 *hp++ = 0; 211 cp = strchr(np, '@'); 212 if (cp == NOSTR) 213 cp = strchr(np, '%'); 214 if (cp) 215 *cp = 0; 216 if (debug) fprintf(stderr, "host %s, name %s\n", hp, np); 217 snprintf(result, sizeof (result), "%s@%s.UUCP", np, hp); 218 if (debug) fprintf(stderr, "unuucp returns %s\n", result); 219 return savestr(result); 220 } 221 222 /* 223 * Turn a network machine name into a unique character 224 */ 225 static int 226 netlook(char machine[], int attnet) 227 { 228 register struct netmach *np; 229 register char *cp, *cp2; 230 char nbuf[BUFSIZ]; 231 232 /* 233 * Make into lower case. 234 */ 235 for (cp = machine, cp2 = nbuf; 236 *cp && cp2 < &nbuf[BUFSIZ-1]; 237 *cp2++ = tolower(*cp++)) 238 /*nothing*/; 239 *cp2 = 0; 240 241 /* 242 * If a single letter machine, look through those first. 243 */ 244 245 if (strlen(nbuf) == 1) 246 for (np = netmach; np->nt_mid != 0; np++) 247 if (np->nt_mid == nbuf[0]) 248 return(nbuf[0]); 249 250 /* 251 * Look for usual name 252 */ 253 254 for (np = netmach; np->nt_mid != 0; np++) 255 if (strcmp(np->nt_machine, nbuf) == 0) 256 return(np->nt_mid); 257 258 /* 259 * Look in side hash table. 260 */ 261 262 return(mstash(nbuf, attnet)); 263 } 264 265 #ifdef OPTIM 266 /* 267 * Turn a network unique character identifier into a network name. 268 */ 269 270 static char * 271 netname(int mid) 272 { 273 register struct netmach *np; 274 275 if (mid & 0200) 276 return(mlook(mid)); 277 for (np = netmach; np->nt_mid != 0; np++) 278 if (np->nt_mid == mid) 279 return(np->nt_machine); 280 return(NOSTR); 281 } 282 #endif 283 284 /* 285 * Deal with arpa net addresses. The way this is done is strange. 286 * name contains an "@" or "%". Look up the machine after it in 287 * the hash table. If it isn't found, return name unmolested. 288 * If ???, return name unmolested. 289 * Otherwise, delete the "@" or "%" and the machine after it from 290 * name, and return the new string. 291 */ 292 static char * 293 arpafix(char name[], char from[]) 294 { 295 register char *cp; 296 register int arpamach; 297 char newname[BUFSIZ]; 298 299 if (debug) { 300 fprintf(stderr, "arpafix(%s, %s)\n", name, from); 301 } 302 cp = strrchr(name, '@'); 303 if (cp == NOSTR) 304 cp = strrchr(name, '%'); 305 if (cp == NOSTR) { 306 fprintf(stderr, 307 gettext("Something's amiss -- no @ or %% in arpafix\n")); 308 return(name); 309 } 310 cp++; 311 arpamach = netlook(cp, '@'); 312 if (debug) 313 fprintf(stderr, 314 "cp '%s', arpamach %o, nettypes arpamach %o LOCAL %o\n", 315 cp, arpamach, nettype(arpamach), nettype(LOCAL)); 316 if (arpamach == 0) { 317 if (debug) 318 fprintf(stderr, "machine %s unknown, uses: %s\n", 319 cp, name); 320 return(name); 321 } 322 if (((nettype(arpamach) & nettype(LOCAL)) & ~AN) == 0) { 323 if (debug) 324 fprintf(stderr, "machine %s known but remote, uses: %s\n", 325 cp, name); 326 return(name); 327 } 328 nstrcpy(newname, sizeof (newname), name); 329 cp = strrchr(newname, '@'); 330 if (cp == NOSTR) 331 cp = strrchr(newname, '%'); 332 *cp = 0; 333 if (debug) fprintf(stderr, "local address, return '%s'\n", newname); 334 return(savestr(newname)); 335 } 336 337 /* 338 * We have name with no @'s in it, and from with @'s. 339 * Assume that name is meaningful only on the site in from, 340 * and return "name@site_in_from". 341 */ 342 static char * 343 makeremote(char name[], char from[]) 344 { 345 register char *cp; 346 char rbuf[BUFSIZ]; 347 348 if (!value("makeremote")) 349 return(name); 350 if (debug) fprintf(stderr, "makeremote(%s, %s) returns ", name, from); 351 cp = strrchr(from, '@'); 352 if (cp == NOSTR) 353 cp = strrchr(from, '%'); 354 snprintf(rbuf, sizeof (rbuf), "%s%s", name, cp); 355 if (debug) fprintf(stderr, "%s\n", rbuf); 356 return(savestr(rbuf)); 357 } 358 359 /* 360 * Take a network machine descriptor and find the types of connected 361 * nets and return it. 362 */ 363 static int 364 nettype(int mid) 365 { 366 register struct netmach *np; 367 368 if (mid & 0200) 369 return(mtype(mid)); 370 for (np = netmach; np->nt_mid != 0; np++) 371 if (np->nt_mid == mid) 372 return(np->nt_type); 373 return(0); 374 } 375 376 /* 377 * Hashing routines to salt away machines seen scanning 378 * networks paths that we don't know about. 379 */ 380 381 #define XHSIZE 97 /* Size of extra hash table */ 382 #define NXMID (XHSIZE*3/4) /* Max extra machines */ 383 384 struct xtrahash { 385 char *xh_name; /* Name of machine */ 386 short xh_mid; /* Machine ID */ 387 short xh_attnet; /* Attached networks */ 388 } xtrahash[XHSIZE]; 389 390 static struct xtrahash *xtab[XHSIZE]; /* F: mid-->machine name */ 391 392 static short midfree; /* Next free machine id */ 393 394 /* 395 * Initialize the extra host hash table. 396 * Called by sreset. 397 */ 398 void 399 minit(void) 400 { 401 register struct xtrahash *xp, **tp; 402 403 midfree = 0; 404 tp = &xtab[0]; 405 for (xp = &xtrahash[0]; xp < &xtrahash[XHSIZE]; xp++) { 406 xp->xh_name = NOSTR; 407 xp->xh_mid = 0; 408 xp->xh_attnet = 0; 409 *tp++ = (struct xtrahash *) 0; 410 } 411 } 412 413 /* 414 * Stash a net name in the extra host hash table. 415 * If a new entry is put in the hash table, deduce what 416 * net the machine is attached to from the net character. 417 * 418 * If the machine is already known, add the given attached 419 * net to those already known. 420 */ 421 static int 422 mstash(char name[], int attnet) 423 { 424 register struct xtrahash *xp; 425 int x; 426 427 xp = xlocate(name); 428 if (xp == (struct xtrahash *) 0) { 429 printf(gettext("Ran out of machine id spots\n")); 430 return(0); 431 } 432 if (xp->xh_name == NOSTR) { 433 if (midfree >= XHSIZE) { 434 printf(gettext("Out of machine ids\n")); 435 return(0); 436 } 437 xtab[midfree] = xp; 438 xp->xh_name = savestr(name); 439 xp->xh_mid = 0200 + midfree++; 440 } 441 x = ntype(attnet); 442 if (x == 0) 443 xp->xh_attnet |= AN; 444 else 445 xp->xh_attnet |= x; 446 return(xp->xh_mid); 447 } 448 449 /* 450 * Search for the given name in the hash table 451 * and return the pointer to it if found, or to the first 452 * empty slot if not found. 453 * 454 * If no free slots can be found, return 0. 455 */ 456 457 static struct xtrahash * 458 xlocate(char name[]) 459 { 460 register int h, q, i; 461 register char *cp; 462 register struct xtrahash *xp; 463 464 for (h = 0, cp = name; *cp; h = (h << 2) + *cp++) 465 ; 466 if (h < 0 && (h = -h) < 0) 467 h = 0; 468 h = h % XHSIZE; 469 cp = name; 470 for (i = 0, q = 0; q < XHSIZE; i++, q = i * i) { 471 xp = &xtrahash[(h + q) % XHSIZE]; 472 if (xp->xh_name == NOSTR) 473 return(xp); 474 if (strcmp(cp, xp->xh_name) == 0) 475 return(xp); 476 if (h - q < 0) 477 h += XHSIZE; 478 xp = &xtrahash[(h - q) % XHSIZE]; 479 if (xp->xh_name == NOSTR) 480 return(xp); 481 if (strcmp(cp, xp->xh_name) == 0) 482 return(xp); 483 } 484 return((struct xtrahash *) 0); 485 } 486 487 #ifdef OPTIM 488 /* 489 * Return the name from the extra host hash table corresponding 490 * to the passed machine id. 491 */ 492 493 static char * 494 mlook(int mid) 495 { 496 register int m; 497 498 if ((mid & 0200) == 0) 499 return(NOSTR); 500 m = mid & 0177; 501 if (m >= midfree) { 502 printf(gettext("Use made of undefined machine id\n")); 503 return(NOSTR); 504 } 505 return(xtab[m]->xh_name); 506 } 507 #endif 508 509 /* 510 * Return the bit mask of net's that the given extra host machine 511 * id has so far. 512 */ 513 static int 514 mtype(int mid) 515 { 516 register int m; 517 518 if ((mid & 0200) == 0) 519 return(0); 520 m = mid & 0177; 521 if (m >= midfree) { 522 printf(gettext("Use made of undefined machine id\n")); 523 return(0); 524 } 525 return(xtab[m]->xh_attnet); 526 } 527 528 #ifdef OPTIM 529 /* 530 * Take a network name and optimize it. This gloriously messy 531 * operation takes place as follows: the name with machine names 532 * in it is tokenized by mapping each machine name into a single 533 * character machine id (netlook). The separator characters (network 534 * metacharacters) are left intact. The last component of the network 535 * name is stripped off and assumed to be the destination user name -- 536 * it does not participate in the optimization. As an example, the 537 * name "res!vax!res!uvax!bill" becomes, tokenized, 538 * "r!x!r!v!" and "bill" A low level routine, optim1, fixes up the 539 * network part (eg, "r!x!r!v!"), then we convert back to network 540 * machine names and tack the user name on the end. 541 * 542 * The result of this is copied into the parameter "name" 543 */ 544 545 static void 546 optim(char net[], char name[]) 547 { 548 char netcomp[BUFSIZ], netstr[STSIZ], xfstr[STSIZ]; 549 register char *cp, *cp2; 550 register int c; 551 552 if (debug) fprintf(stderr, "optim(%s, %s) called\n", net, name); 553 *netstr = '\0'; 554 cp = net; 555 for (;;) { 556 /* 557 * Rip off next path component into netcomp 558 */ 559 cp2 = netcomp; 560 while (*cp && !any(*cp, metanet)) 561 *cp2++ = *cp++; 562 *cp2 = 0; 563 /* 564 * If we hit null byte, then we just scanned 565 * the destination user name. Go off and optimize 566 * if its so. 567 */ 568 if (*cp == 0) 569 break; 570 if ((c = netlook(netcomp, *cp)) == 0) { 571 printf(gettext("No host named \"%s\"\n"), netcomp); 572 err: 573 nstrcpy(name, BUFSIZ, net); 574 return; 575 } 576 stradd(name, BUFSIZ, c); 577 stradd(name, BUFSIZ, *cp++); 578 /* 579 * If multiple network separators given, 580 * throw away the extras. 581 */ 582 while (any(*cp, metanet)) 583 cp++; 584 } 585 if (strlen(netcomp) == 0) { 586 printf(gettext("net name syntax\n")); 587 goto err; 588 } 589 if (debug) fprintf(stderr, "optim1(%s,%s) called\n", netstr, xfstr); 590 optim1(netstr, xfstr); 591 if (debug) fprintf(stderr, "optim1(%s,%s) returns\n", netstr, xfstr); 592 593 /* 594 * Convert back to machine names. 595 */ 596 597 cp = xfstr; 598 *name = '\0'; 599 while (*cp) { 600 if ((cp2 = netname(*cp++)) == NOSTR) { 601 printf(gettext("Made up bad net name\n")); 602 printf(gettext("Machine code %c (0%o)\n"), cp[-1], 603 cp[-1]); 604 printf(gettext("Sorry.\n")); 605 goto err; 606 } 607 nstrcat(name, BUFSIZ, cp2); 608 stradd(name, BUFSIZ, *cp++); 609 } 610 nstrcat(name, BUFSIZ, netcomp); 611 if (debug) fprintf(stderr, "optim returns %s in name\n", name); 612 } 613 614 /* 615 * Take a string of network machine id's and separators and 616 * optimize them. We process these by pulling off maximal 617 * leading strings of the same type, passing these to the appropriate 618 * optimizer and concatenating the results. 619 */ 620 621 static void 622 optim1(char netstr[], char name[]) 623 { 624 char path[STSIZ], rpath[STSIZ]; 625 register char *cp, *cp2; 626 register int tp, nc; 627 628 cp = netstr; 629 prefer(cp); 630 *name = '\0'; 631 /* 632 * If the address ultimately points back to us, 633 * just return a null network path. 634 */ 635 if ((int)strlen(cp) > 1 && cp[strlen(cp) - 2] == LOCAL) 636 return; 637 while (*cp != 0) { 638 *path = '\0'; 639 640 tp = ntype(cp[1]); 641 nc = cp[1]; 642 while (*cp && tp == ntype(cp[1])) { 643 stradd(path, sizeof (path), *cp++); 644 cp++; 645 } 646 switch (netkind(tp)) { 647 default: 648 nstrcpy(rpath, sizeof (rpath), path); 649 break; 650 651 case IMPLICIT: 652 optimimp(path, rpath); 653 break; 654 655 case EXPLICIT: 656 optimex(path, rpath); 657 break; 658 } 659 for (cp2 = rpath; *cp2 != 0; cp2++) { 660 stradd(name, BUFSIZ, *cp2); 661 stradd(name, BUFSIZ, nc); 662 } 663 } 664 optiboth(name); 665 prefer(name); 666 } 667 #endif /* OPTIM */ 668 669 /* 670 * Return the network of the separator -- 671 * AN for arpa net 672 * BN for Bell labs net (e.g. UUCP, NOT Berknet) 673 * SN for Schmidt net (Berknet) 674 * 0 if we don't know. 675 */ 676 static int 677 ntype(register int nc) 678 { 679 register struct ntypetab *np; 680 681 for (np = ntypetab; np->nt_char != 0; np++) 682 if (np->nt_char == nc) 683 return(np->nt_bcode); 684 return(0); 685 } 686 687 #ifdef OPTIM 688 /* 689 * Return the kind of routing used for the particular net 690 * EXPLICIT means explicitly routed 691 * IMPLICIT means implicitly routed 692 * 0 means don't know 693 */ 694 695 static int 696 netkind(register int nt) 697 { 698 register struct nkindtab *np; 699 700 for (np = nkindtab; np->nk_type != 0; np++) 701 if (np->nk_type == nt) 702 return(np->nk_kind); 703 return(0); 704 } 705 706 /* 707 * Do name optimization for an explicitly routed network (eg uucp). 708 */ 709 710 static int 711 optimex(char net[], char name[]) 712 { 713 register char *cp, *rp; 714 register int m; 715 716 nstrcpy(name, STSIZ, net); 717 cp = name; 718 if (strlen(cp) == 0) 719 return(-1); 720 if (cp[strlen(cp)-1] == LOCAL) { 721 name[0] = 0; 722 return(0); 723 } 724 for (cp = name; *cp; cp++) { 725 m = *cp; 726 rp = strrchr(cp+1, m); 727 if (rp != NOSTR) 728 strcpy(cp, rp); 729 } 730 return(0); 731 } 732 733 /* 734 * Do name optimization for implicitly routed network (eg, arpanet). 735 */ 736 737 static int 738 optimimp(char net[], char name[]) 739 { 740 register char *cp; 741 register char m; 742 743 cp = net; 744 if (strlen(cp) == 0) 745 return(-1); 746 m = cp[strlen(cp) - 1]; 747 if (m == LOCAL) { 748 *name = '\0'; 749 return(0); 750 } 751 name[0] = m; 752 name[1] = 0; 753 return(0); 754 } 755 756 /* 757 * Perform global optimization on the given network path. 758 * The trick here is to look ahead to see if there are any loops 759 * in the path and remove them. The interpretation of loops is 760 * more strict here than in optimex since both the machine and net 761 * type must match. 762 */ 763 764 static void 765 optiboth(char net[]) 766 { 767 register char *cp, *cp2; 768 769 cp = net; 770 if (strlen(cp) == 0) 771 return; 772 if (((int)strlen(cp) % 2) != 0) { 773 printf(gettext("Strange arg to optiboth\n")); 774 return; 775 } 776 while (*cp) { 777 cp2 = rpair(cp+2, *cp); 778 if (cp2 != NOSTR) 779 strcpy(cp, cp2); 780 cp += 2; 781 } 782 } 783 784 /* 785 * Find the rightmost instance of the given (machine, type) pair. 786 */ 787 788 static char * 789 rpair(char str[], int mach) 790 { 791 register char *cp, *last; 792 793 cp = str; 794 last = NOSTR; 795 while (*cp) { 796 if (*cp == mach) 797 last = cp; 798 cp += 2; 799 } 800 return(last); 801 } 802 803 /* 804 * Change the network separators in the given network path 805 * to the preferred network transmission means. 806 */ 807 808 static void 809 prefer(char name[]) 810 { 811 register char *cp, n; 812 register int state; 813 814 state = LOCAL; 815 for (cp = name; *cp; cp += 2) { 816 n = best(state, *cp); 817 if (n) 818 cp[1] = n; 819 state = *cp; 820 } 821 } 822 823 /* 824 * Return the best network separator for the given machine pair. 825 */ 826 827 static char 828 best(int src, int dest) 829 { 830 register int dtype, stype; 831 register struct netorder *np; 832 833 stype = nettype(src); 834 dtype = nettype(dest); 835 fflush(stdout); 836 if (stype == 0 || dtype == 0) { 837 printf(gettext("ERROR: unknown internal machine id\n")); 838 return(0); 839 } 840 if ((stype & dtype) == 0) 841 return(0); 842 np = &netorder[0]; 843 while ((np->no_stat & stype & dtype) == 0) 844 np++; 845 return(np->no_char); 846 } 847 #endif /* OPTIM */ 848 849 #ifdef notdef 850 /* 851 * Code to twist around arpa net names. 852 */ 853 854 #define WORD 257 /* Token for a string */ 855 856 static char netbuf[256]; 857 static char *yylval; 858 859 /* 860 * Reverse all of the arpa net addresses in the given name to 861 * be of the form "host @ user" instead of "user @ host" 862 * This function is its own inverse. 863 */ 864 865 char * 866 revarpa(char str[]) 867 { 868 869 if (yyinit(str) < 0) 870 return(NOSTR); 871 if (name()) 872 return(NOSTR); 873 if (strcmp(str, netbuf) == 0) 874 return(str); 875 return(savestr(netbuf)); 876 } 877 878 /* 879 * Parse (by recursive descent) network names, using the following grammar: 880 * name: 881 * term {':' term} 882 * term {'^' term} 883 * term {'!' term} 884 * term '@' name 885 * term '%' name 886 * 887 * term: 888 * string of characters. 889 */ 890 891 static int 892 name(void) 893 { 894 register int t; 895 register char *cp; 896 897 for (;;) { 898 t = yylex(); 899 if (t != WORD) 900 return(-1); 901 cp = yylval; 902 t = yylex(); 903 switch (t) { 904 case 0: 905 nstrcat(netbuf, sizeof (netbuf), cp); 906 return(0); 907 908 case '@': 909 case '%': 910 if (name()) 911 return(-1); 912 stradd(netbuf, sizeof (netbuf), '@'); 913 nstrcat(netbuf, sizeof (netbuf), cp); 914 return(0); 915 case WORD: 916 return(-1); 917 918 default: 919 nstrcat(netbuf, sizeof (netbuf), cp); 920 stradd(netbuf, sizeof (netbuf), t); 921 } 922 } 923 } 924 925 /* 926 * Scanner for network names. 927 */ 928 929 static char *charp; /* Current input pointer */ 930 static int nexttok; /* Salted away next token */ 931 932 /* 933 * Initialize the network name scanner. 934 */ 935 936 int 937 yyinit(char str[]) 938 { 939 static char lexbuf[BUFSIZ]; 940 941 netbuf[0] = 0; 942 if (strlen(str) >= sizeof lexbuf - 1) 943 return(-1); 944 nexttok = 0; 945 nstrcpy(lexbuf, sizeof (lexbuf), str); 946 charp = lexbuf; 947 return(0); 948 } 949 950 /* 951 * Scan and return a single token. 952 * yylval is set to point to a scanned string. 953 */ 954 955 int 956 yylex(void) 957 { 958 register char *cp, *dotp; 959 register int s; 960 961 if (nexttok) { 962 s = nexttok; 963 nexttok = 0; 964 return(s); 965 } 966 cp = charp; 967 while (*cp && isspace(*cp)) 968 cp++; 969 if (*cp == 0) 970 return(0); 971 if (any(*cp, metanet)) { 972 charp = cp+1; 973 return(*cp); 974 } 975 dotp = cp; 976 while (*cp && !any(*cp, metanet) && !any(*cp, " \t")) 977 cp++; 978 if (any(*cp, metanet)) 979 nexttok = *cp; 980 if (*cp == 0) 981 charp = cp; 982 else 983 charp = cp+1; 984 *cp = 0; 985 yylval = dotp; 986 return(WORD); 987 } 988 #endif 989 990 /* 991 * Add a single character onto a string. Here dstsize is the size of the 992 * destnation buffer. 993 */ 994 995 static void 996 stradd(register char *dst, int dstsize, register int c) 997 { 998 while (*dst != '\0') { 999 dst++; 1000 dstsize--; 1001 } 1002 if (--dstsize > 0) 1003 *dst++ = (char)c; 1004 *dst = '\0'; 1005 } 1006