[pe.cust.sources] Domain-Oriented Rmail

jer@peora.UUCP (J. Eric Roskos) (08/21/85)

The following set of files are an experimental, domain-based rmail program
for the UUCP network.

If you have been following recent discussions in net.mail, you know that I
have recently commented several times on an experimental version of a
domain-based mailer which I have been working on in my spare time in order
to test the ideas behind domain addressing for UUCP mail.

As a result of considerable prompting from several people, I have decided
to post this program to pe.cust.sources in order to allow other people to
also experiment with it.  (These are not the people who prompted for it,
but I would rather give it a limited distribution for the time being, since
it is very experimental.)

This program is by no means a PE product; it is a modification of an old
Rand (public domain) mailer which I have been making in my spare time
(mostly my lunch hours) in order to test ideas resulting from the ARPA
Network Working Group's proposed standards for network mail.  It is also an
attempt to discover ways to disambiguate routing and addressing problems
that result from the widespread use of the Sendmail program provided with
BSD 4.2.  Thus, to use the program, you will probably need to make various
changes, particularly in the area of changing the program that gets invoked
to send mail to local mailboxes.  The current program invokes another
program called "deliver", which is an old Rand program.  As explained under
Note(1) in the rmail source, you can probably just change this to invoke
"mail" instead.

Also included are two library subroutines for parsing of domain-style
addresses (in the two popular formats) and generation of UUCP routes from
them.  These routines, and thus rmail itself, require you to have a DBM-
style pathalias database (although you could modify the database lookup
routines in opath if you use the plain text file generated by pathalias).

Before compiling these, look over the source, particularly the beginning of
each file, since there are some strings in each you will probably need to
redefine to suit your particular site's configuration.


Underlying this version of rmail are the "three rules" I explained recently
in net.mail:

1) Never modify a route you are given.   If a message comes in by UUCP,
   send it out by UUCP, using the specified path.

2) If a site is nonadjacent, or in domain format, treat this as a nameserver
   request: generate a path to the site or nameserver.

3) Don't rewrite existing message headers; only add new ones.


This program's main purpose is for forwarding mail to other sites.  In
doing so, it provides the services of a domain nameserver to adjacent sites
which don't have a "smart mailer".  It is capable of serving as THE domain
namerserver for a subdomain (e.g., a corporation's set of local machines
whose connectivity information is not published in the UUCP maps).

Here is the program.  If you use it, let me know how it works out.  We've
been using it here at peora for about nine months now with considerable
success.  However, it has not thus far been tested at any other site.

					   E. Roskos
					   PE Southern Development Center
					   (jer@peora.UUCP)

#	This is a shell archive.
#	Remove everything above and including the cut line.
#	Then run the rest of the file through sh.
#-----cut here-----cut here-----cut here-----cut here-----
#!/bin/sh
# shar:	Shell Archiver
#	Run the following text with /bin/sh to create:
#	opath.c
#	address.c
#	rmail.c
#	deliverr.h
#	/usr/man/local/man1/address.1
#	/usr/man/local/man3/opath.3
#	/usr/man/local/man1/rmail.1
#	/usr/lib/uucp/domains
# This archive created: Wed Aug 21 10:09:07 1985
echo shar: extracting opath.c '(7087 characters)'
cat << \SHAR_EOF > opath.c
/*
 * opath.c - get an optimal uucp path from the path database, using an
 * RFC882-style address as input.  The '%' character is properly translated,
 * and gateway-substitution is done to get mail onto other networks.
 *
 * This program requires the DBM-style pathalias database.
 *
 * Eric Roskos, Perkin-Elmer Corp. SDC
 * Version 2.5 created 85/08/20 13:49:53
 */

static char *opathsccsid = "@(#)opath.c	2.5 (peora) 13:49:53 - 85/08/20";

#include <stdio.h>

/**
 ** User-configurable parameters
 **/

/* locations of files */

static char *archive = "/usr/lib/uucp/alpath";  /* pathalias database   */
static char *domfile = "/usr/lib/uucp/domains"; /* gateway/domain table */
static char *logfile = "/usr/adm/opath.log";    /* activity log */

/* list of sites you talk to directly */

static char *oursites[] =
{
	"peora",   /* must include your own site here too */
	"petsd",
	"pecnos",
	"pesnta",
	"pedsgd",
	"ucf-cs",
	"vbilt",
	0
};

/*
 * define HORTON_SYNTAX to generate Mark & Karen Horton's proposed (and,
 * alas, complicating) new syntax for UUCP paths
 */

/*** #define HORTON_SYNTAX   ***/

/**
 ** Global Variables
 **/

static char pval[150]; /* the path string is built here */

/*
 * the following are used to pass results by side-effect from the domain()
 * routine.
 */

static char prefix[80], suffix[80], fullsite[80];

/**
 ** Subroutines
 **/

/*
 * The Domain Table and its associated routines
 */

static struct domains
{
	char dom[50];
	char pre[50];
	char suf[50];
	int class;
} domtab[100];

/* Inline routine to copy a domain into the domain table */

#define DOMCPY(fld) { int i = 0; q=dp->fld; while (*p!=','&&*p!='\n'&&*p) \
		    {*q++ = *p++; if (i++>=48) break;} \
		    *q++ = '\0'; if (!*p) { \
		    fprintf(stderr,"opath: fld(s) missing in %s at %s\n", \
		    s, buf); \
		    dp++; continue;} p++; }

/* Load the domain table from disk */

static int
loaddomtab(s)
char *s;
{
FILE *f;
char buf[100];
register char *p,*q;
struct domains *dp;

	f = fopen(s,"r");
	if (f==NULL)
	{
		fprintf(stderr,"opath: can't open domain file '%s'\n",s);
		exit(1);
	}

	dp = domtab;

	while (fgets(buf,100,f))
	{
		if (buf[0]=='#') continue; /* comments start with "#" */
		p = buf;
		DOMCPY(dom);
		DOMCPY(pre);
		DOMCPY(suf);
		dp->class = atoi(p);
		if (dp->class == 0)
		{
			fprintf(stderr,"opath: bad domain class in %s\n",s);
			dp->class = 1;
		}
		dp++;
	}

	dp->class = 0;  /* mark end of table */
	fclose(f);

	return(0);
}

/* Get a UUCP path from the pathalias database */

