[comp.mail.misc] Deliver 2.0 Patch #2

chip@ateng.com (Chip Salzenberg) (12/16/89)

Changes in patch #2 to Deliver 2.0:

1.  Normal and error logs have been added.  Their names are defined by
    the new configuration items LOG and ERRLOG.  Note that the normal
    log will only be written if it already exists.  This feature
    provides a convenient way to turn off logging: rename the log file.
    Error logging, however, is unconditional.
    Thanks to Goran Larsson <hacker@isadora.ikp.liu.se> for this idea.

2.  Deliver now tracks recursive invocations, and aborts delivery if
    recursion gets too deep.  Also, the current recursion depth is noted in
    the log files and error messages.
    Thanks for Ron McGrath for giving me the idea by putting a similar
    feature in GNU Make.

3.  New configuration items:
	UMASK           File creation mask.  Not to be confused with
			the mailbox file mode, MBX_MODE.
	ENV_DPID        Environment variable for deliver's pid.
	ENV_DLEVEL      Environment variable for delivery recursion level.
	REC_LIMIT       Limit on delivery recursion.

4.  A bug in the 2.0 release caused unknown users to be reported as
    "context lost (should never happen)".  They are now correctly
    reported as "no such user".

5.  A new flag for the "header" program: "-v" reverses the test for
    printing, rather like grep's -v flag.  For example, "header -vnf
    received" prints an entire header _except_ any Received: lines.
    Thanks to Tom Neff <tneff@bfmny0.UU.NET>.

This patch contains changes to the following files:
	patchlevel.h
	Makefile
	config.h
	deliver.8
	deliver.h
	dfile.c
	header.c
	main.c
	mbox.c
	procs.c
	subs.c
	sysdep.c
	unctime.y
	uucp.c

Index: patchlevel.h
Prereq: 1
***************
*** 1,1 ****
! #define PATCHLEVEL 1
--- 1,1 ----
! #define PATCHLEVEL 2

Index: Makefile
***************
*** 1,3 ****
! # $Header: Makefile,v 2.4 89/10/02 10:58:56 network Exp $
  #
  # Makefile for deliver
--- 1,3 ----
! # $Header: Makefile,v 2.5 89/11/10 12:23:47 network Exp $
  #
  # Makefile for deliver
***************
*** 177,181 ****
  #
  
! lint: deliver.lint uid.lint
  
  deliver.lint: $(HDRS) $(DELSRCC) $(COMSRCS)
--- 177,181 ----
  #
  
! lint: deliver.lint header.lint uid.lint
  
  deliver.lint: $(HDRS) $(DELSRCC) $(COMSRCS)
***************
*** 182,185 ****
--- 182,188 ----
  	lint $(DELSRCC) $(COMSRCS) -lc $(LIBS) >$@
  
+ header.lint: $(HDRSRCS) $(COMSRCS)
+ 	lint $(HDRSRCS) $(COMSRCS) -lc $(LIBS) >$@
+ 
  uid.lint: config.h $(UIDSRCS) $(COMSRCS)
  	lint $(UIDSRCS) $(COMSRCS) -lc $(LIBS) >$@

Index: config.h
***************
*** 1,3 ****
! /* $Header: config.h,v 2.3 89/09/29 18:16:52 network Exp $
   *
   * Deliver configuration.
--- 1,3 ----
! /* $Header: config.h,v 2.5 89/11/10 12:23:49 network Exp $
   *
   * Deliver configuration.
***************
*** 4,7 ****
--- 4,13 ----
   *
   * $Log:	config.h,v $
+  * Revision 2.5  89/11/10  12:23:49  network
+  * Handle recursion.
+  * 
+  * Revision 2.4  89/11/01  10:33:36  network
+  * Add UMASK, LOG, ERRLOG.
+  * 
   * Revision 2.3  89/09/29  18:16:52  network
   * Save message when delivery file produces no output,
***************
*** 194,197 ****
--- 200,220 ----
  
  /*----------------------------------------------------------------------
+  * File creation mask.
+  * Bits turned on here are turned off in newly created files.
+  * This mask is the default when executing delivery files,
+  * but mailboxes have their own mode value (MBX_MODE).
+  */
+ 
+ #define UMASK   022
+ 
+ /*----------------------------------------------------------------------
+  * Recursion limit.
+  * If Deliver detects recursion deeper than this value,
+  * it will assume infinite recursion and abort.
+  */
+ 
+ #define REC_LIMIT  8
+ 
+ /*----------------------------------------------------------------------
   * Characters that may not appear in addresses.
   * (This string should include all metacharacters for your chosen shell.)
***************
*** 253,259 ****
--- 276,293 ----
  
  /*----------------------------------------------------------------------
+  * Log file names.
+  * Errors and warnings are output to stderr and to this file.
+  * To disable logging, don't define LOGFILE.
+  */
+ 
+ #define LOG             "/usr/adm/deliver.log"
+ #define ERRLOG          "/usr/adm/deliver.errlog"
+ 
+ /*----------------------------------------------------------------------
   * Environment variables passed to child processes.
   */
  
+ #define ENV_DPID        "DELPID"        /* Deliver process id           */
+ #define ENV_DLEVEL      "DELLEVEL"      /* Level of recursion           */
  #define ENV_DFLAGS      "DELFLAGS"      /* Flags: [-[Avdt]]             */
  #define ENV_SYSDEL      "SYSDELFILE"    /* System delivery file         */

Index: deliver.8
***************
*** 1,3 ****
! .\" $Header: deliver.8,v 2.2 89/10/04 10:49:10 network Exp $
  .\"
  .\" Man page for deliver.
--- 1,3 ----
! .\" $Header: deliver.8,v 2.4 89/11/10 14:09:46 network Exp $
  .\"
  .\" Man page for deliver.
***************
*** 4,7 ****
--- 4,13 ----
  .\"
  .\" $Log:	deliver.8,v $
+ .\" Revision 2.4  89/11/10  14:09:46  network
+ .\" Document cases in which the log files are not written.
+ .\" 
+ .\" Revision 2.3  89/11/10  13:34:58  network
+ .\" Document recursion and logging.
+ .\" 
  .\" Revision 2.2  89/10/04  10:49:10  network
  .\" Document the "Undel.mail" and "DROP" features.
