Deliver 2.0 Patch #8
Chip Salzenberg
chip at tct.uucp
Thu Mar 8 03:20:35 AEST 1990
NOTE: THIS IS PART OF A COMBINED PATCH. APPLY PATCHES 7-9 TOGETHER.
This patch contains changes to the following files:
patchlevel.h
deliver.h
dest.c
dest.h
dfile.c
log.c
Index: patchlevel.h
Prereq: 7
***************
*** 1,1 ****
! #define PATCHLEVEL 7
--- 1,1 ----
! #define PATCHLEVEL 8
Index: deliver.h
***************
*** 1,3 ****
! /* $Header: deliver.h,v 2.6 90/02/06 11:54:45 chip Exp $
*
* General pull-it-together include file.
--- 1,3 ----
! /* $Header: deliver.h,v 2.8 90/03/06 12:17:42 chip Exp $
*
* General pull-it-together include file.
***************
*** 4,7 ****
--- 4,18 ----
*
* $Log: deliver.h,v $
+ * Revision 2.8 90/03/06 12:17:42 chip
+ * Move logging into log.c and address parsing into addr.c.
+ * New: error delivery file for messages that fail.
+ * Major rearrangement of delivery file code.
+ *
+ * Revision 2.7 90/02/23 14:15:58 chip
+ * Support "#!" in delivery files.
+ * Support "user|program" and "user?error" from delivery files.
+ * Improve debugging and error message formatting.
+ * Rearrange code for clarity.
+ *
* Revision 2.6 90/02/06 11:54:45 chip
* Enforce MBX_MODE regardless of UMASK.
***************
*** 59,62 ****
--- 70,74 ----
extern char *sys_deliver; /* Systemwide delivery file */
extern char *post_deliver; /* Post-user delivery file */
+ extern char *err_deliver; /* Error delivery file */
extern char *user_deliver; /* User delivery file */
extern char *sender; /* Who is sending this message? */
***************
*** 109,112 ****
--- 121,126 ----
char *srealloc();
+ char **choose_args();
+
CONTEXT *name_context();
CONTEXT *uid_context();
***************
*** 113,122 ****
FILE *ftcreate();
! FILE *ct_popenv();
! int ct_pclose();
DEST *dest();
DEST *first_dest();
DEST *next_dest();
time_t unctime();
--- 127,139 ----
FILE *ftcreate();
! FILE *ct_fopenv();
+ DEST *addr_dest();
DEST *dest();
DEST *first_dest();
DEST *next_dest();
+ DEST **dest_array();
+
+ DCLASS addr_class();
time_t unctime();
Index: dest.c
***************
*** 1,3 ****
! /* $Header: dest.c,v 2.2 89/09/29 18:17:57 network Exp $
*
* Operations on the list of mail destinations.
--- 1,3 ----
! /* $Header: dest.c,v 2.5 90/03/06 12:21:10 chip Exp $
*
* Operations on the list of mail destinations.
***************
*** 4,7 ****
--- 4,21 ----
*
* $Log: dest.c,v $
+ * Revision 2.5 90/03/06 12:21:10 chip
+ * Move logging into log.c and address parsing into addr.c.
+ * New: error delivery file for messages that fail.
+ * Major rearrangement of delivery file code.
+ *
+ * Revision 2.4 90/02/23 16:35:53 chip
+ * \Fix problems determining legality of user references.
+ *
+ * Revision 2.3 90/02/23 14:16:42 chip
+ * Support "#!" in delivery files.
+ * Support "user|program" and "user?error" from delivery files.
+ * Improve debugging and error message formatting.
+ * Rearrange code for clarity.
+ *
* Revision 2.2 89/09/29 18:17:57 network
* Save message when delivery file produces no output,
***************
*** 26,30 ****
--- 40,61 ----
#define HEADPTR (&deadhead)
+ /*
+ * Local functions.
+ */
+
+ static int destcmp();
+ static int ptrcmp();
+
/*----------------------------------------------------------------------
+ * Consider mail to the given user as undeliverable.
+ */
+
+ dest_undel(name)
+ char *name;
+ {
+ (void) dest(name, CL_MBOX, MBX_UNDEL);
+ }
+
+ /*----------------------------------------------------------------------
* Add a new destination to the list (unless it already exists).
* Return pointer to DEST.
***************
*** 32,49 ****
DEST *
! dest(name, mailbox)
char *name;
! char *mailbox;
{
DEST *d;
! DCLASS class;
! if (strchr(name, '!'))
! class = CL_UUCP;
! else if (mailbox)
! class = CL_MBOX;
! else
! class = CL_USER;
for (d = HEADPTR->d_next; d != HEADPTR; d = d->d_next)
{
--- 63,80 ----
DEST *
! dest(name, class, s)
char *name;
! DCLASS class;
! char *s;
{
DEST *d;
!
! /* Make sure that parameter is provided when it's needed. */
! if ((class == CL_MBOX || class == CL_PROG) != (s != NULL))
! return NULL;
+ /* Look for an already-existing copy of the given destination. */
+
for (d = HEADPTR->d_next; d != HEADPTR; d = d->d_next)
{
***************
*** 54,64 ****
continue;
! /*
! * If this destination has a named mailbox, then
! * test it for equality as well.
! */
!
! if (class == CL_MBOX
! && strcmp(d->d_mailbox, mailbox) != 0)
continue;
--- 85,89 ----
continue;
! if (s && strcmp(d->d_param, s) != 0)
continue;
***************
*** 78,85 ****
d->d_state = ST_WORKING;
d->d_name = copystr(name);
! if (class == CL_MBOX)
! d->d_mailbox = copystr(mailbox);
! else
! d->d_mailbox = NULL;
/*
--- 103,107 ----
d->d_state = ST_WORKING;
d->d_name = copystr(name);
! d->d_param = s ? copystr(s) : NULL;
/*
***************
*** 87,91 ****
*/
! if (!valid_address(name))
dest_err(d, E_IVADDR);
else if (class != CL_UUCP && name_context(name) == NULL)
--- 109,113 ----
*/
! if (!addr_clean(name))
dest_err(d, E_IVADDR);
else if (class != CL_UUCP && name_context(name) == NULL)
***************
*** 133,146 ****
/*----------------------------------------------------------------------
! * Return an error message given a DERROR.
*/
char *
! derrmsg(e)
! DERROR e;
{
static char unknown_buf[40];
! switch (e)
{
case E_IVADDR:
--- 155,277 ----
/*----------------------------------------------------------------------
! * Return the number of destinations in the list.
! */
!
! int
! dest_count()
! {
! DEST *d;
! int count;
!
! count = 0;
! for (d = HEADPTR->d_next; d && d != HEADPTR; d = d->d_next)
! ++count;
!
! return count;
! }
!
! /*----------------------------------------------------------------------
! * Return an allocated array of DEST pointers, or NULL if none.
! * The given integer is set to the array size.
! * Note that the caller must FREE this array when he's done.
! */
!
! DEST **
! dest_array(countp)
! int *countp;
! {
! DEST **dv, *d;
! int i, count;
!
! if ((count = dest_count()) <= 0)
! {
! *countp = 0;
! return NULL;
! }
!
! dv = (DEST **) zalloc(count * sizeof(DEST *));
!
! i = 0;
! for (d = HEADPTR->d_next; d && d != HEADPTR; d = d->d_next)
! {
! if (i < count)
! dv[i++] = d;
! }
!
! qsort((char *)dv, count, sizeof(dv[0]), destcmp);
!
! *countp = count;
! return dv;
! }
!
! /*----------------------------------------------------------------------
! * Compare two DEST pointers, for output sorting.
! */
!
! static int
! destcmp(p1, p2)
! char *p1, *p2;
! {
! DEST *d1, *d2;
! int cmp;
!
! d1 = *(DEST **)p1;
! d2 = *(DEST **)p2;
!
! #if 0
! /* Errors go last. */
! if ((d1->d_state == ST_ERROR) != (d2->d_state == ST_ERROR))
! return (d1->d_state == ST_ERROR) ? 1 : -1;
! #endif
!
! #if 0
! /* By class. */
! if ((cmp = (int)d1->d_class - (int)d2->d_class) != 0)
! return (cmp < 0) ? -1 : 1;
! #endif
!
! /* By user name. */
! if ((cmp = ptrcmp(d1->d_name, d2->d_name)) != 0)
! return cmp;
!
! /* By mailbox/program. */
! if ((cmp = ptrcmp(d1->d_param, d2->d_param)) != 0)
! return cmp;
!
! return 0;
! }
!
! /*----------------------------------------------------------------------
! * Compare two pointers, either of which may be NULL.
*/
+ static int
+ ptrcmp(p, q)
+ char *p, *q;
+ {
+ if (p == q)
+ return 0;
+ if (p == NULL)
+ return -1;
+ if (q == NULL)
+ return 1;
+ return strcmp(p, q);
+ }
+
+ /*----------------------------------------------------------------------
+ * Return a destination's error message.
+ */
+
char *
! derrmsg(d)
! DEST *d;
{
static char unknown_buf[40];
+ static char no_error[] = "no error?!";
+
+ if (!d || d->d_state != ST_ERROR)
+ return no_error;
! switch (d->d_error)
{
case E_IVADDR:
***************
*** 149,153 ****
return "No such user";
case E_NSHOST:
! return "No such host (UUCP addresses)";
case E_CTPERM:
return "No permissions for that context";
--- 280,284 ----
return "No such user";
case E_NSHOST:
! return "No such UUCP host";
case E_CTPERM:
return "No permissions for that context";
***************
*** 156,164 ****
case E_MBOX:
return "Can't write to mailbox";
! case E_UUX:
! return "Can't pipe to uux";
}
! (void) sprintf(unknown_buf, "Unknown error %d", e);
return unknown_buf;
}
--- 287,301 ----
case E_MBOX:
return "Can't write to mailbox";
! case E_PROG:
! return "Subprocess reported failure when exiting";
! case E_PIPE:
! return "Subprocess died while reading its standard input";
! case E_DFONLY:
! return "Address not valid from command line";
! case E_ERRMSG:
! return d->d_errmsg ? d->d_errmsg : no_error;
}
! (void) sprintf(unknown_buf, "Unknown error %d", d->d_error);
return unknown_buf;
}
Index: dest.h
***************
*** 1,3 ****
! /* $Header: dest.h,v 2.1 89/06/09 12:25:23 network Exp $
*
* Description of a mail destination and its state.
--- 1,3 ----
! /* $Header: dest.h,v 2.2 90/02/23 14:16:41 chip Exp $
*
* Description of a mail destination and its state.
***************
*** 4,7 ****
--- 4,13 ----
*
* $Log: dest.h,v $
+ * Revision 2.2 90/02/23 14:16:41 chip
+ * Support "#!" in delivery files.
+ * Support "user|program" and "user?error" from delivery files.
+ * Improve debugging and error message formatting.
+ * Rearrange code for clarity.
+ *
* Revision 2.1 89/06/09 12:25:23 network
* Update RCS revisions.
***************
*** 19,22 ****
--- 25,29 ----
CL_USER, /* User name, no mailbox */
CL_MBOX, /* User name, with mailbox name */
+ CL_PROG, /* Program to run with message on stdin */
CL_UUCP /* UUCP address (bang path) */
} DCLASS;
***************
*** 39,42 ****
--- 46,50 ----
typedef enum {
E_IVADDR, /* invalid address string */
+ E_DFONLY, /* "user:mbox" etc. for delfiles only */
E_NSUSER, /* no such user */
E_NSHOST, /* no such host (UUCP addresses) */
***************
*** 44,48 ****
E_CTLOST, /* context lost (should never happen) */
E_MBOX, /* can't write to mailbox */
! E_UUX /* can't pipe to uux */
} DERROR;
--- 52,58 ----
E_CTLOST, /* context lost (should never happen) */
E_MBOX, /* can't write to mailbox */
! E_PROG, /* subprocess exited with non-zero */
! E_PIPE, /* can't pipe to subprocess (incl. uux) */
! E_ERRMSG /* other user-described error */
} DERROR;
***************
*** 57,64 ****
DCLASS d_class; /* destination class */
DSTATE d_state; /* destination state */
! DERROR d_error; /* error message (if state is ERROR) */
int d_dfdone; /* boolean -- delivery file was run */
char *d_name; /* context for delivery */
! char *d_mailbox; /* mailbox name or NULL for default */
};
--- 67,75 ----
DCLASS d_class; /* destination class */
DSTATE d_state; /* destination state */
! DERROR d_error; /* error code (if state is ST_ERROR) */
! char *d_errmsg; /* error message (if error is E_ERRMSG) */
int d_dfdone; /* boolean -- delivery file was run */
char *d_name; /* context for delivery */
! char *d_param; /* parameter (mailbox or program name) */
};
Index: dfile.c
***************
*** 1,3 ****
! /* $Header: dfile.c,v 2.4 89/11/10 12:23:52 network Exp $
*
* Filter destination(s) through delivery file(s).
--- 1,3 ----
! /* $Header: dfile.c,v 2.7 90/03/06 12:21:12 chip Exp $
*
* Filter destination(s) through delivery file(s).
***************
*** 4,7 ****
--- 4,21 ----
*
* $Log: dfile.c,v $
+ * Revision 2.7 90/03/06 12:21:12 chip
+ * Move logging into log.c and address parsing into addr.c.
+ * New: error delivery file for messages that fail.
+ * Major rearrangement of delivery file code.
+ *
+ * Revision 2.6 90/02/23 16:35:54 chip
+ * \Fix problems determining legality of user references.
+ *
+ * Revision 2.5 90/02/23 14:16:44 chip
+ * Support "#!" in delivery files.
+ * Support "user|program" and "user?error" from delivery files.
+ * Improve debugging and error message formatting.
+ * Rearrange code for clarity.
+ *
* Revision 2.4 89/11/10 12:23:52 network
* Be more selective about trying to deliver to MBX_UNDEL.
***************
*** 27,92 ****
/*----------------------------------------------------------------------
! * Filter all valid destinations through the global delivery file.
*/
! sys_dfile(dac, dav)
! int dac;
! char **dav;
! {
! char **fav;
! int fac, a;
!
! /*
! * If there is no global delivery file, forget it.
! */
!
! if (!exists(relpath(eff_ct->ct_home, sys_deliver)))
! {
! if (verbose)
! message("no system delivery file\n");
! return -1;
! }
!
! /*
! * If we've been asked not to run delivery files, forget it.
! */
! if (!rundfiles)
{
! if (verbose)
! message("system delivery file disabled\n");
! return -1;
! }
! /*
! * Collect the arguments for the delivery file.
! */
! fav = (char **) zalloc((dac + 3) * sizeof(char **));
! fav[0] = shell;
! fav[1] = sys_deliver;
! fac = 2;
! for (a = 0; a < dac; ++a)
! {
! char *addr;
! addr = dav[a];
! if (valid_address(addr))
! {
! /* Let the delivery file handle valid addresses. */
- fav[fac++] = addr;
- }
else
! {
! /* Note invalid address(es); report them later. */
!
! (void) dest(addr, (char *) NULL);
! }
}
- fav[fac] = NULL;
-
/*
* If there were any good names found, let loose the delivery
--- 41,83 ----
/*----------------------------------------------------------------------
! * Filter all valid destinations through the system delivery file.
! * Return 1 (executed), 0 (not executed), -1 (no attempt made).
*/
! static int sys_ac;
! static char **sys_av;
!
! char **
! sys_args(pac)
! int *pac;
! {
! char **fav;
! int fac, a;
!
! fav = (char **) zalloc(sys_ac * sizeof(char **));
! fac = 0;
! for (a = 0; a < sys_ac; ++a)
{
! char *addr;
! addr = sys_av[a];
! /* Note invalid address(es); report them later. */
! if (!addr_clean(addr))
! (void) dest(addr, CL_USER, (char *) NULL);
!
! /* Note non-user address(es); report them later. */
!
! else if (addr_class(addr) != CL_USER)
! (void) addr_dest(addr, (CONTEXT *)NULL);
! /* Let the system delivery file handle the rest. */
else
! fav[fac++] = addr;
}
/*
* If there were any good names found, let loose the delivery
***************
*** 96,118 ****
*/
! if (fac > 2)
{
! /*
! * If we get nothing back from the system delivery file,
! * put the message in the "undelivered" mailbox.
! */
!
! if (do_dfile(eff_ct, fav, (DEST *)NULL) == 0)
! {
! if (verbose)
! message("sys_dfile: no output\n");
!
! (void) dest(eff_ct->ct_name, MBX_UNDEL);
! }
}
! free((char *) fav);
! return 0;
}
--- 87,107 ----
*/
! if (fac <= 0)
{
! free((char *) fav);
! fav = NULL;
}
! *pac = fac;
! return fav;
! }
! sys_dfile(ac, av)
! int ac;
! char **av;
! {
! sys_ac = ac;
! sys_av = av;
! return glob_dfile("system", sys_deliver, sys_args, FALSE);
}
***************
*** 120,139 ****
* Filter some undelivered destinations through the post-user
* delivery file.
*/
post_dfile()
{
! DEST *d;
! char **fav;
! int num_dests, fac;
! /*
! * If there is no post-user delivery file, forget it.
! */
! if (!exists(relpath(eff_ct->ct_home, post_deliver)))
! {
! if (verbose)
! message("no post-user delivery file\n");
return -1;
}
--- 109,189 ----
* Filter some undelivered destinations through the post-user
* delivery file.
+ * Return 1 (executed), 0 (not executed), -1 (no attempt made).
*/
+ post_choose(d)
+ DEST *d;
+ {
+ if ((d->d_class == CL_USER || d->d_class == CL_UUCP)
+ && (d->d_state == ST_WORKING
+ || (d->d_state == ST_ERROR && d->d_error == E_NSUSER)))
+ {
+ d->d_state = ST_HOLD;
+ return TRUE;
+ }
+
+ return FALSE;
+ }
+
+ char **
+ post_args(pac)
+ int *pac;
+ {
+ return choose_args(pac, post_choose);
+ }
+
post_dfile()
{
! return glob_dfile("post-user", post_deliver, post_args, FALSE);
! }
! /*----------------------------------------------------------------------
! * Filter broken (but well-formed) destinations through the error
! * delivery file.
! * Return 1 (executed), 0 (not executed), -1 (no attempt made).
! */
! err_choose(d)
! DEST *d;
! {
! return (d->d_state == ST_ERROR);
! }
!
! char **
! err_args(pac)
! int *pac;
! {
! return choose_args(pac, err_choose);
! }
!
! err_dfile()
! {
! return glob_dfile("error", err_deliver, err_args, TRUE);
! }
!
! /*----------------------------------------------------------------------
! * Execute a global delivery file given description of delivery file,
! * its path, a function to get arguments, and a boolean to indicate whether
! * a lack of output is a normal condition.
! * Return 1 (executed), 0 (not executed), -1 (no attempt made).
! */
!
! glob_dfile(desc, dfile, args, silent_ok)
! char *desc;
! char *dfile;
! char **(*args)();
! int silent_ok;
! {
! char **fav;
! int fac;
!
! /*
! * If the delivery file is missing, forget it.
! */
!
! if (!exists(relpath(eff_ct->ct_home, dfile)))
! {
! if (verbose)
! message("no %s delivery file\n", desc);
return -1;
}
***************
*** 146,150 ****
{
if (verbose)
! message("post-user delivery file disabled\n");
return -1;
}
--- 196,200 ----
{
if (verbose)
! message("%s delivery file disabled\n", desc);
return -1;
}
***************
*** 151,198 ****
/*
! * Generate the delivery file argument list.
*/
! num_dests = 0;
! for (d = first_dest(); d; d = next_dest(d))
! ++num_dests;
! fav = (char **) zalloc((num_dests + 3) * sizeof(char *));
! fav[0] = shell;
! fav[1] = post_deliver;
! fac = 2;
for (d = first_dest(); d; d = next_dest(d))
{
! if ((d->d_class == CL_USER || d->d_class == CL_UUCP)
! && (d->d_state == ST_WORKING
! || (d->d_state == ST_ERROR && d->d_error == E_NSUSER)))
! {
fav[fac++] = d->d_name;
- d->d_state = ST_HOLD;
- }
}
! fav[fac] = NULL;
!
! if (fac > 2)
{
! /*
! * If we get nothing back from the post-user delivery file,
! * put the message in the "undelivered" mailbox.
! */
!
! if (do_dfile(eff_ct, fav, (DEST *)NULL) == 0)
! {
! if (verbose)
! message("post_dfile: no output\n");
!
! (void) dest(eff_ct->ct_name, MBX_UNDEL);
! }
}
! free((char *) fav);
!
! return 0;
}
--- 201,274 ----
/*
! * Now we can get the argument list.
! * If the list is empty, that's all she wrote.
*/
! if ((fav = (*args)(&fac)) == NULL)
! return 0;
!
! /*
! * "Just do it."
! * If we get nothing back from the delivery file,
! * and if silence is not supposed to be permitted,
! * put the message in the "undelivered" mailbox.
! */
!
! if (run_dfile(eff_ct, dfile, fac, fav, (DEST *)NULL) <= 0
! && !silent_ok)
! {
! if (verbose)
! message("%s delivery file: no output\n", desc);
! dest_undel(eff_ct->ct_name);
! }
!
! /*
! * The argument function allocated the arguments; we free them.
! */
!
! free((char *) fav);
!
! /*
! * Return "done".
! */
!
! return 1;
! }
!
! /*----------------------------------------------------------------------
! * Generate a delivery file argument list.
! * We do this by getting an array of all destinations,
! * then keeping only the ones we want.
! */
!
! char **
! choose_args(pac, choose)
! int *pac;
! int (*choose)();
! {
! DEST *d;
! char **fav;
! int count, fac;
!
! if ((count = dest_count()) <= 0)
! return NULL;
! fav = (char **) zalloc(count * sizeof(char *));
! fac = 0;
for (d = first_dest(); d; d = next_dest(d))
{
! if ((*choose)(d))
fav[fac++] = d->d_name;
}
! if (fac <= 0)
{
! free((char *) fav);
! fav = NULL;
}
! *pac = fac;
! return fav;
}
***************
*** 199,202 ****
--- 275,279 ----
/*----------------------------------------------------------------------
* Filter all user destinations through their local delivery files.
+ * Return 1 (some executed), 0 (none executed), -1 (no attempt made).
*/
***************
*** 204,208 ****
{
DEST *d;
! int nfound;
/*
--- 281,285 ----
{
DEST *d;
! int nfound, ret;
/*
***************
*** 214,222 ****
if (verbose)
message("user delivery files disabled\n");
-
return -1;
}
-
/*
* Continue to loop through all addresses until no destination
--- 291,297 ----
***************
*** 224,227 ****
--- 299,303 ----
*/
+ ret = 0;
do {
nfound = 0;
***************
*** 232,237 ****
&& !d->d_dfdone)
{
! one_dfile(d);
d->d_dfdone = TRUE;
}
}
--- 308,314 ----
&& !d->d_dfdone)
{
! u_dfile(d);
d->d_dfdone = TRUE;
+ ret = 1;
}
}
***************
*** 238,254 ****
} while (nfound > 0);
! return 0;
}
/*----------------------------------------------------------------------
! * Run the delivery file (if any) for the specified destination.
*/
! one_dfile(d)
DEST *d;
{
- CONTEXT *ct;
- char *s, *udel_path, *fav[4];
struct stat st;
if ((ct = name_context(d->d_name)) == NULL)
--- 315,332 ----
} while (nfound > 0);
! return ret;
}
/*----------------------------------------------------------------------
! * Run the user delivery file (if any) for the specified destination.
*/
! u_dfile(d)
DEST *d;
{
struct stat st;
+ CONTEXT *ct;
+ char *s, *udel_path;
+ int n;
if ((ct = name_context(d->d_name)) == NULL)
***************
*** 304,325 ****
/*
* Time to run the file!
*/
! fav[0] = shell;
! fav[1] = udel_path;
! fav[2] = d->d_name;
! fav[3] = NULL;
!
! if (do_dfile(ct, fav, d) == 0)
! {
! /*
! * If we get nothing back from the user delivery file,
! * put the message in the user's "undelivered" mailbox.
! */
!
! if (verbose)
! message("one_dfile: no output\n");
!
! (void) dest(ct->ct_name, MBX_UNDEL);
}
--- 382,396 ----
/*
* Time to run the file!
+ * If we get nothing back from the user delivery file,
+ * put the message in the user's "undelivered" mailbox--
+ * or ours, depending on the kind of failure.
*/
! n = run_dfile(ct, udel_path, 1, &d->d_name, d);
! if (n <= 0)
! {
! if (verbose)
! message("u_dfile: no output\n");
! dest_undel((n == 0 ? ct : eff_ct)->ct_name);
}
***************
*** 328,332 ****
/*----------------------------------------------------------------------
! * 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.
--- 399,403 ----
/*----------------------------------------------------------------------
! * Execute a delivery file (global or user).
* Return the count of valid destinations we got back from it.
* If delivering to MBX_UNDEL is possible, errors return zero.
***************
*** 335,346 ****
int
! do_dfile(ct, av, d)
CONTEXT *ct;
! char **av;
DEST *d;
{
FILE *fp;
! char *name, *mailbox;
! int count;
if (!ct)
--- 406,420 ----
int
! run_dfile(ct, dfile, fac, fav, d)
CONTEXT *ct;
! char *dfile;
! int fac;
! char **fav;
DEST *d;
{
FILE *fp;
! char **av;
! int ac, a, fd, linecount;
! static char buf[BUFSIZ];
if (!ct)
***************
*** 347,351 ****
return -1;
! if (! ok_context(ct))
{
if (d)
--- 421,425 ----
return -1;
! if (! ok_context(eff_uid, real_uid, real_gid, ct))
{
if (d)
***************
*** 382,385 ****
--- 456,514 ----
}
+ /* Produce the arguments in the form we need. */
+
+ av = (char **) zalloc((fac + 4) * sizeof(char *));
+ ac = 0;
+
+ /* Process the "#!" hack. */
+
+ if ((fd = open(dfile, O_RDONLY)) != -1)
+ {
+ char *p;
+ int rd;
+ static char hashbang[64]; /* arbitrary */
+
+ rd = read(fd, hashbang, sizeof(hashbang) - 1);
+ (void) close(fd);
+ hashbang[rd > 0 ? rd : 0] = 0;
+
+ if ((p = strchr(hashbang, '\n')) != NULL
+ && hashbang[0] == '#'
+ && hashbang[1] == '!')
+ {
+ *p = 0;
+
+ /* Interpreter. */
+
+ p = hashbang + 2;
+ while (isspace(*p))
+ ++p;
+ av[ac++] = p;
+ while (*p && !isspace(*p))
+ ++p;
+ if (*p)
+ *p++ = 0;
+
+ /* Only one argument; sorry. */
+
+ while (isspace(*p))
+ ++p;
+ if (*p)
+ av[ac++] = p;
+ }
+ }
+
+ /*
+ * If no "#!" found, use the default shell.
+ * Then add the delivery file, address(es), and a NULL.
+ */
+
+ if (ac == 0)
+ av[ac++] = shell;
+ av[ac++] = dfile;
+ for (a = 0; a < fac; ++a)
+ av[ac++] = fav[a];
+ av[ac] = NULL;
+
/* Here we go! */
***************
*** 387,391 ****
message("Processing delivery file as %s\n", ct->ct_name);
! if ((fp = ct_popenv(ct, shell, av, "r")) == NULL)
{
error("can't execute delivery file as %s\n", ct->ct_name);
--- 516,528 ----
message("Processing delivery file as %s\n", ct->ct_name);
! fp = ct_fopenv(ct, av[0], av, "r");
!
! /* We don't need the argument vector any more. */
!
! free((char *) av);
!
! /* If something went wrong, bail out now. */
!
! if (fp == NULL)
{
error("can't execute delivery file as %s\n", ct->ct_name);
***************
*** 397,503 ****
*/
! count = 0;
! while (dfile_gets(fp, &name, &mailbox) >= 0)
{
! DEST *nd;
!
! ++count;
! if (strcmp(name, DFILE_DROP) == 0)
{
! if (verbose)
! message("delivery file says OK to drop\n");
! continue;
! }
! nd = dest(name, mailbox);
! if (nd->d_state == ST_HOLD)
! nd->d_state = ST_WORKING;
!
! /*
! * If the delivery file specified a mailbox, verify
! * that the user whose delivery file is running has
! * permissions for the requested context.
! */
!
! if ((nd->d_state == ST_WORKING) && (mailbox != NULL))
! {
! CONTEXT *nct;
! if ((nct = name_context(name)) == NULL)
! dest_err(nd, E_CTLOST);
! else if (! ok_context(nct))
! dest_err(nd, E_CTPERM);
}
! if (nd->d_state != ST_ERROR)
! ++count;
! }
!
! (void) ct_pclose(fp);
! return count;
! }
! /*----------------------------------------------------------------------
! * Get and parse a single delivery file output line.
! */
! int
! dfile_gets(fp, namep, mailboxp)
! FILE *fp;
! char **namep;
! char **mailboxp;
! {
! char *p, *q;
! static char buf[BUFSIZ];
! if (fgets(buf, GETSIZE(buf), fp) == NULL)
! return -1;
! if ((p = strchr(buf, '\n')) != NULL)
! *p = 0;
! else
! {
! int c;
! while ((c = fgetc(fp)) != '\n' && c != EOF)
! ; /* keep reading */
! error("invalid line from delivery file: '%s'\n", buf);
! return -1;
! }
! /* Strip out all whitespace and eliminate duplicated slashes */
! p = q = buf;
! while (*p)
! {
! if (isspace(*p))
! ++p;
! else if ((*q++ = *p++) == '/')
! {
! while (*p == '/')
! ++p;
! }
}
- *q = 0;
! /* Debugging message: display input line */
!
! if (verbose)
! message("\t'%s'\n", buf);
!
! if ((p = strchr(buf, ':')) != NULL)
! {
! *p++ = 0;
! if ((q = strchr(p, ':')) != NULL)
! *q = 0;
! }
! *namep = buf;
! *mailboxp = p;
! return 0;
}
--- 534,589 ----
*/
! linecount = 0;
! while (fgets(buf, GETSIZE(buf), fp) != NULL)
{
! DEST *nd;
! char *p;
! if ((p = strchr(buf, '\n')) != NULL)
! *p = 0;
! else
{
! int c;
! while ((c = fgetc(fp)) != '\n' && c != EOF)
! ; /* keep reading */
! error("invalid line from delivery file: '%s'\n", buf);
! continue;
}
! /* Debugging message: display input line. */
! if (verbose)
! message("\t'%s'\n", buf);
! /* Okay-to-drop directive is a special case. */
! if (strcmp(buf, DFILE_DROP) == 0)
! {
! message("\tDelivery file says OK to drop\n");
! ++linecount;
! continue;
! }
! /* Parse destination; if none, look for next line. */
! if ((nd = addr_dest(buf, ct)) == NULL)
! continue;
! /* We got some output; remember that. */
! ++linecount;
! /* If destination was on hold, it's not so anymore. */
! if (nd->d_state == ST_HOLD)
! nd->d_state = ST_WORKING;
}
! (void) ct_fclose(fp);
! return linecount;
}
Index: log.c
***************
*** 0 ****
--- 1,403 ----
+ /* $Header: log.c,v 2.2 90/03/05 17:54:53 chip Exp $
+ *
+ * Deliver logging.
+ *
+ * $Log: log.c,v $
+ * Revision 2.2 90/03/05 17:54:53 chip
+ * Create log.c from various routines throughout the code.
+ *
+ */
+
+ #include "deliver.h"
+ #include <time.h>
+
+ /*----------------------------------------------------------------------
+ * Open temporary log files.
+ */
+
+ openlogs()
+ {
+ #ifdef ERRLOG
+ /* If we're delivering and not being verbose, keep an error log. */
+
+ if (!dryrun && !verbose)
+ {
+ errlogfile = tempfile();
+ if ((errlog = ftcreate(errlogfile)) == NULL)
+ syserr("can't create %s", errlogfile);
+ }
+ #endif
+
+ #ifdef LOG
+ /* If we're delivering and the log file exists, keep data for it. */
+
+ if (!dryrun && exists(LOG))
+ {
+ logfile = tempfile();
+ if ((log = ftcreate(logfile)) == NULL)
+ syserr("can't create %s", logfile);
+ }
+ #endif
+ }
+
+ /*------------------------------------------------------------------------
+ * Discard temporary log files.
+ */
+
+ tosslogs()
+ {
+ if (logfile && unlink(logfile) == -1)
+ (void) syserr("can't remove %s", logfile);
+ if (errlogfile && unlink(errlogfile) == -1)
+ (void) syserr("can't remove %s", logfile);
+ }
+
+ /*----------------------------------------------------------------------
+ * Write a report to the log file.
+ */
+
+ logreport(ac, av)
+ int ac;
+ char **av;
+ {
+ int a;
+
+ if (!log)
+ return;
+
+ logstart(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);
+
+ logdone(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 dcount;
+
+ dcount = 0;
+ for (d = first_dest(); d; d = next_dest(d))
+ {
+ if (d->d_state != state)
+ continue;
+
+ if (++dcount == 1)
+ (void) fprintf(log, "%s:", desc);
+ (void) fprintf(log, " %s", d->d_name);
+ if (d->d_class == CL_MBOX)
+ (void) fprintf(log, ":%s", d->d_param);
+ else if (d->d_class == CL_PROG)
+ (void) fprintf(log, "|\"%s\"", d->d_param);
+ }
+ if (dcount)
+ (void) fputc('\n', log);
+ }
+
+ /*----------------------------------------------------------------------
+ * Save contents of temporary logs in the real logfiles.
+ */
+
+ savelogs()
+ {
+ /* If logs weren't kept, forget it. */
+
+ if (!log && !errlog)
+ return;
+
+ /* If temporary logs contain anything, append them to real logs. */
+
+ if ((log && ftell(log) > 0)
+ || (errlog && ftell(errlog) > 0))
+ {
+ if (create_lockfile(LOGLOCK) == 0)
+ {
+ #ifdef LOG
+ applog(&log, LOG);
+ #endif
+ errdone();
+ #ifdef ERRLOG
+ applog(&errlog, ERRLOG);
+ #endif
+ (void) remove_lockfile(LOGLOCK);
+ }
+ }
+ }
+
+ /*----------------------------------------------------------------------
+ * Append a temporary log file to a real logfile.
+ * We pass a FILE **, so that it can be set to NULL when closed;
+ * this is important, since errlog is used by syserr().
+ * Note: The logfile is ass_u_med to be locked already!
+ */
+
+ applog(fpp, realfile)
+ FILE **fpp;
+ char *realfile;
+ {
+ FILE *fp = fpp ? *fpp : NULL;
+ int fd, realfd;
+
+ /* If log data weren't kept, never mind. */
+
+ if (fp == NULL)
+ return;
+
+ /* Flush buffered data. */
+
+ (void) fflush(fp);
+
+ /* If the file is empty, never mind. */
+
+ if (ftell(fp) == 0)
+ {
+ (void) fclose(fp);
+ *fpp = NULL;
+ return;
+ }
+
+ /* Get an fd and close the stream. */
+
+ if ((fd = dup(fileno(fp))) == -1)
+ {
+ syserr("can't dup log fd");
+ (void) fclose(fp);
+ *fpp = NULL;
+ return;
+ }
+ (void) fclose(fp);
+ *fpp = NULL;
+
+ /*
+ * Open the real logfile, creating it if necessary.
+ * Note that there is no race condition since the logs are locked.
+ */
+
+ #ifdef O_CREAT
+ realfd = open(realfile, O_WRONLY|O_CREAT, 0666);
+ #else
+ if ((realfd = open(realfile, O_WRONLY)) == -1)
+ realfd = creat(realfile, 0666);
+ #endif
+ if (realfd == -1)
+ syserr("can't open %s for writing", logfile);
+ else
+ {
+ /* Append the temporary log to the real log. */
+
+ (void) lseek(fd, 0L, 0);
+ (void) lseek(realfd, 0L, 2);
+ (void) copyfd(fd, realfd);
+ (void) close(realfd);
+ }
+
+ /* Close the temporary log. */
+
+ (void) close(fd);
+ }
+
+ /*----------------------------------------------------------------------
+ * 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 (ftell(errlog) > 0)
+ 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_param, 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()
+ {
+ /* If we've already written a time stamp, don't do it again. */
+
+ if (!errlog || ftell(errlog) > 0)
+ return;
+
+ /* Write a time stamp and various useful info. */
+
+ logstart(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);
+ }
+
+ /*----------------------------------------------------------------------
+ * Record the end of this process's error log entry.
+ */
+
+ errdone()
+ {
+ /* If we never wrote to the error log file, do nothing. */
+
+ if (!errlog || ftell(errlog) == 0)
+ 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");
+
+ logdone(errlog);
+ }
+
+ /*----------------------------------------------------------------------
+ * Start a log entry.
+ * Various useful info goes here -- especially a timestamp.
+ */
+
+ logstart(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);
+ else
+ (void) fputs("---", fp);
+ (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 USG
+ tzname[lt->tm_isdst ? 1 : 0]
+ #else
+ lt->tm_zone
+ #endif
+ );
+ }
+
+ /*----------------------------------------------------------------------
+ * Write a concluding marker to the given logfile.
+ * This marker separates instances of Deliver at recursion level zero.
+ */
+
+ logdone(fp)
+ FILE *fp;
+ {
+ if (rec_level == 0)
+ (void) fputs("===========================\n\n", fp);
+ }
--
Chip Salzenberg at ComDev/TCT <chip%tct at ateng.com>, <uunet!ateng!tct!chip>
"The Usenet, in a very real sense, does not exist."
More information about the Comp.sources.bugs
mailing list