X-Git-Url: https://diplodocus.org/git/nmh/blobdiff_plain/23dde40d04b6cd6c8e6b266678df12dece44f7ee..2181cd0442664bf083825fd5b2d789714ba1812d:/uip/sendsbr.c diff --git a/uip/sendsbr.c b/uip/sendsbr.c index 1088d316..bfd65157 100644 --- a/uip/sendsbr.c +++ b/uip/sendsbr.c @@ -63,6 +63,7 @@ static int attach(char *, char *, int); 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 *); /* @@ -418,31 +419,35 @@ make_mime_composition_file_entry(char *file_name, int attachformat, { 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); + } } /* @@ -468,7 +473,8 @@ make_mime_composition_file_entry(char *file_name, int attachformat, (void)fclose(fp); - content_type = binary ? "application/octet-stream" : "text/plain"; + content_type = + strdup (binary ? "application/octet-stream" : "text/plain"); } /* @@ -579,6 +585,8 @@ make_mime_composition_file_entry(char *file_name, int attachformat, adios ((char *)0, "unsupported attachformat %d", attachformat); } + free (content_type); + /* * Finish up with the file name. */ @@ -588,6 +596,75 @@ make_mime_composition_file_entry(char *file_name, int attachformat, 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 :, 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. @@ -876,7 +953,6 @@ sendaux (char **vec, int vecp, char *program, char *drft, struct stat *st) fprintf (stderr, "unable to exec "); perror (postproc); _exit (-1); - break; /* NOT REACHED */ default: /*