/[mailutils]/mailutils/mh/mhn.c
ViewVC logotype

Diff of /mailutils/mh/mhn.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 1.1 by gray, Sat Mar 15 23:19:49 2003 UTC revision 1.2 by gray, Mon Mar 17 15:15:21 2003 UTC
# Line 18  Line 18 
18  /* MH mhn command */  /* MH mhn command */
19    
20  #include <mh.h>  #include <mh.h>
21    #define obstack_chunk_alloc xmalloc
22    #define obstack_chunk_free free
23    #include <obstack.h>
24    
25  const char *argp_program_version = "mhn (" PACKAGE_STRING ")";  const char *argp_program_version = "mhn (" PACKAGE_STRING ")";
26  static char doc[] = N_("GNU MH mhn\v"  static char doc[] = N_("GNU MH mhn\v"
# Line 57  static struct argp_option options[] = { Line 60  static struct argp_option options[] = {
60    {"form",         ARG_FORM,         N_("FILE"), 0,    {"form",         ARG_FORM,         N_("FILE"), 0,
61     N_("Read mhl format from FILE"), 22},     N_("Read mhl format from FILE"), 22},
62    {"pause",        ARG_PAUSE,        N_("BOOL"), OPTION_ARG_OPTIONAL,    {"pause",        ARG_PAUSE,        N_("BOOL"), OPTION_ARG_OPTIONAL,
63     N_("* Pause prior to displaying content"), 22},     N_("Pause prior to displaying content"), 22},
64    {"nopause",      ARG_NOPAUSE,      NULL, OPTION_HIDDEN, "", 22 },    {"nopause",      ARG_NOPAUSE,      NULL, OPTION_HIDDEN, "", 22 },
65        
66    {N_("Saving options"),   0,  NULL, OPTION_DOC,  NULL, 30},    {N_("Saving options"),   0,  NULL, OPTION_DOC,  NULL, 30},
67    {"store",        ARG_STORE,        N_("BOOL"), OPTION_ARG_OPTIONAL,    {"store",        ARG_STORE,        N_("BOOL"), OPTION_ARG_OPTIONAL,
68     N_("* Store the contents of the messages on disk"), 31},     N_("Store the contents of the messages on disk"), 31},
69    {"nostore",      ARG_NOSTORE,      NULL, OPTION_HIDDEN, "", 31 },    {"nostore",      ARG_NOSTORE,      NULL, OPTION_HIDDEN, "", 31 },
70    {"auto",         ARG_AUTO,         N_("BOOL"), OPTION_ARG_OPTIONAL,    {"auto",         ARG_AUTO,         N_("BOOL"), OPTION_ARG_OPTIONAL,
71     N_("* Use filenames from the content headers"), 31},     N_("Use filenames from the content headers"), 31},
72    {"noauto",       ARG_NOAUTO,       NULL, OPTION_HIDDEN, "", 31 },    {"noauto",       ARG_NOAUTO,       NULL, OPTION_HIDDEN, "", 31 },
73    
74    {N_("Other options"),    0,  NULL, OPTION_DOC,  NULL, 40},    {N_("Other options"),    0,  NULL, OPTION_DOC,  NULL, 40},
# Line 76  static struct argp_option options[] = { Line 79  static struct argp_option options[] = {
79    {"verbose",       ARG_VERBOSE,     N_("BOOL"), OPTION_ARG_OPTIONAL,    {"verbose",       ARG_VERBOSE,     N_("BOOL"), OPTION_ARG_OPTIONAL,
80     N_("Print additional information"), 41 },     N_("Print additional information"), 41 },
81    {"noverbose",     ARG_NOVERBOSE,   NULL, OPTION_HIDDEN, "", 41 },    {"noverbose",     ARG_NOVERBOSE,   NULL, OPTION_HIDDEN, "", 41 },
82      {"quiet",         ARG_QUIET, 0, 0,
83       N_("Be quiet")},
84    {NULL}    {NULL}
85  };  };
86    
# Line 125  static enum mhn_mode mode = mode_compose Line 130  static enum mhn_mode mode = mode_compose
130  #define OPT_AUTO       010  #define OPT_AUTO       010
131  #define OPT_SERIALONLY 020  #define OPT_SERIALONLY 020
132  #define OPT_VERBOSE    040  #define OPT_VERBOSE    040
133    #define OPT_QUIET      100
134    
135  static int mode_options = OPT_HEADERS;  static int mode_options = OPT_HEADERS;
136  static char *formfile;  static char *formfile;
# Line 138  static mailbox_t mbox; Line 144  static mailbox_t mbox;
144  static message_t message;  static message_t message;
145  static msg_part_t req_part;  static msg_part_t req_part;
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    
153  void  void
154  sfree (char **ptr)  sfree (char **ptr)
155  {  {
# Line 170  split_content (const char *content, char Line 182  split_content (const char *content, char
182      }      }
183  }  }
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    
239  static int  static int
240  opt_handler (int key, char *arg, void *unused, struct argp_state *state)  opt_handler (int key, char *arg, void *unused, struct argp_state *state)
241  {  {
# Line 316  opt_handler (int key, char *arg, void *u Line 382  opt_handler (int key, char *arg, void *u
382      case ARG_PART:      case ARG_PART:
383        req_part = msg_part_parse (arg);        req_part = msg_part_parse (arg);
384        break;        break;
385          
386        case ARG_QUIET:
387          mode_options |= OPT_QUIET;
388          break;
389            
390      default:      default:
391        return 1;        return 1;
392      }      }
# Line 405  msg_part_print (msg_part_t p, int max_wi Line 475  msg_part_print (msg_part_t p, int max_wi
475      putchar (' ');      putchar (' ');
476  }  }
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    
522  msg_part_t  msg_part_t
523  msg_part_parse (char *str)  msg_part_parse (char *str)
524  {  {
# Line 449  msg_part_subpart (msg_part_t p, int leve Line 563  msg_part_subpart (msg_part_t p, int leve
563  }  }
564    
565    
566  /* ************************** Message iterators *************************** */  /* *********************** Context file accessors ************************* */
567    
568  int  char *
569  _get_hdr_value (header_t hdr, const char *name, char **value)  _mhn_profile_get (char *prefix, char *type, char *subtype, char *defval)
570  {  {
571    int status = header_aget_value (hdr, name, value);    char *str, *name;
572    if (status == 0)    
573      if (subtype)
574      {      {
575        /* Remove the newlines.  */        asprintf (&name, "mhn-%s-%s/%s", prefix, type, subtype);
576        char *nl;        str = mh_global_profile_get (name, NULL);
577        while ((nl = strchr (*value, '\n')) != NULL)        free (name);
578          *nl = ' ';        if (!str)
579            return _mhn_profile_get (prefix, type, NULL, defval);
580      }      }
581    return status;    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;
588  }  }
589    
590  int  char *
591  _get_content_type (header_t hdr, char **value)  mhn_show_command (message_t msg, msg_part_t part, int *flags, char **tempfile)
592  {  {
593    char *type = NULL;    char *p, *str, *tmp;
594    _get_hdr_value (hdr, MU_HEADER_CONTENT_TYPE, &type);    char *typestr, *type, *subtype, *typeargs;
595    if (type == NULL || *type == '\0')    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++)
623      {      {
624        if (type)        if (*p == '%')
625          free (type);          {
626        type = strdup ("text/plain"); /* Default.  */            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);
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;
697    else    else
698      {      str = strdup (str);
699        char *p = strchr (type, ';');  
700        if (p)    obstack_free (&stk, NULL);
701          *p = 0;    return str;
     }  
   *value = type;  
   return 0;  
702  }  }
703    
704  static int  char *
705  _get_content_encoding (header_t hdr, char **value)  mhn_store_command (message_t msg, msg_part_t part, char *name)
706  {  {
707    char *encoding = NULL;    char *p, *str, *tmp;
708    _get_hdr_value (hdr, MU_HEADER_CONTENT_TRANSFER_ENCODING, &encoding);    char *typestr, *type, *subtype, *typeargs;
709    if (encoding == NULL || *encoding == '\0')    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++)
726      {      {
727        if (encoding)        if (*p == '%')
728          free (encoding);          {
729        encoding = strdup ("7bit"); /* Default.  */            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);
776      }      }
777    *value = encoding;    obstack_1grow (&stk, *p);
778    return 0;  
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;
793  }  }
794    
795    
796    /* ************************** Message iterators *************************** */
797    
798    
799  typedef int (*msg_handler_t) __PMT((message_t msg, msg_part_t part,  typedef int (*msg_handler_t) __PMT((message_t msg, msg_part_t part,
800                                      char *type, char *encoding,                                      char *type, char *encoding,
801                                      void *data));                                      void *data));
# Line 518  match_content (char *content) Line 813  match_content (char *content)
813    
814    split_content (content, &type, &subtype);    split_content (content, &type, &subtype);
815    
816    if (strcasecmp (content_type, type) == 0)    if ((rc = strcasecmp (content_type, type)) == 0)
817      rc = strcasecmp (content_subtype, subtype);      {
818          if (content_subtype)
819            rc = strcasecmp (content_subtype, subtype);
820        }
821    else    else
822      rc = strcasecmp (content_type, subtype);      rc = strcasecmp (content_type, subtype);
823    
# Line 548  handle_message (message_t msg, msg_part_ Line 846  handle_message (message_t msg, msg_part_
846    int ismime = 0;    int ismime = 0;
847        
848    message_get_header (msg, &hdr);    message_get_header (msg, &hdr);
849    _get_content_type (hdr, &type);    _get_content_type (hdr, &type, NULL);
850    _get_content_encoding (hdr, &encoding);    _get_content_encoding (hdr, &encoding);
851    
852    fun (msg, part, type, encoding, data);    fun (msg, part, type, encoding, data);
# Line 570  handle_message (message_t msg, msg_part_ Line 868  handle_message (message_t msg, msg_part_
868            if (message_get_part (msg, i, &message) == 0)            if (message_get_part (msg, i, &message) == 0)
869              {              {
870                message_get_header (message, &hdr);                message_get_header (message, &hdr);
871                _get_content_type (hdr, &type);                _get_content_type (hdr, &type, NULL);
872                _get_content_encoding (hdr, &encoding);                _get_content_encoding (hdr, &encoding);
873    
874                msg_part_set_subpart (part, i);                msg_part_set_subpart (part, i);
875    
876                if (strcasecmp (type, "multipart/mixed") == 0)                if (message_is_multipart (message, &ismime) == 0 && ismime)
877                  handle_message (message, part, fun, data);                  handle_message (message, part, fun, data);
878                else                else
879                  call_handler (message, part, type, encoding, fun, data);                  call_handler (message, part, type, encoding, fun, data);
# Line 641  list_handler (message_t msg, msg_part_t Line 939  list_handler (message_t msg, msg_part_t
939    header_t hdr;    header_t hdr;
940        
941    if (msg_part_level (part) == 0)    if (msg_part_level (part) == 0)
942      printf ("%3lu       ", (unsigned long) msg_part_subpart (part, 0));      printf ("%4lu      ", (unsigned long) msg_part_subpart (part, 0));
943    else    else
944      {      {
945        printf ("    ");        printf ("     ");
946        msg_part_print (part, 5);        msg_part_print (part, 4);
947        putchar (' ');        putchar (' ');
948      }      }
949    printf ("%-26s", type);    printf ("%-25s", type);
950        
951    mhn_message_size (msg, &size);    mhn_message_size (msg, &size);
952    printf ("%4lu", (unsigned long) size);    if (size < 1024)
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      
959    if (message_get_header (msg, &hdr) == 0)    if (message_get_header (msg, &hdr) == 0)
960      {      {
961        char *descr;        char *descr;
# Line 670  list_handler (message_t msg, msg_part_t Line 973  list_handler (message_t msg, msg_part_t
973  int  int
974  list_message (message_t msg, size_t num)  list_message (message_t msg, size_t num)
975  {  {
976    msg_part_t part = msg_part_create (num);    size_t uid;
977      msg_part_t part;
978    
979      mh_message_number (msg, &uid);
980      part = msg_part_create (uid);
981    handle_message (msg, part, list_handler, NULL);    handle_message (msg, part, list_handler, NULL);
982    msg_part_destroy (part);    msg_part_destroy (part);
983    return 0;    return 0;
# Line 688  mhn_list () Line 995  mhn_list ()
995    int rc;    int rc;
996    
997    if (mode_options & OPT_HEADERS)    if (mode_options & OPT_HEADERS)
998      printf (_("msg part  type/subtype              size description\n"));      printf (_(" msg part type/subtype              size  description\n"));
999    
1000    if (message)    if (message)
1001      rc = list_message (message, 0);      rc = list_message (message, 0);
# Line 717  cat_message (stream_t out, stream_t in) Line 1024  cat_message (stream_t out, stream_t in)
1024  }  }
1025    
1026  int  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
1132  show_handler (message_t msg, msg_part_t part, char *type, char *encoding,  show_handler (message_t msg, msg_part_t part, char *type, char *encoding,
1133                void *data)                void *data)
1134  {  {
1135    stream_t out = data;    stream_t out = data;
1136      char *cmd;
1137    if (strncasecmp (type, "multipart", 9) == 0)    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)
1144      return 0;      return 0;
1145    if (mhl_format)  
1146      mhl_format_run (mhl_format, width, 0, MHL_DECODE, msg, out);    stream_get_fd (out, &fd);
1147    else  
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)
1154        {
1155          char *str;
1156          size_t size = 0;
1157    
1158          str = _("part ");
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        int rc;        if (isatty (fd) && isatty (0))
       body_t body = NULL;  
       stream_t dstr, bstr;  
     
       if ((rc = message_get_body (msg, &body)))  
1175          {          {
1176            mh_error (_("%lu: can't get message body: %s"),            printf (_("Press <return> to show content..."));
1177                      (unsigned long) msg_part_subpart (part, 0),            if (!fgets (buf, sizeof buf, stdin) || buf[0] != '\n')
1178                      mu_strerror (rc));              return 0;
           return 0;  
1179          }          }
1180        body_get_stream (body, &bstr);      }
1181        rc = filter_create(&dstr, bstr, encoding,        
1182                           MU_FILTER_DECODE, MU_STREAM_READ);    if (!cmd)
1183        if (rc == 0)      {
1184          bstr = dstr;        char *pager = mh_global_profile_get ("moreproc", getenv ("PAGER"));
1185        cat_message (out, bstr);        if (pager)
1186        if (dstr)          exec_internal (msg, part, encoding, pager);
1187          stream_destroy (&dstr, stream_get_owner (dstr));        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);
1196      }      }
1197    
1198      return 0;
1199  }  }
1200    
1201  int  int
1202  show_message (message_t msg, size_t num, void *data)  show_message (message_t msg, size_t num, void *data)
1203  {  {
1204    msg_part_t part = msg_part_create (num);    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    
1210    handle_message (msg, part, show_handler, data);    handle_message (msg, part, show_handler, data);
1211    msg_part_destroy (part);    msg_part_destroy (part);
1212    return 0;    return 0;
# Line 762  show_message (message_t msg, size_t num, Line 1215  show_message (message_t msg, size_t num,
1215  void  void
1216  show_iterator (mailbox_t mbox, message_t msg, size_t num, void *data)  show_iterator (mailbox_t mbox, message_t msg, size_t num, void *data)
1217  {  {
1218      msg_part_t part;
1219      
1220      mh_message_number (msg, &num);
1221      part = msg_part_create (num);
1222    show_message (msg, num, data);    show_message (msg, num, data);
1223      msg_part_destroy (part);
1224  }  }
1225    
1226  int  int
# Line 807  mhn_show () Line 1265  mhn_show ()
1265      rc = mh_iterate (mbox, &msgset, show_iterator, ostr);      rc = mh_iterate (mbox, &msgset, show_iterator, ostr);
1266    return rc;    return rc;
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    }
1484    
1485    
1486    
# Line 859  main (int argc, char **argv) Line 1533  main (int argc, char **argv)
1533        break;        break;
1534                
1535      case mode_store:      case mode_store:
1536        mh_error ("mode is not yet implemented");        rc = mhn_store ();
       rc = 1;  
1537        break;        break;
1538                
1539      default:      default:

Legend:
Removed from v.1.1  
changed lines
  Added in v.1.2

savannah-hackers-public@gnu.org
ViewVC Help
Powered by ViewVC 1.1.26