1 #if !defined(lint) && !defined(DOS)
2 static char rcsid
[] = "$Id: mimetype.c 955 2008-03-06 23:52:36Z hubert@u.washington.edu $";
6 * ========================================================================
7 * Copyright 2006-2008 University of Washington
8 * Copyright 2013-2017 Eduardo Chappa
10 * Licensed under the Apache License, Version 2.0 (the "License");
11 * you may not use this file except in compliance with the License.
12 * You may obtain a copy of the License at
14 * http://www.apache.org/licenses/LICENSE-2.0
16 * ========================================================================
19 #include "../pith/headers.h"
20 #include "../pith/mimetype.h"
21 #include "../pith/mimedesc.h"
22 #include "../pith/state.h"
23 #include "../pith/conf.h"
24 #include "../pith/mailcap.h"
25 #include "../pith/util.h"
28 * We've decided not to implement the RFC1524 standard minimum path, because
29 * some of us think it is harder to debug a problem when you may be misled
30 * into looking at the wrong mailcap entry. Likewise for MIME.Types files.
32 #if defined(DOS) || defined(OS2)
33 #define MT_PATH_SEPARATOR ';'
34 #define MT_USER_FILE "MIMETYPE"
35 #define MT_STDPATH NULL
37 #define MT_PATH_SEPARATOR ':'
38 #define MT_USER_FILE NULL
40 ".mime.types:/etc/mime.types:/usr/local/lib/mime.types"
43 #define LINE_BUF_SIZE 2000
47 * Types used to pass parameters and operator functions to the
48 * mime.types searching routines.
50 #define MT_MAX_FILE_EXTENSION 3
56 int mt_browse_types_file(MT_OPERATORPROC
, MT_MAP_T
*, char *);
57 int mt_srch_by_type(MT_MAP_T
*, FILE *);
62 * Exported function that does the work of sniffing the mime.types
63 * files and filling in the body pointer if found. Returns 1 (TRUE) if
64 * extension found, and body pointer filled in, 0 (FALSE) otherwise.
67 set_mime_type_by_extension(struct mail_bodystruct
*body
, char *filename
)
71 if(mt_get_file_ext(filename
, &e2b
.from
.ext
)
72 && mt_srch_mime_type(mt_srch_by_ext
, &e2b
)){
73 body
->type
= e2b
.to
.mime
.type
;
74 body
->subtype
= e2b
.to
.mime
.subtype
; /* NOTE: subtype was malloc'd */
83 * Exported function that maps from mime types to file extensions.
86 set_mime_extension_by_type (char *ext
, char *mtype
)
90 t2e
.from
.mime_type
= mtype
;
92 return (mt_srch_mime_type (mt_srch_by_type
, &t2e
));
97 check_mime_type_by_extension (char *ext
, char *mtype
)
102 if((e2t
.from
.ext
= ext
) != NULL
&& *e2t
.from
.ext
103 && mt_srch_mime_type(mt_srch_by_ext
, &e2t
)){
104 snprintf(mimet
, sizeof(mimet
), "%s/%s",
105 body_type_names(e2t
.to
.mime
.type
), e2t
.to
.mime
.subtype
);
106 mimet
[sizeof(mimet
) - 1] = '\0';
107 fs_give((void **)& e2t
.to
.mime
.subtype
);
108 return strucmp(mimet
, mtype
) ? 0 : 1;
116 * Separate and return a pointer to the first character in the 'filename'
117 * character buffer that comes after the rightmost '.' character in the
118 * filename. (What I mean is a pointer to the filename - extension).
120 * Returns 1 if an extension is found, 0 otherwise.
123 mt_get_file_ext(char *filename
, char **extension
)
125 dprint((5, "mt_get_file_ext : filename=\"%s\", ",
126 filename
? filename
: "?"));
128 for(*extension
= NULL
; filename
&& *filename
; filename
++)
130 *extension
= filename
+ 1;
132 dprint((5, "extension=\"%s\"\n",
133 (extension
&& *extension
) ? *extension
: "?"));
135 return(*extension
? 1 : 0);
140 * Build a list of possible mime.type files. For each one that exists
141 * call the mt_operator function.
142 * Loop terminates when mt_operator returns non-zero.
145 mt_srch_mime_type(MT_OPERATORPROC mt_operator
, MT_MAP_T
*mt_map
)
147 char *s
, *pathcopy
, *path
;
150 dprint((5, "- mt_srch_mime_type -\n"));
152 pathcopy
= mc_conf_path(ps_global
->VAR_MIMETYPE_PATH
, getenv("MIMETYPES"),
153 MT_USER_FILE
, MT_PATH_SEPARATOR
, MT_STDPATH
);
155 path
= pathcopy
; /* overloaded "path" */
157 dprint((7, "mime_types: path: %s\n", path
? path
: "?"));
159 if((s
= strindex(path
, MT_PATH_SEPARATOR
)) != NULL
)
162 if((rv
= mt_browse_types_file(mt_operator
, mt_map
, path
)) != 0)
169 fs_give((void **)&pathcopy
);
171 if(!rv
&& mime_os_specific_access()){
172 if(mt_operator
== mt_srch_by_ext
){
176 if(mime_get_os_mimetype_from_ext(mt_map
->from
.ext
, buf
, 256)){
177 if((s
= strindex(buf
, '/')) != NULL
){
179 mt_map
->to
.mime
.type
= mt_translate_type(buf
);
180 mt_map
->to
.mime
.subtype
= cpystr(s
);
185 else if(mt_operator
== mt_srch_by_type
){
186 if(mime_get_os_ext_from_mimetype(mt_map
->from
.mime_type
,
187 mt_map
->to
.ext
, 32)){
188 /* the 32 comes from var ext[] in display_attachment() */
189 if(*(s
= mt_map
->to
.ext
) == '.')
190 while((*s
= *(s
+1)) != '\0')
197 alpine_panic("Unhandled mime type search");
200 /* if we still can not find the type, but it is a .docx (or alike) extension
201 set the type here. Do not use the grope function.
204 rv
= 1; /* assume success */
205 mt_map
->to
.mime
.type
= TYPEAPPLICATION
;
206 if(!strucmp(mt_map
->from
.ext
, "docx"))
207 mt_map
->to
.mime
.subtype
= cpystr("VND.OPENXMLFORMATS-OFFICEDOCUMENT.WORDPROCESSINGML.DOCUMENT");
208 else if(!strucmp(mt_map
->from
.ext
, "xslx"))
209 mt_map
->to
.mime
.subtype
= cpystr("VND.OPENXMLFORMATS-OFFICEDOCUMENT.SPREADSHEETML.SHEET");
210 else if(!strucmp(mt_map
->from
.ext
, "xltx"))
211 mt_map
->to
.mime
.subtype
= cpystr("VND.OPENXMLFORMATS-OFFICEDOCUMENT.SPREADSHEETML.TEMPLATE");
212 else if(!strucmp(mt_map
->from
.ext
, "potx"))
213 mt_map
->to
.mime
.subtype
= cpystr("VND.OPENXMLFORMATS-OFFICEDOCUMENT.PRESENTATIONML.TEMPLATE");
214 else if(!strucmp(mt_map
->from
.ext
, "ppsx"))
215 mt_map
->to
.mime
.subtype
= cpystr("VND.OPENXMLFORMATS-OFFICEDOCUMENT.PRESENTATIONML.SLIDESHOW");
216 else if(!strucmp(mt_map
->from
.ext
, "pptx"))
217 mt_map
->to
.mime
.subtype
= cpystr("VND.OPENXMLFORMATS-OFFICEDOCUMENT.PRESENTATIONML.PRESENTATION");
218 else if(!strucmp(mt_map
->from
.ext
, "sldx"))
219 mt_map
->to
.mime
.subtype
= cpystr("VND.OPENXMLFORMATS-OFFICEDOCUMENT.PRESENTATIONML.SLIDE");
220 else if(!strucmp(mt_map
->from
.ext
, "dotx"))
221 mt_map
->to
.mime
.subtype
= cpystr("VND.OPENXMLFORMATS-OFFICEDOCUMENT.WORDPROCESSINGML.TEMPLATE");
222 else if(!strucmp(mt_map
->from
.ext
, "xlam"))
223 mt_map
->to
.mime
.subtype
= cpystr("VND.MS-EXCEL.ADDIN.MACROENABLED.12");
224 else if(!strucmp(mt_map
->from
.ext
, "xslb"))
225 mt_map
->to
.mime
.subtype
= cpystr("VND.MS-EXCEL.SHEET.BINARY.MACROENABLED.12");
226 else rv
= 0; /* else, failure */
235 * Try to match a file extension against extensions found in the file
236 * ``filename'' if that file exists. return 1 if a match
237 * was found and 0 in all other cases.
240 mt_browse_types_file(MT_OPERATORPROC mt_operator
, MT_MAP_T
*mt_map
, char *filename
)
245 dprint((7, "mt_browse_types_file(%s)\n", filename
? filename
: "?"));
246 if((file
= our_fopen(filename
, "rb")) != NULL
){
247 rv
= (*mt_operator
)(mt_map
, file
);
251 dprint((1, "mt_browse: FAILED open(%s) : %s.\n",
252 filename
? filename
: "?", error_description(errno
)));
260 * scan each line of the file. Treat each line as a mime type definition.
261 * The first word is a type/subtype specification. All following words
262 * are file extensions belonging to that type/subtype. Words are separated
263 * bij whitespace characters.
264 * If a file extension occurs more than once, then the first definition
265 * determines the file type and subtype.
268 mt_srch_by_ext(MT_MAP_T
*e2b
, FILE *file
)
270 char buffer
[LINE_BUF_SIZE
];
272 /* construct a loop reading the file line by line. Then check each
273 * line for a matching definition.
275 while(fgets(buffer
,LINE_BUF_SIZE
,file
) != NULL
){
280 continue; /* comment */
282 /* divide the input buffer into words separated by whitespace.
283 * The first words is the type and subtype. All following words
284 * are file extensions.
286 dprint((5, "traverse: buffer=\"%s\"\n", buffer
));
287 typespec
= strtok(buffer
," \t"); /* extract type,subtype */
291 dprint((5, "typespec=\"%s\"\n", typespec
? typespec
: "?"));
292 while((try_extension
= strtok(NULL
, " \t\n\r")) != NULL
){
293 /* compare the extensions, and assign the type if a match
296 dprint((5,"traverse: trying ext \"%s\"\n",try_extension
));
297 if(strucmp(try_extension
, e2b
->from
.ext
) == 0){
298 /* split the 'type/subtype' specification */
299 char *type
, *subtype
= NULL
;
301 type
= strtok(typespec
,"/");
303 subtype
= strtok(NULL
,"/");
305 dprint((5, "traverse: type=%s, subtype=%s.\n",
306 type
? type
: "<null>",
307 subtype
? subtype
: "<null>"));
308 /* The type is encoded as a small integer. we have to
309 * translate the character string naming the type into
310 * the corresponding number.
312 e2b
->to
.mime
.type
= mt_translate_type(type
);
313 e2b
->to
.mime
.subtype
= cpystr(subtype
? subtype
: "x-unknown");
314 return 1; /* a match has been found */
319 dprint((5, "traverse: search failed.\n"));
325 * scan each line of the file. Treat each line as a mime type definition.
326 * Here we are looking for a matching type. When that is found return the
327 * first extension that is three chars or less.
330 mt_srch_by_type(MT_MAP_T
*t2e
, FILE *file
)
332 char buffer
[LINE_BUF_SIZE
];
334 /* construct a loop reading the file line by line. Then check each
335 * line for a matching definition.
337 while(fgets(buffer
,LINE_BUF_SIZE
,file
) != NULL
){
342 continue; /* comment */
344 /* divide the input buffer into words separated by whitespace.
345 * The first words is the type and subtype. All following words
346 * are file extensions.
348 dprint((5, "traverse: buffer=%s.\n", buffer
));
349 typespec
= strtok(buffer
," \t"); /* extract type,subtype */
350 dprint((5, "typespec=%s.\n", typespec
? typespec
: "?"));
351 if (strucmp (typespec
, t2e
->from
.mime_type
) == 0) {
352 while((try_extension
= strtok(NULL
, " \t\n\r")) != NULL
){
353 if (strlen (try_extension
) <= MT_MAX_FILE_EXTENSION
) {
354 strncpy (t2e
->to
.ext
, try_extension
, 32);
356 * not sure of the 32, so don't write to byte 32
358 * t2e->to.ext[31] = '\0';
359 * in case that breaks something
368 dprint((5, "traverse: search failed.\n"));
374 * Translate a character string representing a content type into a short
375 * integer number, according to the coding described in c-client/mail.h
376 * List of content types taken from rfc1521, September 1993.
379 mt_translate_type(char *type
)
383 for (i
=0;(i
<=TYPEMAX
) && body_types
[i
] && strucmp(type
,body_types
[i
]);i
++)
388 else if (!body_types
[i
]) /* if empty slot, assign it to this type */
389 body_types
[i
] = cpystr (type
);