[MPR] Import Wine commit: 9988bb5e0729178b527052803d3ad670e5e0b46e
[reactos.git] / dll / win32 / mpr / wnet.c
index fc701b6..6c9d7cd 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright 1999 Ulrich Weigand
  * Copyright 2004 Juan Lang
  * Copyright 2007 Maarten Lankhorst
- * Copyright 2016 Pierre Schweitzer
+ * Copyright 2016-2018 Pierre Schweitzer
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
-#include "precomp.h"
-
-#include <winioctl.h>
-#include <npapi.h>
+#include <stdarg.h>
+#include "windef.h"
+#include "winbase.h"
+#include "winnls.h"
+#include "winioctl.h"
+#include "winnetwk.h"
+#include "npapi.h"
+#include "winreg.h"
+#include "winuser.h"
 #define WINE_MOUNTMGR_EXTENSIONS
-#include <ddk/mountmgr.h>
-#include <wine/unicode.h>
+#include "ddk/mountmgr.h"
+#include "wine/debug.h"
+#include "wine/unicode.h"
+#include "mprres.h"
+#include "wnetpriv.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(mpr);
 
 /* Data structures representing network service providers.  Assumes only one
  * thread creates them, and that they are constant for the life of the process
@@ -63,15 +73,14 @@ typedef struct _WNetProviderTable
     WNetProvider     table[1];
 } WNetProviderTable, *PWNetProviderTable;
 
-#define WNET_ENUMERATOR_TYPE_NULL      0
-#define WNET_ENUMERATOR_TYPE_GLOBAL    1
-#define WNET_ENUMERATOR_TYPE_PROVIDER  2
-#define WNET_ENUMERATOR_TYPE_CONTEXT   3
-#define WNET_ENUMERATOR_TYPE_CONNECTED 4
+#define WNET_ENUMERATOR_TYPE_GLOBAL     0
+#define WNET_ENUMERATOR_TYPE_PROVIDER   1
+#define WNET_ENUMERATOR_TYPE_CONTEXT    2
+#define WNET_ENUMERATOR_TYPE_CONNECTED  3
+#define WNET_ENUMERATOR_TYPE_REMEMBERED 4
 
 /* An WNet enumerator.  Note that the type doesn't correspond to the scope of
  * the enumeration; it represents one of the following types:
- * - a 'null' enumeration, one that contains no members
  * - a global enumeration, one that's executed across all providers
  * - a provider-specific enumeration, one that's only executed by a single
  *   provider
@@ -82,6 +91,8 @@ typedef struct _WNetProviderTable
  *   of the context scope results in a context type enumerator, which morphs
  *   into a global enumeration (so the enumeration continues across all
  *   providers).
+ * - a remembered enumeration, not related to providers themselves, but it
+ *   is a registry enumeration for saved connections
  */
 typedef struct _WNetEnumerator
 {
@@ -96,6 +107,11 @@ typedef struct _WNetEnumerator
     {
         NETRESOURCEW* net;
         HANDLE* handles;
+        struct
+        {
+            HKEY registry;
+            DWORD index;
+        } remembered;
     } specific;
 } WNetEnumerator, *PWNetEnumerator;
 
@@ -253,85 +269,6 @@ static void _tryLoadProvider(PCWSTR provider)
          debugstr_w(provider));
 }
 
