[comp.unix.xenix] Smail 2.5 vs. SCO Xenix System V: my solution

chip@ateng.UUCP (Chip Salzenberg) (12/01/87)

This posting is a sharchive of my modifications to smail 2.5 for use under
SCO Xenix System V.  I've only run it on Xenix/286 v2.2.0, but I can't
imagine that my code isn't portable. ;-)

DISCLAIMER AHEAD - DANGER WILL ROBINSON
>> Sorry, I'm not responsible for lost mail.  Your mileage may vary.
END OF DISCLAIMER

What to do:

	1.  Unpack the sharchive.

	2.  Integrate the resulting files with the standard smail files.

	    This may be as simple as `mv * /usr/src/smail', although it
	    would be good to check the defs.h file for correctness
	    before proceeding.

	3.  Compile smail and execm with the command `make'.

	4.  As root, run `./install_smail'.

Note that as shipped, this modification to smail gives you two (count 'em, two)
alias files.  Smail uses /usr/lib/mail/saliases; you can use RFC822 addresses
here.  Execmail uses /usr/lib/mail/aliases; you can use pipe aliases here.
(You know, "rnews: |/usr/lib/news/uurec" and the like.)

To use RFC822 addresses with Xenix `mail', add the line "set execmail" to the
/usr/lib/mail/mailrc file.

	"It is forbidden to take the Bastille"
		-- Sign in pre-revolutionary France

#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the "#! /bin/sh" line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create the files:
#	Makefile
#	install_smail
#	execm.c
#	defs.h
#	deliver.c
# This archive created: Tue Dec  1 16:04:26 1987
export PATH; PATH=/bin:$PATH
:
echo 'shar: extracting "Makefile" (1246 characters) '
if test -f 'Makefile'
then
	echo 'shar: will not overwrite existing file "Makefile" '
else
sed 's/^X//' << \SHAR_EOF > 'Makefile'
X# Makefile for smail
X# @(#)Makefile	2.5 (smail) 9/15/87
X#
X# Modified for SCO Xenix by Chip Salzenberg (chip@ateng.UUCP).
X# Released to Usenet on 01 Dec 1987.
X#
X# With the addition of the `all' pseudo-target, this makefile now makes
X# both smail and execm by default.
X#
X# Use the `install_smail' script to install the resulting binaries.
X
XCFLAGS	= -O
XLDFLAGS = -i
XSHELL	= /bin/sh
X
X#
X# System V Release 2.0 sites can use -lmalloc for a faster malloc
X#
X#LIBS	=	-lmalloc
X
XOBJECTS =	main.o map.o resolve.o deliver.o misc.o alias.o pw.o headers.o getpath.o str.o getopt.o
X
Xall:            smail execm
X
Xsmail:		$(OBJECTS)
X		$(CC) $(LDFLAGS) -F 4000 $(OBJECTS) -o smail $(LIBS)
X
X$(OBJECTS):	defs.h
X		$(CC) $(CFLAGS) -c $<
X
Xexecm:          execm.c
X		$(CC) $(CFLAGS) execm.c -o execm
X
Xsvbinmail:	svbinmail.c defs.h
X		$(CC) $(LDFLAGS) svbinmail.c -o svbinmail
X
Xlcasep:		lcasep.c
X		$(CC) $(LDFLAGS) lcasep.c -o lcasep
X
Xpathproc:	pathproc.sh
X		$(COPY) pathproc.sh pathproc
X		chmod 755 pathproc
X
Xmkfnames:	mkfnames.sh
X		$(COPY) mkfnames.sh mkfnames
X		chmod 755 mkfnames
X
Xnptx:		nptx.o pw.o str.o
X		$(CC) $(CFLAGS) nptx.o pw.o str.o -o nptx $(LIBS)
X
Xclean:
X		rm -f *.o *.ln a.out core
X
Xclobber:	clean
X		rm -f smail rmail lcasep pathproc mkfnames svbinmail nptx
SHAR_EOF
if test 1246 -ne `wc -c < 'Makefile'`
then
	echo 'shar: error transmitting "Makefile" (should have been 1246 characters) '
fi
chmod 664 'Makefile'
fi  # end of overwriting check
:
echo 'shar: extracting "install_smail" (1137 characters) '
if test -f 'install_smail'
then
	echo 'shar: will not overwrite existing file "install_smail" '
