static void clean_up_temporary_files(void);
static int get_line(void);
static void make_mime_composition_file_entry(char *, int, char *);
+static char *mime_type (const char *);
/*
{
int binary; /* binary character found flag */
int c; /* current character */
- char cmd[PATH_MAX + 6]; /* file command buffer */
+ char cmd[PATH_MAX + 8]; /* file command buffer */
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 */
struct stat st; /* file status buffer */
- content_type = default_content_type;
-
- /*
- * 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 mhnshow,
- * 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 ((content_type = mime_type (file_name)) == 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 mhnshow, 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, '.')) != (char *)0) {
+ 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) {
+ content_type = strdup (np->n_name + 14);
+ break;
+ }
+ }
+ }
- if ((p = strrchr(file_name, '.')) != (char *)0) {
- 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) {
- content_type = np->n_name + 14;
- break;
- }
- }
+ if (content_type == NULL && default_content_type != NULL) {
+ content_type = strdup (default_content_type);
+ }
}
/*
(void)fclose(fp);
- content_type = binary ? "application/octet-stream" : "text/plain";
+ content_type =
+ strdup (binary ? "application/octet-stream" : "text/plain");
}
/*
adios ((char *)0, "unsupported attachformat %d", attachformat);
}
+ free (content_type);
+
/*
* Finish up with the file name.
*/
return;
}
+/*
+ * Try to use external command to determine mime type, and possibly
+ * encoding. Caller is responsible for free'ing returned memory.
+ */
+static char *
+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 buf[BUFSIZ >= 2048 ? BUFSIZ : 2048];
+ FILE *fp; /* content and pipe file pointer */
+ char mimetypeproc[] = MIMETYPEPROC " '%s'";
+
+ 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;
+
+ /* Skip leading <filename>:<whitespace>, if present. */
+ if ((content_type = strchr (buf, ':')) != NULL) {
+ ++content_type;
+ while (*content_type && isblank (*content_type)) {
+ ++content_type;
+ }
+ } else {
+ content_type = 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 = ';';
+ }
+ }
+ }
+ } else {
+ advise (NULL, "unable to read mime type");
+ }
+ } else {
+ advise (NULL, "unable to run %s", buf);
+ }
+ } else {
+ advise (NULL, "filename to large to deduce mime type");
+ }
+#else
+ NMH_UNUSED (file_name);
+#endif
+
+ return content_type ? strdup (content_type) : NULL;
+}
+
/*
* Split large message into several messages of
* type "message/partial" and send them.