-#ifdef __REACTOS__
-static void _restoreSavedConnection(HKEY connection, WCHAR * local)
-{
-    NETRESOURCEW net;
-    DWORD type, prov, index, size;
-
-    net.lpProvider = NULL;
-    net.lpRemoteName = NULL;
-    net.lpLocalName = NULL;
-
-    TRACE("Restoring: %S\n", local);
-
-    size = sizeof(DWORD);
-    if (RegQueryValueExW(connection, L"ConnectionType", NULL, &type, (BYTE *)&net.dwType, &size) != ERROR_SUCCESS)
-       return;
-
-    if (type != REG_DWORD || size != sizeof(DWORD))
-        return;
-
-    if (RegQueryValueExW(connection, L"ProviderName", NULL, &type, NULL, &size) != ERROR_SUCCESS)
-        return;
-
-    if (type != REG_SZ)
-        return;
-
-    net.lpProvider = HeapAlloc(GetProcessHeap(), 0, size);
-    if (!net.lpProvider)
-        return;
-
-    if (RegQueryValueExW(connection, L"ProviderName", NULL, NULL, (BYTE *)net.lpProvider, &size) != ERROR_SUCCESS)
-        goto cleanup;
-
-    size = sizeof(DWORD);
-    if (RegQueryValueExW(connection, L"ProviderType", NULL, &type, (BYTE *)&prov, &size) != ERROR_SUCCESS)
-        goto cleanup;
-
-    if (type != REG_DWORD || size != sizeof(DWORD))
-        goto cleanup;
-
-    index = _findProviderIndexW(net.lpProvider);
-    if (index == BAD_PROVIDER_INDEX)
-        goto cleanup;
-
-    if (providerTable->table[index].dwNetType != prov)
-        goto cleanup;
-
-    if (RegQueryValueExW(connection, L"RemotePath", NULL, &type, NULL, &size) != ERROR_SUCCESS)
-        goto cleanup;
-
-    if (type != REG_SZ)
-        goto cleanup;
-
-    net.lpRemoteName = HeapAlloc(GetProcessHeap(), 0, size);
-    if (!net.lpRemoteName)
-        goto cleanup;
-
-    if (RegQueryValueExW(connection, L"RemotePath", NULL, NULL, (BYTE *)net.lpRemoteName, &size) != ERROR_SUCCESS)
-        goto cleanup;
-
-    size = strlenW(local);
-    net.lpLocalName = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR) + 2 * sizeof(WCHAR));
-    if (!net.lpLocalName)
-        goto cleanup;
-
-    strcpyW(net.lpLocalName, local);
-    net.lpLocalName[size] = ':';
-    net.lpLocalName[size + 1] = 0;
-
-    TRACE("Attempting connection\n");
-
-    WNetAddConnection2W(&net, NULL, NULL, 0);
-
-cleanup:
-    HeapFree(GetProcessHeap(), 0, net.lpProvider);
-    HeapFree(GetProcessHeap(), 0, net.lpRemoteName);
-    HeapFree(GetProcessHeap(), 0, net.lpLocalName);
-}
-#endif
-
 void wnetInit(HINSTANCE hInstDll)
 {
     static const WCHAR providerOrderKey[] = { 'S','y','s','t','e','m','\\',
@@ -410,64 +347,6 @@ void wnetInit(HINSTANCE hInstDll)
         }
         RegCloseKey(hKey);
     }
-
-#ifdef __REACTOS__
-    if (providerTable)
-    {
-        HKEY user_profile;
-
-        if (RegOpenCurrentUser(KEY_ALL_ACCESS, &user_profile) == ERROR_SUCCESS)
-        {
-            HKEY network;
-            WCHAR subkey[8] = {'N', 'e', 't', 'w', 'o', 'r', 'k', 0};
-
-            if (RegOpenKeyExW(user_profile, subkey, 0, KEY_READ, &network) == ERROR_SUCCESS)
-            {
-                DWORD size, max;
-
-                TRACE("Enumerating remembered connections\n");
-
-                if (RegQueryInfoKey(network, NULL, NULL, NULL, &max, &size, NULL, NULL, NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
-                {
-                    WCHAR *local;
-
-                    TRACE("There are %lu connections\n", max);
-
-                    local = HeapAlloc(GetProcessHeap(), 0, (size + 1) * sizeof(WCHAR));
-                    if (local)
-                    {
-                        DWORD index;
-
-                        for (index = 0; index < max; ++index)
-                        {
-                            DWORD len = size + 1;
-                            HKEY connection;
-
-                            TRACE("Trying connection %lu\n", index);
-
-                            if (RegEnumKeyExW(network, index, local, &len, NULL, NULL, NULL, NULL) != ERROR_SUCCESS)
-                                continue;
-
-                            TRACE("It is %S\n", local);
-
-                            if (RegOpenKeyExW(network, local, 0, KEY_READ, &connection) != ERROR_SUCCESS)
-                                continue;
-
-                            _restoreSavedConnection(connection, local);
-                            RegCloseKey(connection);
-                        }
-
-                        HeapFree(GetProcessHeap(), 0, local);
-                    }
-                }
-
-                RegCloseKey(network);
-            }
-
-            RegCloseKey(user_profile);
-        }
-    }
-#endif
 }
 
 void wnetFree(void)
@@ -543,16 +422,6 @@ static void _freeEnumNetResource(LPNETRESOURCEW lpNet)
     }
 }
 