else
sed 's/^X//' << \SHAR_EOF > 'install_smail'
X: install_smail
X# Shell script to install smail in a Xenix System V system.
X#
X# Written by Chip Salzenberg (chip@ateng.UUCP).
X# Released to Usenet on 01 Dec 1987.
X#
X# Note that this script renames the standard Xenix rmail and execmail
X# programs to rmail.x and execmail.x respectively.  If those `.x' files
X# already exist, then no renaming takes place, so you can run this script
X# more than once without losing those renamed programs.
X#
X# BTW, be sure to test everything thoroughly; a broken mail system is
X# sure to upset any users on your system.
X
XCOPY="copy -m"
XSMAIL="/usr/bin/smail"
XRMAIL="/usr/bin/rmail"
XEXECM="/usr/lib/mail/execmail"
X
Xfor f in smail execm
Xdo
X    if [ ! -x $f ]; then
X	echo "You need to compile $f first."
X	exit 1
X    fi
Xdone
X
Xecho "Installing current smail -- you have 5 seconds to abort."
Xsleep 5
X
Xif [ ! -f $RMAIL.x ]; then
X    mv $RMAIL $RMAIL.x
Xfi
Xrm -f $RMAIL
Xif [ ! -f $EXECM.x ]; then
X    mv $EXECM $EXECM.x
Xfi
Xrm -f $EXECM
X
X$COPY execm $EXECM
Xchown bin $EXECM
Xchgrp bin $EXECM
Xchmod 755 $EXECM
X
Xrm -f $SMAIL $RMAIL
X$COPY smail $SMAIL
Xchown bin $SMAIL
Xchgrp bin $SMAIL
Xchmod 755 $SMAIL
Xln $SMAIL $RMAIL
SHAR_EOF
if test 1137 -ne `wc -c < 'install_smail'`
then
	echo 'shar: error transmitting "install_smail" (should have been 1137 characters) '
fi
chmod 775 'install_smail'
fi  # end of overwriting check
:
echo 'shar: extracting "execm.c" (747 characters) '
if test -f 'execm.c'
then
	echo 'shar: will not overwrite existing file "execm.c" '
else
sed 's/^X//' << \SHAR_EOF > 'execm.c'
X/*
X * execm.c
X *
X * This program is a substitute for Xenix's /usr/lib/mail/execmail.
X *
X * Written by Chip Salzenberg (chip@ateng.UUCP).
X * Released to Usenet on 01 Dec 1987.
X *
X * Do what you want with it; I'm not responsible for lost mail,
X * but I don't expect that this little program will lose anything.
X */
X
X#include <stdio.h>
X
Xmain(argc, argv)
Xint     argc;
Xchar    **argv;
X{
X	char *progname = argv[0];
X
X	/*
X	 * Drop the execmail options.
X	 */
X	while (argv[1][0] == '-')
X	{
X		switch (argv[1][1])
X		{
X		case 'f':
X		case 'h':
X			argv += 2;
X			break;
X		default:
X			++argv;
X			break;
X		}
X	}
X
X	argv[0] = progname;
X	execv("/usr/bin/smail", argv);
X	execv("/bin/smail", argv);
X
X	fprintf(stderr, "%s: can't execute smail!\n", progname);
X	exit(1);
X}
SHAR_EOF
if test 747 -ne `wc -c < 'execm.c'`
then
	echo 'shar: error transmitting "execm.c" (should have been 747 characters) '
fi
chmod 664 'execm.c'
fi  # end of overwriting check
:
echo 'shar: extracting "defs.h" (11012 characters) '
if test -f 'defs.h'
then
	echo 'shar: will not overwrite existing file "defs.h" '
