Better mime types for attachments. Use some command; e.g. `file --mime'.
authormarkus schnalke <meillo@marmaro.de>
Wed, 8 Feb 2012 10:19:50 +0000 (11:19 +0100)
committermarkus schnalke <meillo@marmaro.de>
Wed, 8 Feb 2012 10:19:50 +0000 (11:19 +0100)
Up to now attachments had either been text/plain or application/octet-stream,
if one hadn't added mhshow-suffix- profile entries for any possible type.
Now we call mimetypequeryproc (default: `file -b --mime' for GNU file),
this can be changed with the profile entry `Mime-Type-Query'. This command
will be executed with the attachment filename as last argument. If your
file(1) command does not print MIME types, you can still grep your profile
for matching mhshow-suffix- entries. However, I suggest to store this data
somewhere else. IMO the profile is not the right location for it.

config/config.c
h/mh.h
uip/mhparam.c
uip/sendsbr.c

index cdf8f5a..3cc7305 100644 (file)
@@ -103,6 +103,9 @@ char *nmhaccessftp = "nmh-access-ftp";
 /* Default attachment header field name */
 char *attach_hdr = "Attach";
 
+/* the tool to query the mime type of a file */
+char *mimetypequery = "Mime-Type-Query";
+char *mimetypequeryproc = "file -b --mime";
 
 
 
diff --git a/h/mh.h b/h/mh.h
index ef7aa03..52dc504 100644 (file)
--- a/h/mh.h
+++ b/h/mh.h
@@ -312,6 +312,8 @@ extern char *mhlformat;
 extern char *mhlforward;
 extern char *mhlproc;
 extern char *mhlreply;
+extern char *mimetypequery;
+extern char *mimetypequeryproc;
 extern char *moreproc;
 extern char *msgprot;
 extern char *nmhaccessftp;
index 4f20f55..2a1d97e 100644 (file)
@@ -46,6 +46,7 @@ static struct proc procs [] = {
        { "lproc",         &lproc },
        { "mailproc",      &mailproc },
        { "mhlproc",       &mhlproc },
+       { "mimetypequeryproc", &mimetypequeryproc },
        { "moreproc",      &moreproc },
        { "msgprot",       &msgprot },
        { "postproc",      &postproc },
index 89a0748..f8b415c 100644 (file)
@@ -365,100 +365,46 @@ get_line(void)
 static void
 make_mime_composition_file_entry(char *file_name)
 {
-       int binary;  /* binary character found flag */
-       int c;  /* current character */
-       char *content_type;  /* mime content type */
-       FILE *fp;  /* content and pipe file pointer */
-       struct node *np;  /* context scan node pointer */
-       char *p;  /* miscellaneous string pointer */
-
-       content_type = NULL;
-
-       
-       /*
-       ** Check the file name for a suffix.  Scan the context for that
-       ** suffix on a mhshow-suffix- entry.  We use these entries to
-       ** be compatible with mhshow, and there's no reason to make the
-       ** user specify each suffix twice.  Context entries of the form
-       ** "mhshow-suffix-contenttype" in the name have the suffix in
-       ** the field, including the dot.
-       */
-
-       if ((p = strrchr(file_name, '.')) != NULL) {
-               for (np = m_defs; np; np = np->n_next) {
-                       if (strncasecmp(np->n_name, "mhshow-suffix-", 14) == 0
-                                       && mh_strcasecmp(p, np->n_field) == 0)
-                                       {
-                               content_type = np->n_name + 14;
-                               break;
-                       }
+       FILE *fp;
+       struct node *np;
+       char *cp;
+       char content_type[BUFSIZ];
+       char cmdbuf[BUFSIZ];
+       char *cmd = mimetypequeryproc;
+
+       for (np = m_defs; np; np = np->n_next) {
+               if (strcasecmp(np->n_name, mimetypequery)==0) {
+                       cmd = np->n_field;
+                       break;
                }
        }
+       snprintf(cmdbuf, sizeof cmdbuf, "%s %s", cmd, file_name);
 
-       /*
-       ** No content type was found, either because there was no matching
-       ** entry in the context or because the file name has no suffix.
-       ** Open the file and check for non-ASCII characters.  Choose the
-       ** content type based on this check.
-       */
-
-       if (content_type == NULL) {
-               if ((fp = fopen(file_name, "r")) == (FILE *)0) {
-                       clean_up_temporary_files();
-                       adios(NULL, "unable to access file \"%s\"",
-                                       file_name);
-               }
-
-               binary = 0;
-
-               while ((c = getc(fp)) != EOF) {
-                       if (c > 127 || c < 0) {
-                               binary = 1;
-                               break;
-                       }
-               }
-
-               fclose(fp);
-
-               content_type = binary ?
-                               "application/octet-stream" : "text/plain";
+       if (!(fp = popen(cmdbuf, "r"))) {
+               clean_up_temporary_files();
+               adios(NULL, "unable to determine content type with `%s'",
+                               cmdbuf);
        }
+       if (fgets(content_type, sizeof content_type, fp) &&
+                       (cp = strrchr(content_type, '\n'))) {
+               *cp = '\0';
+       } else {
+               strcpy(content_type, "application/octet-stream");
+               admonish(NULL, "problems with `%s', using fall back type `%s'",
+                               cmdbuf, content_type);
+       }
+       pclose(fp);
 
-       /*
-       ** Make sure that the attachment file exists and is readable.
-       ** Append a mhbuild directive to the draft file.  This starts with
-       ** the content type.  Append a file name attribute and a private
-       ** x-unix-mode attribute.  Also append a description obtained
-       ** (if possible) by running the "file" command on the file.
-       */
-
+       /* TODO: don't use access(2) because it checks for ruid, not euid */
        if (access(file_name, R_OK) != 0) {
                clean_up_temporary_files();
-               adios(NULL, "unable to access file \"%s\"", file_name);
+               adios(NULL, "unable to access file `%s'", file_name);
        }
 
+       fprintf(composition_file, "#%s; name=\"%s\" <>{attachment}",
+               content_type,
+               (!(cp = strrchr(file_name, '/'))) ? file_name : cp + 1);
 
-       if (stringdex(toabsdir(invo_name), file_name) == 0) {
-               /*
-               ** Content had been placed by send into a temp file.
-               ** Don't generate Content-Disposition header, because
-               ** it confuses Microsoft Outlook, Build 10.0.6626, at
-               ** least.
-               */
-               fprintf(composition_file, "#%s <>", content_type);
-       } else {
-               /*
-               ** Suppress Content-Id, insert simple
-               ** Content-Disposition.
-               */
-               fprintf(composition_file,
-                       "#%s; name=\"%s\" <>{attachment}",
-                       content_type,
-                       ((p = strrchr(file_name, '/')) == NULL) ?
-                       file_name : p + 1);
-       }
-
-       /* Finish up with the file name. */
        fprintf(composition_file, " %s\n", file_name);
 
        return;