[comp.sources.unix] v11i071: Smail, UUCP domain maielr, Part03/03

rsalz@uunet.UU.NET (Rich Salz) (09/23/87)

Submitted-by: Larry Auton <clyde.ATT.COM!lda>
Posting-number: Volume 11, Issue 71
Archive-name: smail3/Part03

# This is a shell archive.  Remove anything before this line, then
# unpack it by saving it in a file and typing "sh file".  (Files
# unpacked will be owned by you and have default permissions.)
#
# This archive contains:
# lcasep.c main.c make.cf.sh map.c misc.c mkfnames.sh nptx.c patchlevel
# pathproc.sh pw.c resolve.c smail.prompt str.c svbinmail.c sysexits.h
# template.cf

echo x - lcasep.c
cat > "lcasep.c" << '//E*O*F lcasep.c//'
/*
** convert the host name on a pathalias line to lower case
*/

#ifndef lint
static char 	*sccsid="@(#)lcasep.c	2.5 (smail) 9/15/87";
#endif

#include <stdio.h>
#include <ctype.h>

# define lower(c) 		( isupper(c) ? c-'A'+'a' : c )

void exit(), perror();

main(argc, argv)
int argc;
char *argv[];
{
	FILE *ifp, *ofp;
	char buf[BUFSIZ];
	register char *p;
	int c;

	extern int optind;
	extern char *optarg;

	ifp = stdin;
	ofp = stdout;

	while((c = getopt(argc, argv, "f:o:")) != EOF) {
		switch(c) {
		case 'f':
			if((ifp = fopen(optarg, "r")) == NULL) {
				(void) fprintf(stderr, "%s: can't open %s: ",
					argv[0], optarg);
				perror("");
				exit(1);
			}
			break;
		case 'o':
			if((ofp = fopen(optarg, "w")) == NULL) {
				(void) fprintf(stderr, "%s: can't open %s: ",
					argv[0], optarg);
				perror("");
				exit(1);
			}
			break;
		default:
			(void) fprintf(stderr,
				"usage: %s [-f file] [-o outfile]\n", argv[0]);
			exit(1);
			/* NOTREACHED */
			break;
		}
	}

	while(fgets(buf, sizeof(buf), ifp) != NULL) {
		for(p = buf; *p != '\t' && *p != '\0' ; p++) {
			(void) fputc(lower(*p), ofp);
		}
		(void) fputs(p, ofp);
	}
	return(0);
}
//E*O*F lcasep.c//

echo x - main.c
cat > "main.c" << '//E*O*F main.c//'
/*
**
**  rmail/smail - UUCP mailer with automatic routing.
**
**  Christopher Seiwald		/+\
**  chris@cbosgd.att.com	+\
**  January, 1985		\+/
**
*/

#ifndef lint
static char 	*sccsid="@(#)main.c	2.5 (smail) 9/15/87";
#endif

/*
**
**  usage:  	rmail [options] address...
**		smail [options] address...
**  options:
**		-d 		debug - verbose and don't invoke mailers.
**		-v		verbose - just verbose.
**		-A		print mapped addresses.  don't invoke mailers.
**		-h hostname	set hostname 
**		-H hostdomain	set hostdomain (default hostname.MYDOM)
**		-p pathfile	path database filename
**		-r		force routing of host!address
**		-R		reroute even explicit path!user
**		-l		user@domain goes to local mailer
**		-L		all mail goes local
**		-q number	mail queueing cost threshold
**		-m number	limit on number of uux_noqueue jobs
**		-u string	string of flags for uux
**              -F address      name to substitute in From: line
**		-a aliasfile	aliases filename (not used with SENDMAIL)
**		-n namelist	list of full names for simple aliases
*/

#include	<stdio.h>
#include	<ctype.h>
#include	"defs.h"

int exitstat = 0;		/* exit status, set by resolve, deliver	*/

enum edebug debug     = NO;	/* set by -d or -v option		*/
enum ehandle handle   = HANDLE;	/* which mail we can handle, see defs.h	*/
enum erouting routing = ROUTING;/* to route or not to route, see defs.h */

char hostname[SMLBUF]   = "";	/* set by -h, defaults in defs.h 	*/
char hostdomain[SMLBUF] = "";	/* set by -H, defaults in defs.h 	*/
char hostuucp[SMLBUF] = "";	/* built with hostname+".UUCP"	 	*/

char *pathfile  = PATHS;	/* or set by -p 			*/
char *uuxargs   = NULL;		/* or set by -u				*/

char *aliasfile =
#ifdef ALIAS
		ALIAS;		/* or set by -a				*/
#else
		NULL;
#endif

char *fnlist    =
#ifdef FULLNAME
		FULLNAME;	/* or set by -n				*/
#else
		NULL;
#endif

int  queuecost  = QUEUECOST;	/* or set by -q				*/
char *from_addr = NULL;		/* or set by -F				*/
int  maxnoqueue = MAXNOQUEUE;	/* or set by -m                         */

int  getcost    = 
#ifdef GETCOST
		1;	/* get cost of path even if not routing */
#else
		0;
#endif

char *spoolfile = NULL;		/* name of the file containing letter   */
FILE *spoolfp;			/* file pointer to spoolfile		*/
int  spoolmaster = 0;		/* indicates 'control' of spoolfile     */

void spool();


/*
**
**  rmail/smail: mail stdin letter to argv addresses.
**
**  After processing command line options and finding our host and domain 
**  names, we map addresses into <host,user,form,cost> sets.  Then we deliver.
**
*/

main(argc, argv)
int argc;
char *argv[];
{
	char *hostv[MAXARGS];		/* UUCP neighbor 		*/
	char *userv[MAXARGS];		/* address given to host 	*/
	int  costv[MAXARGS];		/* cost of resolved route	*/
	enum eform formv[MAXARGS];	/* invalid, local, or uucp 	*/
	char *p;
	int c;
	int  printaddr  = 0;		/* or set by -A			*/
	int nargc;
	char **nargv, **alias();

	char *optstr = "cdvArRlLH:h:p:u:q:a:n:m:f:F:";
	extern char *optarg;
	extern int optind;

/*
**  see if we aren't invoked as rmail
*/
	if((p = rindex(argv[0], '/')) == NULL) {
		p = argv[0];
	} else {
		p++;
	}

	if(*p != 'r' ) {
		handle = ALL;
	}

/*
**  Process command line arguments
*/
	while ((c = getopt(argc, argv, optstr)) != EOF) {
		switch ( c ) {
		case 'd': debug      = YES; 		break;
		case 'v': debug      = VERBOSE; 	break; 
		case 'A': printaddr  = 1; 		break; 
		case 'F': from_addr  = optarg;		break;
		case 'r': routing    = ALWAYS;		break;
		case 'R': routing    = REROUTE;		break;
		case 'l': handle     = JUSTUUCP;	break;
		case 'L': handle     = NONE;		break;
		case 'f': spoolfile  = optarg;		break;
		case 'p': pathfile   = optarg; 		break;
		case 'u': uuxargs    = optarg; 		break;
		case 'a': aliasfile  = optarg; 		break;
		case 'n': fnlist     = optarg; 		break;
		case 'H': (void) strcpy(hostdomain, optarg);	break;
		case 'h': (void) strcpy(hostname, optarg); 	break;
		case 'm': if(isdigit(*optarg)) {
				  maxnoqueue = atoi(optarg);
			  }
			  break;
		case 'c': getcost     = 1;		break;
		case 'q': if(isdigit(*optarg)) {
				  queuecost = atoi(optarg);
			  }
			  break;
		default:
			error( EX_USAGE, "valid flags are %s\n", optstr);
		}
	}
	if ( argc <= optind ) {
		error( EX_USAGE, "usage: %s [flags] address...\n", argv[0] );
	}

/*
**  Get our default hostname and hostdomain.
*/
	getmynames();

/*
**  Spool the letter in a temporary file.
*/
	nargc = argc - optind;
	if(printaddr == 0) {
		spool(nargc, &argv[optind]);
	}

/*
** Do aliasing and fullname resolution
*/
	nargv = alias(&nargc, &argv[optind]);

/*
**  Map argv addresses to <host, user, form, cost>.
*/
	map(nargc, nargv, hostv, userv, formv, costv);
/*
**  If all we want it mapped addresses, print them and exit.
*/
	if(printaddr) {
		int i;
		char abuf[SMLBUF];
		for(i=nargc-1; i >= 0; i--) {
			if(formv[i] == ERROR) {
				(void) strcpy(abuf, nargv[i]);
			} else {
				build(hostv[i], userv[i], formv[i], abuf);
			}
			(void) fputs(abuf, stdout);
			if(i != 0) (void) putchar(' ');
		}
		(void) putchar('\n');
		exit(0);
	}
/*
**  Deliver.
*/
	deliver(nargc, hostv, userv, formv, costv);
/*
**  Exitstat was set if any resolve or deliver failed, otherwise 0.
*/
	return( exitstat );
}
//E*O*F main.c//