else
sed 's/^X//' << \SHAR_EOF > 'defs.h'
X/*
X**
X**  Defs.h:  header file for rmail/smail.
X**
X**  Configuration options for rmail/smail.
X**	default configuration is:
X**	full domain name is 'hostname.uucp' (get registered!)
X**	path file is /usr/lib/uucp/paths.
X**	no log, no record, use sendmail.
X** 
X**  You can change these in the next few blocks.
X**
X*/
X
X/*
X**	@(#)defs.h	2.5 (smail) 9/15/87
X*/
X
X/*
X**      Modified for SCO Xenix by Chip Salzenberg (chip@ateng.UUCP).
X**      Released to Usenet on 01 Dec 1987.
X**
X**      SCO's compiler automatically defines M_XENIX; we use it here.
X**
X**      Note that we define EXECMAIL here; Xenix's execmail is almost,
X**      but not quite, entirely unlike sendmail.  :-)  Thus it is not
X**      quite useful to define SENDMAIL as "execmail".
X*/
X
X#ifndef VERSION
X#define	VERSION	"smail2.5"
X#endif
X
X/*#define BSD				/* if system is a Berkeley system */
X/*#define SENDMAIL "/usr/lib/sendmail"  /* if system has Berkeley sendmail */
X
X#ifdef BSD
X#define GETHOSTNAME			/* use gethostname() */
X#else
X#define UNAME 				/* use uname() */
X#endif
X
X/* if defined, HOSTNAME overrides UNAME and GETHOSTNAME */
X/*#define HOSTNAME	"host"		/* literal name */
X
X/*#define HOSTDOMAIN	"host.dom"	/* overrides default HOSTNAME.MYDOM */
X
X/*
X * .UUCP here is just for testing, GET REGISTERED in COM, EDU, etc.
X * See INFO.REGISTRY for details.
X */
X
X#define MYDOM		".UUCP"		/* literal domain suffix */
X
X/*
X * WARNING: DOMGATE is only for qualified gateways - use caution.
X * If you don't fully understand it - don't use it!
X * If you are not completely sure you need it - don't use it!
X * If you are not prepared to handle all addresses to MYDOM - don't use it!
X *
X * if defined, DOMGATE (DOMain GATEway) will cause addresses of the form
X *
X *	user@MYDOM or MYDOM!user
X *
X * (with and without the leading '.' on MYDOM)
X * to be seen treated simply 'user' - a purely local address.
X * Then, it is left to the aliasing code to map it back to a
X * non-local address if necessary.
X */
X
X/*#define DOMGATE		/* Act as Domain Gateway */
X
X/*
X * HIDDENHOSTS allows hosts that serve as domain gateways to hide
X * the subdomains beneath them.  Mail that originates at any of
X * the hosts in the subdomain will appear to come from the gateway host.
X * Hence, mail from
X *
X * 		anything.hostdomain!user
X *
X * will appear to come from 
X *
X * 		hostdomain!user
X *
X * A consequence is that return mail to hostdomain!user would need to
X * be forwarded to the proper subdomain via aliases or other forwarding
X * facilities.
X *
X * If you're using sendmail, then if defined here,
X * it should be used in ruleset 4 of the sendmail.cf, too.
X */
X
X/*#define HIDDENHOSTS			/* hide subdomains of hostdomain */
X
X/*
X * Mail that would otherwise be undeliverable will be passed to the
X * aliased SMARTHOST for potential delivery.
X *
X * Be sure that the host you specify in your pathalias input knows that you're
X * using it as a relay, or you might upset somebody when they find out some
X * other way.  If you're using 'foovax' as your relay, and below you have
X * #define SMARTHOST "smart-host", then the pathalias alias would be:
X *
X *	smart-host = foovax
X */
X
X#define SMARTHOST  "smart-host"      /* pathalias alias for relay host */
X
X/*
X**  ALIAS and CASEALIAS are used only if SENDMAIL is NOT defined.
X**  Sites using sendmail have to let sendmail do the aliasing.
X**  LOWERLOGNAME maps all local login names into lower case.  This
X**  helps sites who have only upper case send mail to mixed case sites.
X*/
X
X	/* Location of mail aliases */
X#ifdef M_XENIX
X#define ALIAS   "/usr/lib/mail/saliases"
X#else
X#define ALIAS   "/usr/lib/aliases"
X#endif
X/*#define CASEALIAS			/* make aliases case sensitive    */
X/*#define LOWERLOGNAME			/* map local logins to lower case */
X
X/*
X * defining FULLNAME means that Full Name resolution
X * will be attempted when necessary.
X *
X * the Full Name information will be taken from a
X * list of {Full Name, address} pairs.
X * The names in the list must be sorted
X * without regard to upper/lower case.
X *
X * defining DOT_REQD says that the user name must contain a '.' for
X * the Full Name search to be done.
X *
X * All full name searches are case insensitive.
X *
X */
X
X	/* list of Full Name, address pairs */
X#ifdef M_XENIX
X#define FULLNAME        "/usr/lib/mail/fullnames"
X#else
X#define FULLNAME	"/usr/lib/fullnames"
X#endif
X
X/*#define DOT_REQD			/* Must be George.P.Burdell@gatech.EDU
X					** not just  Burdell@gatech.EDU
X					*/
X
X/*
X**	PATHS is name of pathalias file.  This is mandatory.
X**	Define LOG if you want a log of mail.  This can be handy for
X**	debugging and traffic analysis.
X**	Define RECORD for a copy of all mail.  This uses much time and
X**	space and is only used for extreme debugging cases.
X*/
X
X#ifndef PATHS
X#define PATHS   "/usr/lib/uucp/paths"   /* location of the path database */
X#endif
X
X#define LOG   "/usr/spool/uucp/mail.log"        /* log of uucp mail */
X/*#define RECORD	"/tmp/mail.log"		/* record of uucp mail */
X
X/*
X**  Mailer options:
X**	RMAIL is the command to invoke rmail on machine sys.
X**	RARG is how to insulate metacharacters from RMAIL. 
X**	LMAIL is the command to invoke the local mail transfer agent.
X**	LARG is how to insulate metacharacters from LMAIL. 
X**	RLARG is LARG with host! on the front - to pass a uux addr to sendmail.
X**	SENDMAIL selects one of two sets of defines below for either
X**	using sendmail or /bin/lmail.
X*/	
X
X#ifndef UUX
X#define UUX		"/usr/bin/uux"	/* location of uux command   */
X#endif
X
X#ifndef SMAIL
X#define SMAIL           "/usr/bin/smail"  /* location of smail command */
X#endif
X
X/*
X** command used to retry failed mail, flag is used to set the routing level.
X*/
X#define VFLAG		((debug == VERBOSE)?"-v":"")
X#define RETRY(flag)	"%s %s %s -f %s ", SMAIL, VFLAG, flag, spoolfile
X
X/*
X** use the -a if you have it.  This sometimes helps failed mail and warning
X** messages get back to where the mail originated.
X**
X** some versions of uux can't do '-a' - pick one of the next two definitions
X*/
X
X/*#define RMAIL(flags,from,sys) "%s -a%s %s - %s!rmail",UUX,from,flags,sys /* */
X#define RMAIL(flags,from,sys) "%s %s - %s!rmail",UUX,flags,sys /* */
X
X#define RARG(user)              " '(%s)'",user
X#define RFROM(frm,now,host) 	"From %s  %.24s remote from %s\n",frm,now,host
X
X
X#ifdef SENDMAIL
X
X	/* We're letting sendmail do lots of work for us. */
X
X#define HANDLE	JUSTUUCP	/* see HANDLE definition below */
X#define ROUTING JUSTDOMAIN	/* see ROUTING definition below */
X
X#define LMAIL(frm,sys)          "%s -em -f'%s'",SENDMAIL,frm
X
X#define LARG(user)		" '%s'",postmaster(user)
X#define RLARG(sys,frm)		" '%s!%s'",sys,frm
X#define LFROM(frm,now,host)	"From %s %.24s\n",frm,now
X
X#else  /* !SENDMAIL */
X
X	/* We don't have sendmail, so we'll do the work ourselves. */
X
X#define HANDLE  ALL             /* see HANDLE definition below */
X#define ROUTING ALWAYS          /* see ROUTING definition below */
X
X#if defined(BSD)        /* BSD local delivery agent */
X#define LMAIL(frm,sys)          "/bin/mail"
X
X#elif defined(M_XENIX)  /* Xenix local delivery agent (renamed) */
X#define EXECMAIL                "/usr/lib/mail/execmail.x"
X#define LMAIL(frm,sys)          "%s -m -f '%s'",EXECMAIL,frm
X
X#else                   /* System V local delivery agent */
X#define LMAIL(frm,sys)          "/bin/lmail"
X
X#endif
X
X#define LARG(user)		" '%s'",postmaster(user)
X#define RLARG(sys,frm)		" '%s!%s'",sys,frm
X#define LFROM(frm,now,host)	"From %s %.24s\n",frm,now
X
X#endif
X
X/*
X**	The following definitions affect the queueing algorithm for uux.
X**
X**	DEFQUEUE	if defined the default is to queue uux mail
X**
X**	QUEUECOST	remote mail with a cost of less than QUEUECOST
X**			will be handed to uux for immediate delivery.
X**
X**	MAXNOQUEUE	don't allow more than 'n' immediate delivery
X**			jobs to be started on a single invocation of smail.
X**	
X**	GETCOST		if defined, the paths file will be searched for
X**			each address to discover the cost of the route.
X**			this allows informed decisions about whether to
X**			use the queue flags when calling uux.  The price
X**			is in the overhead of a paths file search for
X**			addresses that are not going to be routed.
X*/
X
X#define DEFQUEUE			/* default is to queue uux jobs */
X
X#define QUEUECOST		100	/* deliver immediately if the cost
X					/* is DEDICATED+LOW or better */
X
X#define MAXNOQUEUE		2	/* max UUX_NOQUEUE jobs         */
X
X#ifdef M_XENIX          /* Xenix UUCP doesn't have a `spool this' option */
X#define UUX_QUEUE               ""      /* uux flag for queueing        */
X#define UUX_NOQUEUE		""	/* uux with immediate delivery	*/
X#else                   /* Normal UUCP */
X#define GETCOST				/* search for cost		*/
X#define UUX_QUEUE               "-r"    /* uux flag for queueing        */
X#define UUX_NOQUEUE		""	/* uux with immediate delivery	*/
X#endif
X
X/*
X** Normally, all mail destined for the local host is delivered with a single
X** call to the local mailer, and all remote mail is delivered with one call
X** to the remote mailer for each remote host.  This kind of 'batching' saves
X** on the cpu overhead.
X**
X** MAXCLEN is used to limit the length of commands that are exec'd by smail.
X** This is done to keep other program's buffers from overflowing, or to
X** allow for less intelligent commands which can take only one argument
X** at a time (e.g., 4.1 /bin/mail).  To disable the batching, set MAXCLEN
X** a small value (like 0).
X*/
X
X#define MAXCLEN			128	/* longest command allowed (approx.)
X					/* this is to keep other's buffers
X					** from overflowing
X					*/
X
X/*
X** PLEASE DON'T TOUCH THE REST
X*/
X
X#define SMLBUF	512	/* small buffer (handle one item) */
X#define BIGBUF	4096	/* handle lots of items */
X 
X#define MAXPATH	32	/* number of elements in ! path */
X#define MAXDOMS	16	/* number of subdomains in . domain */
X#define MAXARGS	500	/* number of arguments */
X#ifndef NULL
X#define NULL	0
X#endif
X
X#define DEBUG 		if (debug==YES) (void) printf
X#define ADVISE 		if (debug!=NO) (void) printf
X#define error(stat,msg,a)	{ (void) fprintf(stderr, msg, a); exit(stat); }
X#define lower(c) 		( isupper(c) ? c-'A'+'a' : c )
X
X
Xenum eform {	/* format of addresses */
X	ERROR, 		/* bad or invalidated format */
X	LOCAL, 		/* just a local name */
X	DOMAIN, 	/* user@domain or domain!user */
X	UUCP,		/* host!address */
X	ROUTE,		/* intermediate form - to be routed */
X	SENT		/* sent to a mailer on a previous pass */
X};
X
Xenum ehandle { 	/* what addresses can we handle? (don't kick to LMAIL) */
X	ALL,		/* UUCP and DOMAIN addresses */
X	JUSTUUCP,	/* UUCP only; set by -l  */
X	NONE		/* all mail is LOCAL; set by -L */
X};
X
Xenum erouting {	/* when to route A!B!C!D */
X	JUSTDOMAIN,	/* route A if A is a domain */
X	ALWAYS,		/* route A always; set by -r */
X	REROUTE		/* route C, B, or A (whichever works); set by -R */
X};
X
Xenum edebug {	/* debug modes */
X	NO,		/* normal deliver */
X	VERBOSE,	/* talk alot */
X	YES		/* talk and don't deliver */
X};
X
X#ifdef BSD
X
X#include <strings.h>
X#include <sysexits.h>
X
X#else
X
X#include <string.h>
X#include "sysexits.h"
X#define	index	strchr
X#define	rindex	strrchr
X
X#endif
Xextern void exit(), perror();
Xextern unsigned sleep();
SHAR_EOF
if test 11012 -ne `wc -c < 'defs.h'`
then
	echo 'shar: error transmitting "defs.h" (should have been 11012 characters) '
