2 * ========================================================================
3 * Copyright 2013-2022 Eduardo Chappa
4 * Copyright 2006-2008 University of Washington
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * ========================================================================
18 #include "../../c-client/fs.h"
21 #include "../../pico/osdep/mswin.h"
25 #include "../charconv/utf8.h"
27 #include "../../pith/osdep/collate.h" /* for strucmp */
28 #include <Security/AuthSession.h>
36 int mswin_reg_viewer(LPTSTR mime_type
, LPTSTR mime_ext
,
37 char *cmd
, int clen
, int chk
);
38 int mswin_reg_mime_type(LPTSTR file_ext
, LPTSTR mime_type
, size_t mime_type_len
);
39 int mswin_reg_mime_ext(LPTSTR mime_type
, LPTSTR file_ext
, size_t file_ext_len
);
45 int osx_build_mime_type_cmd(char *, char *, int, int *);
46 int osx_build_mime_ext_cmd(char *, char *, int, int *);
48 #endif /* OSX_TARGET */
53 * Determine if there is an OS-specific mechanism for accessing
54 * MIME and extension data. In the general *nix case this is all
55 * done through mailcap and mime.types files.
57 * Returns: 0 if there is no support (most *nix cases)
58 * 1 if there is support (Mac OS X, Windows)
61 mime_os_specific_access(void)
66 # ifdef AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER
69 * if we don't have the WidowSession then we should avoid using
70 * frameworks unless they call themselves daemon-safe
72 SecuritySessionId session_id
;
73 SessionAttributeBits session_bits
;
75 if((SessionGetInfo(callerSecuritySession
, &session_id
, &session_bits
)
77 && session_bits
& sessionHasGraphicAccess
)
92 * Return the command based on either the mimetype or the file
93 * extension. Mime-type always takes precedence.
95 * mime_type - mime-type of the file we're looking at
96 * mime_ext - file extension given us by the mime data
97 * cmd - buffer to copy the resulting command into
98 * chk - whether or not we should check the file extension
100 * Returns: 1 on success, 0 on failure
103 mime_get_os_mimetype_command(char *mime_type
, char *mime_ext
, char *cmd
,
104 int clen
, int chk
, int *sp_hndlp
)
108 LPTSTR mime_type_lpt
, mime_ext_lpt
;
110 mime_type_lpt
= utf8_to_lptstr(mime_type
);
111 mime_ext_lpt
= utf8_to_lptstr(mime_ext
);
113 ret
= mswin_reg_viewer(mime_type_lpt
, mime_ext_lpt
, cmd
, clen
, chk
);
116 fs_give((void **) &mime_type_lpt
);
119 fs_give((void **) &mime_ext_lpt
);
126 * if we wanted to be more like PC-Pine, we'd try checking
127 * the mime-type of mime_ext and seeing if that matches
128 * with our mime-type, which is safe for opening
130 if(!mime_os_specific_access())
133 /* don't want to use Mail or something for a part alpine is good at */
134 if(!strucmp(mime_type
, "message/rfc822"))
137 return(osx_build_mime_type_cmd(mime_type
, cmd
, clen
, sp_hndlp
)
138 || (chk
&& mime_ext
&& *mime_ext
&&
139 osx_build_mime_ext_cmd(mime_ext
, cmd
, clen
, sp_hndlp
)));
147 * Given a file extension, return the mime-type if there is one
149 * Returns: 1 on success, 0 on failure
152 mime_get_os_mimetype_from_ext(char *file_ext
, char *mime_type
, int mime_type_len
)
156 LPTSTR x
, file_ext_lpt
, mime_type_lpt
;
158 file_ext_lpt
= utf8_to_lptstr(file_ext
);
162 mime_type_lpt
= (LPTSTR
) fs_get(mime_type_len
* sizeof(TCHAR
));
163 mime_type_lpt
[0] = '\0';
166 mime_type_lpt
= NULL
;
169 ret
= mswin_reg_mime_type(file_ext_lpt
, mime_type_lpt
, (size_t) mime_type_len
);
171 /* convert answer back to UTF-8 */
172 if(ret
&& mime_type_lpt
&& mime_type
){
175 u
= lptstr_to_utf8(mime_type_lpt
);
177 strncpy(mime_type
, u
, mime_type_len
);
178 mime_type
[mime_type_len
-1] = '\0';
179 fs_give((void **) &u
);
184 fs_give((void **) &file_ext_lpt
);
187 fs_give((void **) &mime_type_lpt
);
193 if(!mime_os_specific_access())
195 #ifdef AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER
196 CFStringRef mime_ref
= NULL
, type_id_ref
= NULL
, ext_ref
= NULL
;
199 if(!file_ext
|| !*file_ext
)
202 /* This for if we built on OS X >= 10.3 but run on < 10.3 */
203 if(&UTTypeCreatePreferredIdentifierForTag
== NULL
)
205 if((ext_ref
= CFStringCreateWithCString(NULL
, *file_ext
== '.' ?
206 file_ext
+ 1 : file_ext
,
207 kCFStringEncodingASCII
)) == NULL
)
210 = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension
,
211 ext_ref
, NULL
)) == NULL
)
214 if((mime_ref
= UTTypeCopyPreferredTagWithClass(type_id_ref
,
215 kUTTagClassMIMEType
)) == NULL
)
217 if(CFStringGetCString(mime_ref
, mime_type
,
218 (CFIndex
)mime_type_len
- 1,
219 kCFStringEncodingASCII
) == false)
222 mime_type
[mime_type_len
- 1] = '\0';
227 #endif /* AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER */
231 #endif /* OSX_TARGET */
236 * Given a mime-type, return the file extension if there is one
238 * Returns: 1 on success, 0 on failure
241 mime_get_os_ext_from_mimetype(char *mime_type
, char *file_ext
, int file_ext_len
)
245 LPTSTR x
, mime_type_lpt
, file_ext_lpt
;
247 mime_type_lpt
= utf8_to_lptstr(mime_type
);
251 file_ext_lpt
= (LPTSTR
) fs_get(file_ext_len
* sizeof(TCHAR
));
252 file_ext_lpt
[0] = '\0';
258 ret
= mswin_reg_mime_ext(mime_type_lpt
, file_ext_lpt
, (size_t) file_ext_len
);
260 /* convert answer back to UTF-8 */
261 if(ret
&& file_ext_lpt
&& file_ext
){
264 u
= lptstr_to_utf8(file_ext_lpt
);
266 strncpy(file_ext
, u
, file_ext_len
);
267 file_ext
[file_ext_len
-1] = '\0';
268 fs_give((void **) &u
);
273 fs_give((void **) &mime_type_lpt
);
276 fs_give((void **) &file_ext_lpt
);
282 if(!mime_os_specific_access())
284 #ifdef AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER
285 CFStringRef mime_ref
= NULL
, type_id_ref
= NULL
, ext_ref
= NULL
;
287 if(!mime_type
|| !*mime_type
)
289 /* This for if we built on OS X >= 10.3 but run on < 10.3 */
290 if(&UTTypeCreatePreferredIdentifierForTag
== NULL
)
292 if((mime_ref
= CFStringCreateWithCString(NULL
, mime_type
,
293 kCFStringEncodingASCII
)) == NULL
)
296 = UTTypeCreatePreferredIdentifierForTag(kUTTagClassMIMEType
,
297 mime_ref
, NULL
)) == NULL
)
300 if((ext_ref
= UTTypeCopyPreferredTagWithClass(type_id_ref
,
301 kUTTagClassFilenameExtension
)) == NULL
)
303 if((CFStringGetCString(ext_ref
, file_ext
, (CFIndex
)file_ext_len
- 1,
304 kCFStringEncodingASCII
)) == false)
307 file_ext
[file_ext_len
- 1] = '\0';
312 #endif /* AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER */
316 #endif /* OSX_TARGET */
327 mswin_reg_viewer(LPTSTR mime_type
, LPTSTR mime_ext
, char *cmd
, int clen
, int chk
)
335 * Everything's based on the file extension.
336 * So, sniff at registry's mapping for the given MIME type/subtype
337 * and sniff at clues on how to launch it, or
338 * extension mapping and then
339 * look for clues that some app will handle it.
342 return(((mswin_reg_mime_ext(mime_type
, ext
= tmp
, sizeof(tmp
)/sizeof(TCHAR
))
343 || ((ext
= mime_ext
) && *mime_ext
344 && ((mswin_reg_mime_type(mime_ext
, tmp
, sizeof(tmp
)/sizeof(TCHAR
))
345 && mime_type
&& !_tcsicmp(mime_type
, tmp
))
346 || mime_type
&& !_tcsicmp(mime_type
, TEXT("application/octet-stream")))))
347 && MSWRShellCanOpen(ext
, cmd
, clen
, 0) == TRUE
)
348 || (chk
&& MSWRShellCanOpen(ext
, cmd
, clen
, 1) == TRUE
));
353 * given a file name extension, fill in the provided buf with its
354 * corresponding MIME type
357 mswin_reg_mime_type(LPTSTR file_ext
, LPTSTR mime_type
, size_t mime_type_len
)
360 DWORD len
= mime_type_len
;
362 if(file_ext
[0] != '.'){
364 _tcsncpy(buf
+ 1, file_ext
, sizeof(buf
)/sizeof(TCHAR
)-1);
365 buf
[sizeof(buf
)/sizeof(TCHAR
)-1] = '\0';
369 return(MSWRPeek(HKEY_CLASSES_ROOT
, file_ext
, TEXT("content type"),
370 mime_type
, &len
) == TRUE
);
375 * given a mime_type, fill in the provided buf with its
376 * corresponding file name extension
379 mswin_reg_mime_ext(LPTSTR mime_type
, LPTSTR file_ext
, size_t file_ext_len
)
382 DWORD len
= file_ext_len
;
384 if(mime_type
&& _tcslen(mime_type
) < 50){
385 _sntprintf(keybuf
, sizeof(keybuf
), TEXT("MIME\\Database\\Content Type\\%s"), mime_type
);
386 return(MSWRPeek(HKEY_CLASSES_ROOT
, keybuf
,
387 TEXT("extension"), file_ext
, &len
) == TRUE
);
392 #endif /* _WINDOWS */
397 /* returns: 1 if success, 0 if failure */
399 osx_build_mime_type_cmd(mime_type
, cmd
, cmdlen
, sp_hndlp
)
400 char *mime_type
, *cmd
;
401 int cmdlen
, *sp_hndlp
;
405 if(!mime_os_specific_access())
407 #ifdef AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER
408 CFStringRef str_ref
= NULL
, ret_str_ref
= NULL
;
409 CFURLRef url_ref
= NULL
;
411 if(&LSCopyApplicationForMIMEType
== NULL
)
413 if((str_ref
= CFStringCreateWithCString(NULL
, mime_type
,
414 kCFStringEncodingASCII
)) == NULL
)
416 if(LSCopyApplicationForMIMEType(str_ref
, kLSRolesAll
, &url_ref
)
417 != kLSApplicationNotFoundErr
){
418 if((ret_str_ref
= CFURLGetString(url_ref
)) == NULL
)
420 if(CFStringGetCString(ret_str_ref
, cmd
, (CFIndex
)cmdlen
,
421 kCFStringEncodingASCII
) == false)
429 #endif /* AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER */
434 /* returns: 1 if success, 0 if failure */
436 osx_build_mime_ext_cmd(mime_ext
, cmd
, cmdlen
, sp_hndlp
)
437 char *mime_ext
, *cmd
;
438 int cmdlen
, *sp_hndlp
;
442 if(!mime_os_specific_access())
445 #ifdef AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER
446 CFStringRef str_ref
= NULL
, ret_str_ref
= NULL
;
447 CFURLRef url_ref
= NULL
;
449 if((str_ref
= CFStringCreateWithCString(NULL
, (*mime_ext
) == '.'
450 ? mime_ext
+1 : mime_ext
,
451 kCFStringEncodingASCII
)) == NULL
)
453 if(LSGetApplicationForInfo(kLSUnknownType
, kLSUnknownCreator
,
454 str_ref
, kLSRolesAll
, NULL
, &url_ref
)
455 != kLSApplicationNotFoundErr
){
456 if((ret_str_ref
= CFURLGetString(url_ref
)) == NULL
)
458 if(CFStringGetCString(ret_str_ref
, cmd
, (CFIndex
)cmdlen
,
459 kCFStringEncodingASCII
) == false)
470 #endif /* OSX_TARGET */