connections.c 10.8 KB
Newer Older
1
/*
2
 * Copyright 2018 Piotr Caban for CodeWeavers
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
 *
 */

#include <stdarg.h>
#include <windef.h>
#include <winbase.h>
23
#include <winnls.h>
24 25 26 27 28 29
#include <wininet.h>
#include <winuser.h>
#include <winreg.h>

#include "inetcpl.h"
#include "wine/debug.h"
30
#include "wine/heap.h"
31 32 33

WINE_DEFAULT_DEBUG_CHANNEL(inetcpl);

34
static const WCHAR internet_settings[] = L"Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings";
35 36 37

static BOOL initdialog_done;

38
#define CONNECTION_SETTINGS_VERSION 0x46
39 40 41
#define CONNECTION_SETTINGS_MANUAL_PROXY 0x2
#define CONNECTION_SETTINGS_PAC_SCRIPT 0x4
#define CONNECTION_SETTINGS_WPAD 0x8
42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57

typedef struct {
    DWORD version;
    DWORD id;
    DWORD flags;
    BYTE data[1];
    /* DWORD proxy_server_len; */
    /* UTF8 proxy_server[proxy_server_len]; */
    /* DWORD bypass_list_len; */
    /* UTF8 bypass_list[bypass_list_len]; */
    /* DWORD configuration_script_len; */
    /* UTF8 configuration_script[configuration_script_len]; */
    /* DWORD unk[8]; set to 0 */
} connection_settings;

static DWORD create_connection_settings(BOOL manual_proxy, const WCHAR *proxy_server,
58
        BOOL use_wpad, BOOL use_pac_script, const WCHAR *pac_url, connection_settings **ret)
59 60 61
{
    DWORD size = FIELD_OFFSET(connection_settings, data), pos;
    DWORD proxy_server_len;
62
    DWORD pac_url_len;
63 64

    size += sizeof(DWORD);
65
    if(L"ProxyServer")
66 67 68 69 70 71 72 73 74
    {
        proxy_server_len = WideCharToMultiByte(CP_UTF8, 0, proxy_server, -1,
                NULL, 0, NULL, NULL);
        if(!proxy_server_len) return 0;
        proxy_server_len--;
    }
    else
        proxy_server_len = 0;
    size += proxy_server_len;
75 76 77 78 79 80 81 82 83
    if(pac_url)
    {
        pac_url_len = WideCharToMultiByte(CP_UTF8, 0, pac_url, -1,
                NULL, 0, NULL, NULL);
        if(!pac_url_len) return 0;
        pac_url_len--;
    }
    else
        pac_url_len = 0;
84 85 86 87 88 89 90
    size += sizeof(DWORD)*10;

    *ret = heap_alloc_zero(size);
    if(!*ret) return 0;

    (*ret)->version = CONNECTION_SETTINGS_VERSION;
    (*ret)->flags = 1;
91 92 93
    if(manual_proxy) (*ret)->flags |= CONNECTION_SETTINGS_MANUAL_PROXY;
    if(use_pac_script) (*ret)->flags |= CONNECTION_SETTINGS_PAC_SCRIPT;
    if(use_wpad) (*ret)->flags |= CONNECTION_SETTINGS_WPAD;
94 95 96 97 98 99 100 101
    ((DWORD*)(*ret)->data)[0] = proxy_server_len;
    pos = sizeof(DWORD);
    if(proxy_server_len)
    {
        WideCharToMultiByte(CP_UTF8, 0, proxy_server, -1,
                (char*)(*ret)->data+pos, proxy_server_len, NULL, NULL);
        pos += proxy_server_len;
    }
102 103 104 105 106 107 108 109 110
    pos += sizeof(DWORD); /* skip proxy bypass list */
    ((DWORD*)((*ret)->data+pos))[0] = pac_url_len;
    pos += sizeof(DWORD);
    if(pac_url_len)
    {
        WideCharToMultiByte(CP_UTF8, 0, pac_url, -1,
                (char*)(*ret)->data+pos, pac_url_len, NULL, NULL);
        pos += pac_url_len;
    }
111 112 113
    return size;
}