-static PWNetEnumerator _createNullEnumerator(void)
-{
-    PWNetEnumerator ret = HeapAlloc(GetProcessHeap(),
-     HEAP_ZERO_MEMORY, sizeof(WNetEnumerator));
-
-    if (ret)
-        ret->enumType = WNET_ENUMERATOR_TYPE_NULL;
-    return ret;
-}
-
 static PWNetEnumerator _createGlobalEnumeratorW(DWORD dwScope, DWORD dwType,
  DWORD dwUsage, LPNETRESOURCEW lpNet)
 {
@@ -629,6 +498,20 @@ static PWNetEnumerator _createConnectedEnumerator(DWORD dwScope, DWORD dwType,
     return ret;
 }
 
+static PWNetEnumerator _createRememberedEnumerator(DWORD dwScope, DWORD dwType,
+ HKEY remembered)
+{
+    PWNetEnumerator ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WNetEnumerator));
+    if (ret)
+    {
+        ret->enumType = WNET_ENUMERATOR_TYPE_REMEMBERED;
+        ret->dwScope = dwScope;
+        ret->dwType = dwType;
+        ret->specific.remembered.registry = remembered;
+    }
+    return ret;
+}
+
 /* Thunks the array of wide-string LPNETRESOURCEs lpNetArrayIn into buffer
  * lpBuffer, with size *lpBufferSize.  lpNetArrayIn contains *lpcCount entries
  * to start.  On return, *lpcCount reflects the number thunked into lpBuffer.
@@ -994,8 +877,23 @@ DWORD WINAPI WNetOpenEnumW( DWORD dwScope, DWORD dwType, DWORD dwUsage,
                 ret = *lphEnum ? WN_SUCCESS : WN_OUT_OF_MEMORY;
                 break;
             case RESOURCE_REMEMBERED:
-                *lphEnum = _createNullEnumerator();
-                ret = *lphEnum ? WN_SUCCESS : WN_OUT_OF_MEMORY;
+                {
+                    HKEY remembered, user_profile;
+
+                    ret = WN_OUT_OF_MEMORY;
+                    if (RegOpenCurrentUser(KEY_READ, &user_profile) == ERROR_SUCCESS)
+                    {
+                        WCHAR subkey[8] = {'N', 'e', 't', 'w', 'o', 'r', 'k', 0};
+
+                        if (RegOpenKeyExW(user_profile, subkey, 0, KEY_READ, &remembered) == ERROR_SUCCESS)
+                        {
+                            *lphEnum = _createRememberedEnumerator(dwScope, dwType, remembered);
+                            ret = *lphEnum ? WN_SUCCESS : WN_OUT_OF_MEMORY;
+                        }
+
+                        RegCloseKey(user_profile);
+                    }
+                }
                 break;
             default:
                 WARN("unknown scope 0x%08x\n", dwScope);
@@ -1502,6 +1400,162 @@ static DWORD _enumerateConnectedW(PWNetEnumerator enumerator, DWORD* user_count,
     return ret;
 }
 
+static const WCHAR connectionType[] = { 'C','o','n','n','e','c','t','i','o','n','T','y','p','e',0 };
+static const WCHAR providerName[] = { 'P','r','o','v','i','d','e','r','N','a','m','e',0 };
+static const WCHAR remotePath[] = { 'R','e','m','o','t','e','P','a','t','h',0 };
+
+static WCHAR *get_reg_str(HKEY hkey, const WCHAR *value, DWORD *len)
+{
+    DWORD type;
+    WCHAR *ret = NULL;
+
+    if (!RegQueryValueExW(hkey, value, NULL, &type, NULL, len) && type == REG_SZ)
+    {
+        if (!(ret = HeapAlloc(GetProcessHeap(), 0, *len))) return NULL;
+        RegQueryValueExW(hkey, value, 0, 0, (BYTE *)ret, len);
+    }
+
+    return ret;
+}
+
+static DWORD _enumeratorRememberedW(PWNetEnumerator enumerator, DWORD* user_count,
+                                    void* user_buffer, DWORD* user_size)
+{
+    HKEY registry, connection;
+    WCHAR buffer[255];
+    LONG size_left;
+    DWORD index, ret, type, len, size, registry_size, full_size = 0, total_count;
+    NETRESOURCEW * net_buffer = user_buffer;
+    WCHAR * str, * registry_string;
+
+    /* we will do the work in a single loop, so here is some things:
+     * we write netresource at the begin of the user buffer
+     * we write strings at the end of the user buffer
+     */
+    size_left = *user_size;
+    total_count = 0;
+    type = enumerator->dwType;
+    registry = enumerator->specific.remembered.registry;
+    str = (WCHAR *)((ULONG_PTR)user_buffer + *user_size - sizeof(WCHAR));
+    for (index = enumerator->specific.remembered.index; ; ++index)
+    {
+        enumerator->specific.remembered.index = index;
+
+        if (*user_count != -1 && total_count == *user_count)
+        {
+            ret = WN_SUCCESS;
+            break;
+        }
+
+        len = ARRAY_SIZE(buffer);
+        ret = RegEnumKeyExW(registry, index, buffer, &len, NULL, NULL, NULL, NULL);
+        if (ret != ERROR_SUCCESS)
+        {
+            if (ret == ERROR_NO_MORE_ITEMS) ret = WN_SUCCESS;
+            break;
+        }
+
+        if (RegOpenKeyExW(registry, buffer, 0, KEY_READ, &connection) != ERROR_SUCCESS)
+        {
+            continue;
+        }
+
+        full_size = sizeof(NETRESOURCEW);
+        size_left -= sizeof(NETRESOURCEW);
+
+        if (size_left > 0)
+        {
+            size = sizeof(DWORD);
+            RegQueryValueExW(connection, connectionType, NULL, NULL, (BYTE *)&net_buffer->dwType, &size);
+            if (type != RESOURCETYPE_ANY && net_buffer->dwType != type)
+            {
+                size_left += sizeof(NETRESOURCEW);
+                RegCloseKey(connection);
+                continue;
+            }
+
+            net_buffer->dwScope = RESOURCE_REMEMBERED;
+            net_buffer->dwDisplayType = RESOURCEDISPLAYTYPE_GENERIC;
+            net_buffer->dwUsage = RESOURCEUSAGE_CONNECTABLE;
+        }
+        else
+            ret = WN_MORE_DATA;
+
+        /* FIXME: this only supports drive letters */
+        full_size += 3 * sizeof(WCHAR);
+        size_left -= 3 * sizeof(WCHAR);
+        if (size_left > 0)
+        {
+            str -= 3;
+            str[0] = buffer[0];
+            str[1] = ':';
+            str[2] = 0;
+            net_buffer->lpLocalName = str;
+        }
+
+        registry_size = 0;
+        registry_string = get_reg_str(connection, providerName, &registry_size);
+        if (registry_string)
+        {
+            full_size += registry_size;
+            size_left -= registry_size;
+
+            if (size_left > 0)
+            {
+                str -= (registry_size / sizeof(WCHAR));
+                lstrcpyW(str, registry_string);
+                net_buffer->lpProvider = str;
+            }
+            else
+                ret = WN_MORE_DATA;
+
+            HeapFree(GetProcessHeap(), 0, registry_string);
+        }
+
+        registry_size = 0;
+        registry_string = get_reg_str(connection, remotePath, &registry_size);
+        if (registry_string)
+        {
+            full_size += registry_size;
+            size_left -= registry_size;
+
+            if (size_left > 0)
+            {
+                str -= (registry_size / sizeof(WCHAR));
+                lstrcpyW(str, registry_string);
+                net_buffer->lpRemoteName = str;
+            }
+            else
+                ret = WN_MORE_DATA;
+
+            HeapFree(GetProcessHeap(), 0, registry_string);
+        }
+
+        RegCloseKey(connection);
+
+        net_buffer->lpComment = NULL;
+
+        if (size_left < 0)
+            break;
+
+        ++total_count;
+        ++net_buffer;
+    }
+
+    if (total_count == 0)
+        ret = WN_NO_MORE_ENTRIES;
+
+    *user_count = total_count;
+
+    if (ret != WN_MORE_DATA && ret != WN_NO_MORE_ENTRIES)
+        ret = WN_SUCCESS;
+
+    if (ret == WN_MORE_DATA)
+        *user_size = *user_size + full_size;
+
+    return ret;
+}
+
 /*********************************************************************
  * WNetEnumResourceW [MPR.@]
  */
