|
|
researchv10 Norman
#ident "@(#)optim.c 1.4 'attmail mail(1) command'"
#ident "@(#)mailx:optim.c 1.5.2.1"
/* Copyright (c) 1984 AT&T */
/* All Rights Reserved */
/* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T */
/* The copyright notice above does not evidence any */
/* actual or intended publication of such source code. */
#ident "@(#)mailx:optim.c 1.5"
/*
* mailx -- a modified version of a University of California at Berkeley
* mail program
*
* Network name modification routines.
*/
#include "rcv.h"
#include "configdefs.h"
static char *arpafix();
static char *lasthost();
static char *makeremote();
static int mstash();
static int mtype();
static int netlook();
static int nettype();
static int ntype();
static char *revarpa();
static char *tackon();
static struct xtrahash *xlocate();
static int yyinit();
static int yylex();
/*
* 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
* nonsense.
*/
char *
netmap(name, from)
char name[], from[];
{
char nbuf[BUFSIZ], ret[BUFSIZ];
register char *cp, *oname;
if (debug) fprintf(stderr, "netmap(name '%s', from '%s')\n", name, from);
if (strlen(from) == 0)
return(name);
if (any('@', name) || any('%', name))
return(arpafix(name, from));
if (any('@', from) || any('%', from))
return(unuucp(makeremote(name, from)));
if (value("onehop") && (cp = strchr(name, '!')) && cp > name)
strcpy(nbuf, name);
else {
from = tackon(host, from);
*strrchr(from, '!') = 0;
name = tackon(lasthost(from), name);
while (((cp = lasthost(from)) != 0) && ishost(cp, name)) {
oname = name;
name = strchr(name, '!') + 1;
if (cp == from) {
from[strlen(from)] = '!';
if (value("mustbang") && !strchr(name, '!'))
name = oname;
return(unuucp(name));
}
*--cp = 0;
}
from[strlen(from)] = '!';
from = strchr(from, '!') + 1;
sprintf(nbuf, "%s!%s", from, name);
}
strcpy(ret, nbuf);
cp = revarpa(ret);
if (debug) fprintf(stderr, "wind up with '%s'\n", name);
if (!icequal(name, cp))
return(unuucp(savestr(cp)));
return(unuucp(name));
}
/*
* Stick a host on the beginning of a uucp
* address if it isn't there already.
*/
static char *
tackon(sys, rest)
char *sys, *rest;
{
while (*rest == '!')
rest++;
if (!ishost(sys, rest)) {
char *r = salloc(strlen(sys) + strlen(rest) + 2);
sprintf(r, "%s!%s", sys, rest);
rest = r;
}
return rest;
}
/*
* Check equality of the first host in a uucp address.
*/
ishost(sys, rest)
char *sys, *rest;
{
while (*sys && *sys == *rest)
sys++, rest++;
return(*sys == 0 && *rest == '!');
}
/*
* Return last host in a uucp address.
*/
static char *
lasthost(addr)
char *addr;
{
char *r = strrchr(addr, '!');
return r ? ++r : addr;
}
/*
* Optionally translate an old format uucp name into a new one, e.g.
* "mach1!mach2!user" becomes "[email protected]". This optional because
* some information is necessarily lost (e.g. the route it got here
* via) and if we don't have the host in our routing tables, we lose.
*/
char *
unuucp(name)
char *name;
{
register char *np, *hp, *cp;
char result[100];
char tname[300];
if (UnUUCP==0 &&
((cp = value("conv"))==NOSTR || strcmp(cp, "internet")))
return name;
if (debug) fprintf(stderr, "unuucp(%s)\n", name);
strcpy(tname, name);
np = strrchr(tname, '!');
if (np == NOSTR)
return name;
*np++ = 0;
hp = strrchr(tname, '!');
if (hp == NOSTR)
hp = tname;
else
*hp++ = 0;
cp = strchr(np, '@');
if (cp == NOSTR)
cp = strchr(np, '%');
if (cp)
*cp = 0;
if (debug) fprintf(stderr, "host %s, name %s\n", hp, np);
sprintf(result, "%s@%s.UUCP", np, hp);
if (debug) fprintf(stderr, "unuucp returns %s\n", result);
return savestr(result);
}
/*
* Turn a network machine name into a unique character
*/
static int
netlook(machine, attnet)
char machine[];
{
register struct netmach *np;
register char *cp, *cp2;
char nbuf[BUFSIZ];
/*
* Make into lower case.
*/
for (cp = machine, cp2 = nbuf;
*cp && cp2 < &nbuf[BUFSIZ-1];
*cp2++ = tolower(*cp++))
/*nothing*/;
*cp2 = 0;
/*
* If a single letter machine, look through those first.
*/
if (strlen(nbuf) == 1)
for (np = netmach; np->nt_mid != 0; np++)
if (np->nt_mid == nbuf[0])
return(nbuf[0]);
/*
* Look for usual name
*/
for (np = netmach; np->nt_mid != 0; np++)
if (strcmp(np->nt_machine, nbuf) == 0)
return(np->nt_mid);
/*
* Look in side hash table.
*/
return(mstash(nbuf, attnet));
}
/*
* 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.
*/
static char *
arpafix(name, from)
char name[];
char from[];
{
register char *cp;
register int arpamach;
char newname[BUFSIZ];
if (debug) {
fprintf(stderr, "arpafix(%s, %s)\n", name, from);
}
cp = strrchr(name, '@');
if (cp == NOSTR)
cp = strrchr(name, '%');
if (cp == NOSTR) {
fprintf(stderr, "Somethings amiss -- no @ or %% in arpafix\n");
return(name);
}
cp++;
arpamach = netlook(cp, '@');
if (debug) fprintf(stderr, "cp '%s', arpamach %o, nettypes arpamach %o LOCAL %o\n", cp, arpamach, nettype(arpamach), nettype(LOCAL));
if (arpamach == 0) {
if (debug)
fprintf(stderr, "machine %s unknown, uses: %s\n", cp, name);
return(name);
}
if (((nettype(arpamach) & nettype(LOCAL)) & ~AN) == 0) {
if (debug)
fprintf(stderr, "machine %s known but remote, uses: %s\n",
cp, name);
return(name);
}
strcpy(newname, name);
cp = strrchr(newname, '@');
if (cp == NOSTR)
cp = strrchr(newname, '%');
*cp = 0;
if (debug) fprintf(stderr, "local address, return '%s'\n", newname);
return(savestr(newname));
}
/*
* We have name with no @'s in it, and from with @'s.
* Assume that name is meaningful only on the site in from.
*/
static char *
makeremote(name, from)
char name[];
char from[];
{
register char *cp;
static char rbuf[200];
if (debug) fprintf(stderr, "makeremote(%s, %s) returns ", name, from);
strcpy(rbuf, name);
cp = strrchr(from, '@');
if (cp == NOSTR)
cp = strrchr(from, '%');
strcat(rbuf, cp);
if (debug) fprintf(stderr, "%s\n", rbuf);
return rbuf;
}
/*
* Take a network machine descriptor and find the types of connected
* nets and return it.
*/
static int
nettype(mid)
{
register struct netmach *np;
if (mid & 0200)
return(mtype(mid));
for (np = netmach; np->nt_mid != 0; np++)
if (np->nt_mid == mid)
return(np->nt_type);
return(0);
}
/*
* 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 */
struct xtrahash {
char *xh_name; /* Name of machine */
short xh_mid; /* Machine ID */
short xh_attnet; /* Attached networks */
} xtrahash[XHSIZE];
static struct xtrahash *xtab[XHSIZE]; /* F: mid-->machine name */
static short midfree; /* Next free machine id */
/*
* Initialize the extra host hash table.
* Called by sreset.
*/
void
minit()
{
register struct xtrahash *xp, **tp;
midfree = 0;
tp = &xtab[0];
for (xp = &xtrahash[0]; xp < &xtrahash[XHSIZE]; xp++) {
xp->xh_name = NOSTR;
xp->xh_mid = 0;
xp->xh_attnet = 0;
*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.
*/
static int
mstash(name, attnet)
char name[];
{
register struct xtrahash *xp;
int x;
xp = xlocate(name);
if (xp == (struct xtrahash *) 0) {
printf("Ran out of machine id spots\n");
return(0);
}
if (xp->xh_name == NOSTR) {
if (midfree >= XHSIZE) {
printf("Out of machine ids\n");
return(0);
}
xtab[midfree] = xp;
xp->xh_name = savestr(name);
xp->xh_mid = 0200 + midfree++;
}
x = ntype(attnet);
if (x == 0)
xp->xh_attnet |= AN;
else
xp->xh_attnet |= x;
return(xp->xh_mid);
}
/*
* 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.
*/
static struct xtrahash *
xlocate(name)
char name[];
{
register int h, q, i;
register char *cp;
register struct xtrahash *xp;
for (h = 0, cp = name; *cp; h = (h << 2) + *cp++)
;
if (h < 0 && (h = -h) < 0)
h = 0;
h = h % XHSIZE;
cp = name;
for (i = 0, q = 0; q < XHSIZE; i++, q = i * i) {
xp = &xtrahash[(h + q) % XHSIZE];
if (xp->xh_name == NOSTR)
return(xp);
if (strcmp(cp, xp->xh_name) == 0)
return(xp);
if (h - q < 0)
q += XHSIZE;
xp = &xtrahash[(h - q) % XHSIZE];
if (xp->xh_name == NOSTR)
return(xp);
if (strcmp(cp, xp->xh_name) == 0)
return(xp);
}
return((struct xtrahash *) 0);
}
/*
* Return the bit mask of net's that the given extra host machine
* id has so far.
*/
static int
mtype(mid)
{
register int m;
if ((mid & 0200) == 0)
return(0);
m = mid & 0177;
if (m >= midfree) {
printf("Use made of undefined machine id\n");
return(0);
}
return(xtab[m]->xh_attnet);
}
/*
* Return the network of the separator --
* AN for arpa net
* BN for Bell labs net (e.g. UUCP, NOT Berknet)
* SN for Schmidt net (Berknet)
* 0 if we don't know.
*/
static int
ntype(nc)
register int nc;
{
register struct ntypetab *np;
for (np = ntypetab; np->nt_char != 0; np++)
if (np->nt_char == nc)
return(np->nt_bcode);
return(0);
}
/*
* Code to twist around arpa net names.
*/
#define WORD 257 /* Token for a string */
static char netbuf[256];
static char *yylval;
/*
* 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.
*/
static char *
revarpa(str)
char str[];
{
if (yyinit(str) < 0)
return(NOSTR);
if (name())
return(NOSTR);
if (strcmp(str, netbuf) == 0)
return(str);
return(savestr(netbuf));
}
/*
* Parse (by recursive descent) network names, using the following grammar:
* name:
* term {':' term}
* term {'^' term}
* term {'!' term}
* term '@' name
* term '%' name
*
* term:
* string of characters.
*/
name()
{
register int t;
register char *cp;
for (;;) {
t = yylex();
if (t != WORD)
return(-1);
cp = yylval;
t = yylex();
switch (t) {
case 0:
strcat(netbuf, cp);
return(0);
case '@':
case '%':
if (name())
return(-1);
strcat(netbuf, "@");
strcat(netbuf, cp);
return(0);
case WORD:
return(-1);
default:
strcat(netbuf, cp);
stradd(netbuf, t);
}
}
}
/*
* Scanner for network names.
*/
static char *charp; /* Current input pointer */
static int nexttok; /* Salted away next token */
/*
* Initialize the network name scanner.
*/
static int
yyinit(str)
char str[];
{
static char lexbuf[BUFSIZ];
netbuf[0] = 0;
if (strlen(str) >= sizeof lexbuf - 1)
return(-1);
nexttok = 0;
strcpy(lexbuf, str);
charp = lexbuf;
return(0);
}
/*
* Scan and return a single token.
* yylval is set to point to a scanned string.
*/
static int
yylex()
{
register char *cp, *dot;
register int s;
if (nexttok) {
s = nexttok;
nexttok = 0;
return(s);
}
cp = charp;
while (*cp && isspace(*cp))
cp++;
if (*cp == 0)
return(0);
if (any(*cp, metanet)) {
charp = cp+1;
return(*cp);
}
dot = cp;
while (*cp && !any(*cp, metanet) && !any(*cp, " \t"))
cp++;
if (any(*cp, metanet))
nexttok = *cp;
if (*cp == 0)
charp = cp;
else
charp = cp+1;
*cp = 0;
yylval = dot;
return(WORD);
}
/*
* Add a single character onto a string.
*/
void
stradd(str, c)
register char *str;
register int c;
{
while (*str)
str++;
*str++ = (char)c;
*str = '\0';
}
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.