Deliver 1.00 (patchlevel 8) Part 3/3

Chip Salzenberg chip at ateng.ateng.com
Fri Feb 24 02:48:11 AEST 1989


#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of shell archive."
# Contents:  main.c mbox.c procs.c subs.c sysdep.c uucp.c
# Wrapped by network at ateng on Wed Feb 15 20:36:33 1989
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'main.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'main.c'\"
else
echo shar: Extracting \"'main.c'\" \(13643 characters\)
sed "s/^X//" >'main.c' <<'END_OF_FILE'
X/* $Header: main.c,v 1.11 89/02/15 19:11:25 network Exp $
X *
X * A program to deliver local mail with some flexibility.
X *
X * $Log:	main.c,v $
X * Revision 1.11  89/02/15  19:11:25  network
X * Provide second system-wide delivery file, executed after user delivery
X * files but before any deliveries take place.  Useful for implementing
X * system-wide aliases.
X * Also, fix bug in do_dfile() that caused infinite loops if delivery files
X * output any lines containing white space. (!)
X * 
X * Revision 1.10  89/02/10  15:46:59  network
X * V7 support.
X * 
X * Revision 1.9  88/11/28  18:08:03  network
X * patch5: Copy temp files before handing them to delivery files.
X * patch5: Introduce "uid" program.
X * 
X * Revision 1.8  88/11/26  13:20:51  network
X * patch4: Add return type of signal handlers to config.h.
X * patch4: Provide a version of getopt() for systems that lack it.
X * patch4: Call va_end() in routines that use varargs.
X * patch4: Make consistent checks for valid address strings.
X * 
X * Revision 1.7  88/11/18  12:17:17  network
X * patch2: Improved signal handling.
X * patch2: Make sure all environment variables are always provided.
X * patch2: Some users can be trusted to specify delivery files.
X * 
X * Revision 1.6  88/10/13  12:19:27  network
X * patch1: add "-n" option, and general bug fixes.
X * 
X * Revision 1.5  88/09/14  20:00:03  network
X * Add version string, including patchlevel.
X * 
X * Revision 1.4  88/09/14  19:41:54  network
X * Portability to System V and BSD.
X * General fixup.
X * 
X * Revision 1.3  88/08/30  16:13:54  network
X * Remove general subroutines to new module, subs.c.
X * 
X * Revision 1.2  88/08/25  15:29:59  network
X * Implement -s and -u options and ENV_SYSDEL and ENV_USERDEL environment
X * variables.  Tighten up control over effective and real uid/gid.
X * In particular, renounce setuid privileges if the system or user delivery
X * file is specified.
X * 
X * Revision 1.1  88/06/06  09:38:54  chip
X * Initial revision
X * 
X */
X
X#include "deliver.h"
X#include "patchlevel.h"
X#include <signal.h>
X
X/*
X * External data.
X */
X
X/* Variables set by getopt() [blech] */
X
Xextern  int     optind, opterr;
Xextern  char    *optarg;
X
X/*
X * Local data
X */
X
Xstatic  char    sys_dfl[] = SYS_DELIVER;
Xstatic  char    post_dfl[] = POST_DELIVER;
Xstatic  char    user_dfl[] = USER_DELIVER;
X
X/*
X * Global data
X */
X
Xint     verbose         = FALSE;
Xint     dryrun          = FALSE;
Xint     rundfiles       = TRUE;
Xint     printaddrs      = FALSE;
Xint     leavetemps      = FALSE;
Xint     boxdelivery     = FALSE;
X
Xchar    *progname       = "deliver";
Xchar    version[32]     = "1.0";
Xchar    *shell          = SHELL;
X
Xchar    *sys_deliver    = sys_dfl;
Xchar    *post_deliver   = post_dfl;
Xchar    *user_deliver   = user_dfl;
Xchar    *sender         = NULL;
Xchar    *hostname       = NULL;
X
Xint     eff_uid         = -1;
Xint     eff_gid         = -1;
Xint     real_uid        = -1;
Xint     real_gid        = -1;
X
XCONTEXT *eff_ct         = NULL;
XCONTEXT *real_ct        = NULL;
X
Xint     tty_input       = FALSE;
XSIGFLAG got_sig         = FALSE;
X
Xint     trust_user      = FALSE;
Xint     trust_delfiles  = FALSE;
X
Xchar    *ttype[T_MAX]   = { "header", "body", "header copy", "body copy" };
Xchar    *tfile[T_MAX]   = { NULL, NULL, NULL, NULL };
Xchar    *tenv[T_MAX]    = { NULL, NULL, ENV_HEADER, ENV_BODY };
Xint     tfd[T_MAX]      = { -1, -1, -1, -1 };
X
X/*
X * Local functions.
X */
X
Xstatic  SIGTYPE sighup(), sigint(), sigquit();
X
X/*----------------------------------------------------------------------
X * The Program.
X */
X
Xmain(argc, argv)
Xint     argc;
Xchar    **argv;
X{
X	char    *p;
X	int     u, c, errcount, copy;
X
X	/* Make sure that stdout and stderr are interleaved correctly */
X
X	Linebuf(stdout);
X	Linebuf(stderr);
X
X	/* Figure out the name used to invoke this program. */
X
X	progname = basename(argv[0]);
X
X	/* What version of the program is this? */
X
X	(void) sprintf(version + strlen(version), ".%02d", PATCHLEVEL);
X
X	/* Figure out the name of this host */
X
X	if ((hostname = gethost()) == NULL)
X	{
X		hostname = "unknown";
X		error("unable to determine host name; using \"%s\"\n",
X		      hostname);
X	}
X
X	/* Find effective and real uids and gids. */
X
X	eff_uid = geteuid();
X	eff_gid = getegid();
X	real_uid = getuid();
X	real_gid = getgid();
X
X	if (eff_uid != real_uid && eff_uid != 0)
X	{
X		error("if setuid, must be setuid root\n");
X		leave(1);
X	}
X
X	/* Process environment: handle recursive invocation */
X
X	if ((p = getenv(ENV_DFLAGS)) != NULL)
X	{
X		while (*p)
X		{
X			switch (*p++)
X			{
X			case 'v':
X				verbose = TRUE;
X				break;
X			case 'd':
X				verbose = TRUE;
X				dryrun = TRUE;
X				break;
X			case 'A':
X				printaddrs = TRUE;
X				dryrun = TRUE;
X				break;
X			case 'n':
X				rundfiles = FALSE;
X				break;
X			case 't':
X				leavetemps = TRUE;
X				break;
X			}
X		}
X	}
X
X	if ((p = getenv(ENV_SYSDEL)) != NULL && *p)
X		sys_deliver = p;
X	if ((p = getenv(ENV_POSTDEL)) != NULL && *p)
X		post_deliver = p;
X	if ((p = getenv(ENV_USERDEL)) != NULL && *p)
X		user_deliver = p;
X	if ((p = getenv(ENV_SENDER)) != NULL && *p)
X		sender = p;
X	if ((p = getenv(ENV_HOSTNAME)) != NULL && *p)
X		hostname = p;
X
X	/* Parse command line arguments */
X
X	while ((c = getopt(argc, argv, "vdAntbs:p:u:r:h:")) != EOF)
X	{
X		switch (c)
X		{
X		case 'v':
X			verbose = TRUE;
X			break;
X		case 'd':
X			verbose = TRUE;
X			dryrun = TRUE;
X			break;
X		case 'A':
X			printaddrs = TRUE;
X			dryrun = TRUE;
X			break;
X		case 'n':
X			rundfiles = FALSE;
X			break;
X		case 't':
X			leavetemps = TRUE;
X			break;
X		case 'b':
X			boxdelivery = TRUE;
X			break;
X		case 's':
X			if (*optarg)
X				sys_deliver = optarg;
X			break;
X		case 'p':
X			if (*optarg)
X				post_deliver = optarg;
X			break;
X		case 'u':
X			if (*optarg)
X				user_deliver = optarg;
X			break;
X		case 'r':
X			if (*optarg)
X				sender = optarg;
X			break;
X		case 'h':
X			if (*optarg)
X				hostname = optarg;
X			break;
X		case '?':
X			usage();
X		}
X	}
X
X	/* If no destinations were given, forget it. */
X
X	if (optind >= argc)
X	{
X		error("no recipients specified\n");
X		usage();
X	}
X
X	/* Print a debugging message */
X
X	if (verbose)
X	{
X		message("%s %s running on host %s\n",
X			progname, version, hostname);
X	}
X
X	/* Do we trust our caller? */
X
X	if (trusted_uid(real_uid))
X		trust_user = TRUE;
X
X	/* Do we trust our delivery files? */
X
X	if (strcmp(sys_dfl, sys_deliver) == 0
X	 && strcmp(post_dfl, post_deliver) == 0
X	 && strcmp(user_dfl, user_deliver) == 0)
X		trust_delfiles = TRUE;
X
X	/* Renounce special privileges if something insecure was requested. */
X
X	if (!trust_user && !trust_delfiles)
X	{
X		if (setgid(eff_gid = real_gid) == -1
X		 || setuid(eff_uid = real_uid) == -1)
X		{
X			syserr("can't renounce setuid privileges");
X			leave(1);
X		}
X	}
X
X	/* Get the contexts of our effective and real uids. */
X
X	if ((eff_ct = uid_context(eff_uid)) == NULL)
X		error("invalid effective uid %d!?\n", eff_uid);
X
X	if ((real_ct = uid_context(real_uid)) == NULL)
X		error("invalid real uid %d!?\n", real_uid);
X
X	if (!eff_ct || !real_ct)
X		leave(1);
X
X	if (verbose)
X	{
X		message("effective uid = %s (%d/%d); real uid = %s (%d/%d)\n",
X			eff_ct->ct_name, eff_ct->ct_uid, eff_ct->ct_gid,
X			real_ct->ct_name, real_ct->ct_uid, real_ct->ct_gid);
X	}
X
X	/* Let's be sane about the file creation mask. */
X
X	u = umask(0);
X	u &= ~0700;     /* Let's not deprive ourselves of permissions.  */
X	u |= 022;       /* Let's be reasonably paranoid about writing.  */
X	(void) umask(u);
X
X	/*
X	 * Where is the message coming from?
X	 */
X
X	if (isatty(0))
X		tty_input = TRUE;
X
X	/*
X	 * If we are not going to deliver, or if we are receiving the
X	 * message from a tty, catch signals so we can remove temp files.
X	 * Otherwise, ignore signals.
X	 */
X
X	if (dryrun || tty_input)
X		catch_sigs();
X	else
X		ignore_sigs();
X
X	/*
X	 * Create the temporary files and write the message to them.
X	 */
X
X	copy = copy_message();
X
X	/*
X	 * No more signals...
X	 */
X
X	ignore_sigs();
X
X	/*
X	 * ... but if we had already caught a signal,
X	 *     or if copy_msg() had a problem, leave.
X	 */
X
X	if ((copy < 0) || got_sig)
X	{
X		if (got_sig)
X			error("caught signal - exiting\n");
X		leave(1);
X	}
X
X	/*
X	 * Set up useful environment variables.
X	 * Note that this must be done _after_ copy_message(),
X	 * since that's where the temp files are created.
X	 */
X
X	setup_environ();
X
X	/*
X	 * Perhaps we should consider all arguments as mailbox names...
X	 */
X
X	if (boxdelivery)
X	{
X		int     a;
X
X		if (verbose)
X			message("mailbox delivery as %s\n", real_ct->ct_name);
X
X		/*
X		 * Consider all arguments as mailbox filenames.
X		 */
X
X		for (a = optind; a < argc; ++a)
X			(void) dest(real_ct->ct_name, argv[a]);
X
X		if (verbose)
X			dumpdests("(should all be mailboxes)");
X	}
X
X	/*
X	 * They're not mailbox names, so they should be mail addresses.
X	 */
X
X	else
X	{
X		/* Run all destinations though the system delivery file. */
X
X		if (sys_dfile(argc - optind, argv + optind) >= 0)
X		{
X			if (verbose)
X				dumpdests("after running system delivery file");
X		}
X		else
X		{
X			int     a;
X
X			/*
X			 * System delivery file is missing or ignored.
X			 * Use the argument list verbatim.
X			 */
X
X			for (a = optind; a < argc; ++a)
X				(void) dest(argv[a], (char *) NULL);
X
X			if (verbose)
X				dumpdests("as taken from argument list");
X		}
X
X		/*
X		 * Run each user destination through his delivery file.
X		 */
X
X		if (user_dfiles() >= 0)
X		{
X			if (verbose)
X				dumpdests("after running user delivery files");
X		}
X
X		/*
X		 * Run each remaining destination though the post-user
X		 * delivery file.
X		 */
X
X		if (post_dfile() >= 0)
X		{
X			if (verbose)
X				dumpdests("after running post-user delivery file");
X		}
X	}
X
X	/*
X	 * Drop mail in mailbox(es).
X	 */
X
X	mbox_deliver();
X
X	if (verbose)
X		dumpdests("after delivery to all mailboxes");
X
X	/*
X	 * Send mail to UUCP address(es).
X	 */
X
X	uucp_deliver();
X
X	if (verbose)
X		dumpdests("after delivery to UUCP addresses");
X
X	/*
X	 * Report any errors, and leave.
X	 */
X
X	errcount = report_errors();
X
X	/*
X	 * All done.
X	 */
X
X	leave(errcount ? 1 : 0);
X	/* NOTREACHED */
X}
X
X/*----------------------------------------------------------------------
X * Print a usage message and exit.
X */
X
Xusage()
X{
X	message("Usage: %s [-b][-A][-d][-v][-n][-t][-r from][-h host] args\n", progname);
X	message("-b       All arguments are mailbox filenames.\n");
X	message("         (Default: arguments are user names.)\n");
X	message("-A       Resolve addresses but do not deliver.\n");
X	message("-d       Be verbose but do not deliver.\n");
X	message("-v       Be verbose and deliver.\n");
X	message("-n       Do not run any delivery files.\n");
X	message("-t       Do not remote temp files before exiting.\n");
X	message("-s file  Specify the system delivery filename.\n");
X	message("-p file  Specify the post-user delivery filename.\n");
X	message("-u file  Specify the user delivery filename.\n");
X	message("-r from  Specify the address to appear in the \"From \" line.\n");
X	message("-h host  Specify the host name.\n");
X	message("args     Either user addresses or mailboxes (-b).\n");
X	leave(1);
X}
X
X/*----------------------------------------------------------------------
X * Clean up and exit.
X */
X
Xleave(code)
Xint     code;
X{
X	if (! leavetemps)
X	{
X		int     t;
X
X		for (t = 0; t < T_MAX; ++t)
X		{
X			if (tfd[t] != -1)
X				(void) close(tfd[t]);
X			if (tfile[t] && unlink(tfile[t]) == -1)
X				syserr("can't unlink %s", tfile[t]);
X		}
X	}
X
X	exit(code);
X}
X
X/*----------------------------------------------------------------------
X * Catch signals.
X */
X
Xcatch_sigs()
X{
X	if (signal(SIGHUP, SIG_IGN) != SIG_IGN)
X		(void) signal(SIGHUP, sighup);
X	if (signal(SIGINT, SIG_IGN) != SIG_IGN)
X		(void) signal(SIGINT, sigint);
X	if (signal(SIGQUIT, SIG_IGN) != SIG_IGN)
X		(void) signal(SIGQUIT, sigquit);
X}
X
X/*----------------------------------------------------------------------
X * Ignore signals.
X */
X
Xignore_sigs()
X{
X	(void) signal(SIGHUP, SIG_IGN);
X	(void) signal(SIGINT, SIG_IGN);
X	(void) signal(SIGQUIT, SIG_IGN);
X}
X
Xstatic SIGTYPE
Xsighup()
X{
X	(void) signal(SIGHUP, sighup);
X	got_sig = TRUE;
X}
X
Xstatic SIGTYPE
Xsigint()
X{
X	(void) signal(SIGINT, sigint);
X	got_sig = TRUE;
X}
X
Xstatic SIGTYPE
Xsigquit()
X{
X	(void) signal(SIGQUIT, sigquit);
X	got_sig = TRUE;
X}
X
X/*----------------------------------------------------------------------
X * Report any errors to stderr.
X * Return an error count.
X */
X
Xint
Xreport_errors()
X{
X	DEST    *d;
X	int     count = 0;
X
X	for (d = first_dest(); d; d = next_dest(d))
X	{
X		if (d->d_state != ST_ERROR)
X			continue;
X
X		if (++count == 1)
X		{
X			error(
X		    "delivery to the following address(es) failed on host %s\n",
X				hostname);
X		}
X
X		message("\t\"%s\"", d->d_name);
X		if (d->d_class == CL_MBOX)
X			message(", mailbox \"%s\"", d->d_mailbox);
X		message(": %s\n", derrmsg(d->d_error));
X	}
X
X	return count;
X}
X
X/*----------------------------------------------------------------------
X * Is the given uid trusted?
X */
X
Xint
Xtrusted_uid(uid)
Xint     uid;
X{
X	CONTEXT *ct;
X	char    **n;
X	static char *t[] = { TRUSTED_USERS, 0 };
X
X	for (n = t; *n; ++n)
X	{
X		if ((ct = name_context(*n)) != NULL && uid == ct->ct_uid)
X			return TRUE;
X	}
X
X	return FALSE;
X}
X
X/*----------------------------------------------------------------------
X * Set up useful environment variables.
X */
X
Xsetup_environ()
X{
X	char    flags[8];
X	int     f = 0;
X
X	flags[f++] = '-';
X	if (verbose)
X		flags[f++] = (dryrun ? 'd' : 'v');
X	if (printaddrs)
X		flags[f++] = 'A';
X	if (leavetemps)
X		flags[f++] = 't';
X	flags[f] = 0;
X
X	alloc_env(ENV_DFLAGS, (f > 1) ? flags : "");
X	if (sys_deliver && *sys_deliver)
X		alloc_env(ENV_SYSDEL, sys_deliver);
X	if (user_deliver && *user_deliver)
X		alloc_env(ENV_USERDEL, user_deliver);
X	if (hostname && *hostname)
X		alloc_env(ENV_HOSTNAME, hostname);
X	if (sender && *sender)
X		alloc_env(ENV_SENDER, sender);
X
X	alloc_env("IFS", " \t\n");
X}
END_OF_FILE
if test 13643 -ne `wc -c <'main.c'`; then
    echo shar: \"'main.c'\" unpacked with wrong size!
