[WLAN-BRINGUP]
[reactos.git] / dll / win32 / urlmon / internet.c
index 3d41def..3832c52 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * Copyright 2005 Jacek Caban
+ * Copyright 2011 Thomas Mullaly for CodeWeavers
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
 
 WINE_DEFAULT_DEBUG_CHANNEL(urlmon);
 
+static const WCHAR feature_control_keyW[] =
+    {'S','o','f','t','w','a','r','e','\\',
+     'M','i','c','r','o','s','o','f','t','\\',
+     'I','n','t','e','r','n','e','t',' ','E','x','p','l','o','r','e','r','\\',
+     'M','a','i','n','\\',
+     'F','e','a','t','u','r','e','C','o','n','t','r','o','l',0};
+
+static const WCHAR feature_object_cachingW[] =
+    {'F','E','A','T','U','R','E','_','O','B','J','E','C','T','_','C','A','C','H','I','N','G',0};
+static const WCHAR feature_zone_elevationW[] =
+    {'F','E','A','T','U','R','E','_','Z','O','N','E','_','E','L','E','V','A','T','I','O','N',0};
+static const WCHAR feature_mime_handlingW[] =
+    {'F','E','A','T','U','R','E','_','M','I','M','E','_','H','A','N','D','L','I','N','G',0};
+static const WCHAR feature_mime_sniffingW[] =
+    {'F','E','A','T','U','R','E','_','M','I','M','E','_','S','N','I','F','F','I','N','G',0};
+static const WCHAR feature_window_restrictionsW[] =
+    {'F','E','A','T','U','R','E','_','W','I','N','D','O','W','_','R','E','S','T','R','I','C','T','I','O','N','S',0};
+static const WCHAR feature_weboc_popupmanagementW[] =
+    {'F','E','A','T','U','R','E','_','W','E','B','O','C','_','P','O','P','U','P','M','A','N','A','G','E','M','E','N','T',0};
+static const WCHAR feature_behaviorsW[] =
+    {'F','E','A','T','U','R','E','_','B','E','H','A','V','I','O','R','S',0};
+static const WCHAR feature_disable_mk_protocolW[] =
+    {'F','E','A','T','U','R','E','_','D','I','S','A','B','L','E','_','M','K','_','P','R','O','T','O','C','O','L',0};
+static const WCHAR feature_localmachine_lockdownW[] =
+    {'F','E','A','T','U','R','E','_','L','O','C','A','L','M','A','C','H','I','N','E','_','L','O','C','K','D','O','W','N',0};
+static const WCHAR feature_securitybandW[] =
+    {'F','E','A','T','U','R','E','_','S','E','C','U','R','I','T','Y','B','A','N','D',0};
+static const WCHAR feature_restrict_activexinstallW[] =
+    {'F','E','A','T','U','R','E','_','R','E','S','T','R','I','C','T','_','A','C','T','I','V','E','X','I','N','S','T','A','L','L',0};
+static const WCHAR feature_validate_navigate_urlW[] =
+    {'F','E','A','T','U','R','E','_','V','A','L','I','D','A','T','E','_','N','A','V','I','G','A','T','E','_','U','R','L',0};
+static const WCHAR feature_restrict_filedownloadW[] =
+    {'F','E','A','T','U','R','E','_','R','E','S','T','R','I','C','T','_','F','I','L','E','D','O','W','N','L','O','A','D',0};
+static const WCHAR feature_addon_managementW[] =
+    {'F','E','A','T','U','R','E','_','A','D','D','O','N','_','M','A','N','A','G','E','M','E','N','T',0};
+static const WCHAR feature_protocol_lockdownW[] =
+    {'F','E','A','T','U','R','E','_','P','R','O','T','O','C','O','L','_','L','O','C','K','D','O','W','N',0};
+static const WCHAR feature_http_username_password_disableW[] =
+    {'F','E','A','T','U','R','E','_','H','T','T','P','_','U','S','E','R','N','A','M','E','_',
+     'P','A','S','S','W','O','R','D','_','D','I','S','A','B','L','E',0};
+static const WCHAR feature_safe_bindtoobjectW[] =
+    {'F','E','A','T','U','R','E','_','S','A','F','E','_','B','I','N','D','T','O','O','B','J','E','C','T',0};
+static const WCHAR feature_unc_savedfilecheckW[] =
+    {'F','E','A','T','U','R','E','_','U','N','C','_','S','A','V','E','D','F','I','L','E','C','H','E','C','K',0};
+static const WCHAR feature_get_url_dom_filepath_unencodedW[] =
+    {'F','E','A','T','U','R','E','_','G','E','T','_','U','R','L','_','D','O','M','_',
+     'F','I','L','E','P','A','T','H','_','U','N','E','N','C','O','D','E','D',0};
+static const WCHAR feature_tabbed_browsingW[] =
+    {'F','E','A','T','U','R','E','_','T','A','B','B','E','D','_','B','R','O','W','S','I','N','G',0};
+static const WCHAR feature_ssluxW[] =
+    {'F','E','A','T','U','R','E','_','S','S','L','U','X',0};
+static const WCHAR feature_disable_navigation_soundsW[] =
+    {'F','E','A','T','U','R','E','_','D','I','S','A','B','L','E','_','N','A','V','I','G','A','T','I','O','N','_',
+     'S','O','U','N','D','S',0};
+static const WCHAR feature_disable_legacy_compressionW[] =
+    {'F','E','A','T','U','R','E','_','D','I','S','A','B','L','E','_','L','E','G','A','C','Y','_',
+     'C','O','M','P','R','E','S','S','I','O','N',0};
+static const WCHAR feature_force_addr_and_statusW[] =
+    {'F','E','A','T','U','R','E','_','F','O','R','C','E','_','A','D','D','R','_','A','N','D','_',
+     'S','T','A','T','U','S',0};
+static const WCHAR feature_xmlhttpW[] =
+    {'F','E','A','T','U','R','E','_','X','M','L','H','T','T','P',0};
+static const WCHAR feature_disable_telnet_protocolW[] =
+    {'F','E','A','T','U','R','E','_','D','I','S','A','B','L','E','_','T','E','L','N','E','T','_',
+     'P','R','O','T','O','C','O','L',0};
+static const WCHAR feature_feedsW[] =
+    {'F','E','A','T','U','R','E','_','F','E','E','D','S',0};
+static const WCHAR feature_block_input_promptsW[] =
+    {'F','E','A','T','U','R','E','_','B','L','O','C','K','_','I','N','P','U','T','_','P','R','O','M','P','T','S',0};
+
+static CRITICAL_SECTION process_features_cs;
+static CRITICAL_SECTION_DEBUG process_features_cs_dbg =
+{
+    0, 0, &process_features_cs,
+    { &process_features_cs_dbg.ProcessLocksList, &process_features_cs_dbg.ProcessLocksList },
+      0, 0, { (DWORD_PTR)(__FILE__ ": process features") }
+};
+static CRITICAL_SECTION process_features_cs = { &process_features_cs_dbg, -1, 0, 0, 0, 0 };
+
+typedef struct feature_control {
+    LPCWSTR feature_name;
+    BOOL    enabled;
+    BOOL    check_registry;
+} feature_control;
+
+/* IMPORTANT!!!
+ *
+ * This array is indexed using INTERNETFEATURELIST values, so everything must
+ * appear in the same order as it does in INTERNETFEATURELIST.
+ */
+static feature_control process_feature_controls[FEATURE_ENTRY_COUNT] = {
+    {feature_object_cachingW,                   TRUE ,TRUE},
+    {feature_zone_elevationW,                   FALSE,TRUE},
+    {feature_mime_handlingW,                    FALSE,TRUE},
+    {feature_mime_sniffingW,                    FALSE,TRUE},
+    {feature_window_restrictionsW,              FALSE,TRUE},
+    {feature_weboc_popupmanagementW,            FALSE,TRUE},
+    {feature_behaviorsW,                        TRUE ,TRUE},
+    {feature_disable_mk_protocolW,              TRUE ,TRUE},
+    {feature_localmachine_lockdownW,            FALSE,TRUE},
+    {feature_securitybandW,                     FALSE,TRUE},
+    {feature_restrict_activexinstallW,          FALSE,TRUE},
+    {feature_validate_navigate_urlW,            FALSE,TRUE},
+    {feature_restrict_filedownloadW,            FALSE,TRUE},
+    {feature_addon_managementW,                 FALSE,TRUE},
+    {feature_protocol_lockdownW,                FALSE,TRUE},
+    {feature_http_username_password_disableW,   FALSE,TRUE},
+    {feature_safe_bindtoobjectW,                FALSE,TRUE},
+    {feature_unc_savedfilecheckW,               FALSE,TRUE},
+    {feature_get_url_dom_filepath_unencodedW,   TRUE ,TRUE},
+    {feature_tabbed_browsingW,                  FALSE,TRUE},
+    {feature_ssluxW,                            FALSE,TRUE},
+    {feature_disable_navigation_soundsW,        FALSE,TRUE},
+    {feature_disable_legacy_compressionW,       TRUE ,TRUE},
+    {feature_force_addr_and_statusW,            FALSE,TRUE},
+    {feature_xmlhttpW,                          TRUE ,TRUE},
+    {feature_disable_telnet_protocolW,          FALSE,TRUE},
+    {feature_feedsW,                            FALSE,TRUE},
+    {feature_block_input_promptsW,              FALSE,TRUE}
+};
+
 static HRESULT parse_schema(LPCWSTR url, DWORD flags, LPWSTR result, DWORD size, DWORD *rsize)
 {
     WCHAR *ptr;
@@ -397,20 +519,182 @@ HRESULT WINAPI CoInternetQueryInfo(LPCWSTR pwzUrl, QUERYOPTION QueryOption,
     return S_OK;
 }
 
+static void set_feature_on_process(INTERNETFEATURELIST feature, BOOL enable)
+{
+    EnterCriticalSection(&process_features_cs);
+
+    process_feature_controls[feature].enabled = enable;
+    process_feature_controls[feature].check_registry = FALSE;
+
+    LeaveCriticalSection(&process_features_cs);
+}
+
+static HRESULT set_internet_feature(INTERNETFEATURELIST feature, DWORD flags, BOOL enable)
+{
+    const DWORD supported_flags = SET_FEATURE_ON_PROCESS;
+
+    if(feature >= FEATURE_ENTRY_COUNT)
+        return E_FAIL;
+
+    if(flags & ~supported_flags) {
+        FIXME("Unsupported flags: %08x\n", flags & ~supported_flags);
+        return E_NOTIMPL;
+    }
+
+    if(flags & SET_FEATURE_ON_PROCESS)
+        set_feature_on_process(feature, enable);
+
+    return S_OK;
+}
+
+static BOOL get_feature_from_reg(HKEY feature_control, LPCWSTR feature_name, LPCWSTR process_name, BOOL *enabled)
+{
+    BOOL ret = FALSE;
+    HKEY feature;
+    DWORD res;
+
+    static const WCHAR wildcardW[] = {'*',0};
+
+    res = RegOpenKeyW(feature_control, feature_name, &feature);
+    if(res == ERROR_SUCCESS) {
+        DWORD type, value, size;
+
+        size = sizeof(DWORD);
+        res = RegQueryValueExW(feature, process_name, NULL, &type, (BYTE*)&value, &size);
+        if(type != REG_DWORD)
+            WARN("Unexpected registry value type %d (expected REG_DWORD) for %s\n", type, debugstr_w(process_name));
+
+        if(res == ERROR_SUCCESS && type == REG_DWORD) {
+            *enabled = value == 1;
+            ret = TRUE;
+        } else {
+            size = sizeof(DWORD);
+            res = RegQueryValueExW(feature, wildcardW, NULL, &type, (BYTE*)&value, &size);
+            if(type != REG_DWORD)
+                WARN("Unexpected registry value type %d (expected REG_DWORD) for %s\n", type, debugstr_w(wildcardW));
+
+            if(res == ERROR_SUCCESS && type == REG_DWORD) {
+                *enabled = value == 1;
+                ret = TRUE;
+            }
+        }
+        RegCloseKey(feature);
+    }
+
+    return ret;
+}
+
+/* Assumes 'process_features_cs' is held. */
+static HRESULT load_process_feature(INTERNETFEATURELIST feature)
+{
+    DWORD res;
+    HKEY feature_control;
+    WCHAR module_name[MAX_PATH];
+    LPCWSTR process_name, feature_name;
+    HRESULT hres = S_FALSE;
+    BOOL check_hklm = FALSE;
+    BOOL enabled;
+
+    if (!GetModuleFileNameW(NULL, module_name, sizeof(module_name)/sizeof(WCHAR))) {
+        ERR("Failed to get module file name: %u\n", GetLastError());
+        return E_UNEXPECTED;
+    }
+
+    process_name = strrchrW(module_name, '\\');
+    if(!process_name) {
+        ERR("Invalid module file name: %s\n", debugstr_w(module_name));
+        return E_UNEXPECTED;
+    }
+
+    /* Skip past the '\\' in front of the filename. */
+    ++process_name;
+
+    feature_name = process_feature_controls[feature].feature_name;
+
+    res = RegOpenKeyW(HKEY_CURRENT_USER, feature_control_keyW, &feature_control);
+    if(res == ERROR_SUCCESS) {
+        if(get_feature_from_reg(feature_control, feature_name, process_name, &enabled)) {
+            hres = enabled ? S_OK : S_FALSE;
+            process_feature_controls[feature].enabled = enabled;
+        } else
+            /* We didn't find anything in HKCU, so check HKLM. */
+            check_hklm = TRUE;
+
+        RegCloseKey(feature_control);
+    }
+
+    if(check_hklm) {
+        res = RegOpenKeyW(HKEY_LOCAL_MACHINE, feature_control_keyW, &feature_control);
+        if(res == ERROR_SUCCESS) {
+            if(get_feature_from_reg(feature_control, feature_name, process_name, &enabled)) {
+                hres = enabled ? S_OK : S_FALSE;
+                process_feature_controls[feature].enabled = enabled;
+            }
+            RegCloseKey(feature_control);
+        }
+    }
+
+    /* Don't bother checking the registry again for this feature. */
+    process_feature_controls[feature].check_registry = FALSE;
+
+    return hres;
+}
+
+static HRESULT get_feature_from_process(INTERNETFEATURELIST feature)
+{
+    HRESULT hres;
+
+    EnterCriticalSection(&process_features_cs);
+
+    /* Try loading the feature from the registry, if it hasn't already
+     * been done.
+     */
+    if(process_feature_controls[feature].check_registry) {
+        hres = load_process_feature(feature);
+        if(FAILED(hres)) {
+            LeaveCriticalSection(&process_features_cs);
+            return hres;
+        }
+    }
+
+    hres = process_feature_controls[feature].enabled ? S_OK : S_FALSE;
+
+    LeaveCriticalSection(&process_features_cs);
+
+    return hres;
+}
+
+static HRESULT get_internet_feature(INTERNETFEATURELIST feature, DWORD flags)
+{
+    HRESULT hres;
+
+    if(feature >= FEATURE_ENTRY_COUNT)
+        return E_FAIL;
+
+    if(flags == GET_FEATURE_FROM_PROCESS)
+        hres = get_feature_from_process(feature);
+    else {
+        FIXME("Unsupported flags: %08x\n", flags);
+        hres = E_NOTIMPL;
+    }
+
+    return hres;
+}
+
 /***********************************************************************
  *             CoInternetSetFeatureEnabled (URLMON.@)
  */
-HRESULT WINAPI CoInternetSetFeatureEnabled(INTERNETFEATURELIST feature, DWORD flags, BOOL enable)
+HRESULT WINAPI CoInternetSetFeatureEnabled(INTERNETFEATURELIST FeatureEntry, DWORD dwFlags, BOOL fEnable)
 {
-    FIXME("%d, 0x%08x, %x, stub\n", feature, flags, enable);
-    return E_NOTIMPL;
+    TRACE("(%d, %08x, %x)\n", FeatureEntry, dwFlags, fEnable);
+    return set_internet_feature(FeatureEntry, dwFlags, fEnable);
 }
 
 /***********************************************************************
  *             CoInternetIsFeatureEnabled (URLMON.@)
  */
-HRESULT WINAPI CoInternetIsFeatureEnabled(INTERNETFEATURELIST feature, DWORD flags)
+HRESULT WINAPI CoInternetIsFeatureEnabled(INTERNETFEATURELIST FeatureEntry, DWORD dwFlags)
 {
-    FIXME("%d, 0x%08x, stub\n", feature, flags);
-    return E_NOTIMPL;
+    TRACE("(%d, %08x)\n", FeatureEntry, dwFlags);
+    return get_internet_feature(FeatureEntry, dwFlags);
 }