114 115 116 117
static void connections_on_initdialog(HWND hwnd)
{
    DWORD type, size, enabled;
    WCHAR address[INTERNET_MAX_URL_LENGTH], *port;
118 119
    WCHAR pac_url[INTERNET_MAX_URL_LENGTH];
    HKEY hkey, con;
120 121
    LONG res;

122 123
    SendMessageW(GetDlgItem(hwnd, IDC_EDIT_PAC_SCRIPT),
            EM_LIMITTEXT, INTERNET_MAX_URL_LENGTH, 0);
124 125 126 127 128 129 130 131 132
    SendMessageW(GetDlgItem(hwnd, IDC_EDIT_PROXY_SERVER),
            EM_LIMITTEXT, INTERNET_MAX_URL_LENGTH-10, 0);
    SendMessageW(GetDlgItem(hwnd, IDC_EDIT_PROXY_PORT), EM_LIMITTEXT, 8, 0);

    res = RegOpenKeyW(HKEY_CURRENT_USER, internet_settings, &hkey);
    if(res)
        return;

    size = sizeof(enabled);
133
    res = RegQueryValueExW(hkey, L"ProxyEnable", NULL, &type, (BYTE*)&enabled, &size);
134 135 136
    if(res || type != REG_DWORD)
        enabled = 0;
    size = sizeof(address);
137
    res = RegQueryValueExW(hkey, L"ProxyServer", NULL, &type, (BYTE*)address, &size);
138 139
    if(res || type != REG_SZ)
        address[0] = 0;
140
    size = sizeof(pac_url);
141
    res = RegQueryValueExW(hkey, L"AutoConfigURL", NULL, &type, (BYTE*)pac_url, &size);
142 143 144
    if(res || type != REG_SZ)
        pac_url[0] = 0;

145
    res = RegOpenKeyW(hkey, L"Connections", &con);
146
    RegCloseKey(hkey);
147 148 149 150 151
    if(!res)
    {
        connection_settings *settings = NULL;
        size = 0;

152
        while((res = RegQueryValueExW(con, L"DefaultConnectionSettings", NULL, &type,
153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174
                        (BYTE*)settings, &size)) == ERROR_MORE_DATA || !settings)
        {
            connection_settings *new_settings = heap_realloc(settings, size);
            if(!new_settings)
            {
                RegCloseKey(con);
                heap_free(settings);
                return;
            }
            settings = new_settings;
        }
        RegCloseKey(con);

        if(!res && type == REG_BINARY)
        {
            if(settings->version != CONNECTION_SETTINGS_VERSION)
                FIXME("unexpected structure version (%x)\n", settings->version);
            else if(settings->flags & CONNECTION_SETTINGS_WPAD)
                CheckDlgButton(hwnd, IDC_USE_WPAD, BST_CHECKED);
        }
        heap_free(settings);
    }
175 176 177

    TRACE("ProxyEnable = %x\n", enabled);
    TRACE("ProxyServer = %s\n", wine_dbgstr_w(address));
178
    TRACE("AutoConfigURL = %s\n", wine_dbgstr_w(pac_url));
179 180 181 182 183 184 185 186

    if(enabled)
    {
        CheckDlgButton(hwnd, IDC_USE_PROXY_SERVER, BST_CHECKED);
        EnableWindow(GetDlgItem(hwnd, IDC_EDIT_PROXY_SERVER), TRUE);
        EnableWindow(GetDlgItem(hwnd, IDC_EDIT_PROXY_PORT), TRUE);
    }

187
    port = wcschr(address, ':');
188 189 190 191 192 193 194 195 196
    if(port)
    {
        *port = 0;
        port++;
    }
    SetDlgItemTextW(hwnd, IDC_EDIT_PROXY_SERVER, address);
    if(port)
        SetDlgItemTextW(hwnd, IDC_EDIT_PROXY_PORT, port);

197 198 199 200 201 202 203
    if(pac_url[0])
    {
        CheckDlgButton(hwnd, IDC_USE_PAC_SCRIPT, BST_CHECKED);
        EnableWindow(GetDlgItem(hwnd, IDC_EDIT_PAC_SCRIPT), TRUE);
        SetDlgItemTextW(hwnd, IDC_EDIT_PAC_SCRIPT, pac_url);
    }

204 205 206 207 208 209 210 211 212
    return;
}

static INT_PTR connections_on_command(HWND hwnd, WPARAM wparam)
{
    BOOL checked;

    switch (wparam)
    {
213 214 215 216
        case IDC_USE_PAC_SCRIPT:
            checked = IsDlgButtonChecked(hwnd, IDC_USE_PAC_SCRIPT);
            EnableWindow(GetDlgItem(hwnd, IDC_EDIT_PAC_SCRIPT), checked);
            break;
217 218 219 220
        case IDC_USE_PROXY_SERVER:
            checked = IsDlgButtonChecked(hwnd, IDC_USE_PROXY_SERVER);
            EnableWindow(GetDlgItem(hwnd, IDC_EDIT_PROXY_SERVER), checked);
            EnableWindow(GetDlgItem(hwnd, IDC_EDIT_PROXY_PORT), checked);
221 222 223 224 225 226 227 228
    }

    switch (wparam)
    {
        case IDC_USE_WPAD:
        case IDC_USE_PAC_SCRIPT:
        case IDC_USE_PROXY_SERVER:
        case MAKEWPARAM(IDC_EDIT_PAC_SCRIPT, EN_CHANGE):
229 230 231 232 233 234 235 236 237 238 239 240
        case MAKEWPARAM(IDC_EDIT_PROXY_SERVER, EN_CHANGE):
        case MAKEWPARAM(IDC_EDIT_PROXY_PORT, EN_CHANGE):
            if(initdialog_done)
                SendMessageW(GetParent(hwnd), PSM_CHANGED, (WPARAM)hwnd, 0);
            return TRUE;
    }

    return FALSE;
}