***************
*** 248,251 ****
--- 254,272 ----
  are:
  .TP
+ .B DELPID
+ The process id of the running
+ .I deliver
+ process.  Used by a child
+ .I deliver
+ to determine its parent's process id.
+ .B DELLEVEL
+ The
+ .I deliver
+ recursion level.  Each time
+ .I deliver
+ is called recursively, this value is incremented.  When the maximum
+ recursion level (default: eight) is exceeded,
+ .I deliver
+ assumes infinite recursion and aborts.
  .B DELFLAGS
  The command line flags, if any, specified on the
***************
*** 337,340 ****
--- 358,399 ----
  file unless they are output by the given user's delivery file.  In other
  words, no user can request writing a mailbox as another user.
+ .SH LOGGING
+ .I Deliver
+ records its activity in two files: the "delivery log", named
+ .IR /usr/adm/deliver.log,
+ and the "error log", named
+ .IR /usr/adm/deliver.errlog.
+ .PP
+ The deliver log is a record of activity of each
+ .I deliver
+ process.
+ Each delivery log entry include the users or mailboxes named on the command
+ line, the users and/or mailboxes where delivery succeeded, and those where
+ it failed.  Note that
+ .I deliver
+ will write to the delivery log only if it already exists.
+ .PP
+ The error log is a record of any problems encounted during delivery.  Each
+ error log entry includes all diagnostic output, a copy of the message
+ header, and other miscellaneous information that might prove helpful.
+ .PP
+ If
+ .I deliver
+ is performing a "dry run" -- that is, if the
+ .B \-d
+ (debug) or
+ .B \-A
+ (print address) flag is specified -- it will not write to either log file.
+ .PP
+ If you want a delivery log, you must create the delivery log file yourself.
+ If the delivery log file does not exist,
+ .I deliver
+ will not create it.
+ .PP
+ If the
+ .B \-v
+ (verbose) flag is specified,
+ .I deliver
+ will not write to the error log.
  .SH LOCKING
  Several preprocessor labels may be defined during compilation to control
***************
*** 375,378 ****
--- 434,441 ----
  ~user/.deliver                  user delivery file(s)
  .br
+ /usr/adm/deliver.log            delivery log
+ .br
+ /usr/adm/deliver.errlog         error log
+ .br
  /etc/systemid                   system name (Xenix only)
  .SH SUPPORT

Index: deliver.h
***************
*** 1,3 ****
! /* $Header: deliver.h,v 2.2 89/09/29 18:17:56 network Exp $
   *
   * General pull-it-together include file.
--- 1,3 ----
! /* $Header: deliver.h,v 2.5 89/11/10 12:23:51 network Exp $
   *
   * General pull-it-together include file.
***************
*** 4,7 ****
--- 4,16 ----
   *
   * $Log:	deliver.h,v $
+  * Revision 2.5  89/11/10  12:23:51  network
+  * Handle recursion.
+  * 
+  * Revision 2.4  89/11/01  12:18:59  network
+  * Delintify.
+  * 
+  * Revision 2.3  89/11/01  11:51:40  network
+  * Add logging.
+  * 
   * Revision 2.2  89/09/29  18:17:56  network
   * Save message when delivery file produces no output,
***************
*** 36,48 ****
  extern  int     leavetemps;     /* Leave temp files for later perusal   */
  extern  int     boxdelivery;    /* Args are mailboxes, not addresses    */
- extern  char    *sender;        /* Who is sending this message?         */
  
  extern  char    *progname;      /* Name this program was invoked under  */
! extern  char    *hostname;      /* Name of this host                    */
  
  extern  char    *sys_deliver;   /* Systemwide delivery file             */
  extern  char    *post_deliver;  /* Post-user delivery file              */
  extern  char    *user_deliver;  /* User delivery file                   */
! extern  char    *shell;         /* Shell used to run delivery files     */
  
  extern  int     eff_uid;        /* Returned by geteuid()                */
--- 45,60 ----
  extern  int     leavetemps;     /* Leave temp files for later perusal   */
  extern  int     boxdelivery;    /* Args are mailboxes, not addresses    */
  
  extern  char    *progname;      /* Name this program was invoked under  */
! extern  char    version[];      /* Version and patchlevel               */
! extern  char    *shell;         /* Shell used to run delivery files     */
  
+ extern  int     rec_parent;     /* If recursing, parent deliver's pid   */
+ extern  int     rec_level;      /* If recursing, recursion level        */
  extern  char    *sys_deliver;   /* Systemwide delivery file             */
  extern  char    *post_deliver;  /* Post-user delivery file              */
  extern  char    *user_deliver;  /* User delivery file                   */
! extern  char    *sender;        /* Who is sending this message?         */
! extern  char    *hostname;      /* Name of this host                    */
  
  extern  int     eff_uid;        /* Returned by geteuid()                */
***************
*** 57,60 ****
--- 69,79 ----
  extern  int     trust_delfiles; /* Do we trust the delivery files?      */
  
+ extern  FILE    *log;           /* File to log deliveries               */
+ extern  FILE    *errlog;        /* File to log messages and errors      */
+ extern  int     errused;        /* Error log used flag                  */
+ 
+ extern  int     tty_input;      /* Is our input coming from a tty?      */
+ extern  SIGFLAG got_sig;        /* Did we catch a deadly signal?        */
+ 
  /* Temp file indices: */
  #define T_HDR      0    /* Message header                       */

Index: dfile.c
***************
*** 1,3 ****
! /* $Header: dfile.c,v 2.2 89/09/29 18:17:59 network Exp $
   *
   * Filter destination(s) through delivery file(s).
--- 1,3 ----
! /* $Header: dfile.c,v 2.4 89/11/10 12:23:52 network Exp $
   *
   * Filter destination(s) through delivery file(s).
***************
*** 4,7 ****
--- 4,13 ----
   *
   * $Log:	dfile.c,v $
+  * Revision 2.4  89/11/10  12:23:52  network
+  * Be more selective about trying to deliver to MBX_UNDEL.
+  * 
+  * Revision 2.3  89/11/01  12:31:11  network
+  * Use the new exists() function.
+  * 
   * Revision 2.2  89/09/29  18:17:59  network
   * Save message when delivery file produces no output,
***************
*** 30,34 ****
  	char    **fav;
  	int     fac, a;
- 	struct stat st;
  
  	/*
--- 36,39 ----
***************
*** 36,40 ****
  	 */
  
