<<< Date Index >>>     <<< Thread Index >>>

[PATCH] [RFC] Allow mutt to render an e-mail from the command-line



Background: In trying to write yet another biff app, I wanted to
create a brief summary of an e-mail. After fighting some Perl and
MIME packages, and seeing what others had done before, it soon
became clear that I was reinventing a rather large wheel. Mutt does
a wonderful job of rendering e-mail as text already, handling
multi-part messages, HTML, character set conversion, etc. The only
thing it is missing is the ability to call it from the command-line
and render an e-mail to stdout.

The attached patch adds the -r (render) flag, which accepts the
filename of a raw e-mail message. It renders the message to stdout
as you would view it in mutt, but leaves the headers intact. e.g.:
  $ mutt -r <file containing raw e-mail>

I think it'd be a small, but useful addition to mutt.

I'm not familiar with the internals of mutt however, so if there's
something grossly wrong, please let me know. It works for me(tm). :)

Kind regards,
Bernard.
Index: mutt-1.5.13/copy.c
===================================================================
--- mutt-1.5.13.orig/copy.c     2007-02-02 17:45:20.000000000 +1100
+++ mutt-1.5.13/copy.c  2007-02-02 18:15:33.000000000 +1100
@@ -32,6 +32,7 @@
 #include <string.h>
 #include <stdlib.h>
 #include <ctype.h>
+#include <errno.h>
 #include <unistd.h> /* needed for SEEK_SET under SunOS 4.1.4 */
 
 static int address_header_decode (char **str);
@@ -748,6 +749,35 @@
   return r;
 }
 
+int mutt_render_file(FILE *fpout, char *filename)
+{
+  FILE *fpin;
+  HEADER *hdr;
+  int chflags = CH_DECODE;
+  int cmflags = M_CM_DECODE | M_CM_CHARCONV;
+  int r = -1;
+
+  if ((fpin = safe_fopen(filename, "r")) != NULL)
+  {
+    if ((hdr = maildir_parse_message (M_MH, filename, 0, NULL)) != NULL)
+    {
+      mutt_parse_part (fpin, hdr->content);
+
+      fseek(fpin, 0, SEEK_SET);
+      if (_mutt_copy_message (fpout, fpin, hdr, hdr->content, cmflags, 
chflags) == 0 
+         && (ferror (fpout) || feof (fpout)))
+       dprint (1, (debugfile, "_mutt_copy_message failed to detect EOF!\n"));
+      else
+       r = 0;
+      mutt_free_header(&hdr);
+    }
+    safe_fclose(&fpin);
+  }
+  else
+    mutt_error ( _("Unable to open %s: %s"), filename, strerror(errno));
+  return r;
+}
+
 /* appends a copy of the given message to a mailbox
  *
  * dest                destination mailbox
Index: mutt-1.5.13/main.c
===================================================================
--- mutt-1.5.13.orig/main.c     2007-02-02 17:45:20.000000000 +1100
+++ mutt-1.5.13/main.c  2007-02-02 18:22:06.000000000 +1100
@@ -111,6 +111,7 @@
        mutt [ -nR ] [ -e <cmd> ] [ -F <file> ] -D\n\
        mutt [ -nx ] [ -e <cmd> ] [ -a <file> ] [ -F <file> ] [ -H <file> ] [ 
-i <file> ] [ -s <subj> ] [ -b <addr> ] [ -c <addr> ] <addr> [ ... ]\n\
        mutt [ -n ] [ -e <cmd> ] [ -F <file> ] -p\n\
+       mutt [ -n ] [ -e <cmd> ] [ -F <file> ] -r <file>\n\
        mutt -v[v]\n");
 
   puts _("\
@@ -136,6 +137,7 @@
   puts _("\
   -Q <variable>\tquery a configuration variable\n\
   -R\t\topen mailbox in read-only mode\n\
+  -r <file>\trender an e-mail from the given file to stdout and exit\n\
   -s <subj>\tspecify a subject (must be in quotes if it has spaces)\n\
   -v\t\tshow version and compile-time definitions\n\
   -x\t\tsimulate the mailx send mode\n\
@@ -531,6 +533,7 @@
   LIST *commands = NULL;
   LIST *queries = NULL;
   LIST *alias_queries = NULL;
+  LIST *render_files = NULL;
   int sendflags = 0;
   int flags = 0;
   int version = 0;
@@ -566,7 +569,7 @@
   memset (Options, 0, sizeof (Options));
   memset (QuadOptions, 0, sizeof (QuadOptions));
   
-  while ((i = getopt (argc, argv, "A:a:b:F:f:c:Dd:e:H:s:i:hm:npQ:RvxyzZ")) != 
EOF)
+  while ((i = getopt (argc, argv, "A:a:b:F:f:c:Dd:e:H:s:i:hm:npQ:Rr:vxyzZ")) 
!= EOF)
     switch (i)
     {
       case 'A':
@@ -643,6 +646,10 @@
        flags |= M_RO; /* read-only mode */
        break;
 
