source: trunk/third/nmh/uip/mhshowsbr.c @ 14155

Revision 14155, 23.3 KB checked in by danw, 25 years ago (diff)
work around some security issues in the mhn.defaults parsing
Line 
1
2/*
3 * mhshowsbr.c -- routines to display the contents of MIME messages
4 *
5 * $Id: mhshowsbr.c,v 1.4 2000-01-04 21:47:01 danw Exp $
6 */
7
8#include <h/mh.h>
9#include <fcntl.h>
10#include <h/signals.h>
11#include <h/md5.h>
12#include <errno.h>
13#include <setjmp.h>
14#include <signal.h>
15#include <zotnet/mts/mts.h>
16#include <zotnet/tws/tws.h>
17#include <h/mime.h>
18#include <h/mhparse.h>
19
20#ifdef HAVE_SYS_WAIT_H
21# include <sys/wait.h>
22#endif
23
24/*
25 * Just use sigjmp/longjmp on older machines that
26 * don't have sigsetjmp/siglongjmp.
27 */
28#ifndef HAVE_SIGSETJMP
29# define sigjmp_buf jmp_buf
30# define sigsetjmp(env,mask) setjmp(env)
31# define siglongjmp(env,val) longjmp(env,val)
32#endif
33
34extern int errno;
35extern int debugsw;
36
37int pausesw  = 1;
38int serialsw = 0;
39int nolist   = 0;
40
41char *progsw = NULL;
42
43/* flags for moreproc/header display */
44int nomore   = 0;
45char *formsw = NULL;
46
47pid_t xpid = 0, m_pid = 0, intrpid = 0;
48
49static sigjmp_buf intrenv;
50
51
52/* termsbr.c */
53int SOprintf (char *, ...);
54
55/* mhparse.c */
56int pidcheck (int);
57
58/* mhmisc.c */
59int part_ok (CT, int);
60int type_ok (CT, int);
61void content_error (char *, CT, char *, ...);
62void flush_errors (void);
63
64/* mhlistsbr.c */
65int list_switch (CT, int, int, int, int);
66int list_content (CT, int, int, int, int);
67
68/*
69 * prototypes
70 */
71void show_all_messages (CT *);
72int show_content_aux (CT, int, int, char *, char *);
73
74/*
75 * static prototypes
76 */
77static void show_single_message (CT, char *);
78static void DisplayMsgHeader (CT, char *);
79static int show_switch (CT, int, int);
80static int show_content (CT, int, int);
81static int show_content_aux2 (CT, int, int, char *, char *, int, int, int, int, int);
82static int show_text (CT, int, int);
83static int show_multi (CT, int, int);
84static int show_multi_internal (CT, int, int);
85static int show_multi_aux (CT, int, int, char *);
86static int show_message_rfc822 (CT, int, int);
87static int show_partial (CT, int, int);
88static int show_external (CT, int, int);
89static RETSIGTYPE intrser (int);
90static RETSIGTYPE intrser2 (int);
91static void m_popen (char *);
92static void m_pclose (void);
93
94
95/*
96 * Top level entry point to show/display a group of messages
97 */
98
99void
100show_all_messages (CT *cts)
101{
102    CT ct, *ctp;
103
104    /*
105     * If form is not specified, then get default form
106     * for showing headers of MIME messages.
107     */
108    if (!formsw)
109        formsw = getcpy (etcpath ("mhl.headers"));
110
111    /*
112     * If form is "mhl.null", suppress display of header.
113     */
114    if (!strcmp (formsw, "mhl.null"))
115        formsw = NULL;
116
117    for (ctp = cts; *ctp; ctp++) {
118        ct = *ctp;
119
120        /* if top-level type is ok, then display message */
121        if (type_ok (ct, 0))
122            show_single_message (ct, formsw);
123    }
124}
125
126
127/*
128 * Entry point to show/display a single message
129 */
130
131static void
132show_single_message (CT ct, char *form)
133{
134    sigset_t set, oset;
135
136#ifdef WAITINT
137    int status;
138#else
139    union wait status;
140#endif
141
142    umask (ct->c_umask);
143
144    if (!nomore && isatty (fileno (stdout)))
145        m_popen (progsw ? progsw : moreproc);
146
147    /*
148     * If you have a format file, then display
149     * the message headers.
150     */
151    if (form)
152        DisplayMsgHeader(ct, form);
153    else
154        xpid = 0;
155
156    /* Show the body of the message */
157    show_switch (ct, 1, 0);
158
159    if (ct->c_fp) {
160        fclose (ct->c_fp);
161        ct->c_fp = NULL;
162    }
163    if (ct->c_ceclosefnx)
164        (*ct->c_ceclosefnx) (ct);
165
166    /* block a few signals */
167    sigemptyset (&set);
168    sigaddset (&set, SIGHUP);
169    sigaddset (&set, SIGINT);
170    sigaddset (&set, SIGQUIT);
171    sigaddset (&set, SIGTERM);
172    SIGPROCMASK (SIG_BLOCK, &set, &oset);
173
174    m_pclose ();
175
176    while (wait (&status) != NOTOK) {
177#ifdef WAITINT
178        pidcheck (status);
179#else
180        pidcheck (status.w_status);
181#endif
182        continue;
183    }
184
185    /* reset the signal mask */
186    SIGPROCMASK (SIG_SETMASK, &oset, &set);
187
188    xpid = 0;
189    flush_errors ();
190}
191
192
193/*
194 * Use the mhlproc to show the header fields
195 */
196
197static void
198DisplayMsgHeader (CT ct, char *form)
199{
200    pid_t child_id;
201    int i, vecp;
202    char *vec[8];
203
204    vecp = 0;
205    vec[vecp++] = r1bindex (mhlproc, '/');
206    vec[vecp++] = "-form";
207    vec[vecp++] = form;
208    vec[vecp++] = "-nobody";
209    vec[vecp++] = "-nomoreproc";
210    vec[vecp++] = ct->c_file;
211    vec[vecp] = NULL;
212
213    fflush (stdout);
214
215    for (i = 0; (child_id = vfork()) == NOTOK && i < 5; i++)
216        sleep (5);
217
218    switch (child_id) {
219    case NOTOK:
220        adios ("fork", "unable to");
221        /* NOTREACHED */
222
223    case OK:
224        execvp (mhlproc, vec);
225        fprintf (stderr, "unable to exec ");
226        perror (mhlproc);
227        _exit (-1);
228        /* NOTREACHED */
229
230    default:
231        xpid = -child_id;
232        break;
233    }
234}
235
236
237/*
238 * Switching routine.  Call the correct routine
239 * based on content type.
240 */
241
242static int
243show_switch (CT ct, int serial, int alternate)
244{
245    switch (ct->c_type) {
246        case CT_MULTIPART:
247            return show_multi (ct, serial, alternate);
248            break;
249
250        case CT_MESSAGE:
251            switch (ct->c_subtype) {
252                case MESSAGE_PARTIAL:
253                    return show_partial (ct, serial, alternate);
254                    break;
255
256                case MESSAGE_EXTERNAL:
257                    return show_external (ct, serial, alternate);
258                    break;
259
260                case MESSAGE_RFC822:
261                default:
262                    return show_message_rfc822 (ct, serial, alternate);
263                    break;
264            }
265            break;
266
267        case CT_TEXT:
268            return show_text (ct, serial, alternate);
269            break;
270
271        case CT_AUDIO:
272        case CT_IMAGE:
273        case CT_VIDEO:
274        case CT_APPLICATION:
275            return show_content (ct, serial, alternate);
276            break;
277
278        default:
279            adios (NULL, "unknown content type %d", ct->c_type);
280            break;
281    }
282
283    return 0;   /* NOT REACHED */
284}
285
286
287/*
288 * Generic method for displaying content
289 */
290
291static int
292show_content (CT ct, int serial, int alternate)
293{
294    char *cp, buffer[BUFSIZ];
295    CI ci = &ct->c_ctinfo;
296
297    /* Check for mhn-show-type/subtype */
298    snprintf (buffer, sizeof(buffer), "%s-show-%s/%s",
299                invo_name, ci->ci_type, ci->ci_subtype);
300    if ((cp = context_find (buffer)) && *cp != '\0')
301        return show_content_aux (ct, serial, alternate, cp, NULL);
302
303    /* Check for mhn-show-type */
304    snprintf (buffer, sizeof(buffer), "%s-show-%s", invo_name, ci->ci_type);
305    if ((cp = context_find (buffer)) && *cp != '\0')
306        return show_content_aux (ct, serial, alternate, cp, NULL);
307
308    if ((cp = ct->c_showproc))
309        return show_content_aux (ct, serial, alternate, cp, NULL);
310
311    /* complain if we are not a part of a multipart/alternative */
312    if (!alternate)
313        content_error (NULL, ct, "don't know how to display content");
314
315    return NOTOK;
316}
317
318
319/*
320 * Parse the display string for displaying generic content
321 */
322
323int
324show_content_aux (CT ct, int serial, int alternate, char *cp, char *cracked)
325{
326    int fd, len, buflen, sawquote;
327    int xstdin, xlist, xpause, xtty;
328    char *bp, *pp, *file, buffer[BUFSIZ];
329    CI ci = &ct->c_ctinfo;
330
331    if (!ct->c_ceopenfnx) {
332        if (!alternate)
333            content_error (NULL, ct, "don't know how to decode content");
334
335        return NOTOK;
336    }
337
338    file = NULL;
339    if ((fd = (*ct->c_ceopenfnx) (ct, &file)) == NOTOK)
340        return NOTOK;
341    if (ct->c_showproc && !strcmp (ct->c_showproc, "true"))
342        return (alternate ? DONE : OK);
343   
344    xlist  = 0;
345    xpause = 0;
346    xstdin = 0;
347    xtty   = 0;
348
349    if (cracked) {
350        strncpy (buffer, cp, sizeof(buffer));
351        goto got_command;
352    }
353
354    /* get buffer ready to go */
355    bp = buffer;
356    bp[0] = bp[sizeof(buffer) - 1] = '\0';
357    buflen = sizeof(buffer) - 1;
358
359    sawquote = 0;
360
361    /* Now parse display string */
362    for ( ; *cp && buflen > 0; cp++) {
363        if (*cp == '%') {
364            pp = bp;
365
366            switch (*++cp) {
367            case 'a':
368                /* insert parameters from Content-Type field */
369            {
370                char **ap, **ep;
371                char *s = "";
372
373                for (ap = ci->ci_attrs, ep = ci->ci_values; *ap; ap++, ep++) {
374                    snprintf (bp, buflen, "%s%s=\"%s\"", s, *ap, *ep);
375                    len = strlen (bp);
376                    bp += len;
377                    buflen -= len;
378                    s = " ";
379                }
380            }
381            break;
382
383            case 'd':
384                /* insert content description */
385                if (ct->c_descr) {
386                    char *s;
387
388                    s = trimcpy (ct->c_descr);
389                    strncpy (bp, s, buflen);
390                    free (s);
391                }
392                break;
393
394            case 'e':
395                /* exclusive execution */
396                xtty = 1;
397                break;
398
399            case 'F':
400                /* %e, %f, and stdin is terminal not content */
401                xstdin = 1;
402                xtty = 1;
403                /* and fall... */
404
405            case 'f':
406                /* insert filename containing content */
407                snprintf (bp, buflen, "%s", file);
408                break;
409
410            case 'p':
411                /* %l, and pause prior to displaying content */
412                xpause = pausesw;
413                /* and fall... */
414
415            case 'l':
416                /* display listing prior to displaying content */
417                xlist = !nolist;
418                break;
419
420            case 's':
421                /* insert subtype of content */
422                strncpy (bp, ci->ci_subtype, buflen);
423                break;
424
425            case '%':
426                /* insert character % */
427                goto raw;
428
429            default:
430                *bp++ = *--cp;
431                *bp = '\0';
432                buflen--;
433                continue;
434            }
435            len = strlen (bp);
436            bp += len;
437            buflen -= len;
438
439            if (sawquote) {
440                while ((pp = strchr (pp, '\'')) && buflen > 3) {
441                    len = strlen (pp++);
442                    memmove (pp + 3, pp, len);
443                    *pp++ = '\\';
444                    *pp++ = '\'';
445                    *pp++ = '\'';
446                    buflen -= 3;
447                    bp += 3;
448                }
449                /* If pp is set, that means we ran out of space. */
450                if (pp)
451                    buflen = 0;
452            }
453
454            sawquote = 0;
455        } else {
456raw:
457        *bp++ = *cp;
458        *bp = '\0';
459        buflen--;
460        sawquote = *cp == '\'';
461        }
462    }
463
464    if (buflen == 0 ||
465        (ct->c_termproc && buflen < strlen(ct->c_termproc))) {
466        /* content_error would provide a more useful error message
467         * here, except that if we got overrun, it probably would
468         * too.
469         */
470        fprintf(stderr, "Buffer overflow constructing show command!\n");
471        return NOTOK;
472    }
473
474    /* use charset string to modify display method */
475    if (ct->c_termproc) {
476        char term[BUFSIZ];
477
478        strncpy (term, buffer, sizeof(term));
479        snprintf (buffer, sizeof(buffer), ct->c_termproc, term);
480    }
481
482got_command:
483    return show_content_aux2 (ct, serial, alternate, cracked, buffer,
484                              fd, xlist, xpause, xstdin, xtty);
485}
486
487
488/*
489 * Routine to actually display the content
490 */
491
492static int
493show_content_aux2 (CT ct, int serial, int alternate, char *cracked, char *buffer,
494                   int fd, int xlist, int xpause, int xstdin, int xtty)
495{
496    pid_t child_id;
497    int i;
498    char *vec[4], exec[BUFSIZ + sizeof "exec "];
499    int intr;
500    SIGNAL_HANDLER istat;
501   
502    if (debugsw || cracked) {
503        fflush (stdout);
504
505        fprintf (stderr, "%s msg %s", cracked ? "storing" : "show",
506                 ct->c_file);
507        if (ct->c_partno)
508            fprintf (stderr, " part %s", ct->c_partno);
509        if (cracked)
510            fprintf (stderr, " using command (cd %s; %s)\n", cracked, buffer);
511        else
512            fprintf (stderr, " using command %s\n", buffer);
513    }
514
515    if (xpid < 0 || (xtty && xpid)) {
516        if (xpid < 0)
517            xpid = -xpid;
518        pidcheck(pidwait (xpid, NOTOK));
519        xpid = 0;
520    }
521
522    if (xstdin && m_pid)
523        m_pclose ();
524
525    if (xlist) {
526        char prompt[BUFSIZ];
527
528        if (ct->c_type == CT_MULTIPART)
529            list_content (ct, -1, 1, 0, 0);
530        else
531            list_switch (ct, -1, 1, 0, 0);
532
533        if (xpause && SOprintf ("Press <return> to show content..."))
534            printf ("Press <return> to show content...");
535
536        if (xpause) {
537            istat = SIGNAL (SIGINT, intrser);
538            if ((intr = sigsetjmp (intrenv, 1)) == OK) {
539                fflush (stdout);
540                prompt[0] = 0;
541                read (fileno (stdout), prompt, sizeof(prompt));
542            }
543            SIGNAL (SIGINT, istat);
544            if (intr != OK) {
545                (*ct->c_ceclosefnx) (ct);
546                return (alternate ? DONE : NOTOK);
547            }
548        }
549    }
550
551    snprintf (exec, sizeof(exec), "exec %s", buffer);
552
553    vec[0] = "/bin/sh";
554    vec[1] = "-c";
555    vec[2] = exec;
556    vec[3] = NULL;
557
558    fflush (stdout);
559
560    istat = SIGNAL (SIGINT, intrser2);
561    for (i = 0; (intrpid = child_id = vfork ()) == NOTOK && i < 5; i++)
562        sleep (5);
563    switch (child_id) {
564        case NOTOK:
565            SIGNAL (SIGINT, istat);
566            advise ("fork", "unable to");
567            (*ct->c_ceclosefnx) (ct);
568            return NOTOK;
569
570        case OK:
571            if (cracked)
572                chdir (cracked);
573            if (!xstdin)
574                dup2 (fd, 0);
575            close (fd);
576            execvp ("/bin/sh", vec);
577            fprintf (stderr, "unable to exec ");
578            perror ("/bin/sh");
579            _exit (-1);
580            /* NOTREACHED */
581
582        default:
583            if (!serial) {
584                ct->c_pid = child_id;
585                if (xtty)
586                    xpid = child_id;
587            } else {
588                pidcheck (pidXwait (child_id, NULL));
589            }
590
591            if (fd != NOTOK)
592                (*ct->c_ceclosefnx) (ct);
593            SIGNAL (SIGINT, istat);
594            return (alternate ? DONE : OK);
595    }
596}
597
598
599/*
600 * show content of type "text"
601 */
602
603static int
604show_text (CT ct, int serial, int alternate)
605{
606    char *cp, buffer[BUFSIZ];
607    CI ci = &ct->c_ctinfo;
608
609    /* Check for mhn-show-type/subtype */
610    snprintf (buffer, sizeof(buffer), "%s-show-%s/%s",
611                invo_name, ci->ci_type, ci->ci_subtype);
612    if ((cp = context_find (buffer)) && *cp != '\0')
613        return show_content_aux (ct, serial, alternate, cp, NULL);
614
615    /* Check for mhn-show-type */
616    snprintf (buffer, sizeof(buffer), "%s-show-%s", invo_name, ci->ci_type);
617    if ((cp = context_find (buffer)) && *cp != '\0')
618        return show_content_aux (ct, serial, alternate, cp, NULL);
619
620    /*
621     * Use default method if content is text/plain, or if
622     * if it is not a text part of a multipart/alternative
623     */
624    if (!alternate || ct->c_subtype == TEXT_PLAIN) {
625        snprintf (buffer, sizeof(buffer), "%%ecat '%%f'");
626        cp = (ct->c_showproc = add (buffer, NULL));
627        return show_content_aux (ct, serial, alternate, cp, NULL);
628    }
629
630    return NOTOK;
631}
632
633
634/*
635 * show message body of type "multipart"
636 */
637
638static int
639show_multi (CT ct, int serial, int alternate)
640{
641    char *cp, buffer[BUFSIZ];
642    CI ci = &ct->c_ctinfo;
643
644    /* Check for mhn-show-type/subtype */
645    snprintf (buffer, sizeof(buffer), "%s-show-%s/%s",
646                invo_name, ci->ci_type, ci->ci_subtype);
647    if ((cp = context_find (buffer)) && *cp != '\0')
648        return show_multi_aux (ct, serial, alternate, cp);
649
650    /* Check for mhn-show-type */
651    snprintf (buffer, sizeof(buffer), "%s-show-%s", invo_name, ci->ci_type);
652    if ((cp = context_find (buffer)) && *cp != '\0')
653        return show_multi_aux (ct, serial, alternate, cp);
654
655    if ((cp = ct->c_showproc))
656        return show_multi_aux (ct, serial, alternate, cp);
657
658    /*
659     * Use default method to display this multipart content
660     * if it is not a (nested) part of a multipart/alternative,
661     * or if it is one of the known subtypes of multipart.
662     */
663    if (!alternate || ct->c_subtype != MULTI_UNKNOWN)
664        return show_multi_internal (ct, serial, alternate);
665
666    return NOTOK;
667}
668
669
670/*
671 * show message body of subtypes of multipart that
672 * we understand directly (mixed, alternate, etc...)
673 */
674
675static int
676show_multi_internal (CT ct, int serial, int alternate)
677{
678    int alternating, nowalternate, nowserial, result;
679    struct multipart *m = (struct multipart *) ct->c_ctparams;
680    struct part *part;
681    CT p;
682    sigset_t set, oset;
683
684    alternating = 0;
685    nowalternate = alternate;
686
687    if (ct->c_subtype == MULTI_PARALLEL) {
688        nowserial = serialsw;
689    } else if (ct->c_subtype == MULTI_ALTERNATE) {
690        nowalternate = 1;
691        alternating  = 1;
692        nowserial = serial;
693    } else {
694        /*
695         * multipart/mixed
696         * mutlipart/digest
697         * unknown subtypes of multipart (treat as mixed per rfc2046)
698         */
699        nowserial = serial;
700    }
701
702    /* block a few signals */
703    if (!nowserial) {
704        sigemptyset (&set);
705        sigaddset (&set, SIGHUP);
706        sigaddset (&set, SIGINT);
707        sigaddset (&set, SIGQUIT);
708        sigaddset (&set, SIGTERM);
709        SIGPROCMASK (SIG_BLOCK, &set, &oset);
710    }
711
712/*
713 * alternate   -> we are a part inside an multipart/alternative
714 * alternating -> we are a multipart/alternative
715 */
716
717    result = alternate ? NOTOK : OK;
718
719    for (part = m->mp_parts; part; part = part->mp_next) {
720        p = part->mp_part;
721
722        if (part_ok (p, 0) && type_ok (p, 0)) {
723            int inneresult;
724
725            inneresult = show_switch (p, nowserial, nowalternate);
726            switch (inneresult) {
727                case NOTOK:
728                    if (alternate && !alternating) {
729                        result = NOTOK;
730                        goto out;
731                    }
732                    continue;
733
734                case OK:
735                case DONE:
736                    if (alternating) {
737                        result = DONE;
738                        break;
739                    }
740                    if (alternate) {
741                        alternate = nowalternate = 0;
742                        if (result == NOTOK)
743                            result = inneresult;
744                    }
745                    continue;
746            }
747            break;
748        }
749    }
750
751    if (alternating && !part) {
752        if (!alternate)
753            content_error (NULL, ct, "don't know how to display any of the contents");
754        result = NOTOK;
755        goto out;
756    }
757
758    if (serial && !nowserial) {
759        pid_t pid;
760        int kids;
761#ifdef WAITINT
762        int status;
763#else
764        union wait status;
765#endif
766
767        kids = 0;
768        for (part = m->mp_parts; part; part = part->mp_next) {
769            p = part->mp_part;
770
771            if (p->c_pid > OK)
772                if (kill (p->c_pid, 0) == NOTOK)
773                    p->c_pid = 0;
774                else
775                    kids++;
776        }
777
778        while (kids > 0 && (pid = wait (&status)) != NOTOK) {
779#ifdef WAITINT
780            pidcheck (status);
781#else
782            pidcheck (status.w_status);
783#endif
784
785            for (part = m->mp_parts; part; part = part->mp_next) {
786                p = part->mp_part;
787
788                if (xpid == pid)
789                    xpid = 0;
790                if (p->c_pid == pid) {
791                    p->c_pid = 0;
792                    kids--;
793                    break;
794                }
795            }
796        }
797    }
798
799out:
800    if (!nowserial) {
801        /* reset the signal mask */
802        SIGPROCMASK (SIG_SETMASK, &oset, &set);
803    }
804
805    return result;
806}
807
808
809/*
810 * Parse display string for multipart content
811 * and use external program to display it.
812 */
813
814static int
815show_multi_aux (CT ct, int serial, int alternate, char *cp)
816{
817    int len, buflen, sawquote;
818    int xlist, xpause, xtty;
819    char *bp, *pp, *file, buffer[BUFSIZ];
820    struct multipart *m = (struct multipart *) ct->c_ctparams;
821    struct part *part;
822    CI ci = &ct->c_ctinfo;
823    CT p;
824
825    for (part = m->mp_parts; part; part = part->mp_next) {
826        p = part->mp_part;
827
828        if (!p->c_ceopenfnx) {
829            if (!alternate)
830                content_error (NULL, p, "don't know how to decode content");
831            return NOTOK;
832        }
833
834        if (p->c_storage == NULL) {
835            file = NULL;
836            if ((*p->c_ceopenfnx) (p, &file) == NOTOK)
837                return NOTOK;
838
839            /* I'm not sure if this is necessary? */
840            p->c_storage = add (file, NULL);
841
842            if (p->c_showproc && !strcmp (p->c_showproc, "true"))
843                return (alternate ? DONE : OK);
844            (*p->c_ceclosefnx) (p);
845        }
846    }
847
848    xlist     = 0;
849    xpause    = 0;
850    xtty      = 0;
851
852    /* get buffer ready to go */
853    bp = buffer;
854    bp[0] = bp[sizeof(buffer) - 1] = '\0';
855    buflen = sizeof(buffer) - 1;
856
857    sawquote = 0;
858
859    /* Now parse display string */
860    for ( ; *cp && buflen > 0; cp++) {
861        if (*cp == '%') {
862            pp = bp;
863
864            switch (*++cp) {
865            case 'a':
866                /* insert parameters from Content-Type field */
867            {
868                char **ap, **ep;
869                char *s = "";
870
871                for (ap = ci->ci_attrs, ep = ci->ci_values; *ap; ap++, ep++) {
872                    snprintf (bp, buflen, "%s%s=\"%s\"", s, *ap, *ep);
873                    len = strlen (bp);
874                    bp += len;
875                    buflen -= len;
876                    s = " ";
877                }
878            }
879            break;
880
881            case 'd':
882                /* insert content description */
883                if (ct->c_descr) {
884                    char *s;
885
886                    s = trimcpy (ct->c_descr);
887                    strncpy (bp, s, buflen);
888                    free (s);
889                }
890                break;
891
892            case 'e':
893                /* exclusive execution */
894                xtty = 1;
895                break;
896
897            case 'F':
898                /* %e and %f */
899                xtty = 1;
900                /* and fall... */
901
902            case 'f':
903                /* insert filename(s) containing content */
904            {
905                char *s = "";
906                       
907                for (part = m->mp_parts; part; part = part->mp_next) {
908                    p = part->mp_part;
909
910                    snprintf (bp, buflen, "%s'%s'", s, p->c_storage);
911                    len = strlen (bp);
912                    bp += len;
913                    buflen -= len;
914                    s = " ";
915                }
916            }
917            break;
918
919            case 'p':
920                /* %l, and pause prior to displaying content */
921                xpause = pausesw;
922                /* and fall... */
923
924            case 'l':
925                /* display listing prior to displaying content */
926                xlist = !nolist;
927                break;
928
929            case 's':
930                /* insert subtype of content */
931                strncpy (bp, ci->ci_subtype, buflen);
932                break;
933
934            case '%':
935                /* insert character % */
936                goto raw;
937
938            default:
939                *bp++ = *--cp;
940                *bp = '\0';
941                buflen--;
942                continue;
943            }
944            len = strlen (bp);
945            bp += len;
946            buflen -= len;
947
948            if (sawquote) {
949                while ((pp = strchr (pp, '\'')) && buflen > 3) {
950                    len = strlen (pp++);
951                    memmove (pp + 3, pp, len);
952                    *pp++ = '\\';
953                    *pp++ = '\'';
954                    *pp++ = '\'';
955                    buflen -= 3;
956                    bp += 3;
957                }
958                /* If pp is set, that means we ran out of space. */
959                if (pp)
960                    buflen = 0;
961            }
962
963            sawquote = 0;
964        } else {
965raw:
966        *bp++ = *cp;
967        *bp = '\0';
968        buflen--;
969        sawquote = *cp == '\'';
970        }
971    }
972
973    if (buflen == 0 ||
974        (ct->c_termproc && buflen < strlen(ct->c_termproc))) {
975        /* content_error would provide a more useful error message
976         * here, except that if we got overrun, it probably would
977         * too.
978         */
979        fprintf(stderr, "Buffer overflow constructing show command!\n");
980        return NOTOK;
981    }
982
983    /* use charset string to modify display method */
984    if (ct->c_termproc) {
985        char term[BUFSIZ];
986
987        strncpy (term, buffer, sizeof(term));
988        snprintf (buffer, sizeof(buffer), ct->c_termproc, term);
989    }
990
991    return show_content_aux2 (ct, serial, alternate, NULL, buffer,
992                              NOTOK, xlist, xpause, 0, xtty);
993}
994
995
996/*
997 * show content of type "message/rfc822"
998 */
999
1000static int
1001show_message_rfc822 (CT ct, int serial, int alternate)
1002{
1003    char *cp, buffer[BUFSIZ];
1004    CI ci = &ct->c_ctinfo;
1005
1006    /* Check for mhn-show-type/subtype */
1007    snprintf (buffer, sizeof(buffer), "%s-show-%s/%s",
1008                invo_name, ci->ci_type, ci->ci_subtype);
1009    if ((cp = context_find (buffer)) && *cp != '\0')
1010        return show_content_aux (ct, serial, alternate, cp, NULL);
1011
1012    /* Check for mhn-show-type */
1013    snprintf (buffer, sizeof(buffer), "%s-show-%s", invo_name, ci->ci_type);
1014    if ((cp = context_find (buffer)) && *cp != '\0')
1015        return show_content_aux (ct, serial, alternate, cp, NULL);
1016
1017    if ((cp = ct->c_showproc))
1018        return show_content_aux (ct, serial, alternate, cp, NULL);
1019
1020    /* default method for message/rfc822 */
1021    if (ct->c_subtype == MESSAGE_RFC822) {
1022        cp = (ct->c_showproc = add ("%pshow -file '%F'", NULL));
1023        return show_content_aux (ct, serial, alternate, cp, NULL);
1024    }
1025
1026    /* complain if we are not a part of a multipart/alternative */
1027    if (!alternate)
1028        content_error (NULL, ct, "don't know how to display content");
1029
1030    return NOTOK;
1031}
1032
1033
1034/*
1035 * Show content of type "message/partial".
1036 */
1037
1038static int
1039show_partial (CT ct, int serial, int alternate)
1040{
1041    content_error (NULL, ct,
1042        "in order to display this message, you must reassemble it");
1043    return NOTOK;
1044}
1045
1046
1047/*
1048 * Show content of type "message/external".
1049 *
1050 * THE ERROR CHECKING IN THIS ONE IS NOT DONE YET.
1051 */
1052
1053static int
1054show_external (CT ct, int serial, int alternate)
1055{
1056    struct exbody *e = (struct exbody *) ct->c_ctparams;
1057    CT p = e->eb_content;
1058
1059    if (!type_ok (p, 0))
1060        return OK;
1061
1062    return show_switch (p, serial, alternate);
1063
1064#if 0
1065    content_error (NULL, p, "don't know how to display content");
1066    return NOTOK;
1067#endif
1068}
1069
1070
1071static RETSIGTYPE
1072intrser (int i)
1073{
1074#ifndef RELIABLE_SIGNALS
1075    SIGNAL (SIGINT, intrser);
1076#endif
1077
1078    putchar ('\n');
1079    siglongjmp (intrenv, DONE);
1080}
1081
1082static RETSIGTYPE
1083intrser2 (int i)
1084{
1085#ifndef RELIABLE_SIGNALS
1086    SIGNAL (SIGINT, intrser2);
1087#endif
1088    kill (intrpid, SIGKILL);
1089}
1090
1091static  int sd = NOTOK;
1092
1093static void
1094m_popen (char *name)
1095{
1096    int pd[2];
1097
1098    if ((sd = dup (fileno (stdout))) == NOTOK)
1099        adios ("standard output", "unable to dup()");
1100
1101    if (pipe (pd) == NOTOK)
1102        adios ("pipe", "unable to");
1103
1104    switch (m_pid = vfork ()) {
1105        case NOTOK:
1106            adios ("fork", "unable to");
1107
1108        case OK:
1109            SIGNAL (SIGINT, SIG_DFL);
1110            SIGNAL (SIGQUIT, SIG_DFL);
1111
1112            close (pd[1]);
1113            if (pd[0] != fileno (stdin)) {
1114                dup2 (pd[0], fileno (stdin));
1115                close (pd[0]);
1116            }
1117            execlp (name, r1bindex (name, '/'), NULL);
1118            fprintf (stderr, "unable to exec ");
1119            perror (name);
1120            _exit (-1);
1121
1122        default:
1123            close (pd[0]);
1124            if (pd[1] != fileno (stdout)) {
1125                dup2 (pd[1], fileno (stdout));
1126                close (pd[1]);
1127            }
1128    }
1129}
1130
1131
1132void
1133m_pclose (void)
1134{
1135    if (!m_pid)
1136        return;
1137
1138    if (sd != NOTOK) {
1139        if (dup2 (sd, fileno (stdout)) == NOTOK)
1140            adios ("standard output", "unable to dup2()");
1141
1142        clearerr (stdout);
1143        close (sd);
1144        sd = NOTOK;
1145    }
1146    else
1147        fclose (stdout);
1148
1149    pidwait (m_pid, OK);
1150    m_pid = 0;
1151}
Note: See TracBrowser for help on using the repository browser.