v20i024: Deliver, flexible email delivery system, Part02/04
Rich Salz
rsalz at uunet.uu.net
Tue Oct 17 01:52:56 AEST 1989
Submitted-by: Chip Salzenberg <chip at ateng.com>
Posting-number: Volume 20, Issue 24
Archive-name: deliver2.0/part02
#! /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: config.h context.h deliver.h dest.h patchlevel.h misc.h
# context.c copymsg.c
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'config.h' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'config.h'\"
else
echo shar: Extracting \"'config.h'\" \(6654 characters\)
sed "s/^X//" >'config.h' <<'END_OF_FILE'
X/* $Header: config.h,v 2.2 89/06/09 13:07:38 network Exp $
X *
X * Deliver configuration.
X *
X * $Log: config.h,v $
X * Revision 2.2 89/06/09 13:07:38 network
X * Adapt to BSD quirks.
X *
X * Revision 2.1 89/06/09 12:25:11 network
X * Update RCS revisions.
X *
X * Revision 1.11 89/06/09 12:23:38 network
X * Baseline for 2.0 release.
X *
X */
X
X/*----------------------------------------------------------------------
X * SCO Xenix System V compilers define M_SYSV, which implies USG.
X */
X
X#ifdef M_SYSV
X#ifndef USG
X#define USG
X#endif
X#endif
X
X/*----------------------------------------------------------------------
X * Trusted users.
X * Deliver permits "trusted" users to specify delivery filenames
X * without renouncing setuid privileges. Essentially, these users
X * are given the root password. Beware!
X */
X
X#define TRUSTED_USERS "root", "uucp"
X
X/*----------------------------------------------------------------------
X * Signal function type.
X * Signal catching routines have this return value.
X * (For System V Release 3.0 or later, use "void".)
X */
X
X#ifdef USG
X# define SIGTYPE void
X#else
X# define SIGTYPE int
X#endif
X
X/*----------------------------------------------------------------------
X * Signal function declaration.
X * Define this if your <signal.h> doesn't declare signal() correctly.
X */
X
X/* #define DECLARE_SIGNAL */
X
X/*----------------------------------------------------------------------
X * Signal flag type.
X * Variables of this type may be set by signal catching routines.
X */
X
X#ifdef __STDC__
X#define SIGFLAG sig_atomic_t
X#else
X#define SIGFLAG short /* or "volatile short" for aggressive optimizers */
X#endif
X
X/*----------------------------------------------------------------------
X * Various kinds of mailbox locking.
X * You may define one or both of ML_DOTLOCK and ML_DOTMLK.
X * You may define no more than one of ML_FCNTL, ML_LOCKF and ML_LOCKING.
X *
X * File creation locking:
X * ML_DOTLOCK create <mailbox>.lock (most systems except BSD4.3)
X * ML_DOTMLK create /tmp/<basename>.mlk (Xenix)
X *
X * Kernel record locking:
X * ML_FCNTL lock with fcntl(F_SETLKW) (SVID systems only)
X * ML_LOCKF lock with lockf(F_LOCK) (SVID systems only)
X * ML_LOCKING lock with locking(LK_LOCK) (Xenix systems only)
X */
X
X#ifdef M_XENIX
X#define ML_DOTMLK
X#define ML_LOCKING
X#else
X#define ML_DOTLOCK
X#endif
X
X/*----------------------------------------------------------------------
X * Maximum filename length.
X * Note that this is for _filenames_, not _pathnames_.
X * For AT&T file systems, the usual value is 14.
X * For Berzerkley file systems, use something big like 255.
X */
X
X#ifdef BSD
X#define MAX_NAMESIZE 255
X#else
X#define MAX_NAMESIZE 14
X#endif
X
X/*----------------------------------------------------------------------
X * How to get the host name.
X * Define one.
X *
X * HOSTFILE file containing name (Xenix)
X * UNAME uname() (System V)
X * GETHOSTNAME gethostname() (BSD)
X * HOSTNAME host name string (V7)
X */
X
X#ifdef M_XENIX
X#define HOSTFILE "/etc/systemid"
X#else
X#ifdef USG
X#define UNAME
X#else
X#ifdef BSD
X#define GETHOSTNAME
X#else
X#define HOSTNAME "cleese"
X#endif
X#endif
X#endif
X
X/*----------------------------------------------------------------------
X * Is <varargs.h> or <stdarg.h> available?
X */
X
X#ifdef __STDC__
X#define HAS_STDARG
X#else
X#ifdef USG
X#define HAS_VARARGS
X#else
X#ifdef BSD
X#define HAS_VARARGS
X#endif
X#endif
X#endif
X
X/*----------------------------------------------------------------------
X * Are vprintf() and friends available?
X */
X
X#ifdef USG
X#define HAS_VPRINTF
X#endif
X
X/*----------------------------------------------------------------------
X * Is putenv() available?
X */
X
X#ifdef USG
X#define HAS_PUTENV
X#endif
X
X/*----------------------------------------------------------------------
X * Is getopt() available?
X */
X
X#ifdef USG
X#define HAS_GETOPT
X#endif
X
X/*----------------------------------------------------------------------
X * Is setvbuf() backwards?
X * Note: this is true for SCO Xenix Development System 2.2.
X */
X
X/* #define REVERSE_SETVBUF */
X
X/*----------------------------------------------------------------------
X * Name of shell used to execute delivery files.
X */
X
X#define SHELL "/bin/sh"
X
X/*----------------------------------------------------------------------
X * Characters that may not appear in addresses.
X * (This string should include all metacharacters for your chosen shell.)
X */
X
X#define SANITIZE "$*?=\\`'\"|^&;{}()<> \t\n"
X
X/*----------------------------------------------------------------------
X * Standard mailbox location.
X *
X * Define either MBX_NAME or MBOX_DIR.
X * If MBX_NAME is defined, then the default mailbox is a file with
X * that name in the user's home directory.
X * If MBX_DIR is defined, then the default mailbox is a file in that
X * directory with the same name as the user.
X *
X * Define MBX_GROUP if all mailboxes must be owned by a specific group.
X * (System V requires this feature.) If MBX_GROUP is not defined,
X * mailboxes will have their groups set to the recipients' default group.
X *
X * Define MBX_MODE to the file access modes for new mailboxes.
X * (System V requires group write permissions, i.e. 0020.)
X */
X
X#if defined(USG) && !defined(M_XENIX)
X/* #define MBX_NAME "mbox" */
X#define MBX_DIR "/usr/mail"
X#define MBX_MODE 0660
X#define MBX_GROUP "mail"
X#else
X/* #define MBX_NAME "mbox" */
X#define MBX_DIR "/usr/spool/mail"
X#define MBX_MODE 0600
X#endif
X
X/*----------------------------------------------------------------------
X * Names of delivery files.
X *
X * SYS_DELIVER system-wide delivery file
X * POST_DELIVER post-user delivery file
X * USER_DELIVER user delivery file (in user's home directory)
X */
X
X#define SYS_DELIVER "/usr/local/lib/deliver.sys"
X#define POST_DELIVER "/usr/local/lib/deliver.post"
X#define USER_DELIVER ".deliver"
X
X/*----------------------------------------------------------------------
X * Environment variables passed to child processes.
X */
X
X#define ENV_DFLAGS "DELFLAGS" /* Flags: [-[Avdt]] */
X#define ENV_SYSDEL "SYSDELFILE" /* System delivery file */
X#define ENV_POSTDEL "POSTDELFILE" /* Post-user delivery file */
X#define ENV_USERDEL "USERDELFILE" /* User delivery file */
X
X#define ENV_HOSTNAME "HOSTNAME" /* Name of this host */
X#define ENV_SENDER "SENDER" /* Message sender */
X#define ENV_HEADER "HEADER" /* Message header file */
X#define ENV_BODY "BODY" /* Message body file */
END_OF_FILE
if test 6654 -ne `wc -c <'config.h'`; then
echo shar: \"'config.h'\" unpacked with wrong size!
fi
# end of 'config.h'
fi
if test -f 'context.h' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'context.h'\"
else
echo shar: Extracting \"'context.h'\" \(527 characters\)
sed "s/^X//" >'context.h' <<'END_OF_FILE'
X/* $Header: context.h,v 2.1 89/06/09 12:25:15 network Exp $
X *
X * User context, as found in /etc/passwd.
X *
X * $Log: context.h,v $
X * Revision 2.1 89/06/09 12:25:15 network
X * Update RCS revisions.
X *
X * Revision 1.3 89/06/09 12:23:40 network
X * Baseline for 2.0 release.
X *
X */
X
X/*----------------------------------------------------------------------
X * The context structure.
X */
X
X#define CONTEXT struct context
XCONTEXT {
X CONTEXT *ct_next;
X int ct_uid;
X int ct_gid;
X char *ct_name;
X char *ct_home;
X};
END_OF_FILE
if test 527 -ne `wc -c <'context.h'`; then
echo shar: \"'context.h'\" unpacked with wrong size!
fi
# end of 'context.h'
fi
if test -f 'deliver.h' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'deliver.h'\"
else
echo shar: Extracting \"'deliver.h'\" \(3237 characters\)
sed "s/^X//" >'deliver.h' <<'END_OF_FILE'
X/* $Header: deliver.h,v 2.1 89/06/09 12:25:21 network Exp $
X *
X * General pull-it-together include file.
X *
X * $Log: deliver.h,v $
X * Revision 2.1 89/06/09 12:25:21 network
X * Update RCS revisions.
X *
X * Revision 1.10 89/06/09 12:23:44 network
X * Baseline for 2.0 release.
X *
X */
X
X#include <stdio.h>
X#include <ctype.h>
X#include <sys/types.h>
X
X#include "config.h"
X#include "misc.h"
X#include "context.h"
X#include "dest.h"
X
X/*----------------------------------------------------------------------
X * Global data
X */
X
Xextern int verbose; /* Print debugging messages? */
Xextern int dryrun; /* Are we making a dry run? */
Xextern int rundfiles; /* Run delivery files at all? */
Xextern int printaddrs; /* Address resolution only? */
Xextern int leavetemps; /* Leave temp files for later perusal */
Xextern int boxdelivery; /* Args are mailboxes, not addresses */
Xextern char *sender; /* Who is sending this message? */
X
Xextern char *progname; /* Name this program was invoked under */
Xextern char *hostname; /* Name of this host */
X
Xextern char *sys_deliver; /* Systemwide delivery file */
Xextern char *post_deliver; /* Post-user delivery file */
Xextern char *user_deliver; /* User delivery file */
Xextern char *shell; /* Shell used to run delivery files */
X
Xextern int eff_uid; /* Returned by geteuid() */
Xextern int eff_gid; /* Returned by getegid() */
Xextern int real_uid; /* Returned by getuid() */
Xextern int real_gid; /* Returned by getgid() */
X
Xextern CONTEXT *eff_ct; /* Context of effective uid */
Xextern CONTEXT *real_ct; /* Context of real uid */
X
Xextern int trust_user; /* Do we trust the user that called us? */
Xextern int trust_delfiles; /* Do we trust the delivery files? */
X
X/* Temp file indices: */
X#define T_HDR 0 /* Message header */
X#define T_BODY 1 /* Message body */
X#define T_HDRCOPY 2 /* Copy of message header */
X#define T_BODYCOPY 3 /* Copy of message body */
X#define T_MAX 4 /* Number of temp files */
X
Xextern char *ttype[T_MAX]; /* Temp file types (for messages) */
Xextern char *tfile[T_MAX]; /* Temp file names */
Xextern char *tenv[T_MAX]; /* Temp file environment names */
Xextern int tfd[T_MAX]; /* Temp file fd's */
X
Xextern SIGFLAG got_sig; /* We caught a signal and should exit */
X
X/*----------------------------------------------------------------------
X * Global functions
X */
X
Xchar *basename();
Xchar *gethost();
Xchar *copystr();
Xchar *derrmsg();
Xchar *zalloc();
Xchar *srealloc();
X
XCONTEXT *name_context();
XCONTEXT *uid_context();
X
XFILE *ct_popenv();
Xint ct_pclose();
X
XDEST *dest();
XDEST *first_dest();
XDEST *next_dest();
X
Xtime_t unctime();
END_OF_FILE
if test 3237 -ne `wc -c <'deliver.h'`; then
echo shar: \"'deliver.h'\" unpacked with wrong size!
fi
# end of 'deliver.h'
fi
if test -f 'dest.h' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'dest.h'\"
else
echo shar: Extracting \"'dest.h'\" \(2503 characters\)
sed "s/^X//" >'dest.h' <<'END_OF_FILE'
X/* $Header: dest.h,v 2.1 89/06/09 12:25:23 network Exp $
X *
X * Description of a mail destination and its state.
X *
X * $Log: dest.h,v $
X * Revision 2.1 89/06/09 12:25:23 network
X * Update RCS revisions.
X *
X * Revision 1.3 89/06/09 12:23:48 network
X * Baseline for 2.0 release.
X *
X */
X
X/*----------------------------------------------------------------------
X * Destination class.
X */
X
Xtypedef enum {
X CL_USER, /* User name, no mailbox */
X CL_MBOX, /* User name, with mailbox name */
X CL_UUCP /* UUCP address (bang path) */
X} DCLASS;
X
X/*----------------------------------------------------------------------
X * Destination state.
X */
X
Xtypedef enum {
X ST_WORKING, /* the "normal" state */
X ST_HOLD, /* on hold during expansion */
X ST_DONE, /* all processing complete */
X ST_ERROR /* "something is horribly wrong" */
X} DSTATE;
X
X/*----------------------------------------------------------------------
X * Types of destination errors.
X */
X
Xtypedef enum {
X E_IVADDR, /* invalid address string */
X E_NSUSER, /* no such user */
X E_NSHOST, /* no such host (UUCP addresses) */
X E_CTPERM, /* no permissions for that context */
X E_CTLOST, /* context lost (should never happen) */
X E_MBOX, /* can't write to mailbox */
X E_UUX /* can't pipe to uux */
X} DERROR;
X
X/*----------------------------------------------------------------------
X * Structure describing a mail destination.
X */
X
X#define DEST struct dest
XDEST {
X DEST *d_next; /* next destination in the chain */
X DEST *d_prev; /* previous destination in the chain */
X DCLASS d_class; /* destination class */
X DSTATE d_state; /* destination state */
X DERROR d_error; /* error message (if state is ERROR) */
X int d_dfdone; /* boolean -- delivery file was run */
X char *d_name; /* context for delivery */
X char *d_mailbox; /* mailbox name or NULL for default */
X};
X
X/*----------------------------------------------------------------------
X * Action macros.
X */
X
X#define dest_err(d,m) ((d)->d_state = ST_ERROR, (d)->d_error = (m))
END_OF_FILE
if test 2503 -ne `wc -c <'dest.h'`; then
echo shar: \"'dest.h'\" unpacked with wrong size!
fi
# end of 'dest.h'
fi
if test -f 'patchlevel.h' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'patchlevel.h'\"
else
echo shar: Extracting \"'patchlevel.h'\" \(21 characters\)
sed "s/^X//" >'patchlevel.h' <<'END_OF_FILE'
X#define PATCHLEVEL 0
END_OF_FILE
if test 21 -ne `wc -c <'patchlevel.h'`; then
echo shar: \"'patchlevel.h'\" unpacked with wrong size!
fi
# end of 'patchlevel.h'
fi
if test -f 'misc.h' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'misc.h'\"
else
echo shar: Extracting \"'misc.h'\" \(2246 characters\)
sed "s/^X//" >'misc.h' <<'END_OF_FILE'
X/* $Header: misc.h,v 2.1 89/06/09 12:25:35 network Exp $
X *
X * Miscellaneous definitions.
X *
X * $Log: misc.h,v $
X * Revision 2.1 89/06/09 12:25:35 network
X * Update RCS revisions.
X *
X * Revision 1.7 89/06/09 12:23:56 network
X * Baseline for 2.0 release.
X *
X */
X
X/*
X * Non-portable include files
X */
X
X#ifdef USG
X#include <fcntl.h>
X#include <string.h>
X#include <memory.h>
X#endif
X
X#ifdef BSD
X#include <strings.h>
X#include <sys/file.h>
X#endif
X
X/*
X * Constants
X */
X
X#ifdef NULL
X#undef NULL
X#endif
X#define NULL 0 /* The One True NULL */
X
X#define FALSE 0
X#define TRUE 1
X
X#ifndef O_RDONLY
X#define O_RDONLY 0
X#define O_WRONLY 1
X#define O_RDWR 2
X#endif
X
X/*
X * Macros.
X */
X
X/* Length parameter for fgets() on given buffer. */
X
X#define GETSIZE(buf) (int) (sizeof(buf) - 1)
X
X/*
X * Public data.
X */
X
Xextern char **environ;
X
X/*
X * Common library functions.
X */
X
Xextern char *ctime();
Xextern char *getenv();
Xextern char *malloc();
Xextern char *realloc();
Xextern char *mktemp();
Xextern int putenv();
Xextern long lseek();
Xextern long time();
Xextern void free();
X
X#ifdef DECLARE_SIGNAL
Xextern SIGTYPE (*signal())();
X#endif
X
X/*
X * String search functions.
X */
X
X#ifndef USG
X
X#ifndef BSD
Xextern char *index();
Xextern char *rindex();
X#endif /* not BSD */
X
X#define strchr index
X#define strrchr rindex
X
X#endif
X
X/*
X * Memory copy and zero.
X */
X
X#ifdef USG
X#define Copy(d,s,n) (void) memcpy(d,s,n)
X#define Zero(d,n) (void) memset(d,0,(int)(n))
X#else /* not USG */
X#ifdef BSD
X#define Copy(d,s,n) bcopy(s,d,n)
X#define Zero(d,n) bzero(d,n)
X#else /* not BSD */
X#define MEMFUNCS /* define Copy() and Zero() in sysdep.c */
X#endif /* not BSD */
X#endif /* not USG */
X
X/*
X * Line-buffering on stdio files.
X */
X
X#ifdef USG
X
Xextern int setvbuf();
X
X#ifdef REVERSE_SETVBUF
X#define Linebuf(f) (void) setvbuf(f, _IOLBF, (char *)NULL, BUFSIZ)
X#else
X#define Linebuf(f) (void) setvbuf(f, (char *)NULL, _IOLBF, BUFSIZ)
X#endif
X
X#else /* not USG */
X#ifdef BSD
X
Xextern int setlinebuf();
X
X#define Linebuf(f) (void) setlinebuf(f)
X
X#else /* not BSD */
X
X#define Linebuf(f) /* can't do it */
X
X#endif /* not BSD */
X#endif /* not USG */
END_OF_FILE
if test 2246 -ne `wc -c <'misc.h'`; then
echo shar: \"'misc.h'\" unpacked with wrong size!
fi
# end of 'misc.h'
fi
if test -f 'context.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'context.c'\"
else
echo shar: Extracting \"'context.c'\" \(2517 characters\)
sed "s/^X//" >'context.c' <<'END_OF_FILE'
X/* $Header: context.c,v 2.1 89/06/09 12:25:13 network Exp $
X *
X * User context manager.
X * This module exists for efficiency reasons; I could just call getpwnam()
X * every time I need context info.
X *
X * $Log: context.c,v $
X * Revision 2.1 89/06/09 12:25:13 network
X * Update RCS revisions.
X *
X * Revision 1.5 89/06/09 12:23:39 network
X * Baseline for 2.0 release.
X *
X */
X
X#include "deliver.h"
X#include <pwd.h>
X#include <grp.h>
X
Xextern struct passwd *getpwnam();
Xextern struct passwd *getpwuid();
Xextern struct group *getgrnam();
Xextern struct group *getgrgid();
X
X/*
X * Local functions.
X */
X
Xstatic CONTEXT *new_context();
X
X/*
X * Local data.
X */
X
Xstatic CONTEXT *ctlist; /* Chain of CONTEXT structures. */
X
X/*----------------------------------------------------------------------
X * Look up a context by user name.
X */
X
XCONTEXT *
Xname_context(name)
Xchar *name;
X{
X struct passwd *pw;
X CONTEXT *ct;
X
X for (ct = ctlist; ct; ct = ct->ct_next)
X {
X if (strcmp(ct->ct_name, name) == 0)
X return ct;
X }
X
X if ((pw = getpwnam(name)) == NULL)
X return NULL;
X
X return new_context(pw);
X}
X
X/*----------------------------------------------------------------------
X * Look up a context by user ID.
X */
X
XCONTEXT *
Xuid_context(uid)
Xint uid;
X{
X struct passwd *pw;
X CONTEXT *ct;
X
X for (ct = ctlist; ct; ct = ct->ct_next)
X {
X if (ct->ct_uid == uid)
X return ct;
X }
X
X if ((pw = getpwuid(uid)) == NULL)
X return NULL;
X
X return new_context(pw);
X}
X
X/*----------------------------------------------------------------------
X * Local function -- create a new context structure and return
X * its address.
X */
X
Xstatic CONTEXT *
Xnew_context(pw)
Xstruct passwd *pw;
X{
X CONTEXT *ct;
X
X ct = (CONTEXT *) zalloc(sizeof(CONTEXT));
X ct->ct_uid = pw->pw_uid;
X ct->ct_gid = pw->pw_gid;
X ct->ct_name = copystr(pw->pw_name);
X ct->ct_home = copystr(pw->pw_dir);
X
X ct->ct_next = ctlist;
X ctlist = ct;
X
X return ct;
X}
X
X/*----------------------------------------------------------------------
X * Report whether is is possible or not to enter the given context.
X */
X
Xint
Xok_context(ct)
XCONTEXT *ct;
X{
X if (! ct)
X return FALSE;
X
X if (eff_uid == 0
X || ((real_uid == ct->ct_uid) && (real_gid == ct->ct_gid)))
X return TRUE;
X else
X return FALSE;
X}
X
X/*----------------------------------------------------------------------
X * Look up a group ID by name.
X */
X
X#ifdef MBX_GROUP
X
Xint
Xgroup_id(name)
Xchar *name;
X{
X struct group *grp;
X
X if ((grp = getgrnam(name)) == NULL)
X return -1;
X
X return grp->gr_gid;
X}
X
X#endif /* MBX_GROUP */
END_OF_FILE
if test 2517 -ne `wc -c <'context.c'`; then
echo shar: \"'context.c'\" unpacked with wrong size!
fi
# end of 'context.c'
fi
if test -f 'copymsg.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'copymsg.c'\"
else
echo shar: Extracting \"'copymsg.c'\" \(8775 characters\)
sed "s/^X//" >'copymsg.c' <<'END_OF_FILE'
X/* $Header: copymsg.c,v 2.1 89/06/09 12:25:16 network Exp $
X *
X * Take the message from standard input and write it to two temp files,
X * one for the header (including the empty line) and one for the body.
X *
X * $Log: copymsg.c,v $
X * Revision 2.1 89/06/09 12:25:16 network
X * Update RCS revisions.
X *
X * Revision 1.9 89/06/09 12:23:40 network
X * Baseline for 2.0 release.
X *
X */
X
X#include "deliver.h"
X
X/*
X * Macros.
X */
X
X/* Does a string start with "From "? */
X
X#define ISFROM(p) ((p)[0] == 'F' && (p)[1] == 'r' && (p)[2] == 'o' \
X && (p)[3] == 'm' && (p)[4] == ' ')
X
X/*
X * Local functions.
X */
X
Xstatic char *tempfile();
Xstatic int tcreate();
X
X/*----------------------------------------------------------------------
X * Copy the message on the standard input to two temp files:
X * one for the header and one for the body.
X */
X
Xint
Xcopy_message()
X{
X char buf[BUFSIZ];
X FILE *dfp[T_MAX];
X char *p, *from_line, *fsender, *fdate, *fremote;
X int t, b, empty_line;
X int ret = 0;
X
X /*
X * Create temporary files to hold the header and message body.
X */
X
X for (t = T_HDR; t <= T_BODY; ++t)
X {
X int fd;
X
X tfile[t] = tempfile();
X if ((tfd[t] = tcreate(tfile[t])) == -1)
X return -1;
X
X if ((fd = dup(tfd[t])) == -1)
X {
X syserr("dup %s fd", ttype[t]);
X return -1;
X }
X (void) lseek(fd, 0L, 0);
X if ((dfp[t] = fdopen(fd, "r+")) == NULL)
X {
X error("can't fdopen %s fd", ttype[t]);
X return -1;
X }
X }
X
X /* Debugging message for later examination of temp files. */
X
X if (verbose)
X {
X message("header=%s, body=%s\n",
X tfile[T_HDR], tfile[T_BODY]);
X }
X
X /*
X * If there is a From_ line, find the sender name therein.
X */
X
X from_line = NULL;
X fsender = fdate = fremote = NULL;
X
X b = (fgets(buf, GETSIZE(buf), stdin) ? TRUE : FALSE);
X
X if (b && ISFROM(buf) && (p = strchr(buf, '\n')) != NULL)
X {
X b = FALSE;
X
X /* Make a mungable copy of the From_ line */
X
X from_line = copystr(buf);
X if ((p = strchr(from_line, '\n')) != NULL)
X *p = 0;
X
X /* Find sender */
X
X p = from_line + 5;
X while (*p && isspace(*p))
X ++p;
X fsender = p;
X while (*p && !isspace(*p))
X ++p;
X if (*p)
X *p++ = 0;
X
X /* Date received should be around here somewhere */
X
X fdate = p;
X
X /* Find 'remote from' phrase (if any) */
X
X for (; (p = strchr(p, 'r')) != NULL; ++p)
X {
X if (strncmp(p, "remote from", 11) == 0)
X {
X *p = 0;
X p += 11;
X while (*p && isspace(*p))
X ++p;
X if (*p)
X fremote = p;
X break;
X }
X }
X
X /*
X * Advance to first non-space in date.
X * If there is no date, clear the date pointer.
X */
X
X while (*fdate && isspace(*fdate))
X ++fdate;
X if (*fdate == 0)
X fdate = NULL;
X
X /*
X * If sender is missing, or if date is invalid,
X * we consider the entire From_ line invalid.
X */
X
X if (*fsender == 0
X || (fdate != NULL && unctime(fdate) == -1) )
X {
X /* Ignore everything we found. */
X
X fsender = fdate = fremote = NULL;
X
X /* Print invalid From_ line in a harmless way. */
X
X (void) strcpy(from_line, buf);
X (void) strcpy(buf, "Invalid-UUCP-From: ");
X (void) strcat(buf, from_line);
X b = TRUE;
X }
X }
X
X /*
X * Write a From_ line to the header file.
X */
X
X /* if caller specified sender, use it */
X if (sender)
X ; /* fine */
X
X /* else if we found a From_ line, use it */
X else if (fsender)
X {
X if (fremote)
X {
X sender = zalloc(strlen(fremote) + sizeof("!")
X + strlen(fsender));
X (void) sprintf(sender, "%s!%s", fremote, fsender);
X }
X else
X sender = copystr(fsender);
X }
X
X /* else use our real ID */
X else
X sender = real_ct->ct_name;
X
X /* debugging message */
X
X if (verbose)
X message("copy_msg: sender is \"%s\"\n", sender);
X
X /*
X * Finally! Write the From_ line.
X */
X
X (void) fputs("From ", dfp[T_HDR]);
X (void) fputs(sender, dfp[T_HDR]);
X (void) fputc(' ', dfp[T_HDR]);
X if (fdate)
X {
X (void) fputs(fdate, dfp[T_HDR]);
X (void) fputc('\n', dfp[T_HDR]);
X }
X else
X {
X time_t now;
X
X (void) time(&now);
X (void) fputs(ctime(&now), dfp[T_HDR]);
X }
X
X /*
X * Free the From_ line if we allocated a copy of it.
X */
X
X if (from_line)
X free(from_line);
X
X /*
X * Copy the rest of the header (if any).
X */
X
X for (; !feof(stdin) && !ferror(stdin); b = FALSE)
X {
X if (!b)
X {
X if (fgets(buf, GETSIZE(buf), stdin))
X b = TRUE;
X else
X break;
X }
X
X /* Empty line means "end of header" */
X
X if (buf[0] == '\n')
X {
X b = FALSE; /* Don't put this line in the body. */
X break;
X }
X
X /*
X * A line too long to fit in buf[] can't be a header line.
X * At least, that's my opinion... :-)
X */
X
X if (!strchr(buf, '\n'))
X break;
X
X /*
X * If line begins with whitespace, it's a continuation.
X * Else if line begins with From_ or '>', prepend '>'.
X * Else if line doesn't look like a header, this must
X * be the beginning of the body.
X */
X
X if (isspace(buf[0]))
X ; /* continuation */
X else if (ISFROM(buf) || (buf[0] == '>'))
X (void) fputc('>', dfp[T_HDR]);
X else
X {
X /* look for the colon on a header label */
X
X p = buf;
X while (isalpha(*p) || *p == '-')
X ++p;
X if ((p == buf) || (*p != ':'))
X break; /* Not a header line! */
X }
X
X /* Write the line to the header file. */
X
X (void) fputs(buf, dfp[T_HDR]);
X }
X
X /*
X * End the header file with a blank line.
X * This enables us to simply concatenate it with the body file
X * to produce a valid message.
X */
X
X (void) fputc('\n', dfp[T_HDR]);
X
X /*
X * Copy the body (if any).
X */
X
X empty_line = FALSE;
X for (; !feof(stdin) && !ferror(stdin); b = FALSE)
X {
X if (!b)
X {
X if (fgets(buf, GETSIZE(buf), stdin))
X b = TRUE;
X else
X break;
X }
X
X if (ISFROM(buf))
X (void) fputc('>', dfp[T_BODY]);
X (void) fputs(buf, dfp[T_BODY]);
X
X empty_line = (buf[0] == '\n');
X
X /*
X * Output the rest of a very long line.
X * We do this here, instead of going around the loop,
X * in order to avoid misinterpreting From_ strings
X * that may be found in long lines.
X */
X
X while (!strchr(buf, '\n')
X && !feof(stdin)
X && !ferror(stdin)
X && fgets(buf, GETSIZE(buf), stdin))
X (void) fputs(buf, dfp[T_BODY]);
X }
X
X /* Ensure that the body ends with a blank line. */
X
X if (! empty_line)
X (void) fputc('\n', dfp[T_BODY]);
X
X /*
X * If we encountered any trouble writing to the temp files,
X * let's not keep it secret.
X */
X
X for (t = T_HDR; t <= T_BODY; ++t)
X {
X if (ferror(dfp[t]))
X {
X error("error writing to %s file %s\n",
X ttype[t], tfile[t]);
X ret = -1;
X }
X
X (void) fclose(dfp[t]);
X }
X
X /* Return error/success. */
X
X return ret;
X}
X
X/*----------------------------------------------------------------------
X * Create another copy of each temp file, for security reasons.
X * Also, put their names in the environment.
X */
X
Xint
Xcopy_again()
X{
X int r, t;
X
X for (r = T_HDR, t = T_HDRCOPY; r <= T_BODY; ++r, ++t)
X {
X /*
X * If the file exists, remove it but keep its name.
X * Otherwise, make a new name and put that name in
X * the environment.
X */
X
X if (tfile[t])
X (void) unlink(tfile[t]);
X else
X {
X tfile[t] = tempfile();
X if (tenv[t])
X alloc_env(tenv[t], tfile[t]);
X }
X
X /*
X * Create the file and copy the contents of the
X * original file to it.
X */
X
X if (tfd[t] != -1)
X (void) close(tfd[t]);
X
X if ((tfd[t] = tcreate(tfile[t])) == -1)
X return -1;
X
X (void) lseek(tfd[r], 0L, 0);
X if (copyfd(tfd[r], tfd[t]) < 0)
X return -1;
X }
X
X if (verbose)
X {
X message("copy_again: header to %s, body to %s\n",
X tfile[T_HDRCOPY], tfile[T_BODYCOPY]);
X }
X
X return 0;
X}
X
X/*----------------------------------------------------------------------
X * Copy a file via file descriptors.
X */
X
Xint
Xcopyfd(src_fd, dest_fd)
Xint src_fd;
Xint dest_fd;
X{
X char buf[BUFSIZ];
X int rd, wr;
X
X while ((rd = read(src_fd, buf, sizeof(buf))) > 0)
X {
X if ((wr = write(dest_fd, buf, (unsigned) rd)) != rd)
X {
X if (wr == -1)
X syserr("can't write in copyfd");
X else
X error("write error -- disk full?\n");
X return -1;
X }
X }
X
X return 0;
X}
X
X/*----------------------------------------------------------------------
X * Return a pointer to a temporary filename, or NULL if error.
X */
X
Xstatic char *
Xtempfile()
X{
X static char template[] = "/tmp/dl.XXXXXX";
X char *f;
X
X f = zalloc(32);
X (void) strcpy(f, template);
X if (mktemp(f) == NULL)
X {
X error("can't create temporary file");
X return NULL;
X }
X return f;
X}
X
X/*----------------------------------------------------------------------
X * Create a file, or complain if it doesn't work.
X */
X
Xstatic int
Xtcreate(name)
Xchar *name;
X{
X int fd;
X
X#ifdef O_CREAT
X fd = open(name, O_RDWR|O_CREAT|O_EXCL, 0);
X#else
X fd = creat(name, 0);
X#endif
X if (fd == -1)
X {
X syserr("can't create %s", name);
X return -1;
X }
X
X#ifndef O_CREAT
X (void) close(fd);
X if ((fd = open(name, 2)) == -1)
X {
X syserr("can't re-open %s", name);
X return -1;
X }
X#endif
X
X return fd;
X}
X
END_OF_FILE
if test 8775 -ne `wc -c <'copymsg.c'`; then
echo shar: \"'copymsg.c'\" unpacked with wrong size!
fi
# end of 'copymsg.c'
fi
echo shar: End of shell archive.
exit 0
--
Please send comp.sources.unix-related mail to rsalz at uunet.uu.net.
Use a domain-based address or give alternate paths, or you may lose out.
More information about the Comp.sources.unix
mailing list