]> diplodocus.org Git - nmh/commitdiff
Reworked attach to add charset to Content-Type string for
authorDavid Levine <levinedl@acm.org>
Sat, 11 Jan 2014 15:22:36 +0000 (09:22 -0600)
committerDavid Levine <levinedl@acm.org>
Sat, 11 Jan 2014 15:22:36 +0000 (09:22 -0600)
text content.

configure.ac
m4/mimetype.m4
test/mhmail/test-mhmail
uip/attach.c
uip/mhparam.c

index ed4b6b1..f480184 100644 (file)
@@ -308,6 +308,7 @@ MAIL_SPOOL_GRP=$nmh_cv_ls_mail_grp
 AC_SUBST([MAIL_SPOOL_GRP])dnl
 
 NMH_MIMETYPEPROC
+NMH_MIMEENCODINGPROC
 
 dnl ------------------
 dnl CHECK HEADER FILES
index e767ff7..b97c49d 100644 (file)
@@ -2,6 +2,10 @@ dnl
 dnl Try to see if we have a program that can determine the MIME type
 dnl of a particular file
 dnl
+dnl Assume that if file(1) doesn't support --mime-type, then it's
+dnl unusable.  The --mime option to file 4.17 on CentOS 5.9, for
+dnl example, prints out a long description after the mime type.  We
+dnl don't want that.
 
 AC_DEFUN([NMH_MIMETYPEPROC],
 [AC_CACHE_CHECK([for a program to provide a MIME type string],
@@ -10,9 +14,23 @@ AC_DEFUN([NMH_MIMETYPEPROC],
    for mprog in 'file --brief --mime-type' 'file --mime-type'
    do
      AS_IF([$mprog "${srcdir}/configure" > /dev/null 2>&1],
-          [nmh_cv_mimetype_proc="$mprog"; break])
+          [nmh_cv_mimetype_proc="$mprog"; break])
    done])
 AS_IF([test X"$nmh_cv_mimetype_proc" != X],
       [mimetype_proc="\"${nmh_cv_mimetype_proc}\""
        AC_DEFINE_UNQUOTED([MIMETYPEPROC], [$mimetype_proc],
-                         [Program, with arguments, that provides MIME type string.])])])
+                 [Program, with arguments, to provides MIME type.])])])
+
+AC_DEFUN([NMH_MIMEENCODINGPROC],
+[AC_CACHE_CHECK([for a program to provide a MIME encoding string],
+               [nmh_cv_mimeencoding_proc],
+  [nmh_cv_mimeencoding_proc=
+   for mprog in 'file --brief --mime-encoding' 'file --mime-encoding'
+   do
+     AS_IF([$mprog "${srcdir}/configure" > /dev/null 2>&1],
+          [nmh_cv_mimeencoding_proc="$mprog"; break])
+   done])
+AS_IF([test X"$nmh_cv_mimeencoding_proc" != X],
+      [mimeencoding_proc="\"${nmh_cv_mimeencoding_proc}\""
+       AC_DEFINE_UNQUOTED([MIMEENCODINGPROC], [$mimeencoding_proc],
+                 [Program, with arguments, to provides MIME encoding.])])])
index 27188c7..043d95e 100755 (executable)
@@ -14,16 +14,18 @@ fi
 
 . "${srcdir}/test/post/test-post-common.sh"
 
-# Find MIME type string, using mimetypeproc if configured with it.
+# Find MIME type string, using configured procs if available.
 MIMETYPEPROC=`mhparam mimetypeproc`
+MIMEENCODINGPROC=`mhparam mimeencodingproc`
 content_type_string() {
-  if test -z "$MIMETYPEPROC"; then
+  if test -z "$MIMETYPEPROC"  -o  -z "$MIMEENCODINGPROC"; then
+    #### This should be the order of name and charset.
     echo "text/plain; name=\"`basename $1`\"; charset=\"us-ascii\""
   else
-    # 1) Excise leading filename followed by : and any whitespace.
-    # 2) Wrap charset value in double quotes.  Assume that it isn't already.
-    printf "%s%s" \
-      `$MIMETYPEPROC $1` "; name=\"`basename $1`\"; charset=\"us-ascii\""
+    #### Excise any leading filename followed by : and whitespace.
+    printf '%s; charset="%s"; name="%s"' \
+      `$MIMETYPEPROC $1 | sed -e 's/.*: *//'` \
+      `$MIMEENCODINGPROC $1 | sed -e 's/.*: *//'` `basename $1`
   fi
 }
 
