/*
* mhshowsbr.c -- routines to display the contents of MIME messages
*
- * $Id$
+ * This code is Copyright (c) 2002, by the authors of nmh. See the
+ * COPYRIGHT file in the root directory of the nmh distribution for
+ * complete copyright information.
*/
#include <h/mh.h>
#include <errno.h>
#include <setjmp.h>
#include <signal.h>
-#include <zotnet/mts/mts.h>
-#include <zotnet/tws/tws.h>
+#include <h/mts.h>
+#include <h/tws.h>
#include <h/mime.h>
#include <h/mhparse.h>
+#include <h/utils.h>
+#include <sys/wait.h>
-#ifdef HAVE_SYS_WAIT_H
-# include <sys/wait.h>
-#endif
-
-/*
- * Just use sigjmp/longjmp on older machines that
- * don't have sigsetjmp/siglongjmp.
- */
-#ifndef HAVE_SIGSETJMP
-# define sigjmp_buf jmp_buf
-# define sigsetjmp(env,mask) setjmp(env)
-# define siglongjmp(env,val) longjmp(env,val)
-#endif
-
-extern int errno;
extern int debugsw;
int pausesw = 1;
static sigjmp_buf intrenv;
-/* termsbr.c */
-int SOprintf (char *, ...);
-
-/* mhparse.c */
-int pidcheck (int);
-
/* mhmisc.c */
int part_ok (CT, int);
int type_ok (CT, int);
static int show_message_rfc822 (CT, int, int);
static int show_partial (CT, int, int);
static int show_external (CT, int, int);
-static RETSIGTYPE intrser (int);
+static void intrser (int);
/*
ct = *ctp;
/* if top-level type is ok, then display message */
- if (type_ok (ct, 0))
+ if (type_ok (ct, 1))
show_single_message (ct, formsw);
}
}
{
sigset_t set, oset;
-#ifdef WAITINT
int status;
-#else
- union wait status;
-#endif
- umask (ct->c_umask);
+ /* Allow user executable bit so that temporary directories created by
+ * the viewer (e.g., lynx) are going to be accessible */
+ umask (ct->c_umask & ~(0100));
/*
* If you have a format file, then display
sigaddset (&set, SIGINT);
sigaddset (&set, SIGQUIT);
sigaddset (&set, SIGTERM);
- SIGPROCMASK (SIG_BLOCK, &set, &oset);
+ sigprocmask (SIG_BLOCK, &set, &oset);
while (wait (&status) != NOTOK) {
-#ifdef WAITINT
pidcheck (status);
-#else
- pidcheck (status.w_status);
-#endif
continue;
}
/* reset the signal mask */
- SIGPROCMASK (SIG_SETMASK, &oset, &set);
+ sigprocmask (SIG_SETMASK, &oset, &set);
xpid = 0;
flush_errors ();
int
show_content_aux (CT ct, int serial, int alternate, char *cp, char *cracked)
{
- int fd, len, buflen;
+ int fd, len, buflen, quoted;
int xstdin, xlist, xpause, xtty;
- char *bp, *file, buffer[BUFSIZ];
+ char *bp, *pp, *file, buffer[BUFSIZ];
CI ci = &ct->c_ctinfo;
if (!ct->c_ceopenfnx) {
/* get buffer ready to go */
bp = buffer;
- bp[0] = '\0';
- buflen = sizeof(buffer);
+ buflen = sizeof(buffer) - 1;
+ bp[0] = bp[buflen] = '\0';
+ quoted = 0;
/* Now parse display string */
- for ( ; *cp; cp++) {
+ for ( ; *cp && buflen > 0; cp++) {
if (*cp == '%') {
+ pp = bp;
+
switch (*++cp) {
case 'a':
/* insert parameters from Content-Type field */
case 'f':
/* insert filename containing content */
- snprintf (bp, buflen, "%s", file);
+ snprintf (bp, buflen, "'%s'", file);
+ /* since we've quoted the file argument, set things up
+ * to look past it, to avoid problems with the quoting
+ * logic below. (I know, I should figure out what's
+ * broken with the quoting logic, but..)
+ */
+ len = strlen(bp);
+ buflen -= len;
+ bp += len;
+ pp = bp;
break;
case 'p':
len = strlen (bp);
bp += len;
buflen -= len;
+
+ /* Did we actually insert something? */
+ if (bp != pp) {
+ /* Insert single quote if not inside quotes already */
+ if (!quoted && buflen) {
+ len = strlen (pp);
+ memmove (pp + 1, pp, len);
+ *pp++ = '\'';
+ buflen--;
+ bp++;
+ }
+ /* Escape existing quotes */
+ while ((pp = strchr (pp, '\'')) && buflen > 3) {
+ len = strlen (pp++);
+ memmove (pp + 3, pp, len);
+ *pp++ = '\\';
+ *pp++ = '\'';
+ *pp++ = '\'';
+ buflen -= 3;
+ bp += 3;
+ }
+ /* If pp is still set, that means we ran out of space. */
+ if (pp)
+ buflen = 0;
+ if (!quoted && buflen) {
+ *bp++ = '\'';
+ *bp = '\0';
+ buflen--;
+ }
+ }
} else {
raw:
- *bp++ = *cp;
- *bp = '\0';
- buflen--;
+ *bp++ = *cp;
+ *bp = '\0';
+ buflen--;
+
+ if (*cp == '\'')
+ quoted = !quoted;
}
}
+ if (buflen <= 0 ||
+ (ct->c_termproc && (size_t) buflen <= strlen(ct->c_termproc))) {
+ /* content_error would provide a more useful error message
+ * here, except that if we got overrun, it probably would
+ * too.
+ */
+ fprintf(stderr, "Buffer overflow constructing show command!\n");
+ return NOTOK;
+ }
+
/* use charset string to modify display method */
if (ct->c_termproc) {
char term[BUFSIZ];
else
list_switch (ct, -1, 1, 0, 0);
- if (xpause && SOprintf ("Press <return> to show content..."))
- printf ("Press <return> to show content...");
-
- if (xpause) {
+ if (xpause && isatty (fileno (stdout))) {
int intr;
SIGNAL_HANDLER istat;
+ if (SOprintf ("Press <return> to show content..."))
+ printf ("Press <return> to show content...");
+
istat = SIGNAL (SIGINT, intrser);
if ((intr = sigsetjmp (intrenv, 1)) == OK) {
fflush (stdout);
fflush (stdout);
- for (i = 0; (child_id = vfork ()) == NOTOK && i < 5; i++)
+ for (i = 0; (child_id = vfork()) == NOTOK && i < 5; i++)
sleep (5);
switch (child_id) {
case NOTOK:
sigaddset (&set, SIGINT);
sigaddset (&set, SIGQUIT);
sigaddset (&set, SIGTERM);
- SIGPROCMASK (SIG_BLOCK, &set, &oset);
+ sigprocmask (SIG_BLOCK, &set, &oset);
}
/*
for (part = m->mp_parts; part; part = part->mp_next) {
p = part->mp_part;
- if (part_ok (p, 0) && type_ok (p, 0)) {
+ if (part_ok (p, 1) && type_ok (p, 1)) {
int inneresult;
inneresult = show_switch (p, nowserial, nowalternate);
if (serial && !nowserial) {
pid_t pid;
int kids;
-#ifdef WAITINT
int status;
-#else
- union wait status;
-#endif
kids = 0;
for (part = m->mp_parts; part; part = part->mp_next) {
}
while (kids > 0 && (pid = wait (&status)) != NOTOK) {
-#ifdef WAITINT
pidcheck (status);
-#else
- pidcheck (status.w_status);
-#endif
for (part = m->mp_parts; part; part = part->mp_next) {
p = part->mp_part;
out:
if (!nowserial) {
/* reset the signal mask */
- SIGPROCMASK (SIG_SETMASK, &oset, &set);
+ sigprocmask (SIG_SETMASK, &oset, &set);
}
return result;
static int
show_multi_aux (CT ct, int serial, int alternate, char *cp)
{
- int len, buflen;
+ int len, buflen, quoted;
int xlist, xpause, xtty;
- char *bp, *file, buffer[BUFSIZ];
+ char *bp, *pp, *file, buffer[BUFSIZ];
struct multipart *m = (struct multipart *) ct->c_ctparams;
struct part *part;
CI ci = &ct->c_ctinfo;
/* get buffer ready to go */
bp = buffer;
- bp[0] = '\0';
- buflen = sizeof(buffer);
+ buflen = sizeof(buffer) - 1;
+ bp[0] = bp[buflen] = '\0';
+ quoted = 0;
/* Now parse display string */
- for ( ; *cp; cp++) {
+ for ( ; *cp && buflen > 0; cp++) {
if (*cp == '%') {
+ pp = bp;
switch (*++cp) {
case 'a':
/* insert parameters from Content-Type field */
buflen -= len;
s = " ";
}
+ /* set our starting pointer back to bp, to avoid
+ * requoting the filenames we just added
+ */
+ pp = bp;
}
break;
len = strlen (bp);
bp += len;
buflen -= len;
+
+ /* Did we actually insert something? */
+ if (bp != pp) {
+ /* Insert single quote if not inside quotes already */
+ if (!quoted && buflen) {
+ len = strlen (pp);
+ memmove (pp + 1, pp, len);
+ *pp++ = '\'';
+ buflen--;
+ bp++;
+ }
+ /* Escape existing quotes */
+ while ((pp = strchr (pp, '\'')) && buflen > 3) {
+ len = strlen (pp++);
+ memmove (pp + 3, pp, len);
+ *pp++ = '\\';
+ *pp++ = '\'';
+ *pp++ = '\'';
+ buflen -= 3;
+ bp += 3;
+ }
+ /* If pp is still set, that means we ran out of space. */
+ if (pp)
+ buflen = 0;
+ if (!quoted && buflen) {
+ *bp++ = '\'';
+ *bp = '\0';
+ buflen--;
+ }
+ }
} else {
raw:
- *bp++ = *cp;
- *bp = '\0';
- buflen--;
+ *bp++ = *cp;
+ *bp = '\0';
+ buflen--;
+
+ if (*cp == '\'')
+ quoted = !quoted;
}
}
+ if (buflen <= 0 ||
+ (ct->c_termproc && (size_t) buflen <= strlen(ct->c_termproc))) {
+ /* content_error would provide a more useful error message
+ * here, except that if we got overrun, it probably would
+ * too.
+ */
+ fprintf(stderr, "Buffer overflow constructing show command!\n");
+ return NOTOK;
+ }
+
/* use charset string to modify display method */
if (ct->c_termproc) {
char term[BUFSIZ];
static int
show_partial (CT ct, int serial, int alternate)
{
+ NMH_UNUSED (serial);
+ NMH_UNUSED (alternate);
+
content_error (NULL, ct,
"in order to display this message, you must reassemble it");
return NOTOK;
}
-static RETSIGTYPE
+static void
intrser (int i)
{
-#ifndef RELIABLE_SIGNALS
- SIGNAL (SIGINT, intrser);
-#endif
+ NMH_UNUSED (i);
putchar ('\n');
siglongjmp (intrenv, DONE);