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