index d4902d5..b1a4f44 100644 (file)
@@ -11,6 +11,9 @@
 #include <h/tws.h>
 
 static int get_line(FILE *, char *, size_t);
+#ifdef MIMETYPEPROC
+static char *get_file_info(const char *, const char *);
+#endif /* MIMETYPEPROC */
 
 int
 attach(char *attachment_header_field_name, char *draft_file_name,
@@ -285,69 +288,98 @@ get_line(FILE *draft_file, char *field, size_t field_size)
  * encoding.  Caller is responsible for free'ing returned memory.
  */
 char *
-mime_type (const char *file_name) {
+mime_type(const char *file_name) {
     char *content_type = NULL;  /* mime content type */
 
 #ifdef MIMETYPEPROC
-    char cmd[2 * PATH_MAX + 2]; /* file command buffer */
+    char *mimetype;
+
+    if ((mimetype = get_file_info(MIMETYPEPROC, file_name))) {
+#ifdef MIMEENCODINGPROC
+        /* Try to append charset for text content. */
+        char *mimeencoding;
+
+        if (strncasecmp(mimetype, "text", 4) == 0) {
+            if ((mimeencoding = get_file_info(MIMEENCODINGPROC, file_name))) {
+                content_type = concat(mimetype, "; charset=", mimeencoding,
+                                      NULL);
+            } else {
+                content_type = strdup(mimetype);
+            }
+        } else {
+            content_type = strdup(mimetype);
+        }
+#else  /* MIMEENCODINGPROC */
+        content_type = strdup(mimetype);
+#endif /* MIMEENCODINGPROC */
+    }
+#else  /* MIMETYPEPROC */
+    NMH_UNUSED(file_name);
+#endif /* MIMETYPEPROC */
+
+    return content_type;
+}
+
+
+#ifdef MIMETYPEPROC
+/*
+ * Get information using proc about a file.
+ */
+static char *
+get_file_info(const char *proc, const char *file_name) {
     char buf[BUFSIZ >= 2048  ?  BUFSIZ  : 2048];
-    FILE *fp;                   /* content and pipe file pointer */
-    char mimetypeproc[] = MIMETYPEPROC " '%s'";
+    char *cmd, *cp;
+    char *quotec = "'";
+    FILE *fp;
+
+    if ((cp = strchr(file_name, '\''))) {
+        /* file_name contains a single quote. */
+        if (strchr(file_name, '"')) {
+            advise(NULL, "filenames containing both single and double quotes "
+                   "are unsupported for attachment");
+            return NULL;
+        } else {
+            quotec = "\"";
+        }
+    }
 
-    if ((int) snprintf (cmd, sizeof cmd, mimetypeproc, file_name) <
-        (int) sizeof cmd) {
-        if ((fp = popen (cmd, "r")) != NULL) {
-            /* Make sure that buf has space for one additional
-               character, the semicolon that might be added below. */
-            if (fgets (buf, sizeof buf - 1, fp)) {
-                char *cp, *space;
+    cmd = concat(proc, " ", quotec, file_name, quotec, NULL);
+    if ((cmd = concat(proc, " ", quotec, file_name, quotec, NULL))) {
+        if ((fp = popen(cmd, "r")) != NULL) {
+            if (fgets(buf, sizeof buf, fp)) {
+                char *eol;
 
                 /* Skip leading <filename>:<whitespace>, if present. */
-                if ((content_type = strchr (buf, ':')) != NULL) {
-                    ++content_type;
-                    while (*content_type  &&  isblank (*content_type)) {
-                        ++content_type;
+                if ((cp = strchr(buf, ':')) != NULL) {
+                    ++cp;
+                    while (*cp  &&  isblank((unsigned char) *cp)) {
+                        ++cp;
                     }
                 } else {
-                    content_type = buf;
+                    cp = buf;
                 }
 
                 /* Truncate at newline (LF or CR), if present. */
-                if ((cp = strpbrk (content_type, "\n\n")) != NULL) {
-                    *cp = '\0';
-                }
-
-                /* If necessary, insert semicolon between content type
-                   and charset.  Assume that the first space is between
-                   them. */
-                if ((space = strchr (content_type, ' ')) != NULL) {
-                    ssize_t len = strlen (content_type);
-
-                    if (space - content_type > 0  &&
-                        len > space - content_type + 1) {
-                        if (*(space - 1) != ';') {
-                            /* The +1 is for the terminating NULL. */
-                            memmove (space + 1, space,
-                                     len - (space - content_type) + 1);
-                            *space = ';';
-                        }
-                    }
+                if ((eol = strpbrk(cp, "\n\r")) != NULL) {
+                    *eol = '\0';
                 }
             } else {
-                advise (NULL, "unable to read mime type");
+                advise(NULL, "unable to read mime type");
             }
+
+            (void) pclose(fp);
         } else {
-            advise (NULL, "unable to run %s", buf);
+            advise(NULL, "no output from %s", cmd);
         }
+
+        free(cmd);
     } else {
-        advise (NULL, "filename too large to deduce mime type");
+        advise(NULL, "concat with \"%s\" failed, out of memory?", proc);
     }
-#else
-    NMH_UNUSED (file_name);
-#endif
 
-    return content_type ? strdup (content_type) : NULL;
+    return cp  ?  strdup(cp)  :  NULL;
 }
+#endif /* MIMETYPEPROC */
 
 
 /*
index 351f0b9..b0c119c 100644 (file)
@@ -68,43 +68,51 @@ char *mimetypeproc =
     "";
 #endif
 
+char *mimeencodingproc =
+#ifdef MIMEENCODINGPROC
+    MIMEENCODINGPROC;
+#else
+    "";
+#endif
+
 struct proc {
     char *p_name;
     char **p_field;
 };
 
 static struct proc procs [] = {
-     { "context",       &context },
-     { "mh-sequences",  &mh_seq },
-     { "buildmimeproc", &buildmimeproc },
-     { "fileproc",      &fileproc },
-     { "foldprot",      &foldprot },
-     { "formatproc",   &formatproc },
-     { "incproc",       &incproc },
-     { "lproc",         &lproc },
-     { "mailproc",      &mailproc },
-     { "mhlproc",       &mhlproc },
-     { "mimetypeproc",  &mimetypeproc },
-     { "moreproc",      &moreproc },
-     { "msgprot",       &msgprot },
-     { "mshproc",       &mshproc },
-     { "packproc",      &packproc },
-     { "postproc",      &postproc },
-     { "rmmproc",       &rmmproc },
-     { "sendproc",      &sendproc },
-     { "showmimeproc",  &showmimeproc },
-     { "showproc",      &showproc },
-     { "version",       &version_num },
-     { "vmhproc",       &vmhproc },
-     { "whatnowproc",   &whatnowproc },
-     { "whomproc",      &whomproc },
-     { "etcdir",        &mhetcdir },
-     { "libdir",        &mhlibdir },
-     { "sbackup",       &sbackup },
-     { "lockmethod",    &lockmethod },
-     { "sasl",          &sasl },
-     { "tls",           &tls },
-     { NULL,            NULL },
+     { "context",          &context },
+     { "mh-sequences",     &mh_seq },
+     { "buildmimeproc",    &buildmimeproc },
+     { "fileproc",         &fileproc },
+     { "foldprot",         &foldprot },
+     { "formatproc",      &formatproc },
+     { "incproc",          &incproc },
+     { "lproc",            &lproc },
+     { "mailproc",         &mailproc },
+     { "mhlproc",          &mhlproc },
+     { "mimetypeproc",     &mimetypeproc },
+     { "mimeencodingproc", &mimeencodingproc },
+     { "moreproc",         &moreproc },
+     { "msgprot",          &msgprot },
+     { "mshproc",          &mshproc },
+     { "packproc",         &packproc },
+     { "postproc",         &postproc },
+     { "rmmproc",          &rmmproc },
+     { "sendproc",         &sendproc },
+     { "showmimeproc",     &showmimeproc },
+     { "showproc",         &showproc },
+     { "version",          &version_num },
+     { "vmhproc",          &vmhproc },
+     { "whatnowproc",      &whatnowproc },
+     { "whomproc",         &whomproc },
+     { "etcdir",           &mhetcdir },
+     { "libdir",           &mhlibdir },
+     { "sbackup",          &sbackup },
+     { "lockmethod",       &lockmethod },
+     { "sasl",             &sasl },
+     { "tls",              &tls },
+     { NULL,               NULL },
 };