fi
# end of 'main.c'
fi
if test -f 'mbox.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'mbox.c'\"
else
echo shar: Extracting \"'mbox.c'\" \(4621 characters\)
sed "s/^X//" >'mbox.c' <<'END_OF_FILE'
X/* $Header: mbox.c,v 1.4 89/02/10 15:47:10 network Exp $
X *
X * Finally!  Put the message in the specified mailbox(es).
X *
X * $Log:	mbox.c,v $
X * Revision 1.4  89/02/10  15:47:10  network
X * V7 support.
X * 
X * Revision 1.3  88/11/28  18:08:13  network
X * patch5: Copy temp files before handing them to delivery files.
X * patch5: Introduce "uid" program.
X * 
X * Revision 1.2  88/09/14  19:42:06  network
X * Portability to System V and BSD.
X * General fixup.
X * 
X * Revision 1.1  88/06/06  09:39:06  chip
X * Initial revision
X * 
X */
X
X#include "deliver.h"
X#include <sys/types.h>
X#include <sys/stat.h>
X#include <errno.h>
X
X/*
X * External data.
X */
X
Xextern  int     errno;
X
X/*
X * Local functions.
X */
X
Xstatic          mbox_one();
Xstatic  int     mbox_write();
X
X/*----------------------------------------------------------------------
X * Deliver mail to all valid destinations.
X */
X
Xmbox_deliver()
X{
X	DEST    *d;
X
X	for (d = first_dest(); d; d = next_dest(d))
X	{
X		switch (d->d_class)
X		{
X		case CL_USER:
X		case CL_MBOX:
X			if (d->d_state == ST_WORKING)
X				mbox_one(d);
X			break;
X		}
X	}
X}
X
X/*----------------------------------------------------------------------
X * Deliver mail to one destination.
X */
X
Xstatic
Xmbox_one(d)
XDEST    *d;
X{
X	CONTEXT *ct;
X	int     ret = 0;
X
X	if (printaddrs)
X	{
X		(void) printf("%s", d->d_name);
X		if (d->d_class == CL_MBOX)
X			(void) printf(":%s", d->d_mailbox);
X		(void) printf("\n");
X	}
X
X	if (dryrun)
X	{
X		d->d_state = ST_DONE;
X		return;
X	}
X
X	if ((ct = name_context(d->d_name)) == NULL)
X	{
X		dest_err(d, E_CTLOST);
X		return;
X	}
X
X	if (! ok_context(ct))
X	{
X		dest_err(d, E_CTPERM);
X		return;
X	}
X
X	if (d->d_class == CL_MBOX)
X	{
X		if (sfork() == 0)
X		{
X			if (become(ct, !boxdelivery) < 0)
X				exit(1);
X			if (mbox_write(d->d_mailbox, ct, FALSE) < 0)
X				exit(1);
X			exit(0);
X		}
X
X		if (await_child() != 0)
X			ret = -1;
X	}
X	else
X	{
X		char    mailbox[100];
X
X		(void) sprintf(mailbox, "%s/%s",
X#ifdef MBX_DIR
X			MBX_DIR, d->d_name
X#else
X			d->d_home, MBX_NAME
X#endif
X			);
X
X		if (mbox_write(mailbox, ct, TRUE) < 0)
X			ret = -1;
X	}
X
X	if (ret >= 0)
X		d->d_state = ST_DONE;
X	else
X		dest_err(d, E_MBOX);
X}
X
X/*----------------------------------------------------------------------
X * Write mail to the named mailbox.
X * If we have to create the mailbox, give it to the specified user.
X * If "is_sys" is true, then we're writing to a system mailbox.
X */
X
Xstatic int
Xmbox_write(mailbox, ct, is_sys)
Xchar    *mailbox;
XCONTEXT *ct;
Xint     is_sys;
X{
X	struct stat st;
X	int     fd, t, mbox_uid, mbox_gid;
X	int     ret = 0;
X
X	if (verbose)
X	{
X		message("As %s, delivering to %s mailbox %s\n",
X			ct->ct_name, (is_sys ? "system" : "user"), mailbox);
X	}
X
X	if (name_lock(mailbox) < 0)
X		return -1;
X
X	while ((fd = open(mailbox, O_WRONLY)) == -1)
X	{
X		if (errno != ENOENT)
X		{
X			syserr("can't open %s", mailbox);
X			break;
X		}
X
X#ifdef O_CREAT
X		fd = open(mailbox, O_WRONLY|O_CREAT|O_EXCL, MBX_MODE);
X
X		/* If it exists now, try open() again. */
X		if (fd == -1 && errno == EEXIST)
X			continue;
X#else
X		fd = creat(mailbox, MBX_MODE);
X#endif
X		if (fd == -1)
X		{
X			syserr("can't create %s", mailbox);
X			break;
X		}
X
X		/* Make sure the mailbox receives the correct modes */
X
X		mbox_uid = ct->ct_uid;
X		mbox_gid = ct->ct_gid;
X
X#ifdef MBX_GROUP
X		if (is_sys)
X		{
X			static int mbox_sv_gid = -2;
X
X			if (mbox_sv_gid == -2)
X				mbox_sv_gid = group_id(MBX_GROUP);
X
X			if (mbox_sv_gid < 0)
X				message("%s: no such group\n", MBX_GROUP);
X			else
X				mbox_gid = mbox_sv_gid;
X		}
X#endif /* MBX_GROUP */
X
X		if (fstat(fd, &st) == -1)
X		{
X			syserr("can't fstat open mailbox?!");
X			(void) close(fd);
X			fd = -1;
X			break;
X		}
X
X		/* Change mailbox ownership if it's not already correct. */
X
X		if ((st.st_uid != mbox_uid || st.st_gid != mbox_gid)
X		 && chown(mailbox, mbox_uid, mbox_gid) == -1)
X		{
X			/* print a message, but that's all. (???) */
X			syserr("can't chown %s to %d,%d",
X				mailbox, mbox_uid, mbox_gid);
X		}
X
X		/* It's open now, so we can stop looping now. */
X
X		break;
X	}
X
X	if (fd == -1)
X	{
X		(void) name_unlock(mailbox);
X		return -1;
X	}
X
X	if (fd_lock(fd) < 0)
X	{
X		(void) close(fd);
X		(void) name_unlock(mailbox);
X		return -1;
X	}
X
X	(void) lseek(fd, 0L, 2); /* No error check: may be a special file */
X
X	for (t = T_HDR; t <= T_BODY; ++t)
X	{
X		if (lseek(tfd[t], 0L, 0) == -1)
X		{
X			syserr("lseek in %s file %s", ttype[t], tfile[t]);
X			ret = -1;
X			break;
X		}
X
X		if (copyfd(tfd[t], fd) < 0)
X		{
X			ret = -1;
X			break;
X		}
X	}
X
X	if (verbose)
X	{
X		if (ret >= 0)
X			message("wrote message to %s\n", mailbox);
X	}
X
X	if (fd_unlock(fd) < 0)
X		ret = -1;
X	(void) close(fd);
X	if (name_unlock(mailbox) < 0)
X		ret = -1;
X
X	return ret;
X}
END_OF_FILE
if test 4621 -ne `wc -c <'mbox.c'`; then
    echo shar: \"'mbox.c'\" unpacked with wrong size!