static char *
gpath(s)
char *s;
{
static char path[100];
char *uupath();

	strcpy(path,uupath(s));
	strcat(path,"!"); /* depends on version of pathalias */
	return(path);
}

/* String compare: entire first argument must match suffix of 2nd argument */

static int
domcmp(ss,tt)
char *ss, *tt;
{
char *s, *t;
int cmp;

	s = ss + strlen(ss) - 1;
	t = tt + strlen(tt) - 1;

	do
	{
		if (*s - *t) break;
		s--;
		t--;
	} while (s >= ss);

	if (++s == ss) return(0);
	else return(1);
}

/* Look up a domain, and by side effect set prefix and suffix appropriately */

static int domain(s)
char *s;
{
struct domains *d;
char *p;
static int loaded = 0;

	if (!loaded++) loaddomtab(domfile);

	if (*s!='.') /* default to UUCP domain */
	{
		prefix[0]=suffix[0]='\0';
		return(1);
	}

	for (p=s; *p; p++) if (*p>='a' && *p<='z') *p -= 'a'-'A';

	for (d = &domtab[0]; d->class; d++)
	{
		if (domcmp(d->dom,s)==0) break;
	}

	strcpy(prefix,(d->pre[0]=='>')? gpath(&d->pre[1]) : d->pre);
	strcpy(suffix,d->suf);

	return(d->class);
}

/* opath: generates a UUCP path from an RFC-822 address */

char *
opath(s)
char *s;
{
char user[50],site[50];
static char cm[150];
FILE *f;
char *p, *q, *t;
int d;
int i;
int found;
char *suf;

	for (p=user,q=s;(*p = *q)!='@'; p++,q++)
		if (*q=='\0') return(s);
	*p = '\0';

	strcpy(fullsite,++q);

	for (p=site;(*p = *q)!='.'; p++,q++)
		if (*q=='\0') break;
	*p = '\0';

	d = domain(q);

	/* Now based on what kind of domain it is, xlate the address */

	if (d==5)  /* delivery to a UUCP domain server */
	{
		strcpy(cm,prefix);
		strcat(cm,site);
		strcat(cm,"!");
		strcat(cm,user);
		return(cm);
	}
	else
	if (d!=1)  /* delivery to an other-network gateway */
	{
		strcpy(cm,prefix);
#ifndef HORTON_SYNTAX
		strcat(cm,s);
#else
		if (*suffix)
		{
			for (suf=suffix; *suf=='@'; suf++) ;
			strcat(cm,suf);
			strcat(cm,"!");
		}
		strcat(cm,fullsite);
		strcat(cm,"!");
		for (p=s,t = &cm[strlen(cm)]; *p && *p!='@'; p++,t++) *t = *p;
		*t = '\0';
#endif
		if (d==2 || d==3)
		{
			for (p=cm+strlen(cm)-1; p>cm; p--)
			{
				if (*p=='@')
				{
					*p = d==2? '%' : '.';
					break;
				}
				if (*p=='.' && d==3) *p='\0';
			}
		}
#ifndef HORTON_SYNTAX
		strcat(cm,suffix);
#endif
		return(cm);
	}

	/* delivery to a UUCP site whose path we can fully resolve */

	/**** WARNING: don't change value of q below this point ****/

	for (i=0,found=0; oursites[i]; i++)
		if (strcmp(site,oursites[i])==0)
		{
			strcpy(pval,site);
			found++;
			break;
		}

	if (!found) strcpy(pval,uupath(site));
	strcat(pval,"!");
	for (p=user+strlen(user); p>=user; --p)
		if (*p=='%')
		{
			*p = '@';
			break;
		}
	strcat(pval,user);
	if (*q=='\0') strcpy(p,".UUCP"); /* here's why you shldn't change q */
	return(pval);
}

/* oupath: generates a uucp path from a (possibly disconnected) uucp path */

char *oupath(s)
char *s;
{
char *p,*q;
static char adr[100];
char first[100];
int found;

	for (p=s,q=first,found=0; *p!='!' && *p!='\0'; p++)
	{
		if (*p=='.') found++;
		*q++ = *p;
	}
	if (*p=='\0') return (s);

	*q = '\0';

	if (found)
	{
		strcpy(adr,++p);
		strcat(adr,"@");
		strcat(adr,first);
		return(opath(adr));
	}
	else
	{
	int i;
		for (i=0; oursites[i]; i++)
			if (strcmp(first,oursites[i])==0)
				return(s);

		strcpy(adr,gpath(first));
		strcat(adr,++p);

		return(adr);
	}
}

/**
 ** Public-domain subroutines obtained from net.sources
 **/

/*
 * The following is extracted from William Sebok's uupath program
 */

/* * * * uupath - look up path to computer in database * * * W.Sebok 11/4/83 */
#ifdef NULL
#undef NULL
#define NULL 0
#endif

typedef struct {char *dptr; int dsize;} datum;
datum fetch();
datum firstkey();
datum nextkey();


static char *
uupath(s)
char *s;
{
	char *fil;
	int ret;
	datum key;
	static datum result;
	char buf[BUFSIZ];
	static int inited = 0;

	fil = archive;
	strcpy(buf,s);
/***    strcat(buf,"!");  ***/
	key.dptr = buf;
	key.dsize = strlen(key.dptr) + 1 ;
	if (!inited++) {
		ret = dbminit(fil);
		if (ret != 0) {
			fprintf(stderr,"Can't open database '%s'\n",fil);
			return(s);
		}
	}
	result = fetch(key);
	if (result.dptr != NULL) {
		if (strcmp("!%s",&result.dptr[result.dsize-4])==0) {
			result.dptr[result.dsize-4] = '\0';
		}
		/* next line handles strange pathalias "feature" */
		if (strcmp(result.dptr,"%s")==0) return(&oursites[0]);
		return(result.dptr);
	} else {
		fprintf(stderr,"%s not found\n",s);
		return(s);
	}
	return(s);
}

opathlog(fmt,a,b,c,d)
char *fmt;
int a,b,c,d;
{
FILE *f;

	f = fopen(logfile,"a");
	if (f==NULL) return;

	fprintf(f,fmt,a,b,c,d);
	fclose(f);
}
SHAR_EOF
if test 7087 -ne "`wc -c opath.c`"
then
echo shar: error transmitting opath.c '(should have been 7087 characters)'
fi
echo shar: extracting address.c '(581 characters)'
cat << \SHAR_EOF > address.c
/*
 * address - run opath to see what a translated RFC822 address will come
 * out as.
 *
 * By E. Roskos 1/16/85
 */

