From: Alex Henrie Subject: [PATCH resend 2/2] winemenubuilder: Create .desktop files for programs that open URIs Message-Id: <20200402045939.123780-2-alexhenrie24@gmail.com> Date: Wed, 1 Apr 2020 22:59:19 -0600 In-Reply-To: <20200402045939.123780-1-alexhenrie24@gmail.com> References: <20200402045939.123780-1-alexhenrie24@gmail.com> Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=22904 Signed-off-by: Alex Henrie --- loader/wine.inf.in | 4 + programs/winemenubuilder/winemenubuilder.c | 224 ++++++++++++--------- 2 files changed, 129 insertions(+), 99 deletions(-) diff --git a/loader/wine.inf.in b/loader/wine.inf.in index efe3db735f..cc7d2ea4db 100644 --- a/loader/wine.inf.in +++ b/loader/wine.inf.in @@ -510,6 +510,10 @@ HKCU,Software\Wine\FileOpenBlacklist\.txt,"notepad",,"%11%\notepad.exe %1" HKCU,Software\Wine\FileOpenBlacklist\.url,"ieframe",,"rundll32.exe ieframe.dll,OpenURL %l" HKCU,Software\Wine\FileOpenBlacklist\.wri,"wordpad",,"""%16422%\Windows NT\Accessories\wordpad.exe"" %1" HKCU,Software\Wine\FileOpenBlacklist\.xml,"winebrowser",,"""%11%\winebrowser.exe"" -nohome" +HKCU,Software\Wine\FileOpenBlacklist\ftp,"winebrowser",,"""%11%\winebrowser.exe"" -nohome" +HKCU,Software\Wine\FileOpenBlacklist\http,"winebrowser",,"""%11%\winebrowser.exe"" -nohome" +HKCU,Software\Wine\FileOpenBlacklist\https,"winebrowser",,"""%11%\winebrowser.exe"" -nohome" +HKCU,Software\Wine\FileOpenBlacklist\mailto,"winebrowser",,"%11%\winebrowser %1" [ContentIndex] HKLM,System\CurrentControlSet\Control\ContentIndex\Language\Neutral,"WBreakerClass",,"{369647e0-17b0-11ce-9950-00aa004bbb1f}" diff --git a/programs/winemenubuilder/winemenubuilder.c b/programs/winemenubuilder/winemenubuilder.c index 6f1dd7c571..a793b49f6b 100644 --- a/programs/winemenubuilder/winemenubuilder.c +++ b/programs/winemenubuilder/winemenubuilder.c @@ -2253,10 +2253,13 @@ static BOOL has_association_changed(LPCWSTR extensionW, LPCSTR mimeType, LPCWSTR ret = TRUE; HeapFree(GetProcessHeap(), 0, valueA); - value = reg_get_valW(assocKey, extensionW, ProgIDW); - if (!value || strcmpW(value, progId)) - ret = TRUE; - HeapFree(GetProcessHeap(), 0, value); + if (progId) + { + value = reg_get_valW(assocKey, extensionW, ProgIDW); + if (!value || strcmpW(value, progId)) + ret = TRUE; + HeapFree(GetProcessHeap(), 0, value); + } valueA = reg_get_val_utf8(assocKey, extensionW, AppNameW); if (!valueA || lstrcmpA(valueA, appName)) @@ -2340,7 +2343,7 @@ static void update_association(LPCWSTR extension, LPCSTR mimeType, LPCWSTR progI } RegSetValueExW(subkey, MimeTypeW, 0, REG_SZ, (const BYTE*) mimeTypeW, (lstrlenW(mimeTypeW) + 1) * sizeof(WCHAR)); - RegSetValueExW(subkey, ProgIDW, 0, REG_SZ, (const BYTE*) progId, (lstrlenW(progId) + 1) * sizeof(WCHAR)); + if (progId) RegSetValueExW(subkey, ProgIDW, 0, REG_SZ, (const BYTE*) progId, (lstrlenW(progId) + 1) * sizeof(WCHAR)); RegSetValueExW(subkey, AppNameW, 0, REG_SZ, (const BYTE*) appNameW, (lstrlenW(appNameW) + 1) * sizeof(WCHAR)); RegSetValueExW(subkey, DesktopFileW, 0, REG_SZ, (const BYTE*) desktopFileW, (lstrlenW(desktopFileW) + 1) * sizeof(WCHAR)); if (openWithIcon) @@ -2479,7 +2482,7 @@ static BOOL is_hard_blacklisted(const WCHAR *extension) return FALSE; } -static BOOL is_soft_blacklisted(const WCHAR *extension, const WCHAR *command) +static BOOL is_soft_blacklisted(const WCHAR *win_type, const WCHAR *command) { static const WCHAR FileOpenBlacklistW[] = {'S','o','f','t','w','a','r','e','\\', 'W','i','n','e','\\', @@ -2490,11 +2493,11 @@ static BOOL is_soft_blacklisted(const WCHAR *extension, const WCHAR *command) DWORD len = ARRAY_SIZE(program_name); DWORD i = 0; - if (ARRAY_SIZE(FileOpenBlacklistW) + lstrlenW(extension) > ARRAY_SIZE(blacklist_key_path)) + if (ARRAY_SIZE(FileOpenBlacklistW) + lstrlenW(win_type) > ARRAY_SIZE(blacklist_key_path)) return FALSE; lstrcpyW(blacklist_key_path, FileOpenBlacklistW); - lstrcatW(blacklist_key_path, extension); + lstrcatW(blacklist_key_path, win_type); if (RegOpenKeyExW(HKEY_CURRENT_USER, blacklist_key_path, 0, KEY_QUERY_VALUE, &blacklist_key) != ERROR_SUCCESS) return FALSE; @@ -2523,15 +2526,15 @@ static const char* get_special_mime_type(LPCWSTR extension) return NULL; } -static BOOL write_freedesktop_association_entry(const char *desktopPath, const char *dot_extension, +static BOOL write_freedesktop_association_entry(const char *desktopPath, const char *winType, const char *friendlyAppName, const char *mimeType, const char *progId, const char *openWithIcon) { BOOL ret = FALSE; FILE *desktop; - WINE_TRACE("writing association for file type %s, friendlyAppName=%s, MIME type %s, progID=%s, icon=%s to file %s\n", - wine_dbgstr_a(dot_extension), wine_dbgstr_a(friendlyAppName), wine_dbgstr_a(mimeType), + WINE_TRACE("writing association for type %s, friendlyAppName=%s, MIME type %s, progID=%s, icon=%s to file %s\n", + wine_dbgstr_a(winType), wine_dbgstr_a(friendlyAppName), wine_dbgstr_a(mimeType), wine_dbgstr_a(progId), wine_dbgstr_a(openWithIcon), wine_dbgstr_a(desktopPath)); desktop = fopen(desktopPath, "w"); @@ -2541,7 +2544,11 @@ static BOOL write_freedesktop_association_entry(const char *desktopPath, const c fprintf(desktop, "Type=Application\n"); fprintf(desktop, "Name=%s\n", friendlyAppName); fprintf(desktop, "MimeType=%s;\n", mimeType); - fprintf(desktop, "Exec=env WINEPREFIX=\"%s\" wine start /ProgIDOpen %s %%f\n", wine_get_config_dir(), progId); + fprintf(desktop, "Exec=env WINEPREFIX=\"%s\" wine start", wine_get_config_dir()); + if (progId) /* file association */ + fprintf(desktop, " /ProgIDOpen %s %%f\n", progId); + else /* protocol association */ + fprintf(desktop, " %%u\n"); fprintf(desktop, "NoDisplay=true\n"); fprintf(desktop, "StartupNotify=true\n"); if (openWithIcon) @@ -2557,6 +2564,7 @@ static BOOL write_freedesktop_association_entry(const char *desktopPath, const c static BOOL generate_associations(const char *xdg_data_home, const char *packages_dir, const char *applications_dir) { static const WCHAR openW[] = {'o','p','e','n',0}; + static const WCHAR UrlProtocolW[] = {'U','R','L',' ','P','r','o','t','o','c','o','l',0}; struct wine_rb_tree mimeProgidTree = { winemenubuilder_rb_string_compare }; struct list nativeMimeTypes = LIST_INIT(nativeMimeTypes); LSTATUS ret = 0; @@ -2571,26 +2579,33 @@ static BOOL generate_associations(const char *xdg_data_home, const char *package for (i = 0; ; i++) { - WCHAR *extensionW = NULL; + WCHAR *winTypeW = NULL; DWORD size = 1024; + BOOL is_protocol_type = FALSE; do { - HeapFree(GetProcessHeap(), 0, extensionW); - extensionW = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR)); - if (extensionW == NULL) + HeapFree(GetProcessHeap(), 0, winTypeW); + winTypeW = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR)); + if (winTypeW == NULL) { WINE_ERR("out of memory\n"); ret = ERROR_OUTOFMEMORY; break; } - ret = RegEnumKeyExW(HKEY_CLASSES_ROOT, i, extensionW, &size, NULL, NULL, NULL, NULL); + ret = RegEnumKeyExW(HKEY_CLASSES_ROOT, i, winTypeW, &size, NULL, NULL, NULL, NULL); size *= 2; } while (ret == ERROR_MORE_DATA); - if (ret == ERROR_SUCCESS && extensionW[0] == '.' && !is_hard_blacklisted(extensionW)) + if (ret == ERROR_SUCCESS && winTypeW[0] != '.') + { + if (RegGetValueW(HKEY_CLASSES_ROOT, winTypeW, UrlProtocolW, RRF_RT_ANY, NULL, NULL, NULL) == ERROR_SUCCESS) + is_protocol_type = TRUE; + } + + if (ret == ERROR_SUCCESS && (is_protocol_type || (winTypeW[0] == '.' && !is_hard_blacklisted(winTypeW)))) { - char *extensionA = NULL; + char *winTypeA = NULL; WCHAR *commandW = NULL; WCHAR *executableW = NULL; char *openWithIconA = NULL; @@ -2606,23 +2621,23 @@ static BOOL generate_associations(const char *xdg_data_home, const char *package char *progIdA = NULL; char *mimeProgId = NULL; - commandW = assoc_query(ASSOCSTR_COMMAND, extensionW, openW); + commandW = assoc_query(ASSOCSTR_COMMAND, winTypeW, openW); if (commandW == NULL) /* no command => no application is associated */ goto end; - if (is_soft_blacklisted(extensionW, commandW)) + if (is_soft_blacklisted(winTypeW, commandW)) /* command is on the blacklist => desktop integration is not desirable */ goto end; - extensionA = wchars_to_utf8_chars(strlwrW(extensionW)); - if (extensionA == NULL) + winTypeA = wchars_to_utf8_chars(strlwrW(winTypeW)); + if (winTypeA == NULL) { WINE_ERR("out of memory\n"); goto end; } - friendlyDocNameW = assoc_query(ASSOCSTR_FRIENDLYDOCNAME, extensionW, NULL); + friendlyDocNameW = assoc_query(ASSOCSTR_FRIENDLYDOCNAME, winTypeW, NULL); if (friendlyDocNameW) { friendlyDocNameA = wchars_to_utf8_chars(friendlyDocNameW); @@ -2633,61 +2648,105 @@ static BOOL generate_associations(const char *xdg_data_home, const char *package } } - iconW = assoc_query(ASSOCSTR_DEFAULTICON, extensionW, NULL); + iconW = assoc_query(ASSOCSTR_DEFAULTICON, winTypeW, NULL); - contentTypeW = assoc_query(ASSOCSTR_CONTENTTYPE, extensionW, NULL); + contentTypeW = assoc_query(ASSOCSTR_CONTENTTYPE, winTypeW, NULL); if (contentTypeW) strlwrW(contentTypeW); - if (!freedesktop_mime_type_for_extension(&nativeMimeTypes, extensionA, extensionW, &mimeTypeA)) - goto end; - - if (mimeTypeA == NULL) + if (is_protocol_type) { - if (contentTypeW != NULL && strchrW(contentTypeW, '/')) - mimeTypeA = wchars_to_utf8_chars(contentTypeW); - else if ((get_special_mime_type(extensionW))) - mimeTypeA = strdupA(get_special_mime_type(extensionW)); - else - mimeTypeA = heap_printf("application/x-wine-extension-%s", &extensionA[1]); + mimeTypeA = heap_printf("x-scheme-handler/%s", winTypeA); + } + else + { + if (!freedesktop_mime_type_for_extension(&nativeMimeTypes, winTypeA, winTypeW, &mimeTypeA)) + goto end; - if (mimeTypeA != NULL) + if (mimeTypeA == NULL) { - /* GNOME seems to ignore the tag in MIME packages, - * and the default name is more intuitive anyway. - */ - if (iconW) + if (contentTypeW != NULL && strchrW(contentTypeW, '/')) + mimeTypeA = wchars_to_utf8_chars(contentTypeW); + else if ((get_special_mime_type(winTypeW))) + mimeTypeA = strdupA(get_special_mime_type(winTypeW)); + else + mimeTypeA = heap_printf("application/x-wine-extension-%s", winTypeA+1); + + if (mimeTypeA != NULL) { - char *flattened_mime = slashes_to_minuses(mimeTypeA); - if (flattened_mime) + /* GNOME seems to ignore the tag in MIME packages, + * and the default name is more intuitive anyway. + */ + if (iconW) { - int index = 0; - WCHAR *comma = strrchrW(iconW, ','); - if (comma) + char *flattened_mime = slashes_to_minuses(mimeTypeA); + if (flattened_mime) { - *comma = 0; - index = atoiW(comma + 1); + int index = 0; + WCHAR *comma = strrchrW(iconW, ','); + if (comma) + { + *comma = 0; + index = atoiW(comma + 1); + } + iconA = extract_icon(iconW, index, flattened_mime, FALSE); + HeapFree(GetProcessHeap(), 0, flattened_mime); } - iconA = extract_icon(iconW, index, flattened_mime, FALSE); - HeapFree(GetProcessHeap(), 0, flattened_mime); } + + write_freedesktop_mime_type_entry(packages_dir, winTypeA, mimeTypeA, friendlyDocNameA); + hasChanged = TRUE; + } + else + { + WINE_FIXME("out of memory\n"); + goto end; } + } - write_freedesktop_mime_type_entry(packages_dir, extensionA, mimeTypeA, friendlyDocNameA); - hasChanged = TRUE; + progIdW = reg_get_valW(HKEY_CLASSES_ROOT, winTypeW, NULL); + if (progIdW) + { + progIdA = escape(progIdW); + if (progIdA == NULL) + { + WINE_ERR("out of memory\n"); + goto end; + } } else + goto end; /* no progID => not a file type association */ + + /* Do not allow duplicate ProgIDs for a MIME type, it causes unnecessary duplication in Open dialogs */ + mimeProgId = heap_printf("%s=>%s", mimeTypeA, progIdA); + if (mimeProgId) { - WINE_FIXME("out of memory\n"); - goto end; + struct rb_string_entry *entry; + if (wine_rb_get(&mimeProgidTree, mimeProgId)) + { + HeapFree(GetProcessHeap(), 0, mimeProgId); + goto end; + } + entry = HeapAlloc(GetProcessHeap(), 0, sizeof(struct rb_string_entry)); + if (!entry) + { + WINE_ERR("out of memory allocating rb_string_entry\n"); + goto end; + } + entry->string = mimeProgId; + if (wine_rb_put(&mimeProgidTree, mimeProgId, &entry->entry)) + { + WINE_ERR("error updating rb tree\n"); + goto end; + } } } - executableW = assoc_query(ASSOCSTR_EXECUTABLE, extensionW, openW); + executableW = assoc_query(ASSOCSTR_EXECUTABLE, winTypeW, openW); if (executableW) openWithIconA = extract_icon(executableW, 0, NULL, FALSE); - friendlyAppNameW = assoc_query(ASSOCSTR_FRIENDLYAPPNAME, extensionW, openW); + friendlyAppNameW = assoc_query(ASSOCSTR_FRIENDLYAPPNAME, winTypeW, openW); if (friendlyAppNameW) { friendlyAppNameA = wchars_to_utf8_chars(friendlyAppNameW); @@ -2707,59 +2766,26 @@ static BOOL generate_associations(const char *xdg_data_home, const char *package } } - progIdW = reg_get_valW(HKEY_CLASSES_ROOT, extensionW, NULL); - if (progIdW) - { - progIdA = escape(progIdW); - if (progIdA == NULL) - { - WINE_ERR("out of memory\n"); - goto end; - } - } - else - goto end; /* no progID => not a file type association */ - - /* Do not allow duplicate ProgIDs for a MIME type, it causes unnecessary duplication in Open dialogs */ - mimeProgId = heap_printf("%s=>%s", mimeTypeA, progIdA); - if (mimeProgId) - { - struct rb_string_entry *entry; - if (wine_rb_get(&mimeProgidTree, mimeProgId)) - { - HeapFree(GetProcessHeap(), 0, mimeProgId); - goto end; - } - entry = HeapAlloc(GetProcessHeap(), 0, sizeof(struct rb_string_entry)); - if (!entry) - { - WINE_ERR("out of memory allocating rb_string_entry\n"); - goto end; - } - entry->string = mimeProgId; - if (wine_rb_put(&mimeProgidTree, mimeProgId, &entry->entry)) - { - WINE_ERR("error updating rb tree\n"); - goto end; - } - } - - if (has_association_changed(extensionW, mimeTypeA, progIdW, friendlyAppNameA, openWithIconA)) + if (has_association_changed(winTypeW, mimeTypeA, progIdW, friendlyAppNameA, openWithIconA)) { - char *desktopPath = heap_printf("%s/wine-extension-%s.desktop", applications_dir, &extensionA[1]); + char *desktopPath; + if (is_protocol_type) + desktopPath = heap_printf("%s/wine-protocol-%s.desktop", applications_dir, winTypeA); + else + desktopPath = heap_printf("%s/wine-extension-%s.desktop", applications_dir, winTypeA+1); if (desktopPath) { - if (write_freedesktop_association_entry(desktopPath, extensionA, friendlyAppNameA, mimeTypeA, progIdA, openWithIconA)) + if (write_freedesktop_association_entry(desktopPath, winTypeA, friendlyAppNameA, mimeTypeA, progIdA, openWithIconA)) { hasChanged = TRUE; - update_association(extensionW, mimeTypeA, progIdW, friendlyAppNameA, desktopPath, openWithIconA); + update_association(winTypeW, mimeTypeA, progIdW, friendlyAppNameA, desktopPath, openWithIconA); } HeapFree(GetProcessHeap(), 0, desktopPath); } } end: - HeapFree(GetProcessHeap(), 0, extensionA); + HeapFree(GetProcessHeap(), 0, winTypeA); HeapFree(GetProcessHeap(), 0, commandW); HeapFree(GetProcessHeap(), 0, executableW); HeapFree(GetProcessHeap(), 0, openWithIconA); @@ -2774,7 +2800,7 @@ static BOOL generate_associations(const char *xdg_data_home, const char *package HeapFree(GetProcessHeap(), 0, progIdW); HeapFree(GetProcessHeap(), 0, progIdA); } - HeapFree(GetProcessHeap(), 0, extensionW); + HeapFree(GetProcessHeap(), 0, winTypeW); if (ret != ERROR_SUCCESS) break; } -- 2.26.0