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