#include <stdio.h>

char *opath();

main(argc,argv)
int argc;
char **argv;
{
char *p;
int uswitch;

	if (argc < 2)
	{
		fprintf(stderr,"usage: %s rfcaddress [...]\n",
			argv[0]);
		exit(1);
	}

	while (--argc)
	{
		p = *++argv;
		if (*p=='-')
		{
			switch(*++p)
			{
			case 'u': uswitch++;
				  continue;
			default:  printf("unknown switch: %c\n",*p);
				  continue;
			}
			continue;
		}
		printf("%s: %s\n",p,uswitch?oupath(p):opath(p));
	}

	exit(0);
}
SHAR_EOF
if test 581 -ne "`wc -c address.c`"
then
echo shar: error transmitting address.c '(should have been 581 characters)'
fi
echo shar: extracting rmail.c '(15480 characters)'
cat << \SHAR_EOF > rmail.c
/*
 * rmail - A uucp rmail remote mail-receiver, with domain nameserver and
 *         class 3 routing.
 *
 *         The original program was written at Rand as part of the Rand 4.1
 *         mail handler.  It is since been substantially revised to add the
 *         domain handling facilities, returning of undeliverable messages,
 *         and a variety of other features, by Eric Roskos of the
 *         Perkin-Elmer Data Systems Group, Systems Software Development,
 *         Southern Development Center.  This program is NOT a Perkin-Elmer
 *         product, and is not supported in any way by Perkin-Elmer.
 *
 *         This is an unsupported, public-domain program.
 *         However, it would be nice of you to leave the authors' names
 *         and organizations in, though you can of course add your own if
 *         you make changes...
 *
 * Note(1) - The code following the comment "Note(1)" must be changed for
 * most users, to invoke your particular delivery program.  For users with
 * a UUCP-only site, you can just replace the execl with something like:
 *      execl("/bin/mail","mail",to,0);
 * to invoke your ordinary mail program.  Note that the code right after
 * the Note(1) sets the standard input to the text of the message to be
 * delivered, so if you exec a program that reads from the standard input
 * at that point, it will read the message to be delivered.  The name of
 * the file containing the message is in the string "tmpfil", if you need
 * it.   This file is deleted after the program you invoke exits.
 */

/* JER 8/6/85 define PEDNS to make experimental PE domain transform */

#define PEDNS

#ifdef COMMENT
	Copyright abandoned, 1983, The Rand Corporation
#endif

/*
 * Version number/name strings
 * Do not change these!
 */

static char *sccsid = "@(#)from rmail.c      4.1.@(#)rmail.c	1.17 (Berkeley) 10/1/80";
static char *version = "4.1.1.17 Class III/DNS";
static char *dnsid  = "Perkin-Elmer SDC Mailer/Domain-Nameserver   Version %s\n%s\n";
static char *errmsg = "/usr/lib/uucp/mail-rtn.msg";

/*
 * includes
 */

#include <whoami.h>
#include <stdio.h>
#include "deliverr.h"

#define MATCH   0
#define PARSE   1
#define NOPARSE 0

char *index();
char *makename();

/* log file for rmail (existence optional) */
char *errlog="/usr/adm/rmail.log";

/* uucp transport mechanism */
char *uux = "/usr/bin/uux";

/* inter-network delivery program */
char *mh_deliver = "/usr/local/lib/mh/deliver";


/* global variables */

FILE *out;              /* output to delivermail */
FILE *froms;            /* file to contain from messages */
char *tmpfil;           /* file name of same */
char tmpfila[124];      /* array for tmpfil */
char tmpfilb[124];      /* temp file for "from" messages */
char *to;               /* argv[1] */
char from[512];         /* accumulated path of sender */
char lbuf[512];         /* one line of the message */
char *fileid;           /* AAnnnn-style message id */

char d1[10], d2[10], d3[10], d4[10], d5[10];   /*** ctime() fields ***/

main(argc, argv)
char **argv;
{
	char ufrom[64];	/* user on remote system */
	char sys[64];	/* a system in path */
	char junk[512];	/* scratchpad */
	char *cp;
	int badhdr;   /***/
	long tim;

	/* JER 1/2/85 write error messages on a log file */

	if (freopen(errlog,"a",stderr)==NULL)
	{
		close(creat(errlog,644));
		if (freopen(errlog,"a",stderr)==NULL)
		{
			printf("Can't open log file '%s'.\n",errlog);
			exit(1);
		}
	}

	/* JER 2/1-2/85 add class III to rmail */

	if (index(argv[1],'!')==NULL) /* if no UUCP path left in address  */
		to = opath(argv[1]);  /* then generate next part of route */
	else
		to = oupath(argv[1]); /* otherwise use the UUCP path syntx*/

	/* JER 7/30/85 add logging of reroutes */
	if (strcmp(to,argv[1])!=0)
		opathlog("Reroute '%s' to '%s'\n",argv[1],to);

	if (argc != 2) {
		logmsg("Usage: rmail user\n");
		fclose(stderr);
		exit(1);
	}
	tmpfil = tmpfila;
	fileid = makename("AA","");
	sprintf (tmpfil, "/usr/spool/rmail/%s", fileid);
	fileid[1] = 'F';
	sprintf(tmpfilb,"/usr/spool/rmail/%s", fileid);
	if ((out=fopen(tmpfil, "w")) == NULL) {
		logmsg("Can't create '%s'\n", tmpfil);
		fclose(stderr);
		exit(1);
	}
	if ((froms=fopen(tmpfilb,"w")) == NULL) {
		logmsg("Can't create '%s'\n",tmpfilb);
		unlink(tmpfil);
		fclose(stderr);
		exit(1);
	}

	/* put on our UUCP "From_" line */

	time(&tim);
	fprintf(out, "From %s  %.24s remote from %s\n", "uucp",
			ctime(&tim), SYSNAME);

	for (;;) {
		fgets(lbuf, sizeof lbuf, stdin);
		if (strncmp(lbuf, "From ", 5) && strncmp(lbuf, ">From ", 6))
			break;
		fputs(lbuf, out); /* Save--in case we are just forwarding */
		fprintf(froms, "X-UUCP-Sent: %s",lbuf+5);
/***/           sscanf(lbuf, "%s %s %s %s %s %s %s remote from %s",
		 junk, ufrom, d1, d2, d3, d4, d5, sys);
		cp = lbuf;
		for (;;) {
			cp = index(cp+1, 'r');
			if (cp == NULL)
				cp = "remote from somewhere";
			if (strncmp(cp, "remote from ", 12) == MATCH)
				break;
		}
		sscanf(cp, "remote from %s", sys);
		strcat(from, sys);
		strcat(from, "!");
	}
	strcat(from, ufrom);

	if (index (to, '!')) {
		/* Just forwarding! */
		putmsg(NOPARSE);
		deliver(to);
		fclose(stderr);
		exit(0);
	}

	truncate();
	/* fprintf(out, "To: %s\n",to); */
	putfrom();

	putmsg(badhdr?NOPARSE:PARSE);
	deliver(to);
	fclose(stderr);
	exit(0);
}