@@ -1531,9 +1585,6 @@ DWORD WINAPI WNetEnumResourceW( HANDLE hEnum, LPDWORD lpcCount,
 
         switch (enumerator->enumType)
         {
-            case WNET_ENUMERATOR_TYPE_NULL:
-                ret = WN_NO_MORE_ENTRIES;
-                break;
             case WNET_ENUMERATOR_TYPE_GLOBAL:
                 ret = _enumerateGlobalW(enumerator, lpcCount, lpBuffer,
                  lpBufferSize);
@@ -1550,6 +1601,10 @@ DWORD WINAPI WNetEnumResourceW( HANDLE hEnum, LPDWORD lpcCount,
                 ret = _enumerateConnectedW(enumerator, lpcCount, lpBuffer,
                  lpBufferSize);
                 break;
+            case WNET_ENUMERATOR_TYPE_REMEMBERED:
+                ret = _enumeratorRememberedW(enumerator, lpcCount, lpBuffer,
+                 lpBufferSize);
+                break;
             default:
                 WARN("bogus enumerator type!\n");
                 ret = WN_NO_NETWORK;
@@ -1577,9 +1632,6 @@ DWORD WINAPI WNetCloseEnum( HANDLE hEnum )
 
         switch (enumerator->enumType)
         {
-            case WNET_ENUMERATOR_TYPE_NULL:
-                ret = WN_SUCCESS;
-                break;
             case WNET_ENUMERATOR_TYPE_GLOBAL:
                 if (enumerator->specific.net)
                     _freeEnumNetResource(enumerator->specific.net);
@@ -1604,6 +1656,10 @@ DWORD WINAPI WNetCloseEnum( HANDLE hEnum )
                 HeapFree(GetProcessHeap(), 0, handles);
                 ret = WN_SUCCESS;
                 break;
+            case WNET_ENUMERATOR_TYPE_REMEMBERED:
+                RegCloseKey(enumerator->specific.remembered.registry);
+                ret = WN_SUCCESS;
+                break;
             default:
                 WARN("bogus enumerator type!\n");
                 ret = WN_BAD_HANDLE;
@@ -2577,7 +2633,7 @@ DWORD WINAPI WNetGetUniversalNameA ( LPCSTR lpLocalPath, DWORD dwInfoLevel,
         break;
     }
     case REMOTE_NAME_INFO_LEVEL:
-        err = WN_NO_NETWORK;
+        err = WN_NOT_CONNECTED;
         break;
 
     default:
@@ -2636,6 +2692,64 @@ DWORD WINAPI WNetGetUniversalNameW ( LPCWSTR lpLocalPath, DWORD dwInfoLevel,
     return err;
 }
 
+/*****************************************************************
+ * WNetClearConnections [MPR.@]
+ */
+DWORD WINAPI WNetClearConnections ( HWND owner )
+{
+    HANDLE connected;
+    PWSTR connection;
+    DWORD ret, size, count;
+    NETRESOURCEW * resources, * iter;
+
+    ret = WNetOpenEnumW(RESOURCE_CONNECTED, RESOURCETYPE_ANY, 0, NULL, &connected);
+    if (ret != WN_SUCCESS)
+    {
+        if (ret != WN_NO_NETWORK)
+        {
+            return ret;
+        }
+
+        /* Means no provider, then, clearing is OK */
+        return WN_SUCCESS;
+    }
+
+    size = 0x1000;
+    resources = HeapAlloc(GetProcessHeap(), 0, size);
+    if (!resources)
+    {
+        WNetCloseEnum(connected);
+        return WN_OUT_OF_MEMORY;
+    }
+
+    for (;;)
+    {
+        size = 0x1000;
+        count = -1;
+
+        memset(resources, 0, size);
+        ret = WNetEnumResourceW(connected, &count, resources, &size);
+        if (ret == WN_SUCCESS || ret == WN_MORE_DATA)
+        {
+            for (iter = resources; count; count--, iter++)
+            {
+                if (iter->lpLocalName && iter->lpLocalName[0])
+                    connection = iter->lpLocalName;
+                else
+                    connection = iter->lpRemoteName;
+
+                WNetCancelConnection2W(connection, 0, TRUE);
+            }
+        }
+        else
+            break;
+    }
+
+    HeapFree(GetProcessHeap(), 0, resources);
+    WNetCloseEnum(connected);
+
+    return ret;
+}
 
 
 /*