Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=22904
-- v3: winecfg: Mention protocol associations. winemenubuilder: Create .desktop files for programs that open URIs.
From: Alex Henrie alexhenrie24@gmail.com
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=22904 --- programs/winemenubuilder/winemenubuilder.c | 164 ++++++++++++--------- 1 file changed, 96 insertions(+), 68 deletions(-)
diff --git a/programs/winemenubuilder/winemenubuilder.c b/programs/winemenubuilder/winemenubuilder.c index ae657d87bb1..d8ab78d1de8 100644 --- a/programs/winemenubuilder/winemenubuilder.c +++ b/programs/winemenubuilder/winemenubuilder.c @@ -1833,10 +1833,13 @@ static BOOL has_association_changed(LPCWSTR extensionW, const WCHAR *mimeType, c ret = TRUE; heap_free(value);
- value = reg_get_valW(assocKey, extensionW, L"ProgID"); - if (!value || wcscmp(value, progId)) - ret = TRUE; - heap_free(value); + if (progId) + { + value = reg_get_valW(assocKey, extensionW, L"ProgID"); + if (!value || wcscmp(value, progId)) + ret = TRUE; + heap_free(value); + }
value = reg_get_valW(assocKey, extensionW, L"AppName"); if (!value || wcscmp(value, appName)) @@ -1880,7 +1883,7 @@ static void update_association(LPCWSTR extension, const WCHAR *mimeType, const W }
RegSetValueExW(subkey, L"MimeType", 0, REG_SZ, (const BYTE*) mimeType, (lstrlenW(mimeType) + 1) * sizeof(WCHAR)); - RegSetValueExW(subkey, L"ProgID", 0, REG_SZ, (const BYTE*) progId, (lstrlenW(progId) + 1) * sizeof(WCHAR)); + if (progId) RegSetValueExW(subkey, L"ProgID", 0, REG_SZ, (const BYTE*) progId, (lstrlenW(progId) + 1) * sizeof(WCHAR)); RegSetValueExW(subkey, L"AppName", 0, REG_SZ, (const BYTE*) appName, (lstrlenW(appName) + 1) * sizeof(WCHAR)); RegSetValueExW(subkey, L"DesktopFile", 0, REG_SZ, (const BYTE*) desktopFile, (lstrlenW(desktopFile) + 1) * sizeof(WCHAR)); if (openWithIcon) @@ -1964,12 +1967,16 @@ static BOOL write_freedesktop_mime_type_entry(const WCHAR *packages_dir, const W return ret; }
-static BOOL is_extension_banned(LPCWSTR extension) +static BOOL is_type_banned(const WCHAR *win_type) { /* These are managed through external tools like wine.desktop, to evade malware created file type associations */ - if (!wcsicmp(extension, L".com") || - !wcsicmp(extension, L".exe") || - !wcsicmp(extension, L".msi")) + if (!wcsicmp(win_type, L".com") || + !wcsicmp(win_type, L".exe") || + !wcsicmp(win_type, L".msi")) + return TRUE; + /* Associating a program with the file URI scheme is like associating it with all file types, which is not allowed + * for the same reasons */ + if (!wcsicmp(win_type, L"file")) return TRUE; return FALSE; } @@ -2043,11 +2050,15 @@ static BOOL write_freedesktop_association_entry(const WCHAR *desktopPath, const if (prefix) { char *path = wine_get_unix_file_name( prefix ); - fprintf(desktop, "Exec=env WINEPREFIX="%s" wine start /ProgIDOpen %s %%f\n", path, escape(progId)); + fprintf(desktop, "Exec=env WINEPREFIX="%s" wine start ", path); heap_free( path ); } else - fprintf(desktop, "Exec=wine start /ProgIDOpen %s %%f\n", escape(progId)); + fprintf(desktop, "Exec=wine start "); + if (progId) /* file association */ + fprintf(desktop, "/ProgIDOpen %s %%f\n", escape(progId)); + else /* protocol association */ + fprintf(desktop, "%%u\n"); fprintf(desktop, "NoDisplay=true\n"); fprintf(desktop, "StartupNotify=true\n"); if (openWithIcon) @@ -2075,12 +2086,19 @@ static BOOL generate_associations(const WCHAR *packages_dir, const WCHAR *applic
for (i = 0; ; i++) { - WCHAR *extensionW; + WCHAR *winTypeW; + BOOL isProtocolType = FALSE;
- if (!(extensionW = reg_enum_keyW(HKEY_CLASSES_ROOT, i))) + if (!(winTypeW = reg_enum_keyW(HKEY_CLASSES_ROOT, i))) break;
- if (extensionW[0] == '.' && !is_extension_banned(extensionW)) + if (winTypeW[0] != '.') + { + if (RegGetValueW(HKEY_CLASSES_ROOT, winTypeW, L"URL Protocol", RRF_RT_ANY, NULL, NULL, NULL) == ERROR_SUCCESS) + isProtocolType = TRUE; + } + + if ((winTypeW[0] == '.' || isProtocolType) && !is_type_banned(winTypeW)) { WCHAR *commandW = NULL; WCHAR *executableW = NULL; @@ -2094,7 +2112,7 @@ static BOOL generate_associations(const WCHAR *packages_dir, const WCHAR *applic WCHAR *mimeProgId = NULL; struct rb_string_entry *entry;
- commandW = assoc_query(ASSOCSTR_COMMAND, extensionW, L"open"); + commandW = assoc_query(ASSOCSTR_COMMAND, winTypeW, L"open"); if (commandW == NULL) /* no command => no application is associated */ goto end; @@ -2103,78 +2121,88 @@ static BOOL generate_associations(const WCHAR *packages_dir, const WCHAR *applic /* command is on the exclude list => desktop integration is not desirable */ goto end;
- wcslwr(extensionW); - friendlyDocNameW = assoc_query(ASSOCSTR_FRIENDLYDOCNAME, extensionW, NULL); + iconW = assoc_query(ASSOCSTR_DEFAULTICON, winTypeW, NULL);
- iconW = assoc_query(ASSOCSTR_DEFAULTICON, extensionW, NULL); + if (isProtocolType) + { + mimeType = heap_wprintf(L"x-scheme-handler/%s", winTypeW); + } + else + { + wcslwr(winTypeW); + friendlyDocNameW = assoc_query(ASSOCSTR_FRIENDLYDOCNAME, winTypeW, NULL);
- contentTypeW = assoc_query(ASSOCSTR_CONTENTTYPE, extensionW, NULL); - if (contentTypeW) - wcslwr(contentTypeW); + contentTypeW = assoc_query(ASSOCSTR_CONTENTTYPE, winTypeW, NULL); + if (contentTypeW) + wcslwr(contentTypeW);
- mimeType = freedesktop_mime_type_for_extension(&nativeMimeTypes, extensionW); + mimeType = freedesktop_mime_type_for_extension(&nativeMimeTypes, winTypeW);
- if (mimeType == NULL) - { - if (contentTypeW != NULL && wcschr(contentTypeW, '/')) - mimeType = xwcsdup(contentTypeW); - else if (!(mimeType = get_special_mime_type(extensionW))) - mimeType = heap_wprintf(L"application/x-wine-extension-%s", &extensionW[1]); - - /* GNOME seems to ignore the <icon> tag in MIME packages, - * and the default name is more intuitive anyway. - */ - if (iconW) + if (mimeType == NULL) { - WCHAR *flattened_mime = slashes_to_minuses(mimeType); - int index = 0; - WCHAR *comma = wcsrchr(iconW, ','); - if (comma) + if (contentTypeW != NULL && wcschr(contentTypeW, '/')) + mimeType = xwcsdup(contentTypeW); + else if (!(mimeType = get_special_mime_type(winTypeW))) + mimeType = heap_wprintf(L"application/x-wine-extension-%s", &winTypeW[1]); + + /* GNOME seems to ignore the <icon> tag in MIME packages, + * and the default name is more intuitive anyway. + */ + if (iconW) { - *comma = 0; - index = wcstol(comma + 1, NULL, 10); + WCHAR *flattened_mime = slashes_to_minuses(mimeType); + int index = 0; + WCHAR *comma = wcsrchr(iconW, ','); + if (comma) + { + *comma = 0; + index = wcstol(comma + 1, NULL, 10); + } + extract_icon(iconW, index, flattened_mime, FALSE); + heap_free(flattened_mime); } - extract_icon(iconW, index, flattened_mime, FALSE); - heap_free(flattened_mime); + + write_freedesktop_mime_type_entry(packages_dir, winTypeW, mimeType, friendlyDocNameW); + hasChanged = TRUE; }
- write_freedesktop_mime_type_entry(packages_dir, extensionW, mimeType, friendlyDocNameW); - hasChanged = TRUE; + progIdW = reg_get_valW(HKEY_CLASSES_ROOT, winTypeW, NULL); + if (!progIdW) 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_wprintf(L"%s=>%s", mimeType, progIdW); + if (wine_rb_get(&mimeProgidTree, mimeProgId)) + { + heap_free(mimeProgId); + goto end; + } + entry = xmalloc(sizeof(struct rb_string_entry)); + 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, L"open"); + executableW = assoc_query(ASSOCSTR_EXECUTABLE, winTypeW, L"open"); if (executableW) openWithIcon = compute_native_identifier(0, executableW, NULL);
- friendlyAppName = assoc_query(ASSOCSTR_FRIENDLYAPPNAME, extensionW, L"open"); + friendlyAppName = assoc_query(ASSOCSTR_FRIENDLYAPPNAME, winTypeW, L"open"); if (!friendlyAppName) friendlyAppName = L"A Wine application";
- progIdW = reg_get_valW(HKEY_CLASSES_ROOT, extensionW, NULL); - if (!progIdW) 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_wprintf(L"%s=>%s", mimeType, progIdW); - if (wine_rb_get(&mimeProgidTree, mimeProgId)) + if (has_association_changed(winTypeW, mimeType, progIdW, friendlyAppName, openWithIcon)) { - heap_free(mimeProgId); - goto end; - } - entry = xmalloc(sizeof(struct rb_string_entry)); - 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, mimeType, progIdW, friendlyAppName, openWithIcon)) - { - WCHAR *desktopPath = heap_wprintf(L"%s\wine-extension-%s.desktop", - applications_dir, extensionW + 1 ); + WCHAR *desktopPath; + if (isProtocolType) + desktopPath = heap_wprintf(L"%s\wine-protocol-%s.desktop", applications_dir, winTypeW); + else + desktopPath = heap_wprintf(L"%s\wine-extension-%s.desktop", applications_dir, winTypeW + 1); if (write_freedesktop_association_entry(desktopPath, friendlyAppName, mimeType, progIdW, openWithIcon)) { hasChanged = TRUE; - update_association(extensionW, mimeType, progIdW, friendlyAppName, desktopPath, openWithIcon); + update_association(winTypeW, mimeType, progIdW, friendlyAppName, desktopPath, openWithIcon); } heap_free(desktopPath); } @@ -2191,7 +2219,7 @@ static BOOL generate_associations(const WCHAR *packages_dir, const WCHAR *applic heap_free(mimeType); heap_free(progIdW); } - heap_free(extensionW); + heap_free(winTypeW); }
wine_rb_destroy(&mimeProgidTree, winemenubuilder_rb_destroy, NULL);
From: Alex Henrie alexhenrie24@gmail.com
--- programs/winecfg/winecfg.rc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/programs/winecfg/winecfg.rc b/programs/winecfg/winecfg.rc index b2b51ffbf70..48fe0b9f9f0 100644 --- a/programs/winecfg/winecfg.rc +++ b/programs/winecfg/winecfg.rc @@ -307,7 +307,7 @@ BEGIN CONTROL "",IDC_SYSPARAM_SIZE_UD,UPDOWN_CLASSA,UDS_SETBUDDYINT | UDS_ALIGNRIGHT | WS_DISABLED, 185,75,15,13
GROUPBOX "MIME types",IDC_STATIC,8,95,244,23 - CONTROL "Manage file &associations",IDC_ENABLE_FILE_ASSOCIATIONS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,15,105,230,10 + CONTROL "Manage file and protocol &associations",IDC_ENABLE_FILE_ASSOCIATIONS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,15,105,230,10
PUSHBUTTON "&Font...",IDC_SYSPARAM_FONT,190,75,55,13,WS_DISABLED GROUPBOX "Folders",IDC_STATIC,8,120,244,94
On Sun May 7 21:56:46 2023 +0000, Zebediah Figura wrote:
I agree that Wine shouldn't advertise `file:` URI handlers to the
desktop environment, because Windows programs can't use Unix file paths. I just pushed a new patch that adds the `file` "protocol" to the blacklist. We may not want to translate protocol handlers for file: for other reasons, but it's worth pointing out that Wine actually does allow using Unix paths. You can try it yourself by opening cmd and running `explorer /some/unix/path/`. [Note that this translation isn't specific to cmd or anything; it's done at the ntdll level.]
That's really interesting, I didn't know that Wine could do that. I tried it and `explorer file:///some/unix/path/` works too.
However, as you alluded to, there is a bigger reason why we don't want desktop integration for file URIs: Associating a program with the file "protocol" is like associating it with all file types, which would be obnoxious and lend itself to the same kinds of abuse as associating a program with .com, .exe, or .msi. (Incidentally, desktop integration for third-party associations with .bat really shouldn't be allowed either.)
I've pushed a new patch that changes the comment in is_type_banned to explain the above reasoning for prohibiting desktop integration for file URI associations. Please let me know if you have any further concerns.
On Mon May 8 04:35:44 2023 +0000, Alex Henrie wrote:
That's really interesting, I didn't know that Wine could do that. I tried it and `explorer file:///some/unix/path/` works too. However, as you alluded to, there is a bigger reason why we don't want desktop integration for file URIs: Associating a program with the file "protocol" is like associating it with all file types, which would be obnoxious and lend itself to the same kinds of abuse as associating a program with .com, .exe, or .msi. (Incidentally, desktop integration for third-party associations with .bat really shouldn't be allowed either.) I've pushed a new patch that changes the comment in is_type_banned to explain the above reasoning for prohibiting desktop integration for file URI associations. Please let me know if you have any further concerns.
The `file:` protocol should be handled by the already existing `wine-extension-%s.desktop` files.
Could protocol and file handling be in separate check boxes? Or is that WIP and will be in a wine MR in the future?
Using `HKCU\Software\Wine\ProtocolAssociations\Enable` could be an alternative too.
On Sat Jun 10 19:13:53 2023 +0000, Loïc Rebmeister wrote:
Could protocol and file handling be in separate check boxes? Or is that WIP and will be in a wine MR in the future? Using `HKCU\Software\Wine\ProtocolAssociations\Enable` could be an alternative too.
Perhaps we should get this patch into Wine Staging and see if it annoys people in practice before giving protocol associations special treatment.
On Sat Jun 10 19:13:53 2023 +0000, Alex Henrie wrote:
Perhaps we should get this patch into Wine Staging and see if it annoys people in practice before giving protocol associations special treatment.
I think wine-staging is the way to go here. I think the community feedback could help a lot with improving this patch. Especially because of edge cases.
On Sun Jun 11 23:49:45 2023 +0000, Loïc Rebmeister wrote:
I think wine-staging is the way to go here. I think the community feedback could help a lot with improving this patch. Especially because of edge cases.
Possibly, but I will warn that we don't really get community feedback. E.g. when Alex's winemenubuilder patches were in wine-staging, I don't recall seeing any comments about them being a good or bad thing. Perhaps there's a ground that someone can keep an ear to, but I don't know of it.
On Mon Jun 12 00:32:23 2023 +0000, Zebediah Figura wrote:
Possibly, but I will warn that we don't really get community feedback. E.g. when Alex's winemenubuilder patches were in wine-staging, I don't recall seeing any comments about them being a good or bad thing. Perhaps there's a ground that someone can keep an ear to, but I don't know of it.
After the patch has been in Staging for a while, I could ask for feedback on the [WineHQ Forums](https://forum.winehq.org/). It would also be interesting to just google it and see if there are any blogs or forum posts out there that comment on the feature, or to just ask people in your local Linux user community, if you have one. (I can do that because I am fortunate enough to know people locally who use Wine.)
On Mon Jun 12 00:49:31 2023 +0000, Alex Henrie wrote:
After the patch has been in Staging for a while, I could ask for feedback on the [WineHQ Forums](https://forum.winehq.org/). It would also be interesting to just google it and see if there are any blogs or forum posts out there that comment on the feature, or to just ask people in your local Linux user community, if you have one. (I can do that because I am fortunate enough to know people locally who use Wine.)
If you want to talk to more peoples you can go on wine-tkg and linux gaming dev Discords WineTkg Discord: https://discord.gg/jRy3Nxk Linux Gaming Dev Discord: https://discord.gg/linuxgamingdev I'll share this patch there to try getting more feedback!
On Mon Jun 12 11:08:48 2023 +0000, Loïc Rebmeister wrote:
If you want to talk to more peoples you can go on wine-tkg and linux gaming dev Discords WineTkg Discord: https://discord.gg/jRy3Nxk Linux Gaming Dev Discord: https://discord.gg/linuxgamingdev I'll share this patch there to try getting more feedback!
I'm not sure that a community focused on gaming is going to be a good place to get commentary on this kind of functionality.