fi
# end of 'mbox.c'
fi
if test -f 'procs.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'procs.c'\"
else
echo shar: Extracting \"'procs.c'\" \(5411 characters\)
sed "s/^X//" >'procs.c' <<'END_OF_FILE'
X/* $Header: procs.c,v 1.4 89/02/10 15:47:31 network Exp $
X *
X * Process management and misc support.
X *
X * $Log:	procs.c,v $
X * Revision 1.4  89/02/10  15:47:31  network
X * V7 support.
X * 
X * Revision 1.3  88/11/26  13:21:07  network
X * patch4: Add return type of signal handlers to config.h.
X * patch4: Provide a version of getopt() for systems that lack it.
X * patch4: Call va_end() in routines that use varargs.
X * patch4: Make consistent checks for valid address strings.
X * 
X * Revision 1.2  88/09/14  19:42:28  network
X * Portability to System V and BSD.
X * General fixup.
X * 
X * Revision 1.1  88/06/06  09:39:15  chip
X * Initial revision
X * 
X */
X
X#include "deliver.h"
X#include <errno.h>
X#include <signal.h>
X
X/*
X * External data.
X */
X
Xextern  int     errno;
X
X/*
X * Local data.
X */
X
Xstatic  int     child_pid = -1;
Xstatic  SIGTYPE (*saved_sigpipe)() = SIG_DFL;
X
X/*----------------------------------------------------------------------
X * Like popen(), but execute the child in a specific context.
X * Also, the argument list is already a vector.
X */
X
XFILE *
Xct_popenv(ct, prog, av, mode)
XCONTEXT *ct;
Xchar    *prog;
Xchar    **av;
Xchar    *mode;
X{
X	char    ch;
X	int     child, parent;
X	int     pfd[2];
X
X	if (!ct || !prog || !av || !mode)
X		return NULL;
X
X	if (mode[0] == 'r' && mode[1] == 0)
X		child = 1, parent = 0;
X	else if (mode[0] == 'w' && mode[1] == 0)
X		child = 0, parent = 1;
X	else
X		return NULL;
X
X	/* We can't have more than one child at a time. */
X
X	if (child_pid >= 0)
X	{
X		error("in ct_popen: a process is already open\n");
X		return NULL;
X	}
X
X	/* Make a stab at predicting uid-related failure. */
X
X	if (! ok_context(ct))
X	{
X		error("in ct_popen: no permissions to become %s\n",
X		      ct->ct_name);
X		return NULL;
X	}
X
X	/* Pipes?  Like, tubular, fer shur! */
X
X	if (pipe(pfd) == -1)
X	{
X		syserr("can't create a pipe");
X		return NULL;
X	}
X
X	/* Generate a debugging message. */
X
X	if (verbose)
X	{
X		int a;
X
X		message("Spawning");
X		for (a = 0; av[a]; ++a)
X			message(" %s", av[a]);
X		message("\n");
X	}
X
X	/* Handle the child case */
X
X	if (sfork() == 0)
X	{
X		if (child == 0)
X		{
X			(void) close(0);
X			(void) dup(pfd[0]);     /* ass_u_me 0 */
X		}
X		else
X		{
X			(void) close(0);
X			if (open("/dev/null", O_RDONLY) != 0)
X			{
X				/* This should _never_ happen, but... */
X				syserr("can't open /dev/null");
X				(void) dup(1);  /* ass_u_me 0 */
X			}
X
X			(void) close(1);
X			(void) dup(pfd[1]);     /* ass_u_me 1 */
X		}
X
X		if (become(ct, TRUE) < 0)
X			(void) write(pfd[1], "n", 1);
X		else
X		{
X			int     t;
X
X			(void) write(pfd[1], "y", 1);
X
X			(void) close(pfd[child]);
X			(void) close(pfd[parent]);
X			for (t = 0; t < T_MAX; ++t)
X				(void) close(tfd[t]);
X
X			(void) execv(prog, av);
X			syserr("can't execute %s", prog);
X		}
X
X		exit(127);
X	}
X
X	/* Make sure that a broken pipe won't kill us */
X
X	saved_sigpipe = signal(SIGPIPE, SIG_IGN);
X
X	/* The child must report "OK" before we continue. */
X
X	if ((read(pfd[0], &ch, 1) < 1) || (ch != 'y'))
X	{
X		(void) close(pfd[0]);
X		(void) close(pfd[1]);
X		(void) await_child();
X		return NULL;
X	}
X
X	(void) close(pfd[child]);
X	return fdopen(pfd[parent], mode);
X}
X
X/*----------------------------------------------------------------------
X * Close the stream opened by ct_popen().
X */
X
Xct_pclose(fp)
XFILE    *fp;
X{
X	if (fp)
X		(void) fclose(fp);
X	return await_child();
X}
X
X/*----------------------------------------------------------------------
X * Assume the identity of the given user.
X */
X
Xint
Xbecome(ct, chd)
XCONTEXT *ct;
Xint     chd;
X{
X	char    env_path[32];
X
X	/*
X	 * Assume a new identity.
X	 * Note the importance of doing the setgid() before the setuid().
X	 */
X
X	if (setgid(ct->ct_gid) == -1)
X	{
X		syserr("can't setgid to %d", ct->ct_gid);
X		return -1;
X	}
X	if (setuid(ct->ct_uid) == -1)
X	{
X		syserr("can't setgid to %u", ct->ct_uid);
X		return -1;
X	}
X	if (chd && chdir(ct->ct_home) == -1)
X	{
X		syserr("can't chdir to %s", ct->ct_home);
X		return -1;
X	}
X
X	/* Set up the environment */
X
X	(void) sprintf(env_path, "%s:/bin:/usr/bin",
X			((ct->ct_uid == 0) ? "/etc" : "."));
X	alloc_env("HOME", ct->ct_home);
X	alloc_env("PATH", env_path);
X
X	/* I guess it worked. */
X
X	return 0;
X}
X
X/*----------------------------------------------------------------------
X * Safe fork.  If it doesn't work, it exits.
X */
X
Xint
Xsfork()
X{
X	int     tries;
X
X	/*
X	 * A few safety measures.
X	 */
X
X	(void) await_child();
X	(void) fflush(stdout);
X	(void) fflush(stderr);
X
X	/*
X	 * Be patient in waiting for a fork().
X	 */
X
X	for (tries = 0; tries < 10; ++tries)
X	{
X		if (tries)
X			snooze(3);
X		if ((child_pid = fork()) >= 0)
X			return child_pid;
X		if (errno != EAGAIN)
X			break;
X	}
X
X	syserr("can't fork");
X	leave(1);
X	/* NOTREACHED */
X}
X
X/*----------------------------------------------------------------------
X * Wait for our child (if any) to exit.
X * Returns child's exit status or -1 if there is a problem.
X */
X
Xint
Xawait_child()
X{
X	int     wpid, st;
X
X	if (child_pid < 0)
X		return -1;
X
X	while ((wpid = wait(&st)) >= 0)
X	{
X		if (wpid == child_pid)
X			break;
X	}
X
X	child_pid = -1;
X	if (wpid == -1)
X		syserr("waiting for child");
X
X	(void) signal(SIGPIPE, saved_sigpipe);
X	saved_sigpipe = SIG_DFL;
X
X	if (wpid == -1)
X		return -1;
X
X	if (st & 0xFF)
X	{
X		error("child process died%s due to signal %d.\n",
X			((st & 0x80) ? " and dumped core" : ""),
X			(st & 0x7F));
X
X		return -1;
X	}
X
X	if (verbose)
X	{
X		message("child process exited with status %d.\n",
X			(st >> 8) & 0xFF);
X	}
X
X	return ((st >> 8) & 0xFF);
X}
END_OF_FILE
if test 5411 -ne `wc -c <'procs.c'`; then
    echo shar: \"'procs.c'\" unpacked with wrong size!
