* Mail -- a program for sending and receiving mail.
* Network name modification routines.
static char *SccsId
= "@(#)optim.c 2.4 %G%";
* Map a name into the correct network "view" of the
* name. This is done by prepending the name with the
* network address of the sender, then optimizing away
char nbuf
[BUFSIZ
], ret
[BUFSIZ
];
if (any('@', name
) || any('%', name
))
return(arpafix(name
, from
));
cp
= &nbuf
[strlen(nbuf
) - 1];
while (!any(*cp
, metanet
) && cp
> nbuf
)
strcat(nbuf
, revarpa(name
));
return((char *) savestr(cp
));
* Rename the given network path to use
* the kinds of names that we would right here.
char buf
[BUFSIZ
], path
[BUFSIZ
];
while (!any(c
, metanet
) && c
!= 0) {
host
= netlook(buf
, ntype(c
));
strcat(path
, netname(host
));
if (strcmp(str
, path
) != 0)
* Turn a network machine name into a unique character
register struct netmach
*np
;
for (cp
= machine
, cp2
= nbuf
; *cp
; *cp2
++ = little(*cp
++))
* If a single letter machine, look through those first.
for (np
= netmach
; np
->nt_mid
!= 0; np
++)
if (np
->nt_mid
== nbuf
[0])
for (np
= netmach
; np
->nt_mid
!= 0; np
++)
if (strcmp(np
->nt_machine
, nbuf
) == 0)
* Look in side hash table.
return(mstash(nbuf
, attnet
));
* Make a little character.
if (c
>= 'A' && c
<= 'Z')
* Turn a network unique character identifier into a network name.
register struct netmach
*np
;
for (np
= netmach
; np
->nt_mid
!= 0; np
++)
* Deal with arpa net addresses. The way this is done is strange.
* In particular, if the destination arpa net host is not Berkeley,
* then the address is correct as stands. Otherwise, we strip off
* the trailing @Berkeley, then cook up a phony person for it to
* be from and optimize the result.
fprintf(stderr
, "arpafix(%s, %s)\n", name
, from
);
fprintf(stderr
, "Somethings amiss -- no @ or % in arpafix\n");
arpamach
= netlook(cp
, '@');
fprintf(stderr
, "machine %s unknown, uses: %s\n", cp
, name
);
if (((nettype(arpamach
) & nettype(LOCAL
)) & ~AN
) == 0) {
fprintf(stderr
, "machine %s known but remote, uses: %s\n",
cp
= rindex(newname
, '@');
cp
= rindex(newname
, '%');
strcpy(fakepath
, netname(fake
[0]));
stradd(fakepath
, fake
[1]);
strcat(fakepath
, "daemon");
fprintf(stderr
, "machine local, call netmap(%s, %s)\n",
return(netmap(newname
, fakepath
));
* Take a network machine descriptor and find the types of connected
register struct netmach
*np
;
for (np
= netmach
; np
->nt_mid
!= 0; np
++)
* Hashing routines to salt away machines seen scanning
* networks paths that we don't know about.
#define XHSIZE 19 /* Size of extra hash table */
#define NXMID (XHSIZE*3/4) /* Max extra machines */
char *xh_name
; /* Name of machine */
short xh_mid
; /* Machine ID */
short xh_attnet
; /* Attached networks */
struct xtrahash
*xtab
[XHSIZE
]; /* F: mid-->machine name */
short midfree
; /* Next free machine id */
* Initialize the extra host hash table.
register struct xtrahash
*xp
, **tp
;
for (xp
= &xtrahash
[0]; xp
< &xtrahash
[XHSIZE
]; xp
++) {
*tp
++ = (struct xtrahash
*) 0;
* Stash a net name in the extra host hash table.
* If a new entry is put in the hash table, deduce what
* net the machine is attached to from the net character.
* If the machine is already known, add the given attached
* net to those already known.
register struct xtrahash
*xp
;
struct xtrahash
*xlocate();
if (xp
== (struct xtrahash
*) 0) {
printf("Ran out of machine id spots\n");
if (xp
->xh_name
== NOSTR
) {
printf("Out of machine ids\n");
xp
->xh_name
= savestr(name
);
xp
->xh_mid
= 0200 + midfree
++;
* Search for the given name in the hash table
* and return the pointer to it if found, or to the first
* empty slot if not found.
* If no free slots can be found, return 0.
register struct xtrahash
*xp
;
for (h
= 0, cp
= name
; *cp
; h
= (h
<< 2) + *cp
++)
if (h
< 0 && (h
= -h
) < 0)
for (i
= 0, q
= 0; q
< XHSIZE
; i
++, q
= i
* i
) {
xp
= &xtrahash
[(h
+ q
) % XHSIZE
];
if (xp
->xh_name
== NOSTR
)
if (strcmp(cp
, xp
->xh_name
) == 0)
xp
= &xtrahash
[(h
- q
) % XHSIZE
];
if (xp
->xh_name
== NOSTR
)
if (strcmp(cp
, xp
->xh_name
) == 0)
return((struct xtrahash
*) 0);
* Return the name from the extra host hash table corresponding
* to the passed machine id.
printf("Use made of undefined machine id\n");
return(xtab
[m
]->xh_name
);
* Return the bit mask of net's that the given extra host machine
printf("Use made of undefined machine id\n");
return(xtab
[m
]->xh_attnet
);
* Take a network name and optimize it. This gloriously messy
* operation takes place as follows: the name with machine names
* in it is tokenized by mapping each machine name into a single
* character machine id (netlook). The separator characters (network
* metacharacters) are left intact. The last component of the network
* name is stripped off and assumed to be the destination user name --
* it does not participate in the optimization. As an example, the
* name "research!vax135!research!ucbvax!bill" becomes, tokenized,
* "r!x!r!v!" and "bill" A low level routine, optim1, fixes up the
* network part (eg, "r!x!r!v!"), then we convert back to network
* machine names and tack the user name on the end.
* The result of this is copied into the parameter "name"
char netcomp
[BUFSIZ
], netstr
[40], xfstr
[40];
* Rip off next path component into netcomp
while (*cp
&& !any(*cp
, metanet
))
* If we hit null byte, then we just scanned
* the destination user name. Go off and optimize
if ((c
= netlook(netcomp
, *cp
)) == 0) {
printf("No host named \"%s\"\n", netcomp
);
* If multiple network separators given,
while (any(*cp
, metanet
))
if (strlen(netcomp
) == 0) {
printf("net name syntax\n");
* Convert back to machine names.
if ((cp2
= netname(*cp
++)) == NOSTR
) {
printf("Made up bad net name\n");
printf("Machine code %c (0%o)\n", cp
[-1], cp
[-1]);
printf("Sorry -- dumping now. Alert K. Shoens\n");
* Take a string of network machine id's and separators and
* optimize them. We process these by pulling off maximal
* leading strings of the same type, passing these to the appropriate
* optimizer and concatenating the results.
char path
[40], rpath
[40];
* If the address ultimately points back to us,
* just return a null network path.
if (strlen(cp
) > 1 && cp
[strlen(cp
) - 2] == LOCAL
)
while (*cp
&& tp
== ntype(cp
[1])) {
for (cp2
= rpath
; *cp2
!= 0; cp2
++) {
* Return the network of the separator --
* SN for Schmidt (berkeley net)
register struct nettypetab
*np
;
for (np
= nettypetab
; np
->nt_char
!= 0; np
++)
* Return the kind of routing used for the particular net
* EXPLICIT means explicitly routed
* IMPLICIT means implicitly routed
register struct netkindtab
*np
;
for (np
= netkindtab
; np
->nk_type
!= 0; np
++)
* Do name optimization for an explicitly routed network (eg BTL network).
if (cp
[strlen(cp
)-1] == LOCAL
) {
for (cp
= name
; *cp
; cp
++) {
* Do name optimization for implicitly routed network (eg, arpanet,
* Perform global optimization on the given network path.
* The trick here is to look ahead to see if there are any loops
* in the path and remove them. The interpretation of loops is
* more strict here than in optimex since both the machine and net
if ((strlen(cp
) % 2) != 0) {
printf("Strange arg to optiboth\n");
* Find the rightmost instance of the given (machine, type) pair.
register char *cp
, *last
;
* Change the network separators in the given network path
* to the preferred network transmission means.
for (cp
= name
; *cp
; cp
+= 2) {
* Return the best network separator for the given machine pair.
register int dtype
, stype
;
register struct netorder
*np
;
if (stype
== 0 || dtype
== 0) {
printf("ERROR: unknown internal machine id\n");
if ((stype
& dtype
) == 0)
while ((np
->no_stat
& stype
& dtype
) == 0)
* Code to twist around arpa net names.
#define WORD 257 /* Token for a string */
* Reverse all of the arpa net addresses in the given name to
* be of the form "host @ user" instead of "user @ host"
* This function is its own inverse.
if (strcmp(str
, netbuf
) == 0)
* Parse (by recursive descent) network names, using the following grammar:
* Scanner for network names.
static char *charp
; /* Current input pointer */
static int nexttok
; /* Salted away next token */
* Initialize the network name scanner.
static char lexbuf
[BUFSIZ
];
if (strlen(str
) >= sizeof lexbuf
- 1)
* Scan and return a single token.
* yylval is set to point to a scanned string.
while (*cp
&& isspace(*cp
))
while (*cp
&& !any(*cp
, metanet
) && !any(*cp
, " \t"))
* Add a single character onto a string.