]>
diplodocus.org Git - nmh/blob - sbr/mime_type.c
2 * mime_type.c -- routine to determine the MIME Content-Type of a file
4 * This code is Copyright (c) 2014, by the authors of nmh. See the
5 * COPYRIGHT file in the root directory of the nmh distribution for
6 * complete copyright information.
14 static char *get_file_info(const char *, const char *);
15 #endif /* MIMETYPEPROC */
18 * Try to use external command to determine mime type, and possibly
19 * encoding. If that fails try using the filename extension. Caller
20 * is responsible for free'ing returned memory.
23 mime_type(const char *file_name
) {
24 char *content_type
= NULL
; /* mime content type */
26 static int loaded_defaults
= 0;
31 if ((mimetype
= get_file_info(MIMETYPEPROC
, file_name
))) {
32 #ifdef MIMEENCODINGPROC
33 /* Try to append charset for text content. */
36 if (strncasecmp(mimetype
, "text", 4) == 0) {
37 if ((mimeencoding
= get_file_info(MIMEENCODINGPROC
, file_name
))) {
38 content_type
= concat(mimetype
, "; charset=", mimeencoding
,
41 content_type
= strdup(mimetype
);
44 content_type
= strdup(mimetype
);
46 #else /* MIMEENCODINGPROC */
47 content_type
= strdup(mimetype
);
48 #endif /* MIMEENCODINGPROC */
50 #endif /* MIMETYPEPROC */
53 * If we didn't get the MIME type from the contents (or we don't support
54 * the necessary command) then use the mhshow suffix.
57 if (content_type
== NULL
) {
58 struct node
*np
; /* Content scan node pointer */
59 FILE *fp
; /* File pointer for mhn.defaults */
61 if (! loaded_defaults
&&
62 (fp
= fopen(p
= etcpath("mhn.defaults"), "r"))) {
64 readconfig(NULL
, fp
, p
, 0);
68 if ((p
= strrchr(file_name
, '.')) != NULL
) {
69 for (np
= m_defs
; np
; np
= np
->n_next
) {
70 if (strncasecmp(np
->n_name
, "mhshow-suffix-", 14) == 0 &&
71 strcasecmp(p
, np
->n_field
? np
->n_field
: "") == 0) {
72 content_type
= strdup(np
->n_name
+ 14);
79 * If we didn't match any filename extension, try to infer the
80 * content type. If we have binary, assume application/octet-stream;
81 * otherwise, assume text/plain.
84 if (content_type
== NULL
) {
88 if (!(fp
= fopen(file_name
, "r"))) {
89 advise (NULL
, "unable to access file \"%s\"", file_name
);
93 while ((c
= getc(fp
)) != EOF
) {
103 strdup(binary
? "application/octet-stream" : "text/plain");
113 * Get information using proc about a file.
116 get_file_info(const char *proc
, const char *file_name
) {
120 if ((cp
= strchr(file_name
, '\''))) {
121 /* file_name contains a single quote. */
122 if (strchr(file_name
, '"')) {
123 advise(NULL
, "filenames containing both single and double quotes "
124 "are unsupported for attachment");
131 cmd
= concat(proc
, " ", quotec
, file_name
, quotec
, NULL
);
132 if ((cmd
= concat(proc
, " ", quotec
, file_name
, quotec
, NULL
))) {
135 if ((fp
= popen(cmd
, "r")) != NULL
) {
136 char buf
[BUFSIZ
>= 2048 ? BUFSIZ
: 2048];
139 if (fgets(buf
, sizeof buf
, fp
)) {
142 /* Skip leading <filename>:<whitespace>, if present. */
143 if ((cp
= strchr(buf
, ':')) != NULL
) {
145 while (*cp
&& isblank((unsigned char) *cp
)) {
152 /* Truncate at newline (LF or CR), if present. */
153 if ((eol
= strpbrk(cp
, "\n\r")) != NULL
) {
156 } else if (buf
[0] == '\0') {
157 /* This can happen on Cygwin if the popen()
158 mysteriously fails. Return NULL so that the caller
159 will use another method to determine the info. */
166 advise(NULL
, "no output from %s", cmd
);
171 advise(NULL
, "concat with \"%s\" failed, out of memory?", proc
);
174 return cp
? strdup(cp
) : NULL
;
176 #endif /* MIMETYPEPROC */