fi
# end of 'procs.c'
fi
if test -f 'subs.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'subs.c'\"
else
echo shar: Extracting \"'subs.c'\" \(2775 characters\)
sed "s/^X//" >'subs.c' <<'END_OF_FILE'
X/* $Header: subs.c,v 1.6 89/02/10 15:47:40 network Exp $
X *
X * Miscellaneous subroutines.
X *
X * $Log:	subs.c,v $
X * Revision 1.6  89/02/10  15:47:40  network
X * V7 support.
X * 
X * Revision 1.5  88/11/26  13:21:11  network
X * patch4: Add return type of signal handlers to config.h.
X * patch4: Provide a version of getopt() for systems that lack it.
X * patch4: Call va_end() in routines that use varargs.
X * patch4: Make consistent checks for valid address strings.
X * 
X * Revision 1.4  88/10/13  12:20:34  network
X * patch1: add "-n" option, and general bug fixes.
X * 
X * Revision 1.3  88/09/14  19:42:33  network
X * Portability to System V and BSD.
X * General fixup.
X * 
X * Revision 1.2  88/08/30  16:14:53  network
X * New module.  Includes routines from main.c.
X * Also, new routine savestr().
X * 
X */
X
X#include "deliver.h"
X
X/*----------------------------------------------------------------------
X * Allocate memory for an environment variable, and putenv() it.
X */
X
Xalloc_env(name, value)
Xchar    *name;
Xchar    *value;
X{
X	char    *s;
X
X	if (!name || !value)
X		return;
X
X	s = zalloc((unsigned) (strlen(name) + strlen(value) + 2));
X	(void) sprintf(s, "%s=%s", name, value);
X	if (putenv(s))
X		nomem();
X}
X
X/*----------------------------------------------------------------------
X * Allocate and clear.  If it fails, it takes the emergency exit.
X */
X
Xchar *
Xzalloc(size)
Xunsigned size;
X{
X	char    *p;
X
X	if ((p = malloc(size)) == NULL)
X		nomem();
X
X	Zero(p, size);
X	return p;
X}
X
X/*----------------------------------------------------------------------
X * Reallocate to new size.  If it fails, it takes the emergency exit.
X */
X
Xchar *
Xsrealloc(ptr, size)
Xchar    *ptr;
Xunsigned size;
X{
X	char    *p;
X
X	if ((p = realloc(ptr, size)) == NULL)
X		nomem();
X
X	return p;
X}
X
X/*----------------------------------------------------------------------
X * Make an allocated copy of a string.
X */
X
Xchar *
Xcopystr(s)
Xchar    *s;
X{
X	char    *p;
X
X	if (s == NULL)
X		return NULL;
X
X	if ((p = malloc((unsigned) strlen(s) + 1)) == NULL)
X		nomem();
X
X	(void) strcpy(p, s);
X	return p;
X}
X
X/*----------------------------------------------------------------------
X * Emergency exit for memory loss.
X */
X
Xnomem()
X{
X	error("out of memory\n");
X	leave(1);
X}
X
X/*----------------------------------------------------------------------
X * Return the last component of the given pathname.
X */
X
Xchar *
Xbasename(name)
Xchar    *name;
X{
X	char    *b;
X
X	if ((b = strrchr(name, '/')) != NULL)
X		++b;
X	else
X		b = name;
X
X	return (b);
X}
X
X/*----------------------------------------------------------------------
X * Check an address for validity.
X */
X
Xvalid_address(addr)
Xchar    *addr;
X{
X	char    *p;
X	static char sanitize[] = SANITIZE;
X
X	for (p = addr; *p; ++p)
X	{
X		if (strchr(sanitize, *p))
X			return FALSE;
X	}
X
X	return TRUE;
X}
END_OF_FILE
if test 2775 -ne `wc -c <'subs.c'`; then
    echo shar: \"'subs.c'\" unpacked with wrong size!
