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 *
netmap(char name[],char from[])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 *
tackon(char * sys,char * rest)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
ishost(char * sys,char * rest)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 *
lasthost(char * addr)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 *
unuucp(char * name)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
netlook(char machine[],int attnet)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 *
netname(int mid)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 *
arpafix(char name[],char from[])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 *
makeremote(char name[],char from[])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
nettype(int mid)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
minit(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
mstash(char name[],int attnet)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 *
xlocate(char name[])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 *
mlook(int mid)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
mtype(int mid)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
optim(char net[],char name[])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
optim1(char netstr[],char name[])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
ntype(register int nc)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
netkind(register int nt)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
optimex(char net[],char name[])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
optimimp(char net[],char name[])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
optiboth(char net[])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 *
rpair(char str[],int mach)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
prefer(char name[])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
best(int src,int dest)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 *
revarpa(char str[])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
name(void)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
yyinit(char str[])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
yylex(void)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
stradd(register char * dst,int dstsize,register int c)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