static INT_PTR connections_on_notify(HWND hwnd, WPARAM wparam, LPARAM lparam)
{
241
    connection_settings *default_connection;
242 243
    WCHAR proxy[INTERNET_MAX_URL_LENGTH];
    WCHAR pac_script[INTERNET_MAX_URL_LENGTH];
244
    PSHNOTIFY *psn = (PSHNOTIFY*)lparam;
245 246
    DWORD proxy_len, port_len, pac_script_len;
    DWORD use_proxy, use_pac_script, use_wpad, size;
247
    LRESULT res;
248
    HKEY hkey, con;
249 250 251 252 253 254 255 256

    if(psn->hdr.code != PSN_APPLY)
        return FALSE;

    res = RegOpenKeyW(HKEY_CURRENT_USER, internet_settings, &hkey);
    if(res)
        return FALSE;

257
    use_proxy = IsDlgButtonChecked(hwnd, IDC_USE_PROXY_SERVER);
258
    res = RegSetValueExW(hkey, L"ProxyEnable", 0, REG_DWORD,
259
            (BYTE*)&use_proxy, sizeof(use_proxy));
260 261 262 263 264
    if(res)
    {
        RegCloseKey(hkey);
        return FALSE;
    }
265
    TRACE("ProxyEnable set to %x\n", use_proxy);
266

267
    proxy_len = GetDlgItemTextW(hwnd, IDC_EDIT_PROXY_SERVER, proxy, ARRAY_SIZE(proxy));
268
    if(proxy_len)
269
    {
270
        proxy[proxy_len++] = ':';
271 272
        port_len = GetDlgItemTextW(hwnd, IDC_EDIT_PROXY_PORT, proxy+proxy_len,
                ARRAY_SIZE(proxy)-proxy_len);
273 274
        if(!port_len)
        {
275 276 277
            proxy[proxy_len++] = '8';
            proxy[proxy_len++] = '0';
            proxy[proxy_len] = 0;
278 279
        }

280
        res = RegSetValueExW(hkey, L"ProxyServer", 0, REG_SZ,
281
                (BYTE*)proxy, (proxy_len+port_len)*sizeof(WCHAR));
282 283 284
    }
    else
    {
285
        res = RegDeleteValueW(hkey, L"ProxyServer");
286 287 288
        if(res == ERROR_FILE_NOT_FOUND)
            res = ERROR_SUCCESS;
    }
289 290 291 292 293
    if(res)
    {
        RegCloseKey(hkey);
        return FALSE;
    }
294 295 296 297
    TRACE("ProxtServer set to %s\n", wine_dbgstr_w(proxy));

    use_pac_script = IsDlgButtonChecked(hwnd, IDC_USE_PAC_SCRIPT);
    pac_script_len = GetDlgItemTextW(hwnd, IDC_EDIT_PAC_SCRIPT,
298
            pac_script, ARRAY_SIZE(pac_script));
299 300 301
    if(!pac_script_len) use_pac_script = FALSE;
    if(use_pac_script)
    {
302
        res = RegSetValueExW(hkey, L"AutoConfigURL", 0, REG_SZ,
303 304 305 306
                (BYTE*)pac_script, pac_script_len*sizeof(WCHAR));
    }
    else
    {
307
        res = RegDeleteValueW(hkey, L"AutoConfigURL");
308 309 310 311 312 313 314 315 316 317 318
        if(res == ERROR_FILE_NOT_FOUND)
            res = ERROR_SUCCESS;
    }
    if(res)
    {
        RegCloseKey(hkey);
        return FALSE;
    }
    TRACE("AutoConfigURL set to %s\n", wine_dbgstr_w(use_pac_script ? pac_script : NULL));

    use_wpad = IsDlgButtonChecked(hwnd, IDC_USE_WPAD);
319

320
    res = RegCreateKeyExW(hkey, L"Connections", 0, NULL, 0, KEY_WRITE, NULL, &con, NULL);
321
    RegCloseKey(hkey);
322 323 324
    if(res)
        return FALSE;

325 326
    size = create_connection_settings(use_proxy, proxy, use_wpad,
        use_pac_script, pac_script, &default_connection);
327 328 329 330 331 332
    if(!size)
    {
        RegCloseKey(con);
        return FALSE;
    }

333
    res = RegSetValueExW(con, L"DefaultConnectionSettings", 0, REG_BINARY,
334 335 336
            (BYTE*)default_connection, size);
    heap_free(default_connection);
    RegCloseKey(con);
337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354
    return !res;
}

INT_PTR CALLBACK connections_dlgproc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
{
    switch (msg)
    {
        case WM_INITDIALOG:
            connections_on_initdialog(hwnd);
            initdialog_done = TRUE;
            break;
        case WM_COMMAND:
            return connections_on_command(hwnd, wparam);
        case WM_NOTIFY:
            return connections_on_notify(hwnd, wparam, lparam);
    }
    return FALSE;
}