fi
# end of 'subs.c'
fi
if test -f 'sysdep.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'sysdep.c'\"
else
echo shar: Extracting \"'sysdep.c'\" \(7306 characters\)
sed "s/^X//" >'sysdep.c' <<'END_OF_FILE'
X/* $Header: sysdep.c,v 1.7 89/02/10 15:47:44 network Exp $
X *
X * Routines which are (or might well be) system-dependant.
X * I've put the message routines here since you may need to use
X * the ANSI <stdarg.h> instead of <varargs.h>.
X *
X * $Log:	sysdep.c,v $
X * Revision 1.7  89/02/10  15:47:44  network
X * V7 support.
X * 
X * Revision 1.6  88/11/30  16:24:56  network
X * patch6:  Separate getopt() into its own module.
X * 
X * Revision 1.5  88/11/26  13:21:15  network
X * patch4: Add return type of signal handlers to config.h.
X * patch4: Provide a version of getopt() for systems that lack it.
X * patch4: Call va_end() in routines that use varargs.
X * patch4: Make consistent checks for valid address strings.
X * 
X * Revision 1.4  88/10/13  12:20:39  network
X * patch1: add "-n" option, and general bug fixes.
X * 
X * Revision 1.3  88/09/14  20:00:24  network
X * Fix type of gethostname() for BSD.
X * 
X * Revision 1.2  88/09/14  19:42:37  network
X * Portability to System V and BSD.
X * General fixup.
X * 
X * Revision 1.1  88/06/06  09:39:29  chip
X * Initial revision
X * 
X */
X
X#include "deliver.h"
X#include <errno.h>
X#ifdef HAS_STDARG
X#include <stdarg.h>
X#else
X#ifdef HAS_VARARGS
X#include <varargs.h>
X#else
X/*
X * Non-portable home-grown varargs.  Use at your own risk.
X * Especially note that if sizeof(int) > sizeof(short), then
X * "va_arg(..,short)" is broken.
X */
Xtypedef char *va_list;
X#define va_dcl          int va_alist;
X#define va_start(ap)    ap = (char *) &va_alist
X#define va_arg(ap,type) *(type *)(ap += sizeof(type), ap - sizeof(type))
X#define va_end(ap)      /* nothing */
X#endif
X#endif
X
X#ifdef UNAME
X#include <sys/utsname.h>
X#endif
X
X/*
X * External functions.
X */
X
X#ifdef M_XENIX
Xextern  long    nap();
X#else
Xextern  unsigned sleep();
X#endif
X
X/*
X * External data.
X */
X
Xextern  int     errno;
Xextern  int     sys_nerr;
Xextern  char    *sys_errlist[];
X
X/*----------------------------------------------------------------------
X * Print a message.
X */
X
X/* VARARGS */
X#ifdef HAS_STDARG
Xmessage(char *fmt, ...)
X#else
Xmessage(va_alist) va_dcl
X#endif
X{
X	va_list ap;
X
X#ifdef HAS_STDARG
X	va_start(ap, fmt);
X#else
X	char    *fmt;
X	va_start(ap);
X	fmt = va_arg(ap, char *);
X#endif
X
X	(void) vfprintf(stderr, fmt, ap);
X
X	va_end(ap);
X}
X
X/*----------------------------------------------------------------------
X * Print an error message.
X */
X
X/* VARARGS */
X#ifdef HAS_STDARG
Xerror(char *fmt, ...)
X#else
Xerror(va_alist) va_dcl
X#endif
X{
X	va_list ap;
X
X#ifdef HAS_STDARG
X	va_start(ap, fmt);
X#else
X	char    *fmt;
X	va_start(ap);
X	fmt = va_arg(ap, char *);
X#endif
X
X	(void) fprintf(stderr, "%s: ", progname);
X	(void) vfprintf(stderr, fmt, ap);
X
X	va_end(ap);
X}
X
X/*----------------------------------------------------------------------
X * Report an error returned from a system call.
X */
X
X/* VARARGS */
X#ifdef HAS_STDARG
Xsyserr(char *fmt, ...)
X#else
Xsyserr(va_alist) va_dcl
X#endif
X{
X	int     e = errno;
X	va_list ap;
X
X#ifdef HAS_STDARG
X	va_start(ap, fmt);
X#else
X	char    *fmt;
X	va_start(ap);
X	fmt = va_arg(ap, char *);
X#endif
X
X	(void) fprintf(stderr, "%s: ", progname);
X	(void) vfprintf(stderr, fmt, ap);
X	if (e <= sys_nerr)
X		(void) fprintf(stderr, ": %s\n", sys_errlist[e]);
X	else
X		(void) fprintf(stderr, ": unknown system error %d\n", e);
X
X	va_end(ap);
X}
X
X/*----------------------------------------------------------------------
X * Sleep for the given number of seconds.
X */
X
Xsnooze(n)
Xint     n;
X{
X#ifdef M_XENIX
X	(void) nap(n * 1000L);
X#else
X	(void) sleep(n);
X#endif
X}
X
X/*----------------------------------------------------------------------
X * Get the host name from HOSTFILE.
X */
X
X#ifdef HOSTFILE
X
Xchar *
Xgethost()
X{
X	int     fd, rd;
X	char    *p;
X	static char name[32];
X
X	if ((fd = open(HOSTFILE, O_RDONLY)) == -1)
X		return NULL;
X	rd = read(fd, name, sizeof(name) - 1);
X	(void) close(fd);
X
X	if (rd < 1)
X		return NULL;
X	name[rd] = 0;
X	if ((p = strchr(name, '\n')) != NULL)
X		*p = 0;
X
X	return (name[0] ? name : NULL);
X}
X
X#endif /* HOSTFILE */
X
X/*----------------------------------------------------------------------
X * Get the host name via the uname() system call.
X */
X
X#ifdef UNAME
X
Xchar *
Xgethost()
X{
X	static struct utsname u;
X
X	uname(&u);
X	return (u.nodename[0] ? u.nodename : NULL);
X}
X
X#endif /* UNAME */
X
X/*----------------------------------------------------------------------
X * Get the host name via the gethostname() system call.
X */
X
X#ifdef GETHOSTNAME
X
Xchar *
Xgethost()
X{
X	static char hostname[64];
X
X	if (gethostname(hostname, sizeof(hostname)) == -1)
X		return NULL;
X
X	return hostname;
X}
X
X#endif /* GETHOSTNAME */
X
X/*----------------------------------------------------------------------
X * Return a pre-defined HOSTNAME.
X */
X
X#ifdef HOSTNAME
X
Xchar *
Xgethost()
X{
X	return HOSTNAME;
X}
X
X#endif /* HOSTNAME */
X
X/*----------------------------------------------------------------------
X * Variable-argument-list output, System V style.
X */
X
X#ifndef HAS_VPRINTF
X
Xvprintf(fmt, ap)
Xchar    *fmt;
Xva_list ap;
X{
X	int     a,b,c,d,e,f,g,h;
X
X	a = va_arg(ap, int);
X	b = va_arg(ap, int);
X	c = va_arg(ap, int);
X	d = va_arg(ap, int);
X	e = va_arg(ap, int);
X	f = va_arg(ap, int);
X	g = va_arg(ap, int);
X	h = va_arg(ap, int);
X
X	(void) printf(fmt, a,b,c,d,e,f,g,h);
X}
X
Xvfprintf(fp, fmt, ap)
XFILE    *fp;
Xchar    *fmt;
Xva_list ap;
X{
X	int     a,b,c,d,e,f,g,h;
X
X	a = va_arg(ap, int);
X	b = va_arg(ap, int);
X	c = va_arg(ap, int);
X	d = va_arg(ap, int);
X	e = va_arg(ap, int);
X	f = va_arg(ap, int);
X	g = va_arg(ap, int);
X	h = va_arg(ap, int);
X
X	(void) fprintf(fp, fmt, a,b,c,d,e,f,g,h);
X}
X
Xvsprintf(s, fmt, ap)
Xchar    *s;
Xchar    *fmt;
Xva_list ap;
X{
X	int     a,b,c,d,e,f,g,h;
X
X	a = va_arg(ap, int);
X	b = va_arg(ap, int);
X	c = va_arg(ap, int);
X	d = va_arg(ap, int);
X	e = va_arg(ap, int);
X	f = va_arg(ap, int);
X	g = va_arg(ap, int);
X	h = va_arg(ap, int);
X
X	(void) sprintf(s, fmt, a,b,c,d,e,f,g,h);
X}
X
X#endif  /* !HAS_VPRINTF */
X
X/*----------------------------------------------------------------------
X * Add a new environment variable.
X */
X
X#ifndef HAS_PUTENV
X
Xint
Xputenv(s)
Xchar *s;
X{
X	static  char    **env_array;
X	static  int     env_size;
X	char    *e;
X	int     i, j;
X
X	if (env_array == NULL)
X	{
X		for (i = 0; environ[i]; ++i)
X			{}
X		env_size = i + 10;      /* arbitrary */
X		env_array = (char **) zalloc(env_size * sizeof(char *));
X		Copy((char *)env_array, (char *)environ,
X		     (int) ((i + 1) * sizeof(char *)));
X		environ = env_array;
X	}
X	else if (environ != env_array)
X		message("putenv: warning: someone moved environ!\n");
X
X	if ((e = strchr(s, '=')) != NULL)
X		++e;
X	else
X		e = s + strlen(s);
X
X	j = 0;
X	for (i = 0; env_array[i]; ++i)
X	{
X		if (strncmp(env_array[i], s, e - s) != 0)
X			env_array[j++] = env_array[i];
X	}
X
X	if ((j + 1) >= env_size)
X	{
X		env_size += 10;                 /* arbitrary */
X		env_array = (char **) srealloc((char *)env_array,
X					env_size * sizeof(char **));
X	}
X
X	env_array[j++] = s;
X	env_array[j] = NULL;
X
X	environ = env_array;
X	return 0;
X}
X
X#endif  /* !HAS_PUTENV */
X
X/*----------------------------------------------------------------------
X * Memory copy.
X */
X
X#ifdef MEMFUNCS
X
XCopy(dest, src, len)
Xchar    *dest;
Xchar    *src;
Xint     len;
X{
X	while (len-- > 0)
X		*dest++ = *src++;
X}
X
X#endif
X
X/*----------------------------------------------------------------------
X * Memory clear.
X */
X
X#ifdef MEMFUNCS
X
XZero(dest, len)
Xchar    *dest;
Xint     len;
X{
X	while (len-- > 0)
X		*dest++ = 0;
X}
X
X#endif
END_OF_FILE
if test 7306 -ne `wc -c <'sysdep.c'`; then
    echo shar: \"'sysdep.c'\" unpacked with wrong size!