! 	if (stat(relpath(eff_ct->ct_home, sys_deliver), &st) == -1)
  	{
  		if (verbose)
--- 41,45 ----
  	 */
  
! 	if (!exists(relpath(eff_ct->ct_home, sys_deliver)))
  	{
  		if (verbose)
***************
*** 98,102 ****
  		 */
  
! 		if (do_dfile(eff_ct, fav, (DEST *)NULL) <= 0)
  		{
  			if (verbose)
--- 103,107 ----
  		 */
  
! 		if (do_dfile(eff_ct, fav, (DEST *)NULL) == 0)
  		{
  			if (verbose)
***************
*** 122,126 ****
  	char    **fav;
  	int     num_dests, fac;
- 	struct stat st;
  
  	/*
--- 127,130 ----
***************
*** 128,132 ****
  	 */
  
! 	if (stat(relpath(eff_ct->ct_home, post_deliver), &st) == -1)
  	{
  		if (verbose)
--- 132,136 ----
  	 */
  
! 	if (!exists(relpath(eff_ct->ct_home, post_deliver)))
  	{
  		if (verbose)
***************
*** 179,183 ****
  		 */
  
! 		if (do_dfile(eff_ct, fav, (DEST *)NULL) <= 0)
  		{
  			if (verbose)
--- 183,187 ----
  		 */
  
! 		if (do_dfile(eff_ct, fav, (DEST *)NULL) == 0)
  		{
  			if (verbose)
***************
*** 283,287 ****
  
  	s = relpath(ct->ct_home, user_deliver);
! 	if (stat(s, &st) == -1)
  	{
  		if (verbose)
--- 287,291 ----
  
  	s = relpath(ct->ct_home, user_deliver);
! 	if (!exists(s))
  	{
  		if (verbose)
***************
*** 307,311 ****
  	fav[3] = NULL;
  
! 	if (do_dfile(ct, fav, d) <= 0)
  	{
  		/*
--- 311,315 ----
  	fav[3] = NULL;
  
! 	if (do_dfile(ct, fav, d) == 0)
  	{
  		/*
***************
*** 326,329 ****
--- 330,335 ----
   * Process a delivery file.
   * Return the count of valid destinations we got back from it.
+  * If delivering to MBX_UNDEL is possible, errors return zero.
+  * Otherwise, errors return -1.
   */
  
***************
*** 384,388 ****
  	{
  		error("can't execute delivery file as %s\n", ct->ct_name);
! 		return -1;
  	}
  
--- 390,394 ----
  	{
  		error("can't execute delivery file as %s\n", ct->ct_name);
! 		return 0;
  	}
  

Index: header.c
***************
*** 1,7 ****
! /* $Header: header.c,v 2.2 89/06/09 13:08:07 network Exp $
   *
   * A program to parse RFC 822 mail/news headers.
   *
!  * usage: header [-c] [-n] [-f field] ... files
   *
   * Default action is to print entire header.  If one or more -f options
--- 1,7 ----
! /* $Header: header.c,v 2.5 89/11/10 12:23:54 network Exp $
   *
   * A program to parse RFC 822 mail/news headers.
   *
!  * usage: header [-c] [-n] [-v] [-f field] ... files
   *
   * Default action is to print entire header.  If one or more -f options
***************
*** 8,12 ****
   * are given, only the specified fields are printed.  The field names are
   * not printed unless -n is specified.  Field name comparisons are case
!  * insensitive unless -c is specified.
   *
   * Output lines are preceeded by the filename if more than one file is
--- 8,13 ----
   * are given, only the specified fields are printed.  The field names are
   * not printed unless -n is specified.  Field name comparisons are case
!  * insensitive unless -c is specified.  If -v is specified, all headers 
!  * except those specified with -f are printed.  NOTE: -v implies -n.
   *
   * Output lines are preceeded by the filename if more than one file is
***************
*** 17,20 ****
--- 18,31 ----
   *
   * $Log:	header.c,v $
+  * Revision 2.5  89/11/10  12:23:54  network
+  * Delintify.
+  * 
+  * Revision 2.4  89/10/30  16:08:48  network
+  * Don't automatically print field names with "-v".  (Sorry, Tom.)
+  * 
+  * Revision 2.3  89/10/30  16:03:29  network
+  * Add "-v" (everything except) option.
+  * Submitted by Tom Neff <tneff%bfmny0@uunet.uu.net>.
+  * 
   * Revision 2.2  89/06/09  13:08:07  network
   * Adapt to BSD quirks.
***************
*** 74,77 ****
--- 85,89 ----
  int     nocasematch     = TRUE;         /* ignore case in header matches */
  int     printnames      = FALSE;        /* print field names with data */
+ int     except          = FALSE;        /* reverse sense of -f */
  
  /*----------------------------------------------------------------------
***************
*** 91,95 ****
  
  	errors = FALSE;
! 	while ((c = getopt(argc, argv, "cnf:")) != EOF)
  	{
  		switch (c)
--- 103,107 ----
  
  	errors = FALSE;
! 	while ((c = getopt(argc, argv, "cnvf:")) != EOF)
  	{
  		switch (c)
***************
*** 101,104 ****
--- 113,119 ----
  			printnames = TRUE;
  			break;
+ 		case 'v':
+ 			except = TRUE;
+ 			break;
  		case 'f':
  			if (field_count >= field_alloc)
***************
*** 140,144 ****
  
  			header(fp, (filenames ? argv[a] : (char *)NULL));
! 			fclose(fp);
  		}
  	}
--- 155,159 ----
  
  			header(fp, (filenames ? argv[a] : (char *)NULL));
! 			(void) fclose(fp);
  		}
  	}
***************
*** 145,148 ****
--- 160,164 ----
  
  	exit(errors ? 1 : 0);
+ 	/* NOTREACHED */
  }
  
***************
*** 149,153 ****
  usage()
  {
! 	fprintf(stderr, "usage: header [-c] [-f fieldname] ... files\n");
  	exit(1);
  }
--- 165,170 ----
  usage()
  {
! 	(void) fprintf(stderr,
! 		"usage: header [-c] [-n] [-v] [-f fieldname] ... files\n");
  	exit(1);
  }
***************
*** 155,159 ****
  nomem()
  {
! 	fprintf(stderr, "header: out of memory\n");
  	exit(1);
  }
--- 172,176 ----
  nomem()
  {
! 	(void) fprintf(stderr, "header: out of memory\n");
  	exit(1);
  }
***************
*** 187,190 ****
--- 204,209 ----
  			break;
  		print_this = field(buf, p - buf);
+ 		if (except)
+ 			print_this = !print_this;
  		if (print_this)
  		{
***************
*** 191,196 ****
  			if (filename)
  			{
! 				fputs(filename, stdout);
! 				putc(':', stdout);
  			}
  			++p;
--- 210,215 ----
  			if (filename)
  			{
! 				(void) fputs(filename, stdout);
! 				(void) fputc(':', stdout);
  			}
  			++p;
***************
*** 198,204 ****
  				++p;
  			if (field_count == 0 || printnames)
! 				fputs(buf, stdout);
  			else
! 				fputs(p, stdout);
  		}
  
--- 217,223 ----
  				++p;
  			if (field_count == 0 || printnames)
! 				(void) fputs(buf, stdout);
  			else
! 				(void) fputs(p, stdout);
  		}
  
***************
*** 214,221 ****
  				if (filename)
  				{
! 					fputs(filename, stdout);
! 					putc(':', stdout);
  				}
! 				fputs(buf, stdout);
  			}
  
--- 233,240 ----
  				if (filename)
  				{
! 					(void) fputs(filename, stdout);
! 					(void) fputc(':', stdout);
  				}
! 				(void) fputs(buf, stdout);
  			}
  

Index: main.c
***************
*** 1,3 ****
! /* $Header: main.c,v 2.1 89/06/09 12:25:32 network Exp $
   *
   * A program to deliver local mail with some flexibility.
--- 1,3 ----
! /* $Header: main.c,v 2.4 89/11/10 12:23:55 network Exp $
   *
   * A program to deliver local mail with some flexibility.
***************
*** 4,7 ****
--- 4,16 ----
   *
   * $Log:	main.c,v $
+  * Revision 2.4  89/11/10  12:23:55  network
+  * Handle recursion.  Enhance logging.
+  * 
+  * Revision 2.3  89/11/01  12:19:02  network
+  * Delintify.
+  * 
+  * Revision 2.2  89/11/01  11:51:47  network
+  * Add logging.
+  * 
   * Revision 2.1  89/06/09  12:25:32  network
   * Update RCS revisions.
***************
*** 48,51 ****
--- 57,62 ----
  char    *shell          = SHELL;
  
+ int     rec_level       = 0;
+ int     rec_parent      = -1;
  char    *sys_deliver    = sys_dfl;
  char    *post_deliver   = post_dfl;
***************
*** 62,71 ****
  CONTEXT *real_ct        = NULL;
  
- int     tty_input       = FALSE;
- SIGFLAG got_sig         = FALSE;
- 
  int     trust_user      = FALSE;
  int     trust_delfiles  = FALSE;
  
  char    *ttype[T_MAX]   = { "header", "body", "header copy", "body copy" };
  char    *tfile[T_MAX]   = { NULL, NULL, NULL, NULL };
--- 73,86 ----
  CONTEXT *real_ct        = NULL;
  
  int     trust_user      = FALSE;
  int     trust_delfiles  = FALSE;
  
+ FILE    *log            = NULL;
+ FILE    *errlog         = NULL;
+ int     errused         = FALSE;
+ 
+ int     tty_input       = FALSE;
+ SIGFLAG got_sig         = FALSE;
+ 
  char    *ttype[T_MAX]   = { "header", "body", "header copy", "body copy" };
  char    *tfile[T_MAX]   = { NULL, NULL, NULL, NULL };
***************
*** 88,92 ****
  {
  	char    *p;
! 	int     u, c, errcount, copy;
  
  	/* Make sure that stdout and stderr are interleaved correctly */
--- 103,107 ----
  {
  	char    *p;
! 	int     i, c, errcount, copy;
  
  	/* Make sure that stdout and stderr are interleaved correctly */
***************
*** 99,115 ****
  	progname = basename(argv[0]);
  
! 	/* What version of the program is this? */
  
! 	(void) sprintf(version + strlen(version), ".%02d", PATCHLEVEL);
  
! 	/* Figure out the name of this host */
  
! 	if ((hostname = gethost()) == NULL)
  	{
! 		hostname = "unknown";
! 		error("unable to determine host name; using \"%s\"\n",
! 		      hostname);
  	}
  
  	/* Find effective and real uids and gids. */
  
--- 114,144 ----
  	progname = basename(argv[0]);
  
! 	/* Special hack -- handle the recursion level and parent first. */
  
! 	if ((p = getenv(ENV_DLEVEL)) != NULL && (i = atoi(p)) > 0)
! 		rec_level = i;
  
! 	if ((p = getenv(ENV_DPID)) != NULL && (i = atoi(p)) > 0)
! 		rec_parent = i;
  
! 	/* If recursion level is non-zero, append it to the program name. */
! 
! 	if (rec_level > 0)
  	{
! 		char    *np;
! 
! 		np = zalloc((unsigned) strlen(progname) + 16);
! 		(void) sprintf(np, "%s[%d]", progname, rec_level);
! 		progname = np;
  	}
  
+ 	/* What version of the program is this? */
+ 
+ 	(void) sprintf(version + strlen(version), ".%02d", PATCHLEVEL);
+ 
+ 	/* Let's be sane about the file creation mask. */
+ 
+ 	(void) umask(UMASK);
+ 
  	/* Find effective and real uids and gids. */
  
***************
*** 119,122 ****
--- 148,153 ----
  	real_gid = getgid();
  
+ 	/* Make sure that setuidness is reasonable. */
+ 
  	if (eff_uid != real_uid && eff_uid != 0)
  	{
***************
*** 125,129 ****
  	}
  
! 	/* Process environment: handle recursive invocation */
  
  	if ((p = getenv(ENV_DFLAGS)) != NULL)
--- 156,160 ----
  	}
  
! 	/* Process environment: handle recursive invocation. */
  
  	if ((p = getenv(ENV_DFLAGS)) != NULL)
***************
*** 216,219 ****
--- 247,264 ----
  	}
  
+ #ifdef LOG
+ 	/* If we're delivering and the log file exists, open it. */
+ 
+ 	if (!dryrun && exists(LOG))
+ 		log = fopen(LOG, "a");
+ #endif
+ 
+ #ifdef ERRLOG
+ 	/* If we're delivering and not being verbose, open the error log. */
+ 
+ 	if (!dryrun && !verbose)
+ 		errlog = fopen(ERRLOG, "a");
+ #endif
+ 
  	/* If no destinations were given, forget it. */
  
***************
*** 224,227 ****
--- 269,281 ----
  	}
  
+ 	/* Figure out the name of this host */
+ 
+ 	if ((hostname = gethost()) == NULL)
+ 	{
+ 		hostname = "unknown";
+ 		error("unable to determine host name; using \"%s\"\n",
+ 		      hostname);
+ 	}
+ 
  	/* Print a debugging message */
  
***************
*** 274,284 ****
  	}
  
- 	/* Let's be sane about the file creation mask. */
- 
- 	u = umask(0);
- 	u &= ~0700;     /* Let's not deprive ourselves of permissions.  */
- 	u |= 022;       /* Let's be reasonably paranoid about writing.  */
- 	(void) umask(u);
- 
  	/*
  	 * Where is the message coming from?
--- 328,331 ----
***************
*** 332,340 ****
  
  	/*
! 	 * Perhaps we should consider all arguments as mailbox names...
  	 */
  
! 	if (boxdelivery)
  	{
  		int     a;
  
--- 379,399 ----
  
  	/*
! 	 * If recursion is too deep, consider mail undeliverable.
  	 */
  
! 	if (rec_level > REC_LIMIT)
  	{
+ 		error("recursion limit (%d) exceeded; writing to %s:%s",
+ 		      REC_LIMIT, eff_ct->ct_name, MBX_UNDEL);
+ 
+ 		(void) dest(eff_ct->ct_name, MBX_UNDEL);
+ 	}
+ 
+ 	/*
+ 	 * Else, if all arguments are mailbox names...
+ 	 */
+ 
+ 	else if (boxdelivery)
+ 	{
  		int     a;
  
***************
*** 354,358 ****
  
  	/*
! 	 * They're not mailbox names, so they should be mail addresses.
  	 */
  
--- 413,417 ----
  
  	/*
! 	 * Else, arguments are addresses.
  	 */
  
***************
*** 423,429 ****
  
  	/*
! 	 * Report any errors, and leave.
  	 */
  
  	errcount = report_errors();
  
--- 482,495 ----
  
  	/*
! 	 * Report all results in log file.
  	 */
  
+ 	if (log)
+ 		logreport(argc - optind, argv + optind);
+ 
+ 	/*
+ 	 * Report any errors.
+ 	 */
+ 
  	errcount = report_errors();
  
***************
*** 466,469 ****
--- 532,537 ----
  int     code;
  {
+ 	errinfo();
+ 
  	if (! leavetemps)
  	{
***************
*** 479,482 ****
--- 547,552 ----
  	}
  
+ 	errend();
+ 
  	exit(code);
  }
***************
*** 529,532 ****
--- 599,661 ----
  
  /*----------------------------------------------------------------------
+  * Write a report to the log file.
+  */
+ 
+ logreport(ac, av)
+ int     ac;
+ char    **av;
+ {
+ 	int     a;
+ 
+ 	if (!log)
+ 		return;
+ 
+ 	timestamp(log);
+ 
+ 	if (sender && *sender)
+ 		(void) fprintf(log, "sender: %s\n", sender);
+ 	if (boxdelivery)
+ 		(void) fprintf(log, "mailbox%s:", (ac > 1) ? "es" : "");
+ 	else
+ 		(void) fprintf(log, "destination%s:", (ac > 1) ? "s" : "");
+ 	for (a = 0; a < ac; ++a)
+ 		(void) fprintf(log, " \"%s\"", av[a]);
+ 	(void) fputc('\n', log);
+ 
+ 	logstate("delivered", ST_DONE);
+ 	logstate("failed", ST_ERROR);
+ 
+ 	(void) fflush(log);
+ }
+ 
+ /*----------------------------------------------------------------------
+  * Log the destinations with the given state.
+  * If any are found, the list is prefixed with the given description.
+  */
+ 
+ logstate(desc, state)
+ char    *desc;
+ DSTATE  state;
+ {
+ 	DEST    *d;
+ 	int     count;
+ 
+ 	count = 0;
+ 	for (d = first_dest(); d; d = next_dest(d))
+ 	{
+ 		if (d->d_state != state)
+ 			continue;
+ 
+ 		if (++count == 1)
+ 			(void) fprintf(log, "%s:", desc);
+ 		(void) fprintf(log, " %s", d->d_name);
+ 		if (d->d_mailbox)
+ 			(void) fprintf(log, ":%s", d->d_mailbox);
+ 	}
+ 	if (count)
+ 		(void) fputc('\n', log);
+ }
+ 
+ /*----------------------------------------------------------------------
   * Report any errors to stderr.
   * Return an error count.
***************
*** 547,551 ****
  		{
  			error(
! 		    "delivery to the following address(es) failed on host %s\n",
  				hostname);
  		}
--- 676,680 ----
  		{
  			error(
! 		 "delivery to the following address(es) failed on host %s:\n",
  				hostname);
  		}
***************
*** 587,603 ****
  setup_environ()
  {
! 	char    flags[8];
  	int     f = 0;
  
! 	flags[f++] = '-';
  	if (verbose)
! 		flags[f++] = (dryrun ? 'd' : 'v');
  	if (printaddrs)
! 		flags[f++] = 'A';
  	if (leavetemps)
! 		flags[f++] = 't';
! 	flags[f] = 0;
  
- 	alloc_env(ENV_DFLAGS, (f > 1) ? flags : "");
  	if (sys_deliver && *sys_deliver)
  		alloc_env(ENV_SYSDEL, sys_deliver);
--- 716,738 ----
  setup_environ()
  {
! 	char    s[8];
  	int     f = 0;
  
! 	(void) sprintf(s, "%d", getpid());
! 	alloc_env(ENV_DPID, s);
! 
! 	(void) sprintf(s, "%d", rec_level + 1);
! 	alloc_env(ENV_DLEVEL, s);
! 
! 	s[f++] = '-';
  	if (verbose)
! 		s[f++] = (dryrun ? 'd' : 'v');
  	if (printaddrs)
! 		s[f++] = 'A';
  	if (leavetemps)
! 		s[f++] = 't';
! 	s[f] = 0;
! 	alloc_env(ENV_DFLAGS, (f > 1) ? s : "");
  
  	if (sys_deliver && *sys_deliver)
  		alloc_env(ENV_SYSDEL, sys_deliver);

Index: mbox.c
***************
*** 1,3 ****
! /* $Header: mbox.c,v 2.1 89/06/09 12:25:33 network Exp $
   *
   * Finally!  Put the message in the specified mailbox(es).
--- 1,3 ----
! /* $Header: mbox.c,v 2.2 89/11/01 11:51:05 network Exp $
   *
   * Finally!  Put the message in the specified mailbox(es).
***************
*** 4,7 ****
--- 4,10 ----
   *
   * $Log:	mbox.c,v $
+  * Revision 2.2  89/11/01  11:51:05  network
+  * Fix error code; unknown user is now reported correctly.
+  * 
   * Revision 2.1  89/06/09  12:25:33  network
   * Update RCS revisions.
***************
*** 77,81 ****
  	if ((ct = name_context(d->d_name)) == NULL)
  	{
! 		dest_err(d, E_CTLOST);
  		return;
  	}
--- 80,84 ----
  	if ((ct = name_context(d->d_name)) == NULL)
  	{
! 		dest_err(d, E_NSUSER);
  		return;
  	}

Index: procs.c
***************
*** 1,3 ****
! /* $Header: procs.c,v 2.2 89/09/29 18:18:03 network Exp $
   *
   * Process management and misc support.
--- 1,3 ----
! /* $Header: procs.c,v 2.4 89/11/01 12:19:05 network Exp $
   *
   * Process management and misc support.
***************
*** 4,7 ****
--- 4,13 ----
   *
   * $Log:	procs.c,v $
+  * Revision 2.4  89/11/01  12:19:05  network
+  * Delintify.
+  * 
+  * Revision 2.3  89/11/01  11:51:50  network
+  * Add logging.
+  * 
   * Revision 2.2  89/09/29  18:18:03  network
   * Save message when delivery file produces no output,
***************
*** 132,135 ****
--- 138,145 ----
  			for (t = 0; t < T_MAX; ++t)
  				(void) close(tfd[t]);
+ 			if (log)
+ 				(void) fclose(log);
+ 			if (errlog)
+ 				(void) fclose(errlog);
  
  			(void) execv(prog, av);
***************
*** 233,236 ****
--- 243,250 ----
  	(void) fflush(stdout);
  	(void) fflush(stderr);
+ 	if (log)
+ 		(void) fflush(log);
+ 	if (errlog)
+ 		(void) fflush(errlog);
  
  	/*

Index: subs.c
***************
*** 1,3 ****
! /* $Header: subs.c,v 2.2 89/09/29 18:18:05 network Exp $
   *
   * Miscellaneous subroutines.
--- 1,3 ----
! /* $Header: subs.c,v 2.3 89/11/01 10:37:58 network Exp $
   *
   * Miscellaneous subroutines.
***************
*** 4,7 ****
--- 4,10 ----
   *
   * $Log:	subs.c,v $
+  * Revision 2.3  89/11/01  10:37:58  network
+  * Add exists() function.
+  * 
   * Revision 2.2  89/09/29  18:18:05  network
   * Save message when delivery file produces no output,
***************
*** 18,23 ****
--- 21,40 ----
  
  #include "deliver.h"
+ #include <sys/stat.h>
  
  /*----------------------------------------------------------------------
+  * Report as to whether a file exists or not.
+  */
+ 
+ int
+ exists(path)
+ char    *path;
+ {
+ 	struct stat st;
+ 
+ 	return (stat(path, &st) == 0);
+ }
+ 
+ /*----------------------------------------------------------------------
   * Allocate memory for an environment variable, and putenv() it.
   */

Index: sysdep.c
***************
*** 1,3 ****
! /* $Header: sysdep.c,v 2.1 89/06/09 12:25:40 network Exp $
   *
   * Routines which are (or might well be) system-dependant.
--- 1,3 ----
! /* $Header: sysdep.c,v 2.4 89/11/10 12:23:58 network Exp $
   *
   * Routines which are (or might well be) system-dependant.
***************
*** 6,9 ****
--- 6,18 ----
   *
   * $Log:	sysdep.c,v $
+  * Revision 2.4  89/11/10  12:23:58  network
+  * Log recursion depth, undelivered mail and failed headers.
+  * 
+  * Revision 2.3  89/11/01  12:19:06  network
+  * Delintify.
+  * 
+  * Revision 2.2  89/11/01  11:51:51  network
+  * Add logging.
+  * 
   * Revision 2.1  89/06/09  12:25:40  network
   * Update RCS revisions.
***************
*** 16,19 ****
--- 25,29 ----
  #include "deliver.h"
  #include <errno.h>
+ #include <time.h>
  #ifdef HAS_STDARG
  #include <stdarg.h>
***************
*** 57,84 ****
  extern  char    *sys_errlist[];
  
! /*----------------------------------------------------------------------
!  * Print a message.
   */
  
! /* VARARGS */
! #ifdef HAS_STDARG
! message(char *fmt, ...)
! #else
! message(va_alist) va_dcl
! #endif
! {
! 	va_list ap;
  
  #ifdef HAS_STDARG
! 	va_start(ap, fmt);
  #else
! 	char    *fmt;
! 	va_start(ap);
! 	fmt = va_arg(ap, char *);
  #endif
  
  	(void) vfprintf(stderr, fmt, ap);
  
! 	va_end(ap);
  }
  
--- 67,109 ----
  extern  char    *sys_errlist[];
  
! /*
!  * Locally useful macros.
   */
  
! /* Wrapper macros to hide stdarg/vararg differences. */
  
  #ifdef HAS_STDARG
! #define FMT_PARAM       (char *fmt, ...)
! #define FMT_VARS        va_list ap;
! #define FMT_START       va_start(ap, fmt);
! #define FMT_END         va_end(ap);
  #else
! #define FMT_PARAM       (va_alist) va_dcl
! #define FMT_VARS        va_list ap; char *fmt;
! #define FMT_START       va_start(ap); fmt = va_arg(ap, char *);
! #define FMT_END         va_end(ap);
  #endif
  
+ /*----------------------------------------------------------------------
+  * Print a message.
+  */
+ 
+ /* VARARGS */
+ message
+ FMT_PARAM
+ {
+ 	FMT_VARS
+ 
+ 	FMT_START
  	(void) vfprintf(stderr, fmt, ap);
+ 	FMT_END
  
! 	if (errlog)
! 	{
! 		errstart();
! 		FMT_START
! 		(void) vfprintf(errlog, fmt, ap);
! 		FMT_END
! 	}
  }
  
***************
*** 88,111 ****
  
  /* VARARGS */
! #ifdef HAS_STDARG
! error(char *fmt, ...)
! #else
! error(va_alist) va_dcl
! #endif
  {
! 	va_list ap;
  
! #ifdef HAS_STDARG
! 	va_start(ap, fmt);
! #else
! 	char    *fmt;
! 	va_start(ap);
! 	fmt = va_arg(ap, char *);
! #endif
! 
  	(void) fprintf(stderr, "%s: ", progname);
  	(void) vfprintf(stderr, fmt, ap);
  
! 	va_end(ap);
  }
  
--- 113,134 ----
  
  /* VARARGS */
! error
! FMT_PARAM
  {
! 	FMT_VARS
  
! 	FMT_START
  	(void) fprintf(stderr, "%s: ", progname);
  	(void) vfprintf(stderr, fmt, ap);
+ 	FMT_END
  
! 	if (errlog)
! 	{
! 		errstart();
! 		FMT_START
! 		(void) fprintf(errlog, "%s: ", progname);
! 		(void) vfprintf(errlog, fmt, ap);
! 		FMT_END
! 	}
  }
  
***************
*** 115,146 ****
  
  /* VARARGS */
! #ifdef HAS_STDARG
! syserr(char *fmt, ...)
! #else
! syserr(va_alist) va_dcl
! #endif
  {
  	int     e = errno;
! 	va_list ap;
  
! #ifdef HAS_STDARG
! 	va_start(ap, fmt);
! #else
! 	char    *fmt;
! 	va_start(ap);
! 	fmt = va_arg(ap, char *);
! #endif
! 
  	(void) fprintf(stderr, "%s: ", progname);
! 	(void) vfprintf(stderr, fmt, ap);
  	if (e <= sys_nerr)
! 		(void) fprintf(stderr, ": %s\n", sys_errlist[e]);
  	else
! 		(void) fprintf(stderr, ": unknown system error %d\n", e);
  
! 	va_end(ap);
  }
  
  /*----------------------------------------------------------------------
   * Sleep for the given number of seconds.
   */
--- 138,355 ----
  
  /* VARARGS */
! syserr
! FMT_PARAM
  {
  	int     e = errno;
! 	FMT_VARS
  
! 	FMT_START
  	(void) fprintf(stderr, "%s: ", progname);
! 	vsyserr(stderr, fmt, ap, e);
! 	FMT_END
! 
! 	if (errlog)
! 	{
! 		errstart();
! 		FMT_START
! 		(void) fprintf(errlog, "%s: ", progname);
! 		vsyserr(errlog, fmt, ap, e);
! 		FMT_END
! 	}
! }
! 
! vsyserr(fp, fmt, ap, e)
! FILE    *fp;
! char    *fmt;
! va_list ap;
! int     e;
! {
! 	(void) vfprintf(fp, fmt, ap);
  	if (e <= sys_nerr)
! 		(void) fprintf(fp, ": %s\n", sys_errlist[e]);
  	else
! 		(void) fprintf(fp, ": unknown system error %d\n", e);
! }
  
! /*----------------------------------------------------------------------
!  * Record any interesting information in the error log file.
!  */
! 
! errinfo()
! {
! 	if (!errlog)
! 		return;
! 
! 	/* Log undelivered mail. */
! 
! 	errundel();
! 
! 	/* If any errors have been logged, record the failed header. */
! 
! 	if (errused)
! 		errheader();
  }
  
  /*----------------------------------------------------------------------
+  * Log undelivered mail.
+  *
+  * Note that this algorithm assumes that delivery to the MBX_UNDEL mailbox
+  * is always worth reporting.
+  */
+ 
+ errundel()
+ {
+ 	DEST    *d;
+ 
+ 	if (!errlog)
+ 		return;
+ 
+ 	for (d = first_dest(); d; d = next_dest(d))
+ 	{
+ 		if (d->d_state == ST_DONE
+ 		 && d->d_class == CL_MBOX
+ 		 && strcmp(d->d_mailbox, MBX_UNDEL) == 0)
+ 		{
+ 			CONTEXT *ct;
+ 			char    *home;
+ 
+ 			if ((ct = name_context(d->d_name)) != NULL)
+ 				home = ct->ct_home;
+ 			else
+ 				home = "~";     /* should never happen */
+ 
+ 			errstart();
+ 			(void) fprintf(errlog,
+ 			    "Undelivered mail for %s put in %s/%s\n",
+ 			    d->d_name, home, MBX_UNDEL);
+ 		}
+ 	}
+ }
+ 
+ /*----------------------------------------------------------------------
+  * Log the message header.
+  */
+ 
+ errheader()
+ {
+ 	FILE    *hfp;
+ 	int     hfd;
+ 
+ 	if (!errlog)
+ 		return;
+ 
+ 	/* Copy the failed message's header. */
+ 
+ 	hfd = dup(tfd[T_HDR]);
+ 	hfp = (hfd < 0) ? NULL : fdopen(hfd, "r");
+ 	if (hfp == NULL)
+ 	{
+ 		(void) fprintf(errlog, "%s: can't open header file %s\n",
+ 					progname, tfile[T_HDR]);
+ 	}
+ 	else
+ 	{
+ 		int     c, oc;
+ 
+ 		(void) fprintf(errlog, "+ Header:\n");
+ 
+ 		(void) fseek(hfp, 0L, 0);
+ 		oc = '\n';
+ 		while ((c = getc(hfp)) != EOF)
+ 		{
+ 			if (oc != '\n' || c != '\n')
+ 			{
+ 				if (oc == '\n')
+ 					(void) fputs("| ", errlog);
+ 				(void) putc(c, errlog);
+ 			}
+ 			oc = c;
+ 		}
+ 
+ 		(void) fclose(hfp);
+ 	}
+ }
+ 
+ /*----------------------------------------------------------------------
+  * Record a time stamp in the error log file.
+  */
+ 
+ errstart()
+ {
+ 	/* For the sake of V7, manually seek to EOF. */
+ 
+ 	(void) fseek(errlog, 0L, 2);
+ 
+ 	/* If we've already written a time stamp, don't do it again. */
+ 
+ 	if (errused)
+ 		return;
+ 
+ 	/* Write a time stamp and various useful info. */
+ 
+ 	timestamp(errlog);
+ 	(void) fprintf(errlog, "process %d", getpid());
+ 	if (rec_parent > 0)
+ 		(void) fprintf(errlog, ", parent %d", rec_parent);
+ 	(void) fprintf(errlog, ": %s %s\n", progname, version);
+ 
+ 	/* Remember that we've written the time stamp. */
+ 
+ 	errused = TRUE;
+ }
+ 
+ /*----------------------------------------------------------------------
+  * Record the end of this process's error log entry.
+  */
+ 
+ errend()
+ {
+ 	/* If we never wrote to the error log file, do nothing. */
+ 
+ 	if (!errused)
+ 		return;
+ 
+ 	/* Write a simple closing line for the error log entry. */
+ 
+ 	(void) fprintf(errlog, "process %d", getpid());
+ 	if (rec_parent > 0)
+ 		(void) fprintf(errlog, ", parent %d", rec_parent);
+ 	(void) fprintf(errlog, ": exit\n");
+ 	(void) fflush(errlog);
+ }
+ 
+ /*----------------------------------------------------------------------
+  * Write a timestamp to the given file.
+  */
+ 
+ timestamp(fp)
+ FILE    *fp;
+ {
+ 	struct tm *lt;
+ 	time_t  now;
+ 	static char month[12][4] = {
+ 		"Jan", "Feb", "Mar", "Apr", "May", "Jun",
+ 		"Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
+ 	};
+ 
+ 	(void) time(&now);
+ 	lt = localtime(&now);
+ 
+ 	(void) fputc('\n', fp);
+ 	if (rec_level)
+ 		(void) fprintf(fp, "[%d]", rec_level);
+ 	(void) fputs("======================== ", fp);
+ 	(void) fprintf(fp, "%d %s %d, %02d:%02d:%02d %s\n",
+ 			lt->tm_mday, month[lt->tm_mon], lt->tm_year + 1900,
+ 			lt->tm_hour, lt->tm_min, lt->tm_sec,
+ #ifdef LTZNMAX
+ 			lt->tm_name
+ #else
+ 			lt->tm_zone
+ #endif
+ 			);
+ }
+ 
+ /*----------------------------------------------------------------------
   * Sleep for the given number of seconds.
   */

Index: unctime.y
***************
*** 1,4 ****
  /*
!  * $Header: unctime.y,v 2.1 89/06/09 12:25:42 network Exp $
   *
   * Conversion of ctime-style date string back to a time_t.
--- 1,4 ----
  /*
!  * $Header: unctime.y,v 2.2 89/10/31 12:15:45 network Exp $
   *
   * Conversion of ctime-style date string back to a time_t.
***************
*** 7,10 ****
--- 7,13 ----
   *
   * $Log:	unctime.y,v $
+  * Revision 2.2  89/10/31  12:15:45  network
+  * Fix erroneous cast in BSD-specific code.
+  * 
   * Revision 2.1  89/06/09  12:25:42  network
   * Update RCS revisions.
***************
*** 463,467 ****
    /* The cast is required to shut lint up.  Berkeley goes to all the effort
       to define time_t, why don't they use it? */
!   tm = localtime(&(time_t) tv.tv_sec);
  #else
    (void) time(&now);
--- 466,470 ----
    /* The cast is required to shut lint up.  Berkeley goes to all the effort
       to define time_t, why don't they use it? */
!   tm = localtime((time_t *) &tv.tv_sec);
  #else
    (void) time(&now);

Index: uucp.c
***************
*** 1,3 ****
! /* $Header: uucp.c,v 2.1 89/06/09 12:25:44 network Exp $
   *
   * Handle mail destined for other hosts via UUCP.
--- 1,3 ----
! /* $Header: uucp.c,v 2.2 89/11/01 12:31:17 network Exp $
   *
   * Handle mail destined for other hosts via UUCP.
***************
*** 6,9 ****
--- 6,12 ----
   *
   * $Log:	uucp.c,v $
+  * Revision 2.2  89/11/01  12:31:17  network
+  * Use the new exists() function.
+  * 
   * Revision 2.1  89/06/09  12:25:44  network
   * Update RCS revisions.
***************
*** 15,19 ****
  
  #include "deliver.h"
- #include <sys/stat.h>
  
  /*
--- 18,21 ----
***************
*** 30,34 ****
  uucp_deliver()
  {
- 	struct stat st;
  	DEST    *d;
  	char    *uux;
--- 32,35 ----
***************
*** 36,42 ****
  	static char uux2[] = "/usr/bin/uux";
  
! 	if (stat(uux1, &st) == 0)
  		uux = uux1;
! 	else if (stat(uux2, &st) == 0)
  		uux = uux2;
  	else
--- 37,43 ----
  	static char uux2[] = "/usr/bin/uux";
  
! 	if (exists(uux1))
  		uux = uux1;
! 	else if (exists(uux2))
  		uux = uux2;
  	else
-- 
You may redistribute this article only to those who may freely do likewise.
Chip Salzenberg at A T Engineering;  <chip@ateng.com> or <uunet!ateng!chip>
	  "The Usenet, in a very real sense, does not exist."