/*
 * Deliver file named in global "tmpfil" to user "to".
 *
 * If some "!"s are left in the "to", use the UUCP transport mechanism.
 * Otherwise, invoke the inter-network delivery program to select the
 * transport mechanism to use for the rest of the way.
 */

deliver(to)
	char *to;
{
	int sts,pid,waitid;
	char *fid;
	char logfil[80];
	long tim;
	char nxtsys[50];
	char path[300];
	char *p,*q;


	fclose(out);

	/* create session-log file */

	fid = makename("AS","");
	sprintf (logfil, "/usr/spool/rmail/%s", fileid);

	/* fork delivery process */

	if ((pid=fork()) == -1) {
		logmsg("Cannot fork Deliver!\n");

		fclose(stderr);
		exit(1);
	}
	if(pid) {  /* wait-for-delivery process */
		while(((waitid = wait(&sts)) != pid) && (waitid != -1));

		/* JER 8/7/85 return if undeliverable */

		if (sts!=0)
		{
			logmsg("Can't deliver to '%s'.\n",to);
			returnmail(deliverr[(sts>>8)&0xff],logfil);
		}

		/* delete the message file in case it was left behind */

		unlink(tmpfil);

		/* delete session-log file: this is only place it's done */

		unlink(logfil);

		/* now exit: this is exit point for the main process */

		fclose(stderr);
		exit(0);
	}

	/* this code is for the process that does the actual delivery */

/***    chmod(tmpfil,0666);   only as a last resort ***/
	chown(tmpfil,getuid(),getgid()); /* JER 1/3/84 */

	if (index(to,'!')==NULL) /* if no UUCP path left in address  */
	{
		/* redirect output to the session log file */

		close(1);
		close(2);
		creat(logfil,0666);
		dup(1);

		time(&tim);
		fprintf(stderr,dnsid,version,ctime(&tim));
		fflush(stderr);

		/* now execute the inter-network mail router */
		/* See Note(1)                               */

		close(0);
		open(tmpfil,0);
		execl(mh_deliver, "deliver", "-deliver", to, tmpfil, 0);
	}
	else    /* some UUCP path is left in address - use UUCP transport */
	{
		/* parse next system from routing string */

		q=nxtsys;
		for (p=to; *p && *p!='!';) *q++ = *p++;
		*q++ = '\0';
		if (*p=='!') p++;

		/* make the path string */

		q = path;
		*q++ = '(';
		while (*p) *q++ = *p++;
		*q++ = ')';
		*q++ = '\0';

		/* make the uux command */

		strcat(nxtsys,"!rmail");
		logmsg("In transit: '%s' via '%s'\n",path,nxtsys);
		fflush(stderr);

		/* redirect output to the session log file */

		close(1);
		close(2);
		creat(logfil,0666);
		dup(1);

		/* create header at top of session log */

		time(&tim);
		fprintf(stderr,dnsid,version,ctime(&tim));
		fflush(stderr);

		/* switch stdin to the tmpfile */

		close(0);
		open(tmpfil,0);

		/* now execute the UUCP transport mechanism */

		execl(uux, "uux", "-", "-r", nxtsys, path, 0);
	}

	perror( "Cannot exec Deliver ");

	fclose(stderr);
	exit(1);

}


/*
 * JER 8/7/85 Highly modified this formerly unused routine to return
 * undeliverable mail.
 * Message is a short message to show in the error header of the returned
 * message.  Seslog is the name of the file containing the "deliver"
 * session log.
 * To return a message, the stdin has to be rewindable.
 */

returnmail(message, seslog)
	char  *message;
	char  *seslog;
{
char rfname[100];   /* name of file where returned message is built */
char *fileid;
int i;
FILE *copyf;        /* used to copy files into the returned message */
char buf[256];      /* buffer for copying files                     */

	logmsg("Returned mail to '%s'.\n",from);
	if(!from)
	{
		logmsg("Can't return: no 'from' address found.\n");
		return;
	}

	/* create a temp file into which we write the returned message text */

	fileid = makename("AR","");
	sprintf (rfname, "/usr/spool/rmail/%s", fileid);
	if ((out=fopen(rfname, "w")) == NULL) {
		logmsg("Can't create return temp file %s\n", tmpfil);
		fclose(stderr);
		exit(1);
	}

	/* write the RFC822 message header onto the front of the message */

	putdate(1);
	fprintf(out, "To: %s\n", from);
	fputs("Subject: Failed Message Delivery\n",out);
	fputs("\n",out);

	/* write the message to the user about his mail failing */

	fputs("The following message is being returned to you.  Reason:\n",out);
	fprintf(out,"%s.\n",message);

	/* copy the session transcript into the letter */

	fprintf(out,"\nTranscript of session:\n\n");

	copyf=fopen(seslog,"r");
	if (copyf==NULL)
	{
		fprintf(out,"Can't open session log '%s'\n",seslog);
	}
	else
	{
		while (fgets(buf, sizeof buf, copyf))
			fputs(buf, out);
	}

	/* write the optional error message text to the returned mail */

	copyf=fopen(errmsg,"r");
	if (copyf!=NULL)
	{
		while (fgets(buf, sizeof buf, copyf))
			fputs(buf, out);
	}

	/* now write the text of the failed message */

	fputs("\n\n\n*--------------RETURNED MESSAGE---------------*\n\n",
	  out);

	/* rewind the standard input to replay the message */

	fflush(stdin);
	if (fseek(stdin,0L,0))
	{
		logmsg("Can't rewind stdin to resend msg.\n");
		fputs(out,
		"Can't rewind my standard input to redisplay the message.\n");
		fclose(stdin);
		freopen("/dev/null","r",stdin);
	}

	/* write the message out */

	lbuf[0] = '\0';
	putall();

	/* now invoke deliver to return it back to the sender */

	tmpfil = rfname;

	deliver(from);

}