fi
# end of 'sysdep.c'
fi
if test -f 'uucp.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'uucp.c'\"
else
echo shar: Extracting \"'uucp.c'\" \(3269 characters\)
sed "s/^X//" >'uucp.c' <<'END_OF_FILE'
X/* $Header: uucp.c,v 1.3 89/02/10 15:47:51 network Exp $
X *
X * Handle mail destined for other hosts via UUCP.
X * Deliver is intended as a very low-level program, so we don't
X * do anything fancy here.  We just hand the message to uux.
X *
X * $Log:	uucp.c,v $
X * Revision 1.3  89/02/10  15:47:51  network
X * V7 support.
X * 
X * Revision 1.2  88/11/28  18:08:23  network
X * patch5: Copy temp files before handing them to delivery files.
X * patch5: Introduce "uid" program.
X * 
X * Revision 1.1  88/06/06  09:39:42  chip
X * Initial revision
X * 
X */
X
X#include "deliver.h"
X#include <sys/types.h>
X#include <sys/stat.h>
X
X/*
X * Local functions.
X */
X
Xstatic  int     uucp_copy();
X
X/*----------------------------------------------------------------------
X * Send mail to UUCP addresses (if any).
X * This is a simple implementation: invoke uux once per address.
X */
X
Xuucp_deliver()
X{
X	struct stat st;
X	DEST    *d;
X	char    *uux;
X	static char uux1[] = "/bin/uux";
X	static char uux2[] = "/usr/bin/uux";
X
X	if (stat(uux1, &st) == 0)
X		uux = uux1;
X	else if (stat(uux2, &st) == 0)
X		uux = uux2;
X	else
X	{
X		error("can't find uux!?\n");
X		return;
X	}
X
X	for (d = first_dest(); d; d = next_dest(d))
X	{
X		FILE    *uux_fp;
X		char    *bang;
X		char    *av[5];
X		char    rmail[40];
X		char    who[BUFSIZ];
X
X		if (d->d_class != CL_UUCP || d->d_state != ST_WORKING)
X			continue;
X
X		if (printaddrs)
X			(void) printf("%s\n", d->d_name);
X
X		if (dryrun)
X		{
X			d->d_state = ST_DONE;
X			continue;
X		}
X
X		bang = strchr(d->d_name, '!');
X		*bang = 0;
X		(void) sprintf(rmail, "%s!rmail", d->d_name);
X		*bang++ = '!';
X		(void) sprintf(who, "(%s)", bang);
X
X		av[0] = "uux";
X		av[1] = "-";
X		av[2] = rmail;
X		av[3] = who;
X		av[4] = NULL;
X		if ((uux_fp = ct_popenv(eff_ct, uux, av, "w")) == NULL)
X			continue;
X
X		if (uucp_copy(uux_fp) < 0)
X			dest_err(d, E_UUX);
X
X		if (ct_pclose(uux_fp))
X		{
X			/* "No such host" overrides piping problems. */
X			dest_err(d, E_NSHOST);
X		}
X		else
X			d->d_state = ST_DONE;
X	}
X}
X
X/*----------------------------------------------------------------------
X * Write the message for UUCP transmission to the given file.
X */
X
Xstatic int
Xuucp_copy(ofp)
XFILE    *ofp;
X{
X	FILE    *ifp;
X	char    *p;
X	register int c;
X	int     fd;
X	char    buf[BUFSIZ];
X
X	if ((fd = dup(tfd[T_HDR])) == -1)
X	{
X		syserr("can't dup header fd");
X		return -1;
X	}
X	(void) lseek(fd, 0L, 0);
X	if ((ifp = fdopen(fd, "r")) == NULL)
X	{
X		error("can't fdopen header fd");
X		return -1;
X	}
X
X	/*
X	 * Copy the header, but tack "remote from" onto the end of the
X	 * From_ line.  (If it weren't for dealing with the From_ line,
X	 * I'd skip stream I/O altogether and use read/write.  Maybe
X	 * I should save the length of the From_ line when I copy it...)
X	 */
X
X	(void) fgets(buf, GETSIZE(buf), ifp);
X	if ((p = strchr(buf, '\n')) != NULL)
X		*p = 0;
X	(void) fprintf(ofp, "%s remote from %s\n", buf, hostname);
X
X	while ((c = getc(ifp)) != EOF)
X		(void) putc(c, ofp);
X
X	(void) fclose(ifp);
X
X	/*
X	 * Copy the body
X	 */
X
X	if ((fd = dup(tfd[T_BODY])) == -1)
X	{
X		syserr("can't dup body fd");
X		return -1;
X	}
X	(void) lseek(fd, 0L, 0);
X	if ((ifp = fdopen(fd, "r")) == NULL)
X	{
X		error("can't fdopen body fd");
X		(void) close(fd);
X		return -1;
X	}
X
X	while ((c = getc(ifp)) != EOF)
X		(void) putc(c, ofp);
X
X	(void) fclose(ifp);
X	return 0;
X}
END_OF_FILE
if test 3269 -ne `wc -c <'uucp.c'`; then
    echo shar: \"'uucp.c'\" unpacked with wrong size!
fi
# end of 'uucp.c'
fi
echo shar: End of shell archive.
exit 0
-- 
Chip Salzenberg             <chip at ateng.com> or <uunet!ateng!chip>
A T Engineering             Me?  Speak for my company?  Surely you jest!
	  "It's no good.  They're tapping the lines."



More information about the Comp.sources.bugs mailing list