fi
chmod 664 'defs.h'
fi  # end of overwriting check
:
echo 'shar: extracting "deliver.c" (12233 characters) '
if test -f 'deliver.c'
then
	echo 'shar: will not overwrite existing file "deliver.c" '
else
sed 's/^X//' << \SHAR_EOF > 'deliver.c'
X/*
X**  Deliver.c
X**
X**  Routines to effect delivery of mail for rmail/smail. 
X**
X*/
X
X/*
X**  Modified for SCO Xenix by Chip Salzenberg (chip@ateng.UUCP).
X**  Released to Usenet on 01 Dec 1987.
X*/
X
X#ifndef lint
Xstatic char 	*sccsid="@(#)deliver.c	2.5 (smail) 9/15/87";
X#endif
X
X# include	<stdio.h>
X# include	<sys/types.h>
X# include	<sys/stat.h>
X# include	<ctype.h>
X# include	<signal.h>
X# include	"defs.h"
X
Xextern char *myname;            /* who does caller think we are?*/
Xextern int  exitstat;		/* set if a forked mailer fails */
Xextern enum edebug debug;	/* how verbose we are 		*/ 
Xextern char hostname[];		/* our uucp hostname 		*/
Xextern char hostdomain[];	/* our host's domain 		*/
Xextern enum ehandle handle;	/* what we handle		*/
Xextern enum erouting routing;	/* how we're routing addresses  */
Xextern char *uuxargs;		/* arguments given to uux       */
Xextern int  queuecost;		/* threshold for queueing mail  */
Xextern int  maxnoqueue;		/* max number of uucico's       */
Xextern char *spoolfile;		/* file name of spooled message */
Xextern FILE *spoolfp;		/* file ptr  to spooled message */
Xextern int spoolmaster;		/* set if creator of spoolfile  */
Xextern char nows[];		/* local time in ctime(3) format*/
Xextern char arpanows[];		/* local time in arpadate format*/
Xchar stderrfile[20];		/* error file for stderr traping*/
X
X/*
X**
X**  deliver():  hand the letter to the proper mail programs.
X**
X**  Issues one command for each different host of <hostv>,
X**  constructing the proper command for LOCAL or UUCP mail.
X**  Note that LOCAL mail has blank host names.
X**
X**  The <userv> names for each host are arguments to the command.
X** 
X**  Prepends a "From" line to the letter just before going 
X**  out, with a "remote from <hostname>" if it is a UUCP letter.
X**
X*/
X
Xdeliver(argc, hostv, userv, formv, costv)
Xint argc;				/* number of addresses		*/
Xchar *hostv[];				/* host names			*/
Xchar *userv[];				/* user names			*/
Xenum eform formv[];			/* form for each address	*/
Xint costv[];				/* cost vector 			*/
X{
X	FILE *out;			/* pipe to mailer		*/
X	FILE *popen();			/* to fork a mailer 		*/
X#ifdef RECORD
X	void record();			/* record all transactions	*/
X#endif
X#ifdef LOG
X	void log();
X#endif
X	char *mktemp();
X	char from[SMLBUF];		/* accumulated from argument 	*/
X	char lcommand[SMLBUF];		/* local command issued 	*/
X	char rcommand[SMLBUF];		/* remote command issued	*/
X	char scommand[SMLBUF];		/* retry  command issued	*/
X	char *command;			/* actual command		*/
X	char buf[SMLBUF];		/* copying rest of the letter   */
X	enum eform form;		/* holds form[i] for speed 	*/
X	long size;			/* number of bytes of message 	*/
X	char *flags;			/* flags for uux		*/
X	char *sflag;			/* flag  for smail		*/
X	int i, j, status, retrying;
X	char *c, *postmaster();
X	int failcount = 0;
X	int noqcnt = 0;			/* number of uucico's started   */
X	char *uux_noqueue = UUX_NOQUEUE;/* uucico starts immediately    */
X	char *uux_queue   = UUX_QUEUE;	/* uucico job gets queued       */
X	off_t message;
X	struct stat st;
X
X/*
X** rewind the spool file and read the collapsed From_ line
X*/
X	(void) fseek(spoolfp, 0L, 0);
X	(void) fgets(from, sizeof(from), spoolfp);
X	if((c = index(from, '\n')) != 0) *c = '\0';
X	message = ftell(spoolfp);
X
X/*
X**  We pass through the list of addresses.
X*/
X	stderrfile[0] = '\0';
X	for(i = 0; i < argc; i++) {
X		char *lend = lcommand;
X		char *rend = rcommand;
X		char *send = scommand;
X
X/*
X**  If we don't have sendmail, arrange to trap standard error
X**  for inclusion in the message that is returned with failed mail.
X*/
X		(void) unlink(stderrfile);
X		(void) strcpy(stderrfile, "/tmp/stderrXXXXXX");
X		(void) mktemp(stderrfile);
X		(void) freopen(stderrfile, "w", stderr);
X		if(debug != YES) {
X			(void) freopen(stderrfile, "w", stdout);
X		}
X
X		*lend = *rend = *send = '\0';
X
X/*
X**  If form == ERROR, the address was bad 
X**  If form == SENT, it has been sent on a  previous pass.
X*/
X		form = formv[i];
X		if (form == SENT) {
X			continue;
X		}
X/*
X**  Build the command based on whether this is local mail or uucp mail.
X**  By default, don't allow more than 'maxnoqueue' uucico commands to
X**  be started by a single invocation of 'smail'.
X*/
X		if(uuxargs == NULL) {	/* flags not set on command line */
X			if(noqcnt < maxnoqueue && costv[i] <= queuecost) {
X				flags = uux_noqueue;
X			} else {
X				flags = uux_queue;
X			}
X		} else {
X			flags = uuxargs;
X		}
X
X		retrying = 0;
X		if(routing == JUSTDOMAIN) {
X			sflag = "-r";
X		} else if(routing == ALWAYS) {
X			sflag = "-R";
X		} else {
X			sflag = "";
X		}
X
X		(void) sprintf(lcommand, LMAIL(from, hostv[i]));
X		(void) sprintf(rcommand, RMAIL(flags, from, hostv[i]));
X
X/*
X**  For each address with the same host name and form, append the user
X**  name to the command line, and set form = ERROR so we skip this address
X**  on later passes. 
X*/
X		/* we initialized lend (rend) to point at the
X		 * beginning of its buffer, so that at
X		 * least one address will be used regardless
X		 * of the length of lcommand (rcommand).
X		 */
X		for (j = i; j < argc; j++) {
X			if ((formv[j] != form)
X			 || (strcmpic(hostv[i], hostv[j]) != 0)
X			 || ((lend - lcommand) > MAXCLEN)
X			 || ((rend - rcommand) > MAXCLEN)) {
X				continue;
X			}
X
X			/*
X			** seek to the end of scommand
X			** and add on a 'smail' command
X			** multiple commands are separated by ';'
X			*/
X
X			send += strlen(send);
X			if(send != scommand) {
X				*send++ = ';' ;
X			}
X
X			(void) sprintf(send, RETRY(sflag));
X			send += strlen(send);
X
X			lend += strlen(lend);
X			rend += strlen(rend);
X
X			if (form == LOCAL) {
X				(void) sprintf(lend, LARG(userv[j]));
X				(void) sprintf(send, LARG(userv[j]));
X			} else {
X				(void) sprintf(lend, RLARG(hostv[i], userv[j]));
X				(void) sprintf(send, RLARG(hostv[i], userv[j]));
X			}
X
X			(void) sprintf(rend, RARG(userv[j]));
X			formv[j] = SENT;
X		}
Xretry:
X/*
X** rewind the spool file and read the collapsed From_ line
X*/
X		(void) fseek(spoolfp, message, 0);
X
X		/* if the address was in a bogus form (usually DOMAIN),
X		** then don't bother trying the uux.
X		**
X		** Rather, go straight to the next smail routing level.
X		*/
X		if(form == ERROR) {
X			static char errbuf[SMLBUF];
X			(void) sprintf(errbuf,
X				"address resolution ('%s' @ '%s') failed",
X					userv[i], hostv[i]);
X			command = errbuf;
X			size    = 0;
X			goto form_error;
X		}
X
X		if (retrying) {
X			command = scommand;
X		} else if (form == LOCAL) {
X			command = lcommand;
X		} else {
X			command = rcommand;
X			if(flags == uux_noqueue) {
X				noqcnt++;
X			}
X		}
X		ADVISE("COMMAND: %s\n", command);
X
X/*
X** Fork the mailer and set it up for writing so we can send the mail to it,
X** or for debugging divert the output to stdout.
X*/
X
X/*
X** We may try to write on a broken pipe, if the uux'd host
X** is unknown to us.  Ignore this signal, since we can use the
X** return value of the pclose() as our indication of failure.
X*/
X		(void) signal(SIGPIPE, SIG_IGN);
X
X		if (debug == YES) {
X			out = stdout;
X		} else {
X			failcount = 0;
X			do {
X				out = popen(command, "w");
X				if (out) break;
X				/*
X				 * Fork failed.  System probably overloaded.
X				 * Wait awhile and try again 10 times.
X				 * If it keeps failing, probably some
X				 * other problem, like no uux or smail.
X				 */
X				(void) sleep(60);
X			} while (++failcount < 10);
X		}
X		if(out == NULL) {
X			exitstat = EX_UNAVAILABLE;
X			(void) printf("couldn't execute %s.\n", command);
X			continue;
X		}
X
X		size = 0;
X		if(fstat(fileno(spoolfp), &st) >= 0) {
X			size = st.st_size - message;
X		}
X/*
X**  Output our From_ line.
X*/
X		if (form == LOCAL) {
X
X#if defined(SENDMAIL) || defined(EXECMAIL)
X			/*
X			 * Smart transfer agent (sendmail or execmail)
X			 */
X			(void) sprintf(buf, LFROM(from, nows, hostname));
X			size += strlen(buf);
X			(void) fputs(buf, out);
X
X#else
X			/*
X			 * Dumb transfer agent
X			 */
X			char *p;
X			if((p=index(from, '!')) == NULL) {
X				(void) sprintf(buf,
X					LFROM(from, nows, hostname));
X				size += strlen(buf);
X				(void) fputs(buf, out);
X			} else {
X				*p = '\0';
X				(void) sprintf(buf, RFROM(p+1, nows, from));
X				size += strlen(buf);
X				(void) fputs(buf, out);
X				*p = '!';
X			}
X#endif
X		} else {
X			(void) sprintf(buf, RFROM(from, nows, hostname));
X			size += strlen(buf);
X			(void) fputs(buf, out);
X		}
X
X#if defined(SENDMAIL)
X/*
X**  If using sendmail, insert a Received: line only for mail
X**  that is being passed to uux.  If not using sendmail, always
X**  insert the received line, since sendmail isn't there to do it.
X*/
X		if(command == rcommand && handle != ALL)
X#endif
X		{
X			(void) sprintf(buf,
X				"Received: by %s (%s)\n\tid AA%05d; %s\n",
X					hostdomain, VERSION,
X					getpid(), arpanows);
X			size += strlen(buf);
X			(void) fputs(buf, out);
X		}
X
X/*
X**  Copy input.
X*/
X		while(fgets(buf, sizeof(buf), spoolfp) != NULL) {
X			(void) fputs(buf, out);
X		}
X/*
X**  Get exit status and if non-zero, set global exitstat so when we exit
X**  we can indicate an error.
X*/
Xform_error:
X		if (debug != YES) {
X			if(form == ERROR) {
X				exitstat = EX_NOHOST;
X			} else if (status = pclose(out)) {
X				exitstat = status >> 8;
X			}
X			/*
X			 * The 'retrying' check prevents a smail loop.
X			 */
X			if(exitstat != 0) {
X				/*
X				** the mail failed, probably because the host
X				** being uux'ed isn't in L.sys or local user
X				** is unknown.
X				*/
X
X				if((retrying == 0)	/* first pass */
X				&& (routing != REROUTE)	/* have higher level */
X				&& (form != LOCAL)) {	/* can't route local */
X					/*
X					** Try again using a higher
X					** level of routing.
X					*/
X					ADVISE("%s failed (%d)\ntrying %s\n",
X						command, exitstat, scommand);
X					exitstat = 0;
X					retrying = 1;
X					form = SENT;
X					goto retry;
X				}
X
X				/*
X				** if we have no other routing possibilities
X				** see that the mail is returned to sender.
X				*/
X
X				if((routing == REROUTE)
X			        || (form == LOCAL)) {
X
X					/*
X					** if this was our last chance,
X					** return the mail to the sender.
X					*/
X
X					ADVISE("%s failed (%d)\n",
X						command, exitstat);
X					
X					(void) fseek(spoolfp, message, 0);
X#if defined(SENDMAIL) || defined(EXECMAIL)
X					/* Mail is automatically returned
X					** by sendmail and execmail, so we
X					** need not do it again.
X					*/
X					if(form != LOCAL)
X#endif
X					{
X						return_mail(from, command);
X					}
X					exitstat = 0;
X				}
X			}
X# ifdef LOG
X			else {
X				if (retrying == 0)
X					log(command, from, size); /* */
X			}
X# endif
X		}
X	}
X/*
X**  Update logs and records.
X*/
X# ifdef RECORD
X	(void) fseek(spoolfp, message, 0);
X	record(command, from, size);
X# endif
X
X/*
X**  close spool file pointer.
X**  if we created it, then unlink file.
X*/
X	(void) fclose(spoolfp);
X	if(spoolmaster) {
X		(void) unlink(spoolfile);
X	}
X	(void) unlink(stderrfile);
X}
X
X/*
X** return mail to sender, as determined by From_ line.
X*/
Xreturn_mail(from, fcommand)
Xchar *from, *fcommand;
X{
X	char buf[SMLBUF];
X	char domain[SMLBUF], user[SMLBUF];
X	char *r;
X	FILE *fp, *out, *popen();
X	int i = 0;
X
X	r = buf;
X
X	(void) sprintf(r, "%s %s", SMAIL, VFLAG);
X	r += strlen(r);
X
X	if(islocal(from, domain, user)) {
X		(void) sprintf(r, LARG(user));
X	} else {
X		(void) sprintf(r, RLARG(domain, user));
X	}
X
X	i = 0;
X	do {
X		out = popen(buf, "w");
X		if (out) break;
X		/*
X		 * Fork failed.  System probably overloaded.
X		 * Wait awhile and try again 10 times.
X		 * If it keeps failing, probably some
X		 * other problem, like no uux or smail.
X		 */
X		(void) sleep(60);
X	} while (++i < 10);
X
X	if(out == NULL) {
X		(void) printf("couldn't execute %s.\n", buf);
X		return;
X	}
X
X	(void) fprintf(out, "Date: %s\n", arpanows);
X	(void) fprintf(out, "From: MAILER-DAEMON@%s\n", hostdomain);
X	(void) fprintf(out, "Subject: failed mail\n");
X	(void) fprintf(out, "To: %s\n", from);
X	(void) fprintf(out, "\n");
X	(void) fprintf(out, "=======     command failed      =======\n\n");
X	(void) fprintf(out, " COMMAND: %s\n\n", fcommand);
X
X	(void) fprintf(out, "======= standard error follows  =======\n");
X	(void) fflush(stderr);
X	if((fp = fopen(stderrfile, "r")) != NULL) {
X		while(fgets(buf, sizeof(buf), fp) != NULL) {
X			(void) fputs(buf, out);
X		}
X	}
X	(void) fclose(fp);
X	(void) fprintf(out, "======= text of message follows =======\n");
X/*
X**  Copy input.
X*/
X	(void) fprintf(out, "From %s\n", from);
X	while(fgets(buf, sizeof(buf), spoolfp) != NULL) {
X		(void) fputs(buf, out);
X	}
X	(void) pclose(out);
X}
SHAR_EOF
if test 12233 -ne `wc -c < 'deliver.c'`
then
	echo 'shar: error transmitting "deliver.c" (should have been 12233 characters) '
fi
chmod 664 'deliver.c'
fi  # end of overwriting check
#	End of shell archive
exit 0
-- 
Chip Salzenberg         "chip@ateng.UUCP"  or  "{codas,uunet}!ateng!chip"
A T Engineering         My employer's opinions are not mine, but these are.
   "Gentlemen, your work today has been outstanding.  I intend to recommend
   you all for promotion -- in whatever fleet we end up serving."   - JTK