echo x - make.cf.sh
cat > "make.cf.sh" << '//E*O*F make.cf.sh//'
#! /bin/sh
#
# @(#)make.cf.sh	2.5 (smail) 9/15/87
#
cat <<!EOM!
This script will prompt you for the automatically configurable parameters
in the stock version of the sendmail configuration file.  Naturally, any
local extensions will have to be added manually.

Clyde is a VAX running AT&T System V Release 2.0, with a port of sendmail.
Clyde is a gateway for the domain .att.com.

Below is a trace of the session that
configured the sendmail.cf on clyde.ATT.COM:
===

!EOM!

echo "press return to continue"; read foo

cat <<!EOM!
Enter Date (MM-DD-YY):
06-24-86
Enter This Host's Name:
clyde
Enter This Host's Official Domain:
ATT.COM
Enter Any Equivalent Domain Classes:
ATT
Enter Any Domains For Which This Host Is An Authority:
ATT.UUCP
Does This Host Have SMTP Connections (y/n)?
no
Enter Full Path to Executable That Will Provide Local Mail Delivery:
/bin/lmail
Is /bin/lmail A Berkeley Mailer [i.e., use -r to specify sender] (y/n)?
no
Will This Host Act As A Gateway Between Domains (y/n)?
yes
Are subdomains beneath this hosts' domain to be hidden (y/n)?
yes
===
!EOM!
# get date of configuration
CF_DATE=`/bin/sh ./smail.prompt string "Enter Date (MM-DD-YY):"`

# get host name
CF_HOST=`/bin/sh ./smail.prompt string "Enter This Host's Name:"`

# get host domain
CF_DOMAIN=`/bin/sh ./smail.prompt string "Enter This Host's Official Domain:"`

# get domain classes
CF_DCLASS=`/bin/sh ./smail.prompt string "Enter Any Equivalent Domain Classes:"`

# get domain authority
CF_AUTHORITY=`/bin/sh ./smail.prompt string "Enter Any Domains For Which This Host Is An Authority:"`

CF_SMTP=`/bin/sh ./smail.prompt yesno "Does This Host Have SMTP Connections (y/n)?"`
if test "$CF_SMTP" = "yes"
then

#get list of local SMTP connections
	CF_SMTP=`/bin/sh ./smail.prompt file "Enter Full Path to File that Contains List of SMTP Connections:"`

	CF_SMTP="FE$CF_SMTP %s"
else
	CF_SMTP=""
fi

# get path to local delivery agent
CF_LOCALMAIL=`/bin/sh ./smail.prompt file "Enter Full Path to Executable That Will Provide Local Mail Delivery:"`

CF_SYSTEM=`/bin/sh ./smail.prompt yesno "Is $CF_LOCALMAIL A Berkeley Mailer [i.e., use -r to specify sender] (y/n)?"`
if test "$CF_SYSTEM" = "yes"
then
	CF_SVMAIL="#"
	CF_BSMAIL=""
else
	CF_SVMAIL=""
	CF_BSMAIL="#"
fi

CF_GATEWAY=`/bin/sh ./smail.prompt yesno "Will This Host Act As A Gateway Between Domains(y/n)?"`
if test "$CF_GATEWAY" = "yes"
then
	CF_GATEWAY=""
else
	CF_GATEWAY="#"
fi

CF_HIDDENHOSTS=`/bin/sh ./smail.prompt yesno "Are subdomains beneath this hosts' domain to be hidden (y/n)?"`
if test "$CF_HIDDENHOSTS" = "yes"
then
	CF_HIDDENHOSTS=""
else
	CF_HIDDENHOSTS="#"
fi

sed 	\
	-e "s/CF_HOST/Dw$CF_HOST/" \
	-e "s/CF_DOMAIN/DD$CF_DOMAIN/" \
	-e "s/CF_AUTHORITY/DA$CF_AUTHORITY/" \
	-e "s/CF_DCLASS/CDUUCP $CF_DCLASS/" \
	-e "s;CF_SMTP;$CF_SMTP;" \
	-e "s;CF_DATE;$CF_DATE;" \
	-e "s;CF_LOCALMAIL;$CF_LOCALMAIL;" \
	-e "s;CF_BSMAIL;$CF_BSMAIL;" \
	-e "s;CF_SVMAIL;$CF_SVMAIL;" \
	-e "s;CF_GATEWAY;$CF_GATEWAY;" \
	-e "s;CF_HIDDENHOSTS;$CF_HIDDENHOSTS;" \
	template.cf > sendmail.cf
//E*O*F make.cf.sh//

echo x - map.c
cat > "map.c" << '//E*O*F map.c//'
#ifndef lint
static char 	*sccsid="@(#)map.c	2.5 (smail) 9/15/87";
#endif

# include	<stdio.h>
# include	<sys/types.h>
# include	"defs.h"

extern int queuecost;

/*
**
**  map(): map addresses into <host, user, form, cost> sets.
**
**  Calls resolve() for each address of argv.  The result is hostv and 
**  userv arrays (pointing into buffers userz and hostz), and formv array.
**
*/

map(argc, argv, hostv, userv, formv, costv)
int argc;				/* address count 		*/
char **argv;				/* address vector 		*/
char *hostv[];				/* remote host vector 		*/
char *userv[];				/* user name vector 		*/
enum eform formv[];			/* address format vector 	*/
int costv[];				/* cost vector 			*/
{
	int i, cost;
	enum eform resolve();
	char *c;
	static char userbuf[BIGBUF], *userz;
	static char hostbuf[BIGBUF], *hostz;

	userz = userbuf;
	hostz = hostbuf;

	for( i=0; i<argc; i++ ) {
#ifdef DEFQUEUE
		cost = queuecost+1;		/* default is queueing */
#else
		cost = queuecost-1;		/* default is no queueing */
#endif
		userv[i] = userz;		/* put results here */
		hostv[i] = hostz;
		if ( **argv == '(' ) {		/* strip () */
			++*argv;
			c = index( *argv, ')' );
			if (c)
				*c = '\0';
		}
						/* here it comes! */
		formv[i] = resolve(*argv++, hostz, userz, &cost);
		costv[i] = cost;
		userz += strlen( userz ) + 1;	/* skip past \0 */
		hostz += strlen( hostz ) + 1;
	}
}
//E*O*F map.c//