#include <sys/types.h>
#include <sys/timeb.h>
#include <time.h>

putdate(hdr)
int hdr;
{
	long  now;
	register char *t, *p;
	char *timezone();
	struct timeb tb;
	struct tm *tmp;
	static char *wday[] = {
		"Sun",
		"Mon",
		"Tues",
		"Wednes",
		"Thurs",
		"Fri",
		"Satur"
	};

	now = time((long *)0);
	t = ctime(&now);
	ftime(&tb);
	tmp = localtime(&now);
	p = timezone(tb.timezone, tmp->tm_isdst);

	fprintf(out, "%s %.2s %.3s %.4s %.2s:%.2s:%.2s %.3s (%.3s)\n",
		     hdr?"Date: ":"",
		     t+8, t+4, t+20, t+11, t+14, t+17, p,wday[tmp->tm_wday]);
}


putfrom()
{
char *sp,*up;
int fromrfc = 0;

	sp = up = 0;
	if (strlen(from)) 
	{
		for (up = &from[strlen(from)-1]; *up!='!' && up > from; --up)
		{
			if (*up=='@') fromrfc++;
		}

		if (up != from)
		for (sp=up-1; *sp!='!' && sp > from; --sp) ;

		if (fromrfc)  /* detected '@' in address */
		{
			while (*up=='!') up++;
			fprintf(out,"From: %s\n",up);
			fprintf(out,"Return-Path: %s\n",from);
		}
		else
		if (*sp)      /* detected uucp-style sitename in address */
		{
		char ste[80], *q;
#ifdef PEDNS
		char *transform();
#endif
			fprintf(out,"From: ");
			while (*up=='!') up++;
			while (*up) putc(*up++,out);
			putc('@',out);
			while (*sp=='!') sp++;
			q = ste;
			while (*sp && *sp!='!') *q++ = *sp++;
			*q++ = '\0';
#ifdef PEDNS
			fprintf(out,"%s",transform(ste));
#else
			fprintf(out,"%s",ste);
#endif
			putc('\n',out);
			fprintf(out,"Return-Path: %s\n",from);
		}
		else
			fprintf(out, "From: %s\n",from);
	}
}


putmsg(parse)
int parse;
{
	int dateseen = 0;

	fprintf(out,"Received: by %s.UUCP (%s);\n",SYSNAME,version); /* JER 1/16/85 */
	fprintf(out,"          ID %s; ",fileid);
	putdate(0);

	/* output accumulated UUCP "from" lines */

	if (parse) /* put RFC-style X-UUCP-SENT lines */
		putfroms();

	/* delete file that contained reformatted From lines */

	fclose(froms);
	unlink(tmpfilb);

	/* output the message itself */

	if(!parse)
		putall();
	else {
		if (uleqn(lbuf, "date:", 5) == 0)
			dateseen++;
		fputs(lbuf, out);
		while (fgets(lbuf, sizeof lbuf, stdin)) {
			if(lbuf[0] == '\n' ) { /* end of hdrs */
				if(!dateseen)
					uudate();
				putall();
			} else {
				if (uleqn(lbuf, "date:", 5) == 0)
					dateseen++;
				fputs(lbuf, out);
			}
		}
	}
}


putall()
{
	fputs(lbuf, out);
	while (fgets(lbuf, sizeof lbuf, stdin))
		fputs(lbuf, out);
}

putfroms()
{
char lbuf[256];

	fflush(froms);
	fseek(froms,0L,0);
	while (fgets(lbuf, sizeof lbuf, froms))
		fputs(lbuf, out);
}

truncate()
{
	/* Truncate those "...remote from..." header lines. */
	/* They're kept only if the message is to be uucp-forwarded */

	fclose (out);   out=fopen(tmpfil, "w");
}


/*
 * Compare strings (at most n bytes) without regard to case.
 *   Returns:   s1>s2: >0,  s1==s2: 0,  s1<s2: <0.
 */

uleqn(s1, s2, n)
register char *s1, *s2;
register n;
{

	while (--n >= 0 && (*s1|040) == (*s2|040)) {
		s2++;
		if (*s1++ == '\0')
			return(0);
	}
	return(n<0 ? 0 : (*s1|040) - (*s2|040));
}


uudate()
{
	char *prefix();

	/*                  day    13   Apr  1981 20  :38   -PST */
	fprintf(out, "Date: %sday, %.2s %.3s %.4s %.2s:%.2s-%.3s\n",
		     prefix(d1), d3, d2, d5, d4, d4+3, "???");
}

char *
prefix(str)
char *str;
{
	static char *wday[] = {
		"Sun",
		"Mon",
		"Tues",
		"Wednes",
		"Thurs",
		"Fri",
		"Satur",
		0
	};

	register char **wp;

	for(wp=wday; *wp; wp++)
		if(uleqn(str, *wp, 3) == 0)
			return(*wp);
	return("???");
}

#ifdef PEDNS
/*
 * JER 8/6/85 Experimental!
 * This transforms a PE site name into a PE-domain name.
 */

static struct xform
{
	char oldsite[15];
	char newsite[15];
} xforms[] =
{
	"petsd","tsd.PE.UUCP",
	"petfa","tfa.PE.UUCP",
	"petfe","tfe.PE.UUCP",
	"pesnta","snta.PE.UUCP",
	"peora","ora.PE.UUCP",
	"pedsgd","dsgd.PE.UUCP",
	"pedsgc","dsgc.PE.UUCP",
	"pedsgb","dsgb.PE.UUCP",
	"pedsga","dsga.PE.UUCP",
	"pecnos","cnos.PE.UUCP",
	"petf1","tf1.PE.UUCP",
	"pesvc","svc.PE.UUCP",
	"pesws","sws.PE.UUCP",
	"jjmws","jjmws.PE.UUCP",
	"jjpws","jjpws.PE.UUCP",
	"jjpdej","jjpdej.PE.UUCP",
	"",""
};

