#include <h/dropsbr.h>
#include <h/rcvmail.h>
#include <h/signals.h>
+#include <setjmp.h>
#include <h/tws.h>
#include <h/mts.h>
#include <h/utils.h>
#include <pwd.h>
-#include <signal.h>
#include <sys/ioctl.h>
#include <fcntl.h>
-#ifdef INITGROUPS_HEADER
-#include INITGROUPS_HEADER
-#else
-/* On AIX 4.1, initgroups() is defined and even documented (giving the parameter
- types as char* and int), but doesn't have a prototype in any of the system
- header files. AIX 4.3, SunOS 4.1.3, and ULTRIX 4.2A have the same
- problem. */
-extern int initgroups(char*, int);
-#endif
+/* Hopefully, grp.h declares initgroups(). If we run into a platform
+ where it doesn't, we could consider declaring it here as well. */
+#include <grp.h>
/* This define is needed for Berkeley db v2 and above to
* make the header file expose the 'historical' ndbm APIs.
* harmless.
*/
#define DB_DBM_HSEARCH 1
+#ifdef DB_DBM_HSEARCH
+#endif /* Use DB_DBM_HSEARCH to prevent warning from gcc -Wunused-macros. */
#ifdef NDBM_HEADER
#include NDBM_HEADER
#endif
-#include <utmp.h>
-
-#ifndef HAVE_GETUTENT
-# ifndef UTMP_FILE
-# ifdef _PATH_UTMP
-# define UTMP_FILE _PATH_UTMP
-# else
-# define UTMP_FILE "/etc/utmp"
-# endif
-# endif
-#endif
-
-static struct swit switches[] = {
-#define ADDRSW 0
- { "addr address", 0 },
-#define USERSW 1
- { "user name", 0 },
-#define FILESW 2
- { "file file", 0 },
-#define SENDERSW 3
- { "sender address", 0 },
-#define MAILBOXSW 4
- { "mailbox file", 0 },
-#define HOMESW 5
- { "home directory", -4 },
-#define INFOSW 6
- { "info data", 0 },
-#define MAILSW 7
- { "maildelivery file", 0 },
-#define VERBSW 8
- { "verbose", 0 },
-#define NVERBSW 9
- { "noverbose", 0 },
-#define SUPPRESSDUP 10
- { "suppressdup", 0 },
-#define NSUPPRESSDUP 11
- { "nosuppressdup", 0 },
-#define DEBUGSW 12
- { "debug", 0 },
-#define VERSIONSW 13
- { "version", 0 },
-#define HELPSW 14
- { "help", 0 },
- { NULL, 0 }
-};
+#ifdef HAVE_GETUTXENT
+#include <utmpx.h>
+#endif /* HAVE_GETUTXENT */
+
+#define SLOCAL_SWITCHES \
+ X("addr address", 0, ADDRSW) \
+ X("user name", 0, USERSW) \
+ X("file file", 0, FILESW) \
+ X("sender address", 0, SENDERSW) \
+ X("mailbox file", 0, MAILBOXSW) \
+ X("home directory", -4, HOMESW) \
+ X("info data", 0, INFOSW) \
+ X("maildelivery file", 0, MAILSW) \
+ X("verbose", 0, VERBSW) \
+ X("noverbose", 0, NVERBSW) \
+ X("suppressdup", 0, SUPPRESSDUP) \
+ X("nosuppressdup", 0, NSUPPRESSDUP) \
+ X("debug", 0, DEBUGSW) \
+ X("version", 0, VERSIONSW) \
+ X("help", 0, HELPSW) \
+
+#define X(sw, minchars, id) id,
+DEFINE_SWITCH_ENUM(SLOCAL);
+#undef X
+
+#define X(sw, minchars, id) { sw, minchars, id },
+DEFINE_SWITCH_ARRAY(SLOCAL, switches);
+#undef X
static int globbed = 0; /* have we built "vars" table yet? */
static int parsed = 0; /* have we built header field table yet */
static int usr_file (int, char *, int);
static int usr_pipe (int, char *, char *, char **, int);
static int usr_folder (int, char *);
-static RETSIGTYPE alrmser (int);
+static void alrmser (int);
static void get_sender (char *, char **);
static int copy_message (int, char *, int);
static void verbose_printf (char *fmt, ...);
main (int argc, char **argv)
{
int fd, status;
- FILE *fp = stdin;
+ FILE *fp;
char *cp, *mdlvr = NULL, buf[BUFSIZ];
char mailbox[BUFSIZ], tmpfil[BUFSIZ];
char **argp, **arguments;
-#ifdef LOCALE
- setlocale(LC_ALL, "");
-#endif
- invo_name = r1bindex (*argv, '/');
-
- /* foil search of user profile/context */
- if (context_foil (NULL) == -1)
- done (1);
+ if (nmh_init(argv[0], 0 /* use context_foil() */)) { return 1; }
- mts_init (invo_name);
+ mts_init ();
arguments = getarguments (invo_name, argc, argv, 0);
argp = arguments;
adios (NULL, "-%s unknown", cp);
case HELPSW:
- snprintf (buf, sizeof(buf),
- "%s [switches] [address info sender]", invo_name);
+ snprintf (buf, sizeof(buf), "%s [switches]", invo_name);
print_help (buf, switches, 0);
- done (1);
+ done (0);
case VERSIONSW:
print_version(invo_name);
- done (1);
+ done (0);
case ADDRSW:
if (!(addr = *argp++))/* allow -xyz arguments */
debug++;
continue;
}
- }
-
- switch (argp - (argv + 1)) {
- case 1:
- addr = cp;
- break;
-
- case 2:
- info = cp;
- break;
-
- case 3:
- sender = cp;
- break;
+ } else {
+ adios (NULL, "only switch arguments are supported");
}
}
if (addr == NULL)
addr = getusername ();
- if (user == NULL)
- user = (cp = strchr(addr, '.')) ? ++cp : addr;
+ if (user == NULL) {
+ user = getusername ();
+ }
if ((pw = getpwnam (user)) == NULL)
adios (NULL, "no such local user as %s", user);
if (chdir (pw->pw_dir) == -1)
- chdir ("/");
+ if (chdir ("/") < 0) {
+ advise ("/", "chdir");
+ }
umask (0077);
if (geteuid() == 0) {
- setgid (pw->pw_gid);
+ if (setgid (pw->pw_gid) != 0) {
+ adios ("setgid", "unable to set group to %ld", (long) pw->pw_gid);
+ }
initgroups (pw->pw_name, pw->pw_gid);
- setuid (pw->pw_uid);
+ if (setuid (pw->pw_uid) != 0) {
+ adios ("setuid", "unable to set user to %ld", (long) pw->pw_uid);
+ }
}
-
+
if (info == NULL)
info = "";
if (debug)
debug_printf ("retrieving message from file \"%s\"\n", file);
if ((fd = copy_message (tempfd, tmpfil, 1)) == -1)
- adios (NULL, "unable to create temporary file");
+ adios(NULL, "unable to create temporary file in %s",
+ get_temp_dir());
close (tempfd);
} else {
/* getting message from stdin */
if (debug)
debug_printf ("retrieving message from stdin\n");
if ((fd = copy_message (fileno (stdin), tmpfil, 1)) == -1)
- adios (NULL, "unable to create temporary file");
+ adios(NULL, "unable to create temporary file in %s",
+ get_temp_dir());
}
if (debug)
thing would be to delay this unlink() until later if debug == 1, but I'll
leave that for someone who cares about the temp-file-accessing
functionality (they'll have to watch out for cases where we adios()). */
- unlink (tmpfil);
+ (void) m_unlink (tmpfil);
if (!(fp = fdopen (fd, "r+")))
adios (NULL, "unable to access temporary file");
verbose_printf ("(delivering to standard mail spool)\n");
/* last resort - deliver to standard mail spool */
-#ifdef SLOCAL_MBOX
return usr_file (fd, mbox, MBOX_FORMAT);
-#else
- return usr_file (fd, mbox, MMDF_FORMAT);
-#endif
}
int i, accept, status=1, won, vecp, next;
char *field, *pattern, *action, *result, *string;
char buffer[BUFSIZ], tmpbuf[BUFSIZ];
- char *cp, *vec[NVEC];
+ char *vec[NVEC];
struct stat st;
struct pair *p;
FILE *fp;
if (*buffer == '#' || *buffer == '\n')
continue;
- /* zap trailing newline */
- if ((cp = strchr(buffer, '\n')))
- *cp = 0;
+ TrimSuffixC(buffer, '\n');
/* split buffer into fields */
vecp = split (buffer, vec);
}
if (vecp > 5) {
- if (!mh_strcasecmp (vec[5], "select")) {
+ if (!strcasecmp (vec[5], "select")) {
if (logged_in () != -1)
continue;
if (vecp > 7 && timely (vec[6], vec[7]) == -1)
* "default" matches only if the message hasn't
* been delivered yet.
*/
- if (!mh_strcasecmp (field, "default")) {
+ if (!strcasecmp (field, "default")) {
if (won)
continue;
break;
switch (*action) {
case 'q':
/* deliver to quoted pipe */
- if (mh_strcasecmp (action, "qpipe"))
+ if (strcasecmp (action, "qpipe"))
continue; /* else fall */
case '^':
expand (tmpbuf, string, fd);
case 'p':
/* deliver to pipe */
- if (mh_strcasecmp (action, "pipe"))
+ if (strcasecmp (action, "pipe"))
continue; /* else fall */
case '|':
vec[2] = "sh";
case 'f':
/* mbox format */
- if (!mh_strcasecmp (action, "file")) {
+ if (!strcasecmp (action, "file")) {
status = usr_file (fd, string, MBOX_FORMAT);
break;
}
/* deliver to nmh folder */
- else if (mh_strcasecmp (action, "folder"))
+ else if (strcasecmp (action, "folder"))
continue; /* else fall */
case '+':
status = usr_folder (fd, string);
case 'm':
/* mmdf format */
- if (!mh_strcasecmp (action, "mmdf")) {
+ if (!strcasecmp (action, "mmdf")) {
status = usr_file (fd, string, MMDF_FORMAT);
break;
}
/* mbox format */
- else if (mh_strcasecmp (action, "mbox"))
+ else if (strcasecmp (action, "mbox"))
continue; /* else fall */
case '>':
case 'd':
/* ignore message */
- if (mh_strcasecmp (action, "destroy"))
+ if (strcasecmp (action, "destroy"))
continue;
status = 0;
break;
split (char *cp, char **vec)
{
int i;
- unsigned char *s;
+ char *s;
s = cp;
vec[i] = NULL;
/* zap any whitespace and comma's */
- while (isspace (*s) || *s == ',')
+ while (isspace ((unsigned char) *s) || *s == ',')
*s++ = 0;
/* end of buffer, time to leave */
vec[i++] = s++;
/* move forward to next field delimiter */
- while (*s && !isspace (*s) && *s != ',')
+ while (*s && !isspace ((unsigned char) *s) && *s != ',')
s++;
}
vec[i] = NULL;
char name[NAMESZ], field[BUFSIZ];
struct pair *p, *q;
FILE *in;
+ m_getfld_state_t gstate = 0;
if (parsed++)
return 0;
* Scan the headers of the message and build
* a lookup table.
*/
- for (i = 0, state = FLD;;) {
- switch (state = m_getfld (state, name, field, sizeof(field), in)) {
+ for (i = 0;;) {
+ int fieldsz = sizeof field;
+ switch (state = m_getfld (&gstate, name, field, &fieldsz, in)) {
case FLD:
- case FLDEOF:
case FLDPLUS:
lp = add (field, NULL);
while (state == FLDPLUS) {
- state = m_getfld (state, name, field, sizeof(field), in);
+ fieldsz = sizeof field;
+ state = m_getfld (&gstate, name, field, &fieldsz, in);
lp = add (field, lp);
}
for (p = hdrs; p->p_name; p++) {
- if (!mh_strcasecmp (p->p_name, name)) {
+ if (!strcasecmp (p->p_name, name)) {
if (!(p->p_flags & P_HID)) {
if ((cp = p->p_value)) {
if (p->p_flags & P_ADR) {
}
}
if (p->p_name == NULL && i < NVEC) {
- p->p_name = getcpy (name);
+ p->p_name = mh_xstrdup(name);
p->p_value = lp;
p->p_flags = P_NIL;
p++, i++;
p->p_name = NULL;
}
- if (state != FLDEOF)
- continue;
- break;
+ continue;
case BODY:
- case BODYEOF:
case FILEEOF:
break;
}
break;
}
+ m_getfld_state_destroy (&gstate);
fclose (in);
if ((p = lookup (vars, "reply-to"))) {
if ((p = lookup (vars, "size"))) {
snprintf (buffer, sizeof(buffer), "%d",
fstat (fd, &st) != -1 ? (int) st.st_size : 0);
- p->p_value = getcpy (buffer);
+ p->p_value = mh_xstrdup(buffer);
}
if ((p = lookup (vars, "info")))
p->p_value = getcpy (info);
lookup (struct pair *pairs, char *key)
{
for (; pairs->p_name; pairs++)
- if (!mh_strcasecmp (pairs->p_name, key))
+ if (!strcasecmp (pairs->p_name, key))
return pairs;
return NULL;
* logged in.
*/
-#ifdef HAVE_GETUTENT
static int
logged_in (void)
{
- struct utmp * utp;
+#if HAVE_GETUTXENT
+ struct utmpx *utp;
if (utmped)
return utmped;
- setutent();
+ setutxent();
- while ((utp = getutent()) != NULL) {
- if (
-#ifdef HAVE_STRUCT_UTMP_UT_TYPE
- utp->ut_type == USER_PROCESS
- &&
-#endif
- utp->ut_name[0] != 0
- && strncmp (user, utp->ut_name, sizeof(utp->ut_name)) == 0) {
+ while ((utp = getutxent()) != NULL) {
+ if ( utp->ut_type == USER_PROCESS && utp->ut_user[0] != 0
+ && strncmp (user, utp->ut_user, sizeof(utp->ut_user)) == 0) {
if (debug)
continue;
- endutent();
+ endutxent();
return (utmped = DONE);
}
}
- endutent();
+ endutxent();
+#endif /* HAVE_GETUTXENT */
return (utmped = NOTOK);
}
-#else
-static int
-logged_in (void)
-{
- struct utmp ut;
- FILE *uf;
-
- if (utmped)
- return utmped;
-
- if ((uf = fopen (UTMP_FILE, "r")) == NULL)
- return NOTOK;
-
- while (fread ((char *) &ut, sizeof(ut), 1, uf) == 1) {
- if (ut.ut_name[0] != 0
- && strncmp (user, ut.ut_name, sizeof(ut.ut_name)) == 0) {
- if (debug)
- continue;
- fclose (uf);
- return (utmped = DONE);
- }
- }
-
- fclose (uf);
- return (utmped = NOTOK);
-}
-#endif
#define check(t,a,b) if (t < a || t > b) return -1
#define cmpar(h1,m1,h2,m2) if (h1 < h2 || (h1 == h2 && m1 < m2)) return 0
/* use rcvstore to put message in folder */
status = usr_pipe (fd, "rcvstore", rcvstoreproc, vec, 1);
-#if 0
- /*
- * Currently, verbose status messages are handled by usr_pipe().
- */
- if (verbose) {
- if (status == 0)
- verbose_printf (", success.\n");
- else
- verbose_printf (", failed.\n");
- }
-#endif
-
return status;
}
*/
static int
-usr_pipe (int fd, char *cmd, char *pgm, char **vec, int suppress)
+usr_pipe (int fd_arg, char *cmd, char *pgm, char **vec, int suppress)
{
+ volatile int fd = fd_arg;
pid_t child_id;
int i, bytes, seconds, status;
struct stat st;
/* child process */
if (fd != 0)
dup2 (fd, 0);
- freopen ("/dev/null", "w", stdout);
- freopen ("/dev/null", "w", stderr);
+ if (freopen ("/dev/null", "w", stdout) == NULL) {
+ advise ("stdout", "freopen");
+ }
+ if (freopen ("/dev/null", "w", stderr) == NULL) {
+ advise ("stderr", "freopen");
+ }
if (fd != 3)
dup2 (fd, 3);
closefds (4);
default:
/* parent process */
- if (!setjmp (myctx)) {
+ if (! setjmp (myctx)) {
SIGNAL (SIGALRM, alrmser);
bytes = fstat (fd, &st) != -1 ? (int) st.st_size : 100;
pidstatus (status, stdout, ", failed");
}
return (status == 0 ? 0 : -1);
- } else {
- /*
- * Ruthlessly kill the child and anything
- * else in its process group.
- */
- killpg(child_id, SIGKILL);
- if (verbose)
- verbose_printf (", timed-out; terminated\n");
- return -1;
}
+ /*
+ * Ruthlessly kill the child and anything
+ * else in its process group.
+ */
+ killpg(child_id, SIGKILL);
+ if (verbose)
+ verbose_printf (", timed-out; terminated\n");
+ return -1;
}
}
-static RETSIGTYPE
+static void
alrmser (int i)
{
-#ifndef RELIABLE_SIGNALS
- SIGNAL (SIGALRM, alrmser);
-#endif
+ NMH_UNUSED (i);
longjmp (myctx, DONE);
}
get_sender (char *envelope, char **sender)
{
int i;
- unsigned char *cp;
- unsigned char buffer[BUFSIZ];
+ char *cp;
+ char buffer[BUFSIZ];
if (envelope == NULL) {
- *sender = getcpy ("");
+ *sender = mh_xstrdup("");
return;
}
- i = strlen ("From ");
+ i = LEN("From ");
strncpy (buffer, envelope + i, sizeof(buffer));
if ((cp = strchr(buffer, '\n'))) {
*cp = 0;
*cp = 0;
for (cp = buffer + strlen (buffer) - 1; cp >= buffer; cp--)
- if (isspace (*cp))
+ if (isspace ((unsigned char) *cp))
*cp = 0;
else
break;
- *sender = getcpy (buffer);
+ *sender = mh_xstrdup(buffer);
}
tfile = m_mktemp2(NULL, invo_name, &fd1, NULL);
if (tfile == NULL) return -1;
- fchmod(fd1, 0600);
strncpy (tmpfil, tfile, BUFSIZ);
if (!fold) {
if (write (fd1, buffer, i) != i) {
you_lose:
close (fd1);
- unlink (tmpfil);
+ (void) m_unlink (tmpfil);
return -1;
}
if (i == -1)
* and massage the headers. Save
* a copy of the "From " line for later.
*/
- i = strlen ("From ");
+ i = LEN("From ");
while (fgets (buffer, sizeof(buffer), qfp)) {
if (first) {
first = 0;
if (!strncmp (buffer, "From ", i)) {
/* get copy of envelope information ("From " line) */
- envelope = getcpy (buffer);
-
-#if 0
- /* First go ahead and put "From " line in message */
- fputs (buffer, ffp);
- if (ferror (ffp))
- goto fputs_error;
-#endif
+ envelope = mh_xstrdup(buffer);
/* Put the delivery date in message */
fputs (ddate, ffp);
trim (char *cp)
{
char buffer[BUFSIZ*4];
- unsigned char *bp, *sp;
+ char *bp, *sp;
if (cp == NULL)
return NULL;
bp = buffer;
/* skip over leading whitespace */
- while (isspace(*bp))
+ while (isspace((unsigned char) *bp))
bp++;
/* start at the end and zap trailing whitespace */
for (sp = bp + strlen(bp) - 1; sp >= bp; sp--) {
- if (isspace(*sp))
+ if (isspace((unsigned char) *sp))
*sp = 0;
else
break;
/* replace remaining whitespace with spaces */
for (sp = bp; *sp; sp++)
- if (isspace(*sp))
+ if (isspace((unsigned char) *sp))
*sp = ' ';
/* now return a copy */
- return getcpy(bp);
+ return mh_xstrdup(bp);
}
/*
datum key, value;
DBM *db;
FILE *in;
+ m_getfld_state_t gstate = 0;
if ((fd1 = dup (fd)) == -1)
return -1;
}
rewind (in);
- for (state = FLD;;) {
- state = m_getfld (state, name, buf, sizeof(buf), in);
+ for (;;) {
+ int failed_to_lock = 0;
+ int bufsz = sizeof buf;
+ state = m_getfld (&gstate, name, buf, &bufsz, in);
switch (state) {
case FLD:
case FLDPLUS:
- case FLDEOF:
/* Search for the message ID */
- if (mh_strcasecmp (name, "Message-ID")) {
- while (state == FLDPLUS)
- state = m_getfld (state, name, buf, sizeof(buf), in);
+ if (strcasecmp (name, "Message-ID")) {
+ while (state == FLDPLUS) {
+ bufsz = sizeof buf;
+ state = m_getfld (&gstate, name, buf, &bufsz, in);
+ }
continue;
}
cp = add (buf, NULL);
while (state == FLDPLUS) {
- state = m_getfld (state, name, buf, sizeof(buf), in);
+ bufsz = sizeof buf;
+ state = m_getfld (&gstate, name, buf, &bufsz, in);
cp = add (buf, cp);
}
key.dptr = trimcpy (cp);
* This will fail if your Maildelivery file doesn't
* exist.
*/
- if ((lockfd = lkopen(file, O_RDWR, 0)) == -1) {
+ if ((lockfd = lkopendata(file, O_RDWR, 0, &failed_to_lock))
+ == -1) {
advise (file, "unable to perform file locking on");
free (cp);
fclose (in);
}
dbm_close (db);
- lkclose(lockfd, file);
+ lkclosedata(lockfd, file);
free (cp);
fclose (in);
return result;
- break;
case BODY:
- case BODYEOF:
case FILEEOF:
break;
break;
}
+ m_getfld_state_destroy (&gstate);
fclose (in);
return 0;