X-Git-Url: http://git.marmaro.de/?p=mmh;a=blobdiff_plain;f=uip%2Fmhshowsbr.c;h=9f69c54da73afab625cc344590c95f4d0f7097cf;hp=ef6f02c17459c9dfe6632b37bb0fe74ca0b3b3e4;hb=dfa0332c4e6144699dedd5c9795219adc0f9c0d2;hpb=2da3024caea2be71550f9eabd2fbc08fefe29bb5 diff --git a/uip/mhshowsbr.c b/uip/mhshowsbr.c index ef6f02c..9f69c54 100644 --- a/uip/mhshowsbr.c +++ b/uip/mhshowsbr.c @@ -1,9 +1,10 @@ - /* - * mhshowsbr.c -- routines to display the contents of MIME messages - * - * $Id$ - */ +** mhshowsbr.c -- routines to display the contents of MIME messages +** +** 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 #include @@ -12,1005 +13,1065 @@ #include #include #include -#include -#include +#include #include #include +#include #ifdef HAVE_SYS_WAIT_H # include #endif /* - * Just use sigjmp/longjmp on older machines that - * don't have sigsetjmp/siglongjmp. - */ +** 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; int serialsw = 0; int nolist = 0; - -char *progsw = NULL; - -/* flags for moreproc/header display */ -int nomore = 0; char *formsw = NULL; - pid_t xpid = 0; -static sigjmp_buf intrenv; - - -/* termsbr.c */ -int SOprintf (char *, ...); /* mhparse.c */ -int pidcheck (int); +int pidcheck(int); /* mhmisc.c */ -int part_ok (CT, int); -int type_ok (CT, int); -void content_error (char *, CT, char *, ...); -void flush_errors (void); +int part_ok(CT, int); +int type_ok(CT, int); +void content_error(char *, CT, char *, ...); +void flush_errors(void); /* mhlistsbr.c */ -int list_switch (CT, int, int, int, int); -int list_content (CT, int, int, int, int); +int list_switch(CT, int, int, int, int); +int list_content(CT, int, int, int, int); /* - * prototypes - */ -void show_all_messages (CT *); -int show_content_aux (CT, int, int, char *, char *); +** prototypes +*/ +void show_all_messages(CT *); +int show_content_aux(CT, int, int, char *, char *); /* - * static prototypes - */ -static void show_single_message (CT, char *); -static void DisplayMsgHeader (CT, char *); -static int show_switch (CT, int, int); -static int show_content (CT, int, int); -static int show_content_aux2 (CT, int, int, char *, char *, int, int, int, int, int); -static int show_text (CT, int, int); -static int show_multi (CT, int, int); -static int show_multi_internal (CT, int, int); -static int show_multi_aux (CT, int, int, char *); -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 prototypes +*/ +static void show_single_message(CT, char *); +static void DisplayMsgHeader(CT, char *); +static int show_switch(CT, int, int); +static int show_content(CT, int, int); +static int show_content_aux2(CT, int, int, char *, char *, int, int, int, int); +static int show_text(CT, int, int); +static int show_multi(CT, int, int); +static int show_multi_internal(CT, int, int); +static int show_multi_aux(CT, int, int, char *); +static int show_message_rfc822(CT, int, int); +static int show_partial(CT, int, int); +static int show_external(CT, int, int); /* - * Top level entry point to show/display a group of messages - */ +** Top level entry point to show/display a group of messages +*/ void -show_all_messages (CT *cts) +show_all_messages(CT *cts) { - CT ct, *ctp; - - /* - * If form is not specified, then get default form - * for showing headers of MIME messages. - */ - if (!formsw) - formsw = getcpy (etcpath ("mhl.headers")); - - /* - * If form is "mhl.null", suppress display of header. - */ - if (!strcmp (formsw, "mhl.null")) - formsw = NULL; - - for (ctp = cts; *ctp; ctp++) { - ct = *ctp; - - /* if top-level type is ok, then display message */ - if (type_ok (ct, 0)) - show_single_message (ct, formsw); - } + CT ct, *ctp; + + /* + ** If form is not specified, then get default form + ** for showing headers of MIME messages. + */ + if (!formsw) + formsw = getcpy(etcpath("mhl.headers")); + + /* + ** If form is "mhl.null", suppress display of header. + */ + if (strcmp(formsw, "mhl.null")==0) + formsw = NULL; + + for (ctp = cts; *ctp; ctp++) { + ct = *ctp; + + /* if top-level type is ok, then display message */ + if (type_ok(ct, 1)) + show_single_message(ct, formsw); + } } /* - * Entry point to show/display a single message - */ +** Entry point to show/display a single message +*/ static void -show_single_message (CT ct, char *form) +show_single_message(CT ct, char *form) { - sigset_t set, oset; + sigset_t set, oset; -#ifdef WAITINT - int status; +#ifdef HAVE_UNION_WAIT + union wait status; #else - union wait status; + int 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 - * the message headers. - */ - if (form) - DisplayMsgHeader(ct, form); - else - xpid = 0; + /* + ** If you have a format file, then display + ** the message headers. + */ + if (form) + DisplayMsgHeader(ct, form); + else + xpid = 0; + + /* Show the body of the message */ + show_switch(ct, 1, 0); - /* Show the body of the message */ - show_switch (ct, 1, 0); - - if (ct->c_fp) { - fclose (ct->c_fp); - ct->c_fp = NULL; - } - if (ct->c_ceclosefnx) - (*ct->c_ceclosefnx) (ct); - - /* block a few signals */ - sigemptyset (&set); - sigaddset (&set, SIGHUP); - sigaddset (&set, SIGINT); - sigaddset (&set, SIGQUIT); - sigaddset (&set, SIGTERM); - SIGPROCMASK (SIG_BLOCK, &set, &oset); - - while (wait (&status) != NOTOK) { -#ifdef WAITINT - pidcheck (status); + if (ct->c_fp) { + fclose(ct->c_fp); + ct->c_fp = NULL; + } + if (ct->c_ceclosefnx) + (*ct->c_ceclosefnx) (ct); + + /* block a few signals */ + sigemptyset(&set); + sigaddset(&set, SIGHUP); + sigaddset(&set, SIGINT); + sigaddset(&set, SIGQUIT); + sigaddset(&set, SIGTERM); + SIGPROCMASK(SIG_BLOCK, &set, &oset); + + while (wait(&status) != NOTOK) { +#ifdef HAVE_UNION_WAIT + pidcheck(status.w_status); #else - pidcheck (status.w_status); + pidcheck(status); #endif - continue; - } + continue; + } - /* reset the signal mask */ - SIGPROCMASK (SIG_SETMASK, &oset, &set); + /* reset the signal mask */ + SIGPROCMASK(SIG_SETMASK, &oset, &set); - xpid = 0; - flush_errors (); + xpid = 0; + flush_errors(); } /* - * Use the mhlproc to show the header fields - */ - +** Use mhl to show the header fields +*/ static void -DisplayMsgHeader (CT ct, char *form) +DisplayMsgHeader(CT ct, char *form) { - pid_t child_id; - int i, vecp; - char *vec[8]; - - vecp = 0; - vec[vecp++] = r1bindex (mhlproc, '/'); - vec[vecp++] = "-form"; - vec[vecp++] = form; - vec[vecp++] = "-nobody"; - vec[vecp++] = ct->c_file; - - /* - * If we've specified -(no)moreproc, - * then just pass that along. - */ - if (nomore) { - vec[vecp++] = "-nomoreproc"; - } else if (progsw) { - vec[vecp++] = "-moreproc"; - vec[vecp++] = progsw; - } - vec[vecp] = NULL; - - fflush (stdout); - - for (i = 0; (child_id = vfork()) == NOTOK && i < 5; i++) - sleep (5); - - switch (child_id) { - case NOTOK: - adios ("fork", "unable to"); - /* NOTREACHED */ - - case OK: - execvp (mhlproc, vec); - fprintf (stderr, "unable to exec "); - perror (mhlproc); - _exit (-1); - /* NOTREACHED */ - - default: - xpid = -child_id; - break; - } + pid_t child_id; + int vecp; + char *vec[8]; + + vecp = 0; + vec[vecp++] = "mhl"; + vec[vecp++] = "-form"; + vec[vecp++] = form; + vec[vecp++] = "-nobody"; + vec[vecp++] = ct->c_file; + vec[vecp] = NULL; + + fflush(stdout); + + switch (child_id = fork()) { + case NOTOK: + adios("fork", "unable to"); + /* NOTREACHED */ + + case OK: + execvp("mhl", vec); + fprintf(stderr, "unable to exec "); + perror("mhl"); + _exit(-1); + /* NOTREACHED */ + + default: + xpid = -child_id; + break; + } } /* - * Switching routine. Call the correct routine - * based on content type. - */ +** Switching routine. Call the correct routine +** based on content type. +*/ static int -show_switch (CT ct, int serial, int alternate) +show_switch(CT ct, int serial, int alternate) { - switch (ct->c_type) { + switch (ct->c_type) { case CT_MULTIPART: - return show_multi (ct, serial, alternate); - break; + return show_multi(ct, serial, alternate); + break; case CT_MESSAGE: - switch (ct->c_subtype) { - case MESSAGE_PARTIAL: - return show_partial (ct, serial, alternate); - break; - - case MESSAGE_EXTERNAL: - return show_external (ct, serial, alternate); - break; - - case MESSAGE_RFC822: - default: - return show_message_rfc822 (ct, serial, alternate); - break; - } - break; + switch (ct->c_subtype) { + case MESSAGE_PARTIAL: + return show_partial(ct, serial, alternate); + break; + + case MESSAGE_EXTERNAL: + return show_external(ct, serial, alternate); + break; + + case MESSAGE_RFC822: + default: + return show_message_rfc822(ct, serial, + alternate); + break; + } + break; case CT_TEXT: - return show_text (ct, serial, alternate); - break; + return show_text(ct, serial, alternate); + break; case CT_AUDIO: case CT_IMAGE: case CT_VIDEO: case CT_APPLICATION: - return show_content (ct, serial, alternate); - break; + return show_content(ct, serial, alternate); + break; default: - adios (NULL, "unknown content type %d", ct->c_type); - break; - } + adios(NULL, "unknown content type %d", ct->c_type); + break; + } - return 0; /* NOT REACHED */ + return 0; /* NOT REACHED */ } /* - * Generic method for displaying content - */ +** Generic method for displaying content +*/ static int -show_content (CT ct, int serial, int alternate) +show_content(CT ct, int serial, int alternate) { - char *cp, buffer[BUFSIZ]; - CI ci = &ct->c_ctinfo; + char *cp, buffer[BUFSIZ]; + CI ci = &ct->c_ctinfo; - /* Check for mhn-show-type/subtype */ - snprintf (buffer, sizeof(buffer), "%s-show-%s/%s", - invo_name, ci->ci_type, ci->ci_subtype); - if ((cp = context_find (buffer)) && *cp != '\0') - return show_content_aux (ct, serial, alternate, cp, NULL); + /* Check for mhshow-show-type/subtype */ + snprintf(buffer, sizeof(buffer), "%s-show-%s/%s", + invo_name, ci->ci_type, ci->ci_subtype); + if ((cp = context_find(buffer)) && *cp != '\0') + return show_content_aux(ct, serial, alternate, cp, NULL); - /* Check for mhn-show-type */ - snprintf (buffer, sizeof(buffer), "%s-show-%s", invo_name, ci->ci_type); - if ((cp = context_find (buffer)) && *cp != '\0') - return show_content_aux (ct, serial, alternate, cp, NULL); + /* Check for mhshow-show-type */ + snprintf(buffer, sizeof(buffer), "%s-show-%s", invo_name, ci->ci_type); + if ((cp = context_find(buffer)) && *cp != '\0') + return show_content_aux(ct, serial, alternate, cp, NULL); - if ((cp = ct->c_showproc)) - return show_content_aux (ct, serial, alternate, cp, NULL); + if ((cp = ct->c_showproc)) + return show_content_aux(ct, serial, alternate, cp, NULL); - /* complain if we are not a part of a multipart/alternative */ - if (!alternate) - content_error (NULL, ct, "don't know how to display content"); + /* complain if we are not a part of a multipart/alternative */ + if (!alternate) + content_error(NULL, ct, "don't know how to display content"); - return NOTOK; + return NOTOK; } /* - * Parse the display string for displaying generic content - */ +** Parse the display string for displaying generic content +*/ int -show_content_aux (CT ct, int serial, int alternate, char *cp, char *cracked) +show_content_aux(CT ct, int serial, int alternate, char *cp, char *cracked) { - int fd, len, buflen; - int xstdin, xlist, xpause, xtty; - char *bp, *file, buffer[BUFSIZ]; - CI ci = &ct->c_ctinfo; - - if (!ct->c_ceopenfnx) { - if (!alternate) - content_error (NULL, ct, "don't know how to decode content"); - - return NOTOK; - } - - file = NULL; - if ((fd = (*ct->c_ceopenfnx) (ct, &file)) == NOTOK) - return NOTOK; - if (ct->c_showproc && !strcmp (ct->c_showproc, "true")) - return (alternate ? DONE : OK); - - xlist = 0; - xpause = 0; - xstdin = 0; - xtty = 0; - - if (cracked) { - strncpy (buffer, cp, sizeof(buffer)); - goto got_command; - } - - /* get buffer ready to go */ - bp = buffer; - bp[0] = '\0'; - buflen = sizeof(buffer); - - /* Now parse display string */ - for ( ; *cp; cp++) { - if (*cp == '%') { - switch (*++cp) { - case 'a': - /* insert parameters from Content-Type field */ - { - char **ap, **ep; - char *s = ""; - - for (ap = ci->ci_attrs, ep = ci->ci_values; *ap; ap++, ep++) { - snprintf (bp, buflen, "%s%s=\"%s\"", s, *ap, *ep); - len = strlen (bp); - bp += len; - buflen -= len; - s = " "; - } - } - break; + int fd, len, buflen, quoted; + int xstdin, xlist, xtty; + char *bp, *pp, *file, buffer[BUFSIZ]; + CI ci = &ct->c_ctinfo; - case 'd': - /* insert content description */ - if (ct->c_descr) { - char *s; + if (!ct->c_ceopenfnx) { + if (!alternate) + content_error(NULL, ct, + "don't know how to decode content"); - s = trimcpy (ct->c_descr); - strncpy (bp, s, buflen); - free (s); - } - break; - - case 'e': - /* exclusive execution */ - xtty = 1; - break; - - case 'F': - /* %e, %f, and stdin is terminal not content */ - xstdin = 1; - xtty = 1; - /* and fall... */ + return NOTOK; + } - case 'f': - /* insert filename containing content */ - snprintf (bp, buflen, "%s", file); - break; + file = NULL; + if ((fd = (*ct->c_ceopenfnx) (ct, &file)) == NOTOK) + return NOTOK; + if (ct->c_showproc && strcmp(ct->c_showproc, "true")==0) + return (alternate ? DONE : OK); - case 'p': - /* %l, and pause prior to displaying content */ - xpause = pausesw; - /* and fall... */ + xlist = 0; + xstdin = 0; + xtty = 0; - case 'l': - /* display listing prior to displaying content */ - xlist = !nolist; - break; + if (cracked) { + strncpy(buffer, cp, sizeof(buffer)); + goto got_command; + } - case 's': - /* insert subtype of content */ - strncpy (bp, ci->ci_subtype, buflen); - break; + /* get buffer ready to go */ + bp = buffer; + buflen = sizeof(buffer) - 1; + bp[0] = bp[buflen] = '\0'; + quoted = 0; + + /* Now parse display string */ + for ( ; *cp && buflen > 0; cp++) { + if (*cp == '%') { + pp = bp; + + switch (*++cp) { + case 'a': + /* insert parameters from Content-Type field */ + { + char **ap, **ep; + char *s = ""; + + for (ap = ci->ci_attrs, ep = ci->ci_values; + *ap; ap++, ep++) { + snprintf(bp, buflen, "%s%s=\"%s\"", + s, *ap, *ep); + len = strlen(bp); + bp += len; + buflen -= len; + s = " "; + } + } + break; + + case 'd': + /* insert content description */ + if (ct->c_descr) { + char *s; + + s = trimcpy(ct->c_descr); + strncpy(bp, s, buflen); + free(s); + } + break; + + case 'e': + /* exclusive execution */ + xtty = 1; + break; + + case 'F': + /* %e, %f, and stdin is terminal not content */ + xstdin = 1; + xtty = 1; + /* and fall... */ + + case 'f': + /* insert filename containing content */ + 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': + case 'l': + /* + ** display listing prior to displaying content + */ + xlist = !nolist; + break; + + case 's': + /* insert subtype of content */ + strncpy(bp, ci->ci_subtype, buflen); + break; + + case '%': + /* insert character % */ + goto raw; + + default: + *bp++ = *--cp; + *bp = '\0'; + buflen--; + continue; + } + 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--; - case '%': - /* insert character % */ - goto raw; + if (*cp == '\'') + quoted = !quoted; + } + } - default: - *bp++ = *--cp; - *bp = '\0'; - buflen--; - continue; - } - len = strlen (bp); - bp += len; - buflen -= len; - } else { -raw: - *bp++ = *cp; - *bp = '\0'; - buflen--; + if (buflen <= 0 || (ct->c_termproc && 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]; + /* use charset string to modify display method */ + if (ct->c_termproc) { + char term[BUFSIZ]; - strncpy (term, buffer, sizeof(term)); - snprintf (buffer, sizeof(buffer), ct->c_termproc, term); - } + strncpy(term, buffer, sizeof(term)); + snprintf(buffer, sizeof(buffer), ct->c_termproc, term); + } got_command: - return show_content_aux2 (ct, serial, alternate, cracked, buffer, - fd, xlist, xpause, xstdin, xtty); + return show_content_aux2(ct, serial, alternate, cracked, buffer, + fd, xlist, xstdin, xtty); } /* - * Routine to actually display the content - */ +** Routine to actually display the content +*/ static int -show_content_aux2 (CT ct, int serial, int alternate, char *cracked, char *buffer, - int fd, int xlist, int xpause, int xstdin, int xtty) +show_content_aux2(CT ct, int serial, int alternate, char *cracked, + char *buffer, int fd, int xlist, int xstdin, int xtty) { - pid_t child_id; - int i; - char *vec[4], exec[BUFSIZ + sizeof "exec "]; - - if (debugsw || cracked) { - fflush (stdout); - - fprintf (stderr, "%s msg %s", cracked ? "storing" : "show", - ct->c_file); - if (ct->c_partno) - fprintf (stderr, " part %s", ct->c_partno); - if (cracked) - fprintf (stderr, " using command (cd %s; %s)\n", cracked, buffer); - else - fprintf (stderr, " using command %s\n", buffer); - } - - if (xpid < 0 || (xtty && xpid)) { - if (xpid < 0) - xpid = -xpid; - pidcheck(pidwait (xpid, NOTOK)); - xpid = 0; - } + pid_t child_id; + char *vec[4], exec[BUFSIZ + sizeof "exec "]; + + if (debugsw || cracked) { + fflush(stdout); + + fprintf(stderr, "%s msg %s", cracked ? "storing" : "show", + ct->c_file); + if (ct->c_partno) + fprintf(stderr, " part %s", ct->c_partno); + if (cracked) + fprintf(stderr, " using command (cd %s; %s)\n", + cracked, buffer); + else + fprintf(stderr, " using command %s\n", buffer); + } - if (xlist) { - char prompt[BUFSIZ]; + if (xpid < 0 || (xtty && xpid)) { + if (xpid < 0) + xpid = -xpid; + pidcheck(pidwait(xpid, NOTOK)); + xpid = 0; + } - if (ct->c_type == CT_MULTIPART) - list_content (ct, -1, 1, 0, 0); - else - list_switch (ct, -1, 1, 0, 0); - - if (xpause && SOprintf ("Press to show content...")) - printf ("Press to show content..."); - - if (xpause) { - int intr; - SIGNAL_HANDLER istat; - - istat = SIGNAL (SIGINT, intrser); - if ((intr = sigsetjmp (intrenv, 1)) == OK) { - fflush (stdout); - prompt[0] = 0; - read (fileno (stdout), prompt, sizeof(prompt)); - } - SIGNAL (SIGINT, istat); - if (intr != OK || prompt[0] == 'n') { - (*ct->c_ceclosefnx) (ct); - return (alternate ? DONE : NOTOK); - } - if (prompt[0] == 'q') done(OK); + if (xlist) { + if (ct->c_type == CT_MULTIPART) + list_content(ct, -1, 1, 0, 0); + else + list_switch(ct, -1, 1, 0, 0); } - } - snprintf (exec, sizeof(exec), "exec %s", buffer); + snprintf(exec, sizeof(exec), "exec %s", buffer); - vec[0] = "/bin/sh"; - vec[1] = "-c"; - vec[2] = exec; - vec[3] = NULL; + vec[0] = "/bin/sh"; + vec[1] = "-c"; + vec[2] = exec; + vec[3] = NULL; - fflush (stdout); + fflush(stdout); - for (i = 0; (child_id = vfork ()) == NOTOK && i < 5; i++) - sleep (5); - switch (child_id) { + switch (child_id = fork()) { case NOTOK: - advise ("fork", "unable to"); - (*ct->c_ceclosefnx) (ct); - return NOTOK; + advise("fork", "unable to"); + (*ct->c_ceclosefnx) (ct); + return NOTOK; case OK: - if (cracked) - chdir (cracked); - if (!xstdin) - dup2 (fd, 0); - close (fd); - execvp ("/bin/sh", vec); - fprintf (stderr, "unable to exec "); - perror ("/bin/sh"); - _exit (-1); - /* NOTREACHED */ + if (cracked) + chdir(cracked); + if (!xstdin) + dup2(fd, 0); + close(fd); + execvp("/bin/sh", vec); + fprintf(stderr, "unable to exec "); + perror("/bin/sh"); + _exit(-1); + /* NOTREACHED */ default: - if (!serial) { - ct->c_pid = child_id; - if (xtty) - xpid = child_id; - } else { - pidcheck (pidXwait (child_id, NULL)); - } - - if (fd != NOTOK) - (*ct->c_ceclosefnx) (ct); - return (alternate ? DONE : OK); - } + if (!serial) { + ct->c_pid = child_id; + if (xtty) + xpid = child_id; + } else { + pidcheck(pidXwait(child_id, NULL)); + } + + if (fd != NOTOK) + (*ct->c_ceclosefnx) (ct); + return (alternate ? DONE : OK); + } } /* - * show content of type "text" - */ +** show content of type "text" +*/ static int -show_text (CT ct, int serial, int alternate) +show_text(CT ct, int serial, int alternate) { - char *cp, buffer[BUFSIZ]; - CI ci = &ct->c_ctinfo; - - /* Check for mhn-show-type/subtype */ - snprintf (buffer, sizeof(buffer), "%s-show-%s/%s", - invo_name, ci->ci_type, ci->ci_subtype); - if ((cp = context_find (buffer)) && *cp != '\0') - return show_content_aux (ct, serial, alternate, cp, NULL); - - /* Check for mhn-show-type */ - snprintf (buffer, sizeof(buffer), "%s-show-%s", invo_name, ci->ci_type); - if ((cp = context_find (buffer)) && *cp != '\0') - return show_content_aux (ct, serial, alternate, cp, NULL); - - /* - * Use default method if content is text/plain, or if - * if it is not a text part of a multipart/alternative - */ - if (!alternate || ct->c_subtype == TEXT_PLAIN) { - snprintf (buffer, sizeof(buffer), "%%p%s '%%F'", progsw ? progsw : - moreproc && *moreproc ? moreproc : "more"); - cp = (ct->c_showproc = add (buffer, NULL)); - return show_content_aux (ct, serial, alternate, cp, NULL); - } - - return NOTOK; + char *cp, buffer[BUFSIZ]; + CI ci = &ct->c_ctinfo; + + /* Check for mhshow-show-type/subtype */ + snprintf(buffer, sizeof(buffer), "%s-show-%s/%s", + invo_name, ci->ci_type, ci->ci_subtype); + if ((cp = context_find(buffer)) && *cp != '\0') + return show_content_aux(ct, serial, alternate, cp, NULL); + + /* Check for mhshow-show-type */ + snprintf(buffer, sizeof(buffer), "%s-show-%s", invo_name, ci->ci_type); + if ((cp = context_find(buffer)) && *cp != '\0') + return show_content_aux(ct, serial, alternate, cp, NULL); + + /* + ** Use default method if content is text/plain, or if + ** if it is not a text part of a multipart/alternative + */ + if (!alternate || ct->c_subtype == TEXT_PLAIN) { + snprintf(buffer, sizeof(buffer), "%%p%s '%%F'", defaultpager); + cp = (ct->c_showproc = getcpy(buffer)); + return show_content_aux(ct, serial, alternate, cp, NULL); + } + + return NOTOK; } /* - * show message body of type "multipart" - */ +** show message body of type "multipart" +*/ static int -show_multi (CT ct, int serial, int alternate) +show_multi(CT ct, int serial, int alternate) { - char *cp, buffer[BUFSIZ]; - CI ci = &ct->c_ctinfo; - - /* Check for mhn-show-type/subtype */ - snprintf (buffer, sizeof(buffer), "%s-show-%s/%s", - invo_name, ci->ci_type, ci->ci_subtype); - if ((cp = context_find (buffer)) && *cp != '\0') - return show_multi_aux (ct, serial, alternate, cp); - - /* Check for mhn-show-type */ - snprintf (buffer, sizeof(buffer), "%s-show-%s", invo_name, ci->ci_type); - if ((cp = context_find (buffer)) && *cp != '\0') - return show_multi_aux (ct, serial, alternate, cp); - - if ((cp = ct->c_showproc)) - return show_multi_aux (ct, serial, alternate, cp); - - /* - * Use default method to display this multipart content - * if it is not a (nested) part of a multipart/alternative, - * or if it is one of the known subtypes of multipart. - */ - if (!alternate || ct->c_subtype != MULTI_UNKNOWN) - return show_multi_internal (ct, serial, alternate); - - return NOTOK; + char *cp, buffer[BUFSIZ]; + CI ci = &ct->c_ctinfo; + + /* Check for mhshow-show-type/subtype */ + snprintf(buffer, sizeof(buffer), "%s-show-%s/%s", + invo_name, ci->ci_type, ci->ci_subtype); + if ((cp = context_find(buffer)) && *cp != '\0') + return show_multi_aux(ct, serial, alternate, cp); + + /* Check for mhshow-show-type */ + snprintf(buffer, sizeof(buffer), "%s-show-%s", invo_name, ci->ci_type); + if ((cp = context_find(buffer)) && *cp != '\0') + return show_multi_aux(ct, serial, alternate, cp); + + if ((cp = ct->c_showproc)) + return show_multi_aux(ct, serial, alternate, cp); + + /* + ** Use default method to display this multipart content + ** if it is not a (nested) part of a multipart/alternative, + ** or if it is one of the known subtypes of multipart. + */ + if (!alternate || ct->c_subtype != MULTI_UNKNOWN) + return show_multi_internal(ct, serial, alternate); + + return NOTOK; } /* - * show message body of subtypes of multipart that - * we understand directly (mixed, alternate, etc...) - */ +** show message body of subtypes of multipart that +** we understand directly (mixed, alternate, etc...) +*/ static int -show_multi_internal (CT ct, int serial, int alternate) +show_multi_internal(CT ct, int serial, int alternate) { - int alternating, nowalternate, nowserial, result; - struct multipart *m = (struct multipart *) ct->c_ctparams; - struct part *part; - CT p; - sigset_t set, oset; - - alternating = 0; - nowalternate = alternate; - - if (ct->c_subtype == MULTI_PARALLEL) { - nowserial = serialsw; - } else if (ct->c_subtype == MULTI_ALTERNATE) { - nowalternate = 1; - alternating = 1; - nowserial = serial; - } else { - /* - * multipart/mixed - * mutlipart/digest - * unknown subtypes of multipart (treat as mixed per rfc2046) - */ - nowserial = serial; - } - - /* block a few signals */ - if (!nowserial) { - sigemptyset (&set); - sigaddset (&set, SIGHUP); - sigaddset (&set, SIGINT); - sigaddset (&set, SIGQUIT); - sigaddset (&set, SIGTERM); - SIGPROCMASK (SIG_BLOCK, &set, &oset); - } + int alternating, nowalternate, nowserial, result; + struct multipart *m = (struct multipart *) ct->c_ctparams; + struct part *part; + CT p; + sigset_t set, oset; + + alternating = 0; + nowalternate = alternate; + + if (ct->c_subtype == MULTI_PARALLEL) { + nowserial = serialsw; + } else if (ct->c_subtype == MULTI_ALTERNATE) { + nowalternate = 1; + alternating = 1; + nowserial = serial; + } else { + /* + ** multipart/mixed + ** mutlipart/digest + ** unknown subtypes of multipart (treat as mixed per rfc2046) + */ + nowserial = serial; + } -/* - * alternate -> we are a part inside an multipart/alternative - * alternating -> we are a multipart/alternative - */ - - result = alternate ? NOTOK : OK; - - for (part = m->mp_parts; part; part = part->mp_next) { - p = part->mp_part; - - if (part_ok (p, 0) && type_ok (p, 0)) { - int inneresult; - - inneresult = show_switch (p, nowserial, nowalternate); - switch (inneresult) { - case NOTOK: - if (alternate && !alternating) { - result = NOTOK; - goto out; - } - continue; - - case OK: - case DONE: - if (alternating) { - result = DONE; - break; - } - if (alternate) { - alternate = nowalternate = 0; - if (result == NOTOK) - result = inneresult; - } - continue; - } - break; + /* block a few signals */ + if (!nowserial) { + sigemptyset(&set); + sigaddset(&set, SIGHUP); + sigaddset(&set, SIGINT); + sigaddset(&set, SIGQUIT); + sigaddset(&set, SIGTERM); + SIGPROCMASK(SIG_BLOCK, &set, &oset); } - } - if (alternating && !part) { - if (!alternate) - content_error (NULL, ct, "don't know how to display any of the contents"); - result = NOTOK; - goto out; - } - - if (serial && !nowserial) { - pid_t pid; - int kids; -#ifdef WAITINT - int status; -#else - union wait status; -#endif +/* +** alternate -> we are a part inside an multipart/alternative +** alternating -> we are a multipart/alternative +*/ + + result = alternate ? NOTOK : OK; - kids = 0; for (part = m->mp_parts; part; part = part->mp_next) { - p = part->mp_part; + p = part->mp_part; - if (p->c_pid > OK) { - if (kill (p->c_pid, 0) == NOTOK) - p->c_pid = 0; - else - kids++; - } + if (part_ok(p, 0) && type_ok(p, 0)) { + int inneresult; + + inneresult = show_switch(p, nowserial, nowalternate); + switch (inneresult) { + case NOTOK: + if (alternate && !alternating) { + result = NOTOK; + goto out; + } + continue; + + case OK: + case DONE: + if (alternating) { + result = DONE; + break; + } + if (alternate) { + alternate = nowalternate = 0; + if (result == NOTOK) + result = inneresult; + } + continue; + } + break; + } } - while (kids > 0 && (pid = wait (&status)) != NOTOK) { -#ifdef WAITINT - pidcheck (status); + if (alternating && !part) { + if (!alternate) + content_error(NULL, ct, "don't know how to display any of the contents"); + result = NOTOK; + goto out; + } + + if (serial && !nowserial) { + pid_t pid; + int kids; +#ifdef HAVE_UNION_WAIT + union wait status; #else - pidcheck (status.w_status); + int status; #endif - for (part = m->mp_parts; part; part = part->mp_next) { - p = part->mp_part; + kids = 0; + for (part = m->mp_parts; part; part = part->mp_next) { + p = part->mp_part; + + if (p->c_pid > OK) { + if (kill(p->c_pid, 0) == NOTOK) + p->c_pid = 0; + else + kids++; + } + } + + while (kids > 0 && (pid = wait(&status)) != NOTOK) { +#ifdef HAVE_UNION_WAIT + pidcheck(status.w_status); +#else + pidcheck(status); +#endif - if (xpid == pid) - xpid = 0; - if (p->c_pid == pid) { - p->c_pid = 0; - kids--; - break; + for (part = m->mp_parts; part; part = part->mp_next) { + p = part->mp_part; + + if (xpid == pid) + xpid = 0; + if (p->c_pid == pid) { + p->c_pid = 0; + kids--; + break; + } + } } - } } - } out: - if (!nowserial) { - /* reset the signal mask */ - SIGPROCMASK (SIG_SETMASK, &oset, &set); - } + if (!nowserial) { + /* reset the signal mask */ + SIGPROCMASK(SIG_SETMASK, &oset, &set); + } - return result; + return result; } /* - * Parse display string for multipart content - * and use external program to display it. - */ +** Parse display string for multipart content +** and use external program to display it. +*/ static int -show_multi_aux (CT ct, int serial, int alternate, char *cp) +show_multi_aux(CT ct, int serial, int alternate, char *cp) { - int len, buflen; - int xlist, xpause, xtty; - char *bp, *file, buffer[BUFSIZ]; - struct multipart *m = (struct multipart *) ct->c_ctparams; - struct part *part; - CI ci = &ct->c_ctinfo; - CT p; - - for (part = m->mp_parts; part; part = part->mp_next) { - p = part->mp_part; - - if (!p->c_ceopenfnx) { - if (!alternate) - content_error (NULL, p, "don't know how to decode content"); - return NOTOK; - } - - if (p->c_storage == NULL) { - file = NULL; - if ((*p->c_ceopenfnx) (p, &file) == NOTOK) - return NOTOK; - - /* I'm not sure if this is necessary? */ - p->c_storage = add (file, NULL); + int len, buflen, quoted; + int xlist, xtty; + char *bp, *pp, *file, buffer[BUFSIZ]; + struct multipart *m = (struct multipart *) ct->c_ctparams; + struct part *part; + CI ci = &ct->c_ctinfo; + CT p; - if (p->c_showproc && !strcmp (p->c_showproc, "true")) - return (alternate ? DONE : OK); - (*p->c_ceclosefnx) (p); - } - } - - xlist = 0; - xpause = 0; - xtty = 0; - - /* get buffer ready to go */ - bp = buffer; - bp[0] = '\0'; - buflen = sizeof(buffer); - - /* Now parse display string */ - for ( ; *cp; cp++) { - if (*cp == '%') { - switch (*++cp) { - case 'a': - /* insert parameters from Content-Type field */ - { - char **ap, **ep; - char *s = ""; - - for (ap = ci->ci_attrs, ep = ci->ci_values; *ap; ap++, ep++) { - snprintf (bp, buflen, "%s%s=\"%s\"", s, *ap, *ep); - len = strlen (bp); - bp += len; - buflen -= len; - s = " "; - } - } - break; - - case 'd': - /* insert content description */ - if (ct->c_descr) { - char *s; + for (part = m->mp_parts; part; part = part->mp_next) { + p = part->mp_part; - s = trimcpy (ct->c_descr); - strncpy (bp, s, buflen); - free (s); + if (!p->c_ceopenfnx) { + if (!alternate) + content_error(NULL, p, "don't know how to decode content"); + return NOTOK; } - break; - case 'e': - /* exclusive execution */ - xtty = 1; - break; + if (p->c_storage == NULL) { + file = NULL; + if ((*p->c_ceopenfnx) (p, &file) == NOTOK) + return NOTOK; - case 'F': - /* %e and %f */ - xtty = 1; - /* and fall... */ - - case 'f': - /* insert filename(s) containing content */ - { - char *s = ""; - - for (part = m->mp_parts; part; part = part->mp_next) { - p = part->mp_part; + /* I'm not sure if this is necessary? */ + p->c_storage = getcpy(file); - snprintf (bp, buflen, "%s'%s'", s, p->c_storage); - len = strlen (bp); - bp += len; - buflen -= len; - s = " "; + if (p->c_showproc && strcmp(p->c_showproc, "true")==0) + return (alternate ? DONE : OK); + (*p->c_ceclosefnx) (p); } - } - break; - - case 'p': - /* %l, and pause prior to displaying content */ - xpause = pausesw; - /* and fall... */ + } - case 'l': - /* display listing prior to displaying content */ - xlist = !nolist; - break; + xlist = 0; + xtty = 0; + + /* get buffer ready to go */ + bp = buffer; + buflen = sizeof(buffer) - 1; + bp[0] = bp[buflen] = '\0'; + quoted = 0; + + /* Now parse display string */ + for ( ; *cp && buflen > 0; cp++) { + if (*cp == '%') { + pp = bp; + switch (*++cp) { + case 'a': + /* insert parameters from Content-Type field */ + { + char **ap, **ep; + char *s = ""; + + for (ap = ci->ci_attrs, ep = ci->ci_values; + *ap; ap++, ep++) { + snprintf(bp, buflen, "%s%s=\"%s\"", + s, *ap, *ep); + len = strlen(bp); + bp += len; + buflen -= len; + s = " "; + } + } + break; + + case 'd': + /* insert content description */ + if (ct->c_descr) { + char *s; + + s = trimcpy(ct->c_descr); + strncpy(bp, s, buflen); + free(s); + } + break; + + case 'e': + /* exclusive execution */ + xtty = 1; + break; + + case 'F': + /* %e and %f */ + xtty = 1; + /* and fall... */ + + case 'f': + /* insert filename(s) containing content */ + { + char *s = ""; + + for (part = m->mp_parts; part; + part = part->mp_next) { + p = part->mp_part; + + snprintf(bp, buflen, "%s'%s'", + s, p->c_storage); + len = strlen(bp); + bp += len; + buflen -= len; + s = " "; + } + /* + ** set our starting pointer back to bp, + ** to avoid requoting the filenames we + ** just added + */ + pp = bp; + } + break; - case 's': - /* insert subtype of content */ - strncpy (bp, ci->ci_subtype, buflen); - break; + case 'p': + case 'l': + /* + ** display listing prior to displaying content + */ + xlist = !nolist; + break; + + case 's': + /* insert subtype of content */ + strncpy(bp, ci->ci_subtype, buflen); + break; + + case '%': + /* insert character % */ + goto raw; + + default: + *bp++ = *--cp; + *bp = '\0'; + buflen--; + continue; + } + 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--; - case '%': - /* insert character % */ - goto raw; + if (*cp == '\'') + quoted = !quoted; + } + } - default: - *bp++ = *--cp; - *bp = '\0'; - buflen--; - continue; - } - len = strlen (bp); - bp += len; - buflen -= len; - } else { -raw: - *bp++ = *cp; - *bp = '\0'; - buflen--; + if (buflen <= 0 || + (ct->c_termproc && 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]; + /* use charset string to modify display method */ + if (ct->c_termproc) { + char term[BUFSIZ]; - strncpy (term, buffer, sizeof(term)); - snprintf (buffer, sizeof(buffer), ct->c_termproc, term); - } + strncpy(term, buffer, sizeof(term)); + snprintf(buffer, sizeof(buffer), ct->c_termproc, term); + } - return show_content_aux2 (ct, serial, alternate, NULL, buffer, - NOTOK, xlist, xpause, 0, xtty); + return show_content_aux2(ct, serial, alternate, NULL, buffer, + NOTOK, xlist, 0, xtty); } /* - * show content of type "message/rfc822" - */ +** show content of type "message/rfc822" +*/ static int -show_message_rfc822 (CT ct, int serial, int alternate) +show_message_rfc822(CT ct, int serial, int alternate) { - char *cp, buffer[BUFSIZ]; - CI ci = &ct->c_ctinfo; - - /* Check for mhn-show-type/subtype */ - snprintf (buffer, sizeof(buffer), "%s-show-%s/%s", - invo_name, ci->ci_type, ci->ci_subtype); - if ((cp = context_find (buffer)) && *cp != '\0') - return show_content_aux (ct, serial, alternate, cp, NULL); - - /* Check for mhn-show-type */ - snprintf (buffer, sizeof(buffer), "%s-show-%s", invo_name, ci->ci_type); - if ((cp = context_find (buffer)) && *cp != '\0') - return show_content_aux (ct, serial, alternate, cp, NULL); - - if ((cp = ct->c_showproc)) - return show_content_aux (ct, serial, alternate, cp, NULL); - - /* default method for message/rfc822 */ - if (ct->c_subtype == MESSAGE_RFC822) { - cp = (ct->c_showproc = add ("%pshow -file '%F'", NULL)); - return show_content_aux (ct, serial, alternate, cp, NULL); - } - - /* complain if we are not a part of a multipart/alternative */ - if (!alternate) - content_error (NULL, ct, "don't know how to display content"); - - return NOTOK; + char *cp, buffer[BUFSIZ]; + CI ci = &ct->c_ctinfo; + + /* Check for mhshow-show-type/subtype */ + snprintf(buffer, sizeof(buffer), "%s-show-%s/%s", + invo_name, ci->ci_type, ci->ci_subtype); + if ((cp = context_find(buffer)) && *cp != '\0') + return show_content_aux(ct, serial, alternate, cp, NULL); + + /* Check for mhshow-show-type */ + snprintf(buffer, sizeof(buffer), "%s-show-%s", invo_name, ci->ci_type); + if ((cp = context_find(buffer)) && *cp != '\0') + return show_content_aux(ct, serial, alternate, cp, NULL); + + if ((cp = ct->c_showproc)) + return show_content_aux(ct, serial, alternate, cp, NULL); + + /* default method for message/rfc822 */ + if (ct->c_subtype == MESSAGE_RFC822) { + cp = (ct->c_showproc = getcpy("%pshow -file '%F'")); + return show_content_aux(ct, serial, alternate, cp, NULL); + } + + /* complain if we are not a part of a multipart/alternative */ + if (!alternate) + content_error(NULL, ct, "don't know how to display content"); + + return NOTOK; } /* - * Show content of type "message/partial". - */ +** Show content of type "message/partial". +*/ static int -show_partial (CT ct, int serial, int alternate) +show_partial(CT ct, int serial, int alternate) { - content_error (NULL, ct, - "in order to display this message, you must reassemble it"); - return NOTOK; + content_error(NULL, ct, + "in order to display this message, you must reassemble it"); + return NOTOK; } /* - * Show content of type "message/external". - * - * THE ERROR CHECKING IN THIS ONE IS NOT DONE YET. - */ +** Show content of type "message/external". +** +** THE ERROR CHECKING IN THIS ONE IS NOT DONE YET. +*/ static int -show_external (CT ct, int serial, int alternate) +show_external(CT ct, int serial, int alternate) { - struct exbody *e = (struct exbody *) ct->c_ctparams; - CT p = e->eb_content; + struct exbody *e = (struct exbody *) ct->c_ctparams; + CT p = e->eb_content; - if (!type_ok (p, 0)) - return OK; + if (!type_ok(p, 0)) + return OK; - return show_switch (p, serial, alternate); + return show_switch(p, serial, alternate); #if 0 - content_error (NULL, p, "don't know how to display content"); - return NOTOK; -#endif -} - - -static RETSIGTYPE -intrser (int i) -{ -#ifndef RELIABLE_SIGNALS - SIGNAL (SIGINT, intrser); + content_error(NULL, p, "don't know how to display content"); + return NOTOK; #endif - - putchar ('\n'); - siglongjmp (intrenv, DONE); }