echo x - misc.c
cat > "misc.c" << '//E*O*F misc.c//'

/*
**  Miscellaneous support functions for smail/rmail
*/

#ifndef lint
static char 	*sccsid="@(#)misc.c	2.5 (smail) 9/15/87";
#endif

# include	<stdio.h>
# include	<sys/types.h>
# include	<ctype.h>
# include	"defs.h"
#ifdef BSD
# include	<sys/time.h>
# include	<sys/timeb.h>
#else
# include	<time.h>
# include	<sys/utsname.h>
#endif

extern int  exitstat;		/* set if a forked mailer fails */
extern enum edebug debug;	/* how verbose we are 		*/ 
extern enum ehandle handle;	/* what we handle		*/
extern char *uuxargs;		/* arguments given to uux       */
extern int  queuecost;		/* threshold for queueing mail  */
extern int  maxnoqueue;		/* max number of uucico's       */
extern enum erouting routing;	/* when to route addresses	*/
extern char hostdomain[];	/* */
extern char hostname[];		/* */
extern char hostuucp[];		/* */
extern char *pathfile;		/* location of path database	*/
extern char *spoolfile;		/* file name of spooled message */
extern FILE *spoolfp;		/* file ptr  to spooled message */
extern int spoolmaster;		/* set if creator of spoolfile  */

extern struct tm *localtime();

struct tm *gmt, *loc;		/* GMT and local time structure	*/
time_t now;			/* current system time		*/
char nows[50];			/* time in ctime format		*/
char arpanows[50];		/* time in arpa format		*/

# ifdef LOG
void
log(command, from, size)
char *command, *from;
long size;
{
	FILE *fd;
	char *logtime, tbuf[50];
	int cmask;

	logtime = strcpy(tbuf, nows);
	logtime[16] = '\0';
	logtime += 4;

	cmask = umask(0);
	fd = fopen(LOG, "a");
	(void) umask(cmask);

	if (fd != NULL) {
		(void) fprintf(fd, "%s\t%ld\t%s\t%s\n",
			logtime, size, from, command);
		(void) fclose(fd);
	}
}
# endif

# ifdef RECORD
FILE *
record(command, from, size)
char *command, *from;
long size;
{
	FILE *fd;
	char *logtime, buf[SMLBUF];
	int cmask;

	logtime = strcpy(buf, nows);
	logtime[16] = 0;
	logtime += 4;

	cmask = umask(0);
	fd = fopen(RECORD, "a");
	(void) umask(cmask);

	if (fd != NULL) {
		(void) fprintf(fd, "%s: %s, from %s, %ld bytes\n", 
			logtime, command, from, size);
	}
	while(fgets(buf, sizeof(buf), spoolfp) != NULL) {
		(void) fputs(buf, fd);
	}
	(void) fclose(fd);
}
# endif


setdates()
{
	time_t time();
	struct tm *gmtime();
	char *ctime(), *arpadate();

	(void) time(&now);
	(void) strcpy(nows, ctime(&now));
	gmt = gmtime(&now);
	loc = localtime(&now);
	(void) strcpy(arpanows, arpadate(nows));
}

/*
**  Note: This routine was taken from sendmail
**
**  ARPADATE -- Create date in ARPANET format
**
**	Parameters:
**		ud -- unix style date string.  if NULL, one is created.
**
**	Returns:
**		pointer to an ARPANET date field
**
**	Side Effects:
**		none
**
**	WARNING:
**		date is stored in a local buffer -- subsequent
**		calls will overwrite.
**
**	Bugs:
**		Timezone is computed from local time, rather than
**		from whereever (and whenever) the message was sent.
**		To do better is very hard.
**
**		Some sites are now inserting the timezone into the
**		local date.  This routine should figure out what
**		the format is and work appropriately.
*/

char *
arpadate(ud)
	register char *ud;
{
	register char *p;
	register char *q;
	static char b[40];
	extern char *ctime();
	register int i;
#ifndef BSD
	extern char *tzname[];
	time_t t, time();
#else
	/* V7 and 4BSD */
	struct timeb t;
	extern struct timeb *ftime();
	extern char *timezone();
#endif

	/*
	**  Get current time.
	**	This will be used if a null argument is passed and
	**	to resolve the timezone.
	*/

#ifndef BSD
	(void) time(&t);
	if (ud == NULL)
		ud = ctime(&t);
#else
	/* V7 or 4BSD */
	ftime(&t);
	if (ud == NULL)
		ud = ctime(&t.time);
#endif

	/*
	**  Crack the UNIX date line in a singularly unoriginal way.
	*/

	q = b;

	p = &ud[8];		/* 16 */
	if (*p == ' ')
		p++;
	else
		*q++ = *p++;
	*q++ = *p++;
	*q++ = ' ';

	p = &ud[4];		/* Sep */
	*q++ = *p++;
	*q++ = *p++;
	*q++ = *p++;
	*q++ = ' ';

	p = &ud[22];		/* 1979 */
	*q++ = *p++;
	*q++ = *p++;
	*q++ = ' ';

	p = &ud[11];		/* 01:03:52 */
	for (i = 8; i > 0; i--)
		*q++ = *p++;

				/* -PST or -PDT */
#ifndef BSD
	p = tzname[localtime(&t)->tm_isdst];
#else
	p = timezone(t.timezone, localtime(&t.time)->tm_isdst);
#endif
	if (p[3] != '\0')
	{
		/* hours from GMT */
		p += 3;
		*q++ = *p++;
		if (p[1] == ':')
			*q++ = '0';
		else
			*q++ = *p++;
		*q++ = *p++;
		p++;		/* skip ``:'' */
		*q++ = *p++;
		*q++ = *p++;
	}
	else
	{
		*q++ = ' ';
		*q++ = *p++;
		*q++ = *p++;
		*q++ = *p++;
	}

	p = &ud[0];		/* Mon */
	*q++ = ' ';
	*q++ = '(';
	*q++ = *p++;
	*q++ = *p++;
	*q++ = *p++;
	*q++ = ')';

	*q = '\0';
	return (b);
}

/*
 *	The user name "postmaster" must be accepted regardless of what
 *	combination of upper and lower case is used.  This function is
 *	used to convert all case variants of "postmaster" to all lower
 *	case.  If the user name passed in is not "postmaster", it is
 *	returned unchanged.
 */
char *
postmaster(user)
char *user;
{
	static char *pm = "postmaster";

	if(strcmpic(user, pm) == 0) {
		return(pm);
	} else {
		return(user);
	}
}

/*
 * Return 1 iff the string is "UUCP" (ignore case).
 */
isuucp(str)
char *str;
{
	if(strcmpic(str, "UUCP") == 0) {
		return(1);
	} else {
		return(0);
	}
}

/*
** sform(form) returns a pointer to a string that tells what 'form' means
*/

char *
sform(form)
enum eform form;
{
	if(form == ERROR)  return("ERROR");
	if(form == LOCAL)  return("LOCAL");
	if(form == DOMAIN) return("DOMAIN");
	if(form == UUCP)   return("UUCP");
	if(form == ROUTE)  return("ROUTE");
	return("UNKNOWN");
}

/*
**
**  getmynames(): what is my host name and host domain?
**
**  Hostname set by -h, failing that by #define HOSTNAME, failing
**  that by gethostname() or uname().
**  
**  Hostdomain set by -h, failing that by #define HOSTDOMAIN,
**  failing that as hostname.MYDOM, or as just hostname.
**
**  See defs.h for the inside story.
**
*/

