|
|
1.1 root 1: #ident "@(#)optim.c 1.4 'attmail mail(1) command'"
2: #ident "@(#)mailx:optim.c 1.5.2.1"
3: /* Copyright (c) 1984 AT&T */
4: /* All Rights Reserved */
5:
6: /* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T */
7: /* The copyright notice above does not evidence any */
8: /* actual or intended publication of such source code. */
9:
10: #ident "@(#)mailx:optim.c 1.5"
11:
12: /*
13: * mailx -- a modified version of a University of California at Berkeley
14: * mail program
15: *
16: * Network name modification routines.
17: */
18:
19: #include "rcv.h"
20: #include "configdefs.h"
21:
22: static char *arpafix();
23: static char *lasthost();
24: static char *makeremote();
25: static int mstash();
26: static int mtype();
27: static int netlook();
28: static int nettype();
29: static int ntype();
30: static char *revarpa();
31: static char *tackon();
32: static struct xtrahash *xlocate();
33: static int yyinit();
34: static int yylex();
35:
36: /*
37: * Map a name into the correct network "view" of the
38: * name. This is done by prepending the name with the
39: * network address of the sender, then optimizing away
40: * nonsense.
41: */
42:
43: char *
44: netmap(name, from)
45: char name[], from[];
46: {
47: char nbuf[BUFSIZ], ret[BUFSIZ];
48: register char *cp, *oname;
49:
50: if (debug) fprintf(stderr, "netmap(name '%s', from '%s')\n", name, from);
51: if (strlen(from) == 0)
52: return(name);
53: if (any('@', name) || any('%', name))
54: return(arpafix(name, from));
55: if (any('@', from) || any('%', from))
56: return(unuucp(makeremote(name, from)));
57: if (value("onehop") && (cp = strchr(name, '!')) && cp > name)
58: strcpy(nbuf, name);
59: else {
60: from = tackon(host, from);
61: *strrchr(from, '!') = 0;
62: name = tackon(lasthost(from), name);
63: while (((cp = lasthost(from)) != 0) && ishost(cp, name)) {
64: oname = name;
65: name = strchr(name, '!') + 1;
66: if (cp == from) {
67: from[strlen(from)] = '!';
68: if (value("mustbang") && !strchr(name, '!'))
69: name = oname;
70: return(unuucp(name));
71: }
72: *--cp = 0;
73: }
74: from[strlen(from)] = '!';
75: from = strchr(from, '!') + 1;
76: sprintf(nbuf, "%s!%s", from, name);
77: }
78: strcpy(ret, nbuf);
79: cp = revarpa(ret);
80: if (debug) fprintf(stderr, "wind up with '%s'\n", name);
81: if (!icequal(name, cp))
82: return(unuucp(savestr(cp)));
83: return(unuucp(name));
84: }
85:
86: /*
87: * Stick a host on the beginning of a uucp
88: * address if it isn't there already.
89: */
90: static char *
91: tackon(sys, rest)
92: char *sys, *rest;
93: {
94: while (*rest == '!')
95: rest++;
96: if (!ishost(sys, rest)) {
97: char *r = salloc(strlen(sys) + strlen(rest) + 2);
98: sprintf(r, "%s!%s", sys, rest);
99: rest = r;
100: }
101: return rest;
102: }
103:
104: /*
105: * Check equality of the first host in a uucp address.
106: */
107: ishost(sys, rest)
108: char *sys, *rest;
109: {
110: while (*sys && *sys == *rest)
111: sys++, rest++;
112: return(*sys == 0 && *rest == '!');
113: }
114:
115: /*
116: * Return last host in a uucp address.
117: */
118: static char *
119: lasthost(addr)
120: char *addr;
121: {
122: char *r = strrchr(addr, '!');
123: return r ? ++r : addr;
124: }
125:
126: /*
127: * Optionally translate an old format uucp name into a new one, e.g.
128: * "mach1!mach2!user" becomes "[email protected]". This optional because
129: * some information is necessarily lost (e.g. the route it got here
130: * via) and if we don't have the host in our routing tables, we lose.
131: */
132: char *
133: unuucp(name)
134: char *name;
135: {
136: register char *np, *hp, *cp;
137: char result[100];
138: char tname[300];
139:
140: if (UnUUCP==0 &&
141: ((cp = value("conv"))==NOSTR || strcmp(cp, "internet")))
142: return name;
143: if (debug) fprintf(stderr, "unuucp(%s)\n", name);
144: strcpy(tname, name);
145: np = strrchr(tname, '!');
146: if (np == NOSTR)
147: return name;
148: *np++ = 0;
149: hp = strrchr(tname, '!');
150: if (hp == NOSTR)
151: hp = tname;
152: else
153: *hp++ = 0;
154: cp = strchr(np, '@');
155: if (cp == NOSTR)
156: cp = strchr(np, '%');
157: if (cp)
158: *cp = 0;
159: if (debug) fprintf(stderr, "host %s, name %s\n", hp, np);
160: sprintf(result, "%s@%s.UUCP", np, hp);
161: if (debug) fprintf(stderr, "unuucp returns %s\n", result);
162: return savestr(result);
163: }
164:
165: /*
166: * Turn a network machine name into a unique character
167: */
168: static int
169: netlook(machine, attnet)
170: char machine[];
171: {
172: register struct netmach *np;
173: register char *cp, *cp2;
174: char nbuf[BUFSIZ];
175:
176: /*
177: * Make into lower case.
178: */
179: for (cp = machine, cp2 = nbuf;
180: *cp && cp2 < &nbuf[BUFSIZ-1];
181: *cp2++ = tolower(*cp++))
182: /*nothing*/;
183: *cp2 = 0;
184:
185: /*
186: * If a single letter machine, look through those first.
187: */
188:
189: if (strlen(nbuf) == 1)
190: for (np = netmach; np->nt_mid != 0; np++)
191: if (np->nt_mid == nbuf[0])
192: return(nbuf[0]);
193:
194: /*
195: * Look for usual name
196: */
197:
198: for (np = netmach; np->nt_mid != 0; np++)
199: if (strcmp(np->nt_machine, nbuf) == 0)
200: return(np->nt_mid);
201:
202: /*
203: * Look in side hash table.
204: */
205:
206: return(mstash(nbuf, attnet));
207: }
208:
209: /*
210: * Deal with arpa net addresses. The way this is done is strange.
211: * In particular, if the destination arpa net host is not Berkeley,
212: * then the address is correct as stands. Otherwise, we strip off
213: * the trailing @Berkeley, then cook up a phony person for it to
214: * be from and optimize the result.
215: */
216: static char *
217: arpafix(name, from)
218: char name[];
219: char from[];
220: {
221: register char *cp;
222: register int arpamach;
223: char newname[BUFSIZ];
224:
225: if (debug) {
226: fprintf(stderr, "arpafix(%s, %s)\n", name, from);
227: }
228: cp = strrchr(name, '@');
229: if (cp == NOSTR)
230: cp = strrchr(name, '%');
231: if (cp == NOSTR) {
232: fprintf(stderr, "Somethings amiss -- no @ or %% in arpafix\n");
233: return(name);
234: }
235: cp++;
236: arpamach = netlook(cp, '@');
237: if (debug) fprintf(stderr, "cp '%s', arpamach %o, nettypes arpamach %o LOCAL %o\n", cp, arpamach, nettype(arpamach), nettype(LOCAL));
238: if (arpamach == 0) {
239: if (debug)
240: fprintf(stderr, "machine %s unknown, uses: %s\n", cp, name);
241: return(name);
242: }
243: if (((nettype(arpamach) & nettype(LOCAL)) & ~AN) == 0) {
244: if (debug)
245: fprintf(stderr, "machine %s known but remote, uses: %s\n",
246: cp, name);
247: return(name);
248: }
249: strcpy(newname, name);
250: cp = strrchr(newname, '@');
251: if (cp == NOSTR)
252: cp = strrchr(newname, '%');
253: *cp = 0;
254: if (debug) fprintf(stderr, "local address, return '%s'\n", newname);
255: return(savestr(newname));
256: }
257:
258: /*
259: * We have name with no @'s in it, and from with @'s.
260: * Assume that name is meaningful only on the site in from.
261: */
262: static char *
263: makeremote(name, from)
264: char name[];
265: char from[];
266: {
267: register char *cp;
268: static char rbuf[200];
269:
270: if (debug) fprintf(stderr, "makeremote(%s, %s) returns ", name, from);
271: strcpy(rbuf, name);
272: cp = strrchr(from, '@');
273: if (cp == NOSTR)
274: cp = strrchr(from, '%');
275: strcat(rbuf, cp);
276: if (debug) fprintf(stderr, "%s\n", rbuf);
277: return rbuf;
278: }
279:
280: /*
281: * Take a network machine descriptor and find the types of connected
282: * nets and return it.
283: */
284: static int
285: nettype(mid)
286: {
287: register struct netmach *np;
288:
289: if (mid & 0200)
290: return(mtype(mid));
291: for (np = netmach; np->nt_mid != 0; np++)
292: if (np->nt_mid == mid)
293: return(np->nt_type);
294: return(0);
295: }
296:
297: /*
298: * Hashing routines to salt away machines seen scanning
299: * networks paths that we don't know about.
300: */
301:
302: #define XHSIZE 19 /* Size of extra hash table */
303: #define NXMID (XHSIZE*3/4) /* Max extra machines */
304:
305: struct xtrahash {
306: char *xh_name; /* Name of machine */
307: short xh_mid; /* Machine ID */
308: short xh_attnet; /* Attached networks */
309: } xtrahash[XHSIZE];
310:
311: static struct xtrahash *xtab[XHSIZE]; /* F: mid-->machine name */
312:
313: static short midfree; /* Next free machine id */
314:
315: /*
316: * Initialize the extra host hash table.
317: * Called by sreset.
318: */
319: void
320: minit()
321: {
322: register struct xtrahash *xp, **tp;
323:
324: midfree = 0;
325: tp = &xtab[0];
326: for (xp = &xtrahash[0]; xp < &xtrahash[XHSIZE]; xp++) {
327: xp->xh_name = NOSTR;
328: xp->xh_mid = 0;
329: xp->xh_attnet = 0;
330: *tp++ = (struct xtrahash *) 0;
331: }
332: }
333:
334: /*
335: * Stash a net name in the extra host hash table.
336: * If a new entry is put in the hash table, deduce what
337: * net the machine is attached to from the net character.
338: *
339: * If the machine is already known, add the given attached
340: * net to those already known.
341: */
342: static int
343: mstash(name, attnet)
344: char name[];
345: {
346: register struct xtrahash *xp;
347: int x;
348:
349: xp = xlocate(name);
350: if (xp == (struct xtrahash *) 0) {
351: printf("Ran out of machine id spots\n");
352: return(0);
353: }
354: if (xp->xh_name == NOSTR) {
355: if (midfree >= XHSIZE) {
356: printf("Out of machine ids\n");
357: return(0);
358: }
359: xtab[midfree] = xp;
360: xp->xh_name = savestr(name);
361: xp->xh_mid = 0200 + midfree++;
362: }
363: x = ntype(attnet);
364: if (x == 0)
365: xp->xh_attnet |= AN;
366: else
367: xp->xh_attnet |= x;
368: return(xp->xh_mid);
369: }
370:
371: /*
372: * Search for the given name in the hash table
373: * and return the pointer to it if found, or to the first
374: * empty slot if not found.
375: *
376: * If no free slots can be found, return 0.
377: */
378:
379: static struct xtrahash *
380: xlocate(name)
381: char name[];
382: {
383: register int h, q, i;
384: register char *cp;
385: register struct xtrahash *xp;
386:
387: for (h = 0, cp = name; *cp; h = (h << 2) + *cp++)
388: ;
389: if (h < 0 && (h = -h) < 0)
390: h = 0;
391: h = h % XHSIZE;
392: cp = name;
393: for (i = 0, q = 0; q < XHSIZE; i++, q = i * i) {
394: xp = &xtrahash[(h + q) % XHSIZE];
395: if (xp->xh_name == NOSTR)
396: return(xp);
397: if (strcmp(cp, xp->xh_name) == 0)
398: return(xp);
399: if (h - q < 0)
400: q += XHSIZE;
401: xp = &xtrahash[(h - q) % XHSIZE];
402: if (xp->xh_name == NOSTR)
403: return(xp);
404: if (strcmp(cp, xp->xh_name) == 0)
405: return(xp);
406: }
407: return((struct xtrahash *) 0);
408: }
409:
410: /*
411: * Return the bit mask of net's that the given extra host machine
412: * id has so far.
413: */
414: static int
415: mtype(mid)
416: {
417: register int m;
418:
419: if ((mid & 0200) == 0)
420: return(0);
421: m = mid & 0177;
422: if (m >= midfree) {
423: printf("Use made of undefined machine id\n");
424: return(0);
425: }
426: return(xtab[m]->xh_attnet);
427: }
428:
429: /*
430: * Return the network of the separator --
431: * AN for arpa net
432: * BN for Bell labs net (e.g. UUCP, NOT Berknet)
433: * SN for Schmidt net (Berknet)
434: * 0 if we don't know.
435: */
436: static int
437: ntype(nc)
438: register int nc;
439: {
440: register struct ntypetab *np;
441:
442: for (np = ntypetab; np->nt_char != 0; np++)
443: if (np->nt_char == nc)
444: return(np->nt_bcode);
445: return(0);
446: }
447:
448:
449: /*
450: * Code to twist around arpa net names.
451: */
452:
453: #define WORD 257 /* Token for a string */
454:
455: static char netbuf[256];
456: static char *yylval;
457:
458: /*
459: * Reverse all of the arpa net addresses in the given name to
460: * be of the form "host @ user" instead of "user @ host"
461: * This function is its own inverse.
462: */
463:
464: static char *
465: revarpa(str)
466: char str[];
467: {
468:
469: if (yyinit(str) < 0)
470: return(NOSTR);
471: if (name())
472: return(NOSTR);
473: if (strcmp(str, netbuf) == 0)
474: return(str);
475: return(savestr(netbuf));
476: }
477:
478: /*
479: * Parse (by recursive descent) network names, using the following grammar:
480: * name:
481: * term {':' term}
482: * term {'^' term}
483: * term {'!' term}
484: * term '@' name
485: * term '%' name
486: *
487: * term:
488: * string of characters.
489: */
490:
491: name()
492: {
493: register int t;
494: register char *cp;
495:
496: for (;;) {
497: t = yylex();
498: if (t != WORD)
499: return(-1);
500: cp = yylval;
501: t = yylex();
502: switch (t) {
503: case 0:
504: strcat(netbuf, cp);
505: return(0);
506:
507: case '@':
508: case '%':
509: if (name())
510: return(-1);
511: strcat(netbuf, "@");
512: strcat(netbuf, cp);
513: return(0);
514:
515: case WORD:
516: return(-1);
517:
518: default:
519: strcat(netbuf, cp);
520: stradd(netbuf, t);
521: }
522: }
523: }
524:
525: /*
526: * Scanner for network names.
527: */
528:
529: static char *charp; /* Current input pointer */
530: static int nexttok; /* Salted away next token */
531:
532: /*
533: * Initialize the network name scanner.
534: */
535: static int
536: yyinit(str)
537: char str[];
538: {
539: static char lexbuf[BUFSIZ];
540:
541: netbuf[0] = 0;
542: if (strlen(str) >= sizeof lexbuf - 1)
543: return(-1);
544: nexttok = 0;
545: strcpy(lexbuf, str);
546: charp = lexbuf;
547: return(0);
548: }
549:
550: /*
551: * Scan and return a single token.
552: * yylval is set to point to a scanned string.
553: */
554: static int
555: yylex()
556: {
557: register char *cp, *dot;
558: register int s;
559:
560: if (nexttok) {
561: s = nexttok;
562: nexttok = 0;
563: return(s);
564: }
565: cp = charp;
566: while (*cp && isspace(*cp))
567: cp++;
568: if (*cp == 0)
569: return(0);
570: if (any(*cp, metanet)) {
571: charp = cp+1;
572: return(*cp);
573: }
574: dot = cp;
575: while (*cp && !any(*cp, metanet) && !any(*cp, " \t"))
576: cp++;
577: if (any(*cp, metanet))
578: nexttok = *cp;
579: if (*cp == 0)
580: charp = cp;
581: else
582: charp = cp+1;
583: *cp = 0;
584: yylval = dot;
585: return(WORD);
586: }
587:
588: /*
589: * Add a single character onto a string.
590: */
591:
592: void
593: stradd(str, c)
594: register char *str;
595: register int c;
596: {
597: while (*str)
598: str++;
599: *str++ = (char)c;
600: *str = '\0';
601: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.