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