getmynames()
{
#ifdef HOSTNAME
	if (!*hostname)
		(void) strcpy(hostname, HOSTNAME);
#endif
#ifdef GETHOSTNAME
	if (!*hostname)
		gethostname(hostname, SMLBUF - 1);
#endif
#ifdef UNAME
	if (!*hostname) {
		struct utsname site;

		if (uname(&site) < 0)
			error(EX_SOFTWARE, "uname() call failed", 0);
		(void) strcpy(hostname, site.nodename);
	}
#endif
	if (!*hostname)
		error(EX_SOFTWARE, "can't determine hostname.\n", 0);
#ifdef HOSTDOMAIN
	if (!*hostdomain)
		(void) strcpy(hostdomain, HOSTDOMAIN);
#endif
#ifdef MYDOM
	if (!*hostdomain)
		(void) strcat(strcpy(hostdomain, hostname), MYDOM);
#endif
	if (!*hostdomain)
		(void) strcpy(hostdomain, hostname);

	(void) strcat(strcpy(hostuucp, hostname), ".UUCP");
}
//E*O*F misc.c//

echo x - mkfnames.sh
cat > "mkfnames.sh" << '//E*O*F mkfnames.sh//'
#! /bin/sh
#
# @(#)mkfnames.sh	2.5 (smail) 9/15/87
#
if test $# = 0
then
	sed 's/\(.*\):.*:.*:.*:\(.*\):.*:.*/\1	\2/' /etc/passwd
else
	cat $*
fi	|	# at this point, we have a list of login\tFull Name pairs
nptx	|
lcasep	|
sort -u +0 -1
//E*O*F mkfnames.sh//

echo x - nptx.c
cat > "nptx.c" << '//E*O*F nptx.c//'
#ifndef lint
static char *sccsid = "@(#)nptx.c	2.5 (smail) 9/15/87";
#endif

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <pwd.h>
#include "defs.h"
#include <ctype.h>

char *malloc(), *index(), *fullname();
void nptx(), free(), dotspace();

enum edebug debug;	/* not used by nptx */
char *fnlist = NULL;	/* not used by nptx */

main()
{
	int i;
	char buf[SMLBUF], *p, *name, *last, *nick, *ctmp;

	while(gets(buf) != NULL) {
		/*  line should be in form
		**
		**  login	First Last
		** or
		**  login	First Last(Nickname)
		**
		*/
		if((p = index(buf, '\t')) == NULL) {
			(void) fprintf(stderr, "format error: %s\n", buf);
			continue;
		}

		*p++ = '\0';
		name = fullname(p);
		dotspace(name);

		if (last = rindex(name, '.')) {
			last++;
		} else {
			last = NULL;
		}

		if ((nick = index(p, '(')) != NULL) {
			nick++;
			if ((ctmp = index(nick, ')')) == NULL) {
				nick = NULL;
			} else {
				*ctmp = '\0';
			}
		}

		nptx(buf, name);

		if((last != NULL) && (nick != NULL)) {
			i=strlen(nick) + strlen(last) + 2;
			if((name = malloc(i)) != NULL) {
				(void) strcpy(name, nick);
				(void) strcat(name, ".");
				(void) strcat(name, last);
				dotspace(name);
				nptx(buf, name);
				free(name);
			}
		}
	}
	return(0);
}

void
dotspace(s)
char *s;
{
	register char *p, *t;

	/* turn whitespace to '.' */
	for(p = s; *p != '\0'; p++) {
		if((*p == ' ') || (*p == '\t')) {
			*p = '.';
		}
	}

	/* elide leading '.'s */
	for(p = s; *p == '.' ; p++)
		;

	/* elide mulitple '.'s and all "'"s */
	for(t = s; *p != '\0'; p++, t++) {
		*t = *p;

		if(*t == '\'') {
			t--;
			continue;
		}

		if(*p == '.') {
			while(*(++p) == '.')
				;
			p--;
		}
	}
	*t = '\0';

	/* elide trailing '.' */
	if((t > s) && (*(--t) == '.')) *t = '\0';
}

void
nptx(login, name)
char *login, *name;
{
	int i,j,k,N,lim,mask;
	int ii,ji,ki,Ni,limi,maski;
	char nl[11][100], il[11][100];
	char *pi, *p, *rindex();
	char buf[100];
	char bufi[100];

	if((name == NULL) || (*name == '\0')) {
		return;
	}

	for(i=0; i < 10; i++) {
		if((p = rindex(name, '.')) == NULL) break;
		(void) strcpy(nl[i], p+1);
		*p = NULL;
	}
	(void) strcpy(nl[i], name);

	while((strcmpic(nl[i], "Mr"  ) == 0)
	 ||   (strcmpic(nl[i], "Dr"  ) == 0)
	 ||   (strcmpic(nl[i], "Mrs" ) == 0)
	 ||   (strcmpic(nl[i], "Miss") == 0)
	 ||   (strcmpic(nl[i], "Ms"  ) == 0)) {
		i--;
	}

	while((strcmpic(nl[0], "Jr") == 0)
	 ||   (strcmpic(nl[0], "Sr") == 0)) {
		for(j=0; j < i; j++) {
			(void) strcpy(nl[j], nl[j+1]);
		}
		i--;
	}

	N = i;
	lim = 1 << (N+1);
	for(mask = 1 << N ; mask < lim ; mask++) {
		buf[0] = '\0';
		for(j = 1, k = N; j < lim; j <<=1, k--) {
			if(j & mask) {
				(void) strcat(buf, nl[k]);
				(void) strcat(buf, ".");
			}
		}
		if((p = rindex(buf, '.')) != NULL) {
			*p = '\0';
		}

		for(ii=0; ii < 10; ii++) {
			if((pi = rindex(buf, '.')) == NULL) break;
			(void) strcpy(il[ii], pi+1);
			*pi = NULL;
		}
		(void) strcpy(il[ii], buf);
		Ni = ii;
		limi = 1 << (Ni+1);
		for(maski = 1 << Ni /* 0 */ ; maski < limi ; maski++) {
			bufi[0] = '\0';
			for(ji = 1, ki = Ni; ji < limi; ji <<=1, ki--) {
				if(ji & maski) {
					(void) strcat(bufi, il[ki]);
				} else {
					char init[3];
					init[0] = il[ki][0];
					init[1] = '\0';
					(void) strcat(bufi, init);
				}
				(void) strcat(bufi, ".");
			}
			if((pi = rindex(bufi, '.')) != NULL) {
				*pi = '\0';
			}
#ifdef DOT_REQD
			if(index(bufi, '.') == NULL) {
				continue;
			}
#endif /* DOT_REQD */
			(void) printf("%s\t%s\n",bufi, login); /* */
		}
	}
}
//E*O*F nptx.c//

echo x - patchlevel
cat > "patchlevel" << '//E*O*F patchlevel//'
Patch #: 00
//E*O*F patchlevel//

echo x - pathproc.sh
cat > "pathproc.sh" << '//E*O*F pathproc.sh//'
#
#	@(#)pathproc.sh	2.5 (smail) 9/15/87
#
# This script will do all that's necessary for
# transforming the output of pathalias -f into
# the format of a 'paths' file for smail.
#
# format of the pathalias -f output is
# cost	host	route
#
# format of a 'paths' file for smail is
# host	route	first_hop_cost
#
# move cost field to end of line
#
sed 's/\(.*\)	\(.*\)	\(.*\)/\2	\3	\1/'|
#
# convert target domain/host to lower case
#
lcasep |
#
# sort the stream
#
sort
//E*O*F pathproc.sh//