+      case 'r':
+       render_files = mutt_add_list (render_files, optarg);
+       break;
+
       case 's':
        subject = optarg;
        break;
@@ -688,7 +695,7 @@
   }
 
   /* Check for a batch send. */
-  if (!isatty (0) || queries || alias_queries || dump_variables)
+  if (!isatty (0) || queries || alias_queries || dump_variables || 
render_files)
   {
     set_option (OPTNOCURSES);
     sendflags = SENDBATCH;
@@ -731,6 +738,17 @@
     }
     return rv;
   }
+
+  if (render_files)
+  {
+    int rv = 0;
+    for (; render_files; render_files = render_files->next)
+    {
+      if (mutt_render_file(stdout, render_files->data) != 0)
+       rv = 1;
+    }
+    return rv;
+  }
   
   if (newMagic)
     mx_set_magic (newMagic);
Index: mutt-1.5.13/mh.c
===================================================================
--- mutt-1.5.13.orig/mh.c       2007-02-02 17:45:20.000000000 +1100
+++ mutt-1.5.13/mh.c    2007-02-02 17:45:48.000000000 +1100
@@ -588,7 +588,7 @@
  * Actually parse a maildir message.  This may also be used to fill
  * out a fake header structure generated by lazy maildir parsing.
  */
-static HEADER *maildir_parse_message (int magic, const char *fname,
+HEADER *maildir_parse_message (int magic, const char *fname,
                                      int is_old, HEADER * _h)
 {
   FILE *f;
Index: mutt-1.5.13/PATCHES
===================================================================
--- /dev/null   1970-01-01 00:00:00.000000000 +0000
+++ mutt-1.5.13/PATCHES 2007-02-02 17:45:48.000000000 +1100
@@ -0,0 +1 @@
+patch-1.5.13.bb.render_flag.1
Index: mutt-1.5.13/protos.h
===================================================================
--- mutt-1.5.13.orig/protos.h   2007-02-02 17:45:20.000000000 +1100
+++ mutt-1.5.13/protos.h        2007-02-02 17:45:48.000000000 +1100
@@ -342,6 +342,7 @@
 int mutt_print_attachment (FILE *, BODY *);
 int mutt_query_complete (char *, size_t);
 int mutt_query_variables (LIST *queries);
+int mutt_render_file(FILE *fpout, char *filename);
 int mutt_save_attachment (FILE *, BODY *, char *, int, HEADER *);
 int _mutt_save_message (HEADER *, CONTEXT *, int, int, int);
 int mutt_save_message (HEADER *, int, int, int, int *);
@@ -364,6 +365,9 @@
 
 int mh_valid_message (const char *);
 
+HEADER *maildir_parse_message (int magic, const char *fname,
+                                     int is_old, HEADER * _h);
+
 pid_t mutt_create_filter (const char *, FILE **, FILE **, FILE **);
 pid_t mutt_create_filter_fd (const char *, FILE **, FILE **, FILE **, int, 
int, int);
 
Index: mutt-1.5.13/doc/mutt.man
===================================================================
--- mutt-1.5.13.orig/doc/mutt.man       2007-02-02 17:50:47.000000000 +1100
+++ mutt-1.5.13/doc/mutt.man    2007-02-02 17:51:37.000000000 +1100
@@ -46,6 +46,9 @@
 .B mutt
 [-n] [-e \fIcmd\fP] [-F \fIfile\fP] -A \fIalias\fP
 .PP
+.B mutt
+[-n] [-e \fIcmd\fP] [-F \fIfile\fP] -r \fIfile\fP
+.PP
 .B mutt 
 -v[v]
 .PP
@@ -94,6 +97,8 @@
 the command line have been executed.
 .IP "-R"
 Open a mailbox in \fIread-only\fP mode.
+.IP "-r \fIfile\fP"
+Render an e-mail from the given file to stdout and exit.
 .IP "-s \fIsubject\fP"
 Specify the subject of the message.
 .IP "-v"