[PATCH 2/2] winemenubuilder: Create .desktop files for programs that open URIs

Alex Henrie alexhenrie24 at gmail.com
Mon Mar 2 00:51:07 CST 2020


Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=22904
Signed-off-by: Alex Henrie <alexhenrie24 at gmail.com>
---
 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 e963b4e0f3..bd5763ace1 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 <icon> 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 <icon> 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.25.1




More information about the wine-devel mailing list