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