]> diplodocus.org Git - nmh/blobdiff - sbr/mime_type.c
Fix invalid pointer arithmetic.
[nmh] / sbr / mime_type.c
index 06a6156d418294c0754742c2bc199835d19a8cf0..cc6b1fbf58b85da7b14d3a97da3628cc547e6cc1 100644 (file)
@@ -1,5 +1,4 @@
-/*
- * mime_type.c -- routine to determine the MIME Content-Type of a file
+/* mime_type.c -- routine to determine the MIME Content-Type of a file
  *
  * This code is Copyright (c) 2014, by the authors of nmh.  See the
  * COPYRIGHT file in the root directory of the nmh distribution for
@@ -9,6 +8,7 @@
 #include <h/mh.h>
 #include <h/utils.h>
 #include <h/tws.h>
+#include "mime_type.h"
 
 #ifdef MIMETYPEPROC
 static char *get_file_info(const char *, const char *);
@@ -33,18 +33,15 @@ mime_type(const char *file_name) {
         /* 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);
-        }
+        if (!strncasecmp(mimetype, "text", 4) &&
+            (mimeencoding = get_file_info(MIMEENCODINGPROC, file_name))) {
+            content_type = concat(mimetype, "; charset=", mimeencoding, NULL);
+            free(mimeencoding);
+            free(mimetype);
+        } else
+            content_type = mimetype;
 #else  /* MIMEENCODINGPROC */
-        content_type = strdup(mimetype);
+        content_type = mimetype;
 #endif /* MIMEENCODINGPROC */
     }
 #endif /* MIMETYPEPROC */
@@ -68,7 +65,7 @@ mime_type(const char *file_name) {
        if ((p = strrchr(file_name, '.')) != NULL) {
            for (np = m_defs; np; np = np->n_next) {
                if (strncasecmp(np->n_name, "mhshow-suffix-", 14) == 0 &&
-                   strcasecmp(p, np->n_field ? np->n_field : "") == 0) {
+                   strcasecmp(p, FENDNULL(np->n_field)) == 0) {
                    content_type = strdup(np->n_name + 14);
                    break;
                }
@@ -86,7 +83,7 @@ mime_type(const char *file_name) {
            int binary = 0, c;
 
            if (!(fp = fopen(file_name, "r"))) {
-               advise (NULL, "unable to access file \"%s\"", file_name);
+               inform("unable to access file \"%s\"", file_name);
                return NULL;
            }
 
@@ -111,65 +108,58 @@ mime_type(const char *file_name) {
 #ifdef MIMETYPEPROC
 /*
  * Get information using proc about a file.
- */
+ * Non-null return value must be free(3)'d. */
 static char *
-get_file_info(const char *proc, const char *file_name) {
-    char *cmd, *cp;
-    char *quotec = "'";
-
-    if ((cp = strchr(file_name, '\''))) {
-        /* file_name contains a single quote. */
+get_file_info(const char *proc, const char *file_name)
+{
+    char *quotec;
+    char *cmd;
+    FILE *fp;
+    bool ok;
+    char buf[max(BUFSIZ, 2048)];
+    char *info;
+    char *needle;
+
+    if (strchr(file_name, '\'')) {
         if (strchr(file_name, '"')) {
-            advise(NULL, "filenames containing both single and double quotes "
-                   "are unsupported for attachment");
+            inform("filenames containing both single and double quotes "
+                "are unsupported for attachment");
             return NULL;
-        } else {
-            quotec = "\"";
         }
+        quotec = "\"";
+    } else
+        quotec = "'";
+
+    cmd = concat(proc, " ", quotec, file_name, quotec, NULL);
+    if (!cmd) {
+        inform("concat with \"%s\" failed, out of memory?", proc);
+        return NULL;
     }
 
-    if ((cmd = concat(proc, " ", quotec, file_name, quotec, NULL))) {
-        FILE *fp;
-
-        if ((fp = popen(cmd, "r")) != NULL) {
-            char buf[BUFSIZ >= 2048  ?  BUFSIZ  : 2048];
-
-            buf[0] = '\0';
-            if (fgets(buf, sizeof buf, fp)) {
-                char *eol;
-
-                /* Skip leading <filename>:<whitespace>, if present. */
-                if ((cp = strchr(buf, ':')) != NULL) {
-                    ++cp;
-                    while (*cp  &&  isblank((unsigned char) *cp)) {
-                        ++cp;
-                    }
-                } else {
-                    cp = buf;
-                }
-
-                /* Truncate at newline (LF or CR), if present. */
-                if ((eol = strpbrk(cp, "\n\r")) != NULL) {
-                    *eol = '\0';
-                }
-            } else if (buf[0] == '\0') {
-                /* This can happen on Cygwin if the popen()
-                   mysteriously fails.  Return NULL so that the caller
-                   will use another method to determine the info. */
-                free (cp);
-                cp = NULL;
-            }
-
-            (void) pclose(fp);
-        } else {
-            advise(NULL, "no output from %s", cmd);
-        }
-
+    if ((fp = popen(cmd, "r")) == NULL) {
+        inform("no output from %s", cmd);
         free(cmd);
-    } else {
-        advise(NULL, "concat with \"%s\" failed, out of memory?", proc);
+        return NULL;
+    }
+
+    ok = fgets(buf, sizeof buf, fp);
+    free(cmd);
+    (void)pclose(fp);
+    if (!ok)
+        return NULL;
+
+    /* s#^[^:]*:[ \t]*##. */
+    info = buf;
+    if ((needle = strchr(info, ':'))) {
+        info = needle + 1;
+        while (isblank((unsigned char)*info))
+            info++;
     }
 
-    return cp  ?  strdup(cp)  :  NULL;
+    /* s#[\n\r].*##. */
+    if ((needle = strpbrk(info, "\n\r")))
+        *needle = '\0';
+
+    return strdup(info);
 }
 #endif /* MIMETYPEPROC */