|
|
1.1 root 1: #
2:
3: /*
4: * Mail -- a program for sending and receiving mail.
5: *
6: * Network name modification routines.
7: */
8:
9: #include "rcv.h"
10:
11: /*
12: * Map a name into the correct network "view" of the
13: * name. This is done by prepending the name with the
14: * network address of the sender, then optimizing away
15: * nonsense.
16: */
17:
18: char *metanet = "!^:@";
19:
20: char *
21: netmap(name, from)
22: char name[], from[];
23: {
24: char nbuf[BUFSIZ], ret[BUFSIZ];
25: register char *cp;
26:
27: strcpy(nbuf, from);
28: if (strlen(nbuf) == 0)
29: return(name);
30: cp = &nbuf[strlen(nbuf) - 1];
31: while (!any(*cp, metanet) && cp > nbuf)
32: cp--;
33: if (cp == nbuf)
34: return(name);
35: *++cp = 0;
36: strcat(nbuf, name);
37: optim(nbuf, ret);
38: if (!equal(name, ret))
39: return((char *) savestr(ret));
40: return(name);
41: }
42:
43: /*
44: * Turn a network machine name into a unique character
45: * + give connection-to status. BN -- connected to Bell Net.
46: * AN -- connected to ARPA net, SN -- connected to Schmidt net.
47: * CN -- connected to COCANET.
48: */
49:
50: #define AN 1 /* Connected to ARPA net */
51: #define BN 2 /* Connected to BTL net */
52: #define CN 4 /* Connected to COCANET */
53: #define SN 8 /* Connected to Schmidt net */
54:
55: struct netmach {
56: char *nt_machine;
57: char nt_mid;
58: short nt_type;
59: } netmach[] = {
60: "a", 'a', SN,
61: "b", 'b', SN,
62: "c", 'c', SN,
63: "d", 'd', SN,
64: "e", 'e', SN,
65: "f", 'f', SN,
66: "ccvax", 'f', SN,
67: "ingres", 'i', AN|SN,
68: "ing70", 'i', AN|SN,
69: "ingvax", 'j', SN,
70: "image", 'm', SN,
71: "optvax", 'o', SN,
72: "sesm", 'o', SN,
73: "q", 'q', SN,
74: "research", 'r', BN,
75: "src", 's', SN,
76: "vax", 'v', BN|SN,
77: "csvax", 'v', BN|SN,
78: "ucbvax", 'v', BN|SN,
79: "vax135", 'x', BN,
80: "cory", 'y', SN,
81: "eecs40", 'z', SN,
82: 0, 0, 0
83: };
84:
85: netlook(machine, attnet)
86: char machine[];
87: {
88: register struct netmach *np;
89: register char *cp, *cp2;
90: char nbuf[20];
91:
92: /*
93: * Make into lower case.
94: */
95:
96: for (cp = machine, cp2 = nbuf; *cp; *cp2++ = little(*cp++))
97: ;
98: *cp2 = 0;
99:
100: /*
101: * If a single letter machine, look through those first.
102: */
103:
104: if (strlen(nbuf) == 1)
105: for (np = netmach; np->nt_mid != 0; np++)
106: if (np->nt_mid == nbuf[0])
107: return(nbuf[0]);
108:
109: /*
110: * Look for usual name
111: */
112:
113: for (np = netmach; np->nt_mid != 0; np++)
114: if (strcmp(np->nt_machine, nbuf) == 0)
115: return(np->nt_mid);
116:
117: /*
118: * Look in side hash table.
119: */
120:
121: return(mstash(nbuf, attnet));
122: }
123:
124: /*
125: * Make a little character.
126: */
127:
128: little(c)
129: register int c;
130: {
131:
132: if (c >= 'A' && c <= 'Z')
133: c += 'a' - 'A';
134: return(c);
135: }
136:
137: /*
138: * Turn a network unique character identifier into a network name.
139: */
140:
141: char *
142: netname(mid)
143: {
144: register struct netmach *np;
145: char *mlook();
146:
147: if (mid & 0200)
148: return(mlook(mid));
149: for (np = netmach; np->nt_mid != 0; np++)
150: if (np->nt_mid == mid)
151: return(np->nt_machine);
152: return(NOSTR);
153: }
154:
155: /*
156: * Take a network machine descriptor and find the types of connected
157: * nets and return it.
158: */
159:
160: nettype(mid)
161: {
162: register struct netmach *np;
163:
164: if (mid & 0200)
165: return(mtype(mid));
166: for (np = netmach; np->nt_mid != 0; np++)
167: if (np->nt_mid == mid)
168: return(np->nt_type);
169: return(0);
170: }
171:
172: /*
173: * Hashing routines to salt away machines seen scanning
174: * networks paths that we don't know about.
175: */
176:
177: #define XHSIZE 19 /* Size of extra hash table */
178: #define NXMID (XHSIZE*3/4) /* Max extra machines */
179:
180: struct xtrahash {
181: char *xh_name; /* Name of machine */
182: short xh_mid; /* Machine ID */
183: short xh_attnet; /* Attached networks */
184: } xtrahash[XHSIZE];
185:
186: struct xtrahash *xtab[XHSIZE]; /* F: mid-->machine name */
187:
188: short midfree; /* Next free machine id */
189:
190: /*
191: * Initialize the extra host hash table.
192: * Called by sreset.
193: */
194:
195: minit()
196: {
197: register struct xtrahash *xp, **tp;
198: register int i;
199:
200: midfree = 0;
201: tp = &xtab[0];
202: for (xp = &xtrahash[0]; xp < &xtrahash[XHSIZE]; xp++) {
203: xp->xh_name = NOSTR;
204: xp->xh_mid = 0;
205: xp->xh_attnet = 0;
206: *tp++ = (struct xtrahash *) 0;
207: }
208: }
209:
210: /*
211: * Stash a net name in the extra host hash table.
212: * If a new entry is put in the hash table, deduce what
213: * net the machine is attached to from the net character.
214: *
215: * If the machine is already known, add the given attached
216: * net to those already known.
217: */
218:
219: mstash(name, attnet)
220: char name[];
221: {
222: register struct xtrahash *xp;
223: struct xtrahash *xlocate();
224:
225: xp = xlocate(name);
226: if (xp == (struct xtrahash *) 0) {
227: printf("Ran out of machine id spots\n");
228: return(0);
229: }
230: if (xp->xh_name == NOSTR) {
231: if (midfree >= XHSIZE) {
232: printf("Out of machine ids\n");
233: return(0);
234: }
235: xtab[midfree] = xp;
236: xp->xh_name = savestr(name);
237: xp->xh_mid = 0200 + midfree++;
238: }
239: switch (attnet) {
240: case '!':
241: case '^':
242: xp->xh_attnet |= BN;
243: break;
244:
245: default:
246: case ':':
247: xp->xh_attnet |= SN;
248: break;
249:
250: case '@':
251: xp->xh_attnet |= AN;
252: break;
253: }
254: return(xp->xh_mid);
255: }
256:
257: /*
258: * Search for the given name in the hash table
259: * and return the pointer to it if found, or to the first
260: * empty slot if not found.
261: *
262: * If no free slots can be found, return 0.
263: */
264:
265: struct xtrahash *
266: xlocate(name)
267: char name[];
268: {
269: register int h, q, i;
270: register char *cp;
271: register struct xtrahash *xp;
272:
273: for (h = 0, cp = name; *cp; h = (h << 2) + *cp++)
274: ;
275: if (h < 0 && (h = -h) < 0)
276: h = 0;
277: h = h % XHSIZE;
278: cp = name;
279: for (i = 0, q = 0; q < XHSIZE; i++, q = i * i) {
280: xp = &xtrahash[(h + q) % XHSIZE];
281: if (xp->xh_name == NOSTR)
282: return(xp);
283: if (strcmp(cp, xp->xh_name) == 0)
284: return(xp);
285: if (h - q < 0)
286: q += XHSIZE;
287: xp = &xtrahash[(h - q) % XHSIZE];
288: if (xp->xh_name == NOSTR)
289: return(xp);
290: if (strcmp(cp, xp->xh_name) == 0)
291: return(xp);
292: }
293: return((struct xtrahash *) 0);
294: }
295:
296: /*
297: * Return the name from the extra host hash table corresponding
298: * to the passed machine id.
299: */
300:
301: char *
302: mlook(mid)
303: {
304: register int m;
305:
306: if ((mid & 0200) == 0)
307: return(NOSTR);
308: m = mid & 0177;
309: if (m >= midfree) {
310: printf("Use made of undefined machine id\n");
311: return(NOSTR);
312: }
313: return(xtab[m]->xh_name);
314: }
315:
316: /*
317: * Return the bit mask of net's that the given extra host machine
318: * id has so far.
319: */
320:
321: mtype(mid)
322: {
323: register int m;
324:
325: if ((mid & 0200) == 0)
326: return(0);
327: m = mid & 0177;
328: if (m >= midfree) {
329: printf("Use made of undefined machine id\n");
330: return(0);
331: }
332: return(xtab[m]->xh_attnet);
333: }
334:
335: /*
336: * Take a network name and optimize it. This gloriously messy
337: * opertions takes place as follows: the name with machine names
338: * in it is tokenized by mapping each machine name into a single
339: * character machine id (netlook). The separator characters (network
340: * metacharacters) are left intact. The last component of the network
341: * name is stripped off and assumed to be the destination user name --
342: * it does not participate in the optimization. As an example, the
343: * name "research!vax135!research!ucbvax!bill" becomes, tokenized,
344: * "r!x!r!v!" and "bill" A low level routine, optim1, fixes up the
345: * network part (eg, "r!x!r!v!"), then we convert back to network
346: * machine names and tack the user name on the end.
347: *
348: * The result of this is copied into the parameter "name"
349: */
350:
351: optim(net, name)
352: char net[], name[];
353: {
354: char netcomp[BUFSIZ], netstr[40], xfstr[40];
355: register char *cp, *cp2;
356: register int c;
357:
358: strcpy(netstr, "");
359: cp = net;
360: for (;;) {
361: /*
362: * Rip off next path component into netcomp
363: */
364: cp2 = netcomp;
365: while (*cp && !any(*cp, metanet))
366: *cp2++ = *cp++;
367: *cp2 = 0;
368: /*
369: * If we hit null byte, then we just scanned
370: * the destination user name. Go off and optimize
371: * if its so.
372: */
373: if (*cp == 0)
374: break;
375: if ((c = netlook(netcomp, *cp)) == 0) {
376: printf("No host named \"%s\"\n", netcomp);
377: err:
378: strcpy(name, net);
379: return;
380: }
381: stradd(netstr, c);
382: stradd(netstr, *cp++);
383: /*
384: * If multiple network separators given,
385: * throw away the extras.
386: */
387: while (any(*cp, metanet))
388: cp++;
389: }
390: if (strlen(netcomp) == 0) {
391: printf("net name syntax\n");
392: goto err;
393: }
394: optim1(netstr, xfstr);
395:
396: /*
397: * Convert back to machine names.
398: */
399:
400: cp = xfstr;
401: strcpy(name, "");
402: while (*cp) {
403: if ((cp2 = netname(*cp++)) == NOSTR) {
404: printf("Made up bad net name\n");
405: goto err;
406: }
407: strcat(name, cp2);
408: stradd(name, *cp++);
409: }
410: strcat(name, netcomp);
411: }
412:
413: /*
414: * Take a string of network machine id's and separators and
415: * optimize them. We process these by pulling off maximal
416: * leading strings of the same type, ppassing these to the appropriate
417: * optimizer and concatenating the results.
418: */
419:
420: #define IMPLICIT 1
421: #define EXPLICIT 2
422:
423: optim1(netstr, name)
424: char netstr[], name[];
425: {
426: char path[40], rpath[40];
427: register char *cp, *cp2;
428: register int tp, nc;
429:
430: cp = netstr;
431: prefer(cp);
432: strcpy(name, "");
433: while (*cp != 0) {
434: strcpy(path, "");
435: tp = ntype(cp[1]);
436: nc = cp[1];
437: while (*cp && tp == ntype(cp[1])) {
438: stradd(path, *cp++);
439: cp++;
440: }
441: switch (tp) {
442: default:
443: strcpy(rpath, path);
444: break;
445:
446: case IMPLICIT:
447: optimimp(path, rpath);
448: break;
449:
450: case EXPLICIT:
451: optimex(path, rpath);
452: break;
453: }
454: for (cp2 = rpath; *cp2 != 0; cp2++) {
455: stradd(name, *cp2);
456: stradd(name, nc);
457: }
458: }
459: optiboth(name);
460: prefer(name);
461: }
462:
463: /*
464: * Return the type of the separator --
465: * IMPLICIT -- if for a smart, implicitly routed network
466: * EXPLICIT -- if for a dumb, explicitly routed neetwork.
467: * 0 if we don't know.
468: */
469:
470: ntype(nc)
471: register int nc;
472: {
473:
474: switch (nc) {
475: case '^':
476: case '!':
477: return(EXPLICIT);
478:
479: case ':':
480: return(IMPLICIT);
481:
482: default:
483: return(0);
484: }
485: /* NOTREACHED */
486: }
487:
488: /*
489: * Do name optimization for an explicitly routed network (eg BTL network).
490: */
491:
492: optimex(net, name)
493: char net[], name[];
494: {
495: register char *cp, *rp;
496: register int m;
497: char *rindex();
498:
499: strcpy(name, net);
500: cp = name;
501: if (strlen(cp) == 0)
502: return(-1);
503: if (cp[strlen(cp)-1] == LOCAL) {
504: name[0] = 0;
505: return(0);
506: }
507: for (cp = name; *cp; cp++) {
508: m = *cp;
509: rp = rindex(cp+1, m);
510: if (rp != NOSTR)
511: strcpy(cp, rp);
512: }
513: return(0);
514: }
515:
516: /*
517: * Do name optimization for implicitly routed network (eg, arpanet,
518: * Berkeley network)
519: */
520:
521: optimimp(net, name)
522: char net[], name[];
523: {
524: register char *cp;
525: register int m;
526:
527: cp = net;
528: if (strlen(cp) == 0)
529: return(-1);
530: m = cp[strlen(cp) - 1];
531: if (m == LOCAL) {
532: strcpy(name, "");
533: return(0);
534: }
535: name[0] = m;
536: name[1] = 0;
537: return(0);
538: }
539:
540: /*
541:
542: * Perform global optimization on the given network path.
543: * The trick here is to look ahead to see if there are any loops
544: * in the path and remove them. The interpretation of loops is
545: * more strict here than in optimex since both the machine and net
546: * type must match.
547: */
548:
549: optiboth(net)
550: char net[];
551: {
552: register char *cp, *cp2;
553: char *rpair();
554:
555: cp = net;
556: if (strlen(cp) == 0)
557: return;
558: if ((strlen(cp) % 2) != 0) {
559: printf("Strange arg to optiboth\n");
560: return;
561: }
562: while (*cp) {
563: cp2 = rpair(cp+2, *cp, ntype(cp[1]));
564: if (cp2 != NOSTR)
565: strcpy(cp, cp2);
566: cp += 2;
567: }
568: }
569:
570: /*
571: * Find the rightmost instance of the given (machine, type) pair.
572: */
573:
574: char *
575: rpair(str, mach, t)
576: char str[];
577: {
578: register char *cp, *last;
579:
580: last = NOSTR;
581: while (*cp) {
582: if (*cp == mach /* && ntype(cp[1]) == t */ )
583: last = cp;
584: cp += 2;
585: }
586: return(last);
587: }
588:
589: /*
590: * Change the network separators in the given network path
591: * to the preferred network transmission means.
592: */
593:
594: prefer(name)
595: char name[];
596: {
597: register char *cp;
598: register int state, n;
599:
600: state = LOCAL;
601: for (cp = name; *cp; cp += 2) {
602: n = best(state, *cp);
603: if (n)
604: cp[1] = n;
605: state = *cp;
606: }
607: }
608:
609: /*
610: * Return the best network separator for the given machine pair.
611: */
612:
613: struct netorder {
614: short no_stat;
615: char no_char;
616: } netorder[] = {
617: CN, ':',
618: AN, '@',
619: SN, ':',
620: BN, '!',
621: -1, 0
622: };
623:
624: best(src, dest)
625: {
626: register int dtype, stype;
627: register struct netorder *np;
628:
629: stype = nettype(src);
630: dtype = nettype(dest);
631: if (stype == 0 || dtype == 0) {
632: printf("ERROR: unknown internal machine id\n");
633: return(0);
634: }
635: if ((stype & dtype) == 0) {
636: printf("No way to get from \"%s\" to \"%s\"\n",
637: netname(src), netname(dest));
638: return(0);
639: }
640: np = &netorder[0];
641: while ((np->no_stat & stype & dtype) == 0)
642: np++;
643: return(np->no_char);
644: }
645:
646: /*
647: * Add a single character onto a string.
648: */
649:
650: stradd(str, c)
651: register char *str;
652: register int c;
653: {
654:
655: str += strlen(str);
656: *str++ = c;
657: *str = 0;
658: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.