static char *
transform(s)
char *s;
{
struct xform *p;

	for (p=xforms; *(p->oldsite); p++)
	{
		if (strcmp(s,p->oldsite)==0) return(p->newsite);
	}

	return(s);
}
#endif

/* fprintf a message onto the rmail log file */

logmsg(s,a,b,c,d,e,f)
char *s;
unsigned long a,b,c,d,e,f;
{
long tim;
char str[256];

	time(&tim);
	strcpy(str,ctime(&tim));
	str[strlen(str)-1] = '\0';
	strcat(str,": ");
	strcat(str,s);
	fprintf(stderr,str,a,b,c,d,e,f);
}

/* Rand temp file name-making routine */

#ifdef COMMENT
	Copyright abandoned, 1983, The Rand Corporation
#endif

char *makename(prefix,suffix)
char *prefix, *suffix;
{
	static char tmpname[15];
	register char *cp1, *cp2;
	register int pid;

	pid = getpid();
	cp1 = tmpname;
	for (cp2 = prefix; *cp1++ = *cp2++; );
	cp1--;
	do *cp1++ = pid%10 + '0'; while (pid /= 10);
	for (cp2 = suffix; *cp1++ = *cp2++; );
	if (cp1 >= &tmpname[15]) {
		fprintf(stderr, "strs too long to makename");
		done(1);
	}
	return (tmpname);
}

/* exit-and-cleanup routine */

done(status)
int status;
{
	exit(status);
}
SHAR_EOF
if test 15480 -ne "`wc -c rmail.c`"
then
echo shar: error transmitting rmail.c '(should have been 15480 characters)'
fi
echo shar: extracting deliverr.h '(1183 characters)'
cat << \SHAR_EOF > deliverr.h
/*
 * error codes for deliver
 */

char *deliverr[] =
{
	"No Error",
	"Ambiguous switch",
	"Unknown switch",
	"Missing argument",
	"Command was a help request",
	"Only one message at a time",
	"No message specified",
	"Impossible output width",
	"-deliver switch is su only",
	"Can't access tmp file",
	"Can't open mail file",
	"Can't create tmp file",
	"Can't create tmp file",
	"Too many fcc's",
	"Message header format error",
	"Header parser failure",
	"Unknown local user",
	"Getm failure 17 (addr parse error)",
	"Unknown error 18",
	"Unknown error 19",
	"Unknown error 20",
	"Can't create ARPA temp file",
	"ARPA host table error 22",
	"Unknown error 23",
	"Temp file disappeared",
	"Write error on temp file",
	"Read error on temp file",
	"Can't ID message originator",
	"Can't open uux pipe",
	"uux temp file disappeared",
	"uux temp file write error",
	"uucp queue file read error",
	"Getm failed (addr parse error) 32",
	"Can't open alias file",
	"Bad alias file entry",
	"Addfile input file not found",
	"/etc/group not accessible to alias",
	"Group id in alias not in /etc/group",
	"Unknown error 40",
	"Can't invoke local receiver",
	"uux terminated abnormally",
	0
};
SHAR_EOF
if test 1183 -ne "`wc -c deliverr.h`"
then
echo shar: error transmitting deliverr.h '(should have been 1183 characters)'
fi
echo shar: extracting address.1 '(3563 characters)'
cat << \SHAR_EOF > address.1
.TH ADDRESS 1 local
.SH NAME
address - display the path generated by \fBdeliver\fR for an
RFC822-format address.
.SH SYNOPSIS
address rfc-address [ ... ]
.SH DESCRIPTION
This program allows you to check the UUCP mail routing path that will
be generated by the UUCP mailer \fBdeliver\fR if you specify an
RFC822-format address \fBrfc-address\fR in the ``To:'' field of the mail header.
For each RFC-style address on the command line, \fBaddress\fR echoes the
address to the standard output, followed by a colon, followed by
the UUCP address that will be used to send the message to that address.

.SH "ADDRESS FORMAT"
Briefly, the RFC822-format address is of the form
.nf
.sp 1
	<localaddress>@<hostname>.<network>
.sp 1
.fi
where <hostname> is the name of the system you are sending the message
to, <network> is a modifier for <hostname> identifying the network in
which the address is to be interpreted (UUCP, ARPA, MAILNET, CSNET, etc);
and <localaddress> is an address string to be interpreted on the host
machine.

The <localaddress> field may contain further remote addresses to be
interpreted on the host machine.  Typically this will be an address for
mailing via another network; and in particular, the <localaddress> may
(recursively) be identical in format to the RFC address, but with
the symbol `%' replacing the symbol `@' in the standard address format.
Where this form is used, the rightmost % is replaced by an
@ before the host machine sends the message out.

On our system, the presently
valid <network>s are UUCP, ARPA, CSNET, and MAILNET.
The recently proposed UUCP domain names are also accepted, although
they are treated the same as plain ``UUCP''.
Omitting
the <network> causes the network to default to UUCP.  The <hostname>
should be the name of a remote machine to which the message is
directed; see \fI/usr/lib/uucp/uuaddress.alpha\fR for a list of all
known UUCP hostnames.  It is \fInot\fR necessary to specify a UUCP pathname
when using this format; the pathname is automatically determined for you
and substituted into the address before mailing.  The selected pathname
is determined using the \fBpathalias\fR database, and is supposed
to be optimal, taking into consideration information provided by
each site about how often they send mail out, etc.

