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