echo x - pw.c
cat > "pw.c" << '//E*O*F pw.c//'
#ifndef lint
static char *sccsid = "@(#)pw.c	2.5 (smail) 9/15/87";
#endif

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <pwd.h>
#include "defs.h"
#include <ctype.h>

char *malloc();
void free();

typedef struct pw_node pwlist;

struct pw_node {
	char *lname;			/* login name */
	char *fname;			/* full name  */
	int  uid;			/* user-id    */
	char *home;			/* login name */
	pwlist *vlink;			/* link to next item */
};

pwlist *pwhead;		/* head of linked list */
pwlist *pwparse();	/* head of linked list */

#define PNULL	((pwlist *) 0)

char *
pwfnam(user)
char *user;
{
	pwlist *f;

	/*
	** check for previously cached user
	*/

	for(f=pwhead; f != NULL; f=f->vlink) {
		if(strcmp(user, f->lname) == 0) {
			return(f->fname);
		}
	}
	/*
	** not found parse the password file
	*/

	while((f=pwparse()) != PNULL) {
		if(strcmp(user, f->lname) == 0) {
			return(f->fname);
		}
	}
	return(NULL);
}

char *
pwuid(uid)
int uid;
{
	pwlist *f;

	/*
	** check for previously cached user
	*/

	for(f=pwhead; f != NULL; f=f->vlink) {
		if(uid == f->uid) {
			return(f->lname);
		}
	}
	/*
	** not found parse the password file
	*/

	while((f=pwparse()) != PNULL) {
		if(uid == f->uid) {
			return(f->lname);
		}
	}
	return(NULL);
}

#ifndef SENDMAIL
char *
tilde(user)
char *user;
{
	pwlist *f;

	/*
	** check for previously cached user
	*/

	for(f=pwhead; f != NULL; f=f->vlink) {
		if(strcmp(user, f->lname) == 0) {
			return(f->home);
		}
	}
	/*
	** not found parse the password file
	*/

	while((f=pwparse()) != PNULL) {
		if(strcmp(user, f->lname) == 0) {
			return(f->home);
		}
	}
	return(NULL);
}
#endif /* not SENDMAIL */

char *
fullname(gecos)
char *gecos;
{
	static char fname[SMLBUF];
	register char *cend;

	(void) strcpy(fname, gecos);
	if (cend = index(fname, ','))
		*cend = '\0';
	if (cend = index(fname, '('))
		*cend = '\0';
	/*
	** Skip USG-style 0000-Name nonsense if necessary.
	*/
	if (isdigit(*(cend = fname))) {
		if ((cend = index(fname, '-')) != NULL)
			cend++;
		else
			/*
			** There was no `-' following digits.
			*/
			cend = fname;
	}
	return (cend);
}

pwlist *
pwparse()
{
	pwlist *f;
	char *p, *name;
	struct passwd *pwent, *getpwent();
	unsigned int i;
	static int pw_eof = 0;

	if((pw_eof == 1)
	|| ((pwent = getpwent()) == (struct passwd *) NULL)) {
		pw_eof = 1;
		return(PNULL);
	}
	/*
	** Get an entry from the password file.
	** Parse relevant strings.
	*/
	f = (pwlist *) malloc(sizeof(pwlist));
	if(f == PNULL) return(PNULL);

	f->vlink = pwhead;
	pwhead   = f;
	f->uid   = pwent->pw_uid;

	i=strlen(pwent->pw_name)+1;
	p = malloc(i);
	if(p == NULL) return(PNULL);
	f->lname = strcpy(p, pwent->pw_name);

	i=strlen(pwent->pw_dir)+1;
	p = malloc(i);
	if(p == NULL) return(PNULL);
	f->home  = strcpy(p, pwent->pw_dir);

	name = fullname(pwent->pw_gecos);
	i=strlen(name)+1;
	p = malloc(i);
	if(p == NULL) return(PNULL);
	f->fname = strcpy(p, name);
	return(f);
}

#ifdef FULLNAME
/*
** Resolve a full name to a login name.
** Not too much smarts here.
*/

char *
res_fname(user)
register char *user;
{
	long pos, middle, hi, lo;
	static long pathlength = 0;
	register char *s;
	int c;
	static FILE *file;
	int flag;
	char namebuf[SMLBUF], *path;
	extern enum edebug debug;
	extern char *fnlist;



DEBUG("res_fname: looking for '%s'\n", user);

	if(pathlength == 0) {	/* open file on first use */
		if((file=fopen(fnlist, "r")) == NULL) {
			DEBUG( "can't access %s.\n", fnlist);
			pathlength = -1;
		} else {
			(void) fseek(file, 0L, 2); 	/* find length */
			pathlength = ftell(file);
		}
	}

	if(pathlength == -1 ) return(NULL);

	lo = 0;
	hi = pathlength;
	path = namebuf;

	(void) strcpy( path, user );
	(void) strcat( path, "\t" );

	for( ;; ) {
		pos = middle = ( hi+lo+1 )/2;
		(void) fseek( file, pos, 0 );	/* find midpoint */
		if (pos != 0)		/* to beginning of next line */
			while( ( c=getc( file ) ) != EOF && c != '\n' );
		for( flag = 0, s = path; flag == 0; s++ ) { /* match??? */
			if ( *s == '\0' ) {
				goto solved;
			}
			c = getc( file );
			flag = lower( c ) - lower( *s );
		} 
		if (lo >= middle)		/* failure? */
			return(NULL);

		if(c != EOF && flag < 0)	/* close window */
			lo = middle;
		else 
			hi = middle - 1;
	}
/* 
** Now just copy the result.
*/
solved:
	while(((c  = getc(file)) != EOF) && (c != '\t') && (c != '\n')) {
		*path++ = c;
	}

	if(path == namebuf) {	/* NULL alias field */
		return(NULL);
	}

	*path = '\0';
	if((path = malloc((unsigned) strlen(namebuf)+1)) == NULL) {
		return(NULL);	/* sorry, no memory */
	}

	(void) strcpy(path, namebuf);
	return(path);

}
#endif	/* FULLNAME */
//E*O*F pw.c//

echo x - resolve.c
cat > "resolve.c" << '//E*O*F resolve.c//'
/*
**
**  Resolve.c
**
**  Routes then resolves addresses into UUCP or LOCAL.
**
*/
#ifndef lint
static char 	*sccsid="@(#)resolve.c	2.5 (smail) 9/15/87";
#endif

#include	<ctype.h>
#include	<stdio.h>
#include	"defs.h"

extern int exitstat;		/* set if address doesn't resolve 	*/
extern enum ehandle handle;	/* what mail we can handle		*/
extern enum edebug debug;	/* verbose and debug modes		*/
extern enum erouting routing;	/* when to route addresses		*/
extern char hostdomain[];	/* */
extern char hostname[];		/* */
extern char *pathfile;		/* location of path database		*/
extern int getcost;		/* get path cost even if not routing    */

char *sform();

/*
**
**  rsvp(): how to resolve addresses.
**
**  After parsing an address into <form>, the resolved form will be
**  rsvp( form ).  If == ROUTE, we route the parsed address and parse again.
**
*/

# define rsvp(a) table[(int)a][(int)handle]

enum eform table[5][3] = {
/*	all		justuucp	none */
{	ERROR, 		ERROR, 		ERROR }, 	/* error */
{	LOCAL, 		LOCAL,	 	LOCAL }, 	/* local */
{	ROUTE, 		LOCAL, 		LOCAL }, 	/* domain */
{	UUCP, 		UUCP, 		LOCAL }, 	/* uucp */
{	ERROR, 		ERROR, 		ERROR }};	/* route */

