1 /* Functionality for handling mime types */
2 /* $Id: mime.c,v 1.72 2005/06/28 19:38:51 jonas Exp $ */
12 #include "cache/cache.h"
13 #include "config/options.h"
14 #include "encoding/encoding.h"
15 #include "intl/gettext/libintl.h"
16 #include "main/module.h"
17 #include "mime/backend/common.h"
18 #include "mime/mime.h"
19 #include "protocol/header.h" /* For parse_header() */
20 #include "protocol/uri.h"
21 #include "util/conv.h"
22 #include "util/file.h"
23 #include "util/memory.h"
24 #include "util/string.h"
34 static struct option_info mime_options
[] = {
35 INIT_OPT_TREE("", N_("MIME"),
37 N_("MIME-related options (handlers of various MIME types).")),
39 INIT_OPT_STRING("mime", N_("Default MIME-type"),
40 "default_type", 0, DEFAULT_MIME_TYPE
,
41 N_("Document MIME-type to assume by default (when we are unable to\n"
42 "guess it properly from known information about the document).")),
47 #define get_opt_mime(which) mime_options[(which)].option
48 #define get_default_mime_type() get_opt_mime(MIME_DEFAULT_TYPE).value.string
50 /* Checks protocols headers for a suitable filename */
51 static unsigned char *
52 get_content_filename(struct uri
*uri
, struct cache_entry
*cached
)
54 unsigned char *filename
, *pos
;
56 if (!cached
) cached
= find_in_cache(uri
);
58 if (!cached
|| !cached
->head
)
61 pos
= parse_header(cached
->head
, "Content-Disposition", NULL
);
62 if (!pos
) return NULL
;
64 filename
= parse_header_param(pos
, "filename");
66 if (!filename
) return NULL
;
68 /* Remove start and ending quotes. */
69 if (filename
[0] == '"') {
70 int len
= strlen(filename
);
72 if (len
> 1 && filename
[len
- 1] == '"') {
73 filename
[len
- 1] = 0;
74 memmove(filename
, filename
+ 1, len
);
77 /* It was an empty quotation: "" */
84 /* We don't want to add any directories from the path so make sure we
85 * only add the filename. */
86 pos
= get_filename_position(filename
);
93 memmove(filename
, pos
, strlen(pos
) + 1);
98 /* Checks if application/x-<extension> has any handlers. */
99 static inline unsigned char *
100 check_extension_type(unsigned char *extension
)
102 /* Trim the extension so only last .<extension> is used. */
103 unsigned char *trimmed
= strrchr(extension
, '.');
104 struct mime_handler
*handler
;
105 unsigned char *content_type
;
110 content_type
= straconcat("application/x-", trimmed
+ 1, NULL
);
114 handler
= get_mime_type_handler(content_type
, 1);
120 mem_free(content_type
);
124 /* Check if part of the extension coresponds to a supported encoding and if it
125 * has any handlers. */
126 static inline unsigned char *
127 check_encoding_type(unsigned char *extension
)
129 enum stream_encoding encoding
= guess_encoding(extension
);
130 unsigned char **extension_list
;
131 unsigned char *last_extension
= strrchr(extension
, '.');
133 if (encoding
== ENCODING_NONE
|| !last_extension
)
136 for (extension_list
= listext_encoded(encoding
);
137 extension_list
&& *extension_list
;
139 unsigned char *content_type
;
141 if (strcmp(*extension_list
, last_extension
))
144 *last_extension
= '\0';
145 content_type
= get_content_type_backends(extension
);
146 *last_extension
= '.';
155 #define DEBUG_CONTENT_TYPE
158 #ifdef DEBUG_CONTENT_TYPE
159 #define debug_get_content_type_params(cached) \
160 DBG("get_content_type(head, url)\n=== head ===\n%s\n=== url ===\n%s\n", (cached)->head, struri((cached)->uri))
161 #define debug_ctype(ctype__) DBG("ctype= %s", (ctype__))
162 #define debug_extension(extension__) DBG("extension= %s", (extension__))
164 #define debug_get_content_type_params(cached)
165 #define debug_ctype(ctype__)
166 #define debug_extension(extension__)
170 get_extension_content_type(unsigned char *extension
)
172 unsigned char *ctype
;
174 assert(extension
&& *extension
);
176 ctype
= get_content_type_backends(extension
);
178 if (ctype
) return ctype
;
180 ctype
= check_encoding_type(extension
);
182 if (ctype
) return ctype
;
184 ctype
= check_extension_type(extension
);
190 get_cache_header_content_type(struct cache_entry
*cached
)
192 unsigned char *extension
, *ctype
;
194 ctype
= parse_header(cached
->head
, "Content-Type", NULL
);
196 unsigned char *end
= strchr(ctype
, ';');
199 if (end
) *end
= '\0';
201 ctypelen
= strlen(ctype
);
202 while (ctypelen
&& ctype
[--ctypelen
] <= ' ')
203 ctype
[ctypelen
] = '\0';
214 /* This searches cached->head for filename so put here */
215 extension
= get_content_filename(cached
->uri
, cached
);
216 debug_extension(extension
);
218 ctype
= get_extension_content_type(extension
);
229 get_content_type(struct cache_entry
*cached
)
231 unsigned char *extension
, *ctype
;
233 debug_get_content_type_params(cached
);
235 if (cached
->content_type
)
236 return cached
->content_type
;
238 /* If there's one in header, it's simple.. */
240 ctype
= get_cache_header_content_type(cached
);
241 if (ctype
&& *ctype
) {
242 cached
->content_type
= ctype
;
248 /* We can't use the extension string we are getting below, because we
249 * want to support also things like "ps.gz" - that'd never work, as we
250 * would always compare only to "gz". */
251 /* Guess type accordingly to the extension */
252 extension
= get_extension_from_uri(cached
->uri
);
253 debug_extension(extension
);
256 /* XXX: A little hack for making extension handling case
257 * insensitive. We could probably do it better by making
258 * guess_encoding() case independent the real problem however
259 * is with default (via option system) and mimetypes resolving
260 * doing that option and hash lookup will not be easy to
261 * convert. --jonas */
262 convert_to_lowercase(extension
, strlen(extension
));
264 ctype
= get_extension_content_type(extension
);
266 if (ctype
&& *ctype
) {
267 cached
->content_type
= ctype
;
273 debug_ctype(get_default_mime_type());
275 /* Fallback.. use some hardwired default */
276 cached
->content_type
= stracpy(get_default_mime_type());
278 return cached
->content_type
;
281 struct mime_handler
*
282 get_mime_type_handler(unsigned char *content_type
, int xwin
)
284 return get_mime_handler_backends(content_type
, xwin
);
288 add_mime_filename_to_string(struct string
*string
, struct uri
*uri
)
290 unsigned char *filename
= get_content_filename(uri
, NULL
);
295 add_shell_safe_to_string(string
, filename
, strlen(filename
));
301 return add_uri_to_string(string
, uri
, URI_FILENAME
);
304 /* Backends dynamic area: */
306 #include "mime/backend/default.h"
307 #include "mime/backend/mailcap.h"
308 #include "mime/backend/mimetypes.h"
310 static struct module
*mime_submodules
[] = {
311 &default_mime_module
,
312 #ifdef CONFIG_MAILCAP
313 &mailcap_mime_module
,
315 #ifdef CONFIG_MIMETYPES
316 &mimetypes_mime_module
,
321 struct module mime_module
= struct_module(
322 /* name: */ N_("MIME"),
323 /* options: */ mime_options
,
325 /* submodules: */ mime_submodules
,