include/mscvpdb.h: Use flexible array members for the rest of structures.
[wine.git] / dlls / wininet / internet.c
blob764be89189d606a1f13f41b8b917c1beea22514b
1 /*
2 * Wininet
4 * Copyright 1999 Corel Corporation
5 * Copyright 2002 CodeWeavers Inc.
6 * Copyright 2002 Jaco Greeff
7 * Copyright 2002 TransGaming Technologies Inc.
8 * Copyright 2004 Mike McCormack for CodeWeavers
10 * Ulrich Czekalla
11 * Aric Stewart
12 * David Hammerton
14 * This library is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU Lesser General Public
16 * License as published by the Free Software Foundation; either
17 * version 2.1 of the License, or (at your option) any later version.
19 * This library is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 * Lesser General Public License for more details.
24 * You should have received a copy of the GNU Lesser General Public
25 * License along with this library; if not, write to the Free Software
26 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
29 #include "winsock2.h"
30 #include "ws2ipdef.h"
32 #include <string.h>
33 #include <stdarg.h>
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <ctype.h>
37 #include <assert.h>
38 #include <wchar.h>
40 #include "windef.h"
41 #include "winbase.h"
42 #include "winreg.h"
43 #include "winuser.h"
44 #include "wininet.h"
45 #include "winnls.h"
46 #include "wine/debug.h"
47 #include "winerror.h"
48 #define NO_SHLWAPI_STREAM
49 #include "shlwapi.h"
50 #include "ws2tcpip.h"
51 #include "winternl.h"
52 #include "iphlpapi.h"
53 #include "dhcpcsdk.h"
55 #include "internet.h"
56 #include "resource.h"
58 WINE_DEFAULT_DEBUG_CHANNEL(wininet);
60 typedef struct
62 DWORD dwError;
63 CHAR response[MAX_REPLY_LEN];
64 } WITHREADERROR, *LPWITHREADERROR;
66 static DWORD g_dwTlsErrIndex = TLS_OUT_OF_INDEXES;
67 HMODULE WININET_hModule;
69 static CRITICAL_SECTION WININET_cs;
70 static CRITICAL_SECTION_DEBUG WININET_cs_debug =
72 0, 0, &WININET_cs,
73 { &WININET_cs_debug.ProcessLocksList, &WININET_cs_debug.ProcessLocksList },
74 0, 0, { (DWORD_PTR)(__FILE__ ": WININET_cs") }
76 static CRITICAL_SECTION WININET_cs = { &WININET_cs_debug, -1, 0, 0, 0, 0 };
78 static object_header_t **handle_table;
79 static UINT_PTR next_handle;
80 static UINT_PTR handle_table_size;
82 typedef struct
84 DWORD flags;
85 LPWSTR proxy;
86 LPWSTR proxyBypass;
87 LPWSTR proxyUsername;
88 LPWSTR proxyPassword;
89 LPWSTR autoconf_url;
90 } proxyinfo_t;
92 #define CONNECTION_SETTINGS_VERSION 0x46
93 typedef struct {
94 DWORD version;
95 DWORD id;
96 DWORD flags;
97 BYTE data[1];
98 /* DWORD proxy_server_len; */
99 /* UTF8 proxy_server[proxy_server_len]; */
100 /* DWORD bypass_list_len; */
101 /* UTF8 bypass_list[bypass_list_len]; */
102 /* DWORD configuration_script_len; */
103 /* UTF8 configuration_script[configuration_script_len]; */
104 /* DWORD unk[8]; set to 0 */
105 } connection_settings;
107 static ULONG max_conns = 2, max_1_0_conns = 4;
108 static ULONG connect_timeout = 60000;
109 static ULONG send_timeout = 60000;
110 static ULONG receive_timeout = 60000;
111 static ULONG data_send_timeout = 60000;
112 static ULONG data_receive_timeout = 60000;
115 static const WCHAR szInternetSettings[] =
116 L"Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings";
118 static WCHAR *get_proxy_autoconfig_url(void);
120 void *alloc_object(object_header_t *parent, const object_vtbl_t *vtbl, size_t size)
122 UINT_PTR handle = 0, num;
123 object_header_t *ret;
124 object_header_t **p;
125 BOOL res = TRUE;
127 ret = calloc(1, size);
128 if(!ret)
129 return NULL;
131 list_init(&ret->children);
133 EnterCriticalSection( &WININET_cs );
135 if(!handle_table_size) {
136 num = 16;
137 p = calloc(num, sizeof(handle_table[0]));
138 if(p) {
139 handle_table = p;
140 handle_table_size = num;
141 next_handle = 1;
142 }else {
143 res = FALSE;
145 }else if(next_handle == handle_table_size) {
146 num = handle_table_size * 2;
147 p = realloc(handle_table, sizeof(handle_table[0]) * num);
148 if(p) {
149 memset(p + handle_table_size, 0, sizeof(handle_table[0]) * handle_table_size);
150 handle_table = p;
151 handle_table_size = num;
152 }else {
153 res = FALSE;
157 if(res) {
158 handle = next_handle;
159 if(handle_table[handle])
160 ERR("handle isn't free but should be\n");
161 handle_table[handle] = ret;
162 ret->valid_handle = TRUE;
164 while(next_handle < handle_table_size && handle_table[next_handle])
165 next_handle++;
168 LeaveCriticalSection( &WININET_cs );
170 if(!res) {
171 free(ret);
172 return NULL;
175 ret->vtbl = vtbl;
176 ret->refs = 1;
177 ret->hInternet = (HINTERNET)handle;
179 if(parent) {
180 ret->lpfnStatusCB = parent->lpfnStatusCB;
181 ret->dwInternalFlags = parent->dwInternalFlags & INET_CALLBACKW;
182 ret->connect_timeout = parent->connect_timeout;
183 ret->send_timeout = parent->send_timeout;
184 ret->receive_timeout = parent->receive_timeout;
185 ret->data_send_timeout = parent->data_send_timeout;
186 ret->data_receive_timeout = parent->data_receive_timeout;
187 } else {
188 ret->connect_timeout = connect_timeout;
189 ret->send_timeout = send_timeout;
190 ret->receive_timeout = receive_timeout;
191 ret->data_send_timeout = data_send_timeout;
192 ret->data_receive_timeout = data_receive_timeout;
195 return ret;
198 object_header_t *WININET_AddRef( object_header_t *info )
200 ULONG refs = InterlockedIncrement(&info->refs);
201 TRACE("%p -> refcount = %ld\n", info, refs );
202 return info;
205 object_header_t *get_handle_object( HINTERNET hinternet )
207 object_header_t *info = NULL;
208 UINT_PTR handle = (UINT_PTR) hinternet;
210 EnterCriticalSection( &WININET_cs );
212 if(handle > 0 && handle < handle_table_size && handle_table[handle] && handle_table[handle]->valid_handle)
213 info = WININET_AddRef(handle_table[handle]);
215 LeaveCriticalSection( &WININET_cs );
217 TRACE("handle %Id -> %p\n", handle, info);
219 return info;
222 static void invalidate_handle(object_header_t *info)
224 object_header_t *child, *next;
226 if(!info->valid_handle)
227 return;
228 info->valid_handle = FALSE;
230 /* Free all children as native does */
231 LIST_FOR_EACH_ENTRY_SAFE( child, next, &info->children, object_header_t, entry )
233 TRACE("invalidating child handle %p for parent %p\n", child->hInternet, info);
234 invalidate_handle( child );
237 WININET_Release(info);
240 BOOL WININET_Release( object_header_t *info )
242 ULONG refs = InterlockedDecrement(&info->refs);
243 TRACE( "object %p refcount = %ld\n", info, refs );
244 if( !refs )
246 invalidate_handle(info);
247 if ( info->vtbl->CloseConnection )
249 TRACE( "closing connection %p\n", info);
250 info->vtbl->CloseConnection( info );
252 /* Don't send a callback if this is a session handle created with InternetOpenUrl */
253 if ((info->htype != WH_HHTTPSESSION && info->htype != WH_HFTPSESSION)
254 || !(info->dwInternalFlags & INET_OPENURL))
256 INTERNET_SendCallback(info, info->dwContext,
257 INTERNET_STATUS_HANDLE_CLOSING, &info->hInternet,
258 sizeof(HINTERNET));
260 TRACE( "destroying object %p\n", info);
261 if ( info->htype != WH_HINIT )
262 list_remove( &info->entry );
263 info->vtbl->Destroy( info );
265 if(info->hInternet) {
266 UINT_PTR handle = (UINT_PTR)info->hInternet;
268 EnterCriticalSection( &WININET_cs );
270 handle_table[handle] = NULL;
271 if(next_handle > handle)
272 next_handle = handle;
274 LeaveCriticalSection( &WININET_cs );
277 free(info);
279 return TRUE;
282 /***********************************************************************
283 * DllMain [Internal] Initializes the internal 'WININET.DLL'.
285 * PARAMS
286 * hinstDLL [I] handle to the DLL's instance
287 * fdwReason [I]
288 * lpvReserved [I] reserved, must be NULL
290 * RETURNS
291 * Success: TRUE
292 * Failure: FALSE
295 BOOL WINAPI DllMain (HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
297 TRACE("%p,%lx,%p\n", hinstDLL, fdwReason, lpvReserved);
299 switch (fdwReason) {
300 case DLL_PROCESS_ATTACH:
302 g_dwTlsErrIndex = TlsAlloc();
304 if (g_dwTlsErrIndex == TLS_OUT_OF_INDEXES)
305 return FALSE;
307 if(!init_urlcache())
309 TlsFree(g_dwTlsErrIndex);
310 return FALSE;
313 WININET_hModule = hinstDLL;
314 break;
316 case DLL_THREAD_ATTACH:
317 break;
319 case DLL_THREAD_DETACH:
320 if (g_dwTlsErrIndex != TLS_OUT_OF_INDEXES)
322 free(TlsGetValue(g_dwTlsErrIndex));
324 break;
326 case DLL_PROCESS_DETACH:
327 if (lpvReserved) break;
328 collect_connections(COLLECT_CLEANUP);
329 NETCON_unload();
330 free_urlcache();
331 free_cookie();
333 if (g_dwTlsErrIndex != TLS_OUT_OF_INDEXES)
335 free(TlsGetValue(g_dwTlsErrIndex));
336 TlsFree(g_dwTlsErrIndex);
338 break;
340 return TRUE;
343 /***********************************************************************
344 * DllInstall (WININET.@)
346 HRESULT WINAPI DllInstall(BOOL bInstall, LPCWSTR cmdline)
348 FIXME("(%x %s): stub\n", bInstall, debugstr_w(cmdline));
349 return S_OK;
352 static void connection_settings_write( connection_settings *settings, DWORD *pos, DWORD size, const WCHAR *str )
354 int len = 0;
356 if (str)
358 len = wcslen( str );
359 len = WideCharToMultiByte( CP_UTF8, 0, str, len, settings ? (char*)settings->data + *pos + sizeof(len) : NULL,
360 settings ? size - *pos - sizeof(len) : 0, NULL, NULL );
362 if (settings)
363 memcpy(settings->data + *pos, &len, sizeof(len));
364 *pos += sizeof(len) + len;
367 static LONG save_connection_settings( HKEY key, const WCHAR *connection, proxyinfo_t *lpwpi )
369 connection_settings *settings;
370 DWORD size = 0, pos = 0;
371 LONG ret;
373 connection_settings_write( NULL, &size, 0, lpwpi->proxy );
374 connection_settings_write( NULL, &size, 0, lpwpi->proxyBypass );
375 connection_settings_write( NULL, &size, 0, lpwpi->autoconf_url );
376 size += sizeof(DWORD) * 10; /* unknown fields */
378 settings = calloc( 1, FIELD_OFFSET(connection_settings, data[size]) );
379 if (!settings)
380 return ERROR_OUTOFMEMORY;
382 settings->version = CONNECTION_SETTINGS_VERSION;
383 settings->flags = lpwpi->flags;
384 connection_settings_write( settings, &pos, size, lpwpi->proxy );
385 connection_settings_write( settings, &pos, size, lpwpi->proxyBypass );
386 connection_settings_write( settings, &pos, size, lpwpi->autoconf_url );
388 ret = RegSetValueExW(key, connection, 0, REG_BINARY, (BYTE*)settings,
389 FIELD_OFFSET(connection_settings, data[size]));
390 free(settings);
391 return ret;
394 /***********************************************************************
395 * INTERNET_SaveProxySettings
397 * Stores the proxy settings given by lpwai into the registry
399 * RETURNS
400 * ERROR_SUCCESS if no error, or error code on fail
402 static LONG INTERNET_SaveProxySettings( proxyinfo_t *lpwpi )
404 HKEY key, con;
405 DWORD val;
406 LONG ret;
408 if ((ret = RegOpenKeyW( HKEY_CURRENT_USER, szInternetSettings, &key )))
409 return ret;
411 if ((ret = RegCreateKeyExW( key, L"Connections", 0, NULL, 0, KEY_WRITE, NULL, &con, NULL )))
413 RegCloseKey( key );
414 return ret;
416 ret = save_connection_settings( con, L"DefaultConnectionSettings", lpwpi );
417 RegCloseKey( con );
418 if (ret)
420 RegCloseKey( key );
421 return ret;
424 val = !!(lpwpi->flags & PROXY_TYPE_PROXY);
425 if ((ret = RegSetValueExW( key, L"ProxyEnable", 0, REG_DWORD, (BYTE*)&val, sizeof(DWORD))))
427 RegCloseKey( key );
428 return ret;
431 if (lpwpi->proxy)
433 if ((ret = RegSetValueExW( key, L"ProxyServer", 0, REG_SZ, (BYTE*)lpwpi->proxy,
434 sizeof(WCHAR) * (lstrlenW(lpwpi->proxy) + 1))))
436 RegCloseKey( key );
437 return ret;
440 else
442 if ((ret = RegDeleteValueW( key, L"ProxyServer" )) && ret != ERROR_FILE_NOT_FOUND)
444 RegCloseKey( key );
445 return ret;
449 if (lpwpi->proxyBypass)
451 if ((ret = RegSetValueExW( key, L"ProxyOverride", 0, REG_SZ, (BYTE*)lpwpi->proxyBypass,
452 sizeof(WCHAR) * (lstrlenW(lpwpi->proxyBypass) + 1))))
454 RegCloseKey( key );
455 return ret;
458 else
460 if ((ret = RegDeleteValueW( key, L"ProxyOverride" )) && ret != ERROR_FILE_NOT_FOUND)
462 RegCloseKey( key );
463 return ret;
467 if (lpwpi->autoconf_url && lpwpi->flags & PROXY_TYPE_AUTO_PROXY_URL)
469 if ((ret = RegSetValueExW( key, L"AutoConfigURL", 0, REG_SZ, (BYTE*)lpwpi->autoconf_url,
470 sizeof(WCHAR) * (lstrlenW(lpwpi->autoconf_url) + 1))))
472 RegCloseKey( key );
473 return ret;
476 else
478 if ((ret = RegDeleteValueW( key, L"AutoConfigURL" )) && ret != ERROR_FILE_NOT_FOUND)
480 RegCloseKey( key );
481 return ret;
485 RegCloseKey(key);
486 return ERROR_SUCCESS;
489 /***********************************************************************
490 * INTERNET_FindProxyForProtocol
492 * Searches the proxy string for a proxy of the given protocol.
493 * Returns the found proxy, or the default proxy if none of the given
494 * protocol is found.
496 * PARAMETERS
497 * szProxy [In] proxy string to search
498 * proto [In] protocol to search for, e.g. "http"
499 * foundProxy [Out] found proxy
500 * foundProxyLen [In/Out] length of foundProxy buffer, in WCHARs
502 * RETURNS
503 * TRUE if a proxy is found, FALSE if not. If foundProxy is too short,
504 * *foundProxyLen is set to the required size in WCHARs, including the
505 * NULL terminator, and the last error is set to ERROR_INSUFFICIENT_BUFFER.
507 WCHAR *INTERNET_FindProxyForProtocol(LPCWSTR szProxy, LPCWSTR proto)
509 WCHAR *ret = NULL;
510 const WCHAR *ptr;
512 TRACE("(%s, %s)\n", debugstr_w(szProxy), debugstr_w(proto));
514 /* First, look for the specified protocol (proto=scheme://host:port) */
515 for (ptr = szProxy; ptr && *ptr; )
517 LPCWSTR end, equal;
519 if (!(end = wcschr(ptr, ' ')))
520 end = ptr + lstrlenW(ptr);
521 if ((equal = wcschr(ptr, '=')) && equal < end &&
522 equal - ptr == lstrlenW(proto) &&
523 !wcsnicmp(proto, ptr, lstrlenW(proto)))
525 ret = strndupW(equal + 1, end - equal - 1);
526 TRACE("found proxy for %s: %s\n", debugstr_w(proto), debugstr_w(ret));
527 return ret;
529 if (*end == ' ')
530 ptr = end + 1;
531 else
532 ptr = end;
535 /* It wasn't found: look for no protocol */
536 for (ptr = szProxy; ptr && *ptr; )
538 LPCWSTR end;
540 if (!(end = wcschr(ptr, ' ')))
541 end = ptr + lstrlenW(ptr);
542 if (!wcschr(ptr, '='))
544 ret = strndupW(ptr, end - ptr);
545 TRACE("found proxy for %s: %s\n", debugstr_w(proto), debugstr_w(ret));
546 return ret;
548 if (*end == ' ')
549 ptr = end + 1;
550 else
551 ptr = end;
554 return NULL;
557 /***********************************************************************
558 * InternetInitializeAutoProxyDll (WININET.@)
560 * Setup the internal proxy
562 * PARAMETERS
563 * dwReserved
565 * RETURNS
566 * FALSE on failure
569 BOOL WINAPI InternetInitializeAutoProxyDll(DWORD dwReserved)
571 FIXME("STUB\n");
572 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
573 return FALSE;
576 /***********************************************************************
577 * DetectAutoProxyUrl (WININET.@)
579 * Auto detect the proxy url
581 * RETURNS
582 * FALSE on failure
585 BOOL WINAPI DetectAutoProxyUrl(LPSTR lpszAutoProxyUrl,
586 DWORD dwAutoProxyUrlLength, DWORD dwDetectFlags)
588 FIXME("STUB\n");
589 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
590 return FALSE;
593 static void FreeProxyInfo( proxyinfo_t *lpwpi )
595 free(lpwpi->proxy);
596 free(lpwpi->proxyBypass);
597 free(lpwpi->proxyUsername);
598 free(lpwpi->proxyPassword);
599 free(lpwpi->autoconf_url);
602 static proxyinfo_t global_proxy;
604 static void free_global_proxy( void )
606 EnterCriticalSection( &WININET_cs );
607 FreeProxyInfo( &global_proxy );
608 memset( &global_proxy, 0, sizeof(global_proxy) );
609 LeaveCriticalSection( &WININET_cs );
612 static BOOL parse_proxy_url( proxyinfo_t *info, const WCHAR *url )
614 URL_COMPONENTSW uc = {sizeof(uc)};
616 uc.dwHostNameLength = 1;
617 uc.dwUserNameLength = 1;
618 uc.dwPasswordLength = 1;
620 if (!InternetCrackUrlW( url, 0, 0, &uc )) return FALSE;
621 if (!uc.dwHostNameLength)
623 if (!(info->proxy = wcsdup( url ))) return FALSE;
624 info->proxyUsername = NULL;
625 info->proxyPassword = NULL;
626 return TRUE;
628 if (!(info->proxy = malloc( (uc.dwHostNameLength + 12) * sizeof(WCHAR) ))) return FALSE;
629 swprintf( info->proxy, uc.dwHostNameLength + 12, L"%.*s:%u", uc.dwHostNameLength, uc.lpszHostName, uc.nPort );
631 if (!uc.dwUserNameLength) info->proxyUsername = NULL;
632 else if (!(info->proxyUsername = strndupW( uc.lpszUserName, uc.dwUserNameLength )))
634 free( info->proxy );
635 return FALSE;
637 if (!uc.dwPasswordLength) info->proxyPassword = NULL;
638 else if (!(info->proxyPassword = strndupW( uc.lpszPassword, uc.dwPasswordLength )))
640 free( info->proxyUsername );
641 free( info->proxy );
642 return FALSE;
644 return TRUE;
647 static WCHAR *get_http_proxy( const WCHAR *proxy )
649 const WCHAR *p, *end;
650 WCHAR *ret;
652 p = wcsstr( proxy, L"http=" );
653 if (p) p += 5;
654 else p = proxy;
655 end = wcschr( p, ';' );
656 if (!end) end = p + wcslen( p );
658 ret = malloc( (end - p + 1) * sizeof(WCHAR) );
659 memcpy(ret, p, (end - p) * sizeof(WCHAR) );
660 ret[end - p] = 0;
661 return ret;
664 static LONG connection_settings_read( const connection_settings *settings, DWORD *pos, DWORD size, WCHAR **str)
666 int len, wlen;
668 *str = NULL;
669 if (*pos + sizeof(int) >= size)
670 return ERROR_SUCCESS;
671 memcpy( &len, settings->data + *pos, sizeof(int) );
672 *pos += sizeof(int);
674 if (*pos + len >= size)
676 *pos = size;
677 return ERROR_SUCCESS;
679 wlen = MultiByteToWideChar( CP_UTF8, 0, (const char *)settings->data + *pos, len, NULL, 0 );
680 if (wlen)
682 *str = malloc( (wlen + 1) * sizeof(WCHAR) );
683 if (!*str)
685 *pos = size;
686 return ERROR_OUTOFMEMORY;
688 MultiByteToWideChar( CP_UTF8, 0, (const char *)settings->data + *pos, len, *str, wlen );
689 (*str)[wlen] = 0;
690 *pos += len;
692 return ERROR_SUCCESS;
695 static LONG load_connection_settings( HKEY key, const WCHAR *connection, proxyinfo_t *lpwpi )
697 connection_settings *settings = NULL;
698 DWORD type, pos, size = 0;
699 LONG res;
701 while ((res = RegQueryValueExW( key, connection, NULL, &type, (BYTE*)settings, &size )) == ERROR_MORE_DATA ||
702 (!res && !settings))
704 connection_settings *new_settings = realloc(settings, size);
705 if(!new_settings)
707 free( settings );
708 return ERROR_OUTOFMEMORY;
710 settings = new_settings;
713 memset(lpwpi, 0, sizeof(*lpwpi));
714 if (res || type != REG_BINARY || size < FIELD_OFFSET( connection_settings, data ))
716 lpwpi->flags |= PROXY_TYPE_DIRECT | PROXY_TYPE_AUTO_DETECT;
717 free( settings );
718 return ERROR_SUCCESS;
721 lpwpi->flags = settings->flags;
722 size -= FIELD_OFFSET( connection_settings, data );
723 pos = 0;
724 res = connection_settings_read( settings, &pos, size, &lpwpi->proxy );
725 if (!res)
726 res = connection_settings_read( settings, &pos, size, &lpwpi->proxyBypass );
727 if (!res)
728 res = connection_settings_read( settings, &pos, size, &lpwpi->autoconf_url );
729 free( settings );
730 if (res)
732 FreeProxyInfo( lpwpi );
733 return res;
735 return ERROR_SUCCESS;
738 /***********************************************************************
739 * INTERNET_LoadProxySettings
741 * Loads proxy information from the registry into lpwpi.
743 * The caller should call FreeProxyInfo when done with lpwpi.
745 * FIXME:
746 * The proxy may be specified in the form 'http=proxy.my.org'
747 * Presumably that means there can be ftp=ftpproxy.my.org too.
749 static LONG INTERNET_LoadProxySettings( proxyinfo_t *lpwpi )
751 DWORD type, len, val;
752 HKEY key, con;
753 LONG ret;
755 memset( lpwpi, 0, sizeof(*lpwpi) );
757 if ((ret = RegOpenKeyW( HKEY_CURRENT_USER, szInternetSettings, &key )))
758 return ret;
760 if (!(ret = RegOpenKeyW( key, L"Connections", &con )))
762 load_connection_settings( con, L"DefaultConnectionSettings", lpwpi );
763 RegCloseKey( con );
766 len = sizeof(DWORD);
767 if (RegQueryValueExW( key, L"ProxyEnable", NULL, &type, (BYTE *)&val, &len ) || type != REG_DWORD)
769 val = !!(lpwpi->flags & PROXY_TYPE_PROXY);
770 if((ret = RegSetValueExW( key, L"ProxyEnable", 0, REG_DWORD, (BYTE *)&val, sizeof(DWORD) )))
772 RegCloseKey( key );
773 FreeProxyInfo( lpwpi );
774 return ret;
777 else if (val)
779 lpwpi->flags |= PROXY_TYPE_PROXY;
781 else
783 lpwpi->flags &= ~PROXY_TYPE_PROXY;
786 /* figure out how much memory the proxy setting takes */
787 if (!RegQueryValueExW( key, L"ProxyServer", NULL, &type, NULL, &len ) && len && (type == REG_SZ))
789 LPWSTR szProxy;
791 if (!(szProxy = malloc( len )))
793 RegCloseKey( key );
794 FreeProxyInfo( lpwpi );
795 return ERROR_OUTOFMEMORY;
797 RegQueryValueExW( key, L"ProxyServer", NULL, &type, (BYTE*)szProxy, &len );
799 free( lpwpi->proxy );
800 lpwpi->proxy = szProxy;
803 if (lpwpi->proxy)
805 TRACE("proxy (from registry%s) = %s\n", lpwpi->flags & PROXY_TYPE_PROXY ? "" : ", disabled",
806 debugstr_w(lpwpi->proxy));
808 else
810 TRACE("No proxy server settings in registry.\n");
813 if (!RegQueryValueExW( key, L"ProxyOverride", NULL, &type, NULL, &len ) && len && (type == REG_SZ))
815 LPWSTR szProxy;
817 if (!(szProxy = malloc( len )))
819 RegCloseKey( key );
820 FreeProxyInfo( lpwpi );
821 return ERROR_OUTOFMEMORY;
823 RegQueryValueExW( key, L"ProxyOverride", NULL, &type, (BYTE*)szProxy, &len );
825 free( lpwpi->proxyBypass );
826 lpwpi->proxyBypass = szProxy;
827 TRACE("http proxy bypass (from registry) = %s\n", debugstr_w(lpwpi->proxyBypass));
829 else
831 TRACE("No proxy bypass server settings in registry.\n");
834 if (!RegQueryValueExW( key, L"AutoConfigURL", NULL, &type, NULL, &len ) && len && (type == REG_SZ))
836 LPWSTR autoconf_url;
838 if (!(autoconf_url = malloc( len )))
840 RegCloseKey( key );
841 FreeProxyInfo( lpwpi );
842 return ERROR_OUTOFMEMORY;
844 RegQueryValueExW( key, L"AutoConfigURL", NULL, &type, (BYTE*)autoconf_url, &len );
846 lpwpi->flags |= PROXY_TYPE_AUTO_PROXY_URL;
847 free( lpwpi->autoconf_url );
848 lpwpi->autoconf_url = autoconf_url;
849 TRACE("AutoConfigURL = %s\n", debugstr_w(lpwpi->autoconf_url));
852 RegCloseKey( key );
853 return ERROR_SUCCESS;
856 static void init_global_proxy(void)
858 const WCHAR *envproxy;
860 EnterCriticalSection( &WININET_cs );
861 if (global_proxy.flags) goto done;
863 INTERNET_LoadProxySettings( &global_proxy );
864 if (global_proxy.flags & PROXY_TYPE_PROXY || !(envproxy = _wgetenv( L"http_proxy" )))
865 goto done;
867 if (parse_proxy_url( &global_proxy, envproxy ))
869 global_proxy.flags |= PROXY_TYPE_PROXY;
870 global_proxy.proxyBypass = wcsdup(_wgetenv( L"no_proxy" ));
871 TRACE("http proxy (from environment) = %s\n", debugstr_w(global_proxy.proxy));
872 TRACE("http proxy bypass (from environment) = %s\n", debugstr_w(global_proxy.proxyBypass));
874 else
876 WARN("failed to parse http_proxy value %s\n", debugstr_w(envproxy));
879 done:
880 LeaveCriticalSection( &WININET_cs );
883 /***********************************************************************
884 * INTERNET_GetProxySettings
886 * Loads process-wide proxy settings into lpwpi.
888 static LONG INTERNET_GetProxySettings( proxyinfo_t *lpwpi )
890 init_global_proxy();
892 memset(lpwpi, 0, sizeof(*lpwpi));
893 EnterCriticalSection( &WININET_cs );
894 lpwpi->flags = global_proxy.flags;
895 lpwpi->proxy = wcsdup( global_proxy.proxy );
896 lpwpi->proxyBypass = wcsdup( global_proxy.proxyBypass );
897 lpwpi->proxyUsername = wcsdup( global_proxy.proxyUsername );
898 lpwpi->proxyPassword = wcsdup( global_proxy.proxyPassword );
899 LeaveCriticalSection( &WININET_cs );
900 return ERROR_SUCCESS;
903 /***********************************************************************
904 * INTERNET_ConfigureProxy
906 static BOOL INTERNET_ConfigureProxy( appinfo_t *lpwai )
908 proxyinfo_t wpi;
910 if (INTERNET_GetProxySettings( &wpi ))
911 return FALSE;
913 if (wpi.flags & PROXY_TYPE_PROXY)
915 TRACE("http proxy = %s bypass = %s\n", debugstr_w(wpi.proxy), debugstr_w(wpi.proxyBypass));
917 lpwai->accessType = INTERNET_OPEN_TYPE_PROXY;
918 lpwai->proxy = get_http_proxy( wpi.proxy );
919 lpwai->proxyBypass = wpi.proxyBypass;
920 lpwai->proxyUsername = wpi.proxyUsername;
921 lpwai->proxyPassword = wpi.proxyPassword;
922 free( wpi.proxy );
923 return TRUE;
926 lpwai->accessType = INTERNET_OPEN_TYPE_DIRECT;
927 FreeProxyInfo(&wpi);
928 return FALSE;
931 /***********************************************************************
932 * dump_INTERNET_FLAGS
934 * Helper function to TRACE the internet flags.
936 * RETURNS
937 * None
940 static void dump_INTERNET_FLAGS(DWORD dwFlags)
942 #define FE(x) { x, #x }
943 static const wininet_flag_info flag[] = {
944 FE(INTERNET_FLAG_RELOAD),
945 FE(INTERNET_FLAG_RAW_DATA),
946 FE(INTERNET_FLAG_EXISTING_CONNECT),
947 FE(INTERNET_FLAG_ASYNC),
948 FE(INTERNET_FLAG_PASSIVE),
949 FE(INTERNET_FLAG_NO_CACHE_WRITE),
950 FE(INTERNET_FLAG_MAKE_PERSISTENT),
951 FE(INTERNET_FLAG_FROM_CACHE),
952 FE(INTERNET_FLAG_SECURE),
953 FE(INTERNET_FLAG_KEEP_CONNECTION),
954 FE(INTERNET_FLAG_NO_AUTO_REDIRECT),
955 FE(INTERNET_FLAG_READ_PREFETCH),
956 FE(INTERNET_FLAG_NO_COOKIES),
957 FE(INTERNET_FLAG_NO_AUTH),
958 FE(INTERNET_FLAG_CACHE_IF_NET_FAIL),
959 FE(INTERNET_FLAG_IGNORE_REDIRECT_TO_HTTP),
960 FE(INTERNET_FLAG_IGNORE_REDIRECT_TO_HTTPS),
961 FE(INTERNET_FLAG_IGNORE_CERT_DATE_INVALID),
962 FE(INTERNET_FLAG_IGNORE_CERT_CN_INVALID),
963 FE(INTERNET_FLAG_RESYNCHRONIZE),
964 FE(INTERNET_FLAG_HYPERLINK),
965 FE(INTERNET_FLAG_NO_UI),
966 FE(INTERNET_FLAG_PRAGMA_NOCACHE),
967 FE(INTERNET_FLAG_CACHE_ASYNC),
968 FE(INTERNET_FLAG_FORMS_SUBMIT),
969 FE(INTERNET_FLAG_NEED_FILE),
970 FE(INTERNET_FLAG_TRANSFER_ASCII),
971 FE(INTERNET_FLAG_TRANSFER_BINARY)
973 #undef FE
974 unsigned int i;
976 for (i = 0; i < ARRAY_SIZE(flag); i++) {
977 if (flag[i].val & dwFlags) {
978 TRACE(" %s", flag[i].name);
979 dwFlags &= ~flag[i].val;
982 if (dwFlags)
983 TRACE(" Unknown flags (%08lx)\n", dwFlags);
984 else
985 TRACE("\n");
988 /***********************************************************************
989 * INTERNET_CloseHandle (internal)
991 * Close internet handle
994 static VOID APPINFO_Destroy(object_header_t *hdr)
996 appinfo_t *lpwai = (appinfo_t*)hdr;
998 TRACE("%p\n",lpwai);
1000 free(lpwai->agent);
1001 free(lpwai->proxy);
1002 free(lpwai->proxyBypass);
1003 free(lpwai->proxyUsername);
1004 free(lpwai->proxyPassword);
1007 static WCHAR *copy_optionW(WCHAR *value)
1009 DWORD len;
1010 void *tmp;
1012 if (!value)
1013 return NULL;
1015 len = (wcslen(value) + 1) * sizeof(WCHAR);
1016 if (!(tmp = GlobalAlloc(0, len)))
1017 return NULL;
1019 return memcpy(tmp, value, len);
1022 static char *copy_optionA(WCHAR *value)
1024 DWORD len;
1025 void *tmp;
1027 if (!value)
1028 return NULL;
1030 len = WideCharToMultiByte(CP_ACP, 0, value, -1, NULL, 0, NULL, NULL);
1031 if (!(tmp = GlobalAlloc(0, len)))
1032 return NULL;
1034 WideCharToMultiByte(CP_ACP, 0, value, -1, tmp, len, NULL, NULL);
1035 return tmp;
1038 static DWORD APPINFO_QueryOption(object_header_t *hdr, DWORD option, void *buffer, DWORD *size, BOOL unicode)
1040 appinfo_t *ai = (appinfo_t*)hdr;
1042 switch(option) {
1043 case INTERNET_OPTION_HANDLE_TYPE:
1044 TRACE("INTERNET_OPTION_HANDLE_TYPE\n");
1046 if (*size < sizeof(ULONG))
1047 return ERROR_INSUFFICIENT_BUFFER;
1049 *size = sizeof(DWORD);
1050 *(DWORD*)buffer = INTERNET_HANDLE_TYPE_INTERNET;
1051 return ERROR_SUCCESS;
1053 case INTERNET_OPTION_USER_AGENT: {
1054 DWORD bufsize;
1056 TRACE("INTERNET_OPTION_USER_AGENT\n");
1058 bufsize = *size;
1060 if (unicode) {
1061 DWORD len = ai->agent ? lstrlenW(ai->agent) : 0;
1063 *size = (len + 1) * sizeof(WCHAR);
1064 if(!buffer || bufsize < *size)
1065 return ERROR_INSUFFICIENT_BUFFER;
1067 if (ai->agent)
1068 lstrcpyW(buffer, ai->agent);
1069 else
1070 *(WCHAR *)buffer = 0;
1071 /* If the buffer is copied, the returned length doesn't include
1072 * the NULL terminator.
1074 *size = len;
1075 }else {
1076 if (ai->agent)
1077 *size = WideCharToMultiByte(CP_ACP, 0, ai->agent, -1, NULL, 0, NULL, NULL);
1078 else
1079 *size = 1;
1080 if(!buffer || bufsize < *size)
1081 return ERROR_INSUFFICIENT_BUFFER;
1083 if (ai->agent)
1084 WideCharToMultiByte(CP_ACP, 0, ai->agent, -1, buffer, *size, NULL, NULL);
1085 else
1086 *(char *)buffer = 0;
1087 /* If the buffer is copied, the returned length doesn't include
1088 * the NULL terminator.
1090 *size -= 1;
1093 return ERROR_SUCCESS;
1096 case INTERNET_OPTION_PROXY:
1097 if(!size) return ERROR_INVALID_PARAMETER;
1098 if (unicode) {
1099 INTERNET_PROXY_INFOW *pi = (INTERNET_PROXY_INFOW *)buffer;
1100 DWORD proxyBytesRequired = 0, proxyBypassBytesRequired = 0;
1101 LPWSTR proxy, proxy_bypass;
1103 if (ai->proxy)
1104 proxyBytesRequired = (lstrlenW(ai->proxy) + 1) * sizeof(WCHAR);
1105 if (ai->proxyBypass)
1106 proxyBypassBytesRequired = (lstrlenW(ai->proxyBypass) + 1) * sizeof(WCHAR);
1107 if (!pi || *size < sizeof(INTERNET_PROXY_INFOW) + proxyBytesRequired + proxyBypassBytesRequired)
1109 *size = sizeof(INTERNET_PROXY_INFOW) + proxyBytesRequired + proxyBypassBytesRequired;
1110 return ERROR_INSUFFICIENT_BUFFER;
1112 proxy = (LPWSTR)((LPBYTE)buffer + sizeof(INTERNET_PROXY_INFOW));
1113 proxy_bypass = (LPWSTR)((LPBYTE)buffer + sizeof(INTERNET_PROXY_INFOW) + proxyBytesRequired);
1115 pi->dwAccessType = ai->accessType;
1116 pi->lpszProxy = NULL;
1117 pi->lpszProxyBypass = NULL;
1118 if (ai->proxy) {
1119 lstrcpyW(proxy, ai->proxy);
1120 pi->lpszProxy = proxy;
1123 if (ai->proxyBypass) {
1124 lstrcpyW(proxy_bypass, ai->proxyBypass);
1125 pi->lpszProxyBypass = proxy_bypass;
1128 *size = sizeof(INTERNET_PROXY_INFOW) + proxyBytesRequired + proxyBypassBytesRequired;
1129 return ERROR_SUCCESS;
1130 }else {
1131 INTERNET_PROXY_INFOA *pi = (INTERNET_PROXY_INFOA *)buffer;
1132 DWORD proxyBytesRequired = 0, proxyBypassBytesRequired = 0;
1133 LPSTR proxy, proxy_bypass;
1135 if (ai->proxy)
1136 proxyBytesRequired = WideCharToMultiByte(CP_ACP, 0, ai->proxy, -1, NULL, 0, NULL, NULL);
1137 if (ai->proxyBypass)
1138 proxyBypassBytesRequired = WideCharToMultiByte(CP_ACP, 0, ai->proxyBypass, -1,
1139 NULL, 0, NULL, NULL);
1140 if (!pi || *size < sizeof(INTERNET_PROXY_INFOA) + proxyBytesRequired + proxyBypassBytesRequired)
1142 *size = sizeof(INTERNET_PROXY_INFOA) + proxyBytesRequired + proxyBypassBytesRequired;
1143 return ERROR_INSUFFICIENT_BUFFER;
1145 proxy = (LPSTR)((LPBYTE)buffer + sizeof(INTERNET_PROXY_INFOA));
1146 proxy_bypass = (LPSTR)((LPBYTE)buffer + sizeof(INTERNET_PROXY_INFOA) + proxyBytesRequired);
1148 pi->dwAccessType = ai->accessType;
1149 pi->lpszProxy = NULL;
1150 pi->lpszProxyBypass = NULL;
1151 if (ai->proxy) {
1152 WideCharToMultiByte(CP_ACP, 0, ai->proxy, -1, proxy, proxyBytesRequired, NULL, NULL);
1153 pi->lpszProxy = proxy;
1156 if (ai->proxyBypass) {
1157 WideCharToMultiByte(CP_ACP, 0, ai->proxyBypass, -1, proxy_bypass,
1158 proxyBypassBytesRequired, NULL, NULL);
1159 pi->lpszProxyBypass = proxy_bypass;
1162 *size = sizeof(INTERNET_PROXY_INFOA) + proxyBytesRequired + proxyBypassBytesRequired;
1163 return ERROR_SUCCESS;
1166 case INTERNET_OPTION_PER_CONNECTION_OPTION: {
1167 INTERNET_PER_CONN_OPTION_LISTW *con = buffer;
1168 INTERNET_PER_CONN_OPTION_LISTA *conA = buffer;
1169 LONG res = ERROR_SUCCESS;
1170 WCHAR *url = NULL;
1171 int i;
1173 if (*size < sizeof(INTERNET_PER_CONN_OPTION_LISTW))
1174 return ERROR_INSUFFICIENT_BUFFER;
1176 EnterCriticalSection(&WININET_cs);
1178 if (global_proxy.flags & PROXY_TYPE_AUTO_DETECT)
1179 url = get_proxy_autoconfig_url();
1181 for (i = 0; i < con->dwOptionCount; i++) {
1182 INTERNET_PER_CONN_OPTIONW *optionW = con->pOptions + i;
1183 INTERNET_PER_CONN_OPTIONA *optionA = conA->pOptions + i;
1185 switch (optionW->dwOption) {
1186 case INTERNET_PER_CONN_FLAGS:
1187 optionW->Value.dwValue = global_proxy.flags;
1188 break;
1190 case INTERNET_PER_CONN_PROXY_SERVER:
1191 if (unicode)
1192 optionW->Value.pszValue = copy_optionW(global_proxy.proxy);
1193 else
1194 optionA->Value.pszValue = copy_optionA(global_proxy.proxy);
1195 break;
1197 case INTERNET_PER_CONN_PROXY_BYPASS:
1198 if (unicode)
1199 optionW->Value.pszValue = copy_optionW(global_proxy.proxyBypass);
1200 else
1201 optionA->Value.pszValue = copy_optionA(global_proxy.proxyBypass);
1202 break;
1204 case INTERNET_PER_CONN_AUTOCONFIG_URL:
1205 if (unicode)
1206 optionW->Value.pszValue = copy_optionW(global_proxy.autoconf_url);
1207 else
1208 optionA->Value.pszValue = copy_optionA(global_proxy.autoconf_url);
1209 break;
1211 case INTERNET_PER_CONN_AUTODISCOVERY_FLAGS:
1212 optionW->Value.dwValue = AUTO_PROXY_FLAG_ALWAYS_DETECT;
1213 break;
1215 case INTERNET_PER_CONN_AUTOCONFIG_LAST_DETECT_URL:
1216 if (unicode)
1217 optionW->Value.pszValue = copy_optionW(url);
1218 else
1219 optionA->Value.pszValue = copy_optionA(url);
1220 break;
1222 case INTERNET_PER_CONN_AUTOCONFIG_SECONDARY_URL:
1223 case INTERNET_PER_CONN_AUTOCONFIG_RELOAD_DELAY_MINS:
1224 case INTERNET_PER_CONN_AUTOCONFIG_LAST_DETECT_TIME:
1225 FIXME("Unhandled dwOption %ld\n", optionW->dwOption);
1226 memset(&optionW->Value, 0, sizeof(optionW->Value));
1227 break;
1229 default:
1230 FIXME("Unknown dwOption %ld\n", optionW->dwOption);
1231 res = ERROR_INVALID_PARAMETER;
1232 break;
1236 LeaveCriticalSection(&WININET_cs);
1237 return res;
1241 return INET_QueryOption(hdr, option, buffer, size, unicode);
1244 static DWORD APPINFO_SetOption(object_header_t *hdr, DWORD option, void *buf, DWORD size)
1246 appinfo_t *ai = (appinfo_t*)hdr;
1248 switch(option) {
1249 case INTERNET_OPTION_USER_AGENT:
1250 free(ai->agent);
1251 if (!(ai->agent = wcsdup(buf))) return ERROR_OUTOFMEMORY;
1252 return ERROR_SUCCESS;
1253 case INTERNET_OPTION_REFRESH:
1254 FIXME("INTERNET_OPTION_REFRESH\n");
1255 return ERROR_SUCCESS;
1256 case INTERNET_OPTION_PER_CONNECTION_OPTION: {
1257 INTERNET_PER_CONN_OPTION_LISTW *con = buf;
1258 unsigned int i;
1260 EnterCriticalSection( &WININET_cs );
1261 for (i = 0; i < con->dwOptionCount; i++) {
1262 INTERNET_PER_CONN_OPTIONW *option = con->pOptions + i;
1264 switch (option->dwOption) {
1265 case INTERNET_PER_CONN_PROXY_SERVER:
1266 free(global_proxy.proxy);
1267 global_proxy.proxy = wcsdup(option->Value.pszValue);
1268 break;
1270 case INTERNET_PER_CONN_FLAGS:
1271 if(option->Value.dwValue & ~(PROXY_TYPE_PROXY | PROXY_TYPE_DIRECT))
1272 FIXME("Unhandled flags: 0x%lx\n", option->Value.dwValue);
1273 global_proxy.flags = option->Value.dwValue;
1274 break;
1276 case INTERNET_PER_CONN_PROXY_BYPASS:
1277 free(global_proxy.proxyBypass);
1278 global_proxy.proxyBypass = wcsdup(option->Value.pszValue);
1279 break;
1281 case INTERNET_PER_CONN_AUTOCONFIG_URL:
1282 free(global_proxy.autoconf_url);
1283 global_proxy.autoconf_url = wcsdup(option->Value.pszValue);
1284 break;
1286 case INTERNET_PER_CONN_AUTODISCOVERY_FLAGS:
1287 case INTERNET_PER_CONN_AUTOCONFIG_SECONDARY_URL:
1288 case INTERNET_PER_CONN_AUTOCONFIG_RELOAD_DELAY_MINS:
1289 case INTERNET_PER_CONN_AUTOCONFIG_LAST_DETECT_TIME:
1290 case INTERNET_PER_CONN_AUTOCONFIG_LAST_DETECT_URL:
1291 FIXME("Unhandled dwOption %ld\n", option->dwOption);
1292 break;
1294 default:
1295 FIXME("Unknown dwOption %ld\n", option->dwOption);
1296 SetLastError(ERROR_INVALID_PARAMETER);
1297 break;
1300 LeaveCriticalSection( &WININET_cs );
1301 return ERROR_SUCCESS;
1305 return INET_SetOption(hdr, option, buf, size);
1308 static const object_vtbl_t APPINFOVtbl = {
1309 APPINFO_Destroy,
1310 NULL,
1311 APPINFO_QueryOption,
1312 APPINFO_SetOption,
1313 NULL,
1314 NULL,
1315 NULL,
1316 NULL
1320 /***********************************************************************
1321 * InternetOpenW (WININET.@)
1323 * Per-application initialization of wininet
1325 * RETURNS
1326 * HINTERNET on success
1327 * NULL on failure
1330 HINTERNET WINAPI InternetOpenW(LPCWSTR lpszAgent, DWORD dwAccessType,
1331 LPCWSTR lpszProxy, LPCWSTR lpszProxyBypass, DWORD dwFlags)
1333 appinfo_t *lpwai = NULL;
1335 if (TRACE_ON(wininet)) {
1336 #define FE(x) { x, #x }
1337 static const wininet_flag_info access_type[] = {
1338 FE(INTERNET_OPEN_TYPE_PRECONFIG),
1339 FE(INTERNET_OPEN_TYPE_DIRECT),
1340 FE(INTERNET_OPEN_TYPE_PROXY),
1341 FE(INTERNET_OPEN_TYPE_PRECONFIG_WITH_NO_AUTOPROXY)
1343 #undef FE
1344 DWORD i;
1345 const char *access_type_str = "Unknown";
1347 TRACE("(%s, %li, %s, %s, %li)\n", debugstr_w(lpszAgent), dwAccessType,
1348 debugstr_w(lpszProxy), debugstr_w(lpszProxyBypass), dwFlags);
1349 for (i = 0; i < ARRAY_SIZE(access_type); i++) {
1350 if (access_type[i].val == dwAccessType) {
1351 access_type_str = access_type[i].name;
1352 break;
1355 TRACE(" access type : %s\n", access_type_str);
1356 TRACE(" flags :");
1357 dump_INTERNET_FLAGS(dwFlags);
1360 /* Clear any error information */
1361 INTERNET_SetLastError(0);
1363 if((dwAccessType == INTERNET_OPEN_TYPE_PROXY) && !lpszProxy) {
1364 SetLastError(ERROR_INVALID_PARAMETER);
1365 return NULL;
1368 lpwai = alloc_object(NULL, &APPINFOVtbl, sizeof(appinfo_t));
1369 if (!lpwai) {
1370 SetLastError(ERROR_OUTOFMEMORY);
1371 return NULL;
1374 lpwai->hdr.htype = WH_HINIT;
1375 lpwai->hdr.dwFlags = dwFlags;
1376 lpwai->accessType = dwAccessType;
1377 lpwai->proxyUsername = NULL;
1378 lpwai->proxyPassword = NULL;
1380 lpwai->agent = wcsdup(lpszAgent);
1381 if(dwAccessType == INTERNET_OPEN_TYPE_PRECONFIG)
1382 INTERNET_ConfigureProxy( lpwai );
1383 else if(dwAccessType == INTERNET_OPEN_TYPE_PROXY) {
1384 lpwai->proxy = wcsdup(lpszProxy);
1385 lpwai->proxyBypass = wcsdup(lpszProxyBypass);
1388 TRACE("returning %p\n", lpwai);
1390 return lpwai->hdr.hInternet;
1394 /***********************************************************************
1395 * InternetOpenA (WININET.@)
1397 * Per-application initialization of wininet
1399 * RETURNS
1400 * HINTERNET on success
1401 * NULL on failure
1404 HINTERNET WINAPI InternetOpenA(LPCSTR lpszAgent, DWORD dwAccessType,
1405 LPCSTR lpszProxy, LPCSTR lpszProxyBypass, DWORD dwFlags)
1407 WCHAR *szAgent, *szProxy, *szBypass;
1408 HINTERNET rc;
1410 TRACE("(%s, 0x%08lx, %s, %s, 0x%08lx)\n", debugstr_a(lpszAgent),
1411 dwAccessType, debugstr_a(lpszProxy), debugstr_a(lpszProxyBypass), dwFlags);
1413 szAgent = strdupAtoW(lpszAgent);
1414 szProxy = strdupAtoW(lpszProxy);
1415 szBypass = strdupAtoW(lpszProxyBypass);
1417 rc = InternetOpenW(szAgent, dwAccessType, szProxy, szBypass, dwFlags);
1419 free(szAgent);
1420 free(szProxy);
1421 free(szBypass);
1422 return rc;
1425 /***********************************************************************
1426 * InternetGetLastResponseInfoA (WININET.@)
1428 * Return last wininet error description on the calling thread
1430 * RETURNS
1431 * TRUE on success of writing to buffer
1432 * FALSE on failure
1435 BOOL WINAPI InternetGetLastResponseInfoA(LPDWORD lpdwError,
1436 LPSTR lpszBuffer, LPDWORD lpdwBufferLength)
1438 LPWITHREADERROR lpwite = TlsGetValue(g_dwTlsErrIndex);
1440 TRACE("(%p, %p, %p)\n", lpdwError, lpszBuffer, lpdwBufferLength);
1442 if (!lpdwError || !lpdwBufferLength)
1444 SetLastError(ERROR_INVALID_PARAMETER);
1445 return FALSE;
1447 if (lpwite)
1449 if (lpszBuffer == NULL || *lpdwBufferLength < strlen(lpwite->response))
1451 *lpdwBufferLength = strlen(lpwite->response);
1452 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1453 return FALSE;
1455 *lpdwError = lpwite->dwError;
1456 if (*lpdwBufferLength)
1458 memcpy(lpszBuffer, lpwite->response, *lpdwBufferLength);
1459 lpszBuffer[*lpdwBufferLength - 1] = 0;
1460 *lpdwBufferLength = strlen(lpszBuffer);
1463 else
1465 *lpdwError = 0;
1466 *lpdwBufferLength = 0;
1469 return TRUE;
1472 /***********************************************************************
1473 * InternetGetLastResponseInfoW (WININET.@)
1475 * Return last wininet error description on the calling thread
1477 * RETURNS
1478 * TRUE on success of writing to buffer
1479 * FALSE on failure
1482 BOOL WINAPI InternetGetLastResponseInfoW(LPDWORD lpdwError,
1483 LPWSTR lpszBuffer, LPDWORD lpdwBufferLength)
1485 LPWITHREADERROR lpwite = TlsGetValue(g_dwTlsErrIndex);
1487 TRACE("(%p, %p, %p)\n", lpdwError, lpszBuffer, lpdwBufferLength);
1489 if (!lpdwError || !lpdwBufferLength)
1491 SetLastError(ERROR_INVALID_PARAMETER);
1492 return FALSE;
1494 if (lpwite)
1496 int required_size = MultiByteToWideChar(CP_ACP, 0, lpwite->response, -1, NULL, 0) - 1;
1497 if (lpszBuffer == NULL || *lpdwBufferLength < required_size)
1499 *lpdwBufferLength = required_size;
1500 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1501 return FALSE;
1503 *lpdwError = lpwite->dwError;
1504 if (*lpdwBufferLength)
1505 *lpdwBufferLength = MultiByteToWideChar(CP_ACP, 0, lpwite->response, -1, lpszBuffer, *lpdwBufferLength);
1507 else
1509 *lpdwError = 0;
1510 *lpdwBufferLength = 0;
1513 return TRUE;
1516 /***********************************************************************
1517 * InternetGetConnectedState (WININET.@)
1519 * Return connected state
1521 * RETURNS
1522 * TRUE if connected
1523 * if lpdwStatus is not null, return the status (off line,
1524 * modem, lan...) in it.
1525 * FALSE if not connected
1527 BOOL WINAPI InternetGetConnectedState(LPDWORD lpdwStatus, DWORD dwReserved)
1529 TRACE("(%p, 0x%08lx)\n", lpdwStatus, dwReserved);
1531 return InternetGetConnectedStateExW(lpdwStatus, NULL, 0, dwReserved);
1535 /***********************************************************************
1536 * InternetGetConnectedStateExW (WININET.@)
1538 * Return connected state
1540 * PARAMS
1542 * lpdwStatus [O] Flags specifying the status of the internet connection.
1543 * lpszConnectionName [O] Pointer to buffer to receive the friendly name of the internet connection.
1544 * dwNameLen [I] Size of the buffer, in characters.
1545 * dwReserved [I] Reserved. Must be set to 0.
1547 * RETURNS
1548 * TRUE if connected
1549 * if lpdwStatus is not null, return the status (off line,
1550 * modem, lan...) in it.
1551 * FALSE if not connected
1553 * NOTES
1554 * If the system has no available network connections, an empty string is
1555 * stored in lpszConnectionName. If there is a LAN connection, a localized
1556 * "LAN Connection" string is stored. Presumably, if only a dial-up
1557 * connection is available then the name of the dial-up connection is
1558 * returned. Why any application, other than the "Internet Settings" CPL,
1559 * would want to use this function instead of the simpler InternetGetConnectedStateW
1560 * function is beyond me.
1562 BOOL WINAPI InternetGetConnectedStateExW(LPDWORD lpdwStatus, LPWSTR lpszConnectionName,
1563 DWORD dwNameLen, DWORD dwReserved)
1565 IP_ADAPTER_ADDRESSES *buf = NULL, *aa;
1566 ULONG size = 0;
1567 DWORD status;
1569 TRACE("(%p, %p, %ld, 0x%08lx)\n", lpdwStatus, lpszConnectionName, dwNameLen, dwReserved);
1571 /* Must be zero */
1572 if(dwReserved)
1574 SetLastError(ERROR_INVALID_PARAMETER);
1575 return FALSE;
1578 for (;;)
1580 ULONG flags = GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER |
1581 GAA_FLAG_SKIP_FRIENDLY_NAME | GAA_FLAG_INCLUDE_GATEWAYS;
1582 ULONG errcode = GetAdaptersAddresses(AF_UNSPEC, flags, NULL, buf, &size);
1584 if (errcode == ERROR_SUCCESS)
1585 break;
1586 free(buf);
1587 if (errcode == ERROR_BUFFER_OVERFLOW && !(buf = malloc(size)))
1588 errcode = ERROR_NOT_ENOUGH_MEMORY;
1589 if (errcode != ERROR_BUFFER_OVERFLOW)
1591 if (errcode != ERROR_NO_DATA)
1593 SetLastError(errcode);
1594 return FALSE;
1596 buf = NULL;
1597 break;
1601 status = INTERNET_RAS_INSTALLED;
1602 for (aa = buf; aa; aa = aa->Next)
1604 /* Connected, but not necessarily to internet */
1605 if (aa->FirstUnicastAddress)
1606 status |= INTERNET_CONNECTION_OFFLINE;
1608 /* Connected to internet */
1609 if (aa->FirstGatewayAddress)
1611 WARN("always returning LAN connection.\n");
1612 status &= ~INTERNET_CONNECTION_OFFLINE;
1613 status |= INTERNET_CONNECTION_LAN;
1614 break;
1617 free(buf);
1619 if (lpdwStatus) *lpdwStatus = status;
1621 /* When the buffer size is zero LoadStringW fills the buffer with a pointer to
1622 * the resource, avoid it as we must not change the buffer in this case */
1623 if (lpszConnectionName && dwNameLen)
1625 *lpszConnectionName = '\0';
1626 if (status & INTERNET_CONNECTION_LAN)
1627 LoadStringW(WININET_hModule, IDS_LANCONNECTION, lpszConnectionName, dwNameLen);
1630 if (!(status & (INTERNET_CONNECTION_LAN | INTERNET_CONNECTION_MODEM | INTERNET_CONNECTION_PROXY)))
1632 SetLastError(ERROR_SUCCESS);
1633 return FALSE;
1635 return TRUE;
1639 /***********************************************************************
1640 * InternetGetConnectedStateExA (WININET.@)
1642 BOOL WINAPI InternetGetConnectedStateExA(LPDWORD lpdwStatus, LPSTR lpszConnectionName,
1643 DWORD dwNameLen, DWORD dwReserved)
1645 LPWSTR lpwszConnectionName = NULL;
1646 BOOL rc;
1648 TRACE("(%p, %p, %ld, 0x%08lx)\n", lpdwStatus, lpszConnectionName, dwNameLen, dwReserved);
1650 if (lpszConnectionName && dwNameLen > 0)
1651 lpwszConnectionName = malloc(dwNameLen * sizeof(WCHAR));
1653 rc = InternetGetConnectedStateExW(lpdwStatus,lpwszConnectionName, dwNameLen,
1654 dwReserved);
1655 if (rc && lpwszConnectionName)
1657 WideCharToMultiByte(CP_ACP,0,lpwszConnectionName,-1,lpszConnectionName,
1658 dwNameLen, NULL, NULL);
1659 /* Yes, blindly truncate double-byte characters */
1660 lpszConnectionName[dwNameLen - 1] = '\0';
1663 free(lpwszConnectionName);
1664 return rc;
1668 /***********************************************************************
1669 * InternetConnectW (WININET.@)
1671 * Open a ftp, gopher or http session
1673 * RETURNS
1674 * HINTERNET a session handle on success
1675 * NULL on failure
1678 HINTERNET WINAPI InternetConnectW(HINTERNET hInternet,
1679 LPCWSTR lpszServerName, INTERNET_PORT nServerPort,
1680 LPCWSTR lpszUserName, LPCWSTR lpszPassword,
1681 DWORD dwService, DWORD dwFlags, DWORD_PTR dwContext)
1683 appinfo_t *hIC;
1684 HINTERNET rc = NULL;
1685 DWORD res = ERROR_SUCCESS;
1687 TRACE("(%p, %s, %u, %s, %p, %lu, %lx, %Ix)\n", hInternet, debugstr_w(lpszServerName),
1688 nServerPort, debugstr_w(lpszUserName), lpszPassword, dwService, dwFlags, dwContext);
1690 if (!lpszServerName)
1692 SetLastError(ERROR_INVALID_PARAMETER);
1693 return NULL;
1696 hIC = (appinfo_t*)get_handle_object( hInternet );
1697 if ( (hIC == NULL) || (hIC->hdr.htype != WH_HINIT) )
1699 res = ERROR_INVALID_HANDLE;
1700 goto lend;
1703 switch (dwService)
1705 case INTERNET_SERVICE_FTP:
1706 rc = FTP_Connect(hIC, lpszServerName, nServerPort,
1707 lpszUserName, lpszPassword, dwFlags, dwContext, 0);
1708 if(!rc)
1709 res = INTERNET_GetLastError();
1710 break;
1712 case INTERNET_SERVICE_HTTP:
1713 res = HTTP_Connect(hIC, lpszServerName, nServerPort,
1714 lpszUserName, lpszPassword, dwFlags, dwContext, 0, &rc);
1715 break;
1717 case INTERNET_SERVICE_GOPHER:
1718 default:
1719 break;
1721 lend:
1722 if( hIC )
1723 WININET_Release( &hIC->hdr );
1725 TRACE("returning %p\n", rc);
1726 SetLastError(res);
1727 return rc;
1731 /***********************************************************************
1732 * InternetConnectA (WININET.@)
1734 * Open a ftp, gopher or http session
1736 * RETURNS
1737 * HINTERNET a session handle on success
1738 * NULL on failure
1741 HINTERNET WINAPI InternetConnectA(HINTERNET hInternet,
1742 LPCSTR lpszServerName, INTERNET_PORT nServerPort,
1743 LPCSTR lpszUserName, LPCSTR lpszPassword,
1744 DWORD dwService, DWORD dwFlags, DWORD_PTR dwContext)
1746 HINTERNET rc = NULL;
1747 LPWSTR szServerName;
1748 LPWSTR szUserName;
1749 LPWSTR szPassword;
1751 szServerName = strdupAtoW(lpszServerName);
1752 szUserName = strdupAtoW(lpszUserName);
1753 szPassword = strdupAtoW(lpszPassword);
1755 rc = InternetConnectW(hInternet, szServerName, nServerPort,
1756 szUserName, szPassword, dwService, dwFlags, dwContext);
1758 free(szServerName);
1759 free(szUserName);
1760 free(szPassword);
1761 return rc;
1765 /***********************************************************************
1766 * InternetFindNextFileA (WININET.@)
1768 * Continues a file search from a previous call to FindFirstFile
1770 * RETURNS
1771 * TRUE on success
1772 * FALSE on failure
1775 BOOL WINAPI InternetFindNextFileA(HINTERNET hFind, LPVOID lpvFindData)
1777 BOOL ret;
1778 WIN32_FIND_DATAW fd;
1780 ret = InternetFindNextFileW(hFind, lpvFindData?&fd:NULL);
1781 if(lpvFindData)
1782 WININET_find_data_WtoA(&fd, (LPWIN32_FIND_DATAA)lpvFindData);
1783 return ret;
1786 /***********************************************************************
1787 * InternetFindNextFileW (WININET.@)
1789 * Continues a file search from a previous call to FindFirstFile
1791 * RETURNS
1792 * TRUE on success
1793 * FALSE on failure
1796 BOOL WINAPI InternetFindNextFileW(HINTERNET hFind, LPVOID lpvFindData)
1798 object_header_t *hdr;
1799 DWORD res;
1801 TRACE("\n");
1803 hdr = get_handle_object(hFind);
1804 if(!hdr) {
1805 WARN("Invalid handle\n");
1806 SetLastError(ERROR_INVALID_HANDLE);
1807 return FALSE;
1810 if(hdr->vtbl->FindNextFileW) {
1811 res = hdr->vtbl->FindNextFileW(hdr, lpvFindData);
1812 }else {
1813 WARN("Handle doesn't support NextFile\n");
1814 res = ERROR_INTERNET_INCORRECT_HANDLE_TYPE;
1817 WININET_Release(hdr);
1819 if(res != ERROR_SUCCESS)
1820 SetLastError(res);
1821 return res == ERROR_SUCCESS;
1824 /***********************************************************************
1825 * InternetCloseHandle (WININET.@)
1827 * Generic close handle function
1829 * RETURNS
1830 * TRUE on success
1831 * FALSE on failure
1834 BOOL WINAPI InternetCloseHandle(HINTERNET hInternet)
1836 object_header_t *obj;
1838 TRACE("%p\n", hInternet);
1840 obj = get_handle_object( hInternet );
1841 if (!obj) {
1842 SetLastError(ERROR_INVALID_HANDLE);
1843 return FALSE;
1846 invalidate_handle(obj);
1847 WININET_Release(obj);
1849 return TRUE;
1852 static BOOL set_url_component(WCHAR **component, DWORD *component_length, const WCHAR *value, DWORD len)
1854 TRACE("%s (%ld)\n", debugstr_wn(value, len), len);
1856 if (!*component_length)
1857 return TRUE;
1859 if (!*component) {
1860 *(const WCHAR**)component = value;
1861 *component_length = len;
1862 return TRUE;
1865 if (*component_length < len+1) {
1866 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1867 return FALSE;
1870 *component_length = len;
1871 if(len)
1872 memcpy(*component, value, len*sizeof(WCHAR));
1873 (*component)[len] = 0;
1874 return TRUE;
1877 static BOOL set_url_component_WtoA(const WCHAR *comp_w, DWORD length, const WCHAR *url_w, char **comp, DWORD *ret_length,
1878 const char *url_a)
1880 size_t size, ret_size = *ret_length;
1882 if (!*ret_length)
1883 return TRUE;
1884 size = WideCharToMultiByte(CP_ACP, 0, comp_w, length, NULL, 0, NULL, NULL);
1886 if (!*comp) {
1887 *comp = comp_w ? (char*)url_a + WideCharToMultiByte(CP_ACP, 0, url_w, comp_w-url_w, NULL, 0, NULL, NULL) : NULL;
1888 *ret_length = size;
1889 return TRUE;
1892 if (size+1 > ret_size) {
1893 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1894 *ret_length = size+1;
1895 return FALSE;
1898 *ret_length = size;
1899 WideCharToMultiByte(CP_ACP, 0, comp_w, length, *comp, ret_size-1, NULL, NULL);
1900 (*comp)[size] = 0;
1901 return TRUE;
1904 static BOOL set_url_component_AtoW(const char *comp_a, DWORD len_a, WCHAR **comp_w, DWORD *len_w, WCHAR **buf)
1906 *len_w = len_a;
1908 if(!comp_a) {
1909 *comp_w = NULL;
1910 return TRUE;
1913 if(!(*comp_w = *buf = malloc(len_a * sizeof(WCHAR)))) {
1914 SetLastError(ERROR_OUTOFMEMORY);
1915 return FALSE;
1918 return TRUE;
1921 /***********************************************************************
1922 * InternetCrackUrlA (WININET.@)
1924 * See InternetCrackUrlW.
1926 BOOL WINAPI InternetCrackUrlA(const char *url, DWORD url_length, DWORD flags, URL_COMPONENTSA *ret_comp)
1928 WCHAR *host = NULL, *user = NULL, *pass = NULL, *path = NULL, *scheme = NULL, *extra = NULL;
1929 URL_COMPONENTSW comp;
1930 WCHAR *url_w = NULL;
1931 BOOL ret;
1933 TRACE("(%s %lu %lx %p)\n", url_length ? debugstr_an(url, url_length) : debugstr_a(url), url_length, flags, ret_comp);
1935 if (!url || !*url || !ret_comp || ret_comp->dwStructSize != sizeof(URL_COMPONENTSA)) {
1936 SetLastError(ERROR_INVALID_PARAMETER);
1937 return FALSE;
1940 comp.dwStructSize = sizeof(comp);
1942 ret = set_url_component_AtoW(ret_comp->lpszHostName, ret_comp->dwHostNameLength,
1943 &comp.lpszHostName, &comp.dwHostNameLength, &host)
1944 && set_url_component_AtoW(ret_comp->lpszUserName, ret_comp->dwUserNameLength,
1945 &comp.lpszUserName, &comp.dwUserNameLength, &user)
1946 && set_url_component_AtoW(ret_comp->lpszPassword, ret_comp->dwPasswordLength,
1947 &comp.lpszPassword, &comp.dwPasswordLength, &pass)
1948 && set_url_component_AtoW(ret_comp->lpszUrlPath, ret_comp->dwUrlPathLength,
1949 &comp.lpszUrlPath, &comp.dwUrlPathLength, &path)
1950 && set_url_component_AtoW(ret_comp->lpszScheme, ret_comp->dwSchemeLength,
1951 &comp.lpszScheme, &comp.dwSchemeLength, &scheme)
1952 && set_url_component_AtoW(ret_comp->lpszExtraInfo, ret_comp->dwExtraInfoLength,
1953 &comp.lpszExtraInfo, &comp.dwExtraInfoLength, &extra);
1955 if(ret && !(url_w = strndupAtoW(url, url_length ? url_length : -1, &url_length))) {
1956 SetLastError(ERROR_OUTOFMEMORY);
1957 ret = FALSE;
1960 if (ret && (ret = InternetCrackUrlW(url_w, url_length, flags, &comp))) {
1961 ret_comp->nScheme = comp.nScheme;
1962 ret_comp->nPort = comp.nPort;
1964 ret = set_url_component_WtoA(comp.lpszHostName, comp.dwHostNameLength, url_w,
1965 &ret_comp->lpszHostName, &ret_comp->dwHostNameLength, url)
1966 && set_url_component_WtoA(comp.lpszUserName, comp.dwUserNameLength, url_w,
1967 &ret_comp->lpszUserName, &ret_comp->dwUserNameLength, url)
1968 && set_url_component_WtoA(comp.lpszPassword, comp.dwPasswordLength, url_w,
1969 &ret_comp->lpszPassword, &ret_comp->dwPasswordLength, url)
1970 && set_url_component_WtoA(comp.lpszUrlPath, comp.dwUrlPathLength, url_w,
1971 &ret_comp->lpszUrlPath, &ret_comp->dwUrlPathLength, url)
1972 && set_url_component_WtoA(comp.lpszScheme, comp.dwSchemeLength, url_w,
1973 &ret_comp->lpszScheme, &ret_comp->dwSchemeLength, url)
1974 && set_url_component_WtoA(comp.lpszExtraInfo, comp.dwExtraInfoLength, url_w,
1975 &ret_comp->lpszExtraInfo, &ret_comp->dwExtraInfoLength, url);
1977 if(ret)
1978 TRACE("%s: scheme(%s) host(%s) path(%s) extra(%s)\n", debugstr_a(url),
1979 debugstr_an(ret_comp->lpszScheme, ret_comp->dwSchemeLength),
1980 debugstr_an(ret_comp->lpszHostName, ret_comp->dwHostNameLength),
1981 debugstr_an(ret_comp->lpszUrlPath, ret_comp->dwUrlPathLength),
1982 debugstr_an(ret_comp->lpszExtraInfo, ret_comp->dwExtraInfoLength));
1985 free(host);
1986 free(user);
1987 free(pass);
1988 free(path);
1989 free(scheme);
1990 free(extra);
1991 free(url_w);
1992 return ret;
1995 static const WCHAR *url_schemes[] =
1997 L"ftp",
1998 L"gopher",
1999 L"http",
2000 L"https",
2001 L"file",
2002 L"news",
2003 L"mailto",
2004 L"socks",
2005 L"javascript",
2006 L"vbscript",
2007 L"res"
2010 /***********************************************************************
2011 * GetInternetSchemeW (internal)
2013 * Get scheme of url
2015 * RETURNS
2016 * scheme on success
2017 * INTERNET_SCHEME_UNKNOWN on failure
2020 static INTERNET_SCHEME GetInternetSchemeW(LPCWSTR lpszScheme, DWORD nMaxCmp)
2022 int i;
2024 TRACE("%s %ld\n",debugstr_wn(lpszScheme, nMaxCmp), nMaxCmp);
2026 if(lpszScheme==NULL)
2027 return INTERNET_SCHEME_UNKNOWN;
2029 for (i = 0; i < ARRAY_SIZE(url_schemes); i++)
2030 if (!wcsnicmp(lpszScheme, url_schemes[i], nMaxCmp))
2031 return INTERNET_SCHEME_FIRST + i;
2033 return INTERNET_SCHEME_UNKNOWN;
2036 /***********************************************************************
2037 * InternetCrackUrlW (WININET.@)
2039 * Break up URL into its components
2041 * RETURNS
2042 * TRUE on success
2043 * FALSE on failure
2045 BOOL WINAPI InternetCrackUrlW(const WCHAR *lpszUrl, DWORD dwUrlLength, DWORD dwFlags, URL_COMPONENTSW *lpUC)
2048 * RFC 1808
2049 * <protocol>:[//<net_loc>][/path][;<params>][?<query>][#<fragment>]
2052 LPCWSTR lpszParam = NULL;
2053 BOOL found_colon = FALSE;
2054 LPCWSTR lpszap;
2055 LPCWSTR lpszcp = NULL, lpszNetLoc;
2057 TRACE("(%s %lu %lx %p)\n",
2058 lpszUrl ? debugstr_wn(lpszUrl, dwUrlLength ? dwUrlLength : lstrlenW(lpszUrl)) : "(null)",
2059 dwUrlLength, dwFlags, lpUC);
2061 if (!lpszUrl || !*lpszUrl || !lpUC)
2063 SetLastError(ERROR_INVALID_PARAMETER);
2064 return FALSE;
2067 if (!dwUrlLength)
2068 dwUrlLength = lstrlenW(lpszUrl);
2069 else {
2070 /* Windows stops at a null, regardless of what dwUrlLength says. */
2071 dwUrlLength = wcsnlen(lpszUrl, dwUrlLength);
2074 if (dwFlags & ICU_DECODE)
2076 WCHAR *url_tmp, *buffer;
2077 DWORD len = dwUrlLength + 1;
2078 BOOL ret;
2080 if (!(url_tmp = strndupW(lpszUrl, dwUrlLength)))
2082 SetLastError(ERROR_OUTOFMEMORY);
2083 return FALSE;
2086 buffer = url_tmp;
2087 ret = InternetCanonicalizeUrlW(url_tmp, buffer, &len, ICU_DECODE | ICU_NO_ENCODE);
2088 if (!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
2090 buffer = malloc(len * sizeof(WCHAR));
2091 if (!buffer)
2093 SetLastError(ERROR_OUTOFMEMORY);
2094 free(url_tmp);
2095 return FALSE;
2097 ret = InternetCanonicalizeUrlW(url_tmp, buffer, &len, ICU_DECODE | ICU_NO_ENCODE);
2099 if (ret)
2100 ret = InternetCrackUrlW(buffer, len, dwFlags & ~ICU_DECODE, lpUC);
2102 if (buffer != url_tmp) free(buffer);
2103 free(url_tmp);
2104 return ret;
2106 lpszap = lpszUrl;
2108 /* Determine if the URI is absolute. */
2109 while (lpszap - lpszUrl < dwUrlLength)
2111 if (iswalnum(*lpszap) || *lpszap == '+' || *lpszap == '.' || *lpszap == '-')
2113 lpszap++;
2114 continue;
2116 if (*lpszap == ':')
2118 found_colon = TRUE;
2119 lpszcp = lpszap;
2121 else
2123 lpszcp = lpszUrl; /* Relative url */
2126 break;
2129 if(!found_colon){
2130 SetLastError(ERROR_INTERNET_UNRECOGNIZED_SCHEME);
2131 return FALSE;
2134 lpUC->nScheme = INTERNET_SCHEME_UNKNOWN;
2135 lpUC->nPort = INTERNET_INVALID_PORT_NUMBER;
2137 /* Parse <params> */
2138 lpszParam = wmemchr(lpszap, '?', dwUrlLength - (lpszap - lpszUrl));
2139 if(!lpszParam)
2140 lpszParam = wmemchr(lpszap, '#', dwUrlLength - (lpszap - lpszUrl));
2142 if(!set_url_component(&lpUC->lpszExtraInfo, &lpUC->dwExtraInfoLength,
2143 lpszParam, lpszParam ? dwUrlLength-(lpszParam-lpszUrl) : 0))
2144 return FALSE;
2147 /* Get scheme first. */
2148 lpUC->nScheme = GetInternetSchemeW(lpszUrl, lpszcp - lpszUrl);
2149 if(!set_url_component(&lpUC->lpszScheme, &lpUC->dwSchemeLength, lpszUrl, lpszcp - lpszUrl))
2150 return FALSE;
2152 /* Eat ':' in protocol. */
2153 lpszcp++;
2155 /* double slash indicates the net_loc portion is present */
2156 if ((lpszcp[0] == '/') && (lpszcp[1] == '/'))
2158 lpszcp += 2;
2160 lpszNetLoc = wmemchr(lpszcp, '/', dwUrlLength - (lpszcp - lpszUrl));
2161 if (lpszParam)
2163 if (lpszNetLoc)
2164 lpszNetLoc = min(lpszNetLoc, lpszParam);
2165 else
2166 lpszNetLoc = lpszParam;
2168 else if (!lpszNetLoc)
2169 lpszNetLoc = lpszcp + dwUrlLength-(lpszcp-lpszUrl);
2171 /* Parse net-loc */
2172 if (lpszNetLoc)
2174 LPCWSTR lpszHost;
2175 LPCWSTR lpszPort;
2177 /* [<user>[<:password>]@]<host>[:<port>] */
2178 /* First find the user and password if they exist */
2180 lpszHost = wmemchr(lpszcp, '@', dwUrlLength - (lpszcp - lpszUrl));
2181 if (lpszHost == NULL || lpszHost > lpszNetLoc)
2183 /* username and password not specified. */
2184 set_url_component(&lpUC->lpszUserName, &lpUC->dwUserNameLength, NULL, 0);
2185 set_url_component(&lpUC->lpszPassword, &lpUC->dwPasswordLength, NULL, 0);
2187 else /* Parse out username and password */
2189 LPCWSTR lpszUser = lpszcp;
2190 LPCWSTR lpszPasswd = lpszHost;
2192 while (lpszcp < lpszHost)
2194 if (*lpszcp == ':')
2195 lpszPasswd = lpszcp;
2197 lpszcp++;
2200 if(!set_url_component(&lpUC->lpszUserName, &lpUC->dwUserNameLength, lpszUser, lpszPasswd - lpszUser))
2201 return FALSE;
2203 if (lpszPasswd != lpszHost)
2204 lpszPasswd++;
2205 if(!set_url_component(&lpUC->lpszPassword, &lpUC->dwPasswordLength,
2206 lpszPasswd == lpszHost ? NULL : lpszPasswd, lpszHost - lpszPasswd))
2207 return FALSE;
2209 lpszcp++; /* Advance to beginning of host */
2212 /* Parse <host><:port> */
2214 lpszHost = lpszcp;
2215 lpszPort = lpszNetLoc;
2217 /* special case for res:// URLs: there is no port here, so the host is the
2218 entire string up to the first '/' */
2219 if(lpUC->nScheme==INTERNET_SCHEME_RES)
2221 if(!set_url_component(&lpUC->lpszHostName, &lpUC->dwHostNameLength, lpszHost, lpszPort - lpszHost))
2222 return FALSE;
2223 lpszcp=lpszNetLoc;
2225 else
2227 while (lpszcp < lpszNetLoc)
2229 if (*lpszcp == ':')
2230 lpszPort = lpszcp;
2232 lpszcp++;
2235 /* If the scheme is "file" and the host is just one letter, it's not a host */
2236 if(lpUC->nScheme==INTERNET_SCHEME_FILE && lpszPort <= lpszHost+1)
2238 lpszcp=lpszHost;
2239 set_url_component(&lpUC->lpszHostName, &lpUC->dwHostNameLength, NULL, 0);
2241 else
2243 if(!set_url_component(&lpUC->lpszHostName, &lpUC->dwHostNameLength, lpszHost, lpszPort - lpszHost))
2244 return FALSE;
2245 if (lpszPort != lpszNetLoc)
2246 lpUC->nPort = wcstol(++lpszPort, NULL, 10);
2247 else switch (lpUC->nScheme)
2249 case INTERNET_SCHEME_HTTP:
2250 lpUC->nPort = INTERNET_DEFAULT_HTTP_PORT;
2251 break;
2252 case INTERNET_SCHEME_HTTPS:
2253 lpUC->nPort = INTERNET_DEFAULT_HTTPS_PORT;
2254 break;
2255 case INTERNET_SCHEME_FTP:
2256 lpUC->nPort = INTERNET_DEFAULT_FTP_PORT;
2257 break;
2258 default:
2259 break;
2265 else
2267 set_url_component(&lpUC->lpszUserName, &lpUC->dwUserNameLength, NULL, 0);
2268 set_url_component(&lpUC->lpszPassword, &lpUC->dwPasswordLength, NULL, 0);
2269 set_url_component(&lpUC->lpszHostName, &lpUC->dwHostNameLength, NULL, 0);
2272 /* Here lpszcp points to:
2274 * <protocol>:[//<net_loc>][/path][;<params>][?<query>][#<fragment>]
2275 * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2277 if (lpszcp != 0 && lpszcp - lpszUrl < dwUrlLength && (!lpszParam || lpszcp <= lpszParam))
2279 DWORD len;
2281 /* Only truncate the parameter list if it's already been saved
2282 * in lpUC->lpszExtraInfo.
2284 if (lpszParam && lpUC->dwExtraInfoLength && lpUC->lpszExtraInfo)
2285 len = lpszParam - lpszcp;
2286 else
2288 /* Leave the parameter list in lpszUrlPath. Strip off any trailing
2289 * newlines if necessary.
2291 LPWSTR lpsznewline = wmemchr(lpszcp, '\n', dwUrlLength - (lpszcp - lpszUrl));
2292 if (lpsznewline != NULL)
2293 len = lpsznewline - lpszcp;
2294 else
2295 len = dwUrlLength-(lpszcp-lpszUrl);
2297 if (lpUC->dwUrlPathLength && lpUC->lpszUrlPath &&
2298 lpUC->nScheme == INTERNET_SCHEME_FILE)
2300 WCHAR tmppath[MAX_PATH];
2301 if (*lpszcp == '/')
2303 len = MAX_PATH;
2304 PathCreateFromUrlW(lpszUrl, tmppath, &len, 0);
2306 else
2308 WCHAR *iter;
2309 memcpy(tmppath, lpszcp, len * sizeof(WCHAR));
2310 tmppath[len] = '\0';
2312 iter = tmppath;
2313 while (*iter) {
2314 if (*iter == '/')
2315 *iter = '\\';
2316 ++iter;
2319 /* if ends in \. or \.. append a backslash */
2320 if (tmppath[len - 1] == '.' &&
2321 (tmppath[len - 2] == '\\' ||
2322 (tmppath[len - 2] == '.' && tmppath[len - 3] == '\\')))
2324 if (len < MAX_PATH - 1)
2326 tmppath[len] = '\\';
2327 tmppath[len+1] = '\0';
2328 ++len;
2331 if(!set_url_component(&lpUC->lpszUrlPath, &lpUC->dwUrlPathLength, tmppath, len))
2332 return FALSE;
2334 else if(!set_url_component(&lpUC->lpszUrlPath, &lpUC->dwUrlPathLength, lpszcp, len))
2335 return FALSE;
2337 else
2339 set_url_component(&lpUC->lpszUrlPath, &lpUC->dwUrlPathLength, lpszcp, 0);
2342 TRACE("%s: scheme(%s) host(%s) path(%s) extra(%s)\n", debugstr_wn(lpszUrl,dwUrlLength),
2343 debugstr_wn(lpUC->lpszScheme,lpUC->dwSchemeLength),
2344 debugstr_wn(lpUC->lpszHostName,lpUC->dwHostNameLength),
2345 debugstr_wn(lpUC->lpszUrlPath,lpUC->dwUrlPathLength),
2346 debugstr_wn(lpUC->lpszExtraInfo,lpUC->dwExtraInfoLength));
2348 return TRUE;
2351 /***********************************************************************
2352 * InternetAttemptConnect (WININET.@)
2354 * Attempt to make a connection to the internet
2356 * RETURNS
2357 * ERROR_SUCCESS on success
2358 * Error value on failure
2361 DWORD WINAPI InternetAttemptConnect(DWORD dwReserved)
2363 FIXME("Stub\n");
2364 return ERROR_SUCCESS;
2368 /***********************************************************************
2369 * convert_url_canonicalization_flags
2371 * Helper for InternetCanonicalizeUrl
2373 * PARAMS
2374 * dwFlags [I] Flags suitable for InternetCanonicalizeUrl
2376 * RETURNS
2377 * Flags suitable for UrlCanonicalize
2379 static DWORD convert_url_canonicalization_flags(DWORD dwFlags)
2381 DWORD dwUrlFlags = URL_WININET_COMPATIBILITY | URL_ESCAPE_UNSAFE;
2383 if (dwFlags & ICU_BROWSER_MODE) dwUrlFlags |= URL_BROWSER_MODE;
2384 if (dwFlags & ICU_DECODE) dwUrlFlags |= URL_UNESCAPE;
2385 if (dwFlags & ICU_ENCODE_PERCENT) dwUrlFlags |= URL_ESCAPE_PERCENT;
2386 if (dwFlags & ICU_ENCODE_SPACES_ONLY) dwUrlFlags |= URL_ESCAPE_SPACES_ONLY;
2387 /* Flip this bit to correspond to URL_ESCAPE_UNSAFE */
2388 if (dwFlags & ICU_NO_ENCODE) dwUrlFlags ^= URL_ESCAPE_UNSAFE;
2389 if (dwFlags & ICU_NO_META) dwUrlFlags |= URL_NO_META;
2391 return dwUrlFlags;
2394 /***********************************************************************
2395 * InternetCanonicalizeUrlA (WININET.@)
2397 * Escape unsafe characters and spaces
2399 * RETURNS
2400 * TRUE on success
2401 * FALSE on failure
2404 BOOL WINAPI InternetCanonicalizeUrlA(LPCSTR lpszUrl, LPSTR lpszBuffer,
2405 LPDWORD lpdwBufferLength, DWORD dwFlags)
2407 HRESULT hr;
2409 TRACE("(%s, %p, %p, 0x%08lx) buffer length: %ld\n", debugstr_a(lpszUrl), lpszBuffer,
2410 lpdwBufferLength, dwFlags, lpdwBufferLength ? *lpdwBufferLength : -1);
2412 dwFlags = convert_url_canonicalization_flags(dwFlags);
2413 hr = UrlCanonicalizeA(lpszUrl, lpszBuffer, lpdwBufferLength, dwFlags);
2414 if (hr == E_POINTER) SetLastError(ERROR_INSUFFICIENT_BUFFER);
2415 if (hr == E_INVALIDARG) SetLastError(ERROR_INVALID_PARAMETER);
2417 return hr == S_OK;
2420 /***********************************************************************
2421 * InternetCanonicalizeUrlW (WININET.@)
2423 * Escape unsafe characters and spaces
2425 * RETURNS
2426 * TRUE on success
2427 * FALSE on failure
2430 BOOL WINAPI InternetCanonicalizeUrlW(LPCWSTR lpszUrl, LPWSTR lpszBuffer,
2431 LPDWORD lpdwBufferLength, DWORD dwFlags)
2433 HRESULT hr;
2435 TRACE("(%s, %p, %p, 0x%08lx) buffer length: %ld\n", debugstr_w(lpszUrl), lpszBuffer,
2436 lpdwBufferLength, dwFlags, lpdwBufferLength ? *lpdwBufferLength : -1);
2438 dwFlags = convert_url_canonicalization_flags(dwFlags);
2439 hr = UrlCanonicalizeW(lpszUrl, lpszBuffer, lpdwBufferLength, dwFlags);
2440 if (hr == E_POINTER) SetLastError(ERROR_INSUFFICIENT_BUFFER);
2441 if (hr == E_INVALIDARG) SetLastError(ERROR_INVALID_PARAMETER);
2443 return hr == S_OK;
2446 /* #################################################### */
2448 static INTERNET_STATUS_CALLBACK set_status_callback(
2449 object_header_t *lpwh, INTERNET_STATUS_CALLBACK callback, BOOL unicode)
2451 INTERNET_STATUS_CALLBACK ret;
2453 if (unicode) lpwh->dwInternalFlags |= INET_CALLBACKW;
2454 else lpwh->dwInternalFlags &= ~INET_CALLBACKW;
2456 ret = lpwh->lpfnStatusCB;
2457 lpwh->lpfnStatusCB = callback;
2459 return ret;
2462 /***********************************************************************
2463 * InternetSetStatusCallbackA (WININET.@)
2465 * Sets up a callback function which is called as progress is made
2466 * during an operation.
2468 * RETURNS
2469 * Previous callback or NULL on success
2470 * INTERNET_INVALID_STATUS_CALLBACK on failure
2473 INTERNET_STATUS_CALLBACK WINAPI InternetSetStatusCallbackA(
2474 HINTERNET hInternet ,INTERNET_STATUS_CALLBACK lpfnIntCB)
2476 INTERNET_STATUS_CALLBACK retVal;
2477 object_header_t *lpwh;
2479 TRACE("%p\n", hInternet);
2481 if (!(lpwh = get_handle_object(hInternet)))
2482 return INTERNET_INVALID_STATUS_CALLBACK;
2484 retVal = set_status_callback(lpwh, lpfnIntCB, FALSE);
2486 WININET_Release( lpwh );
2487 return retVal;
2490 /***********************************************************************
2491 * InternetSetStatusCallbackW (WININET.@)
2493 * Sets up a callback function which is called as progress is made
2494 * during an operation.
2496 * RETURNS
2497 * Previous callback or NULL on success
2498 * INTERNET_INVALID_STATUS_CALLBACK on failure
2501 INTERNET_STATUS_CALLBACK WINAPI InternetSetStatusCallbackW(
2502 HINTERNET hInternet ,INTERNET_STATUS_CALLBACK lpfnIntCB)
2504 INTERNET_STATUS_CALLBACK retVal;
2505 object_header_t *lpwh;
2507 TRACE("%p\n", hInternet);
2509 if (!(lpwh = get_handle_object(hInternet)))
2510 return INTERNET_INVALID_STATUS_CALLBACK;
2512 retVal = set_status_callback(lpwh, lpfnIntCB, TRUE);
2514 WININET_Release( lpwh );
2515 return retVal;
2518 /***********************************************************************
2519 * InternetSetFilePointer (WININET.@)
2521 * Sets read position for an open internet file.
2523 * RETURNS
2524 * Current position of the file on success
2525 * INVALID_SET_FILE_POINTER on failure
2527 DWORD WINAPI InternetSetFilePointer(HINTERNET hFile, LONG lDistanceToMove,
2528 PVOID pReserved, DWORD dwMoveContext, DWORD_PTR dwContext)
2530 object_header_t *hdr;
2531 DWORD res;
2533 TRACE("(%p %ld %p %ld %Ix)\n", hFile, lDistanceToMove, pReserved, dwMoveContext, dwContext);
2535 hdr = get_handle_object(hFile);
2536 if(!hdr) {
2537 SetLastError(ERROR_INVALID_HANDLE);
2538 return INVALID_SET_FILE_POINTER;
2541 if(hdr->vtbl->SetFilePointer) {
2542 res = hdr->vtbl->SetFilePointer(hdr, lDistanceToMove, dwMoveContext);
2543 }else {
2544 SetLastError(ERROR_INVALID_HANDLE);
2545 res = INVALID_SET_FILE_POINTER;
2548 WININET_Release(hdr);
2549 return res;
2552 /***********************************************************************
2553 * InternetWriteFile (WININET.@)
2555 * Write data to an open internet file
2557 * RETURNS
2558 * TRUE on success
2559 * FALSE on failure
2562 BOOL WINAPI InternetWriteFile(HINTERNET hFile, LPCVOID lpBuffer,
2563 DWORD dwNumOfBytesToWrite, LPDWORD lpdwNumOfBytesWritten)
2565 object_header_t *lpwh;
2566 BOOL res;
2568 TRACE("(%p %p %ld %p)\n", hFile, lpBuffer, dwNumOfBytesToWrite, lpdwNumOfBytesWritten);
2570 lpwh = get_handle_object( hFile );
2571 if (!lpwh) {
2572 WARN("Invalid handle\n");
2573 SetLastError(ERROR_INVALID_HANDLE);
2574 return FALSE;
2577 if(lpwh->vtbl->WriteFile) {
2578 res = lpwh->vtbl->WriteFile(lpwh, lpBuffer, dwNumOfBytesToWrite, lpdwNumOfBytesWritten);
2579 }else {
2580 WARN("No Writefile method.\n");
2581 res = ERROR_INVALID_HANDLE;
2584 WININET_Release( lpwh );
2586 if(res != ERROR_SUCCESS)
2587 SetLastError(res);
2588 return res == ERROR_SUCCESS;
2592 /***********************************************************************
2593 * InternetReadFile (WININET.@)
2595 * Read data from an open internet file
2597 * RETURNS
2598 * TRUE on success
2599 * FALSE on failure
2602 BOOL WINAPI InternetReadFile(HINTERNET hFile, LPVOID lpBuffer,
2603 DWORD dwNumOfBytesToRead, LPDWORD pdwNumOfBytesRead)
2605 object_header_t *hdr;
2606 DWORD res = ERROR_INTERNET_INCORRECT_HANDLE_TYPE;
2608 TRACE("%p %p %ld %p\n", hFile, lpBuffer, dwNumOfBytesToRead, pdwNumOfBytesRead);
2610 hdr = get_handle_object(hFile);
2611 if (!hdr) {
2612 INTERNET_SetLastError(ERROR_INVALID_HANDLE);
2613 return FALSE;
2616 if(hdr->vtbl->ReadFile) {
2617 res = hdr->vtbl->ReadFile(hdr, lpBuffer, dwNumOfBytesToRead, pdwNumOfBytesRead, 0, 0);
2618 if(res == ERROR_IO_PENDING)
2619 *pdwNumOfBytesRead = 0;
2622 WININET_Release(hdr);
2624 TRACE("-- %s (%lu) (bytes read: %ld)\n", res == ERROR_SUCCESS ? "TRUE": "FALSE", res,
2625 pdwNumOfBytesRead ? *pdwNumOfBytesRead : -1);
2627 SetLastError(res);
2628 return res == ERROR_SUCCESS;
2631 /***********************************************************************
2632 * InternetReadFileExA (WININET.@)
2634 * Read data from an open internet file
2636 * PARAMS
2637 * hFile [I] Handle returned by InternetOpenUrl or HttpOpenRequest.
2638 * lpBuffersOut [I/O] Buffer.
2639 * dwFlags [I] Flags. See notes.
2640 * dwContext [I] Context for callbacks.
2642 * RETURNS
2643 * TRUE on success
2644 * FALSE on failure
2646 * NOTES
2647 * The parameter dwFlags include zero or more of the following flags:
2648 *|IRF_ASYNC - Makes the call asynchronous.
2649 *|IRF_SYNC - Makes the call synchronous.
2650 *|IRF_USE_CONTEXT - Forces dwContext to be used.
2651 *|IRF_NO_WAIT - Don't block if the data is not available, just return what is available.
2653 * However, in testing IRF_USE_CONTEXT seems to have no effect - dwContext isn't used.
2655 * SEE
2656 * InternetOpenUrlA(), HttpOpenRequestA()
2658 BOOL WINAPI InternetReadFileExA(HINTERNET hFile, LPINTERNET_BUFFERSA lpBuffersOut,
2659 DWORD dwFlags, DWORD_PTR dwContext)
2661 object_header_t *hdr;
2662 DWORD res = ERROR_INTERNET_INCORRECT_HANDLE_TYPE;
2664 TRACE("(%p %p 0x%lx 0x%Ix)\n", hFile, lpBuffersOut, dwFlags, dwContext);
2666 if (lpBuffersOut->dwStructSize != sizeof(*lpBuffersOut)) {
2667 SetLastError(ERROR_INVALID_PARAMETER);
2668 return FALSE;
2671 hdr = get_handle_object(hFile);
2672 if (!hdr) {
2673 INTERNET_SetLastError(ERROR_INVALID_HANDLE);
2674 return FALSE;
2677 if(hdr->vtbl->ReadFile)
2678 res = hdr->vtbl->ReadFile(hdr, lpBuffersOut->lpvBuffer, lpBuffersOut->dwBufferLength,
2679 &lpBuffersOut->dwBufferLength, dwFlags, dwContext);
2681 WININET_Release(hdr);
2683 TRACE("-- %s (%lu, bytes read: %ld)\n", res == ERROR_SUCCESS ? "TRUE": "FALSE",
2684 res, lpBuffersOut->dwBufferLength);
2686 if(res != ERROR_SUCCESS)
2687 SetLastError(res);
2688 return res == ERROR_SUCCESS;
2691 /***********************************************************************
2692 * InternetReadFileExW (WININET.@)
2693 * SEE
2694 * InternetReadFileExA()
2696 BOOL WINAPI InternetReadFileExW(HINTERNET hFile, LPINTERNET_BUFFERSW lpBuffer,
2697 DWORD dwFlags, DWORD_PTR dwContext)
2699 object_header_t *hdr;
2700 DWORD res = ERROR_INTERNET_INCORRECT_HANDLE_TYPE;
2702 TRACE("(%p %p 0x%lx 0x%Ix)\n", hFile, lpBuffer, dwFlags, dwContext);
2704 if (!lpBuffer || lpBuffer->dwStructSize != sizeof(*lpBuffer)) {
2705 SetLastError(ERROR_INVALID_PARAMETER);
2706 return FALSE;
2709 hdr = get_handle_object(hFile);
2710 if (!hdr) {
2711 INTERNET_SetLastError(ERROR_INVALID_HANDLE);
2712 return FALSE;
2715 if(hdr->vtbl->ReadFile)
2716 res = hdr->vtbl->ReadFile(hdr, lpBuffer->lpvBuffer, lpBuffer->dwBufferLength, &lpBuffer->dwBufferLength,
2717 dwFlags, dwContext);
2719 WININET_Release(hdr);
2721 TRACE("-- %s (%lu, bytes read: %ld)\n", res == ERROR_SUCCESS ? "TRUE": "FALSE",
2722 res, lpBuffer->dwBufferLength);
2724 if(res != ERROR_SUCCESS)
2725 SetLastError(res);
2726 return res == ERROR_SUCCESS;
2729 static IP_ADAPTER_ADDRESSES *get_adapters(void)
2731 ULONG err, size = 1024, flags = GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST |
2732 GAA_FLAG_SKIP_DNS_SERVER | GAA_FLAG_SKIP_FRIENDLY_NAME;
2733 IP_ADAPTER_ADDRESSES *tmp, *ret;
2735 if (!(ret = malloc( size ))) return NULL;
2736 err = GetAdaptersAddresses( AF_UNSPEC, flags, NULL, ret, &size );
2737 while (err == ERROR_BUFFER_OVERFLOW)
2739 if (!(tmp = realloc( ret, size ))) break;
2740 ret = tmp;
2741 err = GetAdaptersAddresses( AF_UNSPEC, flags, NULL, ret, &size );
2743 if (err == ERROR_SUCCESS) return ret;
2744 free( ret );
2745 return NULL;
2748 static WCHAR *detect_proxy_autoconfig_url_dhcp(void)
2750 IP_ADAPTER_ADDRESSES *adapters, *ptr;
2751 DHCPCAPI_PARAMS_ARRAY send_params, recv_params;
2752 DHCPCAPI_PARAMS param;
2753 WCHAR name[MAX_ADAPTER_NAME_LENGTH + 1], *ret = NULL;
2754 DWORD err, size;
2755 BYTE *tmp, *buf = NULL;
2757 if (!(adapters = get_adapters())) return NULL;
2759 memset( &send_params, 0, sizeof(send_params) );
2760 memset( &param, 0, sizeof(param) );
2761 param.OptionId = OPTION_MSFT_IE_PROXY;
2762 recv_params.nParams = 1;
2763 recv_params.Params = &param;
2765 for (ptr = adapters; ptr; ptr = ptr->Next)
2767 MultiByteToWideChar( CP_ACP, 0, ptr->AdapterName, -1, name, ARRAY_SIZE(name) );
2768 TRACE( "adapter '%s' type %lu dhcpv4 enabled %d\n", wine_dbgstr_w(name), ptr->IfType, ptr->Dhcpv4Enabled );
2770 if (ptr->IfType == IF_TYPE_SOFTWARE_LOOPBACK) continue;
2771 /* FIXME: also skip adapters where DHCP is disabled */
2773 size = 256;
2774 if (!(buf = malloc( size ))) goto done;
2775 err = DhcpRequestParams( DHCPCAPI_REQUEST_SYNCHRONOUS, NULL, name, NULL, send_params, recv_params,
2776 buf, &size, NULL );
2777 while (err == ERROR_MORE_DATA)
2779 if (!(tmp = realloc( buf, size ))) goto done;
2780 buf = tmp;
2781 err = DhcpRequestParams( DHCPCAPI_REQUEST_SYNCHRONOUS, NULL, name, NULL, send_params, recv_params,
2782 buf, &size, NULL );
2784 if (err == ERROR_SUCCESS && param.nBytesData)
2786 int len = MultiByteToWideChar( CP_ACP, 0, (const char *)param.Data, param.nBytesData, NULL, 0 );
2787 if ((ret = malloc( (len + 1) * sizeof(WCHAR) )))
2789 MultiByteToWideChar( CP_ACP, 0, (const char *)param.Data, param.nBytesData, ret, len );
2790 ret[len] = 0;
2792 TRACE("returning %s\n", debugstr_w(ret));
2793 break;
2795 free( buf );
2796 buf = NULL;
2799 done:
2800 free( buf );
2801 free( adapters );
2802 return ret;
2805 static char *get_computer_name( COMPUTER_NAME_FORMAT format )
2807 char *ret;
2808 DWORD size = 0;
2810 GetComputerNameExA( format, NULL, &size );
2811 if (GetLastError() != ERROR_MORE_DATA) return NULL;
2812 if (!(ret = malloc( size ))) return NULL;
2813 if (!GetComputerNameExA( format, ret, &size ))
2815 free( ret );
2816 return NULL;
2818 return ret;
2821 static BOOL is_domain_suffix( const char *domain, const char *suffix )
2823 int len_domain = strlen( domain ), len_suffix = strlen( suffix );
2825 if (len_suffix > len_domain) return FALSE;
2826 if (!stricmp( domain + len_domain - len_suffix, suffix )) return TRUE;
2827 return FALSE;
2830 static int reverse_lookup( const struct addrinfo *ai, char *hostname, size_t len )
2832 return getnameinfo( ai->ai_addr, ai->ai_addrlen, hostname, len, NULL, 0, 0 );
2835 static WCHAR *build_wpad_url( const char *hostname, const struct addrinfo *ai )
2837 char name[NI_MAXHOST];
2838 WCHAR *ret, *p;
2839 int len;
2841 while (ai && ai->ai_family != AF_INET && ai->ai_family != AF_INET6) ai = ai->ai_next;
2842 if (!ai) return NULL;
2844 if (!reverse_lookup( ai, name, sizeof(name) )) hostname = name;
2846 len = lstrlenW( L"http://" ) + strlen( hostname ) + lstrlenW( L"/wpad.dat" );
2847 if (!(ret = p = GlobalAlloc( 0, (len + 1) * sizeof(WCHAR) ))) return NULL;
2848 lstrcpyW( p, L"http://" );
2849 p += lstrlenW( L"http://" );
2850 while (*hostname) { *p++ = *hostname++; }
2851 lstrcpyW( p, L"/wpad.dat" );
2852 return ret;
2855 static WCHAR *detect_proxy_autoconfig_url_dns(void)
2857 char *fqdn, *domain, *p;
2858 WCHAR *ret;
2860 if (!(fqdn = get_computer_name( ComputerNamePhysicalDnsFullyQualified ))) return NULL;
2861 if (!(domain = get_computer_name( ComputerNamePhysicalDnsDomain )))
2863 free( fqdn );
2864 return NULL;
2866 p = fqdn;
2867 while ((p = strchr( p, '.' )) && is_domain_suffix( p + 1, domain ))
2869 char *name;
2870 struct addrinfo *ai, hints;
2871 int res;
2873 if (!(name = malloc( sizeof("wpad") + strlen(p) )))
2875 free( fqdn );
2876 free( domain );
2877 return NULL;
2879 strcpy( name, "wpad" );
2880 strcat( name, p );
2881 memset( &hints, 0, sizeof(hints) );
2882 hints.ai_flags = AI_ALL | AI_DNS_ONLY;
2883 hints.ai_family = AF_UNSPEC;
2884 res = getaddrinfo( name, NULL, &hints, &ai );
2885 if (!res)
2887 ret = build_wpad_url( name, ai );
2888 freeaddrinfo( ai );
2889 if (ret)
2891 TRACE("returning %s\n", debugstr_w(ret));
2892 free( name );
2893 break;
2896 free( name );
2897 p++;
2899 free( domain );
2900 free( fqdn );
2901 return ret;
2904 static WCHAR *get_proxy_autoconfig_url(void)
2906 WCHAR *ret = detect_proxy_autoconfig_url_dhcp();
2907 if (!ret) ret = detect_proxy_autoconfig_url_dns();
2908 return ret;
2911 static DWORD query_global_option(DWORD option, void *buffer, DWORD *size, BOOL unicode)
2913 /* FIXME: This function currently handles more options than it should. Options requiring
2914 * proper handles should be moved to proper functions */
2915 switch(option) {
2916 case INTERNET_OPTION_HTTP_VERSION:
2917 if (*size < sizeof(HTTP_VERSION_INFO))
2918 return ERROR_INSUFFICIENT_BUFFER;
2921 * Presently hardcoded to 1.1
2923 ((HTTP_VERSION_INFO*)buffer)->dwMajorVersion = 1;
2924 ((HTTP_VERSION_INFO*)buffer)->dwMinorVersion = 1;
2925 *size = sizeof(HTTP_VERSION_INFO);
2927 return ERROR_SUCCESS;
2929 case INTERNET_OPTION_CONNECTED_STATE:
2930 FIXME("INTERNET_OPTION_CONNECTED_STATE: semi-stub\n");
2932 if (*size < sizeof(ULONG))
2933 return ERROR_INSUFFICIENT_BUFFER;
2935 *(ULONG*)buffer = INTERNET_STATE_CONNECTED;
2936 *size = sizeof(ULONG);
2938 return ERROR_SUCCESS;
2940 case INTERNET_OPTION_PROXY: {
2941 appinfo_t ai;
2942 BOOL ret;
2944 TRACE("Getting global proxy info\n");
2945 memset(&ai, 0, sizeof(appinfo_t));
2946 INTERNET_ConfigureProxy(&ai);
2948 ret = APPINFO_QueryOption(&ai.hdr, INTERNET_OPTION_PROXY, buffer, size, unicode); /* FIXME */
2949 APPINFO_Destroy(&ai.hdr);
2950 return ret;
2953 case INTERNET_OPTION_MAX_CONNS_PER_SERVER:
2954 TRACE("INTERNET_OPTION_MAX_CONNS_PER_SERVER\n");
2956 if (*size < sizeof(ULONG))
2957 return ERROR_INSUFFICIENT_BUFFER;
2959 *(ULONG*)buffer = max_conns;
2960 *size = sizeof(ULONG);
2962 return ERROR_SUCCESS;
2964 case INTERNET_OPTION_MAX_CONNS_PER_1_0_SERVER:
2965 TRACE("INTERNET_OPTION_MAX_CONNS_1_0_SERVER\n");
2967 if (*size < sizeof(ULONG))
2968 return ERROR_INSUFFICIENT_BUFFER;
2970 *(ULONG*)buffer = max_1_0_conns;
2971 *size = sizeof(ULONG);
2973 return ERROR_SUCCESS;
2975 case INTERNET_OPTION_SECURITY_FLAGS:
2976 FIXME("INTERNET_OPTION_SECURITY_FLAGS: Stub\n");
2977 return ERROR_SUCCESS;
2979 case INTERNET_OPTION_VERSION: {
2980 static const INTERNET_VERSION_INFO info = { 1, 2 };
2982 TRACE("INTERNET_OPTION_VERSION\n");
2984 if (*size < sizeof(INTERNET_VERSION_INFO))
2985 return ERROR_INSUFFICIENT_BUFFER;
2987 memcpy(buffer, &info, sizeof(info));
2988 *size = sizeof(info);
2990 return ERROR_SUCCESS;
2993 case INTERNET_OPTION_PER_CONNECTION_OPTION: {
2994 WCHAR *url = NULL;
2995 INTERNET_PER_CONN_OPTION_LISTW *con = buffer;
2996 INTERNET_PER_CONN_OPTION_LISTA *conA = buffer;
2997 DWORD res = ERROR_SUCCESS, i;
2998 proxyinfo_t pi;
2999 LONG ret;
3001 if((ret = INTERNET_LoadProxySettings(&pi)))
3002 return ret;
3004 TRACE("INTERNET_OPTION_PER_CONNECTION_OPTION\n");
3006 if (*size < sizeof(INTERNET_PER_CONN_OPTION_LISTW)) {
3007 FreeProxyInfo(&pi);
3008 return ERROR_INSUFFICIENT_BUFFER;
3011 if (pi.flags & PROXY_TYPE_AUTO_DETECT)
3012 url = get_proxy_autoconfig_url();
3014 for (i = 0; i < con->dwOptionCount; i++) {
3015 INTERNET_PER_CONN_OPTIONW *optionW = con->pOptions + i;
3016 INTERNET_PER_CONN_OPTIONA *optionA = conA->pOptions + i;
3018 switch (optionW->dwOption) {
3019 case INTERNET_PER_CONN_FLAGS:
3020 optionW->Value.dwValue = pi.flags;
3021 break;
3023 case INTERNET_PER_CONN_PROXY_SERVER:
3024 if (unicode)
3025 optionW->Value.pszValue = copy_optionW(pi.proxy);
3026 else
3027 optionA->Value.pszValue = copy_optionA(pi.proxy);
3028 break;
3030 case INTERNET_PER_CONN_PROXY_BYPASS:
3031 if (unicode)
3032 optionW->Value.pszValue = copy_optionW(pi.proxyBypass);
3033 else
3034 optionA->Value.pszValue = copy_optionA(pi.proxyBypass);
3035 break;
3037 case INTERNET_PER_CONN_AUTOCONFIG_URL:
3038 if (unicode)
3039 optionW->Value.pszValue = copy_optionW(pi.autoconf_url);
3040 else
3041 optionA->Value.pszValue = copy_optionA(pi.autoconf_url);
3042 break;
3044 case INTERNET_PER_CONN_AUTODISCOVERY_FLAGS:
3045 optionW->Value.dwValue = AUTO_PROXY_FLAG_ALWAYS_DETECT;
3046 break;
3048 case INTERNET_PER_CONN_AUTOCONFIG_LAST_DETECT_URL:
3049 if (unicode)
3050 optionW->Value.pszValue = copy_optionW(url);
3051 else
3052 optionA->Value.pszValue = copy_optionA(url);
3053 break;
3055 case INTERNET_PER_CONN_AUTOCONFIG_SECONDARY_URL:
3056 case INTERNET_PER_CONN_AUTOCONFIG_RELOAD_DELAY_MINS:
3057 case INTERNET_PER_CONN_AUTOCONFIG_LAST_DETECT_TIME:
3058 FIXME("Unhandled dwOption %ld\n", optionW->dwOption);
3059 memset(&optionW->Value, 0, sizeof(optionW->Value));
3060 break;
3062 default:
3063 FIXME("Unknown dwOption %ld\n", optionW->dwOption);
3064 res = ERROR_INVALID_PARAMETER;
3065 break;
3068 free(url);
3069 FreeProxyInfo(&pi);
3071 return res;
3073 case INTERNET_OPTION_REQUEST_FLAGS:
3074 case INTERNET_OPTION_USER_AGENT:
3075 *size = 0;
3076 return ERROR_INTERNET_INCORRECT_HANDLE_TYPE;
3077 case INTERNET_OPTION_POLICY:
3078 return ERROR_INVALID_PARAMETER;
3079 case INTERNET_OPTION_CONNECT_TIMEOUT:
3080 TRACE("INTERNET_OPTION_CONNECT_TIMEOUT\n");
3082 if (*size < sizeof(ULONG))
3083 return ERROR_INSUFFICIENT_BUFFER;
3085 *(ULONG*)buffer = connect_timeout;
3086 *size = sizeof(ULONG);
3088 return ERROR_SUCCESS;
3090 case INTERNET_OPTION_SEND_TIMEOUT:
3091 TRACE("INTERNET_OPTION_SEND_TIMEOUT\n");
3093 if (*size < sizeof(ULONG))
3094 return ERROR_INSUFFICIENT_BUFFER;
3096 *(ULONG*)buffer = send_timeout;
3097 *size = sizeof(ULONG);
3099 return ERROR_SUCCESS;
3101 case INTERNET_OPTION_RECEIVE_TIMEOUT:
3102 TRACE("INTERNET_OPTION_RECEIVE_TIMEOUT\n");
3104 if (*size < sizeof(ULONG))
3105 return ERROR_INSUFFICIENT_BUFFER;
3107 *(ULONG*)buffer = receive_timeout;
3108 *size = sizeof(ULONG);
3110 return ERROR_SUCCESS;
3112 case INTERNET_OPTION_DATA_SEND_TIMEOUT:
3113 TRACE("INTERNET_OPTION_DATA_SEND_TIMEOUT\n");
3115 if (*size < sizeof(ULONG))
3116 return ERROR_INSUFFICIENT_BUFFER;
3118 *(ULONG*)buffer = data_send_timeout;
3119 *size = sizeof(ULONG);
3121 return ERROR_SUCCESS;
3123 case INTERNET_OPTION_DATA_RECEIVE_TIMEOUT:
3124 TRACE("INTERNET_OPTION_DATA_RECEIVE_TIMEOUT\n");
3126 if (*size < sizeof(ULONG))
3127 return ERROR_INSUFFICIENT_BUFFER;
3129 *(ULONG*)buffer = data_receive_timeout;
3130 *size = sizeof(ULONG);
3132 return ERROR_SUCCESS;
3135 FIXME("Stub for %ld\n", option);
3136 return ERROR_INTERNET_INCORRECT_HANDLE_TYPE;
3139 DWORD INET_QueryOption(object_header_t *hdr, DWORD option, void *buffer, DWORD *size, BOOL unicode)
3141 switch(option) {
3142 case INTERNET_OPTION_CONTEXT_VALUE:
3143 if (!size)
3144 return ERROR_INVALID_PARAMETER;
3146 if (*size < sizeof(DWORD_PTR)) {
3147 *size = sizeof(DWORD_PTR);
3148 return ERROR_INSUFFICIENT_BUFFER;
3150 if (!buffer)
3151 return ERROR_INVALID_PARAMETER;
3153 *(DWORD_PTR *)buffer = hdr->dwContext;
3154 *size = sizeof(DWORD_PTR);
3155 return ERROR_SUCCESS;
3157 case INTERNET_OPTION_REQUEST_FLAGS:
3158 WARN("INTERNET_OPTION_REQUEST_FLAGS\n");
3159 *size = sizeof(DWORD);
3160 return ERROR_INTERNET_INCORRECT_HANDLE_TYPE;
3162 case INTERNET_OPTION_MAX_CONNS_PER_SERVER:
3163 case INTERNET_OPTION_MAX_CONNS_PER_1_0_SERVER:
3164 WARN("Called on global option %lu\n", option);
3165 return ERROR_INTERNET_INVALID_OPERATION;
3167 case INTERNET_OPTION_CONNECT_TIMEOUT:
3168 TRACE("INTERNET_OPTION_CONNECT_TIMEOUT\n");
3170 if (*size < sizeof(ULONG))
3171 return ERROR_INSUFFICIENT_BUFFER;
3173 *(ULONG*)buffer = hdr->connect_timeout;
3174 *size = sizeof(ULONG);
3176 return ERROR_SUCCESS;
3178 case INTERNET_OPTION_SEND_TIMEOUT:
3179 TRACE("INTERNET_OPTION_SEND_TIMEOUT\n");
3181 if (*size < sizeof(ULONG))
3182 return ERROR_INSUFFICIENT_BUFFER;
3184 *size = sizeof(ULONG);
3185 *(ULONG *)buffer = hdr->send_timeout;
3186 return ERROR_SUCCESS;
3188 case INTERNET_OPTION_RECEIVE_TIMEOUT:
3189 TRACE("INTERNET_OPTION_RECEIVE_TIMEOUT\n");
3191 if (*size < sizeof(ULONG))
3192 return ERROR_INSUFFICIENT_BUFFER;
3194 *size = sizeof(ULONG);
3195 *(ULONG *)buffer = hdr->receive_timeout;
3196 return ERROR_SUCCESS;
3198 case INTERNET_OPTION_DATA_SEND_TIMEOUT:
3199 TRACE("INTERNET_OPTION_DATA_SEND_TIMEOUT\n");
3201 if (*size < sizeof(ULONG))
3202 return ERROR_INSUFFICIENT_BUFFER;
3204 *size = sizeof(ULONG);
3205 *(ULONG *)buffer = hdr->data_send_timeout;
3206 return ERROR_SUCCESS;
3208 case INTERNET_OPTION_DATA_RECEIVE_TIMEOUT:
3209 TRACE("INTERNET_OPTION_DATA_RECEIVE_TIMEOUT\n");
3211 if (*size < sizeof(ULONG))
3212 return ERROR_INSUFFICIENT_BUFFER;
3214 *size = sizeof(ULONG);
3215 *(ULONG *)buffer = hdr->data_receive_timeout;
3216 return ERROR_SUCCESS;
3219 /* FIXME: we shouldn't call it here */
3220 return query_global_option(option, buffer, size, unicode);
3223 /***********************************************************************
3224 * InternetQueryOptionW (WININET.@)
3226 * Queries an options on the specified handle
3228 * RETURNS
3229 * TRUE on success
3230 * FALSE on failure
3233 BOOL WINAPI InternetQueryOptionW(HINTERNET hInternet, DWORD dwOption,
3234 LPVOID lpBuffer, LPDWORD lpdwBufferLength)
3236 object_header_t *hdr;
3237 DWORD res = ERROR_INVALID_HANDLE;
3239 TRACE("%p %ld %p %p\n", hInternet, dwOption, lpBuffer, lpdwBufferLength);
3241 if(hInternet) {
3242 hdr = get_handle_object(hInternet);
3243 if (hdr) {
3244 res = hdr->vtbl->QueryOption(hdr, dwOption, lpBuffer, lpdwBufferLength, TRUE);
3245 WININET_Release(hdr);
3247 }else {
3248 res = query_global_option(dwOption, lpBuffer, lpdwBufferLength, TRUE);
3251 if(res != ERROR_SUCCESS)
3252 SetLastError(res);
3253 return res == ERROR_SUCCESS;
3256 /***********************************************************************
3257 * InternetQueryOptionA (WININET.@)
3259 * Queries an options on the specified handle
3261 * RETURNS
3262 * TRUE on success
3263 * FALSE on failure
3266 BOOL WINAPI InternetQueryOptionA(HINTERNET hInternet, DWORD dwOption,
3267 LPVOID lpBuffer, LPDWORD lpdwBufferLength)
3269 object_header_t *hdr;
3270 DWORD res = ERROR_INVALID_HANDLE;
3272 TRACE("%p %ld %p %p\n", hInternet, dwOption, lpBuffer, lpdwBufferLength);
3274 if(hInternet) {
3275 hdr = get_handle_object(hInternet);
3276 if (hdr) {
3277 res = hdr->vtbl->QueryOption(hdr, dwOption, lpBuffer, lpdwBufferLength, FALSE);
3278 WININET_Release(hdr);
3280 }else {
3281 res = query_global_option(dwOption, lpBuffer, lpdwBufferLength, FALSE);
3284 if(res != ERROR_SUCCESS)
3285 SetLastError(res);
3286 return res == ERROR_SUCCESS;
3289 DWORD INET_SetOption(object_header_t *hdr, DWORD option, void *buf, DWORD size)
3291 switch(option) {
3292 case INTERNET_OPTION_SETTINGS_CHANGED:
3293 FIXME("INTERNETOPTION_SETTINGS_CHANGED semi-stub\n");
3294 collect_connections(COLLECT_CONNECTIONS);
3295 return ERROR_SUCCESS;
3296 case INTERNET_OPTION_CALLBACK:
3297 WARN("Not settable option %lu\n", option);
3298 return ERROR_INTERNET_OPTION_NOT_SETTABLE;
3299 case INTERNET_OPTION_MAX_CONNS_PER_SERVER:
3300 case INTERNET_OPTION_MAX_CONNS_PER_1_0_SERVER:
3301 WARN("Called on global option %lu\n", option);
3302 return ERROR_INTERNET_INVALID_OPERATION;
3303 case INTERNET_OPTION_REFRESH:
3304 return ERROR_INTERNET_INCORRECT_HANDLE_TYPE;
3305 case INTERNET_OPTION_CONNECT_TIMEOUT:
3306 if (!buf || size != sizeof(ULONG)) return ERROR_INVALID_PARAMETER;
3307 hdr->connect_timeout = *(ULONG *)buf;
3308 return ERROR_SUCCESS;
3309 case INTERNET_OPTION_SEND_TIMEOUT:
3310 if (!buf || size != sizeof(ULONG)) return ERROR_INVALID_PARAMETER;
3311 hdr->send_timeout = *(ULONG *)buf;
3312 return ERROR_SUCCESS;
3313 case INTERNET_OPTION_RECEIVE_TIMEOUT:
3314 if (!buf || size != sizeof(ULONG)) return ERROR_INVALID_PARAMETER;
3315 hdr->receive_timeout = *(ULONG *)buf;
3316 return ERROR_SUCCESS;
3317 case INTERNET_OPTION_DATA_SEND_TIMEOUT:
3318 if (!buf || size != sizeof(ULONG)) return ERROR_INVALID_PARAMETER;
3319 hdr->data_send_timeout = *(ULONG *)buf;
3320 return ERROR_SUCCESS;
3321 case INTERNET_OPTION_DATA_RECEIVE_TIMEOUT:
3322 if (!buf || size != sizeof(ULONG)) return ERROR_INVALID_PARAMETER;
3323 hdr->data_receive_timeout = *(ULONG *)buf;
3324 return ERROR_SUCCESS;
3327 return ERROR_INTERNET_INVALID_OPTION;
3330 static DWORD set_global_option(DWORD option, void *buf, DWORD size)
3332 switch(option) {
3333 case INTERNET_OPTION_CALLBACK:
3334 WARN("Not global option %lu\n", option);
3335 return ERROR_INTERNET_INCORRECT_HANDLE_TYPE;
3337 case INTERNET_OPTION_MAX_CONNS_PER_SERVER:
3338 TRACE("INTERNET_OPTION_MAX_CONNS_PER_SERVER\n");
3340 if(size != sizeof(max_conns))
3341 return ERROR_INTERNET_BAD_OPTION_LENGTH;
3342 if(!*(ULONG*)buf)
3343 return ERROR_BAD_ARGUMENTS;
3345 max_conns = *(ULONG*)buf;
3346 return ERROR_SUCCESS;
3348 case INTERNET_OPTION_MAX_CONNS_PER_1_0_SERVER:
3349 TRACE("INTERNET_OPTION_MAX_CONNS_PER_1_0_SERVER\n");
3351 if(size != sizeof(max_1_0_conns))
3352 return ERROR_INTERNET_BAD_OPTION_LENGTH;
3353 if(!*(ULONG*)buf)
3354 return ERROR_BAD_ARGUMENTS;
3356 max_1_0_conns = *(ULONG*)buf;
3357 return ERROR_SUCCESS;
3359 case INTERNET_OPTION_CONNECT_TIMEOUT:
3360 TRACE("INTERNET_OPTION_CONNECT_TIMEOUT\n");
3362 if(size != sizeof(connect_timeout))
3363 return ERROR_INTERNET_BAD_OPTION_LENGTH;
3364 if(!*(ULONG*)buf)
3365 return ERROR_BAD_ARGUMENTS;
3367 connect_timeout = *(ULONG*)buf;
3368 return ERROR_SUCCESS;
3370 case INTERNET_OPTION_SEND_TIMEOUT:
3371 TRACE("INTERNET_OPTION_SEND_TIMEOUT\n");
3373 if(size != sizeof(send_timeout))
3374 return ERROR_INTERNET_BAD_OPTION_LENGTH;
3375 if(!*(ULONG*)buf)
3376 return ERROR_BAD_ARGUMENTS;
3378 send_timeout = *(ULONG*)buf;
3379 return ERROR_SUCCESS;
3381 case INTERNET_OPTION_RECEIVE_TIMEOUT:
3382 TRACE("INTERNET_OPTION_RECEIVE_TIMEOUT\n");
3384 if(size != sizeof(receive_timeout))
3385 return ERROR_INTERNET_BAD_OPTION_LENGTH;
3386 if(!*(ULONG*)buf)
3387 return ERROR_BAD_ARGUMENTS;
3389 receive_timeout = *(ULONG*)buf;
3390 return ERROR_SUCCESS;
3392 case INTERNET_OPTION_DATA_SEND_TIMEOUT:
3393 TRACE("INTERNET_OPTION_DATA_SEND_TIMEOUT\n");
3395 if(size != sizeof(data_send_timeout))
3396 return ERROR_INTERNET_BAD_OPTION_LENGTH;
3397 if(!*(ULONG*)buf)
3398 return ERROR_BAD_ARGUMENTS;
3400 data_send_timeout = *(ULONG*)buf;
3401 return ERROR_SUCCESS;
3403 case INTERNET_OPTION_DATA_RECEIVE_TIMEOUT:
3404 TRACE("INTERNET_OPTION_DATA_RECEIVE_TIMEOUT\n");
3406 if(size != sizeof(data_receive_timeout))
3407 return ERROR_INTERNET_BAD_OPTION_LENGTH;
3408 if(!*(ULONG*)buf)
3409 return ERROR_BAD_ARGUMENTS;
3411 data_receive_timeout = *(ULONG*)buf;
3412 return ERROR_SUCCESS;
3414 case INTERNET_OPTION_SUPPRESS_BEHAVIOR:
3415 FIXME("INTERNET_OPTION_SUPPRESS_BEHAVIOR stub\n");
3417 if(size != sizeof(ULONG))
3418 return ERROR_INTERNET_BAD_OPTION_LENGTH;
3420 FIXME("%08lx\n", *(ULONG*)buf);
3421 return ERROR_SUCCESS;
3424 return INET_SetOption(NULL, option, buf, size);
3427 /***********************************************************************
3428 * InternetSetOptionW (WININET.@)
3430 * Sets an options on the specified handle
3432 * RETURNS
3433 * TRUE on success
3434 * FALSE on failure
3437 BOOL WINAPI InternetSetOptionW(HINTERNET hInternet, DWORD dwOption,
3438 LPVOID lpBuffer, DWORD dwBufferLength)
3440 object_header_t *lpwhh;
3441 BOOL ret = TRUE;
3442 DWORD res;
3444 TRACE("(%p %ld %p %ld)\n", hInternet, dwOption, lpBuffer, dwBufferLength);
3446 lpwhh = (object_header_t*) get_handle_object( hInternet );
3447 if(lpwhh)
3448 res = lpwhh->vtbl->SetOption(lpwhh, dwOption, lpBuffer, dwBufferLength);
3449 else
3450 res = set_global_option(dwOption, lpBuffer, dwBufferLength);
3452 if(res != ERROR_INTERNET_INVALID_OPTION) {
3453 if(lpwhh)
3454 WININET_Release(lpwhh);
3456 if(res != ERROR_SUCCESS)
3457 SetLastError(res);
3459 return res == ERROR_SUCCESS;
3462 switch (dwOption)
3464 case INTERNET_OPTION_HTTP_VERSION:
3466 HTTP_VERSION_INFO* pVersion=(HTTP_VERSION_INFO*)lpBuffer;
3467 FIXME("Option INTERNET_OPTION_HTTP_VERSION(%ld,%ld): STUB\n",pVersion->dwMajorVersion,pVersion->dwMinorVersion);
3469 break;
3470 case INTERNET_OPTION_ERROR_MASK:
3472 if(!lpwhh) {
3473 SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
3474 return FALSE;
3475 } else if(*(ULONG*)lpBuffer & (~(INTERNET_ERROR_MASK_INSERT_CDROM|
3476 INTERNET_ERROR_MASK_COMBINED_SEC_CERT|
3477 INTERNET_ERROR_MASK_LOGIN_FAILURE_DISPLAY_ENTITY_BODY))) {
3478 SetLastError(ERROR_INVALID_PARAMETER);
3479 ret = FALSE;
3480 } else if(dwBufferLength != sizeof(ULONG)) {
3481 SetLastError(ERROR_INTERNET_BAD_OPTION_LENGTH);
3482 ret = FALSE;
3483 } else {
3484 TRACE("INTERNET_OPTION_ERROR_MASK: %lx\n", *(ULONG*)lpBuffer);
3485 lpwhh->ErrorMask = *(ULONG*)lpBuffer;
3488 break;
3489 case INTERNET_OPTION_PROXY:
3491 INTERNET_PROXY_INFOW *info = lpBuffer;
3493 if (!lpBuffer || dwBufferLength < sizeof(INTERNET_PROXY_INFOW))
3495 SetLastError(ERROR_INVALID_PARAMETER);
3496 return FALSE;
3498 if (!hInternet)
3500 EnterCriticalSection( &WININET_cs );
3501 free_global_proxy();
3502 if (info->dwAccessType == INTERNET_OPEN_TYPE_PROXY)
3504 global_proxy.flags = PROXY_TYPE_PROXY;
3505 global_proxy.proxy = wcsdup(info->lpszProxy);
3506 global_proxy.proxyBypass = wcsdup(info->lpszProxyBypass);
3508 else
3510 global_proxy.flags = PROXY_TYPE_DIRECT;
3511 global_proxy.proxy = global_proxy.proxyBypass = NULL;
3513 LeaveCriticalSection( &WININET_cs );
3515 else
3517 /* In general, each type of object should handle
3518 * INTERNET_OPTION_PROXY directly. This FIXME ensures it doesn't
3519 * get silently dropped.
3521 FIXME("INTERNET_OPTION_PROXY unimplemented\n");
3522 SetLastError(ERROR_INTERNET_INVALID_OPTION);
3523 ret = FALSE;
3525 break;
3527 case INTERNET_OPTION_CODEPAGE:
3529 ULONG codepage = *(ULONG *)lpBuffer;
3530 FIXME("Option INTERNET_OPTION_CODEPAGE (%ld): STUB\n", codepage);
3532 break;
3533 case INTERNET_OPTION_REQUEST_PRIORITY:
3535 ULONG priority = *(ULONG *)lpBuffer;
3536 FIXME("Option INTERNET_OPTION_REQUEST_PRIORITY (%ld): STUB\n", priority);
3538 break;
3539 case INTERNET_OPTION_RESET_URLCACHE_SESSION:
3540 FIXME("Option INTERNET_OPTION_RESET_URLCACHE_SESSION: STUB\n");
3541 break;
3542 case INTERNET_OPTION_END_BROWSER_SESSION:
3543 FIXME("Option INTERNET_OPTION_END_BROWSER_SESSION: semi-stub\n");
3544 free_cookie();
3545 free_authorization_cache();
3546 break;
3547 case INTERNET_OPTION_CONNECTED_STATE:
3548 FIXME("Option INTERNET_OPTION_CONNECTED_STATE: STUB\n");
3549 break;
3550 case INTERNET_OPTION_DISABLE_PASSPORT_AUTH:
3551 TRACE("Option INTERNET_OPTION_DISABLE_PASSPORT_AUTH: harmless stub, since not enabled\n");
3552 break;
3553 case INTERNET_OPTION_IGNORE_OFFLINE:
3554 FIXME("Option INTERNET_OPTION_IGNORE_OFFLINE: STUB\n");
3555 break;
3556 case INTERNET_OPTION_CONNECT_RETRIES:
3558 ULONG retries = *(ULONG *)lpBuffer;
3559 FIXME("INTERNET_OPTION_CONNECT_RETRIES %ld\n", retries);
3560 break;
3562 case INTERNET_OPTION_CONTEXT_VALUE:
3564 if (!lpwhh)
3566 SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
3567 return FALSE;
3569 if (!lpBuffer || dwBufferLength != sizeof(DWORD_PTR))
3571 SetLastError(ERROR_INVALID_PARAMETER);
3572 ret = FALSE;
3574 else
3575 lpwhh->dwContext = *(DWORD_PTR *)lpBuffer;
3576 break;
3578 case INTERNET_OPTION_SECURITY_FLAGS:
3579 FIXME("Option INTERNET_OPTION_SECURITY_FLAGS; STUB\n");
3580 break;
3581 case INTERNET_OPTION_DISABLE_AUTODIAL:
3582 FIXME("Option INTERNET_OPTION_DISABLE_AUTODIAL; STUB\n");
3583 break;
3584 case INTERNET_OPTION_HTTP_DECODING:
3585 if (!lpwhh)
3587 SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
3588 return FALSE;
3590 if (!lpBuffer || dwBufferLength != sizeof(BOOL))
3592 SetLastError(ERROR_INVALID_PARAMETER);
3593 ret = FALSE;
3595 else
3596 lpwhh->decoding = *(BOOL *)lpBuffer;
3597 break;
3598 case INTERNET_OPTION_COOKIES_3RD_PARTY:
3599 FIXME("INTERNET_OPTION_COOKIES_3RD_PARTY; STUB\n");
3600 SetLastError(ERROR_INTERNET_INVALID_OPTION);
3601 ret = FALSE;
3602 break;
3603 case INTERNET_OPTION_SEND_UTF8_SERVERNAME_TO_PROXY:
3604 FIXME("INTERNET_OPTION_SEND_UTF8_SERVERNAME_TO_PROXY; STUB\n");
3605 SetLastError(ERROR_INTERNET_INVALID_OPTION);
3606 ret = FALSE;
3607 break;
3608 case INTERNET_OPTION_CODEPAGE_PATH:
3609 FIXME("INTERNET_OPTION_CODEPAGE_PATH; STUB\n");
3610 SetLastError(ERROR_INTERNET_INVALID_OPTION);
3611 ret = FALSE;
3612 break;
3613 case INTERNET_OPTION_CODEPAGE_EXTRA:
3614 FIXME("INTERNET_OPTION_CODEPAGE_EXTRA; STUB\n");
3615 SetLastError(ERROR_INTERNET_INVALID_OPTION);
3616 ret = FALSE;
3617 break;
3618 case INTERNET_OPTION_IDN:
3619 FIXME("INTERNET_OPTION_IDN; STUB\n");
3620 SetLastError(ERROR_INTERNET_INVALID_OPTION);
3621 ret = FALSE;
3622 break;
3623 case INTERNET_OPTION_POLICY:
3624 SetLastError(ERROR_INVALID_PARAMETER);
3625 ret = FALSE;
3626 break;
3627 case INTERNET_OPTION_PER_CONNECTION_OPTION: {
3628 INTERNET_PER_CONN_OPTION_LISTW *con = lpBuffer;
3629 LONG res;
3630 unsigned int i;
3631 proxyinfo_t pi;
3633 if (INTERNET_LoadProxySettings(&pi)) return FALSE;
3635 for (i = 0; i < con->dwOptionCount; i++) {
3636 INTERNET_PER_CONN_OPTIONW *option = con->pOptions + i;
3638 switch (option->dwOption) {
3639 case INTERNET_PER_CONN_PROXY_SERVER:
3640 free(pi.proxy);
3641 pi.proxy = wcsdup(option->Value.pszValue);
3642 break;
3644 case INTERNET_PER_CONN_FLAGS:
3645 if(option->Value.dwValue & ~(PROXY_TYPE_PROXY | PROXY_TYPE_DIRECT))
3646 FIXME("Unhandled flags: 0x%lx\n", option->Value.dwValue);
3647 pi.flags = option->Value.dwValue;
3648 break;
3650 case INTERNET_PER_CONN_PROXY_BYPASS:
3651 free(pi.proxyBypass);
3652 pi.proxyBypass = wcsdup(option->Value.pszValue);
3653 break;
3655 case INTERNET_PER_CONN_AUTOCONFIG_URL:
3656 free(pi.autoconf_url);
3657 pi.autoconf_url = wcsdup(option->Value.pszValue);
3658 break;
3660 case INTERNET_PER_CONN_AUTODISCOVERY_FLAGS:
3661 case INTERNET_PER_CONN_AUTOCONFIG_SECONDARY_URL:
3662 case INTERNET_PER_CONN_AUTOCONFIG_RELOAD_DELAY_MINS:
3663 case INTERNET_PER_CONN_AUTOCONFIG_LAST_DETECT_TIME:
3664 case INTERNET_PER_CONN_AUTOCONFIG_LAST_DETECT_URL:
3665 FIXME("Unhandled dwOption %ld\n", option->dwOption);
3666 break;
3668 default:
3669 FIXME("Unknown dwOption %ld\n", option->dwOption);
3670 SetLastError(ERROR_INVALID_PARAMETER);
3671 break;
3675 if ((res = INTERNET_SaveProxySettings(&pi)))
3676 SetLastError(res);
3678 FreeProxyInfo(&pi);
3680 ret = (res == ERROR_SUCCESS);
3681 break;
3683 default:
3684 FIXME("Option %ld STUB\n",dwOption);
3685 SetLastError(ERROR_INTERNET_INVALID_OPTION);
3686 ret = FALSE;
3687 break;
3690 if(lpwhh)
3691 WININET_Release( lpwhh );
3693 return ret;
3697 /***********************************************************************
3698 * InternetSetOptionA (WININET.@)
3700 * Sets an options on the specified handle.
3702 * RETURNS
3703 * TRUE on success
3704 * FALSE on failure
3707 BOOL WINAPI InternetSetOptionA(HINTERNET hInternet, DWORD dwOption,
3708 LPVOID lpBuffer, DWORD dwBufferLength)
3710 LPVOID wbuffer;
3711 DWORD wlen;
3712 BOOL r;
3714 switch( dwOption )
3716 case INTERNET_OPTION_PROXY:
3718 LPINTERNET_PROXY_INFOA pi = (LPINTERNET_PROXY_INFOA) lpBuffer;
3719 LPINTERNET_PROXY_INFOW piw;
3720 DWORD proxlen, prbylen;
3721 LPWSTR prox, prby;
3723 proxlen = MultiByteToWideChar( CP_ACP, 0, pi->lpszProxy, -1, NULL, 0);
3724 prbylen= MultiByteToWideChar( CP_ACP, 0, pi->lpszProxyBypass, -1, NULL, 0);
3725 wlen = sizeof(*piw) + proxlen + prbylen;
3726 wbuffer = malloc( wlen * sizeof(WCHAR) );
3727 piw = (LPINTERNET_PROXY_INFOW) wbuffer;
3728 piw->dwAccessType = pi->dwAccessType;
3729 prox = (LPWSTR) &piw[1];
3730 prby = &prox[proxlen+1];
3731 MultiByteToWideChar( CP_ACP, 0, pi->lpszProxy, -1, prox, proxlen);
3732 MultiByteToWideChar( CP_ACP, 0, pi->lpszProxyBypass, -1, prby, prbylen);
3733 piw->lpszProxy = prox;
3734 piw->lpszProxyBypass = prby;
3736 break;
3737 case INTERNET_OPTION_USER_AGENT:
3738 case INTERNET_OPTION_USERNAME:
3739 case INTERNET_OPTION_PASSWORD:
3740 case INTERNET_OPTION_PROXY_USERNAME:
3741 case INTERNET_OPTION_PROXY_PASSWORD:
3742 wlen = MultiByteToWideChar( CP_ACP, 0, lpBuffer, -1, NULL, 0 );
3743 if (!(wbuffer = malloc( wlen * sizeof(WCHAR) ))) return ERROR_OUTOFMEMORY;
3744 MultiByteToWideChar( CP_ACP, 0, lpBuffer, -1, wbuffer, wlen );
3745 break;
3746 case INTERNET_OPTION_PER_CONNECTION_OPTION: {
3747 unsigned int i;
3748 INTERNET_PER_CONN_OPTION_LISTW *listW;
3749 INTERNET_PER_CONN_OPTION_LISTA *listA = lpBuffer;
3750 wlen = sizeof(INTERNET_PER_CONN_OPTION_LISTW);
3751 wbuffer = malloc( wlen );
3752 listW = wbuffer;
3754 listW->dwSize = sizeof(INTERNET_PER_CONN_OPTION_LISTW);
3755 if (listA->pszConnection)
3757 wlen = MultiByteToWideChar( CP_ACP, 0, listA->pszConnection, -1, NULL, 0 );
3758 listW->pszConnection = malloc( wlen * sizeof(WCHAR) );
3759 MultiByteToWideChar( CP_ACP, 0, listA->pszConnection, -1, listW->pszConnection, wlen );
3761 else
3762 listW->pszConnection = NULL;
3763 listW->dwOptionCount = listA->dwOptionCount;
3764 listW->dwOptionError = listA->dwOptionError;
3765 listW->pOptions = malloc( sizeof(INTERNET_PER_CONN_OPTIONW) * listA->dwOptionCount );
3767 for (i = 0; i < listA->dwOptionCount; ++i) {
3768 INTERNET_PER_CONN_OPTIONA *optA = listA->pOptions + i;
3769 INTERNET_PER_CONN_OPTIONW *optW = listW->pOptions + i;
3771 optW->dwOption = optA->dwOption;
3773 switch (optA->dwOption) {
3774 case INTERNET_PER_CONN_AUTOCONFIG_URL:
3775 case INTERNET_PER_CONN_PROXY_BYPASS:
3776 case INTERNET_PER_CONN_PROXY_SERVER:
3777 case INTERNET_PER_CONN_AUTOCONFIG_SECONDARY_URL:
3778 case INTERNET_PER_CONN_AUTOCONFIG_LAST_DETECT_URL:
3779 if (optA->Value.pszValue)
3781 wlen = MultiByteToWideChar( CP_ACP, 0, optA->Value.pszValue, -1, NULL, 0 );
3782 optW->Value.pszValue = malloc( wlen * sizeof(WCHAR) );
3783 MultiByteToWideChar( CP_ACP, 0, optA->Value.pszValue, -1, optW->Value.pszValue, wlen );
3785 else
3786 optW->Value.pszValue = NULL;
3787 break;
3788 case INTERNET_PER_CONN_AUTODISCOVERY_FLAGS:
3789 case INTERNET_PER_CONN_FLAGS:
3790 case INTERNET_PER_CONN_AUTOCONFIG_RELOAD_DELAY_MINS:
3791 optW->Value.dwValue = optA->Value.dwValue;
3792 break;
3793 case INTERNET_PER_CONN_AUTOCONFIG_LAST_DETECT_TIME:
3794 optW->Value.ftValue = optA->Value.ftValue;
3795 break;
3796 default:
3797 WARN("Unknown PER_CONN dwOption: %ld, guessing at conversion to Wide\n", optA->dwOption);
3798 optW->Value.dwValue = optA->Value.dwValue;
3799 break;
3803 break;
3804 default:
3805 wbuffer = lpBuffer;
3806 wlen = dwBufferLength;
3809 r = InternetSetOptionW(hInternet,dwOption, wbuffer, wlen);
3811 if( lpBuffer != wbuffer )
3813 if (dwOption == INTERNET_OPTION_PER_CONNECTION_OPTION)
3815 INTERNET_PER_CONN_OPTION_LISTW *list = wbuffer;
3816 unsigned int i;
3817 for (i = 0; i < list->dwOptionCount; ++i) {
3818 INTERNET_PER_CONN_OPTIONW *opt = list->pOptions + i;
3819 switch (opt->dwOption) {
3820 case INTERNET_PER_CONN_AUTOCONFIG_URL:
3821 case INTERNET_PER_CONN_PROXY_BYPASS:
3822 case INTERNET_PER_CONN_PROXY_SERVER:
3823 case INTERNET_PER_CONN_AUTOCONFIG_SECONDARY_URL:
3824 case INTERNET_PER_CONN_AUTOCONFIG_LAST_DETECT_URL:
3825 free( opt->Value.pszValue );
3826 break;
3827 default:
3828 break;
3831 free( list->pOptions );
3833 free( wbuffer );
3836 return r;
3840 /***********************************************************************
3841 * InternetSetOptionExA (WININET.@)
3843 BOOL WINAPI InternetSetOptionExA(HINTERNET hInternet, DWORD dwOption,
3844 LPVOID lpBuffer, DWORD dwBufferLength, DWORD dwFlags)
3846 FIXME("Flags %08lx ignored\n", dwFlags);
3847 return InternetSetOptionA( hInternet, dwOption, lpBuffer, dwBufferLength );
3850 /***********************************************************************
3851 * InternetSetOptionExW (WININET.@)
3853 BOOL WINAPI InternetSetOptionExW(HINTERNET hInternet, DWORD dwOption,
3854 LPVOID lpBuffer, DWORD dwBufferLength, DWORD dwFlags)
3856 FIXME("Flags %08lx ignored\n", dwFlags);
3857 if( dwFlags & ~ISO_VALID_FLAGS )
3859 SetLastError( ERROR_INVALID_PARAMETER );
3860 return FALSE;
3862 return InternetSetOptionW( hInternet, dwOption, lpBuffer, dwBufferLength );
3865 static const WCHAR WININET_wkday[7][4] =
3866 { L"Sun", L"Mon", L"Tue", L"Wed",
3867 L"Thu", L"Fri", L"Sat"};
3868 static const WCHAR WININET_month[12][4] =
3869 { L"Jan", L"Feb", L"Mar", L"Apr",
3870 L"May", L"Jun", L"Jul", L"Aug",
3871 L"Sep", L"Oct", L"Nov", L"Dec"};
3873 static inline BOOL is_time_digit(const WCHAR c)
3875 return c >= '0' && c <= '9';
3878 /***********************************************************************
3879 * InternetTimeFromSystemTimeA (WININET.@)
3881 BOOL WINAPI InternetTimeFromSystemTimeA( const SYSTEMTIME* time, DWORD format, LPSTR string, DWORD size )
3883 BOOL ret;
3884 WCHAR stringW[INTERNET_RFC1123_BUFSIZE];
3886 TRACE( "%p 0x%08lx %p 0x%08lx\n", time, format, string, size );
3888 if (!time || !string || format != INTERNET_RFC1123_FORMAT)
3890 SetLastError(ERROR_INVALID_PARAMETER);
3891 return FALSE;
3894 if (size < INTERNET_RFC1123_BUFSIZE * sizeof(*string))
3896 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3897 return FALSE;
3900 ret = InternetTimeFromSystemTimeW( time, format, stringW, sizeof(stringW) );
3901 if (ret) WideCharToMultiByte( CP_ACP, 0, stringW, -1, string, size, NULL, NULL );
3903 return ret;
3906 /***********************************************************************
3907 * InternetTimeFromSystemTimeW (WININET.@)
3909 BOOL WINAPI InternetTimeFromSystemTimeW( const SYSTEMTIME* time, DWORD format, LPWSTR string, DWORD size )
3911 TRACE( "%p 0x%08lx %p 0x%08lx\n", time, format, string, size );
3913 if (!time || !string || format != INTERNET_RFC1123_FORMAT)
3915 SetLastError(ERROR_INVALID_PARAMETER);
3916 return FALSE;
3919 if (size < INTERNET_RFC1123_BUFSIZE * sizeof(*string))
3921 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3922 return FALSE;
3925 swprintf( string, size, L"%s, %02d %s %4d %02d:%02d:%02d GMT",
3926 WININET_wkday[time->wDayOfWeek],
3927 time->wDay,
3928 WININET_month[time->wMonth - 1],
3929 time->wYear,
3930 time->wHour,
3931 time->wMinute,
3932 time->wSecond );
3934 return TRUE;
3937 /***********************************************************************
3938 * InternetTimeToSystemTimeA (WININET.@)
3940 BOOL WINAPI InternetTimeToSystemTimeA( LPCSTR string, SYSTEMTIME* time, DWORD reserved )
3942 BOOL ret = FALSE;
3943 WCHAR *stringW;
3945 TRACE( "%s %p 0x%08lx\n", debugstr_a(string), time, reserved );
3947 stringW = strdupAtoW( string );
3948 if (stringW)
3950 ret = InternetTimeToSystemTimeW( stringW, time, reserved );
3951 free( stringW );
3953 return ret;
3956 /***********************************************************************
3957 * InternetTimeToSystemTimeW (WININET.@)
3959 BOOL WINAPI InternetTimeToSystemTimeW( LPCWSTR string, SYSTEMTIME* time, DWORD reserved )
3961 unsigned int i;
3962 const WCHAR *s = string;
3963 WCHAR *end;
3965 TRACE( "%s %p 0x%08lx\n", debugstr_w(string), time, reserved );
3967 if (!string || !time) return FALSE;
3969 /* Windows does this too */
3970 GetSystemTime( time );
3972 /* Convert an RFC1123 time such as 'Fri, 07 Jan 2005 12:06:35 GMT' into
3973 * a SYSTEMTIME structure.
3976 while (*s && !iswalpha(*s) && !is_time_digit(*s)) s++;
3977 if (*s == '\0') return TRUE;
3978 time->wDayOfWeek = 7;
3980 if (iswalpha(*s))
3982 if (s[1] == '\0' || s[2] == '\0') return TRUE;
3983 for (i = 0; i < 7; i++)
3985 if (!wcsnicmp(WININET_wkday[i], s, 3))
3987 time->wDayOfWeek = i;
3988 break;
3992 else if (is_time_digit(*s))
3994 time->wDayOfWeek = wcstol(s, &end, 10);
3995 s = end;
3997 if (time->wDayOfWeek > 6) return TRUE;
3999 while (*s && !is_time_digit(*s)) s++;
4000 time->wDay = wcstol( s, &end, 10 );
4001 s = end;
4003 while (*s && !iswalpha(*s) && !is_time_digit(*s)) s++;
4004 if (*s == '\0') return TRUE;
4005 time->wMonth = 0;
4007 if (iswalpha(*s))
4009 if (s[1] == '\0' || s[2] == '\0') return TRUE;
4010 for (i = 0; i < 12; i++)
4012 if (!wcsnicmp(WININET_month[i], s, 3))
4014 time->wMonth = i + 1;
4015 break;
4019 else if (is_time_digit(*s))
4021 time->wMonth = wcstol(s, &end, 10);
4022 s = end;
4024 if (time->wMonth == 0) return TRUE;
4026 while (*s && !is_time_digit(*s)) s++;
4027 if (*s == '\0') return TRUE;
4028 time->wYear = wcstol( s, &end, 10 );
4029 s = end;
4031 while (*s && !is_time_digit(*s)) s++;
4032 if (*s == '\0') return TRUE;
4033 time->wHour = wcstol( s, &end, 10 );
4034 s = end;
4036 while (*s && !is_time_digit(*s)) s++;
4037 if (*s == '\0') return TRUE;
4038 time->wMinute = wcstol( s, &end, 10 );
4039 s = end;
4041 while (*s && !is_time_digit(*s)) s++;
4042 if (*s == '\0') return TRUE;
4043 time->wSecond = wcstol( s, &end, 10 );
4044 s = end;
4046 time->wMilliseconds = 0;
4047 return TRUE;
4050 /***********************************************************************
4051 * InternetCheckConnectionW (WININET.@)
4053 * Pings a requested host to check internet connection
4055 * RETURNS
4056 * TRUE on success and FALSE on failure. If a failure then
4057 * ERROR_NOT_CONNECTED is placed into GetLastError
4060 BOOL WINAPI InternetCheckConnectionW( LPCWSTR lpszUrl, DWORD dwFlags, DWORD dwReserved )
4063 * this is a kludge which runs the resident ping program and reads the output.
4065 * Anyone have a better idea?
4068 BOOL rc = FALSE;
4069 static const CHAR ping[] = "ping -c 1 ";
4070 static const CHAR redirect[] = " >/dev/null 2>/dev/null";
4071 WCHAR *host;
4072 DWORD len, host_len;
4073 INTERNET_PORT port;
4074 int status = -1;
4076 FIXME("(%s %lx %lx)\n", debugstr_w(lpszUrl), dwFlags, dwReserved);
4079 * Crack or set the Address
4081 if (lpszUrl == NULL)
4084 * According to the doc we are supposed to use the ip for the next
4085 * server in the WnInet internal server database. I have
4086 * no idea what that is or how to get it.
4088 * So someone needs to implement this.
4090 FIXME("Unimplemented with URL of NULL\n");
4091 return TRUE;
4093 else
4095 URL_COMPONENTSW components = {sizeof(components)};
4097 components.dwHostNameLength = 1;
4099 if (!InternetCrackUrlW(lpszUrl,0,0,&components))
4100 goto End;
4102 host = components.lpszHostName;
4103 host_len = components.dwHostNameLength;
4104 port = components.nPort;
4105 TRACE("host name: %s port: %d\n",debugstr_wn(host, host_len), port);
4108 if (dwFlags & FLAG_ICC_FORCE_CONNECTION)
4110 struct sockaddr_storage saddr;
4111 int sa_len = sizeof(saddr);
4112 WCHAR *host_z;
4113 int fd;
4114 BOOL b;
4116 host_z = strndupW(host, host_len);
4117 if (!host_z)
4118 return FALSE;
4120 b = GetAddress(host_z, port, (struct sockaddr *)&saddr, &sa_len, NULL);
4121 free(host_z);
4122 if(!b)
4123 goto End;
4124 init_winsock();
4125 fd = socket(saddr.ss_family, SOCK_STREAM, 0);
4126 if (fd != -1)
4128 if (connect(fd, (struct sockaddr *)&saddr, sa_len) == 0)
4129 rc = TRUE;
4130 closesocket(fd);
4133 else
4136 * Build our ping command
4138 char *command;
4140 len = WideCharToMultiByte(CP_UNIXCP, 0, host, host_len, NULL, 0, NULL, NULL);
4141 command = malloc(strlen(ping) + len + strlen(redirect) + 1);
4142 strcpy(command, ping);
4143 WideCharToMultiByte(CP_UNIXCP, 0, host, host_len, command+sizeof(ping)-1, len, NULL, NULL);
4144 strcpy(command+sizeof(ping)-1+len, redirect);
4146 TRACE("Ping command is : %s\n",command);
4148 status = system(command);
4149 free(command);
4151 TRACE("Ping returned a code of %i\n",status);
4153 /* Ping return code of 0 indicates success */
4154 if (status == 0)
4155 rc = TRUE;
4158 End:
4159 if (rc == FALSE)
4160 INTERNET_SetLastError(ERROR_NOT_CONNECTED);
4162 return rc;
4166 /***********************************************************************
4167 * InternetCheckConnectionA (WININET.@)
4169 * Pings a requested host to check internet connection
4171 * RETURNS
4172 * TRUE on success and FALSE on failure. If a failure then
4173 * ERROR_NOT_CONNECTED is placed into GetLastError
4176 BOOL WINAPI InternetCheckConnectionA(LPCSTR lpszUrl, DWORD dwFlags, DWORD dwReserved)
4178 WCHAR *url = NULL;
4179 BOOL rc;
4181 if(lpszUrl) {
4182 url = strdupAtoW(lpszUrl);
4183 if(!url)
4184 return FALSE;
4187 rc = InternetCheckConnectionW(url, dwFlags, dwReserved);
4189 free(url);
4190 return rc;
4194 /**********************************************************
4195 * INTERNET_InternetOpenUrlW (internal)
4197 * Opens an URL
4199 * RETURNS
4200 * handle of connection or NULL on failure
4202 static HINTERNET INTERNET_InternetOpenUrlW(appinfo_t *hIC, LPCWSTR lpszUrl,
4203 LPCWSTR lpszHeaders, DWORD dwHeadersLength, DWORD dwFlags, DWORD_PTR dwContext)
4205 URL_COMPONENTSW urlComponents = { sizeof(urlComponents) };
4206 WCHAR *host, *user = NULL, *pass = NULL, *path;
4207 HINTERNET client = NULL, client1 = NULL;
4208 DWORD res;
4210 TRACE("(%p, %s, %s, %08lx, %08lx, %08Ix)\n", hIC, debugstr_w(lpszUrl), debugstr_w(lpszHeaders),
4211 dwHeadersLength, dwFlags, dwContext);
4213 urlComponents.dwHostNameLength = 1;
4214 urlComponents.dwUserNameLength = 1;
4215 urlComponents.dwPasswordLength = 1;
4216 urlComponents.dwUrlPathLength = 1;
4217 urlComponents.dwExtraInfoLength = 1;
4218 if(!InternetCrackUrlW(lpszUrl, lstrlenW(lpszUrl), 0, &urlComponents))
4219 return NULL;
4221 if ((urlComponents.nScheme == INTERNET_SCHEME_HTTP || urlComponents.nScheme == INTERNET_SCHEME_HTTPS) &&
4222 urlComponents.dwExtraInfoLength)
4224 assert(urlComponents.lpszUrlPath + urlComponents.dwUrlPathLength == urlComponents.lpszExtraInfo);
4225 urlComponents.dwUrlPathLength += urlComponents.dwExtraInfoLength;
4228 host = strndupW(urlComponents.lpszHostName, urlComponents.dwHostNameLength);
4229 path = strndupW(urlComponents.lpszUrlPath, urlComponents.dwUrlPathLength);
4230 if(urlComponents.dwUserNameLength)
4231 user = strndupW(urlComponents.lpszUserName, urlComponents.dwUserNameLength);
4232 if(urlComponents.dwPasswordLength)
4233 pass = strndupW(urlComponents.lpszPassword, urlComponents.dwPasswordLength);
4235 switch(urlComponents.nScheme) {
4236 case INTERNET_SCHEME_FTP:
4237 client = FTP_Connect(hIC, host, urlComponents.nPort,
4238 user, pass, dwFlags, dwContext, INET_OPENURL);
4239 if(client == NULL)
4240 break;
4241 client1 = FtpOpenFileW(client, path, GENERIC_READ, dwFlags, dwContext);
4242 if(client1 == NULL) {
4243 InternetCloseHandle(client);
4244 break;
4246 break;
4248 case INTERNET_SCHEME_HTTP:
4249 case INTERNET_SCHEME_HTTPS: {
4250 LPCWSTR accept[2] = { L"*/*", NULL };
4252 if (urlComponents.nScheme == INTERNET_SCHEME_HTTPS) dwFlags |= INTERNET_FLAG_SECURE;
4254 /* FIXME: should use pointers, not handles, as handles are not thread-safe */
4255 res = HTTP_Connect(hIC, host, urlComponents.nPort,
4256 user, pass, dwFlags, dwContext, INET_OPENURL, &client);
4257 if(res != ERROR_SUCCESS) {
4258 INTERNET_SetLastError(res);
4259 break;
4262 client1 = HttpOpenRequestW(client, NULL, path, NULL, NULL, accept, dwFlags, dwContext);
4263 if(client1 == NULL) {
4264 InternetCloseHandle(client);
4265 break;
4267 HttpAddRequestHeadersW(client1, lpszHeaders, dwHeadersLength, HTTP_ADDREQ_FLAG_ADD);
4268 if (!HttpSendRequestW(client1, NULL, 0, NULL, 0) &&
4269 GetLastError() != ERROR_IO_PENDING) {
4270 InternetCloseHandle(client1);
4271 client1 = NULL;
4272 break;
4275 case INTERNET_SCHEME_GOPHER:
4276 /* gopher doesn't seem to be implemented in wine, but it's supposed
4277 * to be supported by InternetOpenUrlA. */
4278 default:
4279 SetLastError(ERROR_INTERNET_UNRECOGNIZED_SCHEME);
4280 break;
4283 TRACE(" %p <--\n", client1);
4285 free(host);
4286 free(path);
4287 free(user);
4288 free(pass);
4289 return client1;
4292 /**********************************************************
4293 * InternetOpenUrlW (WININET.@)
4295 * Opens an URL
4297 * RETURNS
4298 * handle of connection or NULL on failure
4300 typedef struct {
4301 task_header_t hdr;
4302 WCHAR *url;
4303 WCHAR *headers;
4304 DWORD headers_len;
4305 DWORD flags;
4306 DWORD_PTR context;
4307 } open_url_task_t;
4309 static void AsyncInternetOpenUrlProc(task_header_t *hdr)
4311 open_url_task_t *task = (open_url_task_t*)hdr;
4313 TRACE("%p\n", task->hdr.hdr);
4315 INTERNET_InternetOpenUrlW((appinfo_t*)task->hdr.hdr, task->url, task->headers,
4316 task->headers_len, task->flags, task->context);
4317 free(task->url);
4318 free(task->headers);
4321 HINTERNET WINAPI InternetOpenUrlW(HINTERNET hInternet, LPCWSTR lpszUrl,
4322 LPCWSTR lpszHeaders, DWORD dwHeadersLength, DWORD dwFlags, DWORD_PTR dwContext)
4324 HINTERNET ret = NULL;
4325 appinfo_t *hIC = NULL;
4327 if (TRACE_ON(wininet)) {
4328 TRACE("(%p, %s, %s, %08lx, %08lx, %08Ix)\n", hInternet, debugstr_w(lpszUrl), debugstr_w(lpszHeaders),
4329 dwHeadersLength, dwFlags, dwContext);
4330 TRACE(" flags :");
4331 dump_INTERNET_FLAGS(dwFlags);
4334 if (!lpszUrl)
4336 SetLastError(ERROR_INVALID_PARAMETER);
4337 goto lend;
4340 hIC = (appinfo_t*)get_handle_object( hInternet );
4341 if (NULL == hIC || hIC->hdr.htype != WH_HINIT) {
4342 SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
4343 goto lend;
4346 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC) {
4347 open_url_task_t *task;
4349 task = alloc_async_task(&hIC->hdr, AsyncInternetOpenUrlProc, sizeof(*task));
4350 task->url = wcsdup(lpszUrl);
4351 task->headers = wcsdup(lpszHeaders);
4352 task->headers_len = dwHeadersLength;
4353 task->flags = dwFlags;
4354 task->context = dwContext;
4356 INTERNET_AsyncCall(&task->hdr);
4357 SetLastError(ERROR_IO_PENDING);
4358 } else {
4359 ret = INTERNET_InternetOpenUrlW(hIC, lpszUrl, lpszHeaders, dwHeadersLength, dwFlags, dwContext);
4362 lend:
4363 if( hIC )
4364 WININET_Release( &hIC->hdr );
4365 TRACE(" %p <--\n", ret);
4367 return ret;
4370 /**********************************************************
4371 * InternetOpenUrlA (WININET.@)
4373 * Opens an URL
4375 * RETURNS
4376 * handle of connection or NULL on failure
4378 HINTERNET WINAPI InternetOpenUrlA(HINTERNET hInternet, LPCSTR lpszUrl,
4379 LPCSTR lpszHeaders, DWORD dwHeadersLength, DWORD dwFlags, DWORD_PTR dwContext)
4381 HINTERNET rc = NULL;
4382 LPWSTR szUrl = NULL;
4383 WCHAR *headers = NULL;
4385 TRACE("\n");
4387 if(lpszUrl) {
4388 szUrl = strdupAtoW(lpszUrl);
4389 if(!szUrl)
4390 return NULL;
4393 if(lpszHeaders) {
4394 headers = strndupAtoW(lpszHeaders, dwHeadersLength, &dwHeadersLength);
4395 if(!headers) {
4396 free(szUrl);
4397 return NULL;
4401 rc = InternetOpenUrlW(hInternet, szUrl, headers, dwHeadersLength, dwFlags, dwContext);
4403 free(szUrl);
4404 free(headers);
4405 return rc;
4409 static LPWITHREADERROR INTERNET_AllocThreadError(void)
4411 WITHREADERROR *lpwite = malloc(sizeof(*lpwite));
4413 if (lpwite)
4415 lpwite->dwError = 0;
4416 lpwite->response[0] = '\0';
4419 if (!TlsSetValue(g_dwTlsErrIndex, lpwite))
4421 free(lpwite);
4422 return NULL;
4424 return lpwite;
4428 /***********************************************************************
4429 * INTERNET_SetLastError (internal)
4431 * Set last thread specific error
4433 * RETURNS
4436 void INTERNET_SetLastError(DWORD dwError)
4438 LPWITHREADERROR lpwite = TlsGetValue(g_dwTlsErrIndex);
4440 if (!lpwite)
4441 lpwite = INTERNET_AllocThreadError();
4443 SetLastError(dwError);
4444 if(lpwite)
4445 lpwite->dwError = dwError;
4449 /***********************************************************************
4450 * INTERNET_GetLastError (internal)
4452 * Get last thread specific error
4454 * RETURNS
4457 DWORD INTERNET_GetLastError(void)
4459 LPWITHREADERROR lpwite = TlsGetValue(g_dwTlsErrIndex);
4460 if (!lpwite) return 0;
4461 /* TlsGetValue clears last error, so set it again here */
4462 SetLastError(lpwite->dwError);
4463 return lpwite->dwError;
4467 /***********************************************************************
4468 * INTERNET_WorkerThreadFunc (internal)
4470 * Worker thread execution function
4472 * RETURNS
4475 static DWORD CALLBACK INTERNET_WorkerThreadFunc(LPVOID lpvParam)
4477 task_header_t *task = lpvParam;
4479 TRACE("\n");
4481 task->proc(task);
4482 WININET_Release(task->hdr);
4483 free(task);
4485 if (g_dwTlsErrIndex != TLS_OUT_OF_INDEXES)
4487 free(TlsGetValue(g_dwTlsErrIndex));
4488 TlsSetValue(g_dwTlsErrIndex, NULL);
4490 return TRUE;
4493 void *alloc_async_task(object_header_t *hdr, async_task_proc_t proc, size_t size)
4495 task_header_t *task;
4497 task = malloc(size);
4498 if(!task)
4499 return NULL;
4501 task->hdr = WININET_AddRef(hdr);
4502 task->proc = proc;
4503 return task;
4506 /***********************************************************************
4507 * INTERNET_AsyncCall (internal)
4509 * Retrieves work request from queue
4511 * RETURNS
4514 DWORD INTERNET_AsyncCall(task_header_t *task)
4516 BOOL bSuccess;
4518 TRACE("\n");
4520 bSuccess = QueueUserWorkItem(INTERNET_WorkerThreadFunc, task, WT_EXECUTELONGFUNCTION);
4521 if (!bSuccess)
4523 free(task);
4524 return ERROR_INTERNET_ASYNC_THREAD_FAILED;
4526 return ERROR_SUCCESS;
4530 /***********************************************************************
4531 * INTERNET_GetResponseBuffer (internal)
4533 * RETURNS
4536 LPSTR INTERNET_GetResponseBuffer(void)
4538 LPWITHREADERROR lpwite = TlsGetValue(g_dwTlsErrIndex);
4539 if (!lpwite)
4540 lpwite = INTERNET_AllocThreadError();
4541 TRACE("\n");
4542 return lpwite->response;
4545 /**********************************************************
4546 * InternetQueryDataAvailable (WININET.@)
4548 * Determines how much data is available to be read.
4550 * RETURNS
4551 * TRUE on success, FALSE if an error occurred. If
4552 * INTERNET_FLAG_ASYNC was specified in InternetOpen, and
4553 * no data is presently available, FALSE is returned with
4554 * the last error ERROR_IO_PENDING; a callback with status
4555 * INTERNET_STATUS_REQUEST_COMPLETE will be sent when more
4556 * data is available.
4558 BOOL WINAPI InternetQueryDataAvailable( HINTERNET hFile,
4559 LPDWORD lpdwNumberOfBytesAvailable,
4560 DWORD dwFlags, DWORD_PTR dwContext)
4562 object_header_t *hdr;
4563 DWORD res;
4565 TRACE("(%p %p %lx %Ix)\n", hFile, lpdwNumberOfBytesAvailable, dwFlags, dwContext);
4567 hdr = get_handle_object( hFile );
4568 if (!hdr) {
4569 SetLastError(ERROR_INVALID_HANDLE);
4570 return FALSE;
4573 if(hdr->vtbl->QueryDataAvailable) {
4574 res = hdr->vtbl->QueryDataAvailable(hdr, lpdwNumberOfBytesAvailable, dwFlags, dwContext);
4575 }else {
4576 WARN("wrong handle\n");
4577 res = ERROR_INTERNET_INCORRECT_HANDLE_TYPE;
4580 WININET_Release(hdr);
4582 if(res != ERROR_SUCCESS)
4583 SetLastError(res);
4584 return res == ERROR_SUCCESS;
4587 DWORD create_req_file(const WCHAR *file_name, req_file_t **ret)
4589 req_file_t *req_file;
4591 req_file = calloc(1, sizeof(*req_file));
4592 if(!req_file)
4593 return ERROR_NOT_ENOUGH_MEMORY;
4595 req_file->ref = 1;
4597 req_file->file_name = wcsdup(file_name);
4598 if(!req_file->file_name) {
4599 free(req_file);
4600 return ERROR_NOT_ENOUGH_MEMORY;
4603 req_file->file_handle = CreateFileW(req_file->file_name, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE,
4604 NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
4605 if(req_file->file_handle == INVALID_HANDLE_VALUE) {
4606 req_file_release(req_file);
4607 return GetLastError();
4610 *ret = req_file;
4611 return ERROR_SUCCESS;
4614 void req_file_release(req_file_t *req_file)
4616 if(InterlockedDecrement(&req_file->ref))
4617 return;
4619 if(!req_file->is_committed)
4620 DeleteFileW(req_file->file_name);
4621 if(req_file->file_handle && req_file->file_handle != INVALID_HANDLE_VALUE)
4622 CloseHandle(req_file->file_handle);
4623 free(req_file->file_name);
4624 free(req_file->url);
4625 free(req_file);
4628 /***********************************************************************
4629 * InternetLockRequestFile (WININET.@)
4631 BOOL WINAPI InternetLockRequestFile(HINTERNET hInternet, HANDLE *lphLockReqHandle)
4633 req_file_t *req_file = NULL;
4634 object_header_t *hdr;
4635 DWORD res;
4637 TRACE("(%p %p)\n", hInternet, lphLockReqHandle);
4639 hdr = get_handle_object(hInternet);
4640 if (!hdr) {
4641 SetLastError(ERROR_INVALID_HANDLE);
4642 return FALSE;
4645 if(hdr->vtbl->LockRequestFile) {
4646 res = hdr->vtbl->LockRequestFile(hdr, &req_file);
4647 }else {
4648 WARN("wrong handle\n");
4649 res = ERROR_INTERNET_INCORRECT_HANDLE_TYPE;
4652 WININET_Release(hdr);
4654 *lphLockReqHandle = req_file;
4655 if(res != ERROR_SUCCESS)
4656 SetLastError(res);
4657 return res == ERROR_SUCCESS;
4660 BOOL WINAPI InternetUnlockRequestFile(HANDLE hLockHandle)
4662 TRACE("(%p)\n", hLockHandle);
4664 req_file_release(hLockHandle);
4665 return TRUE;
4669 /***********************************************************************
4670 * InternetAutodial (WININET.@)
4672 * On windows this function is supposed to dial the default internet
4673 * connection. We don't want to have Wine dial out to the internet so
4674 * we return TRUE by default. It might be nice to check if we are connected.
4676 * RETURNS
4677 * TRUE on success
4678 * FALSE on failure
4681 BOOL WINAPI InternetAutodial(DWORD dwFlags, HWND hwndParent)
4683 FIXME("STUB\n");
4685 /* Tell that we are connected to the internet. */
4686 return TRUE;
4689 /***********************************************************************
4690 * InternetAutodialHangup (WININET.@)
4692 * Hangs up a connection made with InternetAutodial
4694 * PARAM
4695 * dwReserved
4696 * RETURNS
4697 * TRUE on success
4698 * FALSE on failure
4701 BOOL WINAPI InternetAutodialHangup(DWORD dwReserved)
4703 FIXME("STUB\n");
4705 /* we didn't dial, we don't disconnect */
4706 return TRUE;
4709 /***********************************************************************
4710 * InternetCombineUrlA (WININET.@)
4712 * Combine a base URL with a relative URL
4714 * RETURNS
4715 * TRUE on success
4716 * FALSE on failure
4720 BOOL WINAPI InternetCombineUrlA(LPCSTR lpszBaseUrl, LPCSTR lpszRelativeUrl,
4721 LPSTR lpszBuffer, LPDWORD lpdwBufferLength,
4722 DWORD dwFlags)
4724 HRESULT hr=S_OK;
4726 TRACE("(%s, %s, %p, %p, 0x%08lx)\n", debugstr_a(lpszBaseUrl), debugstr_a(lpszRelativeUrl), lpszBuffer, lpdwBufferLength, dwFlags);
4728 /* Flip this bit to correspond to URL_ESCAPE_UNSAFE */
4729 dwFlags ^= ICU_NO_ENCODE;
4730 hr=UrlCombineA(lpszBaseUrl,lpszRelativeUrl,lpszBuffer,lpdwBufferLength,dwFlags);
4732 return (hr==S_OK);
4735 /***********************************************************************
4736 * InternetCombineUrlW (WININET.@)
4738 * Combine a base URL with a relative URL
4740 * RETURNS
4741 * TRUE on success
4742 * FALSE on failure
4746 BOOL WINAPI InternetCombineUrlW(LPCWSTR lpszBaseUrl, LPCWSTR lpszRelativeUrl,
4747 LPWSTR lpszBuffer, LPDWORD lpdwBufferLength,
4748 DWORD dwFlags)
4750 HRESULT hr=S_OK;
4752 TRACE("(%s, %s, %p, %p, 0x%08lx)\n", debugstr_w(lpszBaseUrl), debugstr_w(lpszRelativeUrl), lpszBuffer, lpdwBufferLength, dwFlags);
4754 /* Flip this bit to correspond to URL_ESCAPE_UNSAFE */
4755 dwFlags ^= ICU_NO_ENCODE;
4756 hr=UrlCombineW(lpszBaseUrl,lpszRelativeUrl,lpszBuffer,lpdwBufferLength,dwFlags);
4758 return (hr==S_OK);
4761 /* max port num is 65535 => 5 digits */
4762 #define MAX_WORD_DIGITS 5
4764 #define URL_GET_COMP_LENGTH(url, component) ((url)->dw##component##Length ? \
4765 (url)->dw##component##Length : lstrlenW((url)->lpsz##component))
4766 #define URL_GET_COMP_LENGTHA(url, component) ((url)->dw##component##Length ? \
4767 (url)->dw##component##Length : strlen((url)->lpsz##component))
4769 static BOOL url_uses_default_port(INTERNET_SCHEME nScheme, INTERNET_PORT nPort)
4771 if ((nScheme == INTERNET_SCHEME_HTTP) &&
4772 (nPort == INTERNET_DEFAULT_HTTP_PORT))
4773 return TRUE;
4774 if ((nScheme == INTERNET_SCHEME_HTTPS) &&
4775 (nPort == INTERNET_DEFAULT_HTTPS_PORT))
4776 return TRUE;
4777 if ((nScheme == INTERNET_SCHEME_FTP) &&
4778 (nPort == INTERNET_DEFAULT_FTP_PORT))
4779 return TRUE;
4780 if ((nScheme == INTERNET_SCHEME_GOPHER) &&
4781 (nPort == INTERNET_DEFAULT_GOPHER_PORT))
4782 return TRUE;
4784 if (nPort == INTERNET_INVALID_PORT_NUMBER)
4785 return TRUE;
4787 return FALSE;
4790 /* opaque urls do not fit into the standard url hierarchy and don't have
4791 * two following slashes */
4792 static inline BOOL scheme_is_opaque(INTERNET_SCHEME nScheme)
4794 return (nScheme != INTERNET_SCHEME_FTP) &&
4795 (nScheme != INTERNET_SCHEME_GOPHER) &&
4796 (nScheme != INTERNET_SCHEME_HTTP) &&
4797 (nScheme != INTERNET_SCHEME_HTTPS) &&
4798 (nScheme != INTERNET_SCHEME_FILE);
4801 static LPCWSTR INTERNET_GetSchemeString(INTERNET_SCHEME scheme)
4803 int index;
4804 if (scheme < INTERNET_SCHEME_FIRST)
4805 return NULL;
4806 index = scheme - INTERNET_SCHEME_FIRST;
4807 if (index >= ARRAY_SIZE(url_schemes))
4808 return NULL;
4809 return url_schemes[index];
4812 /* we can calculate using ansi strings because we're just
4813 * calculating string length, not size
4815 static BOOL calc_url_length(LPURL_COMPONENTSW lpUrlComponents,
4816 LPDWORD lpdwUrlLength)
4818 INTERNET_SCHEME nScheme;
4820 *lpdwUrlLength = 0;
4822 if (lpUrlComponents->lpszScheme)
4824 DWORD dwLen = URL_GET_COMP_LENGTH(lpUrlComponents, Scheme);
4825 *lpdwUrlLength += dwLen;
4826 nScheme = GetInternetSchemeW(lpUrlComponents->lpszScheme, dwLen);
4828 else
4830 LPCWSTR scheme;
4832 if (lpUrlComponents->nScheme == INTERNET_SCHEME_UNKNOWN)
4834 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
4835 return FALSE;
4838 nScheme = lpUrlComponents->nScheme;
4840 if (nScheme == INTERNET_SCHEME_DEFAULT)
4841 nScheme = INTERNET_SCHEME_HTTP;
4842 scheme = INTERNET_GetSchemeString(nScheme);
4843 *lpdwUrlLength += lstrlenW(scheme);
4846 (*lpdwUrlLength)++; /* ':' */
4847 if (!scheme_is_opaque(nScheme) || lpUrlComponents->lpszHostName)
4848 *lpdwUrlLength += strlen("//");
4850 if (lpUrlComponents->lpszUserName)
4852 *lpdwUrlLength += URL_GET_COMP_LENGTH(lpUrlComponents, UserName);
4853 *lpdwUrlLength += strlen("@");
4855 else
4857 if (lpUrlComponents->lpszPassword)
4859 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
4860 return FALSE;
4864 if (lpUrlComponents->lpszPassword)
4866 *lpdwUrlLength += strlen(":");
4867 *lpdwUrlLength += URL_GET_COMP_LENGTH(lpUrlComponents, Password);
4870 if (lpUrlComponents->lpszHostName)
4872 *lpdwUrlLength += URL_GET_COMP_LENGTH(lpUrlComponents, HostName);
4874 if (!url_uses_default_port(nScheme, lpUrlComponents->nPort))
4876 WCHAR port[MAX_WORD_DIGITS + 1];
4878 _ltow(lpUrlComponents->nPort, port, 10);
4879 *lpdwUrlLength += lstrlenW(port);
4880 *lpdwUrlLength += strlen(":");
4883 if (lpUrlComponents->lpszUrlPath && *lpUrlComponents->lpszUrlPath != '/')
4884 (*lpdwUrlLength)++; /* '/' */
4887 if (lpUrlComponents->lpszUrlPath)
4888 *lpdwUrlLength += URL_GET_COMP_LENGTH(lpUrlComponents, UrlPath);
4890 if (lpUrlComponents->lpszExtraInfo)
4891 *lpdwUrlLength += URL_GET_COMP_LENGTH(lpUrlComponents, ExtraInfo);
4893 return TRUE;
4896 static void convert_urlcomp_atow(LPURL_COMPONENTSA lpUrlComponents, LPURL_COMPONENTSW urlCompW)
4898 INT len;
4900 ZeroMemory(urlCompW, sizeof(URL_COMPONENTSW));
4902 urlCompW->dwStructSize = sizeof(URL_COMPONENTSW);
4903 urlCompW->dwSchemeLength = lpUrlComponents->dwSchemeLength;
4904 urlCompW->nScheme = lpUrlComponents->nScheme;
4905 urlCompW->dwHostNameLength = lpUrlComponents->dwHostNameLength;
4906 urlCompW->nPort = lpUrlComponents->nPort;
4907 urlCompW->dwUserNameLength = lpUrlComponents->dwUserNameLength;
4908 urlCompW->dwPasswordLength = lpUrlComponents->dwPasswordLength;
4909 urlCompW->dwUrlPathLength = lpUrlComponents->dwUrlPathLength;
4910 urlCompW->dwExtraInfoLength = lpUrlComponents->dwExtraInfoLength;
4912 if (lpUrlComponents->lpszScheme)
4914 len = URL_GET_COMP_LENGTHA(lpUrlComponents, Scheme) + 1;
4915 urlCompW->lpszScheme = malloc(len * sizeof(WCHAR));
4916 MultiByteToWideChar(CP_ACP, 0, lpUrlComponents->lpszScheme,
4917 -1, urlCompW->lpszScheme, len);
4920 if (lpUrlComponents->lpszHostName)
4922 len = URL_GET_COMP_LENGTHA(lpUrlComponents, HostName) + 1;
4923 urlCompW->lpszHostName = malloc(len * sizeof(WCHAR));
4924 MultiByteToWideChar(CP_ACP, 0, lpUrlComponents->lpszHostName,
4925 -1, urlCompW->lpszHostName, len);
4928 if (lpUrlComponents->lpszUserName)
4930 len = URL_GET_COMP_LENGTHA(lpUrlComponents, UserName) + 1;
4931 urlCompW->lpszUserName = malloc(len * sizeof(WCHAR));
4932 MultiByteToWideChar(CP_ACP, 0, lpUrlComponents->lpszUserName,
4933 -1, urlCompW->lpszUserName, len);
4936 if (lpUrlComponents->lpszPassword)
4938 len = URL_GET_COMP_LENGTHA(lpUrlComponents, Password) + 1;
4939 urlCompW->lpszPassword = malloc(len * sizeof(WCHAR));
4940 MultiByteToWideChar(CP_ACP, 0, lpUrlComponents->lpszPassword,
4941 -1, urlCompW->lpszPassword, len);
4944 if (lpUrlComponents->lpszUrlPath)
4946 len = URL_GET_COMP_LENGTHA(lpUrlComponents, UrlPath) + 1;
4947 urlCompW->lpszUrlPath = malloc(len * sizeof(WCHAR));
4948 MultiByteToWideChar(CP_ACP, 0, lpUrlComponents->lpszUrlPath,
4949 -1, urlCompW->lpszUrlPath, len);
4952 if (lpUrlComponents->lpszExtraInfo)
4954 len = URL_GET_COMP_LENGTHA(lpUrlComponents, ExtraInfo) + 1;
4955 urlCompW->lpszExtraInfo = malloc(len * sizeof(WCHAR));
4956 MultiByteToWideChar(CP_ACP, 0, lpUrlComponents->lpszExtraInfo,
4957 -1, urlCompW->lpszExtraInfo, len);
4961 /***********************************************************************
4962 * InternetCreateUrlA (WININET.@)
4964 * See InternetCreateUrlW.
4966 BOOL WINAPI InternetCreateUrlA(LPURL_COMPONENTSA lpUrlComponents, DWORD dwFlags,
4967 LPSTR lpszUrl, LPDWORD lpdwUrlLength)
4969 BOOL ret;
4970 LPWSTR urlW = NULL;
4971 URL_COMPONENTSW urlCompW;
4973 TRACE("(%p,%ld,%p,%p)\n", lpUrlComponents, dwFlags, lpszUrl, lpdwUrlLength);
4975 if (!lpUrlComponents || lpUrlComponents->dwStructSize != sizeof(URL_COMPONENTSW) || !lpdwUrlLength)
4977 SetLastError(ERROR_INVALID_PARAMETER);
4978 return FALSE;
4981 convert_urlcomp_atow(lpUrlComponents, &urlCompW);
4983 if (lpszUrl)
4984 urlW = malloc(*lpdwUrlLength * sizeof(WCHAR));
4986 ret = InternetCreateUrlW(&urlCompW, dwFlags, urlW, lpdwUrlLength);
4988 if (!ret && (GetLastError() == ERROR_INSUFFICIENT_BUFFER))
4989 *lpdwUrlLength /= sizeof(WCHAR);
4991 /* on success, lpdwUrlLength points to the size of urlW in WCHARS
4992 * minus one, so add one to leave room for NULL terminator
4994 if (ret)
4995 WideCharToMultiByte(CP_ACP, 0, urlW, -1, lpszUrl, *lpdwUrlLength + 1, NULL, NULL);
4997 free(urlCompW.lpszScheme);
4998 free(urlCompW.lpszHostName);
4999 free(urlCompW.lpszUserName);
5000 free(urlCompW.lpszPassword);
5001 free(urlCompW.lpszUrlPath);
5002 free(urlCompW.lpszExtraInfo);
5003 free(urlW);
5004 return ret;
5007 /***********************************************************************
5008 * InternetCreateUrlW (WININET.@)
5010 * Creates a URL from its component parts.
5012 * PARAMS
5013 * lpUrlComponents [I] URL Components.
5014 * dwFlags [I] Flags. See notes.
5015 * lpszUrl [I] Buffer in which to store the created URL.
5016 * lpdwUrlLength [I/O] On input, the length of the buffer pointed to by
5017 * lpszUrl in characters. On output, the number of bytes
5018 * required to store the URL including terminator.
5020 * NOTES
5022 * The dwFlags parameter can be zero or more of the following:
5023 *|ICU_ESCAPE - Generates escape sequences for unsafe characters in the path and extra info of the URL.
5025 * RETURNS
5026 * TRUE on success
5027 * FALSE on failure
5030 BOOL WINAPI InternetCreateUrlW(LPURL_COMPONENTSW lpUrlComponents, DWORD dwFlags,
5031 LPWSTR lpszUrl, LPDWORD lpdwUrlLength)
5033 DWORD dwLen;
5034 INTERNET_SCHEME nScheme;
5036 static const WCHAR slashSlashW[] = {'/','/'};
5038 TRACE("(%p,%ld,%p,%p)\n", lpUrlComponents, dwFlags, lpszUrl, lpdwUrlLength);
5040 if (!lpUrlComponents || lpUrlComponents->dwStructSize != sizeof(URL_COMPONENTSW) || !lpdwUrlLength)
5042 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
5043 return FALSE;
5046 if (!calc_url_length(lpUrlComponents, &dwLen))
5047 return FALSE;
5049 if (!lpszUrl || *lpdwUrlLength < dwLen)
5051 *lpdwUrlLength = (dwLen + 1) * sizeof(WCHAR);
5052 INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
5053 return FALSE;
5056 *lpdwUrlLength = dwLen;
5057 lpszUrl[0] = 0x00;
5059 dwLen = 0;
5061 if (lpUrlComponents->lpszScheme)
5063 dwLen = URL_GET_COMP_LENGTH(lpUrlComponents, Scheme);
5064 memcpy(lpszUrl, lpUrlComponents->lpszScheme, dwLen * sizeof(WCHAR));
5065 lpszUrl += dwLen;
5067 nScheme = GetInternetSchemeW(lpUrlComponents->lpszScheme, dwLen);
5069 else
5071 LPCWSTR scheme;
5072 nScheme = lpUrlComponents->nScheme;
5074 if (nScheme == INTERNET_SCHEME_DEFAULT)
5075 nScheme = INTERNET_SCHEME_HTTP;
5077 scheme = INTERNET_GetSchemeString(nScheme);
5078 dwLen = lstrlenW(scheme);
5079 memcpy(lpszUrl, scheme, dwLen * sizeof(WCHAR));
5080 lpszUrl += dwLen;
5083 /* all schemes are followed by at least a colon */
5084 *lpszUrl = ':';
5085 lpszUrl++;
5087 if (!scheme_is_opaque(nScheme) || lpUrlComponents->lpszHostName)
5089 memcpy(lpszUrl, slashSlashW, sizeof(slashSlashW));
5090 lpszUrl += ARRAY_SIZE(slashSlashW);
5093 if (lpUrlComponents->lpszUserName)
5095 dwLen = URL_GET_COMP_LENGTH(lpUrlComponents, UserName);
5096 memcpy(lpszUrl, lpUrlComponents->lpszUserName, dwLen * sizeof(WCHAR));
5097 lpszUrl += dwLen;
5099 if (lpUrlComponents->lpszPassword)
5101 *lpszUrl = ':';
5102 lpszUrl++;
5104 dwLen = URL_GET_COMP_LENGTH(lpUrlComponents, Password);
5105 memcpy(lpszUrl, lpUrlComponents->lpszPassword, dwLen * sizeof(WCHAR));
5106 lpszUrl += dwLen;
5109 *lpszUrl = '@';
5110 lpszUrl++;
5113 if (lpUrlComponents->lpszHostName)
5115 dwLen = URL_GET_COMP_LENGTH(lpUrlComponents, HostName);
5116 memcpy(lpszUrl, lpUrlComponents->lpszHostName, dwLen * sizeof(WCHAR));
5117 lpszUrl += dwLen;
5119 if (!url_uses_default_port(nScheme, lpUrlComponents->nPort))
5121 *lpszUrl++ = ':';
5122 _ltow(lpUrlComponents->nPort, lpszUrl, 10);
5123 lpszUrl += lstrlenW(lpszUrl);
5126 /* add slash between hostname and path if necessary */
5127 if (lpUrlComponents->lpszUrlPath && *lpUrlComponents->lpszUrlPath != '/')
5129 *lpszUrl = '/';
5130 lpszUrl++;
5134 if (lpUrlComponents->lpszUrlPath)
5136 dwLen = URL_GET_COMP_LENGTH(lpUrlComponents, UrlPath);
5137 memcpy(lpszUrl, lpUrlComponents->lpszUrlPath, dwLen * sizeof(WCHAR));
5138 lpszUrl += dwLen;
5141 if (lpUrlComponents->lpszExtraInfo)
5143 dwLen = URL_GET_COMP_LENGTH(lpUrlComponents, ExtraInfo);
5144 memcpy(lpszUrl, lpUrlComponents->lpszExtraInfo, dwLen * sizeof(WCHAR));
5145 lpszUrl += dwLen;
5148 *lpszUrl = '\0';
5150 return TRUE;
5153 /***********************************************************************
5154 * InternetConfirmZoneCrossingA (WININET.@)
5157 DWORD WINAPI InternetConfirmZoneCrossingA( HWND hWnd, LPSTR szUrlPrev, LPSTR szUrlNew, BOOL bPost )
5159 FIXME("(%p, %s, %s, %x) stub\n", hWnd, debugstr_a(szUrlPrev), debugstr_a(szUrlNew), bPost);
5160 return ERROR_SUCCESS;
5163 /***********************************************************************
5164 * InternetConfirmZoneCrossingW (WININET.@)
5167 DWORD WINAPI InternetConfirmZoneCrossingW( HWND hWnd, LPWSTR szUrlPrev, LPWSTR szUrlNew, BOOL bPost )
5169 FIXME("(%p, %s, %s, %x) stub\n", hWnd, debugstr_w(szUrlPrev), debugstr_w(szUrlNew), bPost);
5170 return ERROR_SUCCESS;
5173 static DWORD zone_preference = 3;
5175 /***********************************************************************
5176 * PrivacySetZonePreferenceW (WININET.@)
5178 DWORD WINAPI PrivacySetZonePreferenceW( DWORD zone, DWORD type, DWORD template, LPCWSTR preference )
5180 FIXME( "%lx %lx %lx %s: stub\n", zone, type, template, debugstr_w(preference) );
5182 zone_preference = template;
5183 return 0;
5186 /***********************************************************************
5187 * PrivacyGetZonePreferenceW (WININET.@)
5189 DWORD WINAPI PrivacyGetZonePreferenceW( DWORD zone, DWORD type, LPDWORD template,
5190 LPWSTR preference, LPDWORD length )
5192 FIXME( "%lx %lx %p %p %p: stub\n", zone, type, template, preference, length );
5194 if (template) *template = zone_preference;
5195 return 0;
5198 /***********************************************************************
5199 * InternetGetSecurityInfoByURLA (WININET.@)
5201 BOOL WINAPI InternetGetSecurityInfoByURLA(LPSTR lpszURL, PCCERT_CHAIN_CONTEXT *ppCertChain, DWORD *pdwSecureFlags)
5203 WCHAR *url;
5204 BOOL res;
5206 TRACE("(%s %p %p)\n", debugstr_a(lpszURL), ppCertChain, pdwSecureFlags);
5208 url = strdupAtoW(lpszURL);
5209 if(!url)
5210 return FALSE;
5212 res = InternetGetSecurityInfoByURLW(url, ppCertChain, pdwSecureFlags);
5213 free(url);
5214 return res;
5217 /***********************************************************************
5218 * InternetGetSecurityInfoByURLW (WININET.@)
5220 BOOL WINAPI InternetGetSecurityInfoByURLW(LPCWSTR lpszURL, PCCERT_CHAIN_CONTEXT *ppCertChain, DWORD *pdwSecureFlags)
5222 URL_COMPONENTSW url = {sizeof(url)};
5223 server_t *server;
5224 BOOL res;
5226 TRACE("(%s %p %p)\n", debugstr_w(lpszURL), ppCertChain, pdwSecureFlags);
5228 if (!ppCertChain && !pdwSecureFlags) {
5229 SetLastError(ERROR_INVALID_PARAMETER);
5230 return FALSE;
5233 url.dwHostNameLength = 1;
5234 res = InternetCrackUrlW(lpszURL, 0, 0, &url);
5235 if(!res || url.nScheme != INTERNET_SCHEME_HTTPS) {
5236 SetLastError(ERROR_INTERNET_ITEM_NOT_FOUND);
5237 return FALSE;
5240 server = get_server(substr(url.lpszHostName, url.dwHostNameLength), url.nPort, TRUE, FALSE);
5241 if(!server) {
5242 SetLastError(ERROR_INTERNET_ITEM_NOT_FOUND);
5243 return FALSE;
5246 if(server->cert_chain) {
5247 if(pdwSecureFlags)
5248 *pdwSecureFlags = server->security_flags & _SECURITY_ERROR_FLAGS_MASK;
5250 if(ppCertChain && !(*ppCertChain = CertDuplicateCertificateChain(server->cert_chain)))
5251 res = FALSE;
5252 }else {
5253 SetLastError(ERROR_INTERNET_ITEM_NOT_FOUND);
5254 res = FALSE;
5257 server_release(server);
5258 return res;
5261 DWORD WINAPI InternetDialA( HWND hwndParent, LPSTR lpszConnectoid, DWORD dwFlags,
5262 DWORD_PTR* lpdwConnection, DWORD dwReserved )
5264 FIXME("(%p, %p, 0x%08lx, %p, 0x%08lx) stub\n", hwndParent, lpszConnectoid, dwFlags,
5265 lpdwConnection, dwReserved);
5266 return ERROR_SUCCESS;
5269 DWORD WINAPI InternetDialW( HWND hwndParent, LPWSTR lpszConnectoid, DWORD dwFlags,
5270 DWORD_PTR* lpdwConnection, DWORD dwReserved )
5272 FIXME("(%p, %p, 0x%08lx, %p, 0x%08lx) stub\n", hwndParent, lpszConnectoid, dwFlags,
5273 lpdwConnection, dwReserved);
5274 return ERROR_SUCCESS;
5277 BOOL WINAPI InternetGoOnlineA( LPSTR lpszURL, HWND hwndParent, DWORD dwReserved )
5279 FIXME("(%s, %p, 0x%08lx) stub\n", debugstr_a(lpszURL), hwndParent, dwReserved);
5280 return TRUE;
5283 BOOL WINAPI InternetGoOnlineW( LPWSTR lpszURL, HWND hwndParent, DWORD dwReserved )
5285 FIXME("(%s, %p, 0x%08lx) stub\n", debugstr_w(lpszURL), hwndParent, dwReserved);
5286 return TRUE;
5289 DWORD WINAPI InternetHangUp( DWORD_PTR dwConnection, DWORD dwReserved )
5291 FIXME("(0x%08Ix, 0x%08lx) stub\n", dwConnection, dwReserved);
5292 return ERROR_SUCCESS;
5295 BOOL WINAPI CreateMD5SSOHash( PWSTR pszChallengeInfo, PWSTR pwszRealm, PWSTR pwszTarget,
5296 PBYTE pbHexHash )
5298 FIXME("(%s, %s, %s, %p) stub\n", debugstr_w(pszChallengeInfo), debugstr_w(pwszRealm),
5299 debugstr_w(pwszTarget), pbHexHash);
5300 return FALSE;
5303 BOOL WINAPI ResumeSuspendedDownload( HINTERNET hInternet, DWORD dwError )
5305 FIXME("(%p, 0x%08lx) stub\n", hInternet, dwError);
5306 return FALSE;
5309 BOOL WINAPI InternetQueryFortezzaStatus(DWORD *a, DWORD_PTR b)
5311 FIXME("(%p, %08Ix) stub\n", a, b);
5312 return FALSE;
5315 DWORD WINAPI ShowClientAuthCerts(HWND parent)
5317 FIXME("%p: stub\n", parent);
5318 return 0;