/*
**
**  resolve(): resolve addresses to <host, user, form>.
**
**  This is a gnarly piece of code, but it does it all.  Each section 
**  is documented.
**
*/

enum eform
resolve( address, domain, user , cost)
char *address;				/* the input address 	*/
char *domain;				/* the returned domain 	*/
char *user;				/* the returned user 	*/
int *cost;				/* the returned cost 	*/
{
	enum eform form;		/* the returned form	*/ 
	enum eform parse();		/* to crack addresses	*/
	int parts;			/* to ssplit addresses	*/
	char *partv[MAXPATH];		/* "  "      "		*/
	char temp[SMLBUF];		/* "  "      "		*/
	int i;
		

/*
**  If we set REROUTE and are prepared to deliver UUCP mail, we split the 
**  address apart at !'s and try to resolve successively larger righthand 
**  substrings until we succeed.  Otherwise, we just resolve the whole thing 
**  once.
*/
	if ((routing == REROUTE) && (rsvp( UUCP ) == UUCP)) {
		parts = ssplit( address, '!', partv );
	} else {
		parts = 1;
		partv[0] = address;
	}
/*
**  This for(i) loop selects successively larger
**  righthand substrings of the address.
*/
	for( i = parts - 1; i >= 0; i-- ) {
/*
**  Parse the address.
*/
		(void) strcpy( temp, partv[i] );
		form = parse( temp, domain, user );

DEBUG("resolve: parse address '%s' = '%s' @ '%s' (%s)\n",
	temp,user,domain,sform(form));

/*
**  If we are looking at a substring (that's not the entire string)
**  which parses to a LOCAL address, we skip to the next larger substring.
*/
		if((i != 0) && (form == LOCAL))
			continue;
/*
**  Routing, when required, is the next step.
**  We route the address if we have a ROUTE form
**  or if we have a UUCP form and we are told to
**  route ALWAYS or REROUTE (i.e., routing != JUSTDOMAIN)
*/
		if((rsvp( form ) == ROUTE)
		 ||((rsvp( form ) == UUCP) && (routing != JUSTDOMAIN ))) {

			int look_smart = 0;

			if((routing == REROUTE) && (i == 0)) {
				look_smart = 1; /* last chance */
			}

			/* route() puts the new route in 'temp' */
			if(route(domain,user,look_smart,temp,cost) != EX_OK) {
				continue;	/* If routing fails, try
						/* next larger substring.
						/* */
			}
/*
**  After routing, reparse the new route into domain and user. 
*/
			form = parse( temp, domain, user );

DEBUG("resolve: parse route '%s' = '%s' @ '%s' (%s)\n",
	temp,user,domain,sform(form));

		} else if((getcost) && (rsvp(form) == UUCP)) {
			/* get the cost of the route
			** even if we're not going route the mail.
			** this allows smart decisions about using
			** the -r flag to uux when we're not routing.
			*/
			char junk[SMLBUF];
			if(route(domain,user,0,junk,cost) != EX_OK) {
				continue;	/* If routing fails, try
						/* next larger substring.
						/* */
			}
		}
		break;	/* route is resolved */
	}
/*
**  For LOCAL mail in non-local format, we rewrite the full address into 
**  <user> and leave <domain> blank.
*/
	if ((rsvp( form ) == LOCAL) && (form != LOCAL )) {
		build( domain, user, form, temp );
		(void) strcpy( user, temp );
		(void) strcpy( domain, "" );
		form = LOCAL;
	}
/*
**  If we were supposed to route an address but failed (form == ERROR), 
**  or after routing we are left with an address that still needs to
**  be routed (rsvp( form ) == ROUTE), complain.
*/
	if ((form == ERROR) || (rsvp( form ) == ROUTE )) {
		exitstat = EX_NOHOST;
		ADVISE("resolve failed '%s' = '%s' @ '%s' (%s)\n",
			address, user, domain, sform(form));
		form = ERROR;
	} else {
		ADVISE("resolve '%s' = '%s' @ '%s' (%s)\n",
			address, user, domain, sform(form));
	}
	return ( form );
}

/*
**
**  route(): route domain, plug in user.
**
**  Less complicated than it looks.  Each section is documented.
**
*/

route(domain, user, look_smart, result, cost)
char *domain;			/* domain or host name 	*/
char *user;			/* user name 		*/
int look_smart;			/* do we try to route through a smarter host? */
char *result;			/* output route 	*/
int *cost;			/* cost of output route */
{
	int	uucpdom = 0;
	int	domains, step;			/* to split domain	*/
	char	*domainv[MAXDOMS];		/* "  "     "		*/
	char	temp[SMLBUF], path[SMLBUF];

/*
**  Fully qualify the domain, and then strip the last (top level domain) 
**  component off, so that we look it up separately.
*/
	temp[0] = '.';
	(void) strcpy(temp+1, domain );

	domains = ssplit( temp+1, '.', domainv );

/*
** check target domain for the local host name and host domain.
** if it matches, then skip the lookup in the database.
** this prevents mail loops for cases where SMARTHOST is defined
** in the routing table, but the local host is not.  It also is
** a little faster when the local host is the target domain.
*/
	if((strcmpic(domain, hostname) == 0)
	|| (strcmpic(domain, hostdomain) == 0)) {
		step = 0;
		*cost = 0;
		(void) strcpy(path, "%s");
DEBUG("route: '%s' is local\n", domain);
		goto route_complete;
	}

	/* If the domain ends in .UUCP, trim that off. */
	if((domains > 0) && isuucp(domainv[domains-1])) {
		domains--;
		domainv[domains][-1] = '\0';
		uucpdom = 1;
	}
/*
**  Try to get the path for successive components of the domain.  
**  Example for osgd.cb.att.uucp:
**	osgd.cb.att
**	cb.att
**	att
**	uucp ( remember stripping top level? )
**	SMARTHOST
**  Returns with error if we find no path.
*/
	for(step = 0; (step < domains); step++) {
		if((getpath(domainv[step]-1, path, cost) == EX_OK) /* w/ dot */
		|| (getpath(domainv[step]  , path, cost) == EX_OK))/* no dot */
			break;
	}

	if(step == domains) {
	/*
	** we've looked at each component of the domain without success
	*/
		/*
		** If domain is a UUCP address, look for a UUCP gateway.
		*/
		if((uucpdom == 0) || (getpath(".UUCP", path, cost) != EX_OK)) {
			/*
			** The domain not is a UUCP address, or we can't
			** find a UUCP gateway.  If this is our last chance,
			** look for a smarter host to deliver the mail.
			*/
			if((look_smart == 0)
			|| (getpath(SMARTHOST, path, cost) != EX_OK)) {
				/*
				** All our efforts have been in vain.
				** Tell them the bad news.
				*/
				DEBUG("route '%s' failed\n", domain);
				return( EX_NOHOST );
			}
		}
	}

route_complete:

DEBUG("route:  '%s' (%s) = '%s' (%d)\n", domain, domainv[step]?domainv[step]:"NULL", path, *cost);

/*
**  If we matched on the entire domain name, this address is fully resolved, 
**  and we plug <user> into it.  If we matched on only part of the domain 
**  name, we plug <domain>!<user> in.  
*/
	build(domain, user, (step == 0) ? LOCAL : UUCP, temp);
	(void) sprintf(result, path, temp);
	return( EX_OK );
}
//E*O*F resolve.c//

echo x - smail.prompt
cat > "smail.prompt" << '//E*O*F smail.prompt//'
#
# @(#)smail.prompt	2.5 (smail) 9/15/87
#

