rsalz@uunet.uu.net (Rich Salz) (10/16/89)
Submitted-by: Chip Salzenberg <chip@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@uunet.uu.net. Use a domain-based address or give alternate paths, or you may lose out.