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