X-Git-Url: https://diplodocus.org/git/nmh/blobdiff_plain/476f7e5e6e32469a347a055922be6b3d0e45d8ba..351a74de3e5d3cd2048d2ec4444b090c6b7e00ac:/uip/attach.c?ds=sidebyside diff --git a/uip/attach.c b/uip/attach.c index d4902d55..9ff7d095 100644 --- a/uip/attach.c +++ b/uip/attach.c @@ -11,6 +11,9 @@ #include 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, @@ -25,7 +28,6 @@ attach(char *attachment_header_field_name, char *draft_file_name, int length; /* of attachment header field name */ char *p; /* miscellaneous string pointer */ struct stat st; /* file status buffer */ - FILE *fp; /* pointer for mhn.defaults */ FILE *body_file = NULL; /* body file pointer */ FILE *draft_file; /* draft file pointer */ int field_size; /* size of header field buffer */ @@ -98,12 +100,15 @@ attach(char *attachment_header_field_name, char *draft_file_name, * Make names for the temporary files. */ - (void)strncpy(body_file_name, - m_mktemp(m_maildir(invo_name), NULL, NULL), - body_file_name_len); - (void)strncpy(composition_file_name, - m_mktemp(m_maildir(invo_name), NULL, NULL), - composition_file_name_len); + if ((p = m_mktemp2(NULL, invo_name, NULL, NULL)) == NULL) { + adios(NULL, "unable to create temporary file in %s", get_temp_dir()); + } + (void)strncpy(body_file_name, p, body_file_name_len); + if ((p = m_mktemp2(NULL, invo_name, NULL, NULL)) == NULL) { + unlink(body_file_name); + adios(NULL, "unable to create temporary file in %s", get_temp_dir()); + } + (void)strncpy(composition_file_name, p, composition_file_name_len); if (has_body) body_file = fopen(body_file_name, "w"); @@ -174,11 +179,6 @@ attach(char *attachment_header_field_name, char *draft_file_name, * composition file for each. */ - if ((fp = fopen (p = etcpath ("mhn.defaults"), "r"))) { - readconfig ((struct node **) NULL, fp, p, 0); - fclose(fp); - } - rewind(draft_file); while (get_line(draft_file, field, field_size) != EOF && *field != '\0' && @@ -285,69 +285,105 @@ 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 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; + 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 *cmd, *cp; + char *quotec = "'"; + + 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 = "\""; + } + } + + cmd = concat(proc, " ", quotec, file_name, quotec, 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 :, 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"); + } 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, "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 */ /* @@ -365,7 +401,6 @@ construct_build_directive (char *file_name, const char *default_content_type, char cmd[PATH_MAX + 8]; /* file command buffer */ struct stat st; /* file status buffer */ char *p; /* miscellaneous temporary variables */ - FILE *fp; int c; /* current character */ if ((content_type = mime_type (file_name)) == NULL) { @@ -378,6 +413,12 @@ construct_build_directive (char *file_name, const char *default_content_type, * have the suffix in the field, including the dot. */ struct node *np; /* context scan node pointer */ + static FILE *fp = NULL; /* pointer for mhn.defaults */ + + if (fp == NULL && (fp = fopen (p = etcpath ("mhn.defaults"), "r"))) { + readconfig ((struct node **) NULL, fp, p, 0); + fclose(fp); + } if ((p = strrchr(file_name, '.')) != NULL) { for (np = m_defs; np; np = np->n_next) { @@ -402,6 +443,7 @@ construct_build_directive (char *file_name, const char *default_content_type, */ if (content_type == NULL) { int binary; /* binary character found flag */ + FILE *fp; if ((fp = fopen(file_name, "r")) == (FILE *)0) { advise(NULL, "unable to access file \"%s\"", file_name); @@ -426,6 +468,7 @@ construct_build_directive (char *file_name, const char *default_content_type, switch (attachformat) { case 0: { struct stat st; + FILE *fp; char m[4]; /* Insert name, file mode, and Content-Id. */