winex11: Always create XIC preedit and status attributes.
[wine.git] / dlls / wininet / internet.c
blob6dabb0fc5e34bbecc2afb694e1e54901980a32c5
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 proxyEnabled;
85 LPWSTR proxy;
86 LPWSTR proxyBypass;
87 LPWSTR proxyUsername;
88 LPWSTR proxyPassword;
89 } proxyinfo_t;
91 static ULONG max_conns = 2, max_1_0_conns = 4;
92 static ULONG connect_timeout = 60000;
94 static const WCHAR szInternetSettings[] =
95 L"Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings";
97 void *alloc_object(object_header_t *parent, const object_vtbl_t *vtbl, size_t size)
99 UINT_PTR handle = 0, num;
100 object_header_t *ret;
101 object_header_t **p;
102 BOOL res = TRUE;
104 ret = calloc(1, size);
105 if(!ret)
106 return NULL;
108 list_init(&ret->children);
110 EnterCriticalSection( &WININET_cs );
112 if(!handle_table_size) {
113 num = 16;
114 p = calloc(num, sizeof(handle_table[0]));
115 if(p) {
116 handle_table = p;
117 handle_table_size = num;
118 next_handle = 1;
119 }else {
120 res = FALSE;
122 }else if(next_handle == handle_table_size) {
123 num = handle_table_size * 2;
124 p = realloc(handle_table, sizeof(handle_table[0]) * num);
125 if(p) {
126 memset(p + handle_table_size, 0, sizeof(handle_table[0]) * handle_table_size);
127 handle_table = p;
128 handle_table_size = num;
129 }else {
130 res = FALSE;
134 if(res) {
135 handle = next_handle;
136 if(handle_table[handle])
137 ERR("handle isn't free but should be\n");
138 handle_table[handle] = ret;
139 ret->valid_handle = TRUE;
141 while(next_handle < handle_table_size && handle_table[next_handle])
142 next_handle++;
145 LeaveCriticalSection( &WININET_cs );
147 if(!res) {
148 free(ret);
149 return NULL;
152 ret->vtbl = vtbl;
153 ret->refs = 1;
154 ret->hInternet = (HINTERNET)handle;
156 if(parent) {
157 ret->lpfnStatusCB = parent->lpfnStatusCB;
158 ret->dwInternalFlags = parent->dwInternalFlags & INET_CALLBACKW;
161 return ret;
164 object_header_t *WININET_AddRef( object_header_t *info )
166 ULONG refs = InterlockedIncrement(&info->refs);
167 TRACE("%p -> refcount = %ld\n", info, refs );
168 return info;
171 object_header_t *get_handle_object( HINTERNET hinternet )
173 object_header_t *info = NULL;
174 UINT_PTR handle = (UINT_PTR) hinternet;
176 EnterCriticalSection( &WININET_cs );
178 if(handle > 0 && handle < handle_table_size && handle_table[handle] && handle_table[handle]->valid_handle)
179 info = WININET_AddRef(handle_table[handle]);
181 LeaveCriticalSection( &WININET_cs );
183 TRACE("handle %Id -> %p\n", handle, info);
185 return info;
188 static void invalidate_handle(object_header_t *info)
190 object_header_t *child, *next;
192 if(!info->valid_handle)
193 return;
194 info->valid_handle = FALSE;
196 /* Free all children as native does */
197 LIST_FOR_EACH_ENTRY_SAFE( child, next, &info->children, object_header_t, entry )
199 TRACE("invalidating child handle %p for parent %p\n", child->hInternet, info);
200 invalidate_handle( child );
203 WININET_Release(info);
206 BOOL WININET_Release( object_header_t *info )
208 ULONG refs = InterlockedDecrement(&info->refs);
209 TRACE( "object %p refcount = %ld\n", info, refs );
210 if( !refs )
212 invalidate_handle(info);
213 if ( info->vtbl->CloseConnection )
215 TRACE( "closing connection %p\n", info);
216 info->vtbl->CloseConnection( info );
218 /* Don't send a callback if this is a session handle created with InternetOpenUrl */
219 if ((info->htype != WH_HHTTPSESSION && info->htype != WH_HFTPSESSION)
220 || !(info->dwInternalFlags & INET_OPENURL))
222 INTERNET_SendCallback(info, info->dwContext,
223 INTERNET_STATUS_HANDLE_CLOSING, &info->hInternet,
224 sizeof(HINTERNET));
226 TRACE( "destroying object %p\n", info);
227 if ( info->htype != WH_HINIT )
228 list_remove( &info->entry );
229 info->vtbl->Destroy( info );
231 if(info->hInternet) {
232 UINT_PTR handle = (UINT_PTR)info->hInternet;
234 EnterCriticalSection( &WININET_cs );
236 handle_table[handle] = NULL;
237 if(next_handle > handle)
238 next_handle = handle;
240 LeaveCriticalSection( &WININET_cs );
243 free(info);
245 return TRUE;
248 /***********************************************************************
249 * DllMain [Internal] Initializes the internal 'WININET.DLL'.
251 * PARAMS
252 * hinstDLL [I] handle to the DLL's instance
253 * fdwReason [I]
254 * lpvReserved [I] reserved, must be NULL
256 * RETURNS
257 * Success: TRUE
258 * Failure: FALSE
261 BOOL WINAPI DllMain (HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
263 TRACE("%p,%lx,%p\n", hinstDLL, fdwReason, lpvReserved);
265 switch (fdwReason) {
266 case DLL_PROCESS_ATTACH:
268 g_dwTlsErrIndex = TlsAlloc();
270 if (g_dwTlsErrIndex == TLS_OUT_OF_INDEXES)
271 return FALSE;
273 if(!init_urlcache())
275 TlsFree(g_dwTlsErrIndex);
276 return FALSE;
279 WININET_hModule = hinstDLL;
280 break;
282 case DLL_THREAD_ATTACH:
283 break;
285 case DLL_THREAD_DETACH:
286 if (g_dwTlsErrIndex != TLS_OUT_OF_INDEXES)
288 free(TlsGetValue(g_dwTlsErrIndex));
290 break;
292 case DLL_PROCESS_DETACH:
293 if (lpvReserved) break;
294 collect_connections(COLLECT_CLEANUP);
295 NETCON_unload();
296 free_urlcache();
297 free_cookie();
299 if (g_dwTlsErrIndex != TLS_OUT_OF_INDEXES)
301 free(TlsGetValue(g_dwTlsErrIndex));
302 TlsFree(g_dwTlsErrIndex);
304 break;
306 return TRUE;
309 /***********************************************************************
310 * DllInstall (WININET.@)
312 HRESULT WINAPI DllInstall(BOOL bInstall, LPCWSTR cmdline)
314 FIXME("(%x %s): stub\n", bInstall, debugstr_w(cmdline));
315 return S_OK;
318 /***********************************************************************
319 * INTERNET_SaveProxySettings
321 * Stores the proxy settings given by lpwai into the registry
323 * RETURNS
324 * ERROR_SUCCESS if no error, or error code on fail
326 static LONG INTERNET_SaveProxySettings( proxyinfo_t *lpwpi )
328 HKEY key;
329 LONG ret;
331 if ((ret = RegOpenKeyW( HKEY_CURRENT_USER, szInternetSettings, &key )))
332 return ret;
334 if ((ret = RegSetValueExW( key, L"ProxyEnable", 0, REG_DWORD, (BYTE*)&lpwpi->proxyEnabled, sizeof(DWORD))))
336 RegCloseKey( key );
337 return ret;
340 if (lpwpi->proxy)
342 if ((ret = RegSetValueExW( key, L"ProxyServer", 0, REG_SZ, (BYTE*)lpwpi->proxy, sizeof(WCHAR) * (lstrlenW(lpwpi->proxy) + 1))))
344 RegCloseKey( key );
345 return ret;
348 else
350 if ((ret = RegDeleteValueW( key, L"ProxyServer" )) && ret != ERROR_FILE_NOT_FOUND)
352 RegCloseKey( key );
353 return ret;
357 RegCloseKey(key);
358 return ERROR_SUCCESS;
361 /***********************************************************************
362 * INTERNET_FindProxyForProtocol
364 * Searches the proxy string for a proxy of the given protocol.
365 * Returns the found proxy, or the default proxy if none of the given
366 * protocol is found.
368 * PARAMETERS
369 * szProxy [In] proxy string to search
370 * proto [In] protocol to search for, e.g. "http"
371 * foundProxy [Out] found proxy
372 * foundProxyLen [In/Out] length of foundProxy buffer, in WCHARs
374 * RETURNS
375 * TRUE if a proxy is found, FALSE if not. If foundProxy is too short,
376 * *foundProxyLen is set to the required size in WCHARs, including the
377 * NULL terminator, and the last error is set to ERROR_INSUFFICIENT_BUFFER.
379 WCHAR *INTERNET_FindProxyForProtocol(LPCWSTR szProxy, LPCWSTR proto)
381 WCHAR *ret = NULL;
382 const WCHAR *ptr;
384 TRACE("(%s, %s)\n", debugstr_w(szProxy), debugstr_w(proto));
386 /* First, look for the specified protocol (proto=scheme://host:port) */
387 for (ptr = szProxy; ptr && *ptr; )
389 LPCWSTR end, equal;
391 if (!(end = wcschr(ptr, ' ')))
392 end = ptr + lstrlenW(ptr);
393 if ((equal = wcschr(ptr, '=')) && equal < end &&
394 equal - ptr == lstrlenW(proto) &&
395 !wcsnicmp(proto, ptr, lstrlenW(proto)))
397 ret = strndupW(equal + 1, end - equal - 1);
398 TRACE("found proxy for %s: %s\n", debugstr_w(proto), debugstr_w(ret));
399 return ret;
401 if (*end == ' ')
402 ptr = end + 1;
403 else
404 ptr = end;
407 /* It wasn't found: look for no protocol */
408 for (ptr = szProxy; ptr && *ptr; )
410 LPCWSTR end;
412 if (!(end = wcschr(ptr, ' ')))
413 end = ptr + lstrlenW(ptr);
414 if (!wcschr(ptr, '='))
416 ret = strndupW(ptr, end - ptr);
417 TRACE("found proxy for %s: %s\n", debugstr_w(proto), debugstr_w(ret));
418 return ret;
420 if (*end == ' ')
421 ptr = end + 1;
422 else
423 ptr = end;
426 return NULL;
429 /***********************************************************************
430 * InternetInitializeAutoProxyDll (WININET.@)
432 * Setup the internal proxy
434 * PARAMETERS
435 * dwReserved
437 * RETURNS
438 * FALSE on failure
441 BOOL WINAPI InternetInitializeAutoProxyDll(DWORD dwReserved)
443 FIXME("STUB\n");
444 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
445 return FALSE;
448 /***********************************************************************
449 * DetectAutoProxyUrl (WININET.@)
451 * Auto detect the proxy url
453 * RETURNS
454 * FALSE on failure
457 BOOL WINAPI DetectAutoProxyUrl(LPSTR lpszAutoProxyUrl,
458 DWORD dwAutoProxyUrlLength, DWORD dwDetectFlags)
460 FIXME("STUB\n");
461 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
462 return FALSE;
465 static void FreeProxyInfo( proxyinfo_t *lpwpi )
467 free(lpwpi->proxy);
468 free(lpwpi->proxyBypass);
469 free(lpwpi->proxyUsername);
470 free(lpwpi->proxyPassword);
473 static proxyinfo_t *global_proxy;
475 static void free_global_proxy( void )
477 EnterCriticalSection( &WININET_cs );
478 if (global_proxy)
480 FreeProxyInfo( global_proxy );
481 free( global_proxy );
483 LeaveCriticalSection( &WININET_cs );
486 static BOOL parse_proxy_url( proxyinfo_t *info, const WCHAR *url )
488 URL_COMPONENTSW uc = {sizeof(uc)};
490 uc.dwHostNameLength = 1;
491 uc.dwUserNameLength = 1;
492 uc.dwPasswordLength = 1;
494 if (!InternetCrackUrlW( url, 0, 0, &uc )) return FALSE;
495 if (!uc.dwHostNameLength)
497 if (!(info->proxy = wcsdup( url ))) return FALSE;
498 info->proxyUsername = NULL;
499 info->proxyPassword = NULL;
500 return TRUE;
502 if (!(info->proxy = malloc( (uc.dwHostNameLength + 12) * sizeof(WCHAR) ))) return FALSE;
503 swprintf( info->proxy, uc.dwHostNameLength + 12, L"%.*s:%u", uc.dwHostNameLength, uc.lpszHostName, uc.nPort );
505 if (!uc.dwUserNameLength) info->proxyUsername = NULL;
506 else if (!(info->proxyUsername = strndupW( uc.lpszUserName, uc.dwUserNameLength )))
508 free( info->proxy );
509 return FALSE;
511 if (!uc.dwPasswordLength) info->proxyPassword = NULL;
512 else if (!(info->proxyPassword = strndupW( uc.lpszPassword, uc.dwPasswordLength )))
514 free( info->proxyUsername );
515 free( info->proxy );
516 return FALSE;
518 return TRUE;
521 /***********************************************************************
522 * INTERNET_LoadProxySettings
524 * Loads proxy information from process-wide global settings, the registry,
525 * or the environment into lpwpi.
527 * The caller should call FreeProxyInfo when done with lpwpi.
529 * FIXME:
530 * The proxy may be specified in the form 'http=proxy.my.org'
531 * Presumably that means there can be ftp=ftpproxy.my.org too.
533 static LONG INTERNET_LoadProxySettings( proxyinfo_t *lpwpi )
535 HKEY key;
536 DWORD type, len;
537 const WCHAR *envproxy;
538 LONG ret;
540 memset( lpwpi, 0, sizeof(*lpwpi) );
542 EnterCriticalSection( &WININET_cs );
543 if (global_proxy)
545 lpwpi->proxyEnabled = global_proxy->proxyEnabled;
546 lpwpi->proxy = wcsdup( global_proxy->proxy );
547 lpwpi->proxyBypass = wcsdup( global_proxy->proxyBypass );
549 LeaveCriticalSection( &WININET_cs );
551 if ((ret = RegOpenKeyW( HKEY_CURRENT_USER, szInternetSettings, &key )))
553 FreeProxyInfo( lpwpi );
554 return ret;
557 len = sizeof(DWORD);
558 if (RegQueryValueExW( key, L"ProxyEnable", NULL, &type, (BYTE *)&lpwpi->proxyEnabled, &len ) || type != REG_DWORD)
560 lpwpi->proxyEnabled = 0;
561 if((ret = RegSetValueExW( key, L"ProxyEnable", 0, REG_DWORD, (BYTE *)&lpwpi->proxyEnabled, sizeof(DWORD) )))
563 FreeProxyInfo( lpwpi );
564 RegCloseKey( key );
565 return ret;
569 if (!(envproxy = _wgetenv( L"http_proxy" )) || lpwpi->proxyEnabled)
571 /* figure out how much memory the proxy setting takes */
572 if (!RegQueryValueExW( key, L"ProxyServer", NULL, &type, NULL, &len ) && len && (type == REG_SZ))
574 LPWSTR szProxy, p;
576 if (!(szProxy = malloc( len )))
578 RegCloseKey( key );
579 FreeProxyInfo( lpwpi );
580 return ERROR_OUTOFMEMORY;
582 RegQueryValueExW( key, L"ProxyServer", NULL, &type, (BYTE*)szProxy, &len );
584 /* find the http proxy, and strip away everything else */
585 p = wcsstr( szProxy, L"http=" );
586 if (p)
588 p += lstrlenW( L"http=" );
589 lstrcpyW( szProxy, p );
591 p = wcschr( szProxy, ';' );
592 if (p) *p = 0;
594 FreeProxyInfo( lpwpi );
595 lpwpi->proxy = szProxy;
596 lpwpi->proxyBypass = NULL;
598 TRACE("http proxy (from registry) = %s\n", debugstr_w(lpwpi->proxy));
600 else
602 TRACE("No proxy server settings in registry.\n");
603 FreeProxyInfo( lpwpi );
604 lpwpi->proxy = NULL;
605 lpwpi->proxyBypass = NULL;
608 else if (envproxy)
610 FreeProxyInfo( lpwpi );
611 if (parse_proxy_url( lpwpi, envproxy ))
613 TRACE("http proxy (from environment) = %s\n", debugstr_w(lpwpi->proxy));
614 lpwpi->proxyEnabled = 1;
615 lpwpi->proxyBypass = NULL;
617 else
619 WARN("failed to parse http_proxy value %s\n", debugstr_w(envproxy));
620 lpwpi->proxyEnabled = 0;
621 lpwpi->proxy = NULL;
622 lpwpi->proxyBypass = NULL;
626 if (lpwpi->proxyEnabled)
628 TRACE("Proxy is enabled.\n");
630 if (!(envproxy = _wgetenv( L"no_proxy" )))
632 /* figure out how much memory the proxy setting takes */
633 if (!RegQueryValueExW( key, L"ProxyOverride", NULL, &type, NULL, &len ) && len && (type == REG_SZ))
635 LPWSTR szProxy;
637 if (!(szProxy = malloc( len )))
639 RegCloseKey( key );
640 return ERROR_OUTOFMEMORY;
642 RegQueryValueExW( key, L"ProxyOverride", NULL, &type, (BYTE*)szProxy, &len );
644 free( lpwpi->proxyBypass );
645 lpwpi->proxyBypass = szProxy;
647 TRACE("http proxy bypass (from registry) = %s\n", debugstr_w(lpwpi->proxyBypass));
649 else
651 free( lpwpi->proxyBypass );
652 lpwpi->proxyBypass = NULL;
654 TRACE("No proxy bypass server settings in registry.\n");
657 else
659 WCHAR *envproxyW;
661 if (!(envproxyW = malloc( wcslen(envproxy) * sizeof(WCHAR) )))
663 RegCloseKey( key );
664 return ERROR_OUTOFMEMORY;
666 lstrcpyW( envproxyW, envproxy );
668 free( lpwpi->proxyBypass );
669 lpwpi->proxyBypass = envproxyW;
671 TRACE("http proxy bypass (from environment) = %s\n", debugstr_w(lpwpi->proxyBypass));
674 else TRACE("Proxy is disabled.\n");
676 RegCloseKey( key );
677 return ERROR_SUCCESS;
680 /***********************************************************************
681 * INTERNET_ConfigureProxy
683 static BOOL INTERNET_ConfigureProxy( appinfo_t *lpwai )
685 proxyinfo_t wpi;
687 if (INTERNET_LoadProxySettings( &wpi ))
688 return FALSE;
690 if (wpi.proxyEnabled)
692 TRACE("http proxy = %s bypass = %s\n", debugstr_w(wpi.proxy), debugstr_w(wpi.proxyBypass));
694 lpwai->accessType = INTERNET_OPEN_TYPE_PROXY;
695 lpwai->proxy = wpi.proxy;
696 lpwai->proxyBypass = wpi.proxyBypass;
697 lpwai->proxyUsername = wpi.proxyUsername;
698 lpwai->proxyPassword = wpi.proxyPassword;
699 return TRUE;
702 lpwai->accessType = INTERNET_OPEN_TYPE_DIRECT;
703 FreeProxyInfo(&wpi);
704 return FALSE;
707 /***********************************************************************
708 * dump_INTERNET_FLAGS
710 * Helper function to TRACE the internet flags.
712 * RETURNS
713 * None
716 static void dump_INTERNET_FLAGS(DWORD dwFlags)
718 #define FE(x) { x, #x }
719 static const wininet_flag_info flag[] = {
720 FE(INTERNET_FLAG_RELOAD),
721 FE(INTERNET_FLAG_RAW_DATA),
722 FE(INTERNET_FLAG_EXISTING_CONNECT),
723 FE(INTERNET_FLAG_ASYNC),
724 FE(INTERNET_FLAG_PASSIVE),
725 FE(INTERNET_FLAG_NO_CACHE_WRITE),
726 FE(INTERNET_FLAG_MAKE_PERSISTENT),
727 FE(INTERNET_FLAG_FROM_CACHE),
728 FE(INTERNET_FLAG_SECURE),
729 FE(INTERNET_FLAG_KEEP_CONNECTION),
730 FE(INTERNET_FLAG_NO_AUTO_REDIRECT),
731 FE(INTERNET_FLAG_READ_PREFETCH),
732 FE(INTERNET_FLAG_NO_COOKIES),
733 FE(INTERNET_FLAG_NO_AUTH),
734 FE(INTERNET_FLAG_CACHE_IF_NET_FAIL),
735 FE(INTERNET_FLAG_IGNORE_REDIRECT_TO_HTTP),
736 FE(INTERNET_FLAG_IGNORE_REDIRECT_TO_HTTPS),
737 FE(INTERNET_FLAG_IGNORE_CERT_DATE_INVALID),
738 FE(INTERNET_FLAG_IGNORE_CERT_CN_INVALID),
739 FE(INTERNET_FLAG_RESYNCHRONIZE),
740 FE(INTERNET_FLAG_HYPERLINK),
741 FE(INTERNET_FLAG_NO_UI),
742 FE(INTERNET_FLAG_PRAGMA_NOCACHE),
743 FE(INTERNET_FLAG_CACHE_ASYNC),
744 FE(INTERNET_FLAG_FORMS_SUBMIT),
745 FE(INTERNET_FLAG_NEED_FILE),
746 FE(INTERNET_FLAG_TRANSFER_ASCII),
747 FE(INTERNET_FLAG_TRANSFER_BINARY)
749 #undef FE
750 unsigned int i;
752 for (i = 0; i < ARRAY_SIZE(flag); i++) {
753 if (flag[i].val & dwFlags) {
754 TRACE(" %s", flag[i].name);
755 dwFlags &= ~flag[i].val;
758 if (dwFlags)
759 TRACE(" Unknown flags (%08lx)\n", dwFlags);
760 else
761 TRACE("\n");
764 /***********************************************************************
765 * INTERNET_CloseHandle (internal)
767 * Close internet handle
770 static VOID APPINFO_Destroy(object_header_t *hdr)
772 appinfo_t *lpwai = (appinfo_t*)hdr;
774 TRACE("%p\n",lpwai);
776 free(lpwai->agent);
777 free(lpwai->proxy);
778 free(lpwai->proxyBypass);
779 free(lpwai->proxyUsername);
780 free(lpwai->proxyPassword);
783 static DWORD APPINFO_QueryOption(object_header_t *hdr, DWORD option, void *buffer, DWORD *size, BOOL unicode)
785 appinfo_t *ai = (appinfo_t*)hdr;
787 switch(option) {
788 case INTERNET_OPTION_HANDLE_TYPE:
789 TRACE("INTERNET_OPTION_HANDLE_TYPE\n");
791 if (*size < sizeof(ULONG))
792 return ERROR_INSUFFICIENT_BUFFER;
794 *size = sizeof(DWORD);
795 *(DWORD*)buffer = INTERNET_HANDLE_TYPE_INTERNET;
796 return ERROR_SUCCESS;
798 case INTERNET_OPTION_USER_AGENT: {
799 DWORD bufsize;
801 TRACE("INTERNET_OPTION_USER_AGENT\n");
803 bufsize = *size;
805 if (unicode) {
806 DWORD len = ai->agent ? lstrlenW(ai->agent) : 0;
808 *size = (len + 1) * sizeof(WCHAR);
809 if(!buffer || bufsize < *size)
810 return ERROR_INSUFFICIENT_BUFFER;
812 if (ai->agent)
813 lstrcpyW(buffer, ai->agent);
814 else
815 *(WCHAR *)buffer = 0;
816 /* If the buffer is copied, the returned length doesn't include
817 * the NULL terminator.
819 *size = len;
820 }else {
821 if (ai->agent)
822 *size = WideCharToMultiByte(CP_ACP, 0, ai->agent, -1, NULL, 0, NULL, NULL);
823 else
824 *size = 1;
825 if(!buffer || bufsize < *size)
826 return ERROR_INSUFFICIENT_BUFFER;
828 if (ai->agent)
829 WideCharToMultiByte(CP_ACP, 0, ai->agent, -1, buffer, *size, NULL, NULL);
830 else
831 *(char *)buffer = 0;
832 /* If the buffer is copied, the returned length doesn't include
833 * the NULL terminator.
835 *size -= 1;
838 return ERROR_SUCCESS;
841 case INTERNET_OPTION_PROXY:
842 if(!size) return ERROR_INVALID_PARAMETER;
843 if (unicode) {
844 INTERNET_PROXY_INFOW *pi = (INTERNET_PROXY_INFOW *)buffer;
845 DWORD proxyBytesRequired = 0, proxyBypassBytesRequired = 0;
846 LPWSTR proxy, proxy_bypass;
848 if (ai->proxy)
849 proxyBytesRequired = (lstrlenW(ai->proxy) + 1) * sizeof(WCHAR);
850 if (ai->proxyBypass)
851 proxyBypassBytesRequired = (lstrlenW(ai->proxyBypass) + 1) * sizeof(WCHAR);
852 if (!pi || *size < sizeof(INTERNET_PROXY_INFOW) + proxyBytesRequired + proxyBypassBytesRequired)
854 *size = sizeof(INTERNET_PROXY_INFOW) + proxyBytesRequired + proxyBypassBytesRequired;
855 return ERROR_INSUFFICIENT_BUFFER;
857 proxy = (LPWSTR)((LPBYTE)buffer + sizeof(INTERNET_PROXY_INFOW));
858 proxy_bypass = (LPWSTR)((LPBYTE)buffer + sizeof(INTERNET_PROXY_INFOW) + proxyBytesRequired);
860 pi->dwAccessType = ai->accessType;
861 pi->lpszProxy = NULL;
862 pi->lpszProxyBypass = NULL;
863 if (ai->proxy) {
864 lstrcpyW(proxy, ai->proxy);
865 pi->lpszProxy = proxy;
868 if (ai->proxyBypass) {
869 lstrcpyW(proxy_bypass, ai->proxyBypass);
870 pi->lpszProxyBypass = proxy_bypass;
873 *size = sizeof(INTERNET_PROXY_INFOW) + proxyBytesRequired + proxyBypassBytesRequired;
874 return ERROR_SUCCESS;
875 }else {
876 INTERNET_PROXY_INFOA *pi = (INTERNET_PROXY_INFOA *)buffer;
877 DWORD proxyBytesRequired = 0, proxyBypassBytesRequired = 0;
878 LPSTR proxy, proxy_bypass;
880 if (ai->proxy)
881 proxyBytesRequired = WideCharToMultiByte(CP_ACP, 0, ai->proxy, -1, NULL, 0, NULL, NULL);
882 if (ai->proxyBypass)
883 proxyBypassBytesRequired = WideCharToMultiByte(CP_ACP, 0, ai->proxyBypass, -1,
884 NULL, 0, NULL, NULL);
885 if (!pi || *size < sizeof(INTERNET_PROXY_INFOA) + proxyBytesRequired + proxyBypassBytesRequired)
887 *size = sizeof(INTERNET_PROXY_INFOA) + proxyBytesRequired + proxyBypassBytesRequired;
888 return ERROR_INSUFFICIENT_BUFFER;
890 proxy = (LPSTR)((LPBYTE)buffer + sizeof(INTERNET_PROXY_INFOA));
891 proxy_bypass = (LPSTR)((LPBYTE)buffer + sizeof(INTERNET_PROXY_INFOA) + proxyBytesRequired);
893 pi->dwAccessType = ai->accessType;
894 pi->lpszProxy = NULL;
895 pi->lpszProxyBypass = NULL;
896 if (ai->proxy) {
897 WideCharToMultiByte(CP_ACP, 0, ai->proxy, -1, proxy, proxyBytesRequired, NULL, NULL);
898 pi->lpszProxy = proxy;
901 if (ai->proxyBypass) {
902 WideCharToMultiByte(CP_ACP, 0, ai->proxyBypass, -1, proxy_bypass,
903 proxyBypassBytesRequired, NULL, NULL);
904 pi->lpszProxyBypass = proxy_bypass;
907 *size = sizeof(INTERNET_PROXY_INFOA) + proxyBytesRequired + proxyBypassBytesRequired;
908 return ERROR_SUCCESS;
911 case INTERNET_OPTION_CONNECT_TIMEOUT:
912 TRACE("INTERNET_OPTION_CONNECT_TIMEOUT\n");
914 if (*size < sizeof(ULONG))
915 return ERROR_INSUFFICIENT_BUFFER;
917 *(ULONG*)buffer = ai->connect_timeout;
918 *size = sizeof(ULONG);
920 return ERROR_SUCCESS;
923 return INET_QueryOption(hdr, option, buffer, size, unicode);
926 static DWORD APPINFO_SetOption(object_header_t *hdr, DWORD option, void *buf, DWORD size)
928 appinfo_t *ai = (appinfo_t*)hdr;
930 switch(option) {
931 case INTERNET_OPTION_CONNECT_TIMEOUT:
932 TRACE("INTERNET_OPTION_CONNECT_TIMEOUT\n");
934 if(size != sizeof(connect_timeout))
935 return ERROR_INTERNET_BAD_OPTION_LENGTH;
936 if(!*(ULONG*)buf)
937 return ERROR_BAD_ARGUMENTS;
939 ai->connect_timeout = *(ULONG*)buf;
940 return ERROR_SUCCESS;
941 case INTERNET_OPTION_USER_AGENT:
942 free(ai->agent);
943 if (!(ai->agent = wcsdup(buf))) return ERROR_OUTOFMEMORY;
944 return ERROR_SUCCESS;
945 case INTERNET_OPTION_REFRESH:
946 FIXME("INTERNET_OPTION_REFRESH\n");
947 return ERROR_SUCCESS;
950 return INET_SetOption(hdr, option, buf, size);
953 static const object_vtbl_t APPINFOVtbl = {
954 APPINFO_Destroy,
955 NULL,
956 APPINFO_QueryOption,
957 APPINFO_SetOption,
958 NULL,
959 NULL,
960 NULL,
961 NULL
965 /***********************************************************************
966 * InternetOpenW (WININET.@)
968 * Per-application initialization of wininet
970 * RETURNS
971 * HINTERNET on success
972 * NULL on failure
975 HINTERNET WINAPI InternetOpenW(LPCWSTR lpszAgent, DWORD dwAccessType,
976 LPCWSTR lpszProxy, LPCWSTR lpszProxyBypass, DWORD dwFlags)
978 appinfo_t *lpwai = NULL;
980 if (TRACE_ON(wininet)) {
981 #define FE(x) { x, #x }
982 static const wininet_flag_info access_type[] = {
983 FE(INTERNET_OPEN_TYPE_PRECONFIG),
984 FE(INTERNET_OPEN_TYPE_DIRECT),
985 FE(INTERNET_OPEN_TYPE_PROXY),
986 FE(INTERNET_OPEN_TYPE_PRECONFIG_WITH_NO_AUTOPROXY)
988 #undef FE
989 DWORD i;
990 const char *access_type_str = "Unknown";
992 TRACE("(%s, %li, %s, %s, %li)\n", debugstr_w(lpszAgent), dwAccessType,
993 debugstr_w(lpszProxy), debugstr_w(lpszProxyBypass), dwFlags);
994 for (i = 0; i < ARRAY_SIZE(access_type); i++) {
995 if (access_type[i].val == dwAccessType) {
996 access_type_str = access_type[i].name;
997 break;
1000 TRACE(" access type : %s\n", access_type_str);
1001 TRACE(" flags :");
1002 dump_INTERNET_FLAGS(dwFlags);
1005 /* Clear any error information */
1006 INTERNET_SetLastError(0);
1008 if((dwAccessType == INTERNET_OPEN_TYPE_PROXY) && !lpszProxy) {
1009 SetLastError(ERROR_INVALID_PARAMETER);
1010 return NULL;
1013 lpwai = alloc_object(NULL, &APPINFOVtbl, sizeof(appinfo_t));
1014 if (!lpwai) {
1015 SetLastError(ERROR_OUTOFMEMORY);
1016 return NULL;
1019 lpwai->hdr.htype = WH_HINIT;
1020 lpwai->hdr.dwFlags = dwFlags;
1021 lpwai->accessType = dwAccessType;
1022 lpwai->proxyUsername = NULL;
1023 lpwai->proxyPassword = NULL;
1024 lpwai->connect_timeout = connect_timeout;
1026 lpwai->agent = wcsdup(lpszAgent);
1027 if(dwAccessType == INTERNET_OPEN_TYPE_PRECONFIG)
1028 INTERNET_ConfigureProxy( lpwai );
1029 else if(dwAccessType == INTERNET_OPEN_TYPE_PROXY) {
1030 lpwai->proxy = wcsdup(lpszProxy);
1031 lpwai->proxyBypass = wcsdup(lpszProxyBypass);
1034 TRACE("returning %p\n", lpwai);
1036 return lpwai->hdr.hInternet;
1040 /***********************************************************************
1041 * InternetOpenA (WININET.@)
1043 * Per-application initialization of wininet
1045 * RETURNS
1046 * HINTERNET on success
1047 * NULL on failure
1050 HINTERNET WINAPI InternetOpenA(LPCSTR lpszAgent, DWORD dwAccessType,
1051 LPCSTR lpszProxy, LPCSTR lpszProxyBypass, DWORD dwFlags)
1053 WCHAR *szAgent, *szProxy, *szBypass;
1054 HINTERNET rc;
1056 TRACE("(%s, 0x%08lx, %s, %s, 0x%08lx)\n", debugstr_a(lpszAgent),
1057 dwAccessType, debugstr_a(lpszProxy), debugstr_a(lpszProxyBypass), dwFlags);
1059 szAgent = strdupAtoW(lpszAgent);
1060 szProxy = strdupAtoW(lpszProxy);
1061 szBypass = strdupAtoW(lpszProxyBypass);
1063 rc = InternetOpenW(szAgent, dwAccessType, szProxy, szBypass, dwFlags);
1065 free(szAgent);
1066 free(szProxy);
1067 free(szBypass);
1068 return rc;
1071 /***********************************************************************
1072 * InternetGetLastResponseInfoA (WININET.@)
1074 * Return last wininet error description on the calling thread
1076 * RETURNS
1077 * TRUE on success of writing to buffer
1078 * FALSE on failure
1081 BOOL WINAPI InternetGetLastResponseInfoA(LPDWORD lpdwError,
1082 LPSTR lpszBuffer, LPDWORD lpdwBufferLength)
1084 LPWITHREADERROR lpwite = TlsGetValue(g_dwTlsErrIndex);
1086 TRACE("(%p, %p, %p)\n", lpdwError, lpszBuffer, lpdwBufferLength);
1088 if (!lpdwError || !lpdwBufferLength)
1090 SetLastError(ERROR_INVALID_PARAMETER);
1091 return FALSE;
1093 if (lpwite)
1095 if (lpszBuffer == NULL || *lpdwBufferLength < strlen(lpwite->response))
1097 *lpdwBufferLength = strlen(lpwite->response);
1098 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1099 return FALSE;
1101 *lpdwError = lpwite->dwError;
1102 if (*lpdwBufferLength)
1104 memcpy(lpszBuffer, lpwite->response, *lpdwBufferLength);
1105 lpszBuffer[*lpdwBufferLength - 1] = 0;
1106 *lpdwBufferLength = strlen(lpszBuffer);
1109 else
1111 *lpdwError = 0;
1112 *lpdwBufferLength = 0;
1115 return TRUE;
1118 /***********************************************************************
1119 * InternetGetLastResponseInfoW (WININET.@)
1121 * Return last wininet error description on the calling thread
1123 * RETURNS
1124 * TRUE on success of writing to buffer
1125 * FALSE on failure
1128 BOOL WINAPI InternetGetLastResponseInfoW(LPDWORD lpdwError,
1129 LPWSTR lpszBuffer, LPDWORD lpdwBufferLength)
1131 LPWITHREADERROR lpwite = TlsGetValue(g_dwTlsErrIndex);
1133 TRACE("(%p, %p, %p)\n", lpdwError, lpszBuffer, lpdwBufferLength);
1135 if (!lpdwError || !lpdwBufferLength)
1137 SetLastError(ERROR_INVALID_PARAMETER);
1138 return FALSE;
1140 if (lpwite)
1142 int required_size = MultiByteToWideChar(CP_ACP, 0, lpwite->response, -1, NULL, 0) - 1;
1143 if (lpszBuffer == NULL || *lpdwBufferLength < required_size)
1145 *lpdwBufferLength = required_size;
1146 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1147 return FALSE;
1149 *lpdwError = lpwite->dwError;
1150 if (*lpdwBufferLength)
1151 *lpdwBufferLength = MultiByteToWideChar(CP_ACP, 0, lpwite->response, -1, lpszBuffer, *lpdwBufferLength);
1153 else
1155 *lpdwError = 0;
1156 *lpdwBufferLength = 0;
1159 return TRUE;
1162 /***********************************************************************
1163 * InternetGetConnectedState (WININET.@)
1165 * Return connected state
1167 * RETURNS
1168 * TRUE if connected
1169 * if lpdwStatus is not null, return the status (off line,
1170 * modem, lan...) in it.
1171 * FALSE if not connected
1173 BOOL WINAPI InternetGetConnectedState(LPDWORD lpdwStatus, DWORD dwReserved)
1175 TRACE("(%p, 0x%08lx)\n", lpdwStatus, dwReserved);
1177 return InternetGetConnectedStateExW(lpdwStatus, NULL, 0, dwReserved);
1181 /***********************************************************************
1182 * InternetGetConnectedStateExW (WININET.@)
1184 * Return connected state
1186 * PARAMS
1188 * lpdwStatus [O] Flags specifying the status of the internet connection.
1189 * lpszConnectionName [O] Pointer to buffer to receive the friendly name of the internet connection.
1190 * dwNameLen [I] Size of the buffer, in characters.
1191 * dwReserved [I] Reserved. Must be set to 0.
1193 * RETURNS
1194 * TRUE if connected
1195 * if lpdwStatus is not null, return the status (off line,
1196 * modem, lan...) in it.
1197 * FALSE if not connected
1199 * NOTES
1200 * If the system has no available network connections, an empty string is
1201 * stored in lpszConnectionName. If there is a LAN connection, a localized
1202 * "LAN Connection" string is stored. Presumably, if only a dial-up
1203 * connection is available then the name of the dial-up connection is
1204 * returned. Why any application, other than the "Internet Settings" CPL,
1205 * would want to use this function instead of the simpler InternetGetConnectedStateW
1206 * function is beyond me.
1208 BOOL WINAPI InternetGetConnectedStateExW(LPDWORD lpdwStatus, LPWSTR lpszConnectionName,
1209 DWORD dwNameLen, DWORD dwReserved)
1211 IP_ADAPTER_ADDRESSES *buf = NULL, *aa;
1212 ULONG size = 0;
1213 DWORD status;
1215 TRACE("(%p, %p, %ld, 0x%08lx)\n", lpdwStatus, lpszConnectionName, dwNameLen, dwReserved);
1217 /* Must be zero */
1218 if(dwReserved)
1219 return FALSE;
1221 for (;;)
1223 ULONG flags = GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER |
1224 GAA_FLAG_SKIP_FRIENDLY_NAME | GAA_FLAG_INCLUDE_ALL_GATEWAYS;
1225 ULONG errcode = GetAdaptersAddresses(AF_UNSPEC, flags, NULL, buf, &size);
1227 if (errcode == ERROR_SUCCESS)
1228 break;
1229 free(buf);
1230 if (errcode == ERROR_BUFFER_OVERFLOW && !(buf = malloc(size)))
1231 errcode = ERROR_NOT_ENOUGH_MEMORY;
1232 if (errcode != ERROR_BUFFER_OVERFLOW)
1234 if (errcode != ERROR_NO_DATA)
1236 SetLastError(errcode);
1237 return FALSE;
1239 buf = NULL;
1240 break;
1244 status = INTERNET_RAS_INSTALLED;
1245 for (aa = buf; aa; aa = aa->Next)
1247 /* Connected, but not necessarily to internet */
1248 if (aa->FirstUnicastAddress)
1249 status |= INTERNET_CONNECTION_OFFLINE;
1251 /* Connected to internet */
1252 if (aa->FirstGatewayAddress)
1254 WARN("always returning LAN connection.\n");
1255 status &= ~INTERNET_CONNECTION_OFFLINE;
1256 status |= INTERNET_CONNECTION_LAN;
1257 break;
1260 free(buf);
1262 if (lpdwStatus) *lpdwStatus = status;
1264 /* When the buffer size is zero LoadStringW fills the buffer with a pointer to
1265 * the resource, avoid it as we must not change the buffer in this case */
1266 if (lpszConnectionName && dwNameLen)
1268 *lpszConnectionName = '\0';
1269 if (status & INTERNET_CONNECTION_LAN)
1270 LoadStringW(WININET_hModule, IDS_LANCONNECTION, lpszConnectionName, dwNameLen);
1273 if (!(status & (INTERNET_CONNECTION_LAN | INTERNET_CONNECTION_MODEM | INTERNET_CONNECTION_PROXY)))
1275 SetLastError(ERROR_SUCCESS);
1276 return FALSE;
1278 return TRUE;
1282 /***********************************************************************
1283 * InternetGetConnectedStateExA (WININET.@)
1285 BOOL WINAPI InternetGetConnectedStateExA(LPDWORD lpdwStatus, LPSTR lpszConnectionName,
1286 DWORD dwNameLen, DWORD dwReserved)
1288 LPWSTR lpwszConnectionName = NULL;
1289 BOOL rc;
1291 TRACE("(%p, %p, %ld, 0x%08lx)\n", lpdwStatus, lpszConnectionName, dwNameLen, dwReserved);
1293 if (lpszConnectionName && dwNameLen > 0)
1294 lpwszConnectionName = malloc(dwNameLen * sizeof(WCHAR));
1296 rc = InternetGetConnectedStateExW(lpdwStatus,lpwszConnectionName, dwNameLen,
1297 dwReserved);
1298 if (rc && lpwszConnectionName)
1299 WideCharToMultiByte(CP_ACP,0,lpwszConnectionName,-1,lpszConnectionName,
1300 dwNameLen, NULL, NULL);
1302 free(lpwszConnectionName);
1303 return rc;
1307 /***********************************************************************
1308 * InternetConnectW (WININET.@)
1310 * Open a ftp, gopher or http session
1312 * RETURNS
1313 * HINTERNET a session handle on success
1314 * NULL on failure
1317 HINTERNET WINAPI InternetConnectW(HINTERNET hInternet,
1318 LPCWSTR lpszServerName, INTERNET_PORT nServerPort,
1319 LPCWSTR lpszUserName, LPCWSTR lpszPassword,
1320 DWORD dwService, DWORD dwFlags, DWORD_PTR dwContext)
1322 appinfo_t *hIC;
1323 HINTERNET rc = NULL;
1324 DWORD res = ERROR_SUCCESS;
1326 TRACE("(%p, %s, %u, %s, %p, %lu, %lx, %Ix)\n", hInternet, debugstr_w(lpszServerName),
1327 nServerPort, debugstr_w(lpszUserName), lpszPassword, dwService, dwFlags, dwContext);
1329 if (!lpszServerName)
1331 SetLastError(ERROR_INVALID_PARAMETER);
1332 return NULL;
1335 hIC = (appinfo_t*)get_handle_object( hInternet );
1336 if ( (hIC == NULL) || (hIC->hdr.htype != WH_HINIT) )
1338 res = ERROR_INVALID_HANDLE;
1339 goto lend;
1342 switch (dwService)
1344 case INTERNET_SERVICE_FTP:
1345 rc = FTP_Connect(hIC, lpszServerName, nServerPort,
1346 lpszUserName, lpszPassword, dwFlags, dwContext, 0);
1347 if(!rc)
1348 res = INTERNET_GetLastError();
1349 break;
1351 case INTERNET_SERVICE_HTTP:
1352 res = HTTP_Connect(hIC, lpszServerName, nServerPort,
1353 lpszUserName, lpszPassword, dwFlags, dwContext, 0, &rc);
1354 break;
1356 case INTERNET_SERVICE_GOPHER:
1357 default:
1358 break;
1360 lend:
1361 if( hIC )
1362 WININET_Release( &hIC->hdr );
1364 TRACE("returning %p\n", rc);
1365 SetLastError(res);
1366 return rc;
1370 /***********************************************************************
1371 * InternetConnectA (WININET.@)
1373 * Open a ftp, gopher or http session
1375 * RETURNS
1376 * HINTERNET a session handle on success
1377 * NULL on failure
1380 HINTERNET WINAPI InternetConnectA(HINTERNET hInternet,
1381 LPCSTR lpszServerName, INTERNET_PORT nServerPort,
1382 LPCSTR lpszUserName, LPCSTR lpszPassword,
1383 DWORD dwService, DWORD dwFlags, DWORD_PTR dwContext)
1385 HINTERNET rc = NULL;
1386 LPWSTR szServerName;
1387 LPWSTR szUserName;
1388 LPWSTR szPassword;
1390 szServerName = strdupAtoW(lpszServerName);
1391 szUserName = strdupAtoW(lpszUserName);
1392 szPassword = strdupAtoW(lpszPassword);
1394 rc = InternetConnectW(hInternet, szServerName, nServerPort,
1395 szUserName, szPassword, dwService, dwFlags, dwContext);
1397 free(szServerName);
1398 free(szUserName);
1399 free(szPassword);
1400 return rc;
1404 /***********************************************************************
1405 * InternetFindNextFileA (WININET.@)
1407 * Continues a file search from a previous call to FindFirstFile
1409 * RETURNS
1410 * TRUE on success
1411 * FALSE on failure
1414 BOOL WINAPI InternetFindNextFileA(HINTERNET hFind, LPVOID lpvFindData)
1416 BOOL ret;
1417 WIN32_FIND_DATAW fd;
1419 ret = InternetFindNextFileW(hFind, lpvFindData?&fd:NULL);
1420 if(lpvFindData)
1421 WININET_find_data_WtoA(&fd, (LPWIN32_FIND_DATAA)lpvFindData);
1422 return ret;
1425 /***********************************************************************
1426 * InternetFindNextFileW (WININET.@)
1428 * Continues a file search from a previous call to FindFirstFile
1430 * RETURNS
1431 * TRUE on success
1432 * FALSE on failure
1435 BOOL WINAPI InternetFindNextFileW(HINTERNET hFind, LPVOID lpvFindData)
1437 object_header_t *hdr;
1438 DWORD res;
1440 TRACE("\n");
1442 hdr = get_handle_object(hFind);
1443 if(!hdr) {
1444 WARN("Invalid handle\n");
1445 SetLastError(ERROR_INVALID_HANDLE);
1446 return FALSE;
1449 if(hdr->vtbl->FindNextFileW) {
1450 res = hdr->vtbl->FindNextFileW(hdr, lpvFindData);
1451 }else {
1452 WARN("Handle doesn't support NextFile\n");
1453 res = ERROR_INTERNET_INCORRECT_HANDLE_TYPE;
1456 WININET_Release(hdr);
1458 if(res != ERROR_SUCCESS)
1459 SetLastError(res);
1460 return res == ERROR_SUCCESS;
1463 /***********************************************************************
1464 * InternetCloseHandle (WININET.@)
1466 * Generic close handle function
1468 * RETURNS
1469 * TRUE on success
1470 * FALSE on failure
1473 BOOL WINAPI InternetCloseHandle(HINTERNET hInternet)
1475 object_header_t *obj;
1477 TRACE("%p\n", hInternet);
1479 obj = get_handle_object( hInternet );
1480 if (!obj) {
1481 SetLastError(ERROR_INVALID_HANDLE);
1482 return FALSE;
1485 invalidate_handle(obj);
1486 WININET_Release(obj);
1488 return TRUE;
1491 static BOOL set_url_component(WCHAR **component, DWORD *component_length, const WCHAR *value, DWORD len)
1493 TRACE("%s (%ld)\n", debugstr_wn(value, len), len);
1495 if (!*component_length)
1496 return TRUE;
1498 if (!*component) {
1499 *(const WCHAR**)component = value;
1500 *component_length = len;
1501 return TRUE;
1504 if (*component_length < len+1) {
1505 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1506 return FALSE;
1509 *component_length = len;
1510 if(len)
1511 memcpy(*component, value, len*sizeof(WCHAR));
1512 (*component)[len] = 0;
1513 return TRUE;
1516 static BOOL set_url_component_WtoA(const WCHAR *comp_w, DWORD length, const WCHAR *url_w, char **comp, DWORD *ret_length,
1517 const char *url_a)
1519 size_t size, ret_size = *ret_length;
1521 if (!*ret_length)
1522 return TRUE;
1523 size = WideCharToMultiByte(CP_ACP, 0, comp_w, length, NULL, 0, NULL, NULL);
1525 if (!*comp) {
1526 *comp = comp_w ? (char*)url_a + WideCharToMultiByte(CP_ACP, 0, url_w, comp_w-url_w, NULL, 0, NULL, NULL) : NULL;
1527 *ret_length = size;
1528 return TRUE;
1531 if (size+1 > ret_size) {
1532 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1533 *ret_length = size+1;
1534 return FALSE;
1537 *ret_length = size;
1538 WideCharToMultiByte(CP_ACP, 0, comp_w, length, *comp, ret_size-1, NULL, NULL);
1539 (*comp)[size] = 0;
1540 return TRUE;
1543 static BOOL set_url_component_AtoW(const char *comp_a, DWORD len_a, WCHAR **comp_w, DWORD *len_w, WCHAR **buf)
1545 *len_w = len_a;
1547 if(!comp_a) {
1548 *comp_w = NULL;
1549 return TRUE;
1552 if(!(*comp_w = *buf = malloc(len_a * sizeof(WCHAR)))) {
1553 SetLastError(ERROR_OUTOFMEMORY);
1554 return FALSE;
1557 return TRUE;
1560 /***********************************************************************
1561 * InternetCrackUrlA (WININET.@)
1563 * See InternetCrackUrlW.
1565 BOOL WINAPI InternetCrackUrlA(const char *url, DWORD url_length, DWORD flags, URL_COMPONENTSA *ret_comp)
1567 WCHAR *host = NULL, *user = NULL, *pass = NULL, *path = NULL, *scheme = NULL, *extra = NULL;
1568 URL_COMPONENTSW comp;
1569 WCHAR *url_w = NULL;
1570 BOOL ret;
1572 TRACE("(%s %lu %lx %p)\n", url_length ? debugstr_an(url, url_length) : debugstr_a(url), url_length, flags, ret_comp);
1574 if (!url || !*url || !ret_comp || ret_comp->dwStructSize != sizeof(URL_COMPONENTSA)) {
1575 SetLastError(ERROR_INVALID_PARAMETER);
1576 return FALSE;
1579 comp.dwStructSize = sizeof(comp);
1581 ret = set_url_component_AtoW(ret_comp->lpszHostName, ret_comp->dwHostNameLength,
1582 &comp.lpszHostName, &comp.dwHostNameLength, &host)
1583 && set_url_component_AtoW(ret_comp->lpszUserName, ret_comp->dwUserNameLength,
1584 &comp.lpszUserName, &comp.dwUserNameLength, &user)
1585 && set_url_component_AtoW(ret_comp->lpszPassword, ret_comp->dwPasswordLength,
1586 &comp.lpszPassword, &comp.dwPasswordLength, &pass)
1587 && set_url_component_AtoW(ret_comp->lpszUrlPath, ret_comp->dwUrlPathLength,
1588 &comp.lpszUrlPath, &comp.dwUrlPathLength, &path)
1589 && set_url_component_AtoW(ret_comp->lpszScheme, ret_comp->dwSchemeLength,
1590 &comp.lpszScheme, &comp.dwSchemeLength, &scheme)
1591 && set_url_component_AtoW(ret_comp->lpszExtraInfo, ret_comp->dwExtraInfoLength,
1592 &comp.lpszExtraInfo, &comp.dwExtraInfoLength, &extra);
1594 if(ret && !(url_w = strndupAtoW(url, url_length ? url_length : -1, &url_length))) {
1595 SetLastError(ERROR_OUTOFMEMORY);
1596 ret = FALSE;
1599 if (ret && (ret = InternetCrackUrlW(url_w, url_length, flags, &comp))) {
1600 ret_comp->nScheme = comp.nScheme;
1601 ret_comp->nPort = comp.nPort;
1603 ret = set_url_component_WtoA(comp.lpszHostName, comp.dwHostNameLength, url_w,
1604 &ret_comp->lpszHostName, &ret_comp->dwHostNameLength, url)
1605 && set_url_component_WtoA(comp.lpszUserName, comp.dwUserNameLength, url_w,
1606 &ret_comp->lpszUserName, &ret_comp->dwUserNameLength, url)
1607 && set_url_component_WtoA(comp.lpszPassword, comp.dwPasswordLength, url_w,
1608 &ret_comp->lpszPassword, &ret_comp->dwPasswordLength, url)
1609 && set_url_component_WtoA(comp.lpszUrlPath, comp.dwUrlPathLength, url_w,
1610 &ret_comp->lpszUrlPath, &ret_comp->dwUrlPathLength, url)
1611 && set_url_component_WtoA(comp.lpszScheme, comp.dwSchemeLength, url_w,
1612 &ret_comp->lpszScheme, &ret_comp->dwSchemeLength, url)
1613 && set_url_component_WtoA(comp.lpszExtraInfo, comp.dwExtraInfoLength, url_w,
1614 &ret_comp->lpszExtraInfo, &ret_comp->dwExtraInfoLength, url);
1616 if(ret)
1617 TRACE("%s: scheme(%s) host(%s) path(%s) extra(%s)\n", debugstr_a(url),
1618 debugstr_an(ret_comp->lpszScheme, ret_comp->dwSchemeLength),
1619 debugstr_an(ret_comp->lpszHostName, ret_comp->dwHostNameLength),
1620 debugstr_an(ret_comp->lpszUrlPath, ret_comp->dwUrlPathLength),
1621 debugstr_an(ret_comp->lpszExtraInfo, ret_comp->dwExtraInfoLength));
1624 free(host);
1625 free(user);
1626 free(pass);
1627 free(path);
1628 free(scheme);
1629 free(extra);
1630 free(url_w);
1631 return ret;
1634 static const WCHAR *url_schemes[] =
1636 L"ftp",
1637 L"gopher",
1638 L"http",
1639 L"https",
1640 L"file",
1641 L"news",
1642 L"mailto",
1643 L"socks",
1644 L"javascript",
1645 L"vbscript",
1646 L"res"
1649 /***********************************************************************
1650 * GetInternetSchemeW (internal)
1652 * Get scheme of url
1654 * RETURNS
1655 * scheme on success
1656 * INTERNET_SCHEME_UNKNOWN on failure
1659 static INTERNET_SCHEME GetInternetSchemeW(LPCWSTR lpszScheme, DWORD nMaxCmp)
1661 int i;
1663 TRACE("%s %ld\n",debugstr_wn(lpszScheme, nMaxCmp), nMaxCmp);
1665 if(lpszScheme==NULL)
1666 return INTERNET_SCHEME_UNKNOWN;
1668 for (i = 0; i < ARRAY_SIZE(url_schemes); i++)
1669 if (!wcsnicmp(lpszScheme, url_schemes[i], nMaxCmp))
1670 return INTERNET_SCHEME_FIRST + i;
1672 return INTERNET_SCHEME_UNKNOWN;
1675 /***********************************************************************
1676 * InternetCrackUrlW (WININET.@)
1678 * Break up URL into its components
1680 * RETURNS
1681 * TRUE on success
1682 * FALSE on failure
1684 BOOL WINAPI InternetCrackUrlW(const WCHAR *lpszUrl, DWORD dwUrlLength, DWORD dwFlags, URL_COMPONENTSW *lpUC)
1687 * RFC 1808
1688 * <protocol>:[//<net_loc>][/path][;<params>][?<query>][#<fragment>]
1691 LPCWSTR lpszParam = NULL;
1692 BOOL found_colon = FALSE;
1693 LPCWSTR lpszap;
1694 LPCWSTR lpszcp = NULL, lpszNetLoc;
1696 TRACE("(%s %lu %lx %p)\n",
1697 lpszUrl ? debugstr_wn(lpszUrl, dwUrlLength ? dwUrlLength : lstrlenW(lpszUrl)) : "(null)",
1698 dwUrlLength, dwFlags, lpUC);
1700 if (!lpszUrl || !*lpszUrl || !lpUC)
1702 SetLastError(ERROR_INVALID_PARAMETER);
1703 return FALSE;
1706 if (!dwUrlLength)
1707 dwUrlLength = lstrlenW(lpszUrl);
1708 else {
1709 /* Windows stops at a null, regardless of what dwUrlLength says. */
1710 dwUrlLength = wcsnlen(lpszUrl, dwUrlLength);
1713 if (dwFlags & ICU_DECODE)
1715 WCHAR *url_tmp, *buffer;
1716 DWORD len = dwUrlLength + 1;
1717 BOOL ret;
1719 if (!(url_tmp = strndupW(lpszUrl, dwUrlLength)))
1721 SetLastError(ERROR_OUTOFMEMORY);
1722 return FALSE;
1725 buffer = url_tmp;
1726 ret = InternetCanonicalizeUrlW(url_tmp, buffer, &len, ICU_DECODE | ICU_NO_ENCODE);
1727 if (!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
1729 buffer = malloc(len * sizeof(WCHAR));
1730 if (!buffer)
1732 SetLastError(ERROR_OUTOFMEMORY);
1733 free(url_tmp);
1734 return FALSE;
1736 ret = InternetCanonicalizeUrlW(url_tmp, buffer, &len, ICU_DECODE | ICU_NO_ENCODE);
1738 if (ret)
1739 ret = InternetCrackUrlW(buffer, len, dwFlags & ~ICU_DECODE, lpUC);
1741 if (buffer != url_tmp) free(buffer);
1742 free(url_tmp);
1743 return ret;
1745 lpszap = lpszUrl;
1747 /* Determine if the URI is absolute. */
1748 while (lpszap - lpszUrl < dwUrlLength)
1750 if (iswalnum(*lpszap) || *lpszap == '+' || *lpszap == '.' || *lpszap == '-')
1752 lpszap++;
1753 continue;
1755 if (*lpszap == ':')
1757 found_colon = TRUE;
1758 lpszcp = lpszap;
1760 else
1762 lpszcp = lpszUrl; /* Relative url */
1765 break;
1768 if(!found_colon){
1769 SetLastError(ERROR_INTERNET_UNRECOGNIZED_SCHEME);
1770 return FALSE;
1773 lpUC->nScheme = INTERNET_SCHEME_UNKNOWN;
1774 lpUC->nPort = INTERNET_INVALID_PORT_NUMBER;
1776 /* Parse <params> */
1777 lpszParam = wmemchr(lpszap, '?', dwUrlLength - (lpszap - lpszUrl));
1778 if(!lpszParam)
1779 lpszParam = wmemchr(lpszap, '#', dwUrlLength - (lpszap - lpszUrl));
1781 if(!set_url_component(&lpUC->lpszExtraInfo, &lpUC->dwExtraInfoLength,
1782 lpszParam, lpszParam ? dwUrlLength-(lpszParam-lpszUrl) : 0))
1783 return FALSE;
1786 /* Get scheme first. */
1787 lpUC->nScheme = GetInternetSchemeW(lpszUrl, lpszcp - lpszUrl);
1788 if(!set_url_component(&lpUC->lpszScheme, &lpUC->dwSchemeLength, lpszUrl, lpszcp - lpszUrl))
1789 return FALSE;
1791 /* Eat ':' in protocol. */
1792 lpszcp++;
1794 /* double slash indicates the net_loc portion is present */
1795 if ((lpszcp[0] == '/') && (lpszcp[1] == '/'))
1797 lpszcp += 2;
1799 lpszNetLoc = wmemchr(lpszcp, '/', dwUrlLength - (lpszcp - lpszUrl));
1800 if (lpszParam)
1802 if (lpszNetLoc)
1803 lpszNetLoc = min(lpszNetLoc, lpszParam);
1804 else
1805 lpszNetLoc = lpszParam;
1807 else if (!lpszNetLoc)
1808 lpszNetLoc = lpszcp + dwUrlLength-(lpszcp-lpszUrl);
1810 /* Parse net-loc */
1811 if (lpszNetLoc)
1813 LPCWSTR lpszHost;
1814 LPCWSTR lpszPort;
1816 /* [<user>[<:password>]@]<host>[:<port>] */
1817 /* First find the user and password if they exist */
1819 lpszHost = wmemchr(lpszcp, '@', dwUrlLength - (lpszcp - lpszUrl));
1820 if (lpszHost == NULL || lpszHost > lpszNetLoc)
1822 /* username and password not specified. */
1823 set_url_component(&lpUC->lpszUserName, &lpUC->dwUserNameLength, NULL, 0);
1824 set_url_component(&lpUC->lpszPassword, &lpUC->dwPasswordLength, NULL, 0);
1826 else /* Parse out username and password */
1828 LPCWSTR lpszUser = lpszcp;
1829 LPCWSTR lpszPasswd = lpszHost;
1831 while (lpszcp < lpszHost)
1833 if (*lpszcp == ':')
1834 lpszPasswd = lpszcp;
1836 lpszcp++;
1839 if(!set_url_component(&lpUC->lpszUserName, &lpUC->dwUserNameLength, lpszUser, lpszPasswd - lpszUser))
1840 return FALSE;
1842 if (lpszPasswd != lpszHost)
1843 lpszPasswd++;
1844 if(!set_url_component(&lpUC->lpszPassword, &lpUC->dwPasswordLength,
1845 lpszPasswd == lpszHost ? NULL : lpszPasswd, lpszHost - lpszPasswd))
1846 return FALSE;
1848 lpszcp++; /* Advance to beginning of host */
1851 /* Parse <host><:port> */
1853 lpszHost = lpszcp;
1854 lpszPort = lpszNetLoc;
1856 /* special case for res:// URLs: there is no port here, so the host is the
1857 entire string up to the first '/' */
1858 if(lpUC->nScheme==INTERNET_SCHEME_RES)
1860 if(!set_url_component(&lpUC->lpszHostName, &lpUC->dwHostNameLength, lpszHost, lpszPort - lpszHost))
1861 return FALSE;
1862 lpszcp=lpszNetLoc;
1864 else
1866 while (lpszcp < lpszNetLoc)
1868 if (*lpszcp == ':')
1869 lpszPort = lpszcp;
1871 lpszcp++;
1874 /* If the scheme is "file" and the host is just one letter, it's not a host */
1875 if(lpUC->nScheme==INTERNET_SCHEME_FILE && lpszPort <= lpszHost+1)
1877 lpszcp=lpszHost;
1878 set_url_component(&lpUC->lpszHostName, &lpUC->dwHostNameLength, NULL, 0);
1880 else
1882 if(!set_url_component(&lpUC->lpszHostName, &lpUC->dwHostNameLength, lpszHost, lpszPort - lpszHost))
1883 return FALSE;
1884 if (lpszPort != lpszNetLoc)
1885 lpUC->nPort = wcstol(++lpszPort, NULL, 10);
1886 else switch (lpUC->nScheme)
1888 case INTERNET_SCHEME_HTTP:
1889 lpUC->nPort = INTERNET_DEFAULT_HTTP_PORT;
1890 break;
1891 case INTERNET_SCHEME_HTTPS:
1892 lpUC->nPort = INTERNET_DEFAULT_HTTPS_PORT;
1893 break;
1894 case INTERNET_SCHEME_FTP:
1895 lpUC->nPort = INTERNET_DEFAULT_FTP_PORT;
1896 break;
1897 default:
1898 break;
1904 else
1906 set_url_component(&lpUC->lpszUserName, &lpUC->dwUserNameLength, NULL, 0);
1907 set_url_component(&lpUC->lpszPassword, &lpUC->dwPasswordLength, NULL, 0);
1908 set_url_component(&lpUC->lpszHostName, &lpUC->dwHostNameLength, NULL, 0);
1911 /* Here lpszcp points to:
1913 * <protocol>:[//<net_loc>][/path][;<params>][?<query>][#<fragment>]
1914 * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1916 if (lpszcp != 0 && lpszcp - lpszUrl < dwUrlLength && (!lpszParam || lpszcp <= lpszParam))
1918 DWORD len;
1920 /* Only truncate the parameter list if it's already been saved
1921 * in lpUC->lpszExtraInfo.
1923 if (lpszParam && lpUC->dwExtraInfoLength && lpUC->lpszExtraInfo)
1924 len = lpszParam - lpszcp;
1925 else
1927 /* Leave the parameter list in lpszUrlPath. Strip off any trailing
1928 * newlines if necessary.
1930 LPWSTR lpsznewline = wmemchr(lpszcp, '\n', dwUrlLength - (lpszcp - lpszUrl));
1931 if (lpsznewline != NULL)
1932 len = lpsznewline - lpszcp;
1933 else
1934 len = dwUrlLength-(lpszcp-lpszUrl);
1936 if (lpUC->dwUrlPathLength && lpUC->lpszUrlPath &&
1937 lpUC->nScheme == INTERNET_SCHEME_FILE)
1939 WCHAR tmppath[MAX_PATH];
1940 if (*lpszcp == '/')
1942 len = MAX_PATH;
1943 PathCreateFromUrlW(lpszUrl, tmppath, &len, 0);
1945 else
1947 WCHAR *iter;
1948 memcpy(tmppath, lpszcp, len * sizeof(WCHAR));
1949 tmppath[len] = '\0';
1951 iter = tmppath;
1952 while (*iter) {
1953 if (*iter == '/')
1954 *iter = '\\';
1955 ++iter;
1958 /* if ends in \. or \.. append a backslash */
1959 if (tmppath[len - 1] == '.' &&
1960 (tmppath[len - 2] == '\\' ||
1961 (tmppath[len - 2] == '.' && tmppath[len - 3] == '\\')))
1963 if (len < MAX_PATH - 1)
1965 tmppath[len] = '\\';
1966 tmppath[len+1] = '\0';
1967 ++len;
1970 if(!set_url_component(&lpUC->lpszUrlPath, &lpUC->dwUrlPathLength, tmppath, len))
1971 return FALSE;
1973 else if(!set_url_component(&lpUC->lpszUrlPath, &lpUC->dwUrlPathLength, lpszcp, len))
1974 return FALSE;
1976 else
1978 set_url_component(&lpUC->lpszUrlPath, &lpUC->dwUrlPathLength, lpszcp, 0);
1981 TRACE("%s: scheme(%s) host(%s) path(%s) extra(%s)\n", debugstr_wn(lpszUrl,dwUrlLength),
1982 debugstr_wn(lpUC->lpszScheme,lpUC->dwSchemeLength),
1983 debugstr_wn(lpUC->lpszHostName,lpUC->dwHostNameLength),
1984 debugstr_wn(lpUC->lpszUrlPath,lpUC->dwUrlPathLength),
1985 debugstr_wn(lpUC->lpszExtraInfo,lpUC->dwExtraInfoLength));
1987 return TRUE;
1990 /***********************************************************************
1991 * InternetAttemptConnect (WININET.@)
1993 * Attempt to make a connection to the internet
1995 * RETURNS
1996 * ERROR_SUCCESS on success
1997 * Error value on failure
2000 DWORD WINAPI InternetAttemptConnect(DWORD dwReserved)
2002 FIXME("Stub\n");
2003 return ERROR_SUCCESS;
2007 /***********************************************************************
2008 * convert_url_canonicalization_flags
2010 * Helper for InternetCanonicalizeUrl
2012 * PARAMS
2013 * dwFlags [I] Flags suitable for InternetCanonicalizeUrl
2015 * RETURNS
2016 * Flags suitable for UrlCanonicalize
2018 static DWORD convert_url_canonicalization_flags(DWORD dwFlags)
2020 DWORD dwUrlFlags = URL_WININET_COMPATIBILITY | URL_ESCAPE_UNSAFE;
2022 if (dwFlags & ICU_BROWSER_MODE) dwUrlFlags |= URL_BROWSER_MODE;
2023 if (dwFlags & ICU_DECODE) dwUrlFlags |= URL_UNESCAPE;
2024 if (dwFlags & ICU_ENCODE_PERCENT) dwUrlFlags |= URL_ESCAPE_PERCENT;
2025 if (dwFlags & ICU_ENCODE_SPACES_ONLY) dwUrlFlags |= URL_ESCAPE_SPACES_ONLY;
2026 /* Flip this bit to correspond to URL_ESCAPE_UNSAFE */
2027 if (dwFlags & ICU_NO_ENCODE) dwUrlFlags ^= URL_ESCAPE_UNSAFE;
2028 if (dwFlags & ICU_NO_META) dwUrlFlags |= URL_NO_META;
2030 return dwUrlFlags;
2033 /***********************************************************************
2034 * InternetCanonicalizeUrlA (WININET.@)
2036 * Escape unsafe characters and spaces
2038 * RETURNS
2039 * TRUE on success
2040 * FALSE on failure
2043 BOOL WINAPI InternetCanonicalizeUrlA(LPCSTR lpszUrl, LPSTR lpszBuffer,
2044 LPDWORD lpdwBufferLength, DWORD dwFlags)
2046 HRESULT hr;
2048 TRACE("(%s, %p, %p, 0x%08lx) buffer length: %ld\n", debugstr_a(lpszUrl), lpszBuffer,
2049 lpdwBufferLength, dwFlags, lpdwBufferLength ? *lpdwBufferLength : -1);
2051 dwFlags = convert_url_canonicalization_flags(dwFlags);
2052 hr = UrlCanonicalizeA(lpszUrl, lpszBuffer, lpdwBufferLength, dwFlags);
2053 if (hr == E_POINTER) SetLastError(ERROR_INSUFFICIENT_BUFFER);
2054 if (hr == E_INVALIDARG) SetLastError(ERROR_INVALID_PARAMETER);
2056 return hr == S_OK;
2059 /***********************************************************************
2060 * InternetCanonicalizeUrlW (WININET.@)
2062 * Escape unsafe characters and spaces
2064 * RETURNS
2065 * TRUE on success
2066 * FALSE on failure
2069 BOOL WINAPI InternetCanonicalizeUrlW(LPCWSTR lpszUrl, LPWSTR lpszBuffer,
2070 LPDWORD lpdwBufferLength, DWORD dwFlags)
2072 HRESULT hr;
2074 TRACE("(%s, %p, %p, 0x%08lx) buffer length: %ld\n", debugstr_w(lpszUrl), lpszBuffer,
2075 lpdwBufferLength, dwFlags, lpdwBufferLength ? *lpdwBufferLength : -1);
2077 dwFlags = convert_url_canonicalization_flags(dwFlags);
2078 hr = UrlCanonicalizeW(lpszUrl, lpszBuffer, lpdwBufferLength, dwFlags);
2079 if (hr == E_POINTER) SetLastError(ERROR_INSUFFICIENT_BUFFER);
2080 if (hr == E_INVALIDARG) SetLastError(ERROR_INVALID_PARAMETER);
2082 return hr == S_OK;
2085 /* #################################################### */
2087 static INTERNET_STATUS_CALLBACK set_status_callback(
2088 object_header_t *lpwh, INTERNET_STATUS_CALLBACK callback, BOOL unicode)
2090 INTERNET_STATUS_CALLBACK ret;
2092 if (unicode) lpwh->dwInternalFlags |= INET_CALLBACKW;
2093 else lpwh->dwInternalFlags &= ~INET_CALLBACKW;
2095 ret = lpwh->lpfnStatusCB;
2096 lpwh->lpfnStatusCB = callback;
2098 return ret;
2101 /***********************************************************************
2102 * InternetSetStatusCallbackA (WININET.@)
2104 * Sets up a callback function which is called as progress is made
2105 * during an operation.
2107 * RETURNS
2108 * Previous callback or NULL on success
2109 * INTERNET_INVALID_STATUS_CALLBACK on failure
2112 INTERNET_STATUS_CALLBACK WINAPI InternetSetStatusCallbackA(
2113 HINTERNET hInternet ,INTERNET_STATUS_CALLBACK lpfnIntCB)
2115 INTERNET_STATUS_CALLBACK retVal;
2116 object_header_t *lpwh;
2118 TRACE("%p\n", hInternet);
2120 if (!(lpwh = get_handle_object(hInternet)))
2121 return INTERNET_INVALID_STATUS_CALLBACK;
2123 retVal = set_status_callback(lpwh, lpfnIntCB, FALSE);
2125 WININET_Release( lpwh );
2126 return retVal;
2129 /***********************************************************************
2130 * InternetSetStatusCallbackW (WININET.@)
2132 * Sets up a callback function which is called as progress is made
2133 * during an operation.
2135 * RETURNS
2136 * Previous callback or NULL on success
2137 * INTERNET_INVALID_STATUS_CALLBACK on failure
2140 INTERNET_STATUS_CALLBACK WINAPI InternetSetStatusCallbackW(
2141 HINTERNET hInternet ,INTERNET_STATUS_CALLBACK lpfnIntCB)
2143 INTERNET_STATUS_CALLBACK retVal;
2144 object_header_t *lpwh;
2146 TRACE("%p\n", hInternet);
2148 if (!(lpwh = get_handle_object(hInternet)))
2149 return INTERNET_INVALID_STATUS_CALLBACK;
2151 retVal = set_status_callback(lpwh, lpfnIntCB, TRUE);
2153 WININET_Release( lpwh );
2154 return retVal;
2157 /***********************************************************************
2158 * InternetSetFilePointer (WININET.@)
2160 * Sets read position for an open internet file.
2162 * RETURNS
2163 * Current position of the file on success
2164 * INVALID_SET_FILE_POINTER on failure
2166 DWORD WINAPI InternetSetFilePointer(HINTERNET hFile, LONG lDistanceToMove,
2167 PVOID pReserved, DWORD dwMoveContext, DWORD_PTR dwContext)
2169 object_header_t *hdr;
2170 DWORD res;
2172 TRACE("(%p %ld %p %ld %Ix)\n", hFile, lDistanceToMove, pReserved, dwMoveContext, dwContext);
2174 hdr = get_handle_object(hFile);
2175 if(!hdr) {
2176 SetLastError(ERROR_INVALID_HANDLE);
2177 return INVALID_SET_FILE_POINTER;
2180 if(hdr->vtbl->SetFilePointer) {
2181 res = hdr->vtbl->SetFilePointer(hdr, lDistanceToMove, dwMoveContext);
2182 }else {
2183 SetLastError(ERROR_INVALID_HANDLE);
2184 res = INVALID_SET_FILE_POINTER;
2187 WININET_Release(hdr);
2188 return res;
2191 /***********************************************************************
2192 * InternetWriteFile (WININET.@)
2194 * Write data to an open internet file
2196 * RETURNS
2197 * TRUE on success
2198 * FALSE on failure
2201 BOOL WINAPI InternetWriteFile(HINTERNET hFile, LPCVOID lpBuffer,
2202 DWORD dwNumOfBytesToWrite, LPDWORD lpdwNumOfBytesWritten)
2204 object_header_t *lpwh;
2205 BOOL res;
2207 TRACE("(%p %p %ld %p)\n", hFile, lpBuffer, dwNumOfBytesToWrite, lpdwNumOfBytesWritten);
2209 lpwh = get_handle_object( hFile );
2210 if (!lpwh) {
2211 WARN("Invalid handle\n");
2212 SetLastError(ERROR_INVALID_HANDLE);
2213 return FALSE;
2216 if(lpwh->vtbl->WriteFile) {
2217 res = lpwh->vtbl->WriteFile(lpwh, lpBuffer, dwNumOfBytesToWrite, lpdwNumOfBytesWritten);
2218 }else {
2219 WARN("No Writefile method.\n");
2220 res = ERROR_INVALID_HANDLE;
2223 WININET_Release( lpwh );
2225 if(res != ERROR_SUCCESS)
2226 SetLastError(res);
2227 return res == ERROR_SUCCESS;
2231 /***********************************************************************
2232 * InternetReadFile (WININET.@)
2234 * Read data from an open internet file
2236 * RETURNS
2237 * TRUE on success
2238 * FALSE on failure
2241 BOOL WINAPI InternetReadFile(HINTERNET hFile, LPVOID lpBuffer,
2242 DWORD dwNumOfBytesToRead, LPDWORD pdwNumOfBytesRead)
2244 object_header_t *hdr;
2245 DWORD res = ERROR_INTERNET_INCORRECT_HANDLE_TYPE;
2247 TRACE("%p %p %ld %p\n", hFile, lpBuffer, dwNumOfBytesToRead, pdwNumOfBytesRead);
2249 hdr = get_handle_object(hFile);
2250 if (!hdr) {
2251 INTERNET_SetLastError(ERROR_INVALID_HANDLE);
2252 return FALSE;
2255 if(hdr->vtbl->ReadFile) {
2256 res = hdr->vtbl->ReadFile(hdr, lpBuffer, dwNumOfBytesToRead, pdwNumOfBytesRead, 0, 0);
2257 if(res == ERROR_IO_PENDING)
2258 *pdwNumOfBytesRead = 0;
2261 WININET_Release(hdr);
2263 TRACE("-- %s (%lu) (bytes read: %ld)\n", res == ERROR_SUCCESS ? "TRUE": "FALSE", res,
2264 pdwNumOfBytesRead ? *pdwNumOfBytesRead : -1);
2266 SetLastError(res);
2267 return res == ERROR_SUCCESS;
2270 /***********************************************************************
2271 * InternetReadFileExA (WININET.@)
2273 * Read data from an open internet file
2275 * PARAMS
2276 * hFile [I] Handle returned by InternetOpenUrl or HttpOpenRequest.
2277 * lpBuffersOut [I/O] Buffer.
2278 * dwFlags [I] Flags. See notes.
2279 * dwContext [I] Context for callbacks.
2281 * RETURNS
2282 * TRUE on success
2283 * FALSE on failure
2285 * NOTES
2286 * The parameter dwFlags include zero or more of the following flags:
2287 *|IRF_ASYNC - Makes the call asynchronous.
2288 *|IRF_SYNC - Makes the call synchronous.
2289 *|IRF_USE_CONTEXT - Forces dwContext to be used.
2290 *|IRF_NO_WAIT - Don't block if the data is not available, just return what is available.
2292 * However, in testing IRF_USE_CONTEXT seems to have no effect - dwContext isn't used.
2294 * SEE
2295 * InternetOpenUrlA(), HttpOpenRequestA()
2297 BOOL WINAPI InternetReadFileExA(HINTERNET hFile, LPINTERNET_BUFFERSA lpBuffersOut,
2298 DWORD dwFlags, DWORD_PTR dwContext)
2300 object_header_t *hdr;
2301 DWORD res = ERROR_INTERNET_INCORRECT_HANDLE_TYPE;
2303 TRACE("(%p %p 0x%lx 0x%Ix)\n", hFile, lpBuffersOut, dwFlags, dwContext);
2305 if (lpBuffersOut->dwStructSize != sizeof(*lpBuffersOut)) {
2306 SetLastError(ERROR_INVALID_PARAMETER);
2307 return FALSE;
2310 hdr = get_handle_object(hFile);
2311 if (!hdr) {
2312 INTERNET_SetLastError(ERROR_INVALID_HANDLE);
2313 return FALSE;
2316 if(hdr->vtbl->ReadFile)
2317 res = hdr->vtbl->ReadFile(hdr, lpBuffersOut->lpvBuffer, lpBuffersOut->dwBufferLength,
2318 &lpBuffersOut->dwBufferLength, dwFlags, dwContext);
2320 WININET_Release(hdr);
2322 TRACE("-- %s (%lu, bytes read: %ld)\n", res == ERROR_SUCCESS ? "TRUE": "FALSE",
2323 res, lpBuffersOut->dwBufferLength);
2325 if(res != ERROR_SUCCESS)
2326 SetLastError(res);
2327 return res == ERROR_SUCCESS;
2330 /***********************************************************************
2331 * InternetReadFileExW (WININET.@)
2332 * SEE
2333 * InternetReadFileExA()
2335 BOOL WINAPI InternetReadFileExW(HINTERNET hFile, LPINTERNET_BUFFERSW lpBuffer,
2336 DWORD dwFlags, DWORD_PTR dwContext)
2338 object_header_t *hdr;
2339 DWORD res = ERROR_INTERNET_INCORRECT_HANDLE_TYPE;
2341 TRACE("(%p %p 0x%lx 0x%Ix)\n", hFile, lpBuffer, dwFlags, dwContext);
2343 if (!lpBuffer || lpBuffer->dwStructSize != sizeof(*lpBuffer)) {
2344 SetLastError(ERROR_INVALID_PARAMETER);
2345 return FALSE;
2348 hdr = get_handle_object(hFile);
2349 if (!hdr) {
2350 INTERNET_SetLastError(ERROR_INVALID_HANDLE);
2351 return FALSE;
2354 if(hdr->vtbl->ReadFile)
2355 res = hdr->vtbl->ReadFile(hdr, lpBuffer->lpvBuffer, lpBuffer->dwBufferLength, &lpBuffer->dwBufferLength,
2356 dwFlags, dwContext);
2358 WININET_Release(hdr);
2360 TRACE("-- %s (%lu, bytes read: %ld)\n", res == ERROR_SUCCESS ? "TRUE": "FALSE",
2361 res, lpBuffer->dwBufferLength);
2363 if(res != ERROR_SUCCESS)
2364 SetLastError(res);
2365 return res == ERROR_SUCCESS;
2368 static IP_ADAPTER_ADDRESSES *get_adapters(void)
2370 ULONG err, size = 1024, flags = GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST |
2371 GAA_FLAG_SKIP_DNS_SERVER | GAA_FLAG_SKIP_FRIENDLY_NAME;
2372 IP_ADAPTER_ADDRESSES *tmp, *ret;
2374 if (!(ret = malloc( size ))) return NULL;
2375 err = GetAdaptersAddresses( AF_UNSPEC, flags, NULL, ret, &size );
2376 while (err == ERROR_BUFFER_OVERFLOW)
2378 if (!(tmp = realloc( ret, size ))) break;
2379 ret = tmp;
2380 err = GetAdaptersAddresses( AF_UNSPEC, flags, NULL, ret, &size );
2382 if (err == ERROR_SUCCESS) return ret;
2383 free( ret );
2384 return NULL;
2387 static WCHAR *detect_proxy_autoconfig_url_dhcp(void)
2389 IP_ADAPTER_ADDRESSES *adapters, *ptr;
2390 DHCPCAPI_PARAMS_ARRAY send_params, recv_params;
2391 DHCPCAPI_PARAMS param;
2392 WCHAR name[MAX_ADAPTER_NAME_LENGTH + 1], *ret = NULL;
2393 DWORD err, size;
2394 BYTE *tmp, *buf = NULL;
2396 if (!(adapters = get_adapters())) return NULL;
2398 memset( &send_params, 0, sizeof(send_params) );
2399 memset( &param, 0, sizeof(param) );
2400 param.OptionId = OPTION_MSFT_IE_PROXY;
2401 recv_params.nParams = 1;
2402 recv_params.Params = &param;
2404 for (ptr = adapters; ptr; ptr = ptr->Next)
2406 MultiByteToWideChar( CP_ACP, 0, ptr->AdapterName, -1, name, ARRAY_SIZE(name) );
2407 TRACE( "adapter '%s' type %lu dhcpv4 enabled %d\n", wine_dbgstr_w(name), ptr->IfType, ptr->Dhcpv4Enabled );
2409 if (ptr->IfType == IF_TYPE_SOFTWARE_LOOPBACK) continue;
2410 /* FIXME: also skip adapters where DHCP is disabled */
2412 size = 256;
2413 if (!(buf = malloc( size ))) goto done;
2414 err = DhcpRequestParams( DHCPCAPI_REQUEST_SYNCHRONOUS, NULL, name, NULL, send_params, recv_params,
2415 buf, &size, NULL );
2416 while (err == ERROR_MORE_DATA)
2418 if (!(tmp = realloc( buf, size ))) goto done;
2419 buf = tmp;
2420 err = DhcpRequestParams( DHCPCAPI_REQUEST_SYNCHRONOUS, NULL, name, NULL, send_params, recv_params,
2421 buf, &size, NULL );
2423 if (err == ERROR_SUCCESS && param.nBytesData)
2425 int len = MultiByteToWideChar( CP_ACP, 0, (const char *)param.Data, param.nBytesData, NULL, 0 );
2426 if ((ret = malloc( (len + 1) * sizeof(WCHAR) )))
2428 MultiByteToWideChar( CP_ACP, 0, (const char *)param.Data, param.nBytesData, ret, len );
2429 ret[len] = 0;
2431 TRACE("returning %s\n", debugstr_w(ret));
2432 break;
2436 done:
2437 free( buf );
2438 free( adapters );
2439 return ret;
2442 static char *get_computer_name( COMPUTER_NAME_FORMAT format )
2444 char *ret;
2445 DWORD size = 0;
2447 GetComputerNameExA( format, NULL, &size );
2448 if (GetLastError() != ERROR_MORE_DATA) return NULL;
2449 if (!(ret = malloc( size ))) return NULL;
2450 if (!GetComputerNameExA( format, ret, &size ))
2452 free( ret );
2453 return NULL;
2455 return ret;
2458 static BOOL is_domain_suffix( const char *domain, const char *suffix )
2460 int len_domain = strlen( domain ), len_suffix = strlen( suffix );
2462 if (len_suffix > len_domain) return FALSE;
2463 if (!stricmp( domain + len_domain - len_suffix, suffix )) return TRUE;
2464 return FALSE;
2467 static int reverse_lookup( const struct addrinfo *ai, char *hostname, size_t len )
2469 return getnameinfo( ai->ai_addr, ai->ai_addrlen, hostname, len, NULL, 0, 0 );
2472 static WCHAR *build_wpad_url( const char *hostname, const struct addrinfo *ai )
2474 char name[NI_MAXHOST];
2475 WCHAR *ret, *p;
2476 int len;
2478 while (ai && ai->ai_family != AF_INET && ai->ai_family != AF_INET6) ai = ai->ai_next;
2479 if (!ai) return NULL;
2481 if (!reverse_lookup( ai, name, sizeof(name) )) hostname = name;
2483 len = lstrlenW( L"http://" ) + strlen( hostname ) + lstrlenW( L"/wpad.dat" );
2484 if (!(ret = p = GlobalAlloc( 0, (len + 1) * sizeof(WCHAR) ))) return NULL;
2485 lstrcpyW( p, L"http://" );
2486 p += lstrlenW( L"http://" );
2487 while (*hostname) { *p++ = *hostname++; }
2488 lstrcpyW( p, L"/wpad.dat" );
2489 return ret;
2492 static WCHAR *detect_proxy_autoconfig_url_dns(void)
2494 char *fqdn, *domain, *p;
2495 WCHAR *ret;
2497 if (!(fqdn = get_computer_name( ComputerNamePhysicalDnsFullyQualified ))) return NULL;
2498 if (!(domain = get_computer_name( ComputerNamePhysicalDnsDomain )))
2500 free( fqdn );
2501 return NULL;
2503 p = fqdn;
2504 while ((p = strchr( p, '.' )) && is_domain_suffix( p + 1, domain ))
2506 char *name;
2507 struct addrinfo *ai, hints;
2508 int res;
2510 if (!(name = malloc( sizeof("wpad") + strlen(p) )))
2512 free( fqdn );
2513 free( domain );
2514 return NULL;
2516 strcpy( name, "wpad" );
2517 strcat( name, p );
2518 memset( &hints, 0, sizeof(hints) );
2519 hints.ai_flags = AI_ALL | AI_DNS_ONLY;
2520 hints.ai_family = AF_UNSPEC;
2521 res = getaddrinfo( name, NULL, &hints, &ai );
2522 if (!res)
2524 ret = build_wpad_url( name, ai );
2525 freeaddrinfo( ai );
2526 if (ret)
2528 TRACE("returning %s\n", debugstr_w(ret));
2529 free( name );
2530 break;
2533 free( name );
2534 p++;
2536 free( domain );
2537 free( fqdn );
2538 return ret;
2541 static WCHAR *get_proxy_autoconfig_url(void)
2543 WCHAR *ret = detect_proxy_autoconfig_url_dhcp();
2544 if (!ret) ret = detect_proxy_autoconfig_url_dns();
2545 return ret;
2548 static WCHAR *copy_optionW(WCHAR *value)
2550 DWORD len;
2551 void *tmp;
2553 if (!value)
2554 return NULL;
2556 len = (wcslen(value) + 1) * sizeof(WCHAR);
2557 if (!(tmp = HeapAlloc(GetProcessHeap(), 0, len)))
2558 return NULL;
2560 return memcpy(tmp, value, len);
2563 static char *copy_optionA(WCHAR *value)
2565 DWORD len;
2566 void *tmp;
2568 if (!value)
2569 return NULL;
2571 len = wcslen(value) * 3 + 1;
2572 if (!(tmp = HeapAlloc(GetProcessHeap(), 0, len)))
2573 return NULL;
2575 WideCharToMultiByte(CP_ACP, 0, value, -1, tmp, len, NULL, NULL);
2576 return tmp;
2579 static DWORD query_global_option(DWORD option, void *buffer, DWORD *size, BOOL unicode)
2581 /* FIXME: This function currently handles more options than it should. Options requiring
2582 * proper handles should be moved to proper functions */
2583 switch(option) {
2584 case INTERNET_OPTION_HTTP_VERSION:
2585 if (*size < sizeof(HTTP_VERSION_INFO))
2586 return ERROR_INSUFFICIENT_BUFFER;
2589 * Presently hardcoded to 1.1
2591 ((HTTP_VERSION_INFO*)buffer)->dwMajorVersion = 1;
2592 ((HTTP_VERSION_INFO*)buffer)->dwMinorVersion = 1;
2593 *size = sizeof(HTTP_VERSION_INFO);
2595 return ERROR_SUCCESS;
2597 case INTERNET_OPTION_CONNECTED_STATE:
2598 FIXME("INTERNET_OPTION_CONNECTED_STATE: semi-stub\n");
2600 if (*size < sizeof(ULONG))
2601 return ERROR_INSUFFICIENT_BUFFER;
2603 *(ULONG*)buffer = INTERNET_STATE_CONNECTED;
2604 *size = sizeof(ULONG);
2606 return ERROR_SUCCESS;
2608 case INTERNET_OPTION_PROXY: {
2609 appinfo_t ai;
2610 BOOL ret;
2612 TRACE("Getting global proxy info\n");
2613 memset(&ai, 0, sizeof(appinfo_t));
2614 INTERNET_ConfigureProxy(&ai);
2616 ret = APPINFO_QueryOption(&ai.hdr, INTERNET_OPTION_PROXY, buffer, size, unicode); /* FIXME */
2617 APPINFO_Destroy(&ai.hdr);
2618 return ret;
2621 case INTERNET_OPTION_MAX_CONNS_PER_SERVER:
2622 TRACE("INTERNET_OPTION_MAX_CONNS_PER_SERVER\n");
2624 if (*size < sizeof(ULONG))
2625 return ERROR_INSUFFICIENT_BUFFER;
2627 *(ULONG*)buffer = max_conns;
2628 *size = sizeof(ULONG);
2630 return ERROR_SUCCESS;
2632 case INTERNET_OPTION_MAX_CONNS_PER_1_0_SERVER:
2633 TRACE("INTERNET_OPTION_MAX_CONNS_1_0_SERVER\n");
2635 if (*size < sizeof(ULONG))
2636 return ERROR_INSUFFICIENT_BUFFER;
2638 *(ULONG*)buffer = max_1_0_conns;
2639 *size = sizeof(ULONG);
2641 return ERROR_SUCCESS;
2643 case INTERNET_OPTION_SECURITY_FLAGS:
2644 FIXME("INTERNET_OPTION_SECURITY_FLAGS: Stub\n");
2645 return ERROR_SUCCESS;
2647 case INTERNET_OPTION_VERSION: {
2648 static const INTERNET_VERSION_INFO info = { 1, 2 };
2650 TRACE("INTERNET_OPTION_VERSION\n");
2652 if (*size < sizeof(INTERNET_VERSION_INFO))
2653 return ERROR_INSUFFICIENT_BUFFER;
2655 memcpy(buffer, &info, sizeof(info));
2656 *size = sizeof(info);
2658 return ERROR_SUCCESS;
2661 case INTERNET_OPTION_PER_CONNECTION_OPTION: {
2662 WCHAR *url;
2663 INTERNET_PER_CONN_OPTION_LISTW *con = buffer;
2664 INTERNET_PER_CONN_OPTION_LISTA *conA = buffer;
2665 DWORD res = ERROR_SUCCESS, i;
2666 proxyinfo_t pi;
2667 LONG ret;
2669 TRACE("Getting global proxy info\n");
2670 if((ret = INTERNET_LoadProxySettings(&pi)))
2671 return ret;
2673 FIXME("INTERNET_OPTION_PER_CONNECTION_OPTION stub\n");
2675 if (*size < sizeof(INTERNET_PER_CONN_OPTION_LISTW)) {
2676 FreeProxyInfo(&pi);
2677 return ERROR_INSUFFICIENT_BUFFER;
2680 url = get_proxy_autoconfig_url();
2682 for (i = 0; i < con->dwOptionCount; i++) {
2683 INTERNET_PER_CONN_OPTIONW *optionW = con->pOptions + i;
2684 INTERNET_PER_CONN_OPTIONA *optionA = conA->pOptions + i;
2686 switch (optionW->dwOption) {
2687 case INTERNET_PER_CONN_FLAGS:
2688 if(pi.proxyEnabled)
2689 optionW->Value.dwValue = PROXY_TYPE_PROXY;
2690 else
2691 optionW->Value.dwValue = PROXY_TYPE_DIRECT;
2692 if (url)
2693 /* native includes PROXY_TYPE_DIRECT even if PROXY_TYPE_PROXY is set */
2694 optionW->Value.dwValue |= PROXY_TYPE_DIRECT|PROXY_TYPE_AUTO_PROXY_URL;
2695 break;
2697 case INTERNET_PER_CONN_PROXY_SERVER:
2698 if (unicode)
2699 optionW->Value.pszValue = copy_optionW(pi.proxy);
2700 else
2701 optionA->Value.pszValue = copy_optionA(pi.proxy);
2702 break;
2704 case INTERNET_PER_CONN_PROXY_BYPASS:
2705 if (unicode)
2706 optionW->Value.pszValue = copy_optionW(pi.proxyBypass);
2707 else
2708 optionA->Value.pszValue = copy_optionA(pi.proxyBypass);
2709 break;
2711 case INTERNET_PER_CONN_AUTOCONFIG_URL:
2712 if (!url)
2713 optionW->Value.pszValue = NULL;
2714 else if (unicode)
2715 optionW->Value.pszValue = copy_optionW(url);
2716 else
2717 optionA->Value.pszValue = copy_optionA(url);
2718 break;
2720 case INTERNET_PER_CONN_AUTODISCOVERY_FLAGS:
2721 optionW->Value.dwValue = AUTO_PROXY_FLAG_ALWAYS_DETECT;
2722 break;
2724 case INTERNET_PER_CONN_AUTOCONFIG_SECONDARY_URL:
2725 case INTERNET_PER_CONN_AUTOCONFIG_RELOAD_DELAY_MINS:
2726 case INTERNET_PER_CONN_AUTOCONFIG_LAST_DETECT_TIME:
2727 case INTERNET_PER_CONN_AUTOCONFIG_LAST_DETECT_URL:
2728 FIXME("Unhandled dwOption %ld\n", optionW->dwOption);
2729 memset(&optionW->Value, 0, sizeof(optionW->Value));
2730 break;
2732 default:
2733 FIXME("Unknown dwOption %ld\n", optionW->dwOption);
2734 res = ERROR_INVALID_PARAMETER;
2735 break;
2738 free(url);
2739 FreeProxyInfo(&pi);
2741 return res;
2743 case INTERNET_OPTION_REQUEST_FLAGS:
2744 case INTERNET_OPTION_USER_AGENT:
2745 *size = 0;
2746 return ERROR_INTERNET_INCORRECT_HANDLE_TYPE;
2747 case INTERNET_OPTION_POLICY:
2748 return ERROR_INVALID_PARAMETER;
2749 case INTERNET_OPTION_CONNECT_TIMEOUT:
2750 TRACE("INTERNET_OPTION_CONNECT_TIMEOUT\n");
2752 if (*size < sizeof(ULONG))
2753 return ERROR_INSUFFICIENT_BUFFER;
2755 *(ULONG*)buffer = connect_timeout;
2756 *size = sizeof(ULONG);
2758 return ERROR_SUCCESS;
2761 FIXME("Stub for %ld\n", option);
2762 return ERROR_INTERNET_INCORRECT_HANDLE_TYPE;
2765 DWORD INET_QueryOption(object_header_t *hdr, DWORD option, void *buffer, DWORD *size, BOOL unicode)
2767 switch(option) {
2768 case INTERNET_OPTION_CONTEXT_VALUE:
2769 if (!size)
2770 return ERROR_INVALID_PARAMETER;
2772 if (*size < sizeof(DWORD_PTR)) {
2773 *size = sizeof(DWORD_PTR);
2774 return ERROR_INSUFFICIENT_BUFFER;
2776 if (!buffer)
2777 return ERROR_INVALID_PARAMETER;
2779 *(DWORD_PTR *)buffer = hdr->dwContext;
2780 *size = sizeof(DWORD_PTR);
2781 return ERROR_SUCCESS;
2783 case INTERNET_OPTION_REQUEST_FLAGS:
2784 WARN("INTERNET_OPTION_REQUEST_FLAGS\n");
2785 *size = sizeof(DWORD);
2786 return ERROR_INTERNET_INCORRECT_HANDLE_TYPE;
2788 case INTERNET_OPTION_MAX_CONNS_PER_SERVER:
2789 case INTERNET_OPTION_MAX_CONNS_PER_1_0_SERVER:
2790 WARN("Called on global option %lu\n", option);
2791 return ERROR_INTERNET_INVALID_OPERATION;
2794 /* FIXME: we shouldn't call it here */
2795 return query_global_option(option, buffer, size, unicode);
2798 /***********************************************************************
2799 * InternetQueryOptionW (WININET.@)
2801 * Queries an options on the specified handle
2803 * RETURNS
2804 * TRUE on success
2805 * FALSE on failure
2808 BOOL WINAPI InternetQueryOptionW(HINTERNET hInternet, DWORD dwOption,
2809 LPVOID lpBuffer, LPDWORD lpdwBufferLength)
2811 object_header_t *hdr;
2812 DWORD res = ERROR_INVALID_HANDLE;
2814 TRACE("%p %ld %p %p\n", hInternet, dwOption, lpBuffer, lpdwBufferLength);
2816 if(hInternet) {
2817 hdr = get_handle_object(hInternet);
2818 if (hdr) {
2819 res = hdr->vtbl->QueryOption(hdr, dwOption, lpBuffer, lpdwBufferLength, TRUE);
2820 WININET_Release(hdr);
2822 }else {
2823 res = query_global_option(dwOption, lpBuffer, lpdwBufferLength, TRUE);
2826 if(res != ERROR_SUCCESS)
2827 SetLastError(res);
2828 return res == ERROR_SUCCESS;
2831 /***********************************************************************
2832 * InternetQueryOptionA (WININET.@)
2834 * Queries an options on the specified handle
2836 * RETURNS
2837 * TRUE on success
2838 * FALSE on failure
2841 BOOL WINAPI InternetQueryOptionA(HINTERNET hInternet, DWORD dwOption,
2842 LPVOID lpBuffer, LPDWORD lpdwBufferLength)
2844 object_header_t *hdr;
2845 DWORD res = ERROR_INVALID_HANDLE;
2847 TRACE("%p %ld %p %p\n", hInternet, dwOption, lpBuffer, lpdwBufferLength);
2849 if(hInternet) {
2850 hdr = get_handle_object(hInternet);
2851 if (hdr) {
2852 res = hdr->vtbl->QueryOption(hdr, dwOption, lpBuffer, lpdwBufferLength, FALSE);
2853 WININET_Release(hdr);
2855 }else {
2856 res = query_global_option(dwOption, lpBuffer, lpdwBufferLength, FALSE);
2859 if(res != ERROR_SUCCESS)
2860 SetLastError(res);
2861 return res == ERROR_SUCCESS;
2864 DWORD INET_SetOption(object_header_t *hdr, DWORD option, void *buf, DWORD size)
2866 switch(option) {
2867 case INTERNET_OPTION_SETTINGS_CHANGED:
2868 FIXME("INTERNETOPTION_SETTINGS_CHANGED semi-stub\n");
2869 collect_connections(COLLECT_CONNECTIONS);
2870 return ERROR_SUCCESS;
2871 case INTERNET_OPTION_CALLBACK:
2872 WARN("Not settable option %lu\n", option);
2873 return ERROR_INTERNET_OPTION_NOT_SETTABLE;
2874 case INTERNET_OPTION_MAX_CONNS_PER_SERVER:
2875 case INTERNET_OPTION_MAX_CONNS_PER_1_0_SERVER:
2876 WARN("Called on global option %lu\n", option);
2877 return ERROR_INTERNET_INVALID_OPERATION;
2878 case INTERNET_OPTION_REFRESH:
2879 return ERROR_INTERNET_INCORRECT_HANDLE_TYPE;
2882 return ERROR_INTERNET_INVALID_OPTION;
2885 static DWORD set_global_option(DWORD option, void *buf, DWORD size)
2887 switch(option) {
2888 case INTERNET_OPTION_CALLBACK:
2889 WARN("Not global option %lu\n", option);
2890 return ERROR_INTERNET_INCORRECT_HANDLE_TYPE;
2892 case INTERNET_OPTION_MAX_CONNS_PER_SERVER:
2893 TRACE("INTERNET_OPTION_MAX_CONNS_PER_SERVER\n");
2895 if(size != sizeof(max_conns))
2896 return ERROR_INTERNET_BAD_OPTION_LENGTH;
2897 if(!*(ULONG*)buf)
2898 return ERROR_BAD_ARGUMENTS;
2900 max_conns = *(ULONG*)buf;
2901 return ERROR_SUCCESS;
2903 case INTERNET_OPTION_MAX_CONNS_PER_1_0_SERVER:
2904 TRACE("INTERNET_OPTION_MAX_CONNS_PER_1_0_SERVER\n");
2906 if(size != sizeof(max_1_0_conns))
2907 return ERROR_INTERNET_BAD_OPTION_LENGTH;
2908 if(!*(ULONG*)buf)
2909 return ERROR_BAD_ARGUMENTS;
2911 max_1_0_conns = *(ULONG*)buf;
2912 return ERROR_SUCCESS;
2914 case INTERNET_OPTION_CONNECT_TIMEOUT:
2915 TRACE("INTERNET_OPTION_CONNECT_TIMEOUT\n");
2917 if(size != sizeof(connect_timeout))
2918 return ERROR_INTERNET_BAD_OPTION_LENGTH;
2919 if(!*(ULONG*)buf)
2920 return ERROR_BAD_ARGUMENTS;
2922 connect_timeout = *(ULONG*)buf;
2923 return ERROR_SUCCESS;
2925 case INTERNET_OPTION_SUPPRESS_BEHAVIOR:
2926 FIXME("INTERNET_OPTION_SUPPRESS_BEHAVIOR stub\n");
2928 if(size != sizeof(ULONG))
2929 return ERROR_INTERNET_BAD_OPTION_LENGTH;
2931 FIXME("%08lx\n", *(ULONG*)buf);
2932 return ERROR_SUCCESS;
2935 return INET_SetOption(NULL, option, buf, size);
2938 /***********************************************************************
2939 * InternetSetOptionW (WININET.@)
2941 * Sets an options on the specified handle
2943 * RETURNS
2944 * TRUE on success
2945 * FALSE on failure
2948 BOOL WINAPI InternetSetOptionW(HINTERNET hInternet, DWORD dwOption,
2949 LPVOID lpBuffer, DWORD dwBufferLength)
2951 object_header_t *lpwhh;
2952 BOOL ret = TRUE;
2953 DWORD res;
2955 TRACE("(%p %ld %p %ld)\n", hInternet, dwOption, lpBuffer, dwBufferLength);
2957 lpwhh = (object_header_t*) get_handle_object( hInternet );
2958 if(lpwhh)
2959 res = lpwhh->vtbl->SetOption(lpwhh, dwOption, lpBuffer, dwBufferLength);
2960 else
2961 res = set_global_option(dwOption, lpBuffer, dwBufferLength);
2963 if(res != ERROR_INTERNET_INVALID_OPTION) {
2964 if(lpwhh)
2965 WININET_Release(lpwhh);
2967 if(res != ERROR_SUCCESS)
2968 SetLastError(res);
2970 return res == ERROR_SUCCESS;
2973 switch (dwOption)
2975 case INTERNET_OPTION_HTTP_VERSION:
2977 HTTP_VERSION_INFO* pVersion=(HTTP_VERSION_INFO*)lpBuffer;
2978 FIXME("Option INTERNET_OPTION_HTTP_VERSION(%ld,%ld): STUB\n",pVersion->dwMajorVersion,pVersion->dwMinorVersion);
2980 break;
2981 case INTERNET_OPTION_ERROR_MASK:
2983 if(!lpwhh) {
2984 SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
2985 return FALSE;
2986 } else if(*(ULONG*)lpBuffer & (~(INTERNET_ERROR_MASK_INSERT_CDROM|
2987 INTERNET_ERROR_MASK_COMBINED_SEC_CERT|
2988 INTERNET_ERROR_MASK_LOGIN_FAILURE_DISPLAY_ENTITY_BODY))) {
2989 SetLastError(ERROR_INVALID_PARAMETER);
2990 ret = FALSE;
2991 } else if(dwBufferLength != sizeof(ULONG)) {
2992 SetLastError(ERROR_INTERNET_BAD_OPTION_LENGTH);
2993 ret = FALSE;
2994 } else {
2995 TRACE("INTERNET_OPTION_ERROR_MASK: %lx\n", *(ULONG*)lpBuffer);
2996 lpwhh->ErrorMask = *(ULONG*)lpBuffer;
2999 break;
3000 case INTERNET_OPTION_PROXY:
3002 INTERNET_PROXY_INFOW *info = lpBuffer;
3004 if (!lpBuffer || dwBufferLength < sizeof(INTERNET_PROXY_INFOW))
3006 SetLastError(ERROR_INVALID_PARAMETER);
3007 return FALSE;
3009 if (!hInternet)
3011 EnterCriticalSection( &WININET_cs );
3012 free_global_proxy();
3013 global_proxy = malloc(sizeof(proxyinfo_t));
3014 if (global_proxy)
3016 if (info->dwAccessType == INTERNET_OPEN_TYPE_PROXY)
3018 global_proxy->proxyEnabled = 1;
3019 global_proxy->proxy = wcsdup(info->lpszProxy);
3020 global_proxy->proxyBypass = wcsdup(info->lpszProxyBypass);
3022 else
3024 global_proxy->proxyEnabled = 0;
3025 global_proxy->proxy = global_proxy->proxyBypass = NULL;
3028 LeaveCriticalSection( &WININET_cs );
3030 else
3032 /* In general, each type of object should handle
3033 * INTERNET_OPTION_PROXY directly. This FIXME ensures it doesn't
3034 * get silently dropped.
3036 FIXME("INTERNET_OPTION_PROXY unimplemented\n");
3037 SetLastError(ERROR_INTERNET_INVALID_OPTION);
3038 ret = FALSE;
3040 break;
3042 case INTERNET_OPTION_CODEPAGE:
3044 ULONG codepage = *(ULONG *)lpBuffer;
3045 FIXME("Option INTERNET_OPTION_CODEPAGE (%ld): STUB\n", codepage);
3047 break;
3048 case INTERNET_OPTION_REQUEST_PRIORITY:
3050 ULONG priority = *(ULONG *)lpBuffer;
3051 FIXME("Option INTERNET_OPTION_REQUEST_PRIORITY (%ld): STUB\n", priority);
3053 break;
3054 case INTERNET_OPTION_CONNECT_TIMEOUT:
3056 ULONG connecttimeout = *(ULONG *)lpBuffer;
3057 FIXME("Option INTERNET_OPTION_CONNECT_TIMEOUT (%ld): STUB\n", connecttimeout);
3059 break;
3060 case INTERNET_OPTION_DATA_RECEIVE_TIMEOUT:
3062 ULONG receivetimeout = *(ULONG *)lpBuffer;
3063 FIXME("Option INTERNET_OPTION_DATA_RECEIVE_TIMEOUT (%ld): STUB\n", receivetimeout);
3065 break;
3066 case INTERNET_OPTION_RESET_URLCACHE_SESSION:
3067 FIXME("Option INTERNET_OPTION_RESET_URLCACHE_SESSION: STUB\n");
3068 break;
3069 case INTERNET_OPTION_END_BROWSER_SESSION:
3070 FIXME("Option INTERNET_OPTION_END_BROWSER_SESSION: semi-stub\n");
3071 free_cookie();
3072 free_authorization_cache();
3073 break;
3074 case INTERNET_OPTION_CONNECTED_STATE:
3075 FIXME("Option INTERNET_OPTION_CONNECTED_STATE: STUB\n");
3076 break;
3077 case INTERNET_OPTION_DISABLE_PASSPORT_AUTH:
3078 TRACE("Option INTERNET_OPTION_DISABLE_PASSPORT_AUTH: harmless stub, since not enabled\n");
3079 break;
3080 case INTERNET_OPTION_IGNORE_OFFLINE:
3081 FIXME("Option INTERNET_OPTION_IGNORE_OFFLINE: STUB\n");
3082 break;
3083 case INTERNET_OPTION_SEND_TIMEOUT:
3084 case INTERNET_OPTION_RECEIVE_TIMEOUT:
3085 case INTERNET_OPTION_DATA_SEND_TIMEOUT:
3087 ULONG timeout = *(ULONG *)lpBuffer;
3088 FIXME("INTERNET_OPTION_SEND/RECEIVE_TIMEOUT/DATA_SEND_TIMEOUT %ld\n", timeout);
3089 break;
3091 case INTERNET_OPTION_CONNECT_RETRIES:
3093 ULONG retries = *(ULONG *)lpBuffer;
3094 FIXME("INTERNET_OPTION_CONNECT_RETRIES %ld\n", retries);
3095 break;
3097 case INTERNET_OPTION_CONTEXT_VALUE:
3099 if (!lpwhh)
3101 SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
3102 return FALSE;
3104 if (!lpBuffer || dwBufferLength != sizeof(DWORD_PTR))
3106 SetLastError(ERROR_INVALID_PARAMETER);
3107 ret = FALSE;
3109 else
3110 lpwhh->dwContext = *(DWORD_PTR *)lpBuffer;
3111 break;
3113 case INTERNET_OPTION_SECURITY_FLAGS:
3114 FIXME("Option INTERNET_OPTION_SECURITY_FLAGS; STUB\n");
3115 break;
3116 case INTERNET_OPTION_DISABLE_AUTODIAL:
3117 FIXME("Option INTERNET_OPTION_DISABLE_AUTODIAL; STUB\n");
3118 break;
3119 case INTERNET_OPTION_HTTP_DECODING:
3120 if (!lpwhh)
3122 SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
3123 return FALSE;
3125 if (!lpBuffer || dwBufferLength != sizeof(BOOL))
3127 SetLastError(ERROR_INVALID_PARAMETER);
3128 ret = FALSE;
3130 else
3131 lpwhh->decoding = *(BOOL *)lpBuffer;
3132 break;
3133 case INTERNET_OPTION_COOKIES_3RD_PARTY:
3134 FIXME("INTERNET_OPTION_COOKIES_3RD_PARTY; STUB\n");
3135 SetLastError(ERROR_INTERNET_INVALID_OPTION);
3136 ret = FALSE;
3137 break;
3138 case INTERNET_OPTION_SEND_UTF8_SERVERNAME_TO_PROXY:
3139 FIXME("INTERNET_OPTION_SEND_UTF8_SERVERNAME_TO_PROXY; STUB\n");
3140 SetLastError(ERROR_INTERNET_INVALID_OPTION);
3141 ret = FALSE;
3142 break;
3143 case INTERNET_OPTION_CODEPAGE_PATH:
3144 FIXME("INTERNET_OPTION_CODEPAGE_PATH; STUB\n");
3145 SetLastError(ERROR_INTERNET_INVALID_OPTION);
3146 ret = FALSE;
3147 break;
3148 case INTERNET_OPTION_CODEPAGE_EXTRA:
3149 FIXME("INTERNET_OPTION_CODEPAGE_EXTRA; STUB\n");
3150 SetLastError(ERROR_INTERNET_INVALID_OPTION);
3151 ret = FALSE;
3152 break;
3153 case INTERNET_OPTION_IDN:
3154 FIXME("INTERNET_OPTION_IDN; STUB\n");
3155 SetLastError(ERROR_INTERNET_INVALID_OPTION);
3156 ret = FALSE;
3157 break;
3158 case INTERNET_OPTION_POLICY:
3159 SetLastError(ERROR_INVALID_PARAMETER);
3160 ret = FALSE;
3161 break;
3162 case INTERNET_OPTION_PER_CONNECTION_OPTION: {
3163 INTERNET_PER_CONN_OPTION_LISTW *con = lpBuffer;
3164 LONG res;
3165 unsigned int i;
3166 proxyinfo_t pi;
3168 if (INTERNET_LoadProxySettings(&pi)) return FALSE;
3170 for (i = 0; i < con->dwOptionCount; i++) {
3171 INTERNET_PER_CONN_OPTIONW *option = con->pOptions + i;
3173 switch (option->dwOption) {
3174 case INTERNET_PER_CONN_PROXY_SERVER:
3175 free(pi.proxy);
3176 pi.proxy = wcsdup(option->Value.pszValue);
3177 break;
3179 case INTERNET_PER_CONN_FLAGS:
3180 if(option->Value.dwValue & PROXY_TYPE_PROXY)
3181 pi.proxyEnabled = 1;
3182 else
3184 if(option->Value.dwValue != PROXY_TYPE_DIRECT)
3185 FIXME("Unhandled flags: 0x%lx\n", option->Value.dwValue);
3186 pi.proxyEnabled = 0;
3188 break;
3190 case INTERNET_PER_CONN_PROXY_BYPASS:
3191 free(pi.proxyBypass);
3192 pi.proxyBypass = wcsdup(option->Value.pszValue);
3193 break;
3195 case INTERNET_PER_CONN_AUTOCONFIG_URL:
3196 case INTERNET_PER_CONN_AUTODISCOVERY_FLAGS:
3197 case INTERNET_PER_CONN_AUTOCONFIG_SECONDARY_URL:
3198 case INTERNET_PER_CONN_AUTOCONFIG_RELOAD_DELAY_MINS:
3199 case INTERNET_PER_CONN_AUTOCONFIG_LAST_DETECT_TIME:
3200 case INTERNET_PER_CONN_AUTOCONFIG_LAST_DETECT_URL:
3201 FIXME("Unhandled dwOption %ld\n", option->dwOption);
3202 break;
3204 default:
3205 FIXME("Unknown dwOption %ld\n", option->dwOption);
3206 SetLastError(ERROR_INVALID_PARAMETER);
3207 break;
3211 if ((res = INTERNET_SaveProxySettings(&pi)))
3212 SetLastError(res);
3214 FreeProxyInfo(&pi);
3216 ret = (res == ERROR_SUCCESS);
3217 break;
3219 default:
3220 FIXME("Option %ld STUB\n",dwOption);
3221 SetLastError(ERROR_INTERNET_INVALID_OPTION);
3222 ret = FALSE;
3223 break;
3226 if(lpwhh)
3227 WININET_Release( lpwhh );
3229 return ret;
3233 /***********************************************************************
3234 * InternetSetOptionA (WININET.@)
3236 * Sets an options on the specified handle.
3238 * RETURNS
3239 * TRUE on success
3240 * FALSE on failure
3243 BOOL WINAPI InternetSetOptionA(HINTERNET hInternet, DWORD dwOption,
3244 LPVOID lpBuffer, DWORD dwBufferLength)
3246 LPVOID wbuffer;
3247 DWORD wlen;
3248 BOOL r;
3250 switch( dwOption )
3252 case INTERNET_OPTION_PROXY:
3254 LPINTERNET_PROXY_INFOA pi = (LPINTERNET_PROXY_INFOA) lpBuffer;
3255 LPINTERNET_PROXY_INFOW piw;
3256 DWORD proxlen, prbylen;
3257 LPWSTR prox, prby;
3259 proxlen = MultiByteToWideChar( CP_ACP, 0, pi->lpszProxy, -1, NULL, 0);
3260 prbylen= MultiByteToWideChar( CP_ACP, 0, pi->lpszProxyBypass, -1, NULL, 0);
3261 wlen = sizeof(*piw) + proxlen + prbylen;
3262 wbuffer = malloc( wlen * sizeof(WCHAR) );
3263 piw = (LPINTERNET_PROXY_INFOW) wbuffer;
3264 piw->dwAccessType = pi->dwAccessType;
3265 prox = (LPWSTR) &piw[1];
3266 prby = &prox[proxlen+1];
3267 MultiByteToWideChar( CP_ACP, 0, pi->lpszProxy, -1, prox, proxlen);
3268 MultiByteToWideChar( CP_ACP, 0, pi->lpszProxyBypass, -1, prby, prbylen);
3269 piw->lpszProxy = prox;
3270 piw->lpszProxyBypass = prby;
3272 break;
3273 case INTERNET_OPTION_USER_AGENT:
3274 case INTERNET_OPTION_USERNAME:
3275 case INTERNET_OPTION_PASSWORD:
3276 case INTERNET_OPTION_PROXY_USERNAME:
3277 case INTERNET_OPTION_PROXY_PASSWORD:
3278 wlen = MultiByteToWideChar( CP_ACP, 0, lpBuffer, -1, NULL, 0 );
3279 if (!(wbuffer = malloc( wlen * sizeof(WCHAR) ))) return ERROR_OUTOFMEMORY;
3280 MultiByteToWideChar( CP_ACP, 0, lpBuffer, -1, wbuffer, wlen );
3281 break;
3282 case INTERNET_OPTION_PER_CONNECTION_OPTION: {
3283 unsigned int i;
3284 INTERNET_PER_CONN_OPTION_LISTW *listW;
3285 INTERNET_PER_CONN_OPTION_LISTA *listA = lpBuffer;
3286 wlen = sizeof(INTERNET_PER_CONN_OPTION_LISTW);
3287 wbuffer = malloc( wlen );
3288 listW = wbuffer;
3290 listW->dwSize = sizeof(INTERNET_PER_CONN_OPTION_LISTW);
3291 if (listA->pszConnection)
3293 wlen = MultiByteToWideChar( CP_ACP, 0, listA->pszConnection, -1, NULL, 0 );
3294 listW->pszConnection = malloc( wlen * sizeof(WCHAR) );
3295 MultiByteToWideChar( CP_ACP, 0, listA->pszConnection, -1, listW->pszConnection, wlen );
3297 else
3298 listW->pszConnection = NULL;
3299 listW->dwOptionCount = listA->dwOptionCount;
3300 listW->dwOptionError = listA->dwOptionError;
3301 listW->pOptions = malloc( sizeof(INTERNET_PER_CONN_OPTIONW) * listA->dwOptionCount );
3303 for (i = 0; i < listA->dwOptionCount; ++i) {
3304 INTERNET_PER_CONN_OPTIONA *optA = listA->pOptions + i;
3305 INTERNET_PER_CONN_OPTIONW *optW = listW->pOptions + i;
3307 optW->dwOption = optA->dwOption;
3309 switch (optA->dwOption) {
3310 case INTERNET_PER_CONN_AUTOCONFIG_URL:
3311 case INTERNET_PER_CONN_PROXY_BYPASS:
3312 case INTERNET_PER_CONN_PROXY_SERVER:
3313 case INTERNET_PER_CONN_AUTOCONFIG_SECONDARY_URL:
3314 case INTERNET_PER_CONN_AUTOCONFIG_LAST_DETECT_URL:
3315 if (optA->Value.pszValue)
3317 wlen = MultiByteToWideChar( CP_ACP, 0, optA->Value.pszValue, -1, NULL, 0 );
3318 optW->Value.pszValue = malloc( wlen * sizeof(WCHAR) );
3319 MultiByteToWideChar( CP_ACP, 0, optA->Value.pszValue, -1, optW->Value.pszValue, wlen );
3321 else
3322 optW->Value.pszValue = NULL;
3323 break;
3324 case INTERNET_PER_CONN_AUTODISCOVERY_FLAGS:
3325 case INTERNET_PER_CONN_FLAGS:
3326 case INTERNET_PER_CONN_AUTOCONFIG_RELOAD_DELAY_MINS:
3327 optW->Value.dwValue = optA->Value.dwValue;
3328 break;
3329 case INTERNET_PER_CONN_AUTOCONFIG_LAST_DETECT_TIME:
3330 optW->Value.ftValue = optA->Value.ftValue;
3331 break;
3332 default:
3333 WARN("Unknown PER_CONN dwOption: %ld, guessing at conversion to Wide\n", optA->dwOption);
3334 optW->Value.dwValue = optA->Value.dwValue;
3335 break;
3339 break;
3340 default:
3341 wbuffer = lpBuffer;
3342 wlen = dwBufferLength;
3345 r = InternetSetOptionW(hInternet,dwOption, wbuffer, wlen);
3347 if( lpBuffer != wbuffer )
3349 if (dwOption == INTERNET_OPTION_PER_CONNECTION_OPTION)
3351 INTERNET_PER_CONN_OPTION_LISTW *list = wbuffer;
3352 unsigned int i;
3353 for (i = 0; i < list->dwOptionCount; ++i) {
3354 INTERNET_PER_CONN_OPTIONW *opt = list->pOptions + i;
3355 switch (opt->dwOption) {
3356 case INTERNET_PER_CONN_AUTOCONFIG_URL:
3357 case INTERNET_PER_CONN_PROXY_BYPASS:
3358 case INTERNET_PER_CONN_PROXY_SERVER:
3359 case INTERNET_PER_CONN_AUTOCONFIG_SECONDARY_URL:
3360 case INTERNET_PER_CONN_AUTOCONFIG_LAST_DETECT_URL:
3361 free( opt->Value.pszValue );
3362 break;
3363 default:
3364 break;
3367 free( list->pOptions );
3369 free( wbuffer );
3372 return r;
3376 /***********************************************************************
3377 * InternetSetOptionExA (WININET.@)
3379 BOOL WINAPI InternetSetOptionExA(HINTERNET hInternet, DWORD dwOption,
3380 LPVOID lpBuffer, DWORD dwBufferLength, DWORD dwFlags)
3382 FIXME("Flags %08lx ignored\n", dwFlags);
3383 return InternetSetOptionA( hInternet, dwOption, lpBuffer, dwBufferLength );
3386 /***********************************************************************
3387 * InternetSetOptionExW (WININET.@)
3389 BOOL WINAPI InternetSetOptionExW(HINTERNET hInternet, DWORD dwOption,
3390 LPVOID lpBuffer, DWORD dwBufferLength, DWORD dwFlags)
3392 FIXME("Flags %08lx ignored\n", dwFlags);
3393 if( dwFlags & ~ISO_VALID_FLAGS )
3395 SetLastError( ERROR_INVALID_PARAMETER );
3396 return FALSE;
3398 return InternetSetOptionW( hInternet, dwOption, lpBuffer, dwBufferLength );
3401 static const WCHAR WININET_wkday[7][4] =
3402 { L"Sun", L"Mon", L"Tue", L"Wed",
3403 L"Thu", L"Fri", L"Sat"};
3404 static const WCHAR WININET_month[12][4] =
3405 { L"Jan", L"Feb", L"Mar", L"Apr",
3406 L"May", L"Jun", L"Jul", L"Aug",
3407 L"Sep", L"Oct", L"Nov", L"Dec"};
3409 static inline BOOL is_time_digit(const WCHAR c)
3411 return c >= '0' && c <= '9';
3414 /***********************************************************************
3415 * InternetTimeFromSystemTimeA (WININET.@)
3417 BOOL WINAPI InternetTimeFromSystemTimeA( const SYSTEMTIME* time, DWORD format, LPSTR string, DWORD size )
3419 BOOL ret;
3420 WCHAR stringW[INTERNET_RFC1123_BUFSIZE];
3422 TRACE( "%p 0x%08lx %p 0x%08lx\n", time, format, string, size );
3424 if (!time || !string || format != INTERNET_RFC1123_FORMAT)
3426 SetLastError(ERROR_INVALID_PARAMETER);
3427 return FALSE;
3430 if (size < INTERNET_RFC1123_BUFSIZE * sizeof(*string))
3432 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3433 return FALSE;
3436 ret = InternetTimeFromSystemTimeW( time, format, stringW, sizeof(stringW) );
3437 if (ret) WideCharToMultiByte( CP_ACP, 0, stringW, -1, string, size, NULL, NULL );
3439 return ret;
3442 /***********************************************************************
3443 * InternetTimeFromSystemTimeW (WININET.@)
3445 BOOL WINAPI InternetTimeFromSystemTimeW( const SYSTEMTIME* time, DWORD format, LPWSTR string, DWORD size )
3447 TRACE( "%p 0x%08lx %p 0x%08lx\n", time, format, string, size );
3449 if (!time || !string || format != INTERNET_RFC1123_FORMAT)
3451 SetLastError(ERROR_INVALID_PARAMETER);
3452 return FALSE;
3455 if (size < INTERNET_RFC1123_BUFSIZE * sizeof(*string))
3457 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3458 return FALSE;
3461 swprintf( string, size, L"%s, %02d %s %4d %02d:%02d:%02d GMT",
3462 WININET_wkday[time->wDayOfWeek],
3463 time->wDay,
3464 WININET_month[time->wMonth - 1],
3465 time->wYear,
3466 time->wHour,
3467 time->wMinute,
3468 time->wSecond );
3470 return TRUE;
3473 /***********************************************************************
3474 * InternetTimeToSystemTimeA (WININET.@)
3476 BOOL WINAPI InternetTimeToSystemTimeA( LPCSTR string, SYSTEMTIME* time, DWORD reserved )
3478 BOOL ret = FALSE;
3479 WCHAR *stringW;
3481 TRACE( "%s %p 0x%08lx\n", debugstr_a(string), time, reserved );
3483 stringW = strdupAtoW( string );
3484 if (stringW)
3486 ret = InternetTimeToSystemTimeW( stringW, time, reserved );
3487 free( stringW );
3489 return ret;
3492 /***********************************************************************
3493 * InternetTimeToSystemTimeW (WININET.@)
3495 BOOL WINAPI InternetTimeToSystemTimeW( LPCWSTR string, SYSTEMTIME* time, DWORD reserved )
3497 unsigned int i;
3498 const WCHAR *s = string;
3499 WCHAR *end;
3501 TRACE( "%s %p 0x%08lx\n", debugstr_w(string), time, reserved );
3503 if (!string || !time) return FALSE;
3505 /* Windows does this too */
3506 GetSystemTime( time );
3508 /* Convert an RFC1123 time such as 'Fri, 07 Jan 2005 12:06:35 GMT' into
3509 * a SYSTEMTIME structure.
3512 while (*s && !iswalpha(*s) && !is_time_digit(*s)) s++;
3513 if (*s == '\0') return TRUE;
3514 time->wDayOfWeek = 7;
3516 if (iswalpha(*s))
3518 if (s[1] == '\0' || s[2] == '\0') return TRUE;
3519 for (i = 0; i < 7; i++)
3521 if (!wcsnicmp(WININET_wkday[i], s, 3))
3523 time->wDayOfWeek = i;
3524 break;
3528 else if (is_time_digit(*s))
3530 time->wDayOfWeek = wcstol(s, &end, 10);
3531 s = end;
3533 if (time->wDayOfWeek > 6) return TRUE;
3535 while (*s && !is_time_digit(*s)) s++;
3536 time->wDay = wcstol( s, &end, 10 );
3537 s = end;
3539 while (*s && !iswalpha(*s) && !is_time_digit(*s)) s++;
3540 if (*s == '\0') return TRUE;
3541 time->wMonth = 0;
3543 if (iswalpha(*s))
3545 if (s[1] == '\0' || s[2] == '\0') return TRUE;
3546 for (i = 0; i < 12; i++)
3548 if (!wcsnicmp(WININET_month[i], s, 3))
3550 time->wMonth = i + 1;
3551 break;
3555 else if (is_time_digit(*s))
3557 time->wMonth = wcstol(s, &end, 10);
3558 s = end;
3560 if (time->wMonth == 0) return TRUE;
3562 while (*s && !is_time_digit(*s)) s++;
3563 if (*s == '\0') return TRUE;
3564 time->wYear = wcstol( s, &end, 10 );
3565 s = end;
3567 while (*s && !is_time_digit(*s)) s++;
3568 if (*s == '\0') return TRUE;
3569 time->wHour = wcstol( s, &end, 10 );
3570 s = end;
3572 while (*s && !is_time_digit(*s)) s++;
3573 if (*s == '\0') return TRUE;
3574 time->wMinute = wcstol( s, &end, 10 );
3575 s = end;
3577 while (*s && !is_time_digit(*s)) s++;
3578 if (*s == '\0') return TRUE;
3579 time->wSecond = wcstol( s, &end, 10 );
3580 s = end;
3582 time->wMilliseconds = 0;
3583 return TRUE;
3586 /***********************************************************************
3587 * InternetCheckConnectionW (WININET.@)
3589 * Pings a requested host to check internet connection
3591 * RETURNS
3592 * TRUE on success and FALSE on failure. If a failure then
3593 * ERROR_NOT_CONNECTED is placed into GetLastError
3596 BOOL WINAPI InternetCheckConnectionW( LPCWSTR lpszUrl, DWORD dwFlags, DWORD dwReserved )
3599 * this is a kludge which runs the resident ping program and reads the output.
3601 * Anyone have a better idea?
3604 BOOL rc = FALSE;
3605 static const CHAR ping[] = "ping -c 1 ";
3606 static const CHAR redirect[] = " >/dev/null 2>/dev/null";
3607 WCHAR *host;
3608 DWORD len, host_len;
3609 INTERNET_PORT port;
3610 int status = -1;
3612 FIXME("(%s %lx %lx)\n", debugstr_w(lpszUrl), dwFlags, dwReserved);
3615 * Crack or set the Address
3617 if (lpszUrl == NULL)
3620 * According to the doc we are supposed to use the ip for the next
3621 * server in the WnInet internal server database. I have
3622 * no idea what that is or how to get it.
3624 * So someone needs to implement this.
3626 FIXME("Unimplemented with URL of NULL\n");
3627 return TRUE;
3629 else
3631 URL_COMPONENTSW components = {sizeof(components)};
3633 components.dwHostNameLength = 1;
3635 if (!InternetCrackUrlW(lpszUrl,0,0,&components))
3636 goto End;
3638 host = components.lpszHostName;
3639 host_len = components.dwHostNameLength;
3640 port = components.nPort;
3641 TRACE("host name: %s port: %d\n",debugstr_wn(host, host_len), port);
3644 if (dwFlags & FLAG_ICC_FORCE_CONNECTION)
3646 struct sockaddr_storage saddr;
3647 int sa_len = sizeof(saddr);
3648 WCHAR *host_z;
3649 int fd;
3650 BOOL b;
3652 host_z = strndupW(host, host_len);
3653 if (!host_z)
3654 return FALSE;
3656 b = GetAddress(host_z, port, (struct sockaddr *)&saddr, &sa_len, NULL);
3657 free(host_z);
3658 if(!b)
3659 goto End;
3660 init_winsock();
3661 fd = socket(saddr.ss_family, SOCK_STREAM, 0);
3662 if (fd != -1)
3664 if (connect(fd, (struct sockaddr *)&saddr, sa_len) == 0)
3665 rc = TRUE;
3666 closesocket(fd);
3669 else
3672 * Build our ping command
3674 char *command;
3676 len = WideCharToMultiByte(CP_UNIXCP, 0, host, host_len, NULL, 0, NULL, NULL);
3677 command = malloc(strlen(ping) + len + strlen(redirect) + 1);
3678 strcpy(command, ping);
3679 WideCharToMultiByte(CP_UNIXCP, 0, host, host_len, command+sizeof(ping)-1, len, NULL, NULL);
3680 strcpy(command+sizeof(ping)-1+len, redirect);
3682 TRACE("Ping command is : %s\n",command);
3684 status = system(command);
3685 free(command);
3687 TRACE("Ping returned a code of %i\n",status);
3689 /* Ping return code of 0 indicates success */
3690 if (status == 0)
3691 rc = TRUE;
3694 End:
3695 if (rc == FALSE)
3696 INTERNET_SetLastError(ERROR_NOT_CONNECTED);
3698 return rc;
3702 /***********************************************************************
3703 * InternetCheckConnectionA (WININET.@)
3705 * Pings a requested host to check internet connection
3707 * RETURNS
3708 * TRUE on success and FALSE on failure. If a failure then
3709 * ERROR_NOT_CONNECTED is placed into GetLastError
3712 BOOL WINAPI InternetCheckConnectionA(LPCSTR lpszUrl, DWORD dwFlags, DWORD dwReserved)
3714 WCHAR *url = NULL;
3715 BOOL rc;
3717 if(lpszUrl) {
3718 url = strdupAtoW(lpszUrl);
3719 if(!url)
3720 return FALSE;
3723 rc = InternetCheckConnectionW(url, dwFlags, dwReserved);
3725 free(url);
3726 return rc;
3730 /**********************************************************
3731 * INTERNET_InternetOpenUrlW (internal)
3733 * Opens an URL
3735 * RETURNS
3736 * handle of connection or NULL on failure
3738 static HINTERNET INTERNET_InternetOpenUrlW(appinfo_t *hIC, LPCWSTR lpszUrl,
3739 LPCWSTR lpszHeaders, DWORD dwHeadersLength, DWORD dwFlags, DWORD_PTR dwContext)
3741 URL_COMPONENTSW urlComponents = { sizeof(urlComponents) };
3742 WCHAR *host, *user = NULL, *pass = NULL, *path;
3743 HINTERNET client = NULL, client1 = NULL;
3744 DWORD res;
3746 TRACE("(%p, %s, %s, %08lx, %08lx, %08Ix)\n", hIC, debugstr_w(lpszUrl), debugstr_w(lpszHeaders),
3747 dwHeadersLength, dwFlags, dwContext);
3749 urlComponents.dwHostNameLength = 1;
3750 urlComponents.dwUserNameLength = 1;
3751 urlComponents.dwPasswordLength = 1;
3752 urlComponents.dwUrlPathLength = 1;
3753 urlComponents.dwExtraInfoLength = 1;
3754 if(!InternetCrackUrlW(lpszUrl, lstrlenW(lpszUrl), 0, &urlComponents))
3755 return NULL;
3757 if ((urlComponents.nScheme == INTERNET_SCHEME_HTTP || urlComponents.nScheme == INTERNET_SCHEME_HTTPS) &&
3758 urlComponents.dwExtraInfoLength)
3760 assert(urlComponents.lpszUrlPath + urlComponents.dwUrlPathLength == urlComponents.lpszExtraInfo);
3761 urlComponents.dwUrlPathLength += urlComponents.dwExtraInfoLength;
3764 host = strndupW(urlComponents.lpszHostName, urlComponents.dwHostNameLength);
3765 path = strndupW(urlComponents.lpszUrlPath, urlComponents.dwUrlPathLength);
3766 if(urlComponents.dwUserNameLength)
3767 user = strndupW(urlComponents.lpszUserName, urlComponents.dwUserNameLength);
3768 if(urlComponents.dwPasswordLength)
3769 pass = strndupW(urlComponents.lpszPassword, urlComponents.dwPasswordLength);
3771 switch(urlComponents.nScheme) {
3772 case INTERNET_SCHEME_FTP:
3773 client = FTP_Connect(hIC, host, urlComponents.nPort,
3774 user, pass, dwFlags, dwContext, INET_OPENURL);
3775 if(client == NULL)
3776 break;
3777 client1 = FtpOpenFileW(client, path, GENERIC_READ, dwFlags, dwContext);
3778 if(client1 == NULL) {
3779 InternetCloseHandle(client);
3780 break;
3782 break;
3784 case INTERNET_SCHEME_HTTP:
3785 case INTERNET_SCHEME_HTTPS: {
3786 LPCWSTR accept[2] = { L"*/*", NULL };
3788 if (urlComponents.nScheme == INTERNET_SCHEME_HTTPS) dwFlags |= INTERNET_FLAG_SECURE;
3790 /* FIXME: should use pointers, not handles, as handles are not thread-safe */
3791 res = HTTP_Connect(hIC, host, urlComponents.nPort,
3792 user, pass, dwFlags, dwContext, INET_OPENURL, &client);
3793 if(res != ERROR_SUCCESS) {
3794 INTERNET_SetLastError(res);
3795 break;
3798 client1 = HttpOpenRequestW(client, NULL, path, NULL, NULL, accept, dwFlags, dwContext);
3799 if(client1 == NULL) {
3800 InternetCloseHandle(client);
3801 break;
3803 HttpAddRequestHeadersW(client1, lpszHeaders, dwHeadersLength, HTTP_ADDREQ_FLAG_ADD);
3804 if (!HttpSendRequestW(client1, NULL, 0, NULL, 0) &&
3805 GetLastError() != ERROR_IO_PENDING) {
3806 InternetCloseHandle(client1);
3807 client1 = NULL;
3808 break;
3811 case INTERNET_SCHEME_GOPHER:
3812 /* gopher doesn't seem to be implemented in wine, but it's supposed
3813 * to be supported by InternetOpenUrlA. */
3814 default:
3815 SetLastError(ERROR_INTERNET_UNRECOGNIZED_SCHEME);
3816 break;
3819 TRACE(" %p <--\n", client1);
3821 free(host);
3822 free(path);
3823 free(user);
3824 free(pass);
3825 return client1;
3828 /**********************************************************
3829 * InternetOpenUrlW (WININET.@)
3831 * Opens an URL
3833 * RETURNS
3834 * handle of connection or NULL on failure
3836 typedef struct {
3837 task_header_t hdr;
3838 WCHAR *url;
3839 WCHAR *headers;
3840 DWORD headers_len;
3841 DWORD flags;
3842 DWORD_PTR context;
3843 } open_url_task_t;
3845 static void AsyncInternetOpenUrlProc(task_header_t *hdr)
3847 open_url_task_t *task = (open_url_task_t*)hdr;
3849 TRACE("%p\n", task->hdr.hdr);
3851 INTERNET_InternetOpenUrlW((appinfo_t*)task->hdr.hdr, task->url, task->headers,
3852 task->headers_len, task->flags, task->context);
3853 free(task->url);
3854 free(task->headers);
3857 HINTERNET WINAPI InternetOpenUrlW(HINTERNET hInternet, LPCWSTR lpszUrl,
3858 LPCWSTR lpszHeaders, DWORD dwHeadersLength, DWORD dwFlags, DWORD_PTR dwContext)
3860 HINTERNET ret = NULL;
3861 appinfo_t *hIC = NULL;
3863 if (TRACE_ON(wininet)) {
3864 TRACE("(%p, %s, %s, %08lx, %08lx, %08Ix)\n", hInternet, debugstr_w(lpszUrl), debugstr_w(lpszHeaders),
3865 dwHeadersLength, dwFlags, dwContext);
3866 TRACE(" flags :");
3867 dump_INTERNET_FLAGS(dwFlags);
3870 if (!lpszUrl)
3872 SetLastError(ERROR_INVALID_PARAMETER);
3873 goto lend;
3876 hIC = (appinfo_t*)get_handle_object( hInternet );
3877 if (NULL == hIC || hIC->hdr.htype != WH_HINIT) {
3878 SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
3879 goto lend;
3882 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC) {
3883 open_url_task_t *task;
3885 task = alloc_async_task(&hIC->hdr, AsyncInternetOpenUrlProc, sizeof(*task));
3886 task->url = wcsdup(lpszUrl);
3887 task->headers = wcsdup(lpszHeaders);
3888 task->headers_len = dwHeadersLength;
3889 task->flags = dwFlags;
3890 task->context = dwContext;
3892 INTERNET_AsyncCall(&task->hdr);
3893 SetLastError(ERROR_IO_PENDING);
3894 } else {
3895 ret = INTERNET_InternetOpenUrlW(hIC, lpszUrl, lpszHeaders, dwHeadersLength, dwFlags, dwContext);
3898 lend:
3899 if( hIC )
3900 WININET_Release( &hIC->hdr );
3901 TRACE(" %p <--\n", ret);
3903 return ret;
3906 /**********************************************************
3907 * InternetOpenUrlA (WININET.@)
3909 * Opens an URL
3911 * RETURNS
3912 * handle of connection or NULL on failure
3914 HINTERNET WINAPI InternetOpenUrlA(HINTERNET hInternet, LPCSTR lpszUrl,
3915 LPCSTR lpszHeaders, DWORD dwHeadersLength, DWORD dwFlags, DWORD_PTR dwContext)
3917 HINTERNET rc = NULL;
3918 LPWSTR szUrl = NULL;
3919 WCHAR *headers = NULL;
3921 TRACE("\n");
3923 if(lpszUrl) {
3924 szUrl = strdupAtoW(lpszUrl);
3925 if(!szUrl)
3926 return NULL;
3929 if(lpszHeaders) {
3930 headers = strndupAtoW(lpszHeaders, dwHeadersLength, &dwHeadersLength);
3931 if(!headers) {
3932 free(szUrl);
3933 return NULL;
3937 rc = InternetOpenUrlW(hInternet, szUrl, headers, dwHeadersLength, dwFlags, dwContext);
3939 free(szUrl);
3940 free(headers);
3941 return rc;
3945 static LPWITHREADERROR INTERNET_AllocThreadError(void)
3947 WITHREADERROR *lpwite = malloc(sizeof(*lpwite));
3949 if (lpwite)
3951 lpwite->dwError = 0;
3952 lpwite->response[0] = '\0';
3955 if (!TlsSetValue(g_dwTlsErrIndex, lpwite))
3957 free(lpwite);
3958 return NULL;
3960 return lpwite;
3964 /***********************************************************************
3965 * INTERNET_SetLastError (internal)
3967 * Set last thread specific error
3969 * RETURNS
3972 void INTERNET_SetLastError(DWORD dwError)
3974 LPWITHREADERROR lpwite = TlsGetValue(g_dwTlsErrIndex);
3976 if (!lpwite)
3977 lpwite = INTERNET_AllocThreadError();
3979 SetLastError(dwError);
3980 if(lpwite)
3981 lpwite->dwError = dwError;
3985 /***********************************************************************
3986 * INTERNET_GetLastError (internal)
3988 * Get last thread specific error
3990 * RETURNS
3993 DWORD INTERNET_GetLastError(void)
3995 LPWITHREADERROR lpwite = TlsGetValue(g_dwTlsErrIndex);
3996 if (!lpwite) return 0;
3997 /* TlsGetValue clears last error, so set it again here */
3998 SetLastError(lpwite->dwError);
3999 return lpwite->dwError;
4003 /***********************************************************************
4004 * INTERNET_WorkerThreadFunc (internal)
4006 * Worker thread execution function
4008 * RETURNS
4011 static DWORD CALLBACK INTERNET_WorkerThreadFunc(LPVOID lpvParam)
4013 task_header_t *task = lpvParam;
4015 TRACE("\n");
4017 task->proc(task);
4018 WININET_Release(task->hdr);
4019 free(task);
4021 if (g_dwTlsErrIndex != TLS_OUT_OF_INDEXES)
4023 free(TlsGetValue(g_dwTlsErrIndex));
4024 TlsSetValue(g_dwTlsErrIndex, NULL);
4026 return TRUE;
4029 void *alloc_async_task(object_header_t *hdr, async_task_proc_t proc, size_t size)
4031 task_header_t *task;
4033 task = malloc(size);
4034 if(!task)
4035 return NULL;
4037 task->hdr = WININET_AddRef(hdr);
4038 task->proc = proc;
4039 return task;
4042 /***********************************************************************
4043 * INTERNET_AsyncCall (internal)
4045 * Retrieves work request from queue
4047 * RETURNS
4050 DWORD INTERNET_AsyncCall(task_header_t *task)
4052 BOOL bSuccess;
4054 TRACE("\n");
4056 bSuccess = QueueUserWorkItem(INTERNET_WorkerThreadFunc, task, WT_EXECUTELONGFUNCTION);
4057 if (!bSuccess)
4059 free(task);
4060 return ERROR_INTERNET_ASYNC_THREAD_FAILED;
4062 return ERROR_SUCCESS;
4066 /***********************************************************************
4067 * INTERNET_GetResponseBuffer (internal)
4069 * RETURNS
4072 LPSTR INTERNET_GetResponseBuffer(void)
4074 LPWITHREADERROR lpwite = TlsGetValue(g_dwTlsErrIndex);
4075 if (!lpwite)
4076 lpwite = INTERNET_AllocThreadError();
4077 TRACE("\n");
4078 return lpwite->response;
4081 /**********************************************************
4082 * InternetQueryDataAvailable (WININET.@)
4084 * Determines how much data is available to be read.
4086 * RETURNS
4087 * TRUE on success, FALSE if an error occurred. If
4088 * INTERNET_FLAG_ASYNC was specified in InternetOpen, and
4089 * no data is presently available, FALSE is returned with
4090 * the last error ERROR_IO_PENDING; a callback with status
4091 * INTERNET_STATUS_REQUEST_COMPLETE will be sent when more
4092 * data is available.
4094 BOOL WINAPI InternetQueryDataAvailable( HINTERNET hFile,
4095 LPDWORD lpdwNumberOfBytesAvailable,
4096 DWORD dwFlags, DWORD_PTR dwContext)
4098 object_header_t *hdr;
4099 DWORD res;
4101 TRACE("(%p %p %lx %Ix)\n", hFile, lpdwNumberOfBytesAvailable, dwFlags, dwContext);
4103 hdr = get_handle_object( hFile );
4104 if (!hdr) {
4105 SetLastError(ERROR_INVALID_HANDLE);
4106 return FALSE;
4109 if(hdr->vtbl->QueryDataAvailable) {
4110 res = hdr->vtbl->QueryDataAvailable(hdr, lpdwNumberOfBytesAvailable, dwFlags, dwContext);
4111 }else {
4112 WARN("wrong handle\n");
4113 res = ERROR_INTERNET_INCORRECT_HANDLE_TYPE;
4116 WININET_Release(hdr);
4118 if(res != ERROR_SUCCESS)
4119 SetLastError(res);
4120 return res == ERROR_SUCCESS;
4123 DWORD create_req_file(const WCHAR *file_name, req_file_t **ret)
4125 req_file_t *req_file;
4127 req_file = calloc(1, sizeof(*req_file));
4128 if(!req_file)
4129 return ERROR_NOT_ENOUGH_MEMORY;
4131 req_file->ref = 1;
4133 req_file->file_name = wcsdup(file_name);
4134 if(!req_file->file_name) {
4135 free(req_file);
4136 return ERROR_NOT_ENOUGH_MEMORY;
4139 req_file->file_handle = CreateFileW(req_file->file_name, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE,
4140 NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
4141 if(req_file->file_handle == INVALID_HANDLE_VALUE) {
4142 req_file_release(req_file);
4143 return GetLastError();
4146 *ret = req_file;
4147 return ERROR_SUCCESS;
4150 void req_file_release(req_file_t *req_file)
4152 if(InterlockedDecrement(&req_file->ref))
4153 return;
4155 if(!req_file->is_committed)
4156 DeleteFileW(req_file->file_name);
4157 if(req_file->file_handle && req_file->file_handle != INVALID_HANDLE_VALUE)
4158 CloseHandle(req_file->file_handle);
4159 free(req_file->file_name);
4160 free(req_file->url);
4161 free(req_file);
4164 /***********************************************************************
4165 * InternetLockRequestFile (WININET.@)
4167 BOOL WINAPI InternetLockRequestFile(HINTERNET hInternet, HANDLE *lphLockReqHandle)
4169 req_file_t *req_file = NULL;
4170 object_header_t *hdr;
4171 DWORD res;
4173 TRACE("(%p %p)\n", hInternet, lphLockReqHandle);
4175 hdr = get_handle_object(hInternet);
4176 if (!hdr) {
4177 SetLastError(ERROR_INVALID_HANDLE);
4178 return FALSE;
4181 if(hdr->vtbl->LockRequestFile) {
4182 res = hdr->vtbl->LockRequestFile(hdr, &req_file);
4183 }else {
4184 WARN("wrong handle\n");
4185 res = ERROR_INTERNET_INCORRECT_HANDLE_TYPE;
4188 WININET_Release(hdr);
4190 *lphLockReqHandle = req_file;
4191 if(res != ERROR_SUCCESS)
4192 SetLastError(res);
4193 return res == ERROR_SUCCESS;
4196 BOOL WINAPI InternetUnlockRequestFile(HANDLE hLockHandle)
4198 TRACE("(%p)\n", hLockHandle);
4200 req_file_release(hLockHandle);
4201 return TRUE;
4205 /***********************************************************************
4206 * InternetAutodial (WININET.@)
4208 * On windows this function is supposed to dial the default internet
4209 * connection. We don't want to have Wine dial out to the internet so
4210 * we return TRUE by default. It might be nice to check if we are connected.
4212 * RETURNS
4213 * TRUE on success
4214 * FALSE on failure
4217 BOOL WINAPI InternetAutodial(DWORD dwFlags, HWND hwndParent)
4219 FIXME("STUB\n");
4221 /* Tell that we are connected to the internet. */
4222 return TRUE;
4225 /***********************************************************************
4226 * InternetAutodialHangup (WININET.@)
4228 * Hangs up a connection made with InternetAutodial
4230 * PARAM
4231 * dwReserved
4232 * RETURNS
4233 * TRUE on success
4234 * FALSE on failure
4237 BOOL WINAPI InternetAutodialHangup(DWORD dwReserved)
4239 FIXME("STUB\n");
4241 /* we didn't dial, we don't disconnect */
4242 return TRUE;
4245 /***********************************************************************
4246 * InternetCombineUrlA (WININET.@)
4248 * Combine a base URL with a relative URL
4250 * RETURNS
4251 * TRUE on success
4252 * FALSE on failure
4256 BOOL WINAPI InternetCombineUrlA(LPCSTR lpszBaseUrl, LPCSTR lpszRelativeUrl,
4257 LPSTR lpszBuffer, LPDWORD lpdwBufferLength,
4258 DWORD dwFlags)
4260 HRESULT hr=S_OK;
4262 TRACE("(%s, %s, %p, %p, 0x%08lx)\n", debugstr_a(lpszBaseUrl), debugstr_a(lpszRelativeUrl), lpszBuffer, lpdwBufferLength, dwFlags);
4264 /* Flip this bit to correspond to URL_ESCAPE_UNSAFE */
4265 dwFlags ^= ICU_NO_ENCODE;
4266 hr=UrlCombineA(lpszBaseUrl,lpszRelativeUrl,lpszBuffer,lpdwBufferLength,dwFlags);
4268 return (hr==S_OK);
4271 /***********************************************************************
4272 * InternetCombineUrlW (WININET.@)
4274 * Combine a base URL with a relative URL
4276 * RETURNS
4277 * TRUE on success
4278 * FALSE on failure
4282 BOOL WINAPI InternetCombineUrlW(LPCWSTR lpszBaseUrl, LPCWSTR lpszRelativeUrl,
4283 LPWSTR lpszBuffer, LPDWORD lpdwBufferLength,
4284 DWORD dwFlags)
4286 HRESULT hr=S_OK;
4288 TRACE("(%s, %s, %p, %p, 0x%08lx)\n", debugstr_w(lpszBaseUrl), debugstr_w(lpszRelativeUrl), lpszBuffer, lpdwBufferLength, dwFlags);
4290 /* Flip this bit to correspond to URL_ESCAPE_UNSAFE */
4291 dwFlags ^= ICU_NO_ENCODE;
4292 hr=UrlCombineW(lpszBaseUrl,lpszRelativeUrl,lpszBuffer,lpdwBufferLength,dwFlags);
4294 return (hr==S_OK);
4297 /* max port num is 65535 => 5 digits */
4298 #define MAX_WORD_DIGITS 5
4300 #define URL_GET_COMP_LENGTH(url, component) ((url)->dw##component##Length ? \
4301 (url)->dw##component##Length : lstrlenW((url)->lpsz##component))
4302 #define URL_GET_COMP_LENGTHA(url, component) ((url)->dw##component##Length ? \
4303 (url)->dw##component##Length : strlen((url)->lpsz##component))
4305 static BOOL url_uses_default_port(INTERNET_SCHEME nScheme, INTERNET_PORT nPort)
4307 if ((nScheme == INTERNET_SCHEME_HTTP) &&
4308 (nPort == INTERNET_DEFAULT_HTTP_PORT))
4309 return TRUE;
4310 if ((nScheme == INTERNET_SCHEME_HTTPS) &&
4311 (nPort == INTERNET_DEFAULT_HTTPS_PORT))
4312 return TRUE;
4313 if ((nScheme == INTERNET_SCHEME_FTP) &&
4314 (nPort == INTERNET_DEFAULT_FTP_PORT))
4315 return TRUE;
4316 if ((nScheme == INTERNET_SCHEME_GOPHER) &&
4317 (nPort == INTERNET_DEFAULT_GOPHER_PORT))
4318 return TRUE;
4320 if (nPort == INTERNET_INVALID_PORT_NUMBER)
4321 return TRUE;
4323 return FALSE;
4326 /* opaque urls do not fit into the standard url hierarchy and don't have
4327 * two following slashes */
4328 static inline BOOL scheme_is_opaque(INTERNET_SCHEME nScheme)
4330 return (nScheme != INTERNET_SCHEME_FTP) &&
4331 (nScheme != INTERNET_SCHEME_GOPHER) &&
4332 (nScheme != INTERNET_SCHEME_HTTP) &&
4333 (nScheme != INTERNET_SCHEME_HTTPS) &&
4334 (nScheme != INTERNET_SCHEME_FILE);
4337 static LPCWSTR INTERNET_GetSchemeString(INTERNET_SCHEME scheme)
4339 int index;
4340 if (scheme < INTERNET_SCHEME_FIRST)
4341 return NULL;
4342 index = scheme - INTERNET_SCHEME_FIRST;
4343 if (index >= ARRAY_SIZE(url_schemes))
4344 return NULL;
4345 return url_schemes[index];
4348 /* we can calculate using ansi strings because we're just
4349 * calculating string length, not size
4351 static BOOL calc_url_length(LPURL_COMPONENTSW lpUrlComponents,
4352 LPDWORD lpdwUrlLength)
4354 INTERNET_SCHEME nScheme;
4356 *lpdwUrlLength = 0;
4358 if (lpUrlComponents->lpszScheme)
4360 DWORD dwLen = URL_GET_COMP_LENGTH(lpUrlComponents, Scheme);
4361 *lpdwUrlLength += dwLen;
4362 nScheme = GetInternetSchemeW(lpUrlComponents->lpszScheme, dwLen);
4364 else
4366 LPCWSTR scheme;
4368 nScheme = lpUrlComponents->nScheme;
4370 if (nScheme == INTERNET_SCHEME_DEFAULT)
4371 nScheme = INTERNET_SCHEME_HTTP;
4372 scheme = INTERNET_GetSchemeString(nScheme);
4373 *lpdwUrlLength += lstrlenW(scheme);
4376 (*lpdwUrlLength)++; /* ':' */
4377 if (!scheme_is_opaque(nScheme) || lpUrlComponents->lpszHostName)
4378 *lpdwUrlLength += strlen("//");
4380 if (lpUrlComponents->lpszUserName)
4382 *lpdwUrlLength += URL_GET_COMP_LENGTH(lpUrlComponents, UserName);
4383 *lpdwUrlLength += strlen("@");
4385 else
4387 if (lpUrlComponents->lpszPassword)
4389 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
4390 return FALSE;
4394 if (lpUrlComponents->lpszPassword)
4396 *lpdwUrlLength += strlen(":");
4397 *lpdwUrlLength += URL_GET_COMP_LENGTH(lpUrlComponents, Password);
4400 if (lpUrlComponents->lpszHostName)
4402 *lpdwUrlLength += URL_GET_COMP_LENGTH(lpUrlComponents, HostName);
4404 if (!url_uses_default_port(nScheme, lpUrlComponents->nPort))
4406 WCHAR port[MAX_WORD_DIGITS + 1];
4408 _ltow(lpUrlComponents->nPort, port, 10);
4409 *lpdwUrlLength += lstrlenW(port);
4410 *lpdwUrlLength += strlen(":");
4413 if (lpUrlComponents->lpszUrlPath && *lpUrlComponents->lpszUrlPath != '/')
4414 (*lpdwUrlLength)++; /* '/' */
4417 if (lpUrlComponents->lpszUrlPath)
4418 *lpdwUrlLength += URL_GET_COMP_LENGTH(lpUrlComponents, UrlPath);
4420 if (lpUrlComponents->lpszExtraInfo)
4421 *lpdwUrlLength += URL_GET_COMP_LENGTH(lpUrlComponents, ExtraInfo);
4423 return TRUE;
4426 static void convert_urlcomp_atow(LPURL_COMPONENTSA lpUrlComponents, LPURL_COMPONENTSW urlCompW)
4428 INT len;
4430 ZeroMemory(urlCompW, sizeof(URL_COMPONENTSW));
4432 urlCompW->dwStructSize = sizeof(URL_COMPONENTSW);
4433 urlCompW->dwSchemeLength = lpUrlComponents->dwSchemeLength;
4434 urlCompW->nScheme = lpUrlComponents->nScheme;
4435 urlCompW->dwHostNameLength = lpUrlComponents->dwHostNameLength;
4436 urlCompW->nPort = lpUrlComponents->nPort;
4437 urlCompW->dwUserNameLength = lpUrlComponents->dwUserNameLength;
4438 urlCompW->dwPasswordLength = lpUrlComponents->dwPasswordLength;
4439 urlCompW->dwUrlPathLength = lpUrlComponents->dwUrlPathLength;
4440 urlCompW->dwExtraInfoLength = lpUrlComponents->dwExtraInfoLength;
4442 if (lpUrlComponents->lpszScheme)
4444 len = URL_GET_COMP_LENGTHA(lpUrlComponents, Scheme) + 1;
4445 urlCompW->lpszScheme = malloc(len * sizeof(WCHAR));
4446 MultiByteToWideChar(CP_ACP, 0, lpUrlComponents->lpszScheme,
4447 -1, urlCompW->lpszScheme, len);
4450 if (lpUrlComponents->lpszHostName)
4452 len = URL_GET_COMP_LENGTHA(lpUrlComponents, HostName) + 1;
4453 urlCompW->lpszHostName = malloc(len * sizeof(WCHAR));
4454 MultiByteToWideChar(CP_ACP, 0, lpUrlComponents->lpszHostName,
4455 -1, urlCompW->lpszHostName, len);
4458 if (lpUrlComponents->lpszUserName)
4460 len = URL_GET_COMP_LENGTHA(lpUrlComponents, UserName) + 1;
4461 urlCompW->lpszUserName = malloc(len * sizeof(WCHAR));
4462 MultiByteToWideChar(CP_ACP, 0, lpUrlComponents->lpszUserName,
4463 -1, urlCompW->lpszUserName, len);
4466 if (lpUrlComponents->lpszPassword)
4468 len = URL_GET_COMP_LENGTHA(lpUrlComponents, Password) + 1;
4469 urlCompW->lpszPassword = malloc(len * sizeof(WCHAR));
4470 MultiByteToWideChar(CP_ACP, 0, lpUrlComponents->lpszPassword,
4471 -1, urlCompW->lpszPassword, len);
4474 if (lpUrlComponents->lpszUrlPath)
4476 len = URL_GET_COMP_LENGTHA(lpUrlComponents, UrlPath) + 1;
4477 urlCompW->lpszUrlPath = malloc(len * sizeof(WCHAR));
4478 MultiByteToWideChar(CP_ACP, 0, lpUrlComponents->lpszUrlPath,
4479 -1, urlCompW->lpszUrlPath, len);
4482 if (lpUrlComponents->lpszExtraInfo)
4484 len = URL_GET_COMP_LENGTHA(lpUrlComponents, ExtraInfo) + 1;
4485 urlCompW->lpszExtraInfo = malloc(len * sizeof(WCHAR));
4486 MultiByteToWideChar(CP_ACP, 0, lpUrlComponents->lpszExtraInfo,
4487 -1, urlCompW->lpszExtraInfo, len);
4491 /***********************************************************************
4492 * InternetCreateUrlA (WININET.@)
4494 * See InternetCreateUrlW.
4496 BOOL WINAPI InternetCreateUrlA(LPURL_COMPONENTSA lpUrlComponents, DWORD dwFlags,
4497 LPSTR lpszUrl, LPDWORD lpdwUrlLength)
4499 BOOL ret;
4500 LPWSTR urlW = NULL;
4501 URL_COMPONENTSW urlCompW;
4503 TRACE("(%p,%ld,%p,%p)\n", lpUrlComponents, dwFlags, lpszUrl, lpdwUrlLength);
4505 if (!lpUrlComponents || lpUrlComponents->dwStructSize != sizeof(URL_COMPONENTSW) || !lpdwUrlLength)
4507 SetLastError(ERROR_INVALID_PARAMETER);
4508 return FALSE;
4511 convert_urlcomp_atow(lpUrlComponents, &urlCompW);
4513 if (lpszUrl)
4514 urlW = malloc(*lpdwUrlLength * sizeof(WCHAR));
4516 ret = InternetCreateUrlW(&urlCompW, dwFlags, urlW, lpdwUrlLength);
4518 if (!ret && (GetLastError() == ERROR_INSUFFICIENT_BUFFER))
4519 *lpdwUrlLength /= sizeof(WCHAR);
4521 /* on success, lpdwUrlLength points to the size of urlW in WCHARS
4522 * minus one, so add one to leave room for NULL terminator
4524 if (ret)
4525 WideCharToMultiByte(CP_ACP, 0, urlW, -1, lpszUrl, *lpdwUrlLength + 1, NULL, NULL);
4527 free(urlCompW.lpszScheme);
4528 free(urlCompW.lpszHostName);
4529 free(urlCompW.lpszUserName);
4530 free(urlCompW.lpszPassword);
4531 free(urlCompW.lpszUrlPath);
4532 free(urlCompW.lpszExtraInfo);
4533 free(urlW);
4534 return ret;
4537 /***********************************************************************
4538 * InternetCreateUrlW (WININET.@)
4540 * Creates a URL from its component parts.
4542 * PARAMS
4543 * lpUrlComponents [I] URL Components.
4544 * dwFlags [I] Flags. See notes.
4545 * lpszUrl [I] Buffer in which to store the created URL.
4546 * lpdwUrlLength [I/O] On input, the length of the buffer pointed to by
4547 * lpszUrl in characters. On output, the number of bytes
4548 * required to store the URL including terminator.
4550 * NOTES
4552 * The dwFlags parameter can be zero or more of the following:
4553 *|ICU_ESCAPE - Generates escape sequences for unsafe characters in the path and extra info of the URL.
4555 * RETURNS
4556 * TRUE on success
4557 * FALSE on failure
4560 BOOL WINAPI InternetCreateUrlW(LPURL_COMPONENTSW lpUrlComponents, DWORD dwFlags,
4561 LPWSTR lpszUrl, LPDWORD lpdwUrlLength)
4563 DWORD dwLen;
4564 INTERNET_SCHEME nScheme;
4566 static const WCHAR slashSlashW[] = {'/','/'};
4568 TRACE("(%p,%ld,%p,%p)\n", lpUrlComponents, dwFlags, lpszUrl, lpdwUrlLength);
4570 if (!lpUrlComponents || lpUrlComponents->dwStructSize != sizeof(URL_COMPONENTSW) || !lpdwUrlLength)
4572 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
4573 return FALSE;
4576 if (!calc_url_length(lpUrlComponents, &dwLen))
4577 return FALSE;
4579 if (!lpszUrl || *lpdwUrlLength < dwLen)
4581 *lpdwUrlLength = (dwLen + 1) * sizeof(WCHAR);
4582 INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
4583 return FALSE;
4586 *lpdwUrlLength = dwLen;
4587 lpszUrl[0] = 0x00;
4589 dwLen = 0;
4591 if (lpUrlComponents->lpszScheme)
4593 dwLen = URL_GET_COMP_LENGTH(lpUrlComponents, Scheme);
4594 memcpy(lpszUrl, lpUrlComponents->lpszScheme, dwLen * sizeof(WCHAR));
4595 lpszUrl += dwLen;
4597 nScheme = GetInternetSchemeW(lpUrlComponents->lpszScheme, dwLen);
4599 else
4601 LPCWSTR scheme;
4602 nScheme = lpUrlComponents->nScheme;
4604 if (nScheme == INTERNET_SCHEME_DEFAULT)
4605 nScheme = INTERNET_SCHEME_HTTP;
4607 scheme = INTERNET_GetSchemeString(nScheme);
4608 dwLen = lstrlenW(scheme);
4609 memcpy(lpszUrl, scheme, dwLen * sizeof(WCHAR));
4610 lpszUrl += dwLen;
4613 /* all schemes are followed by at least a colon */
4614 *lpszUrl = ':';
4615 lpszUrl++;
4617 if (!scheme_is_opaque(nScheme) || lpUrlComponents->lpszHostName)
4619 memcpy(lpszUrl, slashSlashW, sizeof(slashSlashW));
4620 lpszUrl += ARRAY_SIZE(slashSlashW);
4623 if (lpUrlComponents->lpszUserName)
4625 dwLen = URL_GET_COMP_LENGTH(lpUrlComponents, UserName);
4626 memcpy(lpszUrl, lpUrlComponents->lpszUserName, dwLen * sizeof(WCHAR));
4627 lpszUrl += dwLen;
4629 if (lpUrlComponents->lpszPassword)
4631 *lpszUrl = ':';
4632 lpszUrl++;
4634 dwLen = URL_GET_COMP_LENGTH(lpUrlComponents, Password);
4635 memcpy(lpszUrl, lpUrlComponents->lpszPassword, dwLen * sizeof(WCHAR));
4636 lpszUrl += dwLen;
4639 *lpszUrl = '@';
4640 lpszUrl++;
4643 if (lpUrlComponents->lpszHostName)
4645 dwLen = URL_GET_COMP_LENGTH(lpUrlComponents, HostName);
4646 memcpy(lpszUrl, lpUrlComponents->lpszHostName, dwLen * sizeof(WCHAR));
4647 lpszUrl += dwLen;
4649 if (!url_uses_default_port(nScheme, lpUrlComponents->nPort))
4651 *lpszUrl++ = ':';
4652 _ltow(lpUrlComponents->nPort, lpszUrl, 10);
4653 lpszUrl += lstrlenW(lpszUrl);
4656 /* add slash between hostname and path if necessary */
4657 if (lpUrlComponents->lpszUrlPath && *lpUrlComponents->lpszUrlPath != '/')
4659 *lpszUrl = '/';
4660 lpszUrl++;
4664 if (lpUrlComponents->lpszUrlPath)
4666 dwLen = URL_GET_COMP_LENGTH(lpUrlComponents, UrlPath);
4667 memcpy(lpszUrl, lpUrlComponents->lpszUrlPath, dwLen * sizeof(WCHAR));
4668 lpszUrl += dwLen;
4671 if (lpUrlComponents->lpszExtraInfo)
4673 dwLen = URL_GET_COMP_LENGTH(lpUrlComponents, ExtraInfo);
4674 memcpy(lpszUrl, lpUrlComponents->lpszExtraInfo, dwLen * sizeof(WCHAR));
4675 lpszUrl += dwLen;
4678 *lpszUrl = '\0';
4680 return TRUE;
4683 /***********************************************************************
4684 * InternetConfirmZoneCrossingA (WININET.@)
4687 DWORD WINAPI InternetConfirmZoneCrossingA( HWND hWnd, LPSTR szUrlPrev, LPSTR szUrlNew, BOOL bPost )
4689 FIXME("(%p, %s, %s, %x) stub\n", hWnd, debugstr_a(szUrlPrev), debugstr_a(szUrlNew), bPost);
4690 return ERROR_SUCCESS;
4693 /***********************************************************************
4694 * InternetConfirmZoneCrossingW (WININET.@)
4697 DWORD WINAPI InternetConfirmZoneCrossingW( HWND hWnd, LPWSTR szUrlPrev, LPWSTR szUrlNew, BOOL bPost )
4699 FIXME("(%p, %s, %s, %x) stub\n", hWnd, debugstr_w(szUrlPrev), debugstr_w(szUrlNew), bPost);
4700 return ERROR_SUCCESS;
4703 static DWORD zone_preference = 3;
4705 /***********************************************************************
4706 * PrivacySetZonePreferenceW (WININET.@)
4708 DWORD WINAPI PrivacySetZonePreferenceW( DWORD zone, DWORD type, DWORD template, LPCWSTR preference )
4710 FIXME( "%lx %lx %lx %s: stub\n", zone, type, template, debugstr_w(preference) );
4712 zone_preference = template;
4713 return 0;
4716 /***********************************************************************
4717 * PrivacyGetZonePreferenceW (WININET.@)
4719 DWORD WINAPI PrivacyGetZonePreferenceW( DWORD zone, DWORD type, LPDWORD template,
4720 LPWSTR preference, LPDWORD length )
4722 FIXME( "%lx %lx %p %p %p: stub\n", zone, type, template, preference, length );
4724 if (template) *template = zone_preference;
4725 return 0;
4728 /***********************************************************************
4729 * InternetGetSecurityInfoByURLA (WININET.@)
4731 BOOL WINAPI InternetGetSecurityInfoByURLA(LPSTR lpszURL, PCCERT_CHAIN_CONTEXT *ppCertChain, DWORD *pdwSecureFlags)
4733 WCHAR *url;
4734 BOOL res;
4736 TRACE("(%s %p %p)\n", debugstr_a(lpszURL), ppCertChain, pdwSecureFlags);
4738 url = strdupAtoW(lpszURL);
4739 if(!url)
4740 return FALSE;
4742 res = InternetGetSecurityInfoByURLW(url, ppCertChain, pdwSecureFlags);
4743 free(url);
4744 return res;
4747 /***********************************************************************
4748 * InternetGetSecurityInfoByURLW (WININET.@)
4750 BOOL WINAPI InternetGetSecurityInfoByURLW(LPCWSTR lpszURL, PCCERT_CHAIN_CONTEXT *ppCertChain, DWORD *pdwSecureFlags)
4752 URL_COMPONENTSW url = {sizeof(url)};
4753 server_t *server;
4754 BOOL res;
4756 TRACE("(%s %p %p)\n", debugstr_w(lpszURL), ppCertChain, pdwSecureFlags);
4758 if (!ppCertChain && !pdwSecureFlags) {
4759 SetLastError(ERROR_INVALID_PARAMETER);
4760 return FALSE;
4763 url.dwHostNameLength = 1;
4764 res = InternetCrackUrlW(lpszURL, 0, 0, &url);
4765 if(!res || url.nScheme != INTERNET_SCHEME_HTTPS) {
4766 SetLastError(ERROR_INTERNET_ITEM_NOT_FOUND);
4767 return FALSE;
4770 server = get_server(substr(url.lpszHostName, url.dwHostNameLength), url.nPort, TRUE, FALSE);
4771 if(!server) {
4772 SetLastError(ERROR_INTERNET_ITEM_NOT_FOUND);
4773 return FALSE;
4776 if(server->cert_chain) {
4777 if(pdwSecureFlags)
4778 *pdwSecureFlags = server->security_flags & _SECURITY_ERROR_FLAGS_MASK;
4780 if(ppCertChain && !(*ppCertChain = CertDuplicateCertificateChain(server->cert_chain)))
4781 res = FALSE;
4782 }else {
4783 SetLastError(ERROR_INTERNET_ITEM_NOT_FOUND);
4784 res = FALSE;
4787 server_release(server);
4788 return res;
4791 DWORD WINAPI InternetDialA( HWND hwndParent, LPSTR lpszConnectoid, DWORD dwFlags,
4792 DWORD_PTR* lpdwConnection, DWORD dwReserved )
4794 FIXME("(%p, %p, 0x%08lx, %p, 0x%08lx) stub\n", hwndParent, lpszConnectoid, dwFlags,
4795 lpdwConnection, dwReserved);
4796 return ERROR_SUCCESS;
4799 DWORD WINAPI InternetDialW( HWND hwndParent, LPWSTR lpszConnectoid, DWORD dwFlags,
4800 DWORD_PTR* lpdwConnection, DWORD dwReserved )
4802 FIXME("(%p, %p, 0x%08lx, %p, 0x%08lx) stub\n", hwndParent, lpszConnectoid, dwFlags,
4803 lpdwConnection, dwReserved);
4804 return ERROR_SUCCESS;
4807 BOOL WINAPI InternetGoOnlineA( LPSTR lpszURL, HWND hwndParent, DWORD dwReserved )
4809 FIXME("(%s, %p, 0x%08lx) stub\n", debugstr_a(lpszURL), hwndParent, dwReserved);
4810 return TRUE;
4813 BOOL WINAPI InternetGoOnlineW( LPWSTR lpszURL, HWND hwndParent, DWORD dwReserved )
4815 FIXME("(%s, %p, 0x%08lx) stub\n", debugstr_w(lpszURL), hwndParent, dwReserved);
4816 return TRUE;
4819 DWORD WINAPI InternetHangUp( DWORD_PTR dwConnection, DWORD dwReserved )
4821 FIXME("(0x%08Ix, 0x%08lx) stub\n", dwConnection, dwReserved);
4822 return ERROR_SUCCESS;
4825 BOOL WINAPI CreateMD5SSOHash( PWSTR pszChallengeInfo, PWSTR pwszRealm, PWSTR pwszTarget,
4826 PBYTE pbHexHash )
4828 FIXME("(%s, %s, %s, %p) stub\n", debugstr_w(pszChallengeInfo), debugstr_w(pwszRealm),
4829 debugstr_w(pwszTarget), pbHexHash);
4830 return FALSE;
4833 BOOL WINAPI ResumeSuspendedDownload( HINTERNET hInternet, DWORD dwError )
4835 FIXME("(%p, 0x%08lx) stub\n", hInternet, dwError);
4836 return FALSE;
4839 BOOL WINAPI InternetQueryFortezzaStatus(DWORD *a, DWORD_PTR b)
4841 FIXME("(%p, %08Ix) stub\n", a, b);
4842 return FALSE;
4845 DWORD WINAPI ShowClientAuthCerts(HWND parent)
4847 FIXME("%p: stub\n", parent);
4848 return 0;