loop=true
while test $loop = true
do 
	case "$1" in
	string)
		echo "$2" 1>&2
		read ans
		if test ! -z "$ans"
		then
			echo $ans
			loop=false;
		fi
	;;
	file)
		echo "$2" 1>&2
		read ans
		case "$ans" in
		/*)
			if test -f "$ans"
			then
				echo $ans
				loop=false;
			else
				echo "file '$ans' not found" 1>&2
			fi
		;;
		*)
			echo "must give FULL PATH to file" 1>&2
		;;
		esac
	;;
	yesno)
		echo "$2" 1>&2
		read ans
		case "$ans" in
		y|Y|yes|Yes|YES)
			echo "yes"
			loop=false
		;;
		n|N|no|No|NO)
			echo "no"
			loop=false
		;;
		*)
			echo "Please enter yes or no" 1>&2
		;;
		esac
	;;
	*)

		echo "usage: $0 string|yesno prompt_message" 1>&2
		echo BOGUS_PROMPT_STRING
		loop=false
	;;
	esac
done
//E*O*F smail.prompt//

echo x - str.c
cat > "str.c" << '//E*O*F str.c//'
#ifndef lint
static char 	*sccsid="@(#)str.c	2.5 (smail) 9/15/87";
#endif

#include "defs.h"
#include <ctype.h>

/*
**	strncmpic: string compare, ignore case, stop after 'n' chars
*/

strncmpic(s1, s2, n)
char *s1, *s2;
int n;
{
	register char *u = s1;
	register char *p = s2;

	while((n > 0) && (*p != '\0')) {
		/* chars match or only case different */
		if(lower(*u) == lower(*p)) {
			p++;	/* examine next char */
			u++;
		} else {
			break;	/* no match - stop comparison */
		}
		n--;
	}
	if(n > 0) {
		return(lower(*u) - lower(*p)); /* return "difference" */
	} else {
		return(0);
	}
}

/*
**	strcmpic: string compare, ignore case
*/

strcmpic(s1, s2)
char *s1, *s2;
{
	register char *u = s1;
	register char *p = s2;

	while(*p != '\0') {
		/* chars match or only case different */
		if(lower(*u) == lower(*p)) {
			p++;	/* examine next char */
			u++;
		} else {
			break;	/* no match - stop comparison */
		}
	}

	return(lower(*u) - lower(*p)); /* return "difference" */
}

//E*O*F str.c//

echo x - svbinmail.c
cat > "svbinmail.c" << '//E*O*F svbinmail.c//'
#ifndef lint
static char	*sccsid = "@(#)svbinmail.c	2.5 (smail) 9/15/87";
#endif
/* */
/* This program will be used in place of /bin/mail on SVR2 sites.
/* It looks at the arguments and decides whether to call
/* SENDER for sending mail, or READER for reading mail.
/*
/* before installing as /bin/mail, move the stock /bin/mail to /bin/lmail
/*
/*  */

#include <stdio.h>
#include "defs.h"

#ifdef SENDMAIL
#define SENDER	SENDMAIL
#else
#define	SENDER	"/bin/rmail"
#endif

#define	READER	"/bin/lmail"

#define TRUE 1
#define FALSE 0

char prog[128];

void	perror(), exit(), usage();

main(argc, argv)
int argc;
char *argv[];
{
	extern int optind;
	extern char *optarg;

	int i, j, c;
	int reading, sending;

	reading = sending = FALSE;

	(void) strcpy(prog, argv[0]);

	if(argc == 1) {
		reading = TRUE;
	} else {
		while((c = getopt(argc, argv, "epqrtf:")) != EOF) {
			switch(c) {
			case 'e':
			case 'p':
			case 'q':
			case 'r':
			case 'f':
				reading = TRUE;
				break;
			case 't':
				sending = TRUE;
				break;
			default:
				usage();
				return(1);
			}
		}
	}

	/* any arguments left over -> sending */
	if(argc > optind) {
		sending = TRUE;
	}

	if((reading == TRUE) && (sending == TRUE)) {
		usage();
		return(1);
	}

	if(sending == TRUE) {
		argv[0] = SENDER;
		for(i = 1, j = optind; j < argc; i++, j++) {
			argv[i] = argv[j];
		}
		argv[i] = NULL;
	} else {
		argv[0] = READER;
	}

	(void) execvp(argv[0], argv);
	(void) fprintf(stderr, "%s: execvp(\"%s\", argv) failed: ",
		prog, argv[0]);
	perror("");
	return(1);
}

void
usage()
{
	(void) fprintf(stderr, "usage:\t%s [ -epqr ] [ -f file ]\n", prog);
	(void) fprintf(stderr, "\t%s [ -t ] persons\n", prog);
}
//E*O*F svbinmail.c//

echo x - sysexits.h
cat > "sysexits.h" << '//E*O*F sysexits.h//'
/*
**	@(#)sysexits.h	2.5 (smail) 9/15/87
*/

# define EX_OK		0	/* successful termination */
# define EX_USAGE	64	/* command line usage error */
# define EX_NOHOST	68	/* host name unknown */
# define EX_UNAVAILABLE	69	/* service unavailable */
# define EX_SOFTWARE	70	/* internal software error */
# define EX_OSFILE	72	/* critical OS file missing */
# define EX_CANTCREAT	73	/* can't create (user) output file */
# define EX_TEMPFAIL	75	/* temp failure; user is invited to retry */
//E*O*F sysexits.h//

echo x - template.cf
cat > "template.cf" << '//E*O*F template.cf//'
############################################################
#
#	SENDMAIL CONFIGURATION FILE
#
#	supports internet style addressing
#	over UUCP and ethernet links.
#
#	A product of the UUCP Project.
#
#	@(#)template.cf	2.5 (smail) 9/15/87
#
############################################################


############################################################
#
#  Local configuration options - HINTS
#
# Host name and domain name macros.
#
#	Dw sets $w
#	DD sets $D
#	CD sets $=D
#
# $D and $=D list all domains in which this host sits.
# $D goes into outbound addresses, i.e. "user@$w.$D".
# $A is another domain for which this host is 'authoritative'
# it will will be turned into $D.

CF_HOST
CF_DOMAIN
CF_AUTHORITY
CF_DCLASS

# Preemptive ether connections.  We prefer these connections 
# over both designated transport mechanisms and the general depository.
# You can add more classes (here and in S0).

# /etc/hosts.smtp might be a link to /etc/hosts
#
CF_SMTP

# Mock top-level domain names.  These name designate a transport mechanism
# and appear internally only, set in S3, used in S0, and removed in S4 and
# (possibly) the ruleset for the particular mailer.  

CTETHER UUX

# Relay host.  Used at the end of S0 as the general depository for 
# addresses which didn't resolve locally.  

DRrelay

#
#  End Local configuration options
#
############################################################

############################################################
#
#	General configuration information
#
############################################################

DVsmail2.5/CF_DATE

##########################
#     Special macros     #
##########################

# official hostname
Dj$w.$D
# my name
DnMAILER-DAEMON
# UNIX header format
DlFrom $g  $d
# delimiter (operator) characters
Do.:%@!^=/[]
# format of a total name
Dq$g$?x ($x)$.
# SMTP login message
De$j Sendmail $v/$V ready at $b


###################
#     Options     #
###################

# location of alias file
OA/usr/lib/aliases
# default delivery mode (deliver in background)
Odbackground
# (don't) connect to "expensive" mailers
#Oc
# temporary file mode
OF0644
# default GID
Og1
# location of help file
OH/usr/lib/sendmail.hf
# log level
OL9
# default messages to old style
Oo
# queue directory
OQ/usr/spool/mqueue
# read timeout -- violates protocols
Or2h
# status file
OS/usr/lib/sendmail.st
# queue up everything before starting transmission
Os
# default timeout interval
OT3d
# time zone names (V6 only)
OtPST,PDT
# default UID
Ou1
# wizard's password
OWvoidpasswords

