+/*
+ * Try to use external command to determine mime type, and possibly
+ * encoding. Caller is responsible for free'ing returned memory.
+ */
+char *
+mime_type(const char *file_name) {
+ char *content_type = NULL; /* mime content type */
+
+#ifdef MIMETYPEPROC
+ 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 <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);
+ }
+
+ free(cmd);
+ } else {
+ advise(NULL, "concat with \"%s\" failed, out of memory?", proc);
+ }
+
+ return cp ? strdup(cp) : NULL;
+}
+#endif /* MIMETYPEPROC */
+
+
+/*
+ * Construct an mhbuild directive for the draft file. This starts
+ * with the content type. Append a file name attribute, and depending
+ * on attachformat value a private x-unix-mode attribute and a
+ * description obtained (if possible) by running the "file" command on
+ * the file. Caller is responsible for free'ing returned memory.
+ */
+char *
+construct_build_directive (char *file_name, const char *default_content_type,
+ int attachformat) {
+ char *build_directive = NULL; /* Return value. */
+ char *content_type; /* mime content type */
+ char cmd[PATH_MAX + 8]; /* file command buffer */
+ struct stat st; /* file status buffer */
+ char *p; /* miscellaneous temporary variables */
+ int c; /* current character */