Implemented store mode.
Showing
1 changed file
with
749 additions
and
76 deletions
... | @@ -18,6 +18,9 @@ | ... | @@ -18,6 +18,9 @@ |
18 | /* MH mhn command */ | 18 | /* MH mhn command */ |
19 | 19 | ||
20 | #include <mh.h> | 20 | #include <mh.h> |
21 | #define obstack_chunk_alloc xmalloc | ||
22 | #define obstack_chunk_free free | ||
23 | #include <obstack.h> | ||
21 | 24 | ||
22 | const char *argp_program_version = "mhn (" PACKAGE_STRING ")"; | 25 | const char *argp_program_version = "mhn (" PACKAGE_STRING ")"; |
23 | static char doc[] = N_("GNU MH mhn\v" | 26 | static char doc[] = N_("GNU MH mhn\v" |
... | @@ -57,15 +60,15 @@ static struct argp_option options[] = { | ... | @@ -57,15 +60,15 @@ static struct argp_option options[] = { |
57 | {"form", ARG_FORM, N_("FILE"), 0, | 60 | {"form", ARG_FORM, N_("FILE"), 0, |
58 | N_("Read mhl format from FILE"), 22}, | 61 | N_("Read mhl format from FILE"), 22}, |
59 | {"pause", ARG_PAUSE, N_("BOOL"), OPTION_ARG_OPTIONAL, | 62 | {"pause", ARG_PAUSE, N_("BOOL"), OPTION_ARG_OPTIONAL, |
60 | N_("* Pause prior to displaying content"), 22}, | 63 | N_("Pause prior to displaying content"), 22}, |
61 | {"nopause", ARG_NOPAUSE, NULL, OPTION_HIDDEN, "", 22 }, | 64 | {"nopause", ARG_NOPAUSE, NULL, OPTION_HIDDEN, "", 22 }, |
62 | 65 | ||
63 | {N_("Saving options"), 0, NULL, OPTION_DOC, NULL, 30}, | 66 | {N_("Saving options"), 0, NULL, OPTION_DOC, NULL, 30}, |
64 | {"store", ARG_STORE, N_("BOOL"), OPTION_ARG_OPTIONAL, | 67 | {"store", ARG_STORE, N_("BOOL"), OPTION_ARG_OPTIONAL, |
65 | N_("* Store the contents of the messages on disk"), 31}, | 68 | N_("Store the contents of the messages on disk"), 31}, |
66 | {"nostore", ARG_NOSTORE, NULL, OPTION_HIDDEN, "", 31 }, | 69 | {"nostore", ARG_NOSTORE, NULL, OPTION_HIDDEN, "", 31 }, |
67 | {"auto", ARG_AUTO, N_("BOOL"), OPTION_ARG_OPTIONAL, | 70 | {"auto", ARG_AUTO, N_("BOOL"), OPTION_ARG_OPTIONAL, |
68 | N_("* Use filenames from the content headers"), 31}, | 71 | N_("Use filenames from the content headers"), 31}, |
69 | {"noauto", ARG_NOAUTO, NULL, OPTION_HIDDEN, "", 31 }, | 72 | {"noauto", ARG_NOAUTO, NULL, OPTION_HIDDEN, "", 31 }, |
70 | 73 | ||
71 | {N_("Other options"), 0, NULL, OPTION_DOC, NULL, 40}, | 74 | {N_("Other options"), 0, NULL, OPTION_DOC, NULL, 40}, |
... | @@ -76,6 +79,8 @@ static struct argp_option options[] = { | ... | @@ -76,6 +79,8 @@ static struct argp_option options[] = { |
76 | {"verbose", ARG_VERBOSE, N_("BOOL"), OPTION_ARG_OPTIONAL, | 79 | {"verbose", ARG_VERBOSE, N_("BOOL"), OPTION_ARG_OPTIONAL, |
77 | N_("Print additional information"), 41 }, | 80 | N_("Print additional information"), 41 }, |
78 | {"noverbose", ARG_NOVERBOSE, NULL, OPTION_HIDDEN, "", 41 }, | 81 | {"noverbose", ARG_NOVERBOSE, NULL, OPTION_HIDDEN, "", 41 }, |
82 | {"quiet", ARG_QUIET, 0, 0, | ||
83 | N_("Be quiet")}, | ||
79 | {NULL} | 84 | {NULL} |
80 | }; | 85 | }; |
81 | 86 | ||
... | @@ -125,6 +130,7 @@ static enum mhn_mode mode = mode_compose; | ... | @@ -125,6 +130,7 @@ static enum mhn_mode mode = mode_compose; |
125 | #define OPT_AUTO 010 | 130 | #define OPT_AUTO 010 |
126 | #define OPT_SERIALONLY 020 | 131 | #define OPT_SERIALONLY 020 |
127 | #define OPT_VERBOSE 040 | 132 | #define OPT_VERBOSE 040 |
133 | #define OPT_QUIET 100 | ||
128 | 134 | ||
129 | static int mode_options = OPT_HEADERS; | 135 | static int mode_options = OPT_HEADERS; |
130 | static char *formfile; | 136 | static char *formfile; |
... | @@ -138,6 +144,12 @@ static mailbox_t mbox; | ... | @@ -138,6 +144,12 @@ static mailbox_t mbox; |
138 | static message_t message; | 144 | static message_t message; |
139 | static msg_part_t req_part; | 145 | static msg_part_t req_part; |
140 | 146 | ||
147 | /* Show flags */ | ||
148 | #define MHN_EXCLUSIVE_EXEC 001 | ||
149 | #define MHN_STDIN 002 | ||
150 | #define MHN_LISTING 004 | ||
151 | #define MHN_CONFIRM 010 | ||
152 | |||
141 | void | 153 | void |
142 | sfree (char **ptr) | 154 | sfree (char **ptr) |
143 | { | 155 | { |
... | @@ -170,6 +182,60 @@ split_content (const char *content, char **type, char **subtype) | ... | @@ -170,6 +182,60 @@ split_content (const char *content, char **type, char **subtype) |
170 | } | 182 | } |
171 | } | 183 | } |
172 | 184 | ||
185 | int | ||
186 | _get_hdr_value (header_t hdr, const char *name, char **value) | ||
187 | { | ||
188 | int status = header_aget_value (hdr, name, value); | ||
189 | if (status == 0) | ||
190 | { | ||
191 | /* Remove the newlines. */ | ||
192 | char *nl; | ||
193 | while ((nl = strchr (*value, '\n')) != NULL) | ||
194 | *nl = ' '; | ||
195 | } | ||
196 | return status; | ||
197 | } | ||
198 | |||
199 | int | ||
200 | _get_content_type (header_t hdr, char **value, char **rest) | ||
201 | { | ||
202 | char *type = NULL; | ||
203 | _get_hdr_value (hdr, MU_HEADER_CONTENT_TYPE, &type); | ||
204 | if (type == NULL || *type == '\0') | ||
205 | { | ||
206 | if (type) | ||
207 | free (type); | ||
208 | type = strdup ("text/plain"); /* Default. */ | ||
209 | if (rest) | ||
210 | *rest = NULL; | ||
211 | } | ||
212 | else | ||
213 | { | ||
214 | char *p = strchr (type, ';'); | ||
215 | if (p) | ||
216 | *p++ = 0; | ||
217 | if (rest) | ||
218 | *rest = p; | ||
219 | } | ||
220 | *value = type; | ||
221 | return 0; | ||
222 | } | ||
223 | |||
224 | static int | ||
225 | _get_content_encoding (header_t hdr, char **value) | ||
226 | { | ||
227 | char *encoding = NULL; | ||
228 | _get_hdr_value (hdr, MU_HEADER_CONTENT_TRANSFER_ENCODING, &encoding); | ||
229 | if (encoding == NULL || *encoding == '\0') | ||
230 | { | ||
231 | if (encoding) | ||
232 | free (encoding); | ||
233 | encoding = strdup ("7bit"); /* Default. */ | ||
234 | } | ||
235 | *value = encoding; | ||
236 | return 0; | ||
237 | } | ||
238 | |||
173 | static int | 239 | static int |
174 | opt_handler (int key, char *arg, void *unused, struct argp_state *state) | 240 | opt_handler (int key, char *arg, void *unused, struct argp_state *state) |
175 | { | 241 | { |
... | @@ -316,7 +382,11 @@ opt_handler (int key, char *arg, void *unused, struct argp_state *state) | ... | @@ -316,7 +382,11 @@ opt_handler (int key, char *arg, void *unused, struct argp_state *state) |
316 | case ARG_PART: | 382 | case ARG_PART: |
317 | req_part = msg_part_parse (arg); | 383 | req_part = msg_part_parse (arg); |
318 | break; | 384 | break; |
319 | 385 | ||
386 | case ARG_QUIET: | ||
387 | mode_options |= OPT_QUIET; | ||
388 | break; | ||
389 | |||
320 | default: | 390 | default: |
321 | return 1; | 391 | return 1; |
322 | } | 392 | } |
... | @@ -405,6 +475,50 @@ msg_part_print (msg_part_t p, int max_width) | ... | @@ -405,6 +475,50 @@ msg_part_print (msg_part_t p, int max_width) |
405 | putchar (' '); | 475 | putchar (' '); |
406 | } | 476 | } |
407 | 477 | ||
478 | char * | ||
479 | msg_part_format (msg_part_t p) | ||
480 | { | ||
481 | int i; | ||
482 | int width = 0; | ||
483 | char *str, *s; | ||
484 | char buf[64]; | ||
485 | |||
486 | for (i = 1; i <= p->level; i++) | ||
487 | { | ||
488 | if (i > 1) | ||
489 | width++; | ||
490 | width += snprintf (buf, sizeof buf, "%lu", (unsigned long) p->part[i]); | ||
491 | } | ||
492 | |||
493 | str = s = xmalloc (width + 1); | ||
494 | for (i = 1; i <= p->level; i++) | ||
495 | { | ||
496 | if (i > 1) | ||
497 | *s++ = '.'; | ||
498 | s += sprintf (s, "%lu", (unsigned long) p->part[i]); | ||
499 | } | ||
500 | *s = 0; | ||
501 | return str; | ||
502 | } | ||
503 | |||
504 | void | ||
505 | msg_part_format_stk (struct obstack *stk, msg_part_t p) | ||
506 | { | ||
507 | int i; | ||
508 | char buf[64]; | ||
509 | |||
510 | for (i = 1; i <= p->level; i++) | ||
511 | { | ||
512 | int len; | ||
513 | |||
514 | if (i > 1) | ||
515 | obstack_1grow (stk, '.'); | ||
516 | |||
517 | len = snprintf (buf, sizeof buf, "%lu", (unsigned long) p->part[i]); | ||
518 | obstack_grow (stk, buf, len); | ||
519 | } | ||
520 | } | ||
521 | |||
408 | msg_part_t | 522 | msg_part_t |
409 | msg_part_parse (char *str) | 523 | msg_part_parse (char *str) |
410 | { | 524 | { |
... | @@ -449,58 +563,239 @@ msg_part_subpart (msg_part_t p, int level) | ... | @@ -449,58 +563,239 @@ msg_part_subpart (msg_part_t p, int level) |
449 | } | 563 | } |
450 | 564 | ||
451 | 565 | ||
452 | /* ************************** Message iterators *************************** */ | 566 | /* *********************** Context file accessors ************************* */ |
453 | 567 | ||
454 | int | 568 | char * |
455 | _get_hdr_value (header_t hdr, const char *name, char **value) | 569 | _mhn_profile_get (char *prefix, char *type, char *subtype, char *defval) |
456 | { | 570 | { |
457 | int status = header_aget_value (hdr, name, value); | 571 | char *str, *name; |
458 | if (status == 0) | 572 | |
573 | if (subtype) | ||
459 | { | 574 | { |
460 | /* Remove the newlines. */ | 575 | asprintf (&name, "mhn-%s-%s/%s", prefix, type, subtype); |
461 | char *nl; | 576 | str = mh_global_profile_get (name, NULL); |
462 | while ((nl = strchr (*value, '\n')) != NULL) | 577 | free (name); |
463 | *nl = ' '; | 578 | if (!str) |
579 | return _mhn_profile_get (prefix, type, NULL, defval); | ||
464 | } | 580 | } |
465 | return status; | 581 | else |
582 | { | ||
583 | asprintf (&name, "mhn-%s-%s", prefix, type); | ||
584 | str = mh_global_profile_get (name, defval); | ||
585 | free (name); | ||
586 | } | ||
587 | return str; | ||
466 | } | 588 | } |
467 | 589 | ||
468 | int | 590 | char * |
469 | _get_content_type (header_t hdr, char **value) | 591 | mhn_show_command (message_t msg, msg_part_t part, int *flags, char **tempfile) |
470 | { | 592 | { |
471 | char *type = NULL; | 593 | char *p, *str, *tmp; |
472 | _get_hdr_value (hdr, MU_HEADER_CONTENT_TYPE, &type); | 594 | char *typestr, *type, *subtype, *typeargs; |
473 | if (type == NULL || *type == '\0') | 595 | struct obstack stk; |
596 | header_t hdr; | ||
597 | |||
598 | message_get_header (msg, &hdr); | ||
599 | _get_content_type (hdr, &typestr, &typeargs); | ||
600 | split_content (typestr, &type, &subtype); | ||
601 | str = _mhn_profile_get ("show", type, subtype, NULL); | ||
602 | if (!str) /* FIXME */ | ||
603 | return NULL; | ||
604 | |||
605 | /* Expand macro-notations: | ||
606 | %a additional arguments | ||
607 | %e exclusive execution | ||
608 | %f filename containing content | ||
609 | %F %e, %f, and stdin is terminal not content | ||
610 | %l display listing prior to displaying content | ||
611 | %p %l, and ask for confirmation | ||
612 | %s subtype | ||
613 | %d content description */ | ||
614 | |||
615 | obstack_init (&stk); | ||
616 | for (p = str; *p && isspace (*p); p++) | ||
617 | ; | ||
618 | |||
619 | if (*p == '|') | ||
620 | p++; | ||
621 | |||
622 | for ( ; *p; p++) | ||
474 | { | 623 | { |
475 | if (type) | 624 | if (*p == '%') |
476 | free (type); | 625 | { |
477 | type = strdup ("text/plain"); /* Default. */ | 626 | switch (*++p) |
627 | { | ||
628 | case 'a': | ||
629 | /* additional arguments */ | ||
630 | obstack_grow (&stk, typeargs, strlen (typeargs)); | ||
631 | break; | ||
632 | |||
633 | case 'e': | ||
634 | /* exclusive execution */ | ||
635 | *flags |= MHN_EXCLUSIVE_EXEC; | ||
636 | break; | ||
637 | |||
638 | case 'f': | ||
639 | /* filename containing content */ | ||
640 | if (!*tempfile) | ||
641 | *tempfile = mu_tempname (NULL); | ||
642 | obstack_grow (&stk, *tempfile, strlen (*tempfile)); | ||
643 | break; | ||
644 | |||
645 | case 'F': | ||
646 | /* %e, %f, and stdin is terminal not content */ | ||
647 | *flags |= MHN_STDIN|MHN_EXCLUSIVE_EXEC; | ||
648 | if (!*tempfile) | ||
649 | *tempfile = mu_tempname (NULL); | ||
650 | obstack_grow (&stk, *tempfile, strlen (*tempfile)); | ||
651 | break; | ||
652 | |||
653 | case 'l': | ||
654 | /* display listing prior to displaying content */ | ||
655 | *flags |= MHN_LISTING; | ||
656 | break; | ||
657 | |||
658 | case 'p': | ||
659 | /* %l, and ask for confirmation */ | ||
660 | *flags |= MHN_LISTING|MHN_CONFIRM; | ||
661 | break; | ||
662 | |||
663 | case 's': | ||
664 | /* subtype */ | ||
665 | obstack_grow (&stk, subtype, strlen (subtype)); | ||
666 | break; | ||
667 | |||
668 | case 'd': | ||
669 | /* content description */ | ||
670 | if (header_aget_value (hdr, MU_HEADER_CONTENT_DESCRIPTION, | ||
671 | &tmp) == 0) | ||
672 | { | ||
673 | obstack_grow (&stk, tmp, strlen (tmp)); | ||
674 | free (tmp); | ||
675 | } | ||
676 | break; | ||
677 | |||
678 | default: | ||
679 | obstack_1grow (&stk, *p); | ||
680 | p++; | ||
681 | } | ||
682 | } | ||
683 | else | ||
684 | obstack_1grow (&stk, *p); | ||
478 | } | 685 | } |
686 | obstack_1grow (&stk, 0); | ||
687 | |||
688 | free (typestr); | ||
689 | free (type); | ||
690 | free (subtype); | ||
691 | |||
692 | str = obstack_finish (&stk); | ||
693 | for (p = str; *p && isspace (*p); p++) | ||
694 | ; | ||
695 | if (!*p) | ||
696 | str = NULL; | ||
479 | else | 697 | else |
480 | { | 698 | str = strdup (str); |
481 | char *p = strchr (type, ';'); | 699 | |
482 | if (p) | 700 | obstack_free (&stk, NULL); |
483 | *p = 0; | 701 | return str; |
484 | } | ||
485 | *value = type; | ||
486 | return 0; | ||
487 | } | 702 | } |
488 | 703 | ||
489 | static int | 704 | char * |
490 | _get_content_encoding (header_t hdr, char **value) | 705 | mhn_store_command (message_t msg, msg_part_t part, char *name) |
491 | { | 706 | { |
492 | char *encoding = NULL; | 707 | char *p, *str, *tmp; |
493 | _get_hdr_value (hdr, MU_HEADER_CONTENT_TRANSFER_ENCODING, &encoding); | 708 | char *typestr, *type, *subtype, *typeargs; |
494 | if (encoding == NULL || *encoding == '\0') | 709 | struct obstack stk; |
710 | header_t hdr; | ||
711 | char buf[64]; | ||
712 | |||
713 | message_get_header (msg, &hdr); | ||
714 | _get_content_type (hdr, &typestr, &typeargs); | ||
715 | split_content (typestr, &type, &subtype); | ||
716 | str = _mhn_profile_get ("show", type, subtype, "%m%P.%s"); | ||
717 | |||
718 | /* Expand macro-notations: | ||
719 | %m message number | ||
720 | %P .part | ||
721 | %p part | ||
722 | %s subtype */ | ||
723 | |||
724 | obstack_init (&stk); | ||
725 | for (p = str; *p; p++) | ||
495 | { | 726 | { |
496 | if (encoding) | 727 | if (*p == '%') |
497 | free (encoding); | 728 | { |
498 | encoding = strdup ("7bit"); /* Default. */ | 729 | switch (*++p) |
730 | { | ||
731 | case 'a': | ||
732 | /* additional arguments */ | ||
733 | obstack_grow (&stk, typeargs, strlen (typeargs)); | ||
734 | break; | ||
735 | |||
736 | case 'm': | ||
737 | if (name) | ||
738 | obstack_grow (&stk, name, strlen (name)); | ||
739 | else | ||
740 | { | ||
741 | snprintf (buf, sizeof buf, "%lu", | ||
742 | (unsigned long) msg_part_subpart (part, 0)); | ||
743 | obstack_grow (&stk, buf, strlen (buf)); | ||
744 | } | ||
745 | break; | ||
746 | |||
747 | case 'P': | ||
748 | obstack_1grow (&stk, '.'); | ||
749 | /*FALLTHRU*/ | ||
750 | case 'p': | ||
751 | msg_part_format_stk (&stk, part); | ||
752 | break; | ||
753 | |||
754 | case 's': | ||
755 | /* subtype */ | ||
756 | obstack_grow (&stk, subtype, strlen (subtype)); | ||
757 | break; | ||
758 | |||
759 | case 'd': | ||
760 | /* content description */ | ||
761 | if (header_aget_value (hdr, MU_HEADER_CONTENT_DESCRIPTION, | ||
762 | &tmp) == 0) | ||
763 | { | ||
764 | obstack_grow (&stk, tmp, strlen (tmp)); | ||
765 | free (tmp); | ||
766 | } | ||
767 | break; | ||
768 | |||
769 | default: | ||
770 | obstack_1grow (&stk, *p); | ||
771 | p++; | ||
772 | } | ||
773 | } | ||
774 | else | ||
775 | obstack_1grow (&stk, *p); | ||
499 | } | 776 | } |
500 | *value = encoding; | 777 | obstack_1grow (&stk, *p); |
501 | return 0; | 778 | |
779 | free (typestr); | ||
780 | free (type); | ||
781 | free (subtype); | ||
782 | |||
783 | str = obstack_finish (&stk); | ||
784 | for (p = str; *p && isspace (*p); p++) | ||
785 | ; | ||
786 | if (!*p) | ||
787 | str = NULL; | ||
788 | else | ||
789 | str = strdup (str); | ||
790 | |||
791 | obstack_free (&stk, NULL); | ||
792 | return str; | ||
502 | } | 793 | } |
503 | 794 | ||
795 | |||
796 | /* ************************** Message iterators *************************** */ | ||
797 | |||
798 | |||
504 | typedef int (*msg_handler_t) __PMT((message_t msg, msg_part_t part, | 799 | typedef int (*msg_handler_t) __PMT((message_t msg, msg_part_t part, |
505 | char *type, char *encoding, | 800 | char *type, char *encoding, |
506 | void *data)); | 801 | void *data)); |
... | @@ -518,8 +813,11 @@ match_content (char *content) | ... | @@ -518,8 +813,11 @@ match_content (char *content) |
518 | 813 | ||
519 | split_content (content, &type, &subtype); | 814 | split_content (content, &type, &subtype); |
520 | 815 | ||
521 | if (strcasecmp (content_type, type) == 0) | 816 | if ((rc = strcasecmp (content_type, type)) == 0) |
522 | rc = strcasecmp (content_subtype, subtype); | 817 | { |
818 | if (content_subtype) | ||
819 | rc = strcasecmp (content_subtype, subtype); | ||
820 | } | ||
523 | else | 821 | else |
524 | rc = strcasecmp (content_type, subtype); | 822 | rc = strcasecmp (content_type, subtype); |
525 | 823 | ||
... | @@ -548,7 +846,7 @@ handle_message (message_t msg, msg_part_t part, msg_handler_t fun, void *data) | ... | @@ -548,7 +846,7 @@ handle_message (message_t msg, msg_part_t part, msg_handler_t fun, void *data) |
548 | int ismime = 0; | 846 | int ismime = 0; |
549 | 847 | ||
550 | message_get_header (msg, &hdr); | 848 | message_get_header (msg, &hdr); |
551 | _get_content_type (hdr, &type); | 849 | _get_content_type (hdr, &type, NULL); |
552 | _get_content_encoding (hdr, &encoding); | 850 | _get_content_encoding (hdr, &encoding); |
553 | 851 | ||
554 | fun (msg, part, type, encoding, data); | 852 | fun (msg, part, type, encoding, data); |
... | @@ -570,12 +868,12 @@ handle_message (message_t msg, msg_part_t part, msg_handler_t fun, void *data) | ... | @@ -570,12 +868,12 @@ handle_message (message_t msg, msg_part_t part, msg_handler_t fun, void *data) |
570 | if (message_get_part (msg, i, &message) == 0) | 868 | if (message_get_part (msg, i, &message) == 0) |
571 | { | 869 | { |
572 | message_get_header (message, &hdr); | 870 | message_get_header (message, &hdr); |
573 | _get_content_type (hdr, &type); | 871 | _get_content_type (hdr, &type, NULL); |
574 | _get_content_encoding (hdr, &encoding); | 872 | _get_content_encoding (hdr, &encoding); |
575 | 873 | ||
576 | msg_part_set_subpart (part, i); | 874 | msg_part_set_subpart (part, i); |
577 | 875 | ||
578 | if (strcasecmp (type, "multipart/mixed") == 0) | 876 | if (message_is_multipart (message, &ismime) == 0 && ismime) |
579 | handle_message (message, part, fun, data); | 877 | handle_message (message, part, fun, data); |
580 | else | 878 | else |
581 | call_handler (message, part, type, encoding, fun, data); | 879 | call_handler (message, part, type, encoding, fun, data); |
... | @@ -641,18 +939,23 @@ list_handler (message_t msg, msg_part_t part, char *type, char *encoding, | ... | @@ -641,18 +939,23 @@ list_handler (message_t msg, msg_part_t part, char *type, char *encoding, |
641 | header_t hdr; | 939 | header_t hdr; |
642 | 940 | ||
643 | if (msg_part_level (part) == 0) | 941 | if (msg_part_level (part) == 0) |
644 | printf ("%3lu ", (unsigned long) msg_part_subpart (part, 0)); | 942 | printf ("%4lu ", (unsigned long) msg_part_subpart (part, 0)); |
645 | else | 943 | else |
646 | { | 944 | { |
647 | printf (" "); | 945 | printf (" "); |
648 | msg_part_print (part, 5); | 946 | msg_part_print (part, 4); |
649 | putchar (' '); | 947 | putchar (' '); |
650 | } | 948 | } |
651 | printf ("%-26s", type); | 949 | printf ("%-25s", type); |
652 | 950 | ||
653 | mhn_message_size (msg, &size); | 951 | mhn_message_size (msg, &size); |
654 | printf ("%4lu", (unsigned long) size); | 952 | if (size < 1024) |
655 | 953 | printf (" %4lu", (unsigned long) size); | |
954 | else if (size < 1024*1024) | ||
955 | printf ("%4luK", (unsigned long) size / 1024); | ||
956 | else | ||
957 | printf ("%4luM", (unsigned long) size / 1024 / 1024); | ||
958 | |||
656 | if (message_get_header (msg, &hdr) == 0) | 959 | if (message_get_header (msg, &hdr) == 0) |
657 | { | 960 | { |
658 | char *descr; | 961 | char *descr; |
... | @@ -670,7 +973,11 @@ list_handler (message_t msg, msg_part_t part, char *type, char *encoding, | ... | @@ -670,7 +973,11 @@ list_handler (message_t msg, msg_part_t part, char *type, char *encoding, |
670 | int | 973 | int |
671 | list_message (message_t msg, size_t num) | 974 | list_message (message_t msg, size_t num) |
672 | { | 975 | { |
673 | msg_part_t part = msg_part_create (num); | 976 | size_t uid; |
977 | msg_part_t part; | ||
978 | |||
979 | mh_message_number (msg, &uid); | ||
980 | part = msg_part_create (uid); | ||
674 | handle_message (msg, part, list_handler, NULL); | 981 | handle_message (msg, part, list_handler, NULL); |
675 | msg_part_destroy (part); | 982 | msg_part_destroy (part); |
676 | return 0; | 983 | return 0; |
... | @@ -688,7 +995,7 @@ mhn_list () | ... | @@ -688,7 +995,7 @@ mhn_list () |
688 | int rc; | 995 | int rc; |
689 | 996 | ||
690 | if (mode_options & OPT_HEADERS) | 997 | if (mode_options & OPT_HEADERS) |
691 | printf (_("msg part type/subtype size description\n")); | 998 | printf (_(" msg part type/subtype size description\n")); |
692 | 999 | ||
693 | if (message) | 1000 | if (message) |
694 | rc = list_message (message, 0); | 1001 | rc = list_message (message, 0); |
... | @@ -717,43 +1024,189 @@ cat_message (stream_t out, stream_t in) | ... | @@ -717,43 +1024,189 @@ cat_message (stream_t out, stream_t in) |
717 | } | 1024 | } |
718 | 1025 | ||
719 | int | 1026 | int |
1027 | show_internal (message_t msg, msg_part_t part, char *encoding, stream_t out) | ||
1028 | { | ||
1029 | int rc; | ||
1030 | body_t body = NULL; | ||
1031 | stream_t dstr, bstr; | ||
1032 | |||
1033 | if ((rc = message_get_body (msg, &body))) | ||
1034 | { | ||
1035 | mh_error (_("%lu: can't get message body: %s"), | ||
1036 | (unsigned long) msg_part_subpart (part, 0), | ||
1037 | mu_strerror (rc)); | ||
1038 | return 0; | ||
1039 | } | ||
1040 | body_get_stream (body, &bstr); | ||
1041 | rc = filter_create(&dstr, bstr, encoding, | ||
1042 | MU_FILTER_DECODE, MU_STREAM_READ); | ||
1043 | if (rc == 0) | ||
1044 | bstr = dstr; | ||
1045 | cat_message (out, bstr); | ||
1046 | if (dstr) | ||
1047 | stream_destroy (&dstr, stream_get_owner (dstr)); | ||
1048 | return 0; | ||
1049 | } | ||
1050 | |||
1051 | int | ||
1052 | exec_internal (message_t msg, msg_part_t part, char *encoding, char *cmd) | ||
1053 | { | ||
1054 | int rc; | ||
1055 | stream_t tmp; | ||
1056 | |||
1057 | rc = prog_stream_create (&tmp, cmd, MU_STREAM_WRITE); | ||
1058 | if (rc) | ||
1059 | { | ||
1060 | mh_error (_("can't create proc stream (command %s): %s"), | ||
1061 | cmd, mu_strerror (rc)); | ||
1062 | return rc; | ||
1063 | } | ||
1064 | rc = stream_open (tmp); | ||
1065 | if (rc) | ||
1066 | { | ||
1067 | mh_error (_("can't open proc stream (command %s): %s"), | ||
1068 | cmd, mu_strerror (rc)); | ||
1069 | return rc; | ||
1070 | } | ||
1071 | show_internal (msg, part, encoding, tmp); | ||
1072 | stream_destroy (&tmp, stream_get_owner (tmp)); | ||
1073 | return rc; | ||
1074 | } | ||
1075 | |||
1076 | /* FIXME: stdin is always opened when invoking subprocess, no matter | ||
1077 | what the MHN_STDIN bit is */ | ||
1078 | |||
1079 | int | ||
1080 | mhn_run_command (message_t msg, msg_part_t part, | ||
1081 | char *encoding, | ||
1082 | char *cmd, int flags, | ||
1083 | char *tempfile) | ||
1084 | { | ||
1085 | int rc = 0; | ||
1086 | |||
1087 | if (tempfile) | ||
1088 | { | ||
1089 | /* pass content via a tempfile */ | ||
1090 | int status; | ||
1091 | int argc; | ||
1092 | char **argv; | ||
1093 | stream_t tmp; | ||
1094 | |||
1095 | if (argcv_get (cmd, "", "#", &argc, &argv)) | ||
1096 | { | ||
1097 | mh_error (_("can't parse command line `%s'"), cmd); | ||
1098 | return ENOSYS; | ||
1099 | } | ||
1100 | |||
1101 | rc = file_stream_create (&tmp, tempfile, MU_STREAM_RDWR); | ||
1102 | if (rc) | ||
1103 | { | ||
1104 | mh_error (_("can't create temporary stream (file %s): %s"), | ||
1105 | tempfile, mu_strerror (rc)); | ||
1106 | argcv_free (argc, argv); | ||
1107 | return rc; | ||
1108 | } | ||
1109 | rc = stream_open (tmp); | ||
1110 | if (rc) | ||
1111 | { | ||
1112 | mh_error (_("can't open temporary stream (file %s): %s"), | ||
1113 | tempfile, mu_strerror (rc)); | ||
1114 | stream_destroy (&tmp, stream_get_owner (tmp)); | ||
1115 | argcv_free (argc, argv); | ||
1116 | return rc; | ||
1117 | } | ||
1118 | show_internal (msg, part, encoding, tmp); | ||
1119 | stream_destroy (&tmp, stream_get_owner (tmp)); | ||
1120 | rc = mu_spawnvp (argv[0], argv, &status); | ||
1121 | if (status) | ||
1122 | rc = status; | ||
1123 | argcv_free (argc, argv); | ||
1124 | } | ||
1125 | else | ||
1126 | rc = exec_internal (msg, part, encoding, cmd); | ||
1127 | |||
1128 | return rc; | ||
1129 | } | ||
1130 | |||
1131 | int | ||
720 | show_handler (message_t msg, msg_part_t part, char *type, char *encoding, | 1132 | show_handler (message_t msg, msg_part_t part, char *type, char *encoding, |
721 | void *data) | 1133 | void *data) |
722 | { | 1134 | { |
723 | stream_t out = data; | 1135 | stream_t out = data; |
724 | 1136 | char *cmd; | |
725 | if (strncasecmp (type, "multipart", 9) == 0) | 1137 | int flags = 0; |
1138 | char buf[64]; | ||
1139 | int fd = 1; | ||
1140 | char *tempfile = NULL; | ||
1141 | int ismime; | ||
1142 | |||
1143 | if (message_is_multipart (msg, &ismime) == 0 && ismime) | ||
726 | return 0; | 1144 | return 0; |
727 | if (mhl_format) | 1145 | |
728 | mhl_format_run (mhl_format, width, 0, MHL_DECODE, msg, out); | 1146 | stream_get_fd (out, &fd); |
729 | else | 1147 | |
1148 | if (mode_options & OPT_PAUSE) | ||
1149 | flags |= MHN_CONFIRM; | ||
1150 | cmd = mhn_show_command (msg, part, &flags, &tempfile); | ||
1151 | if (!cmd) | ||
1152 | flags |= MHN_LISTING; | ||
1153 | if (flags & MHN_LISTING) | ||
730 | { | 1154 | { |
731 | int rc; | 1155 | char *str; |
732 | body_t body = NULL; | 1156 | size_t size = 0; |
733 | stream_t dstr, bstr; | 1157 | |
734 | 1158 | str = _("part "); | |
735 | if ((rc = message_get_body (msg, &body))) | 1159 | stream_sequential_write (out, str, strlen (str)); |
1160 | str = msg_part_format (part); | ||
1161 | stream_sequential_write (out, str, strlen (str)); | ||
1162 | free (str); | ||
1163 | stream_sequential_write (out, " ", 1); | ||
1164 | stream_sequential_write (out, type, strlen (type)); | ||
1165 | mhn_message_size (msg, &size); | ||
1166 | snprintf (buf, sizeof buf, " %lu", (unsigned long) size); | ||
1167 | stream_sequential_write (out, buf, strlen (buf)); | ||
1168 | stream_sequential_write (out, "\n", 1); | ||
1169 | stream_flush (out); | ||
1170 | } | ||
1171 | |||
1172 | if (flags & MHN_CONFIRM) | ||
1173 | { | ||
1174 | if (isatty (fd) && isatty (0)) | ||
736 | { | 1175 | { |
737 | mh_error (_("%lu: can't get message body: %s"), | 1176 | printf (_("Press <return> to show content...")); |
738 | (unsigned long) msg_part_subpart (part, 0), | 1177 | if (!fgets (buf, sizeof buf, stdin) || buf[0] != '\n') |
739 | mu_strerror (rc)); | 1178 | return 0; |
740 | return 0; | ||
741 | } | 1179 | } |
742 | body_get_stream (body, &bstr); | 1180 | } |
743 | rc = filter_create(&dstr, bstr, encoding, | 1181 | |
744 | MU_FILTER_DECODE, MU_STREAM_READ); | 1182 | if (!cmd) |
745 | if (rc == 0) | 1183 | { |
746 | bstr = dstr; | 1184 | char *pager = mh_global_profile_get ("moreproc", getenv ("PAGER")); |
747 | cat_message (out, bstr); | 1185 | if (pager) |
748 | if (dstr) | 1186 | exec_internal (msg, part, encoding, pager); |
749 | stream_destroy (&dstr, stream_get_owner (dstr)); | 1187 | else |
1188 | show_internal (msg, part, encoding, out); | ||
1189 | } | ||
1190 | else | ||
1191 | { | ||
1192 | mhn_run_command (msg, part, encoding, cmd, flags, tempfile); | ||
1193 | free (cmd); | ||
1194 | unlink (tempfile); | ||
1195 | free (tempfile); | ||
750 | } | 1196 | } |
1197 | |||
1198 | return 0; | ||
751 | } | 1199 | } |
752 | 1200 | ||
753 | int | 1201 | int |
754 | show_message (message_t msg, size_t num, void *data) | 1202 | show_message (message_t msg, size_t num, void *data) |
755 | { | 1203 | { |
756 | msg_part_t part = msg_part_create (num); | 1204 | msg_part_t part = msg_part_create (num); |
1205 | |||
1206 | if (mhl_format) | ||
1207 | mhl_format_run (mhl_format, width, 0, MHL_DISABLE_BODY, msg, | ||
1208 | (stream_t) data); | ||
1209 | |||
757 | handle_message (msg, part, show_handler, data); | 1210 | handle_message (msg, part, show_handler, data); |
758 | msg_part_destroy (part); | 1211 | msg_part_destroy (part); |
759 | return 0; | 1212 | return 0; |
... | @@ -762,7 +1215,12 @@ show_message (message_t msg, size_t num, void *data) | ... | @@ -762,7 +1215,12 @@ show_message (message_t msg, size_t num, void *data) |
762 | void | 1215 | void |
763 | show_iterator (mailbox_t mbox, message_t msg, size_t num, void *data) | 1216 | show_iterator (mailbox_t mbox, message_t msg, size_t num, void *data) |
764 | { | 1217 | { |
1218 | msg_part_t part; | ||
1219 | |||
1220 | mh_message_number (msg, &num); | ||
1221 | part = msg_part_create (num); | ||
765 | show_message (msg, num, data); | 1222 | show_message (msg, num, data); |
1223 | msg_part_destroy (part); | ||
766 | } | 1224 | } |
767 | 1225 | ||
768 | int | 1226 | int |
... | @@ -807,6 +1265,222 @@ mhn_show () | ... | @@ -807,6 +1265,222 @@ mhn_show () |
807 | rc = mh_iterate (mbox, &msgset, show_iterator, ostr); | 1265 | rc = mh_iterate (mbox, &msgset, show_iterator, ostr); |
808 | return rc; | 1266 | return rc; |
809 | } | 1267 | } |
1268 | |||
1269 | /* ***************************** Store Mode ****************************** */ | ||
1270 | |||
1271 | char * | ||
1272 | normalize_path (char *cwd, char *path) | ||
1273 | { | ||
1274 | int len; | ||
1275 | char *p; | ||
1276 | char *pcwd = NULL; | ||
1277 | |||
1278 | if (!path) | ||
1279 | return path; | ||
1280 | |||
1281 | if (path[0] == '/') | ||
1282 | return NULL; | ||
1283 | |||
1284 | if (!cwd) | ||
1285 | cwd = pcwd = mu_getcwd (); | ||
1286 | |||
1287 | len = strlen (cwd) + strlen (path) + 2; | ||
1288 | p = xmalloc (len); | ||
1289 | sprintf (p, "%s/%s", cwd, path); | ||
1290 | path = p; | ||
1291 | |||
1292 | /* delete trailing delimiter if any */ | ||
1293 | if (len && path[len-1] == '/') | ||
1294 | path[len-1] = 0; | ||
1295 | |||
1296 | /* Eliminate any /../ */ | ||
1297 | for (p = strchr (path, '.'); p; p = strchr (p, '.')) | ||
1298 | { | ||
1299 | if (p > path && p[-1] == '/') | ||
1300 | { | ||
1301 | if (p[1] == '.' && (p[2] == 0 || p[2] == '/')) | ||
1302 | /* found */ | ||
1303 | { | ||
1304 | char *q, *s; | ||
1305 | |||
1306 | /* Find previous delimiter */ | ||
1307 | for (q = p-2; *q != '/' && q >= path; q--) | ||
1308 | ; | ||
1309 | |||
1310 | if (q < path) | ||
1311 | break; | ||
1312 | /* Copy stuff */ | ||
1313 | s = p + 2; | ||
1314 | p = q; | ||
1315 | while (*q++ = *s++) | ||
1316 | ; | ||
1317 | continue; | ||
1318 | } | ||
1319 | } | ||
1320 | |||
1321 | p++; | ||
1322 | } | ||
1323 | |||
1324 | if (path[0] == 0) | ||
1325 | { | ||
1326 | path[0] = '/'; | ||
1327 | path[1] = 0; | ||
1328 | } | ||
1329 | |||
1330 | len = strlen (cwd); | ||
1331 | if (strlen (path) < len || memcmp (path, cwd, len)) | ||
1332 | sfree (&path); | ||
1333 | else | ||
1334 | memmove (path, path + len + 1, strlen (path) - len); | ||
1335 | free (pcwd); | ||
1336 | return path; | ||
1337 | } | ||
1338 | |||
1339 | int | ||
1340 | store_handler (message_t msg, msg_part_t part, char *type, char *encoding, | ||
1341 | void *data) | ||
1342 | { | ||
1343 | char *prefix = data; | ||
1344 | char *name = NULL; | ||
1345 | char *tmp; | ||
1346 | int ismime; | ||
1347 | int rc; | ||
1348 | stream_t out; | ||
1349 | char *dir = mh_global_profile_get ("mhn-storage", NULL); | ||
1350 | |||
1351 | if (message_is_multipart (msg, &ismime) == 0 && ismime) | ||
1352 | return 0; | ||
1353 | |||
1354 | if (mode_options & OPT_AUTO) | ||
1355 | { | ||
1356 | header_t hdr; | ||
1357 | char *val; | ||
1358 | |||
1359 | if (message_get_header (msg, &hdr) == 0 | ||
1360 | && header_aget_value (hdr, MU_HEADER_CONTENT_DISPOSITION, &val) == 0) | ||
1361 | { | ||
1362 | int argc; | ||
1363 | char **argv; | ||
1364 | |||
1365 | if (argcv_get (val, "=", NULL, &argc, &argv) == 0) | ||
1366 | { | ||
1367 | int i; | ||
1368 | |||
1369 | for (i = 0; i < argc; i++) | ||
1370 | { | ||
1371 | if (strcmp (argv[i], "filename") == 0 | ||
1372 | && ++i < argc | ||
1373 | && argv[i][0] == '=' | ||
1374 | && ++i < argc) | ||
1375 | { | ||
1376 | name = normalize_path (dir, argv[i]); | ||
1377 | break; | ||
1378 | } | ||
1379 | } | ||
1380 | argcv_free (argc, argv); | ||
1381 | } | ||
1382 | free (val); | ||
1383 | } | ||
1384 | } | ||
1385 | |||
1386 | if (!name) | ||
1387 | { | ||
1388 | char *fname = mhn_store_command (msg, part, prefix); | ||
1389 | if (dir) | ||
1390 | asprintf (&name, "%s/%s", dir, fname); | ||
1391 | else | ||
1392 | name = fname; | ||
1393 | } | ||
1394 | |||
1395 | tmp = msg_part_format (part); | ||
1396 | if (prefix) | ||
1397 | printf (_("storing message %s part %s as file %s\n"), | ||
1398 | prefix, | ||
1399 | tmp, | ||
1400 | name); | ||
1401 | else | ||
1402 | printf (_("storing message %lu part %s as file %s\n"), | ||
1403 | (unsigned long) msg_part_subpart (part, 0), | ||
1404 | tmp, | ||
1405 | name); | ||
1406 | free (tmp); | ||
1407 | |||
1408 | if (!(mode_options & OPT_QUIET) && access (name, R_OK) == 0) | ||
1409 | { | ||
1410 | char *p; | ||
1411 | int rc; | ||
1412 | |||
1413 | asprintf (&p, _("File %s already exists. Rewrite"), name); | ||
1414 | rc = mh_getyn (p); | ||
1415 | free (p); | ||
1416 | if (!rc) | ||
1417 | { | ||
1418 | free (name); | ||
1419 | return 0; | ||
1420 | } | ||
1421 | } | ||
1422 | |||
1423 | rc = file_stream_create (&out, name, MU_STREAM_WRITE|MU_STREAM_CREAT); | ||
1424 | if (rc) | ||
1425 | { | ||
1426 | mh_error (_("can't create output stream (file %s): %s"), | ||
1427 | name, mu_strerror (rc)); | ||
1428 | free (name); | ||
1429 | return rc; | ||
1430 | } | ||
1431 | rc = stream_open (out); | ||
1432 | if (rc) | ||
1433 | { | ||
1434 | mh_error (_("can't open output stream (file %s): %s"), | ||
1435 | name, mu_strerror (rc)); | ||
1436 | free (name); | ||
1437 | stream_destroy (&out, stream_get_owner (out)); | ||
1438 | return rc; | ||
1439 | } | ||
1440 | show_internal (msg, part, encoding, out); | ||
1441 | |||
1442 | stream_destroy (&out, stream_get_owner (out)); | ||
1443 | free (name); | ||
1444 | |||
1445 | return 0; | ||
1446 | } | ||
1447 | |||
1448 | void | ||
1449 | store_message (message_t msg, void *data) | ||
1450 | { | ||
1451 | size_t uid; | ||
1452 | msg_part_t part; | ||
1453 | |||
1454 | mh_message_number (msg, &uid); | ||
1455 | part = msg_part_create (uid); | ||
1456 | handle_message (msg, part, store_handler, data); | ||
1457 | msg_part_destroy (part); | ||
1458 | } | ||
1459 | |||
1460 | void | ||
1461 | store_iterator (mailbox_t mbox, message_t msg, size_t num, void *data) | ||
1462 | { | ||
1463 | store_message (msg, data); | ||
1464 | } | ||
1465 | |||
1466 | int | ||
1467 | mhn_store () | ||
1468 | { | ||
1469 | int rc = 0; | ||
1470 | |||
1471 | if (message) | ||
1472 | { | ||
1473 | char *p = strrchr (input_file, '/'); | ||
1474 | if (p) | ||
1475 | p++; | ||
1476 | else | ||
1477 | p = input_file; | ||
1478 | store_message (message, p); | ||
1479 | } | ||
1480 | else | ||
1481 | rc = mh_iterate (mbox, &msgset, store_iterator, NULL); | ||
1482 | return rc; | ||
1483 | } | ||
810 | 1484 | ||
811 | 1485 | ||
812 | 1486 | ||
... | @@ -859,8 +1533,7 @@ main (int argc, char **argv) | ... | @@ -859,8 +1533,7 @@ main (int argc, char **argv) |
859 | break; | 1533 | break; |
860 | 1534 | ||
861 | case mode_store: | 1535 | case mode_store: |
862 | mh_error ("mode is not yet implemented"); | 1536 | rc = mhn_store (); |
863 | rc = 1; | ||
864 | break; | 1537 | break; |
865 | 1538 | ||
866 | default: | 1539 | default: | ... | ... |
-
Please register or sign in to post a comment