.SH EXAMPLES
.HP 5
joe
.br
The message is sent to the user ``joe'' on the local system.
.HP 5
joe@ucbvax
.br
The message is sent to joe on the UUCP system named ``ucbvax''; this
address is automatically translated to a proper (and ostensibly
optimal) UUCP path.
.HP 5
joe@ucbvax.UUCP
.br
Same as joe@ucbvax
.HP 5
joe@ucbvax.ARPA
.br
The message is addressed to joe at ucbvax, using the ARPA network.
The message will be routed to the ARPAnet via a UUCP-ARPAnet gateway.
.HP 5
joe%mit-multics.ARPA@ucbvax
.br
The message is sent to ucbvax, who then uses the address
joe@mit-multics.ARPA to send the message on to mit-multics via the
ARPAnet.  Since ucbvax is on the arpanet, this address will work correctly
(as long as there is someone named joe on the MIT multics machine).
.HP 5
joe%vanderbilt.MAILNET%mit-multics.ARPA@ucbvax
.br
The message is sent via UUCP to ucbvax, who then sends the message
to mit-multics via the arpanet; mit-multics then sends the message
to joe@vanderbilt via MAILNET.  Since the above machines each have access
to the networks named in the address, this address will work correctly.
.SH FILES
/usr/lib/uucp/domains - Domain/gateway table
.br
/usr/lib/uucp/archive - Pathalias database
.SH "SEE ALSO"
opath(3)
.SH AUTHOR
Eric Roskos, PE SDC, 1/16/85
SHAR_EOF
if test 3563 -ne "`wc -c address.1`"
then
echo shar: error transmitting address.1 '(should have been 3563 characters)'
fi
echo shar: extracting opath.3 '(4779 characters)'
cat << \SHAR_EOF > opath.3
.TH OPATH 3 "PE SDC"
.SH NAME
opath - Generate a UUCP route from an RFC822 address
.br
oupath - Generate a UUCP route from a (possibly disconnected) UUCP path
.SH SYNOPSIS
char *opath(s)
.br
char *s;
.sp 1
char *oupath(s)
.br
char *s;
.SH DESCRIPTION
These routines use the \fBpathalias\fR database to generate UUCP routing
paths from your local site to specified remote sites on either the UUCP
network or other connected networks.
.PP
\fBopath\fR takes one argument, an RFC822 address, as described in
ADDRESS(1).  From this, it generates and returns a UUCP path to the site
named in the argument.
.PP
\fBoupath\fR takes one argument, a UUCP path.  If the next site on this
path is named \fIx\fR, \fBoupath\fR will prepend a path from your site to
\fIx\fR, if \fIx\fR is nonadjacent to your site.  If \fIx\fR is a domain,
i.e. contains a dot (.), \fBoupath\fR will generate a path to a gateway
for this domain.  Note that \fBoupath\fR will \fInot\fR alter the argument
path, other than to make the above transformations; it does not check whether
sites in the argument are adjacent to one another, or whether they represent
an optimal path; it is assumed that if the user has specified a path, then
he wants to use that path.
.PP
The principal difference between \fBopath\fR and \fBoupath\fR is that the
former gives precedence to ``@'', whereas the latter gives precedence
to ``!''.  The former is intended to be invoked when receiving mail from
a user interface or a non-UUCP source (if the subsequent transport mechanism
is to be UUCP), whereas the latter is intended solely to be used by UUCP
internal software, principally \fBrmail\fR, in routing mail through the
UUCP network.
.SH "FILES"
\fI/usr/lib/uucp/archive\fR - The pathalias database, in DBM(3) format.
See PATHALIAS(1) for information; pathalias is a public-domain program
distributed via the Usenet's net.sources facility.
.br
.sp 1
\fI/usr/lib/uucp/domains\fR - The domain/gateway table.  Each line of this
file consists of either a ``#'' followed by arbitrary comment text, or
an entry of the form:
.br
.in 1i
<domain>,<prefix>,<suffix>,<class>
.br
.in
Where <domain> is the string (in capital letters) identifying a particular
domain; <prefix> is a string to be prepended to the specified address in
order to get to a gateway which can interpret that address; <suffix> is
a string which is to be appended to this address, and <class> indicates
the sort of processing required on the specified address, as follows:
.IP 1
This is a UUCP domain; simply generate a path to the designated host.
This class is used for sites for which you are serving as the final
domain-server; i.e., to which you can generate a complete UUCP path
yourself.
.IP 2
Translate the rightmost ``@'' in the designated address to a ``%'',
prepend <prefix>, and append <suffix>.
Used to forward to an Internet gateway which communicates with
the destination network's gateway.
.IP 3
Translate the rightmost ``@'' in the designated address to a ``.'',
prepend <prefix>, and append <suffix>.
Used to forward to some special-purpose gateways.  Not normally used.
.IP 4
Prepend <prefix> to the designated address, leaving the contents of the
designated address untouched.
This is intended for forwarding to a gateway which could have interpreted
the original address if it had originated at the gateway.
.IP 5
Prepend <prefix> to the designated address; translate the designated
address from a@b to b!a.  This is intended for forwarding messages to
UUCP domain servers.
.PP
Class 2 is normally used for non-ARPA networks which use RFC822 addresses,
e.g., CSnet and Mailnet.  Class 3 is for the Xerox network.  Class 4
is for the ARPAnet or other gateways that do not require a suffix with
``%'' translation.
Class 5 is for forwarding to a UUCP domain server.
.PP
The <prefix> may consist either of a UUCP path, or of a UUCP sitename
preceeded by the symbol ``>''.  In the latter case, the pathalias database
is used to look up a path to the named UUCP site, and this is used as the
prefix.
.PP
When making entries in the domain table, domain names which are a suffix of
another domain name in the table should be ordered such that the longer
string(s) appear first.  For example, .WA.UUCP should preceed .UUCP in
the table.  A linear search is made of the table, and the first domain
found in the table which is a suffix of the domain in the designated address
is used as the domain in generating the routing.
.PP
Following are some example entries for the domain table.  Note that all
domain names begin with a ``.''.
.sp 1
.nf
.in 1i
# This is a comment
\&.HP.UUCP,,,1
\&.UUCP,,,1
\&.CSNET,>decwrl,@CSNET-RELAY.ARPA,2
\&.EDU,>ucbvax,,4
.in
.fi
.sp 1
.SH "SEE ALSO"
PATHALIAS(1), ADDRESS(1)
.SH "AUTHOR"
Eric Roskos, Perkin-Elmer Corp. SDC.
SHAR_EOF
if test 4779 -ne "`wc -c opath.3`"
then
echo shar: error transmitting opath.3 '(should have been 4779 characters)'
fi
echo shar: extracting rmail.1 '(4169 characters)'
cat << \SHAR_EOF > rmail.1
.TH RMAIL 1 PE-SDC
.SH NAME
rmail - receive and forward UUCP mail, with domain support
.SH SYNOPSIS
\fBrmail\fR route
.SH DESCRIPTION
.PP
\fBRmail\fR serves as the decision-making and message-forwarding program
for a UUCP mail site.  Its functions are as follows.
.IP 1.
Receive mail sent in via UUCP.  The message is read from the standard
input.
.IP 2.
Examine the route specified by the \fIroute\fR parameter.  If the next site
named in the route is an adjacent UUCP site, forward the mail there.  If
the next site named is a nonadjacent UUCP site, generate a path to there and
prepend it to the route.  If the next site named is a domain name (i.e.,
a UUCP site name containing a ``.''), generate a path to the domain
nameserver for this domain, or treat this as a domain nameserver request,
if the site running \fBrmail\fR is a nameserver for the specified domain.
If the \fIroute\fR is simply an RFC822-format address, generate a path to
the named site.
.IP 3.
Prepend a standard UUCP mail "From_" line to the message.
.IP 4.
Insert an RFC822-format "Received:" line into the message.
.IP 5.
If the next site in the route generated by step 2 above is a UUCP site,
invoke \fBuux\fR to deliver the message.  If the next site is not a
UUCP site, invoke an inter-network delivery program (presently called
``deliver''), to decide what to do with the message.  If there is no
next site, and all that is left in the route is a user name, also invoke
the inter-network delivery program to deliver the message to the user's
local mailbox.
.IP 6.
If the destination is not another UUCP site, convert all the UUCP ``From_''
lines into a single RFC-822 ``From:'' line and a ``Return-path:'' line.
.IP 7.
If the delivery above fails, return the message to the sender.  An optional
text file is copied into the preamble to the returned message, to give
instructions on how to determine the proper user name, or to give other
information.
.PP
This program uses OPATH(3) to perform the domain nameserver functions, and
thus requires a DBM-format pathalias database.
.PP
The current inter-network delivery mechanism is invocation of the program
\fBdeliver\fR, with the following parameters:
.nf
	\fBdeliver\fR address filename
