1 #if !defined(lint) && !defined(DOS)
2 static char rcsid
[] = "$Id: mimedisp.c 942 2008-03-04 18:21:33Z hubert@u.washington.edu $";
6 * ========================================================================
7 * Copyright 2006-2008 University of Washington
8 * Copyright 2013-2018 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 * ========================================================================
22 #include "../../c-client/fs.h"
25 #include "../../pico/osdep/mswin.h"
29 #include "../charconv/utf8.h"
31 #include "../../pith/osdep/collate.h" /* for strucmp */
32 #include <Security/AuthSession.h>
40 int mswin_reg_viewer(LPTSTR mime_type
, LPTSTR mime_ext
,
41 char *cmd
, int clen
, int chk
);
42 int mswin_reg_mime_type(LPTSTR file_ext
, LPTSTR mime_type
, size_t mime_type_len
);
43 int mswin_reg_mime_ext(LPTSTR mime_type
, LPTSTR file_ext
, size_t file_ext_len
);
49 int osx_build_mime_type_cmd(char *, char *, int, int *);
50 int osx_build_mime_ext_cmd(char *, char *, int, int *);
52 #endif /* OSX_TARGET */
57 * Determine if there is an OS-specific mechanism for accessing
58 * MIME and extension data. In the general *nix case this is all
59 * done through mailcap and mime.types files.
61 * Returns: 0 if there is no support (most *nix cases)
62 * 1 if there is support (Mac OS X, Windows)
65 mime_os_specific_access(void)
70 # ifdef AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER
73 * if we don't have the WidowSession then we should avoid using
74 * frameworks unless they call themselves daemon-safe
76 SecuritySessionId session_id
;
77 SessionAttributeBits session_bits
;
79 if((SessionGetInfo(callerSecuritySession
, &session_id
, &session_bits
)
81 && session_bits
& sessionHasGraphicAccess
)
96 * Return the command based on either the mimetype or the file
97 * extension. Mime-type always takes precedence.
99 * mime_type - mime-type of the file we're looking at
100 * mime_ext - file extension given us by the mime data
101 * cmd - buffer to copy the resulting command into
102 * chk - whether or not we should check the file extension
104 * Returns: 1 on success, 0 on failure
107 mime_get_os_mimetype_command(char *mime_type
, char *mime_ext
, char *cmd
,
108 int clen
, int chk
, int *sp_hndlp
)
112 LPTSTR mime_type_lpt
, mime_ext_lpt
;
114 mime_type_lpt
= utf8_to_lptstr(mime_type
);
115 mime_ext_lpt
= utf8_to_lptstr(mime_ext
);
117 ret
= mswin_reg_viewer(mime_type_lpt
, mime_ext_lpt
, cmd
, clen
, chk
);
120 fs_give((void **) &mime_type_lpt
);
123 fs_give((void **) &mime_ext_lpt
);
130 * if we wanted to be more like PC-Pine, we'd try checking
131 * the mime-type of mime_ext and seeing if that matches
132 * with our mime-type, which is safe for opening
134 if(!mime_os_specific_access())
137 /* don't want to use Mail or something for a part alpine is good at */
138 if(!strucmp(mime_type
, "message/rfc822"))
141 return(osx_build_mime_type_cmd(mime_type
, cmd
, clen
, sp_hndlp
)
142 || (chk
&& mime_ext
&& *mime_ext
&&
143 osx_build_mime_ext_cmd(mime_ext
, cmd
, clen
, sp_hndlp
)));
151 * Given a file extension, return the mime-type if there is one
153 * Returns: 1 on success, 0 on failure
156 mime_get_os_mimetype_from_ext(char *file_ext
, char *mime_type
, int mime_type_len
)
160 LPTSTR x
, file_ext_lpt
, mime_type_lpt
;
162 file_ext_lpt
= utf8_to_lptstr(file_ext
);
166 mime_type_lpt
= (LPTSTR
) fs_get(mime_type_len
* sizeof(TCHAR
));
167 mime_type_lpt
[0] = '\0';
170 mime_type_lpt
= NULL
;
173 ret
= mswin_reg_mime_type(file_ext_lpt
, mime_type_lpt
, (size_t) mime_type_len
);
175 /* convert answer back to UTF-8 */
176 if(ret
&& mime_type_lpt
&& mime_type
){
179 u
= lptstr_to_utf8(mime_type_lpt
);
181 strncpy(mime_type
, u
, mime_type_len
);
182 mime_type
[mime_type_len
-1] = '\0';
183 fs_give((void **) &u
);
188 fs_give((void **) &file_ext_lpt
);
191 fs_give((void **) &mime_type_lpt
);
197 if(!mime_os_specific_access())
199 #ifdef AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER
200 CFStringRef mime_ref
= NULL
, type_id_ref
= NULL
, ext_ref
= NULL
;
203 if(!file_ext
|| !*file_ext
)
206 /* This for if we built on OS X >= 10.3 but run on < 10.3 */
207 if(&UTTypeCreatePreferredIdentifierForTag
== NULL
)
209 if((ext_ref
= CFStringCreateWithCString(NULL
, *file_ext
== '.' ?
210 file_ext
+ 1 : file_ext
,
211 kCFStringEncodingASCII
)) == NULL
)
214 = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension
,
215 ext_ref
, NULL
)) == NULL
)
218 if((mime_ref
= UTTypeCopyPreferredTagWithClass(type_id_ref
,
219 kUTTagClassMIMEType
)) == NULL
)
221 if(CFStringGetCString(mime_ref
, mime_type
,
222 (CFIndex
)mime_type_len
- 1,
223 kCFStringEncodingASCII
) == false)
226 mime_type
[mime_type_len
- 1] = '\0';
231 #endif /* AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER */
235 #endif /* OSX_TARGET */
240 * Given a mime-type, return the file extension if there is one
242 * Returns: 1 on success, 0 on failure
245 mime_get_os_ext_from_mimetype(char *mime_type
, char *file_ext
, int file_ext_len
)
249 LPTSTR x
, mime_type_lpt
, file_ext_lpt
;
251 mime_type_lpt
= utf8_to_lptstr(mime_type
);
255 file_ext_lpt
= (LPTSTR
) fs_get(file_ext_len
* sizeof(TCHAR
));
256 file_ext_lpt
[0] = '\0';
262 ret
= mswin_reg_mime_ext(mime_type_lpt
, file_ext_lpt
, (size_t) file_ext_len
);
264 /* convert answer back to UTF-8 */
265 if(ret
&& file_ext_lpt
&& file_ext
){
268 u
= lptstr_to_utf8(file_ext_lpt
);
270 strncpy(file_ext
, u
, file_ext_len
);
271 file_ext
[file_ext_len
-1] = '\0';
272 fs_give((void **) &u
);
277 fs_give((void **) &mime_type_lpt
);
280 fs_give((void **) &file_ext_lpt
);
286 if(!mime_os_specific_access())
288 #ifdef AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER
289 CFStringRef mime_ref
= NULL
, type_id_ref
= NULL
, ext_ref
= NULL
;
291 if(!mime_type
|| !*mime_type
)
293 /* This for if we built on OS X >= 10.3 but run on < 10.3 */
294 if(&UTTypeCreatePreferredIdentifierForTag
== NULL
)
296 if((mime_ref
= CFStringCreateWithCString(NULL
, mime_type
,
297 kCFStringEncodingASCII
)) == NULL
)
300 = UTTypeCreatePreferredIdentifierForTag(kUTTagClassMIMEType
,
301 mime_ref
, NULL
)) == NULL
)
304 if((ext_ref
= UTTypeCopyPreferredTagWithClass(type_id_ref
,
305 kUTTagClassFilenameExtension
)) == NULL
)
307 if((CFStringGetCString(ext_ref
, file_ext
, (CFIndex
)file_ext_len
- 1,
308 kCFStringEncodingASCII
)) == false)
311 file_ext
[file_ext_len
- 1] = '\0';
316 #endif /* AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER */
320 #endif /* OSX_TARGET */
331 mswin_reg_viewer(LPTSTR mime_type
, LPTSTR mime_ext
, char *cmd
, int clen
, int chk
)
339 * Everything's based on the file extension.
340 * So, sniff at registry's mapping for the given MIME type/subtype
341 * and sniff at clues on how to launch it, or
342 * extension mapping and then
343 * look for clues that some app will handle it.
346 return(((mswin_reg_mime_ext(mime_type
, ext
= tmp
, sizeof(tmp
)/sizeof(TCHAR
))
347 || ((ext
= mime_ext
) && *mime_ext
348 && ((mswin_reg_mime_type(mime_ext
, tmp
, sizeof(tmp
)/sizeof(TCHAR
))
349 && mime_type
&& !_tcsicmp(mime_type
, tmp
))
350 || mime_type
&& !_tcsicmp(mime_type
, TEXT("application/octet-stream")))))
351 && MSWRShellCanOpen(ext
, cmd
, clen
, 0) == TRUE
)
352 || (chk
&& MSWRShellCanOpen(ext
, cmd
, clen
, 1) == TRUE
));
357 * given a file name extension, fill in the provided buf with its
358 * corresponding MIME type
361 mswin_reg_mime_type(LPTSTR file_ext
, LPTSTR mime_type
, size_t mime_type_len
)
364 DWORD len
= mime_type_len
;
366 if(file_ext
[0] != '.'){
368 _tcsncpy(buf
+ 1, file_ext
, sizeof(buf
)/sizeof(TCHAR
)-1);
369 buf
[sizeof(buf
)/sizeof(TCHAR
)-1] = '\0';
373 return(MSWRPeek(HKEY_CLASSES_ROOT
, file_ext
, TEXT("content type"),
374 mime_type
, &len
) == TRUE
);
379 * given a mime_type, fill in the provided buf with its
380 * corresponding file name extension
383 mswin_reg_mime_ext(LPTSTR mime_type
, LPTSTR file_ext
, size_t file_ext_len
)
386 DWORD len
= file_ext_len
;
388 if(mime_type
&& _tcslen(mime_type
) < 50){
389 _sntprintf(keybuf
, sizeof(keybuf
), TEXT("MIME\\Database\\Content Type\\%s"), mime_type
);
390 return(MSWRPeek(HKEY_CLASSES_ROOT
, keybuf
,
391 TEXT("extension"), file_ext
, &len
) == TRUE
);
396 #endif /* _WINDOWS */
401 /* returns: 1 if success, 0 if failure */
403 osx_build_mime_type_cmd(mime_type
, cmd
, cmdlen
, sp_hndlp
)
404 char *mime_type
, *cmd
;
405 int cmdlen
, *sp_hndlp
;
409 if(!mime_os_specific_access())
411 #ifdef AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER
412 CFStringRef str_ref
= NULL
, ret_str_ref
= NULL
;
413 CFURLRef url_ref
= NULL
;
415 if(&LSCopyApplicationForMIMEType
== NULL
)
417 if((str_ref
= CFStringCreateWithCString(NULL
, mime_type
,
418 kCFStringEncodingASCII
)) == NULL
)
420 if(LSCopyApplicationForMIMEType(str_ref
, kLSRolesAll
, &url_ref
)
421 != kLSApplicationNotFoundErr
){
422 if((ret_str_ref
= CFURLGetString(url_ref
)) == NULL
)
424 if(CFStringGetCString(ret_str_ref
, cmd
, (CFIndex
)cmdlen
,
425 kCFStringEncodingASCII
) == false)
433 #endif /* AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER */
438 /* returns: 1 if success, 0 if failure */
440 osx_build_mime_ext_cmd(mime_ext
, cmd
, cmdlen
, sp_hndlp
)
441 char *mime_ext
, *cmd
;
442 int cmdlen
, *sp_hndlp
;
446 if(!mime_os_specific_access())
449 #ifdef AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER
450 CFStringRef str_ref
= NULL
, ret_str_ref
= NULL
;
451 CFURLRef url_ref
= NULL
;
453 if((str_ref
= CFStringCreateWithCString(NULL
, (*mime_ext
) == '.'
454 ? mime_ext
+1 : mime_ext
,
455 kCFStringEncodingASCII
)) == NULL
)
457 if(LSGetApplicationForInfo(kLSUnknownType
, kLSUnknownCreator
,
458 str_ref
, kLSRolesAll
, NULL
, &url_ref
)
459 != kLSApplicationNotFoundErr
){
460 if((ret_str_ref
= CFURLGetString(url_ref
)) == NULL
)
462 if(CFStringGetCString(ret_str_ref
, cmd
, (CFIndex
)cmdlen
,
463 kCFStringEncodingASCII
) == false)
474 #endif /* OSX_TARGET */