###############################
#     Message precedences     #
###############################

Pfirst-class=0
Pspecial-delivery=100
Pjunk=-100

#########################
#     Trusted users     #
#########################

Troot
Tdaemon
Tuucp
Tnetwork

#############################
#     Format of headers     #
#############################

#H?P?Return-Path: <$g>
HReceived: $?sfrom $s 
	$.by $j ($v/$V)
	id $i; $b
H?D?Resent-Date: $a
H?D?Date: $a
H?F?Resent-From: $q
H?F?From: $q
H?x?Full-Name: $x
HSubject:
# HPosted-Date: $a
# H?l?Received-Date: $b
H?M?Resent-Message-Id: <$t.$i@$j>
H?M?Message-Id: <$t.$i@$j>

############################################################
#
#		REWRITING RULES
#


###########################
#			  #
#  Name Canonicalization  #
#			  #
###########################
S3

# basic textual canonicalization
R<>			$@@				turn into magic token
R$*<$+>$*		$2				basic RFC821/822 parsing
R$+ at $+		$1@$2				"at" -> "@" for RFC 822
R$*<$*>$*		$1$2$3				in case recursive

# handle route-addr <@a,@b,@c:user@d> 
R@$+,$+			@$1:$2				change all "," to ":"
R@$+:$+			$@<@$1>:$2			handle <route-addr>
R$+:$*;@$+		$@$1:$2;@$3			list syntax

# Rewrite address into a domain-based address.  Any special mock domain names 
# (like UUX) should be defined on the CT line and removed (if necessary) 
# in S4.  You can use them in S0 for designated transport mechanisms.

# Delimiters with precedence over @.  Add yours here.

# The @ delimiter.  Leave this alone.
R$+@$+			$:$1<@$2>			focus on domain
R$+<$+@$+>		$1$2<@$3>			move gaze right
R$+<@$+>		$@$1<@$2>			already canonical

# Delimiters with precedence below @.  Add yours here.
R$+^$+			$1!$2				convert ^ to !
R$-!$+			$@$2<@$1.UUX>			resolve uucp names
R$+.!$+			$@$2<@$1>			domain.!host
R$+!$+			$@$2<@$1>			domain!host

# % is a low precedence @.
R$*%$*			$@$>3$1@$2			%->@ and retry

############################################################
#
#    		RULESET ZERO PREAMBLE
#
############################################################

S0

# first make canonical
R$*<$*>$*		$1$2$3				defocus
R$+			$:$>3$1				make canonical

# handle special cases.....
R@			$#local$:MAILER-DAEMON		handle <> form
R$*<@[$+]>$*		$#ether$@[$2]$:$1@[$2]$3	numeric internet spec

# strip local stuff
R$*<@$-.$w.$D>$*	$1<@$2>$3			thishost.mydom
CF_GATEWAYR$*<@$-.$D>$*	$1<@$2>$3			mydom
R$*<@$-.$w.$=D>$*	$1<@$2>$4			thishost.anydom
R$*<@$-.$w.$A>$*	$1<@$2>$3			thishost.anotherdom
R$*<@$-.$A>$*		$1<@$2>$3			anotherdom
R$*<@$-.$w.$=T>$*	$1<@$2>$4			thishost.mockdom
CF_GATEWAYR$*<$*$w>$*	$1<$2>$3			thishost
R$*<$*.>$*		$1<$2>$3			drop trailing dot
R<@>:$+			$@$>0$1				strip null route, retry
R$+<@>			$@$>0$1				strip null addr, retry


###############################################
#    Machine dependent part of ruleset zero   #
###############################################

# Preemption: for a host on a known link turn the domain spec into a
# mock domain indicating the link.  One set of these rules for each of 
# the F classes listed in the local configuration options.

R$*<$*$=E.$D>$*			$:$1<$2$3.ETHER>$4	etherhost.mydomain
R$*<$*$=E.$=D>$*		$:$1<$2$3.ETHER>$5	etherhost.anydomain
R$*<$*$=E.$A>$*			$:$1<$2$3.ETHER>$4	etherhost.anotherdomain
R$*<$*$=E.$=T>$*		$:$1<$2$3.ETHER>$5	etherhost.mock-domain
R$*<$*$=E>$*			$:$1<$2$3.ETHER>$4	etherhost

# Designated delivery: use the indicated transport mechanism.  One of
# these rules for each of the mock domains defined in $=T.  You can
# remove these if you just want general disposition.  HINTS.

# Designated delivery:
R$*<@$=U.UUX>$*		$#uux$@$2$:$1$3			known uucphost
R$*<@$=E$+.ETHER>$*	$#ether$@$2$:$1@$2$4		known etherhost
R$*<@$+.ETHER>$*	$#ether$@$2$:$1@$2$3		etherhost

# throw out mock domain name now
R$*<$*.$=T>$*		$1<$2>$4

# General disposition of remote mail (comment out all but one).  You
# might add to this list, if you have other "smarter" mailers.  HINTS.

R$*<@$->:$+		$#uux$@$2$:$1$3			forward to $2
R$*<@$*>$*		$#uux$@$2$:$1$3			hand to uucp
#R$*<@$*>$*		$#uux$@$R$:$1@$2$3		hand to uucp relay
#R$*<@$*>$*		$#ether$@$R$:$1@$2$3		hand to ether relay
#R$*<$*>$*		$#error$:unknown address $1$2$3	don't hand anywhere

# local delivery
R$+			$#local$:$1			user

############################################################
#
# 		Local and Program Mailer specification
#
############################################################

CF_SVMAILMlocal, P=CF_LOCALMAIL, F=lsDFMhumSU, S=10, R=20, A=rmail $u
CF_BSMAILMlocal, P=CF_LOCALMAIL, F=rlsDFMmn, S=10, R=20, A=mail -d $u
Mprog,	P=/bin/sh,   F=lsDFMe,   S=10, R=20, A=sh -c $u

S10
R@			MAILER-DAEMON	errors to mailer-daemon
CF_HIDDENHOSTSR$+<@$+.$j>$*		$1<@$j>$3	hide anydom.$j under $j

S20

############################################################
#
#    		UUCP Mailer specification
#
############################################################

Muux,	P=/bin/smail, F=sDFMhum, S=14, R=24, M=100000,
	A=smail -vH$j $h!$u

S14
R$+<@$=E>		$1			user@etherhost -> user
R$*<@$+>$*		$@$1<@$2>$3		already ok
CF_HIDDENHOSTSR$+<@$+.$j>$*		$1<@$j>$3		hide anydom.$j under $j
R$+			$@$1<@$j>		add our full address

S24

############################################################
#
#    		SMTP ethernet mailer
#
############################################################

Mether,	P=[IPC], F=msDFMuCXP, S=11, R=21, A=IPC $h

S11
R$*<@$+>$*		$@$1<@$2>$3		already ok
R$+			$@$1<@$w>		add our hostname

S21

#################################
#  Final Output Post-rewriting  #
#################################

# This rewrites the internal $=T mock domains into their external form.
# The default is to replace the mock domain name with $D.
# The last two lines are stock.

S4
R@			$@				handle <> error addr
R$+<@$-.UUX>		$2!$1				u@host.UUX => host!u
R$*<$*$=T>$*		$:$1<$2$D>$4			change local info
R$*<$+>$*		$1$2$3				defocus
R@$+:$+:$+		@$1,$2:$3			<route-addr> canonical
//E*O*F template.cf//

exit 0