.fi
The standard input is set to the text of the message to be delivered,
before the program is invoked, in case it reads the standard input to obtain
the message.  A comment in the program's source tells how to modify the
program to use another inter-network delivery mechanism.
.SH FILES
/usr/spool/rmail - mandatory spool directory; contains rmail work files.
.br
/usr/adm/rmail.log - optional log file for error messages
.br
/usr/adm/opath.log - optional log file for monitoring of opath rerouting
.br
/usr/lib/uucp/mail-rtn.msg - optional text file which is copied into the
preamble of returned mail messages.
.SH BUGS
The standard input must be a disk file (or other file on which lseeks are
valid) in order for the message to be returned properly.
.PP
The program should try alternate paths for returning the message (e.g.,
return it to ``postmaster'' or ``root'') if the return path fails.
.PP
The program was not originally intended to be distributed, and thus contains
some hardcoded strings, etc.  It is not a PE product, and is being provided
via pe.cust.sources so that others may experiment with the principles
currently being discussed in net.mail on domain addressing.
.PP
There is optional code, selected by defining PEDNS, which causes PE site names
to be mapped to PE-domain names.  There is no official PE domain nameserver,
however (although peora.UUCP serves this role in the current experiment).
The return-address names are not valid unless the message is routed to peora
for nameservice.
.SH AUTHOR
This program was derived from a short ``rmail'' program written for the
4.1 version of the Rand Mail Handler.  The author of this program,
which according to the original comments was intended solely for the
``Ernie Covax'' system, is not known.  The Rand program was highly revised
by Eric Roskos of Perkin-Elmer's Southern Development Center as an
experiment in handling of domain-based message addressing in January of 1985.
SHAR_EOF
if test 4169 -ne "`wc -c rmail.1`"
then
echo shar: error transmitting rmail.1 '(should have been 4169 characters)'
fi
echo shar: extracting domains '(847 characters)'
cat << \SHAR_EOF > domains
#
# Perkin-Elmer SDC Domain Table
#
# Format: <domain>,<prefix>,<suffix>,<class>
#     where class is:
#     1 - UUCP path
#     2 - prepend prefix, append suffix
#     3 - convert rightmost @ to a .
#     4 - convert rightmost @ to a %
#
#
.WA.UUCP,,,1
.OR.UUCP,,,1
.N-CA.UUCP,,,1
.S-CA.UUCP,,,1
.MTN.UUCP,,,1
.S-CEN.UUCP,,,1
.MID-W.UUCP,,,1
.S-EAST.UUCP,,,1
.ATL.UUCP,,,1
.N-ENG.UUCP,,,1
.HI.UUCP,,,1
.W-CAN.UUCP,,,1
.E-CAN.UUCP,,,1
.EUR.UUCP,,,1
.UK.UUCP,,,1
.AUS.UUCP,,,1
.ISRAEL.UUCP,,,1
.ATT.UUCP,>ihnp4,,5
.HP.UUCP,,,1
.PE.UUCP,,,1
.UUCP,,,1
.CSNET,>ucbvax,@CSNET-RELAY.ARPA,2
.MAILNET,>ucbvax,@MIT-MULTICS.ARPA,2
# .BITNET,>ucbvax,@WISCVM.ARPA,2
.XEROX,>ucbvax,@XEROX.ARPA,3
.DEC,>decwrl,,4
.ARPA,>ucbvax,,4
.EDU,>ucbvax,,4
.COM,>ucbvax,,4
.GOV,>ucbvax,,4
.MIL,>ucbvax,,4
.OTH,>ucbvax,,4
.BITNET,>psuvax,,4
#
# our local domains
#
.PE,,,1
SHAR_EOF
if test 847 -ne "`wc -c domains`"
then
echo shar: error transmitting domains '(should have been 847 characters)'
fi
#	End of shell archive
exit 0
-- 
Shyy-Anzr:  J. Eric Roskos
UUCP:       ..!{decvax,ucbvax,ihnp4}!vax135!petsd!peora!jer
US Mail:    MS 795; Perkin-Elmer SDC;
	    2486 Sand Lake Road, Orlando, FL 32809-7642

	"Gurl ubyq gur fxl/Ba gur bgure fvqr/Bs obeqreyvarf..."