xref: /reactos/dll/win32/wininet/internet.c (revision 58aee30e)
1 /*
2  * Wininet
3  *
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
9  *
10  * Ulrich Czekalla
11  * Aric Stewart
12  * David Hammerton
13  *
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.
18  *
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.
23  *
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
27  */
28 
29 #include "config.h"
30 
31 #ifdef HAVE_CORESERVICES_CORESERVICES_H
32 #define GetCurrentThread MacGetCurrentThread
33 #define LoadResource MacLoadResource
34 #include <CoreServices/CoreServices.h>
35 #undef GetCurrentThread
36 #undef LoadResource
37 #undef DPRINTF
38 #endif
39 
40 #include "winsock2.h"
41 #include "ws2ipdef.h"
42 
43 #include <string.h>
44 #include <stdarg.h>
45 #include <stdio.h>
46 #include <stdlib.h>
47 #include <ctype.h>
48 #include <assert.h>
49 
50 #include "windef.h"
51 #include "winbase.h"
52 #include "winreg.h"
53 #include "winuser.h"
54 #include "wininet.h"
55 #include "winnls.h"
56 #include "wine/debug.h"
57 #include "winerror.h"
58 #define NO_SHLWAPI_STREAM
59 #include "shlwapi.h"
60 
61 #include "wine/exception.h"
62 
63 #include "internet.h"
64 #include "resource.h"
65 
66 #include "wine/unicode.h"
67 
68 WINE_DEFAULT_DEBUG_CHANNEL(wininet);
69 
70 typedef struct
71 {
72     DWORD  dwError;
73     CHAR   response[MAX_REPLY_LEN];
74 } WITHREADERROR, *LPWITHREADERROR;
75 
76 static DWORD g_dwTlsErrIndex = TLS_OUT_OF_INDEXES;
77 HMODULE WININET_hModule;
78 
79 static CRITICAL_SECTION WININET_cs;
80 static CRITICAL_SECTION_DEBUG WININET_cs_debug =
81 {
82     0, 0, &WININET_cs,
83     { &WININET_cs_debug.ProcessLocksList, &WININET_cs_debug.ProcessLocksList },
84       0, 0, { (DWORD_PTR)(__FILE__ ": WININET_cs") }
85 };
86 static CRITICAL_SECTION WININET_cs = { &WININET_cs_debug, -1, 0, 0, 0, 0 };
87 
88 static object_header_t **handle_table;
89 static UINT_PTR next_handle;
90 static UINT_PTR handle_table_size;
91 
92 typedef struct
93 {
94     DWORD  proxyEnabled;
95     LPWSTR proxy;
96     LPWSTR proxyBypass;
97     LPWSTR proxyUsername;
98     LPWSTR proxyPassword;
99 } proxyinfo_t;
100 
101 static ULONG max_conns = 2, max_1_0_conns = 4;
102 static ULONG connect_timeout = 60000;
103 
104 static const WCHAR szInternetSettings[] =
105     { 'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
106       'W','i','n','d','o','w','s','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
107       'I','n','t','e','r','n','e','t',' ','S','e','t','t','i','n','g','s',0 };
108 static const WCHAR szProxyServer[] = { 'P','r','o','x','y','S','e','r','v','e','r', 0 };
109 static const WCHAR szProxyEnable[] = { 'P','r','o','x','y','E','n','a','b','l','e', 0 };
110 static const WCHAR szProxyOverride[] = { 'P','r','o','x','y','O','v','e','r','r','i','d','e', 0 };
111 
112 void *alloc_object(object_header_t *parent, const object_vtbl_t *vtbl, size_t size)
113 {
114     UINT_PTR handle = 0, num;
115     object_header_t *ret;
116     object_header_t **p;
117     BOOL res = TRUE;
118 
119     ret = heap_alloc_zero(size);
120     if(!ret)
121         return NULL;
122 
123     list_init(&ret->children);
124 
125     EnterCriticalSection( &WININET_cs );
126 
127     if(!handle_table_size) {
128         num = 16;
129         p = heap_alloc_zero(sizeof(handle_table[0]) * num);
130         if(p) {
131             handle_table = p;
132             handle_table_size = num;
133             next_handle = 1;
134         }else {
135             res = FALSE;
136         }
137     }else if(next_handle == handle_table_size) {
138         num = handle_table_size * 2;
139         p = heap_realloc_zero(handle_table, sizeof(handle_table[0]) * num);
140         if(p) {
141             handle_table = p;
142             handle_table_size = num;
143         }else {
144             res = FALSE;
145         }
146     }
147 
148     if(res) {
149         handle = next_handle;
150         if(handle_table[handle])
151             ERR("handle isn't free but should be\n");
152         handle_table[handle] = ret;
153         ret->valid_handle = TRUE;
154 
155         while(next_handle < handle_table_size && handle_table[next_handle])
156             next_handle++;
157     }
158 
159     LeaveCriticalSection( &WININET_cs );
160 
161     if(!res) {
162         heap_free(ret);
163         return NULL;
164     }
165 
166     ret->vtbl = vtbl;
167     ret->refs = 1;
168     ret->hInternet = (HINTERNET)handle;
169 
170     if(parent) {
171         ret->lpfnStatusCB = parent->lpfnStatusCB;
172         ret->dwInternalFlags = parent->dwInternalFlags & INET_CALLBACKW;
173     }
174 
175     return ret;
176 }
177 
178 object_header_t *WININET_AddRef( object_header_t *info )
179 {
180     ULONG refs = InterlockedIncrement(&info->refs);
181     TRACE("%p -> refcount = %d\n", info, refs );
182     return info;
183 }
184 
185 object_header_t *get_handle_object( HINTERNET hinternet )
186 {
187     object_header_t *info = NULL;
188     UINT_PTR handle = (UINT_PTR) hinternet;
189 
190     EnterCriticalSection( &WININET_cs );
191 
192     if(handle > 0 && handle < handle_table_size && handle_table[handle] && handle_table[handle]->valid_handle)
193         info = WININET_AddRef(handle_table[handle]);
194 
195     LeaveCriticalSection( &WININET_cs );
196 
197     TRACE("handle %ld -> %p\n", handle, info);
198 
199     return info;
200 }
201 
202 static void invalidate_handle(object_header_t *info)
203 {
204     object_header_t *child, *next;
205 
206     if(!info->valid_handle)
207         return;
208     info->valid_handle = FALSE;
209 
210     /* Free all children as native does */
211     LIST_FOR_EACH_ENTRY_SAFE( child, next, &info->children, object_header_t, entry )
212     {
213         TRACE("invalidating child handle %p for parent %p\n", child->hInternet, info);
214         invalidate_handle( child );
215     }
216 
217     WININET_Release(info);
218 }
219 
220 BOOL WININET_Release( object_header_t *info )
221 {
222     ULONG refs = InterlockedDecrement(&info->refs);
223     TRACE( "object %p refcount = %d\n", info, refs );
224     if( !refs )
225     {
226         invalidate_handle(info);
227         if ( info->vtbl->CloseConnection )
228         {
229             TRACE( "closing connection %p\n", info);
230             info->vtbl->CloseConnection( info );
231         }
232         /* Don't send a callback if this is a session handle created with InternetOpenUrl */
233         if ((info->htype != WH_HHTTPSESSION && info->htype != WH_HFTPSESSION)
234             || !(info->dwInternalFlags & INET_OPENURL))
235         {
236             INTERNET_SendCallback(info, info->dwContext,
237                                   INTERNET_STATUS_HANDLE_CLOSING, &info->hInternet,
238                                   sizeof(HINTERNET));
239         }
240         TRACE( "destroying object %p\n", info);
241         if ( info->htype != WH_HINIT )
242             list_remove( &info->entry );
243         info->vtbl->Destroy( info );
244 
245         if(info->hInternet) {
246             UINT_PTR handle = (UINT_PTR)info->hInternet;
247 
248             EnterCriticalSection( &WININET_cs );
249 
250             handle_table[handle] = NULL;
251             if(next_handle > handle)
252                 next_handle = handle;
253 
254             LeaveCriticalSection( &WININET_cs );
255         }
256 
257         heap_free(info);
258     }
259     return TRUE;
260 }
261 
262 /***********************************************************************
263  * DllMain [Internal] Initializes the internal 'WININET.DLL'.
264  *
265  * PARAMS
266  *     hinstDLL    [I] handle to the DLL's instance
267  *     fdwReason   [I]
268  *     lpvReserved [I] reserved, must be NULL
269  *
270  * RETURNS
271  *     Success: TRUE
272  *     Failure: FALSE
273  */
274 
275 BOOL WINAPI DllMain (HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
276 {
277     TRACE("%p,%x,%p\n", hinstDLL, fdwReason, lpvReserved);
278 
279     switch (fdwReason) {
280         case DLL_PROCESS_ATTACH:
281 
282             g_dwTlsErrIndex = TlsAlloc();
283 
284             if (g_dwTlsErrIndex == TLS_OUT_OF_INDEXES)
285                 return FALSE;
286 
287             if(!init_urlcache())
288             {
289                 TlsFree(g_dwTlsErrIndex);
290                 return FALSE;
291             }
292 
293             WININET_hModule = hinstDLL;
294             break;
295 
296         case DLL_THREAD_ATTACH:
297             break;
298 
299         case DLL_THREAD_DETACH:
300             if (g_dwTlsErrIndex != TLS_OUT_OF_INDEXES)
301             {
302                 heap_free(TlsGetValue(g_dwTlsErrIndex));
303             }
304             break;
305 
306         case DLL_PROCESS_DETACH:
307             if (lpvReserved) break;
308             collect_connections(COLLECT_CLEANUP);
309             NETCON_unload();
310             free_urlcache();
311             free_cookie();
312 
313             if (g_dwTlsErrIndex != TLS_OUT_OF_INDEXES)
314             {
315                 heap_free(TlsGetValue(g_dwTlsErrIndex));
316                 TlsFree(g_dwTlsErrIndex);
317             }
318             break;
319     }
320     return TRUE;
321 }
322 
323 /***********************************************************************
324  *		DllInstall (WININET.@)
325  */
326 HRESULT WINAPI DllInstall(BOOL bInstall, LPCWSTR cmdline)
327 {
328     FIXME("(%x %s): stub\n", bInstall, debugstr_w(cmdline));
329     return S_OK;
330 }
331 
332 /***********************************************************************
333  *           INTERNET_SaveProxySettings
334  *
335  * Stores the proxy settings given by lpwai into the registry
336  *
337  * RETURNS
338  *     ERROR_SUCCESS if no error, or error code on fail
339  */
340 static LONG INTERNET_SaveProxySettings( proxyinfo_t *lpwpi )
341 {
342     HKEY key;
343     LONG ret;
344 
345     if ((ret = RegOpenKeyW( HKEY_CURRENT_USER, szInternetSettings, &key )))
346         return ret;
347 
348     if ((ret = RegSetValueExW( key, szProxyEnable, 0, REG_DWORD, (BYTE*)&lpwpi->proxyEnabled, sizeof(DWORD))))
349     {
350         RegCloseKey( key );
351         return ret;
352     }
353 
354     if (lpwpi->proxy)
355     {
356         if ((ret = RegSetValueExW( key, szProxyServer, 0, REG_SZ, (BYTE*)lpwpi->proxy, sizeof(WCHAR) * (lstrlenW(lpwpi->proxy) + 1))))
357         {
358             RegCloseKey( key );
359             return ret;
360         }
361     }
362     else
363     {
364         if ((ret = RegDeleteValueW( key, szProxyServer )) && ret != ERROR_FILE_NOT_FOUND)
365         {
366             RegCloseKey( key );
367             return ret;
368         }
369     }
370 
371     RegCloseKey(key);
372     return ERROR_SUCCESS;
373 }
374 
375 /***********************************************************************
376  *           INTERNET_FindProxyForProtocol
377  *
378  * Searches the proxy string for a proxy of the given protocol.
379  * Returns the found proxy, or the default proxy if none of the given
380  * protocol is found.
381  *
382  * PARAMETERS
383  *     szProxy       [In]     proxy string to search
384  *     proto         [In]     protocol to search for, e.g. "http"
385  *     foundProxy    [Out]    found proxy
386  *     foundProxyLen [In/Out] length of foundProxy buffer, in WCHARs
387  *
388  * RETURNS
389  *     TRUE if a proxy is found, FALSE if not.  If foundProxy is too short,
390  *     *foundProxyLen is set to the required size in WCHARs, including the
391  *     NULL terminator, and the last error is set to ERROR_INSUFFICIENT_BUFFER.
392  */
393 WCHAR *INTERNET_FindProxyForProtocol(LPCWSTR szProxy, LPCWSTR proto)
394 {
395     WCHAR *ret = NULL;
396     const WCHAR *ptr;
397 
398     TRACE("(%s, %s)\n", debugstr_w(szProxy), debugstr_w(proto));
399 
400     /* First, look for the specified protocol (proto=scheme://host:port) */
401     for (ptr = szProxy; ptr && *ptr; )
402     {
403         LPCWSTR end, equal;
404 
405         if (!(end = strchrW(ptr, ' ')))
406             end = ptr + strlenW(ptr);
407         if ((equal = strchrW(ptr, '=')) && equal < end &&
408              equal - ptr == strlenW(proto) &&
409              !strncmpiW(proto, ptr, strlenW(proto)))
410         {
411             ret = heap_strndupW(equal + 1, end - equal - 1);
412             TRACE("found proxy for %s: %s\n", debugstr_w(proto), debugstr_w(ret));
413             return ret;
414         }
415         if (*end == ' ')
416             ptr = end + 1;
417         else
418             ptr = end;
419     }
420 
421     /* It wasn't found: look for no protocol */
422     for (ptr = szProxy; ptr && *ptr; )
423     {
424         LPCWSTR end;
425 
426         if (!(end = strchrW(ptr, ' ')))
427             end = ptr + strlenW(ptr);
428         if (!strchrW(ptr, '='))
429         {
430             ret = heap_strndupW(ptr, end - ptr);
431             TRACE("found proxy for %s: %s\n", debugstr_w(proto), debugstr_w(ret));
432             return ret;
433         }
434         if (*end == ' ')
435             ptr = end + 1;
436         else
437             ptr = end;
438     }
439 
440     return NULL;
441 }
442 
443 /***********************************************************************
444  *           InternetInitializeAutoProxyDll   (WININET.@)
445  *
446  * Setup the internal proxy
447  *
448  * PARAMETERS
449  *     dwReserved
450  *
451  * RETURNS
452  *     FALSE on failure
453  *
454  */
455 BOOL WINAPI InternetInitializeAutoProxyDll(DWORD dwReserved)
456 {
457     FIXME("STUB\n");
458     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
459     return FALSE;
460 }
461 
462 /***********************************************************************
463  *           DetectAutoProxyUrl   (WININET.@)
464  *
465  * Auto detect the proxy url
466  *
467  * RETURNS
468  *     FALSE on failure
469  *
470  */
471 BOOL WINAPI DetectAutoProxyUrl(LPSTR lpszAutoProxyUrl,
472 	DWORD dwAutoProxyUrlLength, DWORD dwDetectFlags)
473 {
474     FIXME("STUB\n");
475     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
476     return FALSE;
477 }
478 
479 static void FreeProxyInfo( proxyinfo_t *lpwpi )
480 {
481     heap_free(lpwpi->proxy);
482     heap_free(lpwpi->proxyBypass);
483     heap_free(lpwpi->proxyUsername);
484     heap_free(lpwpi->proxyPassword);
485 }
486 
487 static proxyinfo_t *global_proxy;
488 
489 static void free_global_proxy( void )
490 {
491     EnterCriticalSection( &WININET_cs );
492     if (global_proxy)
493     {
494         FreeProxyInfo( global_proxy );
495         heap_free( global_proxy );
496     }
497     LeaveCriticalSection( &WININET_cs );
498 }
499 
500 static BOOL parse_proxy_url( proxyinfo_t *info, const WCHAR *url )
501 {
502     static const WCHAR fmt[] = {'%','.','*','s',':','%','u',0};
503     URL_COMPONENTSW uc = {sizeof(uc)};
504 
505     uc.dwHostNameLength = 1;
506     uc.dwUserNameLength = 1;
507     uc.dwPasswordLength = 1;
508 
509     if (!InternetCrackUrlW( url, 0, 0, &uc )) return FALSE;
510     if (!uc.dwHostNameLength)
511     {
512         if (!(info->proxy = heap_strdupW( url ))) return FALSE;
513         info->proxyUsername = NULL;
514         info->proxyPassword = NULL;
515         return TRUE;
516     }
517     if (!(info->proxy = heap_alloc( (uc.dwHostNameLength + 12) * sizeof(WCHAR) ))) return FALSE;
518     sprintfW( info->proxy, fmt, uc.dwHostNameLength, uc.lpszHostName, uc.nPort );
519 
520     if (!uc.dwUserNameLength) info->proxyUsername = NULL;
521     else if (!(info->proxyUsername = heap_strndupW( uc.lpszUserName, uc.dwUserNameLength )))
522     {
523         heap_free( info->proxy );
524         return FALSE;
525     }
526     if (!uc.dwPasswordLength) info->proxyPassword = NULL;
527     else if (!(info->proxyPassword = heap_strndupW( uc.lpszPassword, uc.dwPasswordLength )))
528     {
529         heap_free( info->proxyUsername );
530         heap_free( info->proxy );
531         return FALSE;
532     }
533     return TRUE;
534 }
535 
536 /***********************************************************************
537  *          INTERNET_LoadProxySettings
538  *
539  * Loads proxy information from process-wide global settings, the registry,
540  * or the environment into lpwpi.
541  *
542  * The caller should call FreeProxyInfo when done with lpwpi.
543  *
544  * FIXME:
545  * The proxy may be specified in the form 'http=proxy.my.org'
546  * Presumably that means there can be ftp=ftpproxy.my.org too.
547  */
548 static LONG INTERNET_LoadProxySettings( proxyinfo_t *lpwpi )
549 {
550     HKEY key;
551     DWORD type, len;
552     LPCSTR envproxy;
553     LONG ret;
554 
555     memset( lpwpi, 0, sizeof(*lpwpi) );
556 
557     EnterCriticalSection( &WININET_cs );
558     if (global_proxy)
559     {
560         lpwpi->proxyEnabled = global_proxy->proxyEnabled;
561         lpwpi->proxy = heap_strdupW( global_proxy->proxy );
562         lpwpi->proxyBypass = heap_strdupW( global_proxy->proxyBypass );
563     }
564     LeaveCriticalSection( &WININET_cs );
565 
566     if ((ret = RegOpenKeyW( HKEY_CURRENT_USER, szInternetSettings, &key )))
567     {
568         FreeProxyInfo( lpwpi );
569         return ret;
570     }
571 
572     len = sizeof(DWORD);
573     if (RegQueryValueExW( key, szProxyEnable, NULL, &type, (BYTE *)&lpwpi->proxyEnabled, &len ) || type != REG_DWORD)
574     {
575         lpwpi->proxyEnabled = 0;
576         if((ret = RegSetValueExW( key, szProxyEnable, 0, REG_DWORD, (BYTE *)&lpwpi->proxyEnabled, sizeof(DWORD) )))
577         {
578             FreeProxyInfo( lpwpi );
579             RegCloseKey( key );
580             return ret;
581         }
582     }
583 
584     if (!(envproxy = getenv( "http_proxy" )) || lpwpi->proxyEnabled)
585     {
586         /* figure out how much memory the proxy setting takes */
587         if (!RegQueryValueExW( key, szProxyServer, NULL, &type, NULL, &len ) && len && (type == REG_SZ))
588         {
589             LPWSTR szProxy, p;
590             static const WCHAR szHttp[] = {'h','t','t','p','=',0};
591 
592             if (!(szProxy = heap_alloc(len)))
593             {
594                 RegCloseKey( key );
595                 FreeProxyInfo( lpwpi );
596                 return ERROR_OUTOFMEMORY;
597             }
598             RegQueryValueExW( key, szProxyServer, NULL, &type, (BYTE*)szProxy, &len );
599 
600             /* find the http proxy, and strip away everything else */
601             p = strstrW( szProxy, szHttp );
602             if (p)
603             {
604                 p += lstrlenW( szHttp );
605                 lstrcpyW( szProxy, p );
606             }
607             p = strchrW( szProxy, ';' );
608             if (p) *p = 0;
609 
610             FreeProxyInfo( lpwpi );
611             lpwpi->proxy = szProxy;
612             lpwpi->proxyBypass = NULL;
613 
614             TRACE("http proxy (from registry) = %s\n", debugstr_w(lpwpi->proxy));
615         }
616         else
617         {
618             TRACE("No proxy server settings in registry.\n");
619             FreeProxyInfo( lpwpi );
620             lpwpi->proxy = NULL;
621             lpwpi->proxyBypass = NULL;
622         }
623     }
624     else if (envproxy)
625     {
626         WCHAR *envproxyW;
627 
628         len = MultiByteToWideChar( CP_UNIXCP, 0, envproxy, -1, NULL, 0 );
629         if (!(envproxyW = heap_alloc(len * sizeof(WCHAR))))
630         {
631             RegCloseKey( key );
632             return ERROR_OUTOFMEMORY;
633         }
634         MultiByteToWideChar( CP_UNIXCP, 0, envproxy, -1, envproxyW, len );
635 
636         FreeProxyInfo( lpwpi );
637         if (parse_proxy_url( lpwpi, envproxyW ))
638         {
639             TRACE("http proxy (from environment) = %s\n", debugstr_w(lpwpi->proxy));
640             lpwpi->proxyEnabled = 1;
641             lpwpi->proxyBypass = NULL;
642         }
643         else
644         {
645             WARN("failed to parse http_proxy value %s\n", debugstr_w(envproxyW));
646             lpwpi->proxyEnabled = 0;
647             lpwpi->proxy = NULL;
648             lpwpi->proxyBypass = NULL;
649         }
650         heap_free( envproxyW );
651     }
652 
653     if (lpwpi->proxyEnabled)
654     {
655         TRACE("Proxy is enabled.\n");
656 
657         if (!(envproxy = getenv( "no_proxy" )))
658         {
659             /* figure out how much memory the proxy setting takes */
660             if (!RegQueryValueExW( key, szProxyOverride, NULL, &type, NULL, &len ) && len && (type == REG_SZ))
661             {
662                 LPWSTR szProxy;
663 
664                 if (!(szProxy = heap_alloc(len)))
665                 {
666                     RegCloseKey( key );
667                     return ERROR_OUTOFMEMORY;
668                 }
669                 RegQueryValueExW( key, szProxyOverride, NULL, &type, (BYTE*)szProxy, &len );
670 
671                 heap_free( lpwpi->proxyBypass );
672                 lpwpi->proxyBypass = szProxy;
673 
674                 TRACE("http proxy bypass (from registry) = %s\n", debugstr_w(lpwpi->proxyBypass));
675             }
676             else
677             {
678                 heap_free( lpwpi->proxyBypass );
679                 lpwpi->proxyBypass = NULL;
680 
681                 TRACE("No proxy bypass server settings in registry.\n");
682             }
683         }
684         else
685         {
686             WCHAR *envproxyW;
687 
688             len = MultiByteToWideChar( CP_UNIXCP, 0, envproxy, -1, NULL, 0 );
689             if (!(envproxyW = heap_alloc(len * sizeof(WCHAR))))
690             {
691                 RegCloseKey( key );
692                 return ERROR_OUTOFMEMORY;
693             }
694             MultiByteToWideChar( CP_UNIXCP, 0, envproxy, -1, envproxyW, len );
695 
696             heap_free( lpwpi->proxyBypass );
697             lpwpi->proxyBypass = envproxyW;
698 
699             TRACE("http proxy bypass (from environment) = %s\n", debugstr_w(lpwpi->proxyBypass));
700         }
701     }
702     else TRACE("Proxy is disabled.\n");
703 
704     RegCloseKey( key );
705     return ERROR_SUCCESS;
706 }
707 
708 /***********************************************************************
709  *           INTERNET_ConfigureProxy
710  */
711 static BOOL INTERNET_ConfigureProxy( appinfo_t *lpwai )
712 {
713     proxyinfo_t wpi;
714 
715     if (INTERNET_LoadProxySettings( &wpi ))
716         return FALSE;
717 
718     if (wpi.proxyEnabled)
719     {
720         TRACE("http proxy = %s bypass = %s\n", debugstr_w(wpi.proxy), debugstr_w(wpi.proxyBypass));
721 
722         lpwai->accessType    = INTERNET_OPEN_TYPE_PROXY;
723         lpwai->proxy         = wpi.proxy;
724         lpwai->proxyBypass   = wpi.proxyBypass;
725         lpwai->proxyUsername = wpi.proxyUsername;
726         lpwai->proxyPassword = wpi.proxyPassword;
727         return TRUE;
728     }
729 
730     lpwai->accessType = INTERNET_OPEN_TYPE_DIRECT;
731     FreeProxyInfo(&wpi);
732     return FALSE;
733 }
734 
735 /***********************************************************************
736  *           dump_INTERNET_FLAGS
737  *
738  * Helper function to TRACE the internet flags.
739  *
740  * RETURNS
741  *    None
742  *
743  */
744 static void dump_INTERNET_FLAGS(DWORD dwFlags)
745 {
746 #define FE(x) { x, #x }
747     static const wininet_flag_info flag[] = {
748         FE(INTERNET_FLAG_RELOAD),
749         FE(INTERNET_FLAG_RAW_DATA),
750         FE(INTERNET_FLAG_EXISTING_CONNECT),
751         FE(INTERNET_FLAG_ASYNC),
752         FE(INTERNET_FLAG_PASSIVE),
753         FE(INTERNET_FLAG_NO_CACHE_WRITE),
754         FE(INTERNET_FLAG_MAKE_PERSISTENT),
755         FE(INTERNET_FLAG_FROM_CACHE),
756         FE(INTERNET_FLAG_SECURE),
757         FE(INTERNET_FLAG_KEEP_CONNECTION),
758         FE(INTERNET_FLAG_NO_AUTO_REDIRECT),
759         FE(INTERNET_FLAG_READ_PREFETCH),
760         FE(INTERNET_FLAG_NO_COOKIES),
761         FE(INTERNET_FLAG_NO_AUTH),
762         FE(INTERNET_FLAG_CACHE_IF_NET_FAIL),
763         FE(INTERNET_FLAG_IGNORE_REDIRECT_TO_HTTP),
764         FE(INTERNET_FLAG_IGNORE_REDIRECT_TO_HTTPS),
765         FE(INTERNET_FLAG_IGNORE_CERT_DATE_INVALID),
766         FE(INTERNET_FLAG_IGNORE_CERT_CN_INVALID),
767         FE(INTERNET_FLAG_RESYNCHRONIZE),
768         FE(INTERNET_FLAG_HYPERLINK),
769         FE(INTERNET_FLAG_NO_UI),
770         FE(INTERNET_FLAG_PRAGMA_NOCACHE),
771         FE(INTERNET_FLAG_CACHE_ASYNC),
772         FE(INTERNET_FLAG_FORMS_SUBMIT),
773         FE(INTERNET_FLAG_NEED_FILE),
774         FE(INTERNET_FLAG_TRANSFER_ASCII),
775         FE(INTERNET_FLAG_TRANSFER_BINARY)
776     };
777 #undef FE
778     unsigned int i;
779 
780     for (i = 0; i < (sizeof(flag) / sizeof(flag[0])); i++) {
781 	if (flag[i].val & dwFlags) {
782 	    TRACE(" %s", flag[i].name);
783 	    dwFlags &= ~flag[i].val;
784 	}
785     }
786     if (dwFlags)
787         TRACE(" Unknown flags (%08x)\n", dwFlags);
788     else
789         TRACE("\n");
790 }
791 
792 /***********************************************************************
793  *           INTERNET_CloseHandle (internal)
794  *
795  * Close internet handle
796  *
797  */
798 static VOID APPINFO_Destroy(object_header_t *hdr)
799 {
800     appinfo_t *lpwai = (appinfo_t*)hdr;
801 
802     TRACE("%p\n",lpwai);
803 
804     heap_free(lpwai->agent);
805     heap_free(lpwai->proxy);
806     heap_free(lpwai->proxyBypass);
807     heap_free(lpwai->proxyUsername);
808     heap_free(lpwai->proxyPassword);
809 }
810 
811 static DWORD APPINFO_QueryOption(object_header_t *hdr, DWORD option, void *buffer, DWORD *size, BOOL unicode)
812 {
813     appinfo_t *ai = (appinfo_t*)hdr;
814 
815     switch(option) {
816     case INTERNET_OPTION_HANDLE_TYPE:
817         TRACE("INTERNET_OPTION_HANDLE_TYPE\n");
818 
819         if (*size < sizeof(ULONG))
820             return ERROR_INSUFFICIENT_BUFFER;
821 
822         *size = sizeof(DWORD);
823         *(DWORD*)buffer = INTERNET_HANDLE_TYPE_INTERNET;
824         return ERROR_SUCCESS;
825 
826     case INTERNET_OPTION_USER_AGENT: {
827         DWORD bufsize;
828 
829         TRACE("INTERNET_OPTION_USER_AGENT\n");
830 
831         bufsize = *size;
832 
833         if (unicode) {
834             DWORD len = ai->agent ? strlenW(ai->agent) : 0;
835 
836             *size = (len + 1) * sizeof(WCHAR);
837             if(!buffer || bufsize < *size)
838                 return ERROR_INSUFFICIENT_BUFFER;
839 
840             if (ai->agent)
841                 strcpyW(buffer, ai->agent);
842             else
843                 *(WCHAR *)buffer = 0;
844             /* If the buffer is copied, the returned length doesn't include
845              * the NULL terminator.
846              */
847             *size = len;
848         }else {
849             if (ai->agent)
850                 *size = WideCharToMultiByte(CP_ACP, 0, ai->agent, -1, NULL, 0, NULL, NULL);
851             else
852                 *size = 1;
853             if(!buffer || bufsize < *size)
854                 return ERROR_INSUFFICIENT_BUFFER;
855 
856             if (ai->agent)
857                 WideCharToMultiByte(CP_ACP, 0, ai->agent, -1, buffer, *size, NULL, NULL);
858             else
859                 *(char *)buffer = 0;
860             /* If the buffer is copied, the returned length doesn't include
861              * the NULL terminator.
862              */
863             *size -= 1;
864         }
865 
866         return ERROR_SUCCESS;
867     }
868 
869     case INTERNET_OPTION_PROXY:
870         if(!size) return ERROR_INVALID_PARAMETER;
871         if (unicode) {
872             INTERNET_PROXY_INFOW *pi = (INTERNET_PROXY_INFOW *)buffer;
873             DWORD proxyBytesRequired = 0, proxyBypassBytesRequired = 0;
874             LPWSTR proxy, proxy_bypass;
875 
876             if (ai->proxy)
877                 proxyBytesRequired = (lstrlenW(ai->proxy) + 1) * sizeof(WCHAR);
878             if (ai->proxyBypass)
879                 proxyBypassBytesRequired = (lstrlenW(ai->proxyBypass) + 1) * sizeof(WCHAR);
880             if (!pi || *size < sizeof(INTERNET_PROXY_INFOW) + proxyBytesRequired + proxyBypassBytesRequired)
881             {
882                 *size = sizeof(INTERNET_PROXY_INFOW) + proxyBytesRequired + proxyBypassBytesRequired;
883                 return ERROR_INSUFFICIENT_BUFFER;
884             }
885             proxy = (LPWSTR)((LPBYTE)buffer + sizeof(INTERNET_PROXY_INFOW));
886             proxy_bypass = (LPWSTR)((LPBYTE)buffer + sizeof(INTERNET_PROXY_INFOW) + proxyBytesRequired);
887 
888             pi->dwAccessType = ai->accessType;
889             pi->lpszProxy = NULL;
890             pi->lpszProxyBypass = NULL;
891             if (ai->proxy) {
892                 lstrcpyW(proxy, ai->proxy);
893                 pi->lpszProxy = proxy;
894             }
895 
896             if (ai->proxyBypass) {
897                 lstrcpyW(proxy_bypass, ai->proxyBypass);
898                 pi->lpszProxyBypass = proxy_bypass;
899             }
900 
901             *size = sizeof(INTERNET_PROXY_INFOW) + proxyBytesRequired + proxyBypassBytesRequired;
902             return ERROR_SUCCESS;
903         }else {
904             INTERNET_PROXY_INFOA *pi = (INTERNET_PROXY_INFOA *)buffer;
905             DWORD proxyBytesRequired = 0, proxyBypassBytesRequired = 0;
906             LPSTR proxy, proxy_bypass;
907 
908             if (ai->proxy)
909                 proxyBytesRequired = WideCharToMultiByte(CP_ACP, 0, ai->proxy, -1, NULL, 0, NULL, NULL);
910             if (ai->proxyBypass)
911                 proxyBypassBytesRequired = WideCharToMultiByte(CP_ACP, 0, ai->proxyBypass, -1,
912                         NULL, 0, NULL, NULL);
913             if (!pi || *size < sizeof(INTERNET_PROXY_INFOA) + proxyBytesRequired + proxyBypassBytesRequired)
914             {
915                 *size = sizeof(INTERNET_PROXY_INFOA) + proxyBytesRequired + proxyBypassBytesRequired;
916                 return ERROR_INSUFFICIENT_BUFFER;
917             }
918             proxy = (LPSTR)((LPBYTE)buffer + sizeof(INTERNET_PROXY_INFOA));
919             proxy_bypass = (LPSTR)((LPBYTE)buffer + sizeof(INTERNET_PROXY_INFOA) + proxyBytesRequired);
920 
921             pi->dwAccessType = ai->accessType;
922             pi->lpszProxy = NULL;
923             pi->lpszProxyBypass = NULL;
924             if (ai->proxy) {
925                 WideCharToMultiByte(CP_ACP, 0, ai->proxy, -1, proxy, proxyBytesRequired, NULL, NULL);
926                 pi->lpszProxy = proxy;
927             }
928 
929             if (ai->proxyBypass) {
930                 WideCharToMultiByte(CP_ACP, 0, ai->proxyBypass, -1, proxy_bypass,
931                         proxyBypassBytesRequired, NULL, NULL);
932                 pi->lpszProxyBypass = proxy_bypass;
933             }
934 
935             *size = sizeof(INTERNET_PROXY_INFOA) + proxyBytesRequired + proxyBypassBytesRequired;
936             return ERROR_SUCCESS;
937         }
938 
939     case INTERNET_OPTION_CONNECT_TIMEOUT:
940         TRACE("INTERNET_OPTION_CONNECT_TIMEOUT\n");
941 
942         if (*size < sizeof(ULONG))
943             return ERROR_INSUFFICIENT_BUFFER;
944 
945         *(ULONG*)buffer = ai->connect_timeout;
946         *size = sizeof(ULONG);
947 
948         return ERROR_SUCCESS;
949     }
950 
951     return INET_QueryOption(hdr, option, buffer, size, unicode);
952 }
953 
954 static DWORD APPINFO_SetOption(object_header_t *hdr, DWORD option, void *buf, DWORD size)
955 {
956     appinfo_t *ai = (appinfo_t*)hdr;
957 
958     switch(option) {
959     case INTERNET_OPTION_CONNECT_TIMEOUT:
960         TRACE("INTERNET_OPTION_CONNECT_TIMEOUT\n");
961 
962         if(size != sizeof(connect_timeout))
963             return ERROR_INTERNET_BAD_OPTION_LENGTH;
964         if(!*(ULONG*)buf)
965             return ERROR_BAD_ARGUMENTS;
966 
967         ai->connect_timeout = *(ULONG*)buf;
968         return ERROR_SUCCESS;
969     case INTERNET_OPTION_USER_AGENT:
970         heap_free(ai->agent);
971         if (!(ai->agent = heap_strdupW(buf))) return ERROR_OUTOFMEMORY;
972         return ERROR_SUCCESS;
973     case INTERNET_OPTION_REFRESH:
974         FIXME("INTERNET_OPTION_REFRESH\n");
975         return ERROR_SUCCESS;
976     }
977 
978     return INET_SetOption(hdr, option, buf, size);
979 }
980 
981 static const object_vtbl_t APPINFOVtbl = {
982     APPINFO_Destroy,
983     NULL,
984     APPINFO_QueryOption,
985     APPINFO_SetOption,
986     NULL,
987     NULL,
988     NULL
989 };
990 
991 
992 /***********************************************************************
993  *           InternetOpenW   (WININET.@)
994  *
995  * Per-application initialization of wininet
996  *
997  * RETURNS
998  *    HINTERNET on success
999  *    NULL on failure
1000  *
1001  */
1002 HINTERNET WINAPI InternetOpenW(LPCWSTR lpszAgent, DWORD dwAccessType,
1003     LPCWSTR lpszProxy, LPCWSTR lpszProxyBypass, DWORD dwFlags)
1004 {
1005     appinfo_t *lpwai = NULL;
1006 
1007 #ifdef __REACTOS__
1008     init_winsock();
1009 #endif
1010     if (TRACE_ON(wininet)) {
1011 #define FE(x) { x, #x }
1012 	static const wininet_flag_info access_type[] = {
1013 	    FE(INTERNET_OPEN_TYPE_PRECONFIG),
1014 	    FE(INTERNET_OPEN_TYPE_DIRECT),
1015 	    FE(INTERNET_OPEN_TYPE_PROXY),
1016 	    FE(INTERNET_OPEN_TYPE_PRECONFIG_WITH_NO_AUTOPROXY)
1017 	};
1018 #undef FE
1019 	DWORD i;
1020 	const char *access_type_str = "Unknown";
1021 
1022 	TRACE("(%s, %i, %s, %s, %i)\n", debugstr_w(lpszAgent), dwAccessType,
1023 	      debugstr_w(lpszProxy), debugstr_w(lpszProxyBypass), dwFlags);
1024 	for (i = 0; i < (sizeof(access_type) / sizeof(access_type[0])); i++) {
1025 	    if (access_type[i].val == dwAccessType) {
1026 		access_type_str = access_type[i].name;
1027 		break;
1028 	    }
1029 	}
1030 	TRACE("  access type : %s\n", access_type_str);
1031 	TRACE("  flags       :");
1032 	dump_INTERNET_FLAGS(dwFlags);
1033     }
1034 
1035     /* Clear any error information */
1036     INTERNET_SetLastError(0);
1037 
1038     if((dwAccessType == INTERNET_OPEN_TYPE_PROXY) && !lpszProxy) {
1039         SetLastError(ERROR_INVALID_PARAMETER);
1040         return NULL;
1041     }
1042 
1043     lpwai = alloc_object(NULL, &APPINFOVtbl, sizeof(appinfo_t));
1044     if (!lpwai) {
1045         SetLastError(ERROR_OUTOFMEMORY);
1046         return NULL;
1047     }
1048 
1049     lpwai->hdr.htype = WH_HINIT;
1050     lpwai->hdr.dwFlags = dwFlags;
1051     lpwai->accessType = dwAccessType;
1052     lpwai->proxyUsername = NULL;
1053     lpwai->proxyPassword = NULL;
1054     lpwai->connect_timeout = connect_timeout;
1055 
1056     lpwai->agent = heap_strdupW(lpszAgent);
1057     if(dwAccessType == INTERNET_OPEN_TYPE_PRECONFIG)
1058         INTERNET_ConfigureProxy( lpwai );
1059     else if(dwAccessType == INTERNET_OPEN_TYPE_PROXY) {
1060         lpwai->proxy = heap_strdupW(lpszProxy);
1061         lpwai->proxyBypass = heap_strdupW(lpszProxyBypass);
1062     }
1063 
1064     TRACE("returning %p\n", lpwai);
1065 
1066     return lpwai->hdr.hInternet;
1067 }
1068 
1069 
1070 /***********************************************************************
1071  *           InternetOpenA   (WININET.@)
1072  *
1073  * Per-application initialization of wininet
1074  *
1075  * RETURNS
1076  *    HINTERNET on success
1077  *    NULL on failure
1078  *
1079  */
1080 HINTERNET WINAPI InternetOpenA(LPCSTR lpszAgent, DWORD dwAccessType,
1081     LPCSTR lpszProxy, LPCSTR lpszProxyBypass, DWORD dwFlags)
1082 {
1083     WCHAR *szAgent, *szProxy, *szBypass;
1084     HINTERNET rc;
1085 
1086     TRACE("(%s, 0x%08x, %s, %s, 0x%08x)\n", debugstr_a(lpszAgent),
1087        dwAccessType, debugstr_a(lpszProxy), debugstr_a(lpszProxyBypass), dwFlags);
1088 
1089     szAgent = heap_strdupAtoW(lpszAgent);
1090     szProxy = heap_strdupAtoW(lpszProxy);
1091     szBypass = heap_strdupAtoW(lpszProxyBypass);
1092 
1093     rc = InternetOpenW(szAgent, dwAccessType, szProxy, szBypass, dwFlags);
1094 
1095     heap_free(szAgent);
1096     heap_free(szProxy);
1097     heap_free(szBypass);
1098     return rc;
1099 }
1100 
1101 /***********************************************************************
1102  *           InternetGetLastResponseInfoA (WININET.@)
1103  *
1104  * Return last wininet error description on the calling thread
1105  *
1106  * RETURNS
1107  *    TRUE on success of writing to buffer
1108  *    FALSE on failure
1109  *
1110  */
1111 BOOL WINAPI InternetGetLastResponseInfoA(LPDWORD lpdwError,
1112     LPSTR lpszBuffer, LPDWORD lpdwBufferLength)
1113 {
1114     LPWITHREADERROR lpwite = TlsGetValue(g_dwTlsErrIndex);
1115 
1116     TRACE("\n");
1117 
1118     if (lpwite)
1119     {
1120         *lpdwError = lpwite->dwError;
1121         if (lpwite->dwError)
1122         {
1123             memcpy(lpszBuffer, lpwite->response, *lpdwBufferLength);
1124             *lpdwBufferLength = strlen(lpszBuffer);
1125         }
1126         else
1127             *lpdwBufferLength = 0;
1128     }
1129     else
1130     {
1131         *lpdwError = 0;
1132         *lpdwBufferLength = 0;
1133     }
1134 
1135     return TRUE;
1136 }
1137 
1138 /***********************************************************************
1139  *           InternetGetLastResponseInfoW (WININET.@)
1140  *
1141  * Return last wininet error description on the calling thread
1142  *
1143  * RETURNS
1144  *    TRUE on success of writing to buffer
1145  *    FALSE on failure
1146  *
1147  */
1148 BOOL WINAPI InternetGetLastResponseInfoW(LPDWORD lpdwError,
1149     LPWSTR lpszBuffer, LPDWORD lpdwBufferLength)
1150 {
1151     LPWITHREADERROR lpwite = TlsGetValue(g_dwTlsErrIndex);
1152 
1153     TRACE("\n");
1154 
1155     if (lpwite)
1156     {
1157         *lpdwError = lpwite->dwError;
1158         if (lpwite->dwError)
1159         {
1160             memcpy(lpszBuffer, lpwite->response, *lpdwBufferLength);
1161             *lpdwBufferLength = lstrlenW(lpszBuffer);
1162         }
1163         else
1164             *lpdwBufferLength = 0;
1165     }
1166     else
1167     {
1168         *lpdwError = 0;
1169         *lpdwBufferLength = 0;
1170     }
1171 
1172     return TRUE;
1173 }
1174 
1175 /***********************************************************************
1176  *           InternetGetConnectedState (WININET.@)
1177  *
1178  * Return connected state
1179  *
1180  * RETURNS
1181  *    TRUE if connected
1182  *    if lpdwStatus is not null, return the status (off line,
1183  *    modem, lan...) in it.
1184  *    FALSE if not connected
1185  */
1186 BOOL WINAPI InternetGetConnectedState(LPDWORD lpdwStatus, DWORD dwReserved)
1187 {
1188     TRACE("(%p, 0x%08x)\n", lpdwStatus, dwReserved);
1189 
1190     return InternetGetConnectedStateExW(lpdwStatus, NULL, 0, dwReserved);
1191 }
1192 
1193 
1194 /***********************************************************************
1195  *           InternetGetConnectedStateExW (WININET.@)
1196  *
1197  * Return connected state
1198  *
1199  * PARAMS
1200  *
1201  * lpdwStatus         [O] Flags specifying the status of the internet connection.
1202  * lpszConnectionName [O] Pointer to buffer to receive the friendly name of the internet connection.
1203  * dwNameLen          [I] Size of the buffer, in characters.
1204  * dwReserved         [I] Reserved. Must be set to 0.
1205  *
1206  * RETURNS
1207  *    TRUE if connected
1208  *    if lpdwStatus is not null, return the status (off line,
1209  *    modem, lan...) in it.
1210  *    FALSE if not connected
1211  *
1212  * NOTES
1213  *   If the system has no available network connections, an empty string is
1214  *   stored in lpszConnectionName. If there is a LAN connection, a localized
1215  *   "LAN Connection" string is stored. Presumably, if only a dial-up
1216  *   connection is available then the name of the dial-up connection is
1217  *   returned. Why any application, other than the "Internet Settings" CPL,
1218  *   would want to use this function instead of the simpler InternetGetConnectedStateW
1219  *   function is beyond me.
1220  */
1221 BOOL WINAPI InternetGetConnectedStateExW(LPDWORD lpdwStatus, LPWSTR lpszConnectionName,
1222                                          DWORD dwNameLen, DWORD dwReserved)
1223 {
1224     TRACE("(%p, %p, %d, 0x%08x)\n", lpdwStatus, lpszConnectionName, dwNameLen, dwReserved);
1225 
1226     /* Must be zero */
1227     if(dwReserved)
1228         return FALSE;
1229 
1230     if (lpdwStatus) {
1231         WARN("always returning LAN connection.\n");
1232         *lpdwStatus = INTERNET_CONNECTION_LAN;
1233     }
1234 
1235     /* When the buffer size is zero LoadStringW fills the buffer with a pointer to
1236      * the resource, avoid it as we must not change the buffer in this case */
1237     if(lpszConnectionName && dwNameLen) {
1238         *lpszConnectionName = '\0';
1239         LoadStringW(WININET_hModule, IDS_LANCONNECTION, lpszConnectionName, dwNameLen);
1240     }
1241 
1242     return TRUE;
1243 }
1244 
1245 
1246 /***********************************************************************
1247  *           InternetGetConnectedStateExA (WININET.@)
1248  */
1249 BOOL WINAPI InternetGetConnectedStateExA(LPDWORD lpdwStatus, LPSTR lpszConnectionName,
1250                                          DWORD dwNameLen, DWORD dwReserved)
1251 {
1252     LPWSTR lpwszConnectionName = NULL;
1253     BOOL rc;
1254 
1255     TRACE("(%p, %p, %d, 0x%08x)\n", lpdwStatus, lpszConnectionName, dwNameLen, dwReserved);
1256 
1257     if (lpszConnectionName && dwNameLen > 0)
1258         lpwszConnectionName = heap_alloc(dwNameLen * sizeof(WCHAR));
1259 
1260     rc = InternetGetConnectedStateExW(lpdwStatus,lpwszConnectionName, dwNameLen,
1261                                       dwReserved);
1262     if (rc && lpwszConnectionName)
1263         WideCharToMultiByte(CP_ACP,0,lpwszConnectionName,-1,lpszConnectionName,
1264                             dwNameLen, NULL, NULL);
1265 
1266     heap_free(lpwszConnectionName);
1267     return rc;
1268 }
1269 
1270 
1271 /***********************************************************************
1272  *           InternetConnectW (WININET.@)
1273  *
1274  * Open a ftp, gopher or http session
1275  *
1276  * RETURNS
1277  *    HINTERNET a session handle on success
1278  *    NULL on failure
1279  *
1280  */
1281 HINTERNET WINAPI InternetConnectW(HINTERNET hInternet,
1282     LPCWSTR lpszServerName, INTERNET_PORT nServerPort,
1283     LPCWSTR lpszUserName, LPCWSTR lpszPassword,
1284     DWORD dwService, DWORD dwFlags, DWORD_PTR dwContext)
1285 {
1286     appinfo_t *hIC;
1287     HINTERNET rc = NULL;
1288     DWORD res = ERROR_SUCCESS;
1289 
1290     TRACE("(%p, %s, %u, %s, %p, %u, %x, %lx)\n", hInternet, debugstr_w(lpszServerName),
1291           nServerPort, debugstr_w(lpszUserName), lpszPassword, dwService, dwFlags, dwContext);
1292 
1293     if (!lpszServerName)
1294     {
1295         SetLastError(ERROR_INVALID_PARAMETER);
1296         return NULL;
1297     }
1298 
1299     hIC = (appinfo_t*)get_handle_object( hInternet );
1300     if ( (hIC == NULL) || (hIC->hdr.htype != WH_HINIT) )
1301     {
1302         res = ERROR_INVALID_HANDLE;
1303         goto lend;
1304     }
1305 
1306     switch (dwService)
1307     {
1308         case INTERNET_SERVICE_FTP:
1309             rc = FTP_Connect(hIC, lpszServerName, nServerPort,
1310             lpszUserName, lpszPassword, dwFlags, dwContext, 0);
1311             if(!rc)
1312                 res = INTERNET_GetLastError();
1313             break;
1314 
1315         case INTERNET_SERVICE_HTTP:
1316 	    res = HTTP_Connect(hIC, lpszServerName, nServerPort,
1317                     lpszUserName, lpszPassword, dwFlags, dwContext, 0, &rc);
1318             break;
1319 
1320         case INTERNET_SERVICE_GOPHER:
1321         default:
1322             break;
1323     }
1324 lend:
1325     if( hIC )
1326         WININET_Release( &hIC->hdr );
1327 
1328     TRACE("returning %p\n", rc);
1329     SetLastError(res);
1330     return rc;
1331 }
1332 
1333 
1334 /***********************************************************************
1335  *           InternetConnectA (WININET.@)
1336  *
1337  * Open a ftp, gopher or http session
1338  *
1339  * RETURNS
1340  *    HINTERNET a session handle on success
1341  *    NULL on failure
1342  *
1343  */
1344 HINTERNET WINAPI InternetConnectA(HINTERNET hInternet,
1345     LPCSTR lpszServerName, INTERNET_PORT nServerPort,
1346     LPCSTR lpszUserName, LPCSTR lpszPassword,
1347     DWORD dwService, DWORD dwFlags, DWORD_PTR dwContext)
1348 {
1349     HINTERNET rc = NULL;
1350     LPWSTR szServerName;
1351     LPWSTR szUserName;
1352     LPWSTR szPassword;
1353 
1354     szServerName = heap_strdupAtoW(lpszServerName);
1355     szUserName = heap_strdupAtoW(lpszUserName);
1356     szPassword = heap_strdupAtoW(lpszPassword);
1357 
1358     rc = InternetConnectW(hInternet, szServerName, nServerPort,
1359         szUserName, szPassword, dwService, dwFlags, dwContext);
1360 
1361     heap_free(szServerName);
1362     heap_free(szUserName);
1363     heap_free(szPassword);
1364     return rc;
1365 }
1366 
1367 
1368 /***********************************************************************
1369  *           InternetFindNextFileA (WININET.@)
1370  *
1371  * Continues a file search from a previous call to FindFirstFile
1372  *
1373  * RETURNS
1374  *    TRUE on success
1375  *    FALSE on failure
1376  *
1377  */
1378 BOOL WINAPI InternetFindNextFileA(HINTERNET hFind, LPVOID lpvFindData)
1379 {
1380     BOOL ret;
1381     WIN32_FIND_DATAW fd;
1382 
1383     ret = InternetFindNextFileW(hFind, lpvFindData?&fd:NULL);
1384     if(lpvFindData)
1385         WININET_find_data_WtoA(&fd, (LPWIN32_FIND_DATAA)lpvFindData);
1386     return ret;
1387 }
1388 
1389 /***********************************************************************
1390  *           InternetFindNextFileW (WININET.@)
1391  *
1392  * Continues a file search from a previous call to FindFirstFile
1393  *
1394  * RETURNS
1395  *    TRUE on success
1396  *    FALSE on failure
1397  *
1398  */
1399 BOOL WINAPI InternetFindNextFileW(HINTERNET hFind, LPVOID lpvFindData)
1400 {
1401     object_header_t *hdr;
1402     DWORD res;
1403 
1404     TRACE("\n");
1405 
1406     hdr = get_handle_object(hFind);
1407     if(!hdr) {
1408         WARN("Invalid handle\n");
1409         SetLastError(ERROR_INVALID_HANDLE);
1410         return FALSE;
1411     }
1412 
1413     if(hdr->vtbl->FindNextFileW) {
1414         res = hdr->vtbl->FindNextFileW(hdr, lpvFindData);
1415     }else {
1416         WARN("Handle doesn't support NextFile\n");
1417         res = ERROR_INTERNET_INCORRECT_HANDLE_TYPE;
1418     }
1419 
1420     WININET_Release(hdr);
1421 
1422     if(res != ERROR_SUCCESS)
1423         SetLastError(res);
1424     return res == ERROR_SUCCESS;
1425 }
1426 
1427 /***********************************************************************
1428  *           InternetCloseHandle (WININET.@)
1429  *
1430  * Generic close handle function
1431  *
1432  * RETURNS
1433  *    TRUE on success
1434  *    FALSE on failure
1435  *
1436  */
1437 BOOL WINAPI InternetCloseHandle(HINTERNET hInternet)
1438 {
1439     object_header_t *obj;
1440 
1441     TRACE("%p\n", hInternet);
1442 
1443     obj = get_handle_object( hInternet );
1444     if (!obj) {
1445         SetLastError(ERROR_INVALID_HANDLE);
1446         return FALSE;
1447     }
1448 
1449     invalidate_handle(obj);
1450     WININET_Release(obj);
1451 
1452     return TRUE;
1453 }
1454 
1455 static BOOL set_url_component(WCHAR **component, DWORD *component_length, const WCHAR *value, DWORD len)
1456 {
1457     TRACE("%s (%d)\n", debugstr_wn(value, len), len);
1458 
1459     if (!*component_length)
1460         return TRUE;
1461 
1462     if (!*component) {
1463         *(const WCHAR**)component = value;
1464         *component_length = len;
1465         return TRUE;
1466     }
1467 
1468     if (*component_length < len+1) {
1469         SetLastError(ERROR_INSUFFICIENT_BUFFER);
1470         return FALSE;
1471     }
1472 
1473     *component_length = len;
1474     if(len)
1475         memcpy(*component, value, len*sizeof(WCHAR));
1476     (*component)[len] = 0;
1477     return TRUE;
1478 }
1479 
1480 static BOOL set_url_component_WtoA(const WCHAR *comp_w, DWORD length, const WCHAR *url_w, char **comp, DWORD *ret_length,
1481                                    const char *url_a)
1482 {
1483     size_t size, ret_size = *ret_length;
1484 
1485     if (!*ret_length)
1486         return TRUE;
1487     size = WideCharToMultiByte(CP_ACP, 0, comp_w, length, NULL, 0, NULL, NULL);
1488 
1489     if (!*comp) {
1490         *comp = comp_w ? (char*)url_a + WideCharToMultiByte(CP_ACP, 0, url_w, comp_w-url_w, NULL, 0, NULL, NULL) : NULL;
1491         *ret_length = size;
1492         return TRUE;
1493     }
1494 
1495     if (size+1 > ret_size) {
1496         SetLastError(ERROR_INSUFFICIENT_BUFFER);
1497         *ret_length = size+1;
1498         return FALSE;
1499     }
1500 
1501     *ret_length = size;
1502     WideCharToMultiByte(CP_ACP, 0, comp_w, length, *comp, ret_size-1, NULL, NULL);
1503     (*comp)[size] = 0;
1504     return TRUE;
1505 }
1506 
1507 static BOOL set_url_component_AtoW(const char *comp_a, DWORD len_a, WCHAR **comp_w, DWORD *len_w, WCHAR **buf)
1508 {
1509     *len_w = len_a;
1510 
1511     if(!comp_a) {
1512         *comp_w = NULL;
1513         return TRUE;
1514     }
1515 
1516     if(!(*comp_w = *buf = heap_alloc(len_a*sizeof(WCHAR)))) {
1517         SetLastError(ERROR_OUTOFMEMORY);
1518         return FALSE;
1519     }
1520 
1521     return TRUE;
1522 }
1523 
1524 /***********************************************************************
1525  *           InternetCrackUrlA (WININET.@)
1526  *
1527  * See InternetCrackUrlW.
1528  */
1529 BOOL WINAPI InternetCrackUrlA(const char *url, DWORD url_length, DWORD flags, URL_COMPONENTSA *ret_comp)
1530 {
1531     WCHAR *host = NULL, *user = NULL, *pass = NULL, *path = NULL, *scheme = NULL, *extra = NULL;
1532     URL_COMPONENTSW comp;
1533     WCHAR *url_w = NULL;
1534     BOOL ret;
1535 
1536     TRACE("(%s %u %x %p)\n", url_length ? debugstr_an(url, url_length) : debugstr_a(url), url_length, flags, ret_comp);
1537 
1538     if (!url || !*url || !ret_comp || ret_comp->dwStructSize != sizeof(URL_COMPONENTSA)) {
1539         SetLastError(ERROR_INVALID_PARAMETER);
1540         return FALSE;
1541     }
1542 
1543     comp.dwStructSize = sizeof(comp);
1544 
1545     ret = set_url_component_AtoW(ret_comp->lpszHostName, ret_comp->dwHostNameLength,
1546                                  &comp.lpszHostName, &comp.dwHostNameLength, &host)
1547         && set_url_component_AtoW(ret_comp->lpszUserName, ret_comp->dwUserNameLength,
1548                                   &comp.lpszUserName, &comp.dwUserNameLength, &user)
1549         && set_url_component_AtoW(ret_comp->lpszPassword, ret_comp->dwPasswordLength,
1550                                   &comp.lpszPassword, &comp.dwPasswordLength, &pass)
1551         && set_url_component_AtoW(ret_comp->lpszUrlPath, ret_comp->dwUrlPathLength,
1552                                   &comp.lpszUrlPath, &comp.dwUrlPathLength, &path)
1553         && set_url_component_AtoW(ret_comp->lpszScheme, ret_comp->dwSchemeLength,
1554                                   &comp.lpszScheme, &comp.dwSchemeLength, &scheme)
1555         && set_url_component_AtoW(ret_comp->lpszExtraInfo, ret_comp->dwExtraInfoLength,
1556                                   &comp.lpszExtraInfo, &comp.dwExtraInfoLength, &extra);
1557 
1558     if(ret && !(url_w = heap_strndupAtoW(url, url_length ? url_length : -1, &url_length))) {
1559         SetLastError(ERROR_OUTOFMEMORY);
1560         ret = FALSE;
1561     }
1562 
1563     if (ret && (ret = InternetCrackUrlW(url_w, url_length, flags, &comp))) {
1564         ret_comp->nScheme = comp.nScheme;
1565         ret_comp->nPort = comp.nPort;
1566 
1567         ret = set_url_component_WtoA(comp.lpszHostName, comp.dwHostNameLength, url_w,
1568                                      &ret_comp->lpszHostName, &ret_comp->dwHostNameLength, url)
1569             && set_url_component_WtoA(comp.lpszUserName, comp.dwUserNameLength, url_w,
1570                                       &ret_comp->lpszUserName, &ret_comp->dwUserNameLength, url)
1571             && set_url_component_WtoA(comp.lpszPassword, comp.dwPasswordLength, url_w,
1572                                       &ret_comp->lpszPassword, &ret_comp->dwPasswordLength, url)
1573             && set_url_component_WtoA(comp.lpszUrlPath, comp.dwUrlPathLength, url_w,
1574                                       &ret_comp->lpszUrlPath, &ret_comp->dwUrlPathLength, url)
1575             && set_url_component_WtoA(comp.lpszScheme, comp.dwSchemeLength, url_w,
1576                                       &ret_comp->lpszScheme, &ret_comp->dwSchemeLength, url)
1577             && set_url_component_WtoA(comp.lpszExtraInfo, comp.dwExtraInfoLength, url_w,
1578                                       &ret_comp->lpszExtraInfo, &ret_comp->dwExtraInfoLength, url);
1579 
1580         if(ret)
1581             TRACE("%s: scheme(%s) host(%s) path(%s) extra(%s)\n", debugstr_a(url),
1582                   debugstr_an(ret_comp->lpszScheme, ret_comp->dwSchemeLength),
1583                   debugstr_an(ret_comp->lpszHostName, ret_comp->dwHostNameLength),
1584                   debugstr_an(ret_comp->lpszUrlPath, ret_comp->dwUrlPathLength),
1585                   debugstr_an(ret_comp->lpszExtraInfo, ret_comp->dwExtraInfoLength));
1586     }
1587 
1588     heap_free(host);
1589     heap_free(user);
1590     heap_free(pass);
1591     heap_free(path);
1592     heap_free(scheme);
1593     heap_free(extra);
1594     heap_free(url_w);
1595     return ret;
1596 }
1597 
1598 static const WCHAR url_schemes[][7] =
1599 {
1600     {'f','t','p',0},
1601     {'g','o','p','h','e','r',0},
1602     {'h','t','t','p',0},
1603     {'h','t','t','p','s',0},
1604     {'f','i','l','e',0},
1605     {'n','e','w','s',0},
1606     {'m','a','i','l','t','o',0},
1607     {'r','e','s',0},
1608 };
1609 
1610 /***********************************************************************
1611  *           GetInternetSchemeW (internal)
1612  *
1613  * Get scheme of url
1614  *
1615  * RETURNS
1616  *    scheme on success
1617  *    INTERNET_SCHEME_UNKNOWN on failure
1618  *
1619  */
1620 static INTERNET_SCHEME GetInternetSchemeW(LPCWSTR lpszScheme, DWORD nMaxCmp)
1621 {
1622     int i;
1623 
1624     TRACE("%s %d\n",debugstr_wn(lpszScheme, nMaxCmp), nMaxCmp);
1625 
1626     if(lpszScheme==NULL)
1627         return INTERNET_SCHEME_UNKNOWN;
1628 
1629     for (i = 0; i < sizeof(url_schemes)/sizeof(url_schemes[0]); i++)
1630         if (!strncmpiW(lpszScheme, url_schemes[i], nMaxCmp))
1631             return INTERNET_SCHEME_FIRST + i;
1632 
1633     return INTERNET_SCHEME_UNKNOWN;
1634 }
1635 
1636 /***********************************************************************
1637  *           InternetCrackUrlW   (WININET.@)
1638  *
1639  * Break up URL into its components
1640  *
1641  * RETURNS
1642  *    TRUE on success
1643  *    FALSE on failure
1644  */
1645 BOOL WINAPI InternetCrackUrlW(const WCHAR *lpszUrl, DWORD dwUrlLength, DWORD dwFlags, URL_COMPONENTSW *lpUC)
1646 {
1647   /*
1648    * RFC 1808
1649    * <protocol>:[//<net_loc>][/path][;<params>][?<query>][#<fragment>]
1650    *
1651    */
1652     LPCWSTR lpszParam    = NULL;
1653     BOOL  found_colon = FALSE;
1654     LPCWSTR lpszap;
1655     LPCWSTR lpszcp = NULL, lpszNetLoc;
1656 
1657     TRACE("(%s %u %x %p)\n",
1658           lpszUrl ? debugstr_wn(lpszUrl, dwUrlLength ? dwUrlLength : strlenW(lpszUrl)) : "(null)",
1659           dwUrlLength, dwFlags, lpUC);
1660 
1661     if (!lpszUrl || !*lpszUrl || !lpUC)
1662     {
1663         SetLastError(ERROR_INVALID_PARAMETER);
1664         return FALSE;
1665     }
1666     if (!dwUrlLength) dwUrlLength = strlenW(lpszUrl);
1667 
1668     if (dwFlags & ICU_DECODE)
1669     {
1670         WCHAR *url_tmp, *buffer;
1671         DWORD len = dwUrlLength + 1;
1672         BOOL ret;
1673 
1674         if (!(url_tmp = heap_strndupW(lpszUrl, dwUrlLength)))
1675         {
1676             SetLastError(ERROR_OUTOFMEMORY);
1677             return FALSE;
1678         }
1679 
1680         buffer = url_tmp;
1681         ret = InternetCanonicalizeUrlW(url_tmp, buffer, &len, ICU_DECODE | ICU_NO_ENCODE);
1682         if (!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
1683         {
1684             buffer = heap_alloc(len * sizeof(WCHAR));
1685             if (!buffer)
1686             {
1687                 SetLastError(ERROR_OUTOFMEMORY);
1688                 heap_free(url_tmp);
1689                 return FALSE;
1690             }
1691             ret = InternetCanonicalizeUrlW(url_tmp, buffer, &len, ICU_DECODE | ICU_NO_ENCODE);
1692         }
1693         if (ret)
1694             ret = InternetCrackUrlW(buffer, len, dwFlags & ~ICU_DECODE, lpUC);
1695 
1696         if (buffer != url_tmp) heap_free(buffer);
1697         heap_free(url_tmp);
1698         return ret;
1699     }
1700     lpszap = lpszUrl;
1701 
1702     /* Determine if the URI is absolute. */
1703     while (lpszap - lpszUrl < dwUrlLength)
1704     {
1705         if (isalnumW(*lpszap) || *lpszap == '+' || *lpszap == '.' || *lpszap == '-')
1706         {
1707             lpszap++;
1708             continue;
1709         }
1710         if (*lpszap == ':')
1711         {
1712             found_colon = TRUE;
1713             lpszcp = lpszap;
1714         }
1715         else
1716         {
1717             lpszcp = lpszUrl; /* Relative url */
1718         }
1719 
1720         break;
1721     }
1722 
1723     if(!found_colon){
1724         SetLastError(ERROR_INTERNET_UNRECOGNIZED_SCHEME);
1725         return FALSE;
1726     }
1727 
1728     lpUC->nScheme = INTERNET_SCHEME_UNKNOWN;
1729     lpUC->nPort = INTERNET_INVALID_PORT_NUMBER;
1730 
1731     /* Parse <params> */
1732     lpszParam = memchrW(lpszap, '?', dwUrlLength - (lpszap - lpszUrl));
1733     if(!lpszParam)
1734         lpszParam = memchrW(lpszap, '#', dwUrlLength - (lpszap - lpszUrl));
1735 
1736     if(!set_url_component(&lpUC->lpszExtraInfo, &lpUC->dwExtraInfoLength,
1737                           lpszParam, lpszParam ? dwUrlLength-(lpszParam-lpszUrl) : 0))
1738         return FALSE;
1739 
1740 
1741     /* Get scheme first. */
1742     lpUC->nScheme = GetInternetSchemeW(lpszUrl, lpszcp - lpszUrl);
1743     if(!set_url_component(&lpUC->lpszScheme, &lpUC->dwSchemeLength, lpszUrl, lpszcp - lpszUrl))
1744         return FALSE;
1745 
1746     /* Eat ':' in protocol. */
1747     lpszcp++;
1748 
1749     /* double slash indicates the net_loc portion is present */
1750     if ((lpszcp[0] == '/') && (lpszcp[1] == '/'))
1751     {
1752         lpszcp += 2;
1753 
1754         lpszNetLoc = memchrW(lpszcp, '/', dwUrlLength - (lpszcp - lpszUrl));
1755         if (lpszParam)
1756         {
1757             if (lpszNetLoc)
1758                 lpszNetLoc = min(lpszNetLoc, lpszParam);
1759             else
1760                 lpszNetLoc = lpszParam;
1761         }
1762         else if (!lpszNetLoc)
1763             lpszNetLoc = lpszcp + dwUrlLength-(lpszcp-lpszUrl);
1764 
1765         /* Parse net-loc */
1766         if (lpszNetLoc)
1767         {
1768             LPCWSTR lpszHost;
1769             LPCWSTR lpszPort;
1770 
1771             /* [<user>[<:password>]@]<host>[:<port>] */
1772             /* First find the user and password if they exist */
1773 
1774             lpszHost = memchrW(lpszcp, '@', dwUrlLength - (lpszcp - lpszUrl));
1775             if (lpszHost == NULL || lpszHost > lpszNetLoc)
1776             {
1777                 /* username and password not specified. */
1778                 set_url_component(&lpUC->lpszUserName, &lpUC->dwUserNameLength, NULL, 0);
1779                 set_url_component(&lpUC->lpszPassword, &lpUC->dwPasswordLength, NULL, 0);
1780             }
1781             else /* Parse out username and password */
1782             {
1783                 LPCWSTR lpszUser = lpszcp;
1784                 LPCWSTR lpszPasswd = lpszHost;
1785 
1786                 while (lpszcp < lpszHost)
1787                 {
1788                     if (*lpszcp == ':')
1789                         lpszPasswd = lpszcp;
1790 
1791                     lpszcp++;
1792                 }
1793 
1794                 if(!set_url_component(&lpUC->lpszUserName, &lpUC->dwUserNameLength, lpszUser, lpszPasswd - lpszUser))
1795                     return FALSE;
1796 
1797                 if (lpszPasswd != lpszHost)
1798                     lpszPasswd++;
1799                 if(!set_url_component(&lpUC->lpszPassword, &lpUC->dwPasswordLength,
1800                                       lpszPasswd == lpszHost ? NULL : lpszPasswd, lpszHost - lpszPasswd))
1801                     return FALSE;
1802 
1803                 lpszcp++; /* Advance to beginning of host */
1804             }
1805 
1806             /* Parse <host><:port> */
1807 
1808             lpszHost = lpszcp;
1809             lpszPort = lpszNetLoc;
1810 
1811             /* special case for res:// URLs: there is no port here, so the host is the
1812                entire string up to the first '/' */
1813             if(lpUC->nScheme==INTERNET_SCHEME_RES)
1814             {
1815                 if(!set_url_component(&lpUC->lpszHostName, &lpUC->dwHostNameLength, lpszHost, lpszPort - lpszHost))
1816                     return FALSE;
1817                 lpszcp=lpszNetLoc;
1818             }
1819             else
1820             {
1821                 while (lpszcp < lpszNetLoc)
1822                 {
1823                     if (*lpszcp == ':')
1824                         lpszPort = lpszcp;
1825 
1826                     lpszcp++;
1827                 }
1828 
1829                 /* If the scheme is "file" and the host is just one letter, it's not a host */
1830                 if(lpUC->nScheme==INTERNET_SCHEME_FILE && lpszPort <= lpszHost+1)
1831                 {
1832                     lpszcp=lpszHost;
1833                     set_url_component(&lpUC->lpszHostName, &lpUC->dwHostNameLength, NULL, 0);
1834                 }
1835                 else
1836                 {
1837                     if(!set_url_component(&lpUC->lpszHostName, &lpUC->dwHostNameLength, lpszHost, lpszPort - lpszHost))
1838                         return FALSE;
1839                     if (lpszPort != lpszNetLoc)
1840                         lpUC->nPort = atoiW(++lpszPort);
1841                     else switch (lpUC->nScheme)
1842                     {
1843                     case INTERNET_SCHEME_HTTP:
1844                         lpUC->nPort = INTERNET_DEFAULT_HTTP_PORT;
1845                         break;
1846                     case INTERNET_SCHEME_HTTPS:
1847                         lpUC->nPort = INTERNET_DEFAULT_HTTPS_PORT;
1848                         break;
1849                     case INTERNET_SCHEME_FTP:
1850                         lpUC->nPort = INTERNET_DEFAULT_FTP_PORT;
1851                         break;
1852                     case INTERNET_SCHEME_GOPHER:
1853                         lpUC->nPort = INTERNET_DEFAULT_GOPHER_PORT;
1854                         break;
1855                     default:
1856                         break;
1857                     }
1858                 }
1859             }
1860         }
1861     }
1862     else
1863     {
1864         set_url_component(&lpUC->lpszUserName, &lpUC->dwUserNameLength, NULL, 0);
1865         set_url_component(&lpUC->lpszPassword, &lpUC->dwPasswordLength, NULL, 0);
1866         set_url_component(&lpUC->lpszHostName, &lpUC->dwHostNameLength, NULL, 0);
1867     }
1868 
1869     /* Here lpszcp points to:
1870      *
1871      * <protocol>:[//<net_loc>][/path][;<params>][?<query>][#<fragment>]
1872      *                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1873      */
1874     if (lpszcp != 0 && lpszcp - lpszUrl < dwUrlLength && (!lpszParam || lpszcp <= lpszParam))
1875     {
1876         DWORD len;
1877 
1878         /* Only truncate the parameter list if it's already been saved
1879          * in lpUC->lpszExtraInfo.
1880          */
1881         if (lpszParam && lpUC->dwExtraInfoLength && lpUC->lpszExtraInfo)
1882             len = lpszParam - lpszcp;
1883         else
1884         {
1885             /* Leave the parameter list in lpszUrlPath.  Strip off any trailing
1886              * newlines if necessary.
1887              */
1888             LPWSTR lpsznewline = memchrW(lpszcp, '\n', dwUrlLength - (lpszcp - lpszUrl));
1889             if (lpsznewline != NULL)
1890                 len = lpsznewline - lpszcp;
1891             else
1892                 len = dwUrlLength-(lpszcp-lpszUrl);
1893         }
1894         if (lpUC->dwUrlPathLength && lpUC->lpszUrlPath &&
1895                 lpUC->nScheme == INTERNET_SCHEME_FILE)
1896         {
1897             WCHAR tmppath[MAX_PATH];
1898             if (*lpszcp == '/')
1899             {
1900                 len = MAX_PATH;
1901                 PathCreateFromUrlW(lpszUrl, tmppath, &len, 0);
1902             }
1903             else
1904             {
1905                 WCHAR *iter;
1906                 memcpy(tmppath, lpszcp, len * sizeof(WCHAR));
1907                 tmppath[len] = '\0';
1908 
1909                 iter = tmppath;
1910                 while (*iter) {
1911                     if (*iter == '/')
1912                         *iter = '\\';
1913                     ++iter;
1914                 }
1915             }
1916             /* if ends in \. or \.. append a backslash */
1917             if (tmppath[len - 1] == '.' &&
1918                     (tmppath[len - 2] == '\\' ||
1919                      (tmppath[len - 2] == '.' && tmppath[len - 3] == '\\')))
1920             {
1921                 if (len < MAX_PATH - 1)
1922                 {
1923                     tmppath[len] = '\\';
1924                     tmppath[len+1] = '\0';
1925                     ++len;
1926                 }
1927             }
1928             if(!set_url_component(&lpUC->lpszUrlPath, &lpUC->dwUrlPathLength, tmppath, len))
1929                 return FALSE;
1930         }
1931         else if(!set_url_component(&lpUC->lpszUrlPath, &lpUC->dwUrlPathLength, lpszcp, len))
1932             return FALSE;
1933     }
1934     else
1935     {
1936         set_url_component(&lpUC->lpszUrlPath, &lpUC->dwUrlPathLength, lpszcp, 0);
1937     }
1938 
1939     TRACE("%s: scheme(%s) host(%s) path(%s) extra(%s)\n", debugstr_wn(lpszUrl,dwUrlLength),
1940              debugstr_wn(lpUC->lpszScheme,lpUC->dwSchemeLength),
1941              debugstr_wn(lpUC->lpszHostName,lpUC->dwHostNameLength),
1942              debugstr_wn(lpUC->lpszUrlPath,lpUC->dwUrlPathLength),
1943              debugstr_wn(lpUC->lpszExtraInfo,lpUC->dwExtraInfoLength));
1944 
1945     return TRUE;
1946 }
1947 
1948 /***********************************************************************
1949  *           InternetAttemptConnect (WININET.@)
1950  *
1951  * Attempt to make a connection to the internet
1952  *
1953  * RETURNS
1954  *    ERROR_SUCCESS on success
1955  *    Error value   on failure
1956  *
1957  */
1958 DWORD WINAPI InternetAttemptConnect(DWORD dwReserved)
1959 {
1960     FIXME("Stub\n");
1961     return ERROR_SUCCESS;
1962 }
1963 
1964 
1965 /***********************************************************************
1966  *           convert_url_canonicalization_flags
1967  *
1968  * Helper for InternetCanonicalizeUrl
1969  *
1970  * PARAMS
1971  *     dwFlags [I] Flags suitable for InternetCanonicalizeUrl
1972  *
1973  * RETURNS
1974  *     Flags suitable for UrlCanonicalize
1975  */
1976 static DWORD convert_url_canonicalization_flags(DWORD dwFlags)
1977 {
1978     DWORD dwUrlFlags = URL_WININET_COMPATIBILITY | URL_ESCAPE_UNSAFE;
1979 
1980     if (dwFlags & ICU_BROWSER_MODE)        dwUrlFlags |= URL_BROWSER_MODE;
1981     if (dwFlags & ICU_DECODE)              dwUrlFlags |= URL_UNESCAPE;
1982     if (dwFlags & ICU_ENCODE_PERCENT)      dwUrlFlags |= URL_ESCAPE_PERCENT;
1983     if (dwFlags & ICU_ENCODE_SPACES_ONLY)  dwUrlFlags |= URL_ESCAPE_SPACES_ONLY;
1984     /* Flip this bit to correspond to URL_ESCAPE_UNSAFE */
1985     if (dwFlags & ICU_NO_ENCODE)           dwUrlFlags ^= URL_ESCAPE_UNSAFE;
1986     if (dwFlags & ICU_NO_META)             dwUrlFlags |= URL_NO_META;
1987 
1988     return dwUrlFlags;
1989 }
1990 
1991 /***********************************************************************
1992  *           InternetCanonicalizeUrlA (WININET.@)
1993  *
1994  * Escape unsafe characters and spaces
1995  *
1996  * RETURNS
1997  *    TRUE on success
1998  *    FALSE on failure
1999  *
2000  */
2001 BOOL WINAPI InternetCanonicalizeUrlA(LPCSTR lpszUrl, LPSTR lpszBuffer,
2002 	LPDWORD lpdwBufferLength, DWORD dwFlags)
2003 {
2004     HRESULT hr;
2005 
2006     TRACE("(%s, %p, %p, 0x%08x) buffer length: %d\n", debugstr_a(lpszUrl), lpszBuffer,
2007         lpdwBufferLength, dwFlags, lpdwBufferLength ? *lpdwBufferLength : -1);
2008 
2009     dwFlags = convert_url_canonicalization_flags(dwFlags);
2010     hr = UrlCanonicalizeA(lpszUrl, lpszBuffer, lpdwBufferLength, dwFlags);
2011     if (hr == E_POINTER) SetLastError(ERROR_INSUFFICIENT_BUFFER);
2012     if (hr == E_INVALIDARG) SetLastError(ERROR_INVALID_PARAMETER);
2013 
2014     return hr == S_OK;
2015 }
2016 
2017 /***********************************************************************
2018  *           InternetCanonicalizeUrlW (WININET.@)
2019  *
2020  * Escape unsafe characters and spaces
2021  *
2022  * RETURNS
2023  *    TRUE on success
2024  *    FALSE on failure
2025  *
2026  */
2027 BOOL WINAPI InternetCanonicalizeUrlW(LPCWSTR lpszUrl, LPWSTR lpszBuffer,
2028     LPDWORD lpdwBufferLength, DWORD dwFlags)
2029 {
2030     HRESULT hr;
2031 
2032     TRACE("(%s, %p, %p, 0x%08x) buffer length: %d\n", debugstr_w(lpszUrl), lpszBuffer,
2033           lpdwBufferLength, dwFlags, lpdwBufferLength ? *lpdwBufferLength : -1);
2034 
2035     dwFlags = convert_url_canonicalization_flags(dwFlags);
2036     hr = UrlCanonicalizeW(lpszUrl, lpszBuffer, lpdwBufferLength, dwFlags);
2037     if (hr == E_POINTER) SetLastError(ERROR_INSUFFICIENT_BUFFER);
2038     if (hr == E_INVALIDARG) SetLastError(ERROR_INVALID_PARAMETER);
2039 
2040     return hr == S_OK;
2041 }
2042 
2043 /* #################################################### */
2044 
2045 static INTERNET_STATUS_CALLBACK set_status_callback(
2046     object_header_t *lpwh, INTERNET_STATUS_CALLBACK callback, BOOL unicode)
2047 {
2048     INTERNET_STATUS_CALLBACK ret;
2049 
2050     if (unicode) lpwh->dwInternalFlags |= INET_CALLBACKW;
2051     else lpwh->dwInternalFlags &= ~INET_CALLBACKW;
2052 
2053     ret = lpwh->lpfnStatusCB;
2054     lpwh->lpfnStatusCB = callback;
2055 
2056     return ret;
2057 }
2058 
2059 /***********************************************************************
2060  *           InternetSetStatusCallbackA (WININET.@)
2061  *
2062  * Sets up a callback function which is called as progress is made
2063  * during an operation.
2064  *
2065  * RETURNS
2066  *    Previous callback or NULL 	on success
2067  *    INTERNET_INVALID_STATUS_CALLBACK  on failure
2068  *
2069  */
2070 INTERNET_STATUS_CALLBACK WINAPI InternetSetStatusCallbackA(
2071 	HINTERNET hInternet ,INTERNET_STATUS_CALLBACK lpfnIntCB)
2072 {
2073     INTERNET_STATUS_CALLBACK retVal;
2074     object_header_t *lpwh;
2075 
2076     TRACE("%p\n", hInternet);
2077 
2078     if (!(lpwh = get_handle_object(hInternet)))
2079         return INTERNET_INVALID_STATUS_CALLBACK;
2080 
2081     retVal = set_status_callback(lpwh, lpfnIntCB, FALSE);
2082 
2083     WININET_Release( lpwh );
2084     return retVal;
2085 }
2086 
2087 /***********************************************************************
2088  *           InternetSetStatusCallbackW (WININET.@)
2089  *
2090  * Sets up a callback function which is called as progress is made
2091  * during an operation.
2092  *
2093  * RETURNS
2094  *    Previous callback or NULL 	on success
2095  *    INTERNET_INVALID_STATUS_CALLBACK  on failure
2096  *
2097  */
2098 INTERNET_STATUS_CALLBACK WINAPI InternetSetStatusCallbackW(
2099 	HINTERNET hInternet ,INTERNET_STATUS_CALLBACK lpfnIntCB)
2100 {
2101     INTERNET_STATUS_CALLBACK retVal;
2102     object_header_t *lpwh;
2103 
2104     TRACE("%p\n", hInternet);
2105 
2106     if (!(lpwh = get_handle_object(hInternet)))
2107         return INTERNET_INVALID_STATUS_CALLBACK;
2108 
2109     retVal = set_status_callback(lpwh, lpfnIntCB, TRUE);
2110 
2111     WININET_Release( lpwh );
2112     return retVal;
2113 }
2114 
2115 /***********************************************************************
2116  *           InternetSetFilePointer (WININET.@)
2117  */
2118 DWORD WINAPI InternetSetFilePointer(HINTERNET hFile, LONG lDistanceToMove,
2119     PVOID pReserved, DWORD dwMoveContext, DWORD_PTR dwContext)
2120 {
2121     FIXME("(%p %d %p %d %lx): stub\n", hFile, lDistanceToMove, pReserved, dwMoveContext, dwContext);
2122     return FALSE;
2123 }
2124 
2125 /***********************************************************************
2126  *           InternetWriteFile (WININET.@)
2127  *
2128  * Write data to an open internet file
2129  *
2130  * RETURNS
2131  *    TRUE  on success
2132  *    FALSE on failure
2133  *
2134  */
2135 BOOL WINAPI InternetWriteFile(HINTERNET hFile, LPCVOID lpBuffer,
2136 	DWORD dwNumOfBytesToWrite, LPDWORD lpdwNumOfBytesWritten)
2137 {
2138     object_header_t *lpwh;
2139     BOOL res;
2140 
2141     TRACE("(%p %p %d %p)\n", hFile, lpBuffer, dwNumOfBytesToWrite, lpdwNumOfBytesWritten);
2142 
2143     lpwh = get_handle_object( hFile );
2144     if (!lpwh) {
2145         WARN("Invalid handle\n");
2146         SetLastError(ERROR_INVALID_HANDLE);
2147         return FALSE;
2148     }
2149 
2150     if(lpwh->vtbl->WriteFile) {
2151         res = lpwh->vtbl->WriteFile(lpwh, lpBuffer, dwNumOfBytesToWrite, lpdwNumOfBytesWritten);
2152     }else {
2153         WARN("No Writefile method.\n");
2154         res = ERROR_INVALID_HANDLE;
2155     }
2156 
2157     WININET_Release( lpwh );
2158 
2159     if(res != ERROR_SUCCESS)
2160         SetLastError(res);
2161     return res == ERROR_SUCCESS;
2162 }
2163 
2164 
2165 /***********************************************************************
2166  *           InternetReadFile (WININET.@)
2167  *
2168  * Read data from an open internet file
2169  *
2170  * RETURNS
2171  *    TRUE  on success
2172  *    FALSE on failure
2173  *
2174  */
2175 BOOL WINAPI InternetReadFile(HINTERNET hFile, LPVOID lpBuffer,
2176         DWORD dwNumOfBytesToRead, LPDWORD pdwNumOfBytesRead)
2177 {
2178     object_header_t *hdr;
2179     DWORD res = ERROR_INTERNET_INCORRECT_HANDLE_TYPE;
2180 
2181     TRACE("%p %p %d %p\n", hFile, lpBuffer, dwNumOfBytesToRead, pdwNumOfBytesRead);
2182 
2183     hdr = get_handle_object(hFile);
2184     if (!hdr) {
2185         INTERNET_SetLastError(ERROR_INVALID_HANDLE);
2186         return FALSE;
2187     }
2188 
2189     if(hdr->vtbl->ReadFile) {
2190         res = hdr->vtbl->ReadFile(hdr, lpBuffer, dwNumOfBytesToRead, pdwNumOfBytesRead, 0, 0);
2191         if(res == ERROR_IO_PENDING)
2192             *pdwNumOfBytesRead = 0;
2193     }
2194 
2195     WININET_Release(hdr);
2196 
2197     TRACE("-- %s (%u) (bytes read: %d)\n", res == ERROR_SUCCESS ? "TRUE": "FALSE", res,
2198           pdwNumOfBytesRead ? *pdwNumOfBytesRead : -1);
2199 
2200     if(res != ERROR_SUCCESS)
2201         SetLastError(res);
2202     return res == ERROR_SUCCESS;
2203 }
2204 
2205 /***********************************************************************
2206  *           InternetReadFileExA (WININET.@)
2207  *
2208  * Read data from an open internet file
2209  *
2210  * PARAMS
2211  *  hFile         [I] Handle returned by InternetOpenUrl or HttpOpenRequest.
2212  *  lpBuffersOut  [I/O] Buffer.
2213  *  dwFlags       [I] Flags. See notes.
2214  *  dwContext     [I] Context for callbacks.
2215  *
2216  * RETURNS
2217  *    TRUE  on success
2218  *    FALSE on failure
2219  *
2220  * NOTES
2221  *  The parameter dwFlags include zero or more of the following flags:
2222  *|IRF_ASYNC - Makes the call asynchronous.
2223  *|IRF_SYNC - Makes the call synchronous.
2224  *|IRF_USE_CONTEXT - Forces dwContext to be used.
2225  *|IRF_NO_WAIT - Don't block if the data is not available, just return what is available.
2226  *
2227  * However, in testing IRF_USE_CONTEXT seems to have no effect - dwContext isn't used.
2228  *
2229  * SEE
2230  *  InternetOpenUrlA(), HttpOpenRequestA()
2231  */
2232 BOOL WINAPI InternetReadFileExA(HINTERNET hFile, LPINTERNET_BUFFERSA lpBuffersOut,
2233 	DWORD dwFlags, DWORD_PTR dwContext)
2234 {
2235     object_header_t *hdr;
2236     DWORD res = ERROR_INTERNET_INCORRECT_HANDLE_TYPE;
2237 
2238     TRACE("(%p %p 0x%x 0x%lx)\n", hFile, lpBuffersOut, dwFlags, dwContext);
2239 
2240     if (lpBuffersOut->dwStructSize != sizeof(*lpBuffersOut)) {
2241         SetLastError(ERROR_INVALID_PARAMETER);
2242         return FALSE;
2243     }
2244 
2245     hdr = get_handle_object(hFile);
2246     if (!hdr) {
2247         INTERNET_SetLastError(ERROR_INVALID_HANDLE);
2248         return FALSE;
2249     }
2250 
2251     if(hdr->vtbl->ReadFile)
2252         res = hdr->vtbl->ReadFile(hdr, lpBuffersOut->lpvBuffer, lpBuffersOut->dwBufferLength,
2253                 &lpBuffersOut->dwBufferLength, dwFlags, dwContext);
2254 
2255     WININET_Release(hdr);
2256 
2257     TRACE("-- %s (%u, bytes read: %d)\n", res == ERROR_SUCCESS ? "TRUE": "FALSE",
2258           res, lpBuffersOut->dwBufferLength);
2259 
2260     if(res != ERROR_SUCCESS)
2261         SetLastError(res);
2262     return res == ERROR_SUCCESS;
2263 }
2264 
2265 /***********************************************************************
2266  *           InternetReadFileExW (WININET.@)
2267  * SEE
2268  *  InternetReadFileExA()
2269  */
2270 BOOL WINAPI InternetReadFileExW(HINTERNET hFile, LPINTERNET_BUFFERSW lpBuffer,
2271 	DWORD dwFlags, DWORD_PTR dwContext)
2272 {
2273     object_header_t *hdr;
2274     DWORD res = ERROR_INTERNET_INCORRECT_HANDLE_TYPE;
2275 
2276     TRACE("(%p %p 0x%x 0x%lx)\n", hFile, lpBuffer, dwFlags, dwContext);
2277 
2278     if (!lpBuffer || lpBuffer->dwStructSize != sizeof(*lpBuffer)) {
2279         SetLastError(ERROR_INVALID_PARAMETER);
2280         return FALSE;
2281     }
2282 
2283     hdr = get_handle_object(hFile);
2284     if (!hdr) {
2285         INTERNET_SetLastError(ERROR_INVALID_HANDLE);
2286         return FALSE;
2287     }
2288 
2289     if(hdr->vtbl->ReadFile)
2290         res = hdr->vtbl->ReadFile(hdr, lpBuffer->lpvBuffer, lpBuffer->dwBufferLength, &lpBuffer->dwBufferLength,
2291                 dwFlags, dwContext);
2292 
2293     WININET_Release(hdr);
2294 
2295     TRACE("-- %s (%u, bytes read: %d)\n", res == ERROR_SUCCESS ? "TRUE": "FALSE",
2296           res, lpBuffer->dwBufferLength);
2297 
2298     if(res != ERROR_SUCCESS)
2299         SetLastError(res);
2300     return res == ERROR_SUCCESS;
2301 }
2302 
2303 static WCHAR *get_proxy_autoconfig_url(void)
2304 {
2305 #if defined(MAC_OS_X_VERSION_10_6) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
2306 
2307     CFDictionaryRef settings = CFNetworkCopySystemProxySettings();
2308     WCHAR *ret = NULL;
2309     SIZE_T len;
2310     const void *ref;
2311 
2312     if (!settings) return NULL;
2313 
2314     if (!(ref = CFDictionaryGetValue( settings, kCFNetworkProxiesProxyAutoConfigURLString )))
2315     {
2316         CFRelease( settings );
2317         return NULL;
2318     }
2319     len = CFStringGetLength( ref );
2320     if (len)
2321         ret = heap_alloc( (len+1) * sizeof(WCHAR) );
2322     if (ret)
2323     {
2324         CFStringGetCharacters( ref, CFRangeMake(0, len), ret );
2325         ret[len] = 0;
2326     }
2327     TRACE( "returning %s\n", debugstr_w(ret) );
2328     CFRelease( settings );
2329     return ret;
2330 #else
2331     static int once;
2332     if (!once++) FIXME( "no support on this platform\n" );
2333     return NULL;
2334 #endif
2335 }
2336 
2337 static DWORD query_global_option(DWORD option, void *buffer, DWORD *size, BOOL unicode)
2338 {
2339     /* FIXME: This function currently handles more options than it should. Options requiring
2340      * proper handles should be moved to proper functions */
2341     switch(option) {
2342     case INTERNET_OPTION_HTTP_VERSION:
2343         if (*size < sizeof(HTTP_VERSION_INFO))
2344             return ERROR_INSUFFICIENT_BUFFER;
2345 
2346         /*
2347          * Presently hardcoded to 1.1
2348          */
2349         ((HTTP_VERSION_INFO*)buffer)->dwMajorVersion = 1;
2350         ((HTTP_VERSION_INFO*)buffer)->dwMinorVersion = 1;
2351         *size = sizeof(HTTP_VERSION_INFO);
2352 
2353         return ERROR_SUCCESS;
2354 
2355     case INTERNET_OPTION_CONNECTED_STATE:
2356         FIXME("INTERNET_OPTION_CONNECTED_STATE: semi-stub\n");
2357 
2358         if (*size < sizeof(ULONG))
2359             return ERROR_INSUFFICIENT_BUFFER;
2360 
2361         *(ULONG*)buffer = INTERNET_STATE_CONNECTED;
2362         *size = sizeof(ULONG);
2363 
2364         return ERROR_SUCCESS;
2365 
2366     case INTERNET_OPTION_PROXY: {
2367         appinfo_t ai;
2368         BOOL ret;
2369 
2370         TRACE("Getting global proxy info\n");
2371         memset(&ai, 0, sizeof(appinfo_t));
2372         INTERNET_ConfigureProxy(&ai);
2373 
2374         ret = APPINFO_QueryOption(&ai.hdr, INTERNET_OPTION_PROXY, buffer, size, unicode); /* FIXME */
2375         APPINFO_Destroy(&ai.hdr);
2376         return ret;
2377     }
2378 
2379     case INTERNET_OPTION_MAX_CONNS_PER_SERVER:
2380         TRACE("INTERNET_OPTION_MAX_CONNS_PER_SERVER\n");
2381 
2382         if (*size < sizeof(ULONG))
2383             return ERROR_INSUFFICIENT_BUFFER;
2384 
2385         *(ULONG*)buffer = max_conns;
2386         *size = sizeof(ULONG);
2387 
2388         return ERROR_SUCCESS;
2389 
2390     case INTERNET_OPTION_MAX_CONNS_PER_1_0_SERVER:
2391             TRACE("INTERNET_OPTION_MAX_CONNS_1_0_SERVER\n");
2392 
2393             if (*size < sizeof(ULONG))
2394                 return ERROR_INSUFFICIENT_BUFFER;
2395 
2396             *(ULONG*)buffer = max_1_0_conns;
2397             *size = sizeof(ULONG);
2398 
2399             return ERROR_SUCCESS;
2400 
2401     case INTERNET_OPTION_SECURITY_FLAGS:
2402         FIXME("INTERNET_OPTION_SECURITY_FLAGS: Stub\n");
2403         return ERROR_SUCCESS;
2404 
2405     case INTERNET_OPTION_VERSION: {
2406         static const INTERNET_VERSION_INFO info = { 1, 2 };
2407 
2408         TRACE("INTERNET_OPTION_VERSION\n");
2409 
2410         if (*size < sizeof(INTERNET_VERSION_INFO))
2411             return ERROR_INSUFFICIENT_BUFFER;
2412 
2413         memcpy(buffer, &info, sizeof(info));
2414         *size = sizeof(info);
2415 
2416         return ERROR_SUCCESS;
2417     }
2418 
2419     case INTERNET_OPTION_PER_CONNECTION_OPTION: {
2420         WCHAR *url;
2421         INTERNET_PER_CONN_OPTION_LISTW *con = buffer;
2422         INTERNET_PER_CONN_OPTION_LISTA *conA = buffer;
2423         DWORD res = ERROR_SUCCESS, i;
2424         proxyinfo_t pi;
2425         LONG ret;
2426 
2427         TRACE("Getting global proxy info\n");
2428         if((ret = INTERNET_LoadProxySettings(&pi)))
2429             return ret;
2430 
2431 #ifdef __REACTOS__
2432         WARN("INTERNET_OPTION_PER_CONNECTION_OPTION stub\n");
2433 #else
2434         FIXME("INTERNET_OPTION_PER_CONNECTION_OPTION stub\n");
2435 #endif
2436 
2437         if (*size < sizeof(INTERNET_PER_CONN_OPTION_LISTW)) {
2438             FreeProxyInfo(&pi);
2439             return ERROR_INSUFFICIENT_BUFFER;
2440         }
2441 
2442         url = get_proxy_autoconfig_url();
2443 
2444         for (i = 0; i < con->dwOptionCount; i++) {
2445             INTERNET_PER_CONN_OPTIONW *optionW = con->pOptions + i;
2446             INTERNET_PER_CONN_OPTIONA *optionA = conA->pOptions + i;
2447 
2448             switch (optionW->dwOption) {
2449             case INTERNET_PER_CONN_FLAGS:
2450                 if(pi.proxyEnabled)
2451                     optionW->Value.dwValue = PROXY_TYPE_PROXY;
2452                 else
2453                     optionW->Value.dwValue = PROXY_TYPE_DIRECT;
2454                 if (url)
2455                     /* native includes PROXY_TYPE_DIRECT even if PROXY_TYPE_PROXY is set */
2456                     optionW->Value.dwValue |= PROXY_TYPE_DIRECT|PROXY_TYPE_AUTO_PROXY_URL;
2457                 break;
2458 
2459             case INTERNET_PER_CONN_PROXY_SERVER:
2460                 if (unicode)
2461                     optionW->Value.pszValue = heap_strdupW(pi.proxy);
2462                 else
2463                     optionA->Value.pszValue = heap_strdupWtoA(pi.proxy);
2464                 break;
2465 
2466             case INTERNET_PER_CONN_PROXY_BYPASS:
2467                 if (unicode)
2468                     optionW->Value.pszValue = heap_strdupW(pi.proxyBypass);
2469                 else
2470                     optionA->Value.pszValue = heap_strdupWtoA(pi.proxyBypass);
2471                 break;
2472 
2473             case INTERNET_PER_CONN_AUTOCONFIG_URL:
2474                 if (!url)
2475                     optionW->Value.pszValue = NULL;
2476                 else if (unicode)
2477                     optionW->Value.pszValue = heap_strdupW(url);
2478                 else
2479                     optionA->Value.pszValue = heap_strdupWtoA(url);
2480                 break;
2481 
2482             case INTERNET_PER_CONN_AUTODISCOVERY_FLAGS:
2483                 optionW->Value.dwValue = AUTO_PROXY_FLAG_ALWAYS_DETECT;
2484                 break;
2485 
2486             case INTERNET_PER_CONN_AUTOCONFIG_SECONDARY_URL:
2487             case INTERNET_PER_CONN_AUTOCONFIG_RELOAD_DELAY_MINS:
2488             case INTERNET_PER_CONN_AUTOCONFIG_LAST_DETECT_TIME:
2489             case INTERNET_PER_CONN_AUTOCONFIG_LAST_DETECT_URL:
2490                 FIXME("Unhandled dwOption %d\n", optionW->dwOption);
2491                 memset(&optionW->Value, 0, sizeof(optionW->Value));
2492                 break;
2493 
2494 #ifdef __REACTOS__
2495             case INTERNET_PER_CONN_FLAGS_UI:
2496                 WARN("Unhandled dwOption %d\n", optionW->dwOption);
2497                 break;
2498 
2499 #endif
2500             default:
2501                 FIXME("Unknown dwOption %d\n", optionW->dwOption);
2502                 res = ERROR_INVALID_PARAMETER;
2503                 break;
2504             }
2505         }
2506         heap_free(url);
2507         FreeProxyInfo(&pi);
2508 
2509         return res;
2510     }
2511     case INTERNET_OPTION_REQUEST_FLAGS:
2512     case INTERNET_OPTION_USER_AGENT:
2513         *size = 0;
2514         return ERROR_INTERNET_INCORRECT_HANDLE_TYPE;
2515     case INTERNET_OPTION_POLICY:
2516         return ERROR_INVALID_PARAMETER;
2517     case INTERNET_OPTION_CONNECT_TIMEOUT:
2518         TRACE("INTERNET_OPTION_CONNECT_TIMEOUT\n");
2519 
2520         if (*size < sizeof(ULONG))
2521             return ERROR_INSUFFICIENT_BUFFER;
2522 
2523         *(ULONG*)buffer = connect_timeout;
2524         *size = sizeof(ULONG);
2525 
2526         return ERROR_SUCCESS;
2527     }
2528 
2529     FIXME("Stub for %d\n", option);
2530     return ERROR_INTERNET_INCORRECT_HANDLE_TYPE;
2531 }
2532 
2533 DWORD INET_QueryOption(object_header_t *hdr, DWORD option, void *buffer, DWORD *size, BOOL unicode)
2534 {
2535     switch(option) {
2536     case INTERNET_OPTION_CONTEXT_VALUE:
2537         if (!size)
2538             return ERROR_INVALID_PARAMETER;
2539 
2540         if (*size < sizeof(DWORD_PTR)) {
2541             *size = sizeof(DWORD_PTR);
2542             return ERROR_INSUFFICIENT_BUFFER;
2543         }
2544         if (!buffer)
2545             return ERROR_INVALID_PARAMETER;
2546 
2547         *(DWORD_PTR *)buffer = hdr->dwContext;
2548         *size = sizeof(DWORD_PTR);
2549         return ERROR_SUCCESS;
2550 
2551     case INTERNET_OPTION_REQUEST_FLAGS:
2552         WARN("INTERNET_OPTION_REQUEST_FLAGS\n");
2553         *size = sizeof(DWORD);
2554         return ERROR_INTERNET_INCORRECT_HANDLE_TYPE;
2555 
2556     case INTERNET_OPTION_MAX_CONNS_PER_SERVER:
2557     case INTERNET_OPTION_MAX_CONNS_PER_1_0_SERVER:
2558         WARN("Called on global option %u\n", option);
2559         return ERROR_INTERNET_INVALID_OPERATION;
2560     }
2561 
2562     /* FIXME: we shouldn't call it here */
2563     return query_global_option(option, buffer, size, unicode);
2564 }
2565 
2566 /***********************************************************************
2567  *           InternetQueryOptionW (WININET.@)
2568  *
2569  * Queries an options on the specified handle
2570  *
2571  * RETURNS
2572  *    TRUE  on success
2573  *    FALSE on failure
2574  *
2575  */
2576 BOOL WINAPI InternetQueryOptionW(HINTERNET hInternet, DWORD dwOption,
2577                                  LPVOID lpBuffer, LPDWORD lpdwBufferLength)
2578 {
2579     object_header_t *hdr;
2580     DWORD res = ERROR_INVALID_HANDLE;
2581 
2582     TRACE("%p %d %p %p\n", hInternet, dwOption, lpBuffer, lpdwBufferLength);
2583 
2584     if(hInternet) {
2585         hdr = get_handle_object(hInternet);
2586         if (hdr) {
2587             res = hdr->vtbl->QueryOption(hdr, dwOption, lpBuffer, lpdwBufferLength, TRUE);
2588             WININET_Release(hdr);
2589         }
2590     }else {
2591         res = query_global_option(dwOption, lpBuffer, lpdwBufferLength, TRUE);
2592     }
2593 
2594     if(res != ERROR_SUCCESS)
2595         SetLastError(res);
2596     return res == ERROR_SUCCESS;
2597 }
2598 
2599 /***********************************************************************
2600  *           InternetQueryOptionA (WININET.@)
2601  *
2602  * Queries an options on the specified handle
2603  *
2604  * RETURNS
2605  *    TRUE  on success
2606  *    FALSE on failure
2607  *
2608  */
2609 BOOL WINAPI InternetQueryOptionA(HINTERNET hInternet, DWORD dwOption,
2610                                  LPVOID lpBuffer, LPDWORD lpdwBufferLength)
2611 {
2612     object_header_t *hdr;
2613     DWORD res = ERROR_INVALID_HANDLE;
2614 
2615     TRACE("%p %d %p %p\n", hInternet, dwOption, lpBuffer, lpdwBufferLength);
2616 
2617     if(hInternet) {
2618         hdr = get_handle_object(hInternet);
2619         if (hdr) {
2620             res = hdr->vtbl->QueryOption(hdr, dwOption, lpBuffer, lpdwBufferLength, FALSE);
2621             WININET_Release(hdr);
2622         }
2623     }else {
2624         res = query_global_option(dwOption, lpBuffer, lpdwBufferLength, FALSE);
2625     }
2626 
2627     if(res != ERROR_SUCCESS)
2628         SetLastError(res);
2629     return res == ERROR_SUCCESS;
2630 }
2631 
2632 DWORD INET_SetOption(object_header_t *hdr, DWORD option, void *buf, DWORD size)
2633 {
2634     switch(option) {
2635     case INTERNET_OPTION_SETTINGS_CHANGED:
2636         FIXME("INTERNETOPTION_SETTINGS_CHANGED semi-stub\n");
2637         collect_connections(COLLECT_CONNECTIONS);
2638         return ERROR_SUCCESS;
2639     case INTERNET_OPTION_CALLBACK:
2640         WARN("Not settable option %u\n", option);
2641         return ERROR_INTERNET_OPTION_NOT_SETTABLE;
2642     case INTERNET_OPTION_MAX_CONNS_PER_SERVER:
2643     case INTERNET_OPTION_MAX_CONNS_PER_1_0_SERVER:
2644         WARN("Called on global option %u\n", option);
2645         return ERROR_INTERNET_INVALID_OPERATION;
2646     case INTERNET_OPTION_REFRESH:
2647         return ERROR_INTERNET_INCORRECT_HANDLE_TYPE;
2648     }
2649 
2650     return ERROR_INTERNET_INVALID_OPTION;
2651 }
2652 
2653 static DWORD set_global_option(DWORD option, void *buf, DWORD size)
2654 {
2655     switch(option) {
2656     case INTERNET_OPTION_CALLBACK:
2657         WARN("Not global option %u\n", option);
2658         return ERROR_INTERNET_INCORRECT_HANDLE_TYPE;
2659 
2660     case INTERNET_OPTION_MAX_CONNS_PER_SERVER:
2661         TRACE("INTERNET_OPTION_MAX_CONNS_PER_SERVER\n");
2662 
2663         if(size != sizeof(max_conns))
2664             return ERROR_INTERNET_BAD_OPTION_LENGTH;
2665         if(!*(ULONG*)buf)
2666             return ERROR_BAD_ARGUMENTS;
2667 
2668         max_conns = *(ULONG*)buf;
2669         return ERROR_SUCCESS;
2670 
2671     case INTERNET_OPTION_MAX_CONNS_PER_1_0_SERVER:
2672         TRACE("INTERNET_OPTION_MAX_CONNS_PER_1_0_SERVER\n");
2673 
2674         if(size != sizeof(max_1_0_conns))
2675             return ERROR_INTERNET_BAD_OPTION_LENGTH;
2676         if(!*(ULONG*)buf)
2677             return ERROR_BAD_ARGUMENTS;
2678 
2679         max_1_0_conns = *(ULONG*)buf;
2680         return ERROR_SUCCESS;
2681 
2682     case INTERNET_OPTION_CONNECT_TIMEOUT:
2683         TRACE("INTERNET_OPTION_CONNECT_TIMEOUT\n");
2684 
2685         if(size != sizeof(connect_timeout))
2686             return ERROR_INTERNET_BAD_OPTION_LENGTH;
2687         if(!*(ULONG*)buf)
2688             return ERROR_BAD_ARGUMENTS;
2689 
2690         connect_timeout = *(ULONG*)buf;
2691         return ERROR_SUCCESS;
2692 
2693     case INTERNET_OPTION_SUPPRESS_BEHAVIOR:
2694         FIXME("INTERNET_OPTION_SUPPRESS_BEHAVIOR stub\n");
2695 
2696         if(size != sizeof(ULONG))
2697             return ERROR_INTERNET_BAD_OPTION_LENGTH;
2698 
2699         FIXME("%08x\n", *(ULONG*)buf);
2700         return ERROR_SUCCESS;
2701     }
2702 
2703     return INET_SetOption(NULL, option, buf, size);
2704 }
2705 
2706 /***********************************************************************
2707  *           InternetSetOptionW (WININET.@)
2708  *
2709  * Sets an options on the specified handle
2710  *
2711  * RETURNS
2712  *    TRUE  on success
2713  *    FALSE on failure
2714  *
2715  */
2716 BOOL WINAPI InternetSetOptionW(HINTERNET hInternet, DWORD dwOption,
2717                            LPVOID lpBuffer, DWORD dwBufferLength)
2718 {
2719     object_header_t *lpwhh;
2720     BOOL ret = TRUE;
2721     DWORD res;
2722 
2723     TRACE("(%p %d %p %d)\n", hInternet, dwOption, lpBuffer, dwBufferLength);
2724 
2725     lpwhh = (object_header_t*) get_handle_object( hInternet );
2726     if(lpwhh)
2727         res = lpwhh->vtbl->SetOption(lpwhh, dwOption, lpBuffer, dwBufferLength);
2728     else
2729         res = set_global_option(dwOption, lpBuffer, dwBufferLength);
2730 
2731     if(res != ERROR_INTERNET_INVALID_OPTION) {
2732         if(lpwhh)
2733             WININET_Release(lpwhh);
2734 
2735         if(res != ERROR_SUCCESS)
2736             SetLastError(res);
2737 
2738         return res == ERROR_SUCCESS;
2739     }
2740 
2741     switch (dwOption)
2742     {
2743     case INTERNET_OPTION_HTTP_VERSION:
2744       {
2745         HTTP_VERSION_INFO* pVersion=(HTTP_VERSION_INFO*)lpBuffer;
2746         FIXME("Option INTERNET_OPTION_HTTP_VERSION(%d,%d): STUB\n",pVersion->dwMajorVersion,pVersion->dwMinorVersion);
2747       }
2748       break;
2749     case INTERNET_OPTION_ERROR_MASK:
2750       {
2751         if(!lpwhh) {
2752             SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
2753             return FALSE;
2754         } else if(*(ULONG*)lpBuffer & (~(INTERNET_ERROR_MASK_INSERT_CDROM|
2755                         INTERNET_ERROR_MASK_COMBINED_SEC_CERT|
2756                         INTERNET_ERROR_MASK_LOGIN_FAILURE_DISPLAY_ENTITY_BODY))) {
2757             SetLastError(ERROR_INVALID_PARAMETER);
2758             ret = FALSE;
2759         } else if(dwBufferLength != sizeof(ULONG)) {
2760             SetLastError(ERROR_INTERNET_BAD_OPTION_LENGTH);
2761             ret = FALSE;
2762         } else
2763             TRACE("INTERNET_OPTION_ERROR_MASK: %x\n", *(ULONG*)lpBuffer);
2764             lpwhh->ErrorMask = *(ULONG*)lpBuffer;
2765       }
2766       break;
2767     case INTERNET_OPTION_PROXY:
2768     {
2769         INTERNET_PROXY_INFOW *info = lpBuffer;
2770 
2771         if (!lpBuffer || dwBufferLength < sizeof(INTERNET_PROXY_INFOW))
2772         {
2773             SetLastError(ERROR_INVALID_PARAMETER);
2774             return FALSE;
2775         }
2776         if (!hInternet)
2777         {
2778             EnterCriticalSection( &WININET_cs );
2779             free_global_proxy();
2780             global_proxy = heap_alloc( sizeof(proxyinfo_t) );
2781             if (global_proxy)
2782             {
2783                 if (info->dwAccessType == INTERNET_OPEN_TYPE_PROXY)
2784                 {
2785                     global_proxy->proxyEnabled = 1;
2786                     global_proxy->proxy = heap_strdupW( info->lpszProxy );
2787                     global_proxy->proxyBypass = heap_strdupW( info->lpszProxyBypass );
2788                 }
2789                 else
2790                 {
2791                     global_proxy->proxyEnabled = 0;
2792                     global_proxy->proxy = global_proxy->proxyBypass = NULL;
2793                 }
2794             }
2795             LeaveCriticalSection( &WININET_cs );
2796         }
2797         else
2798         {
2799             /* In general, each type of object should handle
2800              * INTERNET_OPTION_PROXY directly.  This FIXME ensures it doesn't
2801              * get silently dropped.
2802              */
2803             FIXME("INTERNET_OPTION_PROXY unimplemented\n");
2804             SetLastError(ERROR_INTERNET_INVALID_OPTION);
2805             ret = FALSE;
2806         }
2807         break;
2808     }
2809     case INTERNET_OPTION_CODEPAGE:
2810       {
2811         ULONG codepage = *(ULONG *)lpBuffer;
2812         FIXME("Option INTERNET_OPTION_CODEPAGE (%d): STUB\n", codepage);
2813       }
2814       break;
2815     case INTERNET_OPTION_REQUEST_PRIORITY:
2816       {
2817         ULONG priority = *(ULONG *)lpBuffer;
2818         FIXME("Option INTERNET_OPTION_REQUEST_PRIORITY (%d): STUB\n", priority);
2819       }
2820       break;
2821     case INTERNET_OPTION_CONNECT_TIMEOUT:
2822       {
2823         ULONG connecttimeout = *(ULONG *)lpBuffer;
2824         FIXME("Option INTERNET_OPTION_CONNECT_TIMEOUT (%d): STUB\n", connecttimeout);
2825       }
2826       break;
2827     case INTERNET_OPTION_DATA_RECEIVE_TIMEOUT:
2828       {
2829         ULONG receivetimeout = *(ULONG *)lpBuffer;
2830         FIXME("Option INTERNET_OPTION_DATA_RECEIVE_TIMEOUT (%d): STUB\n", receivetimeout);
2831       }
2832       break;
2833     case INTERNET_OPTION_RESET_URLCACHE_SESSION:
2834         FIXME("Option INTERNET_OPTION_RESET_URLCACHE_SESSION: STUB\n");
2835         break;
2836     case INTERNET_OPTION_END_BROWSER_SESSION:
2837         FIXME("Option INTERNET_OPTION_END_BROWSER_SESSION: semi-stub\n");
2838         free_cookie();
2839         break;
2840     case INTERNET_OPTION_CONNECTED_STATE:
2841         FIXME("Option INTERNET_OPTION_CONNECTED_STATE: STUB\n");
2842         break;
2843     case INTERNET_OPTION_DISABLE_PASSPORT_AUTH:
2844 	TRACE("Option INTERNET_OPTION_DISABLE_PASSPORT_AUTH: harmless stub, since not enabled\n");
2845 	break;
2846     case INTERNET_OPTION_SEND_TIMEOUT:
2847     case INTERNET_OPTION_RECEIVE_TIMEOUT:
2848     case INTERNET_OPTION_DATA_SEND_TIMEOUT:
2849     {
2850         ULONG timeout = *(ULONG *)lpBuffer;
2851         FIXME("INTERNET_OPTION_SEND/RECEIVE_TIMEOUT/DATA_SEND_TIMEOUT %d\n", timeout);
2852         break;
2853     }
2854     case INTERNET_OPTION_CONNECT_RETRIES:
2855     {
2856         ULONG retries = *(ULONG *)lpBuffer;
2857         FIXME("INTERNET_OPTION_CONNECT_RETRIES %d\n", retries);
2858         break;
2859     }
2860     case INTERNET_OPTION_CONTEXT_VALUE:
2861     {
2862         if (!lpwhh)
2863         {
2864             SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
2865             return FALSE;
2866         }
2867         if (!lpBuffer || dwBufferLength != sizeof(DWORD_PTR))
2868         {
2869             SetLastError(ERROR_INVALID_PARAMETER);
2870             ret = FALSE;
2871         }
2872         else
2873             lpwhh->dwContext = *(DWORD_PTR *)lpBuffer;
2874         break;
2875     }
2876     case INTERNET_OPTION_SECURITY_FLAGS:
2877 	 FIXME("Option INTERNET_OPTION_SECURITY_FLAGS; STUB\n");
2878 	 break;
2879     case INTERNET_OPTION_DISABLE_AUTODIAL:
2880 	 FIXME("Option INTERNET_OPTION_DISABLE_AUTODIAL; STUB\n");
2881 	 break;
2882     case INTERNET_OPTION_HTTP_DECODING:
2883     {
2884         if (!lpwhh)
2885         {
2886             SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
2887             return FALSE;
2888         }
2889         if (!lpBuffer || dwBufferLength != sizeof(BOOL))
2890         {
2891             SetLastError(ERROR_INVALID_PARAMETER);
2892             ret = FALSE;
2893         }
2894         else
2895             lpwhh->decoding = *(BOOL *)lpBuffer;
2896         break;
2897     }
2898     case INTERNET_OPTION_COOKIES_3RD_PARTY:
2899         FIXME("INTERNET_OPTION_COOKIES_3RD_PARTY; STUB\n");
2900         SetLastError(ERROR_INTERNET_INVALID_OPTION);
2901         ret = FALSE;
2902         break;
2903     case INTERNET_OPTION_SEND_UTF8_SERVERNAME_TO_PROXY:
2904         FIXME("INTERNET_OPTION_SEND_UTF8_SERVERNAME_TO_PROXY; STUB\n");
2905         SetLastError(ERROR_INTERNET_INVALID_OPTION);
2906         ret = FALSE;
2907         break;
2908     case INTERNET_OPTION_CODEPAGE_PATH:
2909         FIXME("INTERNET_OPTION_CODEPAGE_PATH; STUB\n");
2910         SetLastError(ERROR_INTERNET_INVALID_OPTION);
2911         ret = FALSE;
2912         break;
2913     case INTERNET_OPTION_CODEPAGE_EXTRA:
2914         FIXME("INTERNET_OPTION_CODEPAGE_EXTRA; STUB\n");
2915         SetLastError(ERROR_INTERNET_INVALID_OPTION);
2916         ret = FALSE;
2917         break;
2918     case INTERNET_OPTION_IDN:
2919         FIXME("INTERNET_OPTION_IDN; STUB\n");
2920         SetLastError(ERROR_INTERNET_INVALID_OPTION);
2921         ret = FALSE;
2922         break;
2923     case INTERNET_OPTION_POLICY:
2924         SetLastError(ERROR_INVALID_PARAMETER);
2925         ret = FALSE;
2926         break;
2927     case INTERNET_OPTION_PER_CONNECTION_OPTION: {
2928         INTERNET_PER_CONN_OPTION_LISTW *con = lpBuffer;
2929         LONG res;
2930         unsigned int i;
2931         proxyinfo_t pi;
2932 
2933         if (INTERNET_LoadProxySettings(&pi)) return FALSE;
2934 
2935         for (i = 0; i < con->dwOptionCount; i++) {
2936             INTERNET_PER_CONN_OPTIONW *option = con->pOptions + i;
2937 
2938             switch (option->dwOption) {
2939             case INTERNET_PER_CONN_PROXY_SERVER:
2940                 heap_free(pi.proxy);
2941                 pi.proxy = heap_strdupW(option->Value.pszValue);
2942                 break;
2943 
2944             case INTERNET_PER_CONN_FLAGS:
2945                 if(option->Value.dwValue & PROXY_TYPE_PROXY)
2946                     pi.proxyEnabled = 1;
2947                 else
2948                 {
2949                     if(option->Value.dwValue != PROXY_TYPE_DIRECT)
2950                         FIXME("Unhandled flags: 0x%x\n", option->Value.dwValue);
2951                     pi.proxyEnabled = 0;
2952                 }
2953                 break;
2954 
2955             case INTERNET_PER_CONN_PROXY_BYPASS:
2956                 heap_free(pi.proxyBypass);
2957                 pi.proxyBypass = heap_strdupW(option->Value.pszValue);
2958                 break;
2959 
2960             case INTERNET_PER_CONN_AUTOCONFIG_URL:
2961             case INTERNET_PER_CONN_AUTODISCOVERY_FLAGS:
2962             case INTERNET_PER_CONN_AUTOCONFIG_SECONDARY_URL:
2963             case INTERNET_PER_CONN_AUTOCONFIG_RELOAD_DELAY_MINS:
2964             case INTERNET_PER_CONN_AUTOCONFIG_LAST_DETECT_TIME:
2965             case INTERNET_PER_CONN_AUTOCONFIG_LAST_DETECT_URL:
2966                 FIXME("Unhandled dwOption %d\n", option->dwOption);
2967                 break;
2968 
2969             default:
2970                 FIXME("Unknown dwOption %d\n", option->dwOption);
2971                 SetLastError(ERROR_INVALID_PARAMETER);
2972                 break;
2973             }
2974         }
2975 
2976         if ((res = INTERNET_SaveProxySettings(&pi)))
2977             SetLastError(res);
2978 
2979         FreeProxyInfo(&pi);
2980 
2981         ret = (res == ERROR_SUCCESS);
2982         break;
2983         }
2984     default:
2985         FIXME("Option %d STUB\n",dwOption);
2986         SetLastError(ERROR_INTERNET_INVALID_OPTION);
2987         ret = FALSE;
2988         break;
2989     }
2990 
2991     if(lpwhh)
2992         WININET_Release( lpwhh );
2993 
2994     return ret;
2995 }
2996 
2997 
2998 /***********************************************************************
2999  *           InternetSetOptionA (WININET.@)
3000  *
3001  * Sets an options on the specified handle.
3002  *
3003  * RETURNS
3004  *    TRUE  on success
3005  *    FALSE on failure
3006  *
3007  */
3008 BOOL WINAPI InternetSetOptionA(HINTERNET hInternet, DWORD dwOption,
3009                            LPVOID lpBuffer, DWORD dwBufferLength)
3010 {
3011     LPVOID wbuffer;
3012     DWORD wlen;
3013     BOOL r;
3014 
3015     switch( dwOption )
3016     {
3017     case INTERNET_OPTION_PROXY:
3018         {
3019         LPINTERNET_PROXY_INFOA pi = (LPINTERNET_PROXY_INFOA) lpBuffer;
3020         LPINTERNET_PROXY_INFOW piw;
3021         DWORD proxlen, prbylen;
3022         LPWSTR prox, prby;
3023 
3024         proxlen = MultiByteToWideChar( CP_ACP, 0, pi->lpszProxy, -1, NULL, 0);
3025         prbylen= MultiByteToWideChar( CP_ACP, 0, pi->lpszProxyBypass, -1, NULL, 0);
3026         wlen = sizeof(*piw) + proxlen + prbylen;
3027         wbuffer = heap_alloc(wlen*sizeof(WCHAR) );
3028         piw = (LPINTERNET_PROXY_INFOW) wbuffer;
3029         piw->dwAccessType = pi->dwAccessType;
3030         prox = (LPWSTR) &piw[1];
3031         prby = &prox[proxlen+1];
3032         MultiByteToWideChar( CP_ACP, 0, pi->lpszProxy, -1, prox, proxlen);
3033         MultiByteToWideChar( CP_ACP, 0, pi->lpszProxyBypass, -1, prby, prbylen);
3034         piw->lpszProxy = prox;
3035         piw->lpszProxyBypass = prby;
3036         }
3037         break;
3038     case INTERNET_OPTION_USER_AGENT:
3039     case INTERNET_OPTION_USERNAME:
3040     case INTERNET_OPTION_PASSWORD:
3041     case INTERNET_OPTION_PROXY_USERNAME:
3042     case INTERNET_OPTION_PROXY_PASSWORD:
3043         wlen = MultiByteToWideChar( CP_ACP, 0, lpBuffer, -1, NULL, 0 );
3044         if (!(wbuffer = heap_alloc( wlen * sizeof(WCHAR) ))) return ERROR_OUTOFMEMORY;
3045         MultiByteToWideChar( CP_ACP, 0, lpBuffer, -1, wbuffer, wlen );
3046         break;
3047     case INTERNET_OPTION_PER_CONNECTION_OPTION: {
3048         unsigned int i;
3049         INTERNET_PER_CONN_OPTION_LISTW *listW;
3050         INTERNET_PER_CONN_OPTION_LISTA *listA = lpBuffer;
3051         wlen = sizeof(INTERNET_PER_CONN_OPTION_LISTW);
3052         wbuffer = heap_alloc(wlen);
3053         listW = wbuffer;
3054 
3055         listW->dwSize = sizeof(INTERNET_PER_CONN_OPTION_LISTW);
3056         if (listA->pszConnection)
3057         {
3058             wlen = MultiByteToWideChar( CP_ACP, 0, listA->pszConnection, -1, NULL, 0 );
3059             listW->pszConnection = heap_alloc(wlen*sizeof(WCHAR));
3060             MultiByteToWideChar( CP_ACP, 0, listA->pszConnection, -1, listW->pszConnection, wlen );
3061         }
3062         else
3063             listW->pszConnection = NULL;
3064         listW->dwOptionCount = listA->dwOptionCount;
3065         listW->dwOptionError = listA->dwOptionError;
3066         listW->pOptions = heap_alloc(sizeof(INTERNET_PER_CONN_OPTIONW) * listA->dwOptionCount);
3067 
3068         for (i = 0; i < listA->dwOptionCount; ++i) {
3069             INTERNET_PER_CONN_OPTIONA *optA = listA->pOptions + i;
3070             INTERNET_PER_CONN_OPTIONW *optW = listW->pOptions + i;
3071 
3072             optW->dwOption = optA->dwOption;
3073 
3074             switch (optA->dwOption) {
3075             case INTERNET_PER_CONN_AUTOCONFIG_URL:
3076             case INTERNET_PER_CONN_PROXY_BYPASS:
3077             case INTERNET_PER_CONN_PROXY_SERVER:
3078             case INTERNET_PER_CONN_AUTOCONFIG_SECONDARY_URL:
3079             case INTERNET_PER_CONN_AUTOCONFIG_LAST_DETECT_URL:
3080                 if (optA->Value.pszValue)
3081                 {
3082                     wlen = MultiByteToWideChar( CP_ACP, 0, optA->Value.pszValue, -1, NULL, 0 );
3083                     optW->Value.pszValue = heap_alloc(wlen*sizeof(WCHAR));
3084                     MultiByteToWideChar( CP_ACP, 0, optA->Value.pszValue, -1, optW->Value.pszValue, wlen );
3085                 }
3086                 else
3087                     optW->Value.pszValue = NULL;
3088                 break;
3089             case INTERNET_PER_CONN_AUTODISCOVERY_FLAGS:
3090             case INTERNET_PER_CONN_FLAGS:
3091             case INTERNET_PER_CONN_AUTOCONFIG_RELOAD_DELAY_MINS:
3092                 optW->Value.dwValue = optA->Value.dwValue;
3093                 break;
3094             case INTERNET_PER_CONN_AUTOCONFIG_LAST_DETECT_TIME:
3095                 optW->Value.ftValue = optA->Value.ftValue;
3096                 break;
3097             default:
3098                 WARN("Unknown PER_CONN dwOption: %d, guessing at conversion to Wide\n", optA->dwOption);
3099                 optW->Value.dwValue = optA->Value.dwValue;
3100                 break;
3101             }
3102         }
3103         }
3104         break;
3105     default:
3106         wbuffer = lpBuffer;
3107         wlen = dwBufferLength;
3108     }
3109 
3110     r = InternetSetOptionW(hInternet,dwOption, wbuffer, wlen);
3111 
3112     if( lpBuffer != wbuffer )
3113     {
3114         if (dwOption == INTERNET_OPTION_PER_CONNECTION_OPTION)
3115         {
3116             INTERNET_PER_CONN_OPTION_LISTW *list = wbuffer;
3117             unsigned int i;
3118             for (i = 0; i < list->dwOptionCount; ++i) {
3119                 INTERNET_PER_CONN_OPTIONW *opt = list->pOptions + i;
3120                 switch (opt->dwOption) {
3121                 case INTERNET_PER_CONN_AUTOCONFIG_URL:
3122                 case INTERNET_PER_CONN_PROXY_BYPASS:
3123                 case INTERNET_PER_CONN_PROXY_SERVER:
3124                 case INTERNET_PER_CONN_AUTOCONFIG_SECONDARY_URL:
3125                 case INTERNET_PER_CONN_AUTOCONFIG_LAST_DETECT_URL:
3126                     heap_free( opt->Value.pszValue );
3127                     break;
3128                 default:
3129                     break;
3130                 }
3131             }
3132             heap_free( list->pOptions );
3133         }
3134         heap_free( wbuffer );
3135     }
3136 
3137     return r;
3138 }
3139 
3140 
3141 /***********************************************************************
3142  *           InternetSetOptionExA (WININET.@)
3143  */
3144 BOOL WINAPI InternetSetOptionExA(HINTERNET hInternet, DWORD dwOption,
3145                            LPVOID lpBuffer, DWORD dwBufferLength, DWORD dwFlags)
3146 {
3147     FIXME("Flags %08x ignored\n", dwFlags);
3148     return InternetSetOptionA( hInternet, dwOption, lpBuffer, dwBufferLength );
3149 }
3150 
3151 /***********************************************************************
3152  *           InternetSetOptionExW (WININET.@)
3153  */
3154 BOOL WINAPI InternetSetOptionExW(HINTERNET hInternet, DWORD dwOption,
3155                            LPVOID lpBuffer, DWORD dwBufferLength, DWORD dwFlags)
3156 {
3157     FIXME("Flags %08x ignored\n", dwFlags);
3158     if( dwFlags & ~ISO_VALID_FLAGS )
3159     {
3160         SetLastError( ERROR_INVALID_PARAMETER );
3161         return FALSE;
3162     }
3163     return InternetSetOptionW( hInternet, dwOption, lpBuffer, dwBufferLength );
3164 }
3165 
3166 static const WCHAR WININET_wkday[7][4] =
3167     { { 'S','u','n', 0 }, { 'M','o','n', 0 }, { 'T','u','e', 0 }, { 'W','e','d', 0 },
3168       { 'T','h','u', 0 }, { 'F','r','i', 0 }, { 'S','a','t', 0 } };
3169 static const WCHAR WININET_month[12][4] =
3170     { { 'J','a','n', 0 }, { 'F','e','b', 0 }, { 'M','a','r', 0 }, { 'A','p','r', 0 },
3171       { 'M','a','y', 0 }, { 'J','u','n', 0 }, { 'J','u','l', 0 }, { 'A','u','g', 0 },
3172       { 'S','e','p', 0 }, { 'O','c','t', 0 }, { 'N','o','v', 0 }, { 'D','e','c', 0 } };
3173 
3174 /***********************************************************************
3175  *           InternetTimeFromSystemTimeA (WININET.@)
3176  */
3177 BOOL WINAPI InternetTimeFromSystemTimeA( const SYSTEMTIME* time, DWORD format, LPSTR string, DWORD size )
3178 {
3179     BOOL ret;
3180     WCHAR stringW[INTERNET_RFC1123_BUFSIZE];
3181 
3182     TRACE( "%p 0x%08x %p 0x%08x\n", time, format, string, size );
3183 
3184     if (!time || !string || format != INTERNET_RFC1123_FORMAT)
3185     {
3186         SetLastError(ERROR_INVALID_PARAMETER);
3187         return FALSE;
3188     }
3189 
3190     if (size < INTERNET_RFC1123_BUFSIZE * sizeof(*string))
3191     {
3192         SetLastError(ERROR_INSUFFICIENT_BUFFER);
3193         return FALSE;
3194     }
3195 
3196     ret = InternetTimeFromSystemTimeW( time, format, stringW, sizeof(stringW) );
3197     if (ret) WideCharToMultiByte( CP_ACP, 0, stringW, -1, string, size, NULL, NULL );
3198 
3199     return ret;
3200 }
3201 
3202 /***********************************************************************
3203  *           InternetTimeFromSystemTimeW (WININET.@)
3204  */
3205 BOOL WINAPI InternetTimeFromSystemTimeW( const SYSTEMTIME* time, DWORD format, LPWSTR string, DWORD size )
3206 {
3207     static const WCHAR date[] =
3208         { '%','s',',',' ','%','0','2','d',' ','%','s',' ','%','4','d',' ','%','0',
3209           '2','d',':','%','0','2','d',':','%','0','2','d',' ','G','M','T', 0 };
3210 
3211     TRACE( "%p 0x%08x %p 0x%08x\n", time, format, string, size );
3212 
3213     if (!time || !string || format != INTERNET_RFC1123_FORMAT)
3214     {
3215         SetLastError(ERROR_INVALID_PARAMETER);
3216         return FALSE;
3217     }
3218 
3219     if (size < INTERNET_RFC1123_BUFSIZE * sizeof(*string))
3220     {
3221         SetLastError(ERROR_INSUFFICIENT_BUFFER);
3222         return FALSE;
3223     }
3224 
3225     sprintfW( string, date,
3226               WININET_wkday[time->wDayOfWeek],
3227               time->wDay,
3228               WININET_month[time->wMonth - 1],
3229               time->wYear,
3230               time->wHour,
3231               time->wMinute,
3232               time->wSecond );
3233 
3234     return TRUE;
3235 }
3236 
3237 /***********************************************************************
3238  *           InternetTimeToSystemTimeA (WININET.@)
3239  */
3240 BOOL WINAPI InternetTimeToSystemTimeA( LPCSTR string, SYSTEMTIME* time, DWORD reserved )
3241 {
3242     BOOL ret = FALSE;
3243     WCHAR *stringW;
3244 
3245     TRACE( "%s %p 0x%08x\n", debugstr_a(string), time, reserved );
3246 
3247     stringW = heap_strdupAtoW(string);
3248     if (stringW)
3249     {
3250         ret = InternetTimeToSystemTimeW( stringW, time, reserved );
3251         heap_free( stringW );
3252     }
3253     return ret;
3254 }
3255 
3256 /***********************************************************************
3257  *           InternetTimeToSystemTimeW (WININET.@)
3258  */
3259 BOOL WINAPI InternetTimeToSystemTimeW( LPCWSTR string, SYSTEMTIME* time, DWORD reserved )
3260 {
3261     unsigned int i;
3262     const WCHAR *s = string;
3263     WCHAR       *end;
3264 
3265     TRACE( "%s %p 0x%08x\n", debugstr_w(string), time, reserved );
3266 
3267     if (!string || !time) return FALSE;
3268 
3269     /* Windows does this too */
3270     GetSystemTime( time );
3271 
3272     /*  Convert an RFC1123 time such as 'Fri, 07 Jan 2005 12:06:35 GMT' into
3273      *  a SYSTEMTIME structure.
3274      */
3275 
3276     while (*s && !isalphaW( *s )) s++;
3277     if (s[0] == '\0' || s[1] == '\0' || s[2] == '\0') return TRUE;
3278     time->wDayOfWeek = 7;
3279 
3280     for (i = 0; i < 7; i++)
3281     {
3282         if (toupperW( WININET_wkday[i][0] ) == toupperW( s[0] ) &&
3283             toupperW( WININET_wkday[i][1] ) == toupperW( s[1] ) &&
3284             toupperW( WININET_wkday[i][2] ) == toupperW( s[2] ) )
3285         {
3286             time->wDayOfWeek = i;
3287             break;
3288         }
3289     }
3290 
3291     if (time->wDayOfWeek > 6) return TRUE;
3292     while (*s && !isdigitW( *s )) s++;
3293     time->wDay = strtolW( s, &end, 10 );
3294     s = end;
3295 
3296     while (*s && !isalphaW( *s )) s++;
3297     if (s[0] == '\0' || s[1] == '\0' || s[2] == '\0') return TRUE;
3298     time->wMonth = 0;
3299 
3300     for (i = 0; i < 12; i++)
3301     {
3302         if (toupperW( WININET_month[i][0]) == toupperW( s[0] ) &&
3303             toupperW( WININET_month[i][1]) == toupperW( s[1] ) &&
3304             toupperW( WININET_month[i][2]) == toupperW( s[2] ) )
3305         {
3306             time->wMonth = i + 1;
3307             break;
3308         }
3309     }
3310     if (time->wMonth == 0) return TRUE;
3311 
3312     while (*s && !isdigitW( *s )) s++;
3313     if (*s == '\0') return TRUE;
3314     time->wYear = strtolW( s, &end, 10 );
3315     s = end;
3316 
3317     while (*s && !isdigitW( *s )) s++;
3318     if (*s == '\0') return TRUE;
3319     time->wHour = strtolW( s, &end, 10 );
3320     s = end;
3321 
3322     while (*s && !isdigitW( *s )) s++;
3323     if (*s == '\0') return TRUE;
3324     time->wMinute = strtolW( s, &end, 10 );
3325     s = end;
3326 
3327     while (*s && !isdigitW( *s )) s++;
3328     if (*s == '\0') return TRUE;
3329     time->wSecond = strtolW( s, &end, 10 );
3330     s = end;
3331 
3332     time->wMilliseconds = 0;
3333     return TRUE;
3334 }
3335 
3336 /***********************************************************************
3337  *	InternetCheckConnectionW (WININET.@)
3338  *
3339  * Pings a requested host to check internet connection
3340  *
3341  * RETURNS
3342  *   TRUE on success and FALSE on failure. If a failure then
3343  *   ERROR_NOT_CONNECTED is placed into GetLastError
3344  *
3345  */
3346 BOOL WINAPI InternetCheckConnectionW( LPCWSTR lpszUrl, DWORD dwFlags, DWORD dwReserved )
3347 {
3348 /*
3349  * this is a kludge which runs the resident ping program and reads the output.
3350  *
3351  * Anyone have a better idea?
3352  */
3353 
3354   BOOL   rc = FALSE;
3355   static const CHAR ping[] = "ping -c 1 ";
3356   static const CHAR redirect[] = " >/dev/null 2>/dev/null";
3357   WCHAR *host;
3358   DWORD len, host_len;
3359   INTERNET_PORT port;
3360   int status = -1;
3361 
3362   FIXME("(%s %x %x)\n", debugstr_w(lpszUrl), dwFlags, dwReserved);
3363 
3364   /*
3365    * Crack or set the Address
3366    */
3367   if (lpszUrl == NULL)
3368   {
3369      /*
3370       * According to the doc we are supposed to use the ip for the next
3371       * server in the WnInet internal server database. I have
3372       * no idea what that is or how to get it.
3373       *
3374       * So someone needs to implement this.
3375       */
3376      FIXME("Unimplemented with URL of NULL\n");
3377      return TRUE;
3378   }
3379   else
3380   {
3381      URL_COMPONENTSW components = {sizeof(components)};
3382 
3383      components.dwHostNameLength = 1;
3384 
3385      if (!InternetCrackUrlW(lpszUrl,0,0,&components))
3386        goto End;
3387 
3388      host = components.lpszHostName;
3389      host_len = components.dwHostNameLength;
3390      port = components.nPort;
3391      TRACE("host name: %s port: %d\n",debugstr_wn(host, host_len), port);
3392   }
3393 
3394   if (dwFlags & FLAG_ICC_FORCE_CONNECTION)
3395   {
3396       struct sockaddr_storage saddr;
3397       int sa_len = sizeof(saddr);
3398       WCHAR *host_z;
3399       int fd;
3400       BOOL b;
3401 
3402       host_z = heap_strndupW(host, host_len);
3403       if (!host_z)
3404           return FALSE;
3405 
3406       b = GetAddress(host_z, port, (struct sockaddr *)&saddr, &sa_len, NULL);
3407       heap_free(host_z);
3408       if(!b)
3409           goto End;
3410       init_winsock();
3411       fd = socket(saddr.ss_family, SOCK_STREAM, 0);
3412       if (fd != -1)
3413       {
3414           if (connect(fd, (struct sockaddr *)&saddr, sa_len) == 0)
3415               rc = TRUE;
3416           closesocket(fd);
3417       }
3418   }
3419   else
3420   {
3421       /*
3422        * Build our ping command
3423        */
3424       char *command;
3425 
3426       len = WideCharToMultiByte(CP_UNIXCP, 0, host, host_len, NULL, 0, NULL, NULL);
3427       command = heap_alloc(strlen(ping)+len+strlen(redirect)+1);
3428       strcpy(command, ping);
3429       WideCharToMultiByte(CP_UNIXCP, 0, host, host_len, command+sizeof(ping)-1, len, NULL, NULL);
3430       strcpy(command+sizeof(ping)-1+len, redirect);
3431 
3432       TRACE("Ping command is : %s\n",command);
3433 
3434       status = system(command);
3435       heap_free( command );
3436 
3437       TRACE("Ping returned a code of %i\n",status);
3438 
3439       /* Ping return code of 0 indicates success */
3440       if (status == 0)
3441          rc = TRUE;
3442   }
3443 
3444 End:
3445   if (rc == FALSE)
3446     INTERNET_SetLastError(ERROR_NOT_CONNECTED);
3447 
3448   return rc;
3449 }
3450 
3451 
3452 /***********************************************************************
3453  *	InternetCheckConnectionA (WININET.@)
3454  *
3455  * Pings a requested host to check internet connection
3456  *
3457  * RETURNS
3458  *   TRUE on success and FALSE on failure. If a failure then
3459  *   ERROR_NOT_CONNECTED is placed into GetLastError
3460  *
3461  */
3462 BOOL WINAPI InternetCheckConnectionA(LPCSTR lpszUrl, DWORD dwFlags, DWORD dwReserved)
3463 {
3464     WCHAR *url = NULL;
3465     BOOL rc;
3466 
3467     if(lpszUrl) {
3468         url = heap_strdupAtoW(lpszUrl);
3469         if(!url)
3470             return FALSE;
3471     }
3472 
3473     rc = InternetCheckConnectionW(url, dwFlags, dwReserved);
3474 
3475     heap_free(url);
3476     return rc;
3477 }
3478 
3479 
3480 /**********************************************************
3481  *	INTERNET_InternetOpenUrlW (internal)
3482  *
3483  * Opens an URL
3484  *
3485  * RETURNS
3486  *   handle of connection or NULL on failure
3487  */
3488 static HINTERNET INTERNET_InternetOpenUrlW(appinfo_t *hIC, LPCWSTR lpszUrl,
3489     LPCWSTR lpszHeaders, DWORD dwHeadersLength, DWORD dwFlags, DWORD_PTR dwContext)
3490 {
3491     URL_COMPONENTSW urlComponents = { sizeof(urlComponents) };
3492     WCHAR *host, *user = NULL, *pass = NULL, *path;
3493     HINTERNET client = NULL, client1 = NULL;
3494     DWORD res;
3495 
3496     TRACE("(%p, %s, %s, %08x, %08x, %08lx)\n", hIC, debugstr_w(lpszUrl), debugstr_w(lpszHeaders),
3497 	  dwHeadersLength, dwFlags, dwContext);
3498 
3499     urlComponents.dwHostNameLength = 1;
3500     urlComponents.dwUserNameLength = 1;
3501     urlComponents.dwPasswordLength = 1;
3502     urlComponents.dwUrlPathLength = 1;
3503     urlComponents.dwExtraInfoLength = 1;
3504     if(!InternetCrackUrlW(lpszUrl, strlenW(lpszUrl), 0, &urlComponents))
3505 	return NULL;
3506 
3507     if ((urlComponents.nScheme == INTERNET_SCHEME_HTTP || urlComponents.nScheme == INTERNET_SCHEME_HTTPS) &&
3508         urlComponents.dwExtraInfoLength)
3509     {
3510         assert(urlComponents.lpszUrlPath + urlComponents.dwUrlPathLength == urlComponents.lpszExtraInfo);
3511         urlComponents.dwUrlPathLength += urlComponents.dwExtraInfoLength;
3512     }
3513 
3514     host = heap_strndupW(urlComponents.lpszHostName, urlComponents.dwHostNameLength);
3515     path = heap_strndupW(urlComponents.lpszUrlPath, urlComponents.dwUrlPathLength);
3516     if(urlComponents.dwUserNameLength)
3517         user = heap_strndupW(urlComponents.lpszUserName, urlComponents.dwUserNameLength);
3518     if(urlComponents.dwPasswordLength)
3519         pass = heap_strndupW(urlComponents.lpszPassword, urlComponents.dwPasswordLength);
3520 
3521     switch(urlComponents.nScheme) {
3522     case INTERNET_SCHEME_FTP:
3523 	client = FTP_Connect(hIC, host, urlComponents.nPort,
3524 			     user, pass, dwFlags, dwContext, INET_OPENURL);
3525 	if(client == NULL)
3526 	    break;
3527 	client1 = FtpOpenFileW(client, path, GENERIC_READ, dwFlags, dwContext);
3528 	if(client1 == NULL) {
3529 	    InternetCloseHandle(client);
3530 	    break;
3531 	}
3532 	break;
3533 
3534     case INTERNET_SCHEME_HTTP:
3535     case INTERNET_SCHEME_HTTPS: {
3536 	static const WCHAR szStars[] = { '*','/','*', 0 };
3537 	LPCWSTR accept[2] = { szStars, NULL };
3538 
3539         if (urlComponents.nScheme == INTERNET_SCHEME_HTTPS) dwFlags |= INTERNET_FLAG_SECURE;
3540 
3541         /* FIXME: should use pointers, not handles, as handles are not thread-safe */
3542 	res = HTTP_Connect(hIC, host, urlComponents.nPort,
3543                            user, pass, dwFlags, dwContext, INET_OPENURL, &client);
3544         if(res != ERROR_SUCCESS) {
3545             INTERNET_SetLastError(res);
3546 	    break;
3547         }
3548 
3549         client1 = HttpOpenRequestW(client, NULL, path, NULL, NULL, accept, dwFlags, dwContext);
3550 	if(client1 == NULL) {
3551 	    InternetCloseHandle(client);
3552 	    break;
3553 	}
3554 	HttpAddRequestHeadersW(client1, lpszHeaders, dwHeadersLength, HTTP_ADDREQ_FLAG_ADD);
3555 	if (!HttpSendRequestW(client1, NULL, 0, NULL, 0) &&
3556             GetLastError() != ERROR_IO_PENDING) {
3557 	    InternetCloseHandle(client1);
3558 	    client1 = NULL;
3559 	    break;
3560 	}
3561     }
3562     case INTERNET_SCHEME_GOPHER:
3563 	/* gopher doesn't seem to be implemented in wine, but it's supposed
3564 	 * to be supported by InternetOpenUrlA. */
3565     default:
3566         SetLastError(ERROR_INTERNET_UNRECOGNIZED_SCHEME);
3567 	break;
3568     }
3569 
3570     TRACE(" %p <--\n", client1);
3571 
3572     heap_free(host);
3573     heap_free(path);
3574     heap_free(user);
3575     heap_free(pass);
3576     return client1;
3577 }
3578 
3579 /**********************************************************
3580  *	InternetOpenUrlW (WININET.@)
3581  *
3582  * Opens an URL
3583  *
3584  * RETURNS
3585  *   handle of connection or NULL on failure
3586  */
3587 typedef struct {
3588     task_header_t hdr;
3589     WCHAR *url;
3590     WCHAR *headers;
3591     DWORD headers_len;
3592     DWORD flags;
3593     DWORD_PTR context;
3594 } open_url_task_t;
3595 
3596 static void AsyncInternetOpenUrlProc(task_header_t *hdr)
3597 {
3598     open_url_task_t *task = (open_url_task_t*)hdr;
3599 
3600     TRACE("%p\n", task->hdr.hdr);
3601 
3602     INTERNET_InternetOpenUrlW((appinfo_t*)task->hdr.hdr, task->url, task->headers,
3603             task->headers_len, task->flags, task->context);
3604     heap_free(task->url);
3605     heap_free(task->headers);
3606 }
3607 
3608 HINTERNET WINAPI InternetOpenUrlW(HINTERNET hInternet, LPCWSTR lpszUrl,
3609     LPCWSTR lpszHeaders, DWORD dwHeadersLength, DWORD dwFlags, DWORD_PTR dwContext)
3610 {
3611     HINTERNET ret = NULL;
3612     appinfo_t *hIC = NULL;
3613 
3614     if (TRACE_ON(wininet)) {
3615 	TRACE("(%p, %s, %s, %08x, %08x, %08lx)\n", hInternet, debugstr_w(lpszUrl), debugstr_w(lpszHeaders),
3616 	      dwHeadersLength, dwFlags, dwContext);
3617 	TRACE("  flags :");
3618 	dump_INTERNET_FLAGS(dwFlags);
3619     }
3620 
3621     if (!lpszUrl)
3622     {
3623         SetLastError(ERROR_INVALID_PARAMETER);
3624         goto lend;
3625     }
3626 
3627     hIC = (appinfo_t*)get_handle_object( hInternet );
3628     if (NULL == hIC ||  hIC->hdr.htype != WH_HINIT) {
3629 	SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
3630  	goto lend;
3631     }
3632 
3633     if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC) {
3634 	open_url_task_t *task;
3635 
3636         task = alloc_async_task(&hIC->hdr, AsyncInternetOpenUrlProc, sizeof(*task));
3637         task->url = heap_strdupW(lpszUrl);
3638         task->headers = heap_strdupW(lpszHeaders);
3639         task->headers_len = dwHeadersLength;
3640         task->flags = dwFlags;
3641         task->context = dwContext;
3642 
3643         INTERNET_AsyncCall(&task->hdr);
3644         SetLastError(ERROR_IO_PENDING);
3645     } else {
3646 	ret = INTERNET_InternetOpenUrlW(hIC, lpszUrl, lpszHeaders, dwHeadersLength, dwFlags, dwContext);
3647     }
3648 
3649   lend:
3650     if( hIC )
3651         WININET_Release( &hIC->hdr );
3652     TRACE(" %p <--\n", ret);
3653 
3654     return ret;
3655 }
3656 
3657 /**********************************************************
3658  *	InternetOpenUrlA (WININET.@)
3659  *
3660  * Opens an URL
3661  *
3662  * RETURNS
3663  *   handle of connection or NULL on failure
3664  */
3665 HINTERNET WINAPI InternetOpenUrlA(HINTERNET hInternet, LPCSTR lpszUrl,
3666     LPCSTR lpszHeaders, DWORD dwHeadersLength, DWORD dwFlags, DWORD_PTR dwContext)
3667 {
3668     HINTERNET rc = NULL;
3669     LPWSTR szUrl = NULL;
3670     WCHAR *headers = NULL;
3671 
3672     TRACE("\n");
3673 
3674     if(lpszUrl) {
3675         szUrl = heap_strdupAtoW(lpszUrl);
3676         if(!szUrl)
3677             return NULL;
3678     }
3679 
3680     if(lpszHeaders) {
3681         headers = heap_strndupAtoW(lpszHeaders, dwHeadersLength, &dwHeadersLength);
3682         if(!headers) {
3683             heap_free(szUrl);
3684             return NULL;
3685         }
3686     }
3687 
3688     rc = InternetOpenUrlW(hInternet, szUrl, headers, dwHeadersLength, dwFlags, dwContext);
3689 
3690     heap_free(szUrl);
3691     heap_free(headers);
3692     return rc;
3693 }
3694 
3695 
3696 static LPWITHREADERROR INTERNET_AllocThreadError(void)
3697 {
3698     LPWITHREADERROR lpwite = heap_alloc(sizeof(*lpwite));
3699 
3700     if (lpwite)
3701     {
3702         lpwite->dwError = 0;
3703         lpwite->response[0] = '\0';
3704     }
3705 
3706     if (!TlsSetValue(g_dwTlsErrIndex, lpwite))
3707     {
3708         heap_free(lpwite);
3709         return NULL;
3710     }
3711     return lpwite;
3712 }
3713 
3714 
3715 /***********************************************************************
3716  *           INTERNET_SetLastError (internal)
3717  *
3718  * Set last thread specific error
3719  *
3720  * RETURNS
3721  *
3722  */
3723 void INTERNET_SetLastError(DWORD dwError)
3724 {
3725     LPWITHREADERROR lpwite = TlsGetValue(g_dwTlsErrIndex);
3726 
3727     if (!lpwite)
3728         lpwite = INTERNET_AllocThreadError();
3729 
3730     SetLastError(dwError);
3731     if(lpwite)
3732         lpwite->dwError = dwError;
3733 }
3734 
3735 
3736 /***********************************************************************
3737  *           INTERNET_GetLastError (internal)
3738  *
3739  * Get last thread specific error
3740  *
3741  * RETURNS
3742  *
3743  */
3744 DWORD INTERNET_GetLastError(void)
3745 {
3746     LPWITHREADERROR lpwite = TlsGetValue(g_dwTlsErrIndex);
3747     if (!lpwite) return 0;
3748     /* TlsGetValue clears last error, so set it again here */
3749     SetLastError(lpwite->dwError);
3750     return lpwite->dwError;
3751 }
3752 
3753 
3754 /***********************************************************************
3755  *           INTERNET_WorkerThreadFunc (internal)
3756  *
3757  * Worker thread execution function
3758  *
3759  * RETURNS
3760  *
3761  */
3762 static DWORD CALLBACK INTERNET_WorkerThreadFunc(LPVOID lpvParam)
3763 {
3764     task_header_t *task = lpvParam;
3765 
3766     TRACE("\n");
3767 
3768     task->proc(task);
3769     WININET_Release(task->hdr);
3770     heap_free(task);
3771 
3772     if (g_dwTlsErrIndex != TLS_OUT_OF_INDEXES)
3773     {
3774         heap_free(TlsGetValue(g_dwTlsErrIndex));
3775         TlsSetValue(g_dwTlsErrIndex, NULL);
3776     }
3777     return TRUE;
3778 }
3779 
3780 void *alloc_async_task(object_header_t *hdr, async_task_proc_t proc, size_t size)
3781 {
3782     task_header_t *task;
3783 
3784     task = heap_alloc(size);
3785     if(!task)
3786         return NULL;
3787 
3788     task->hdr = WININET_AddRef(hdr);
3789     task->proc = proc;
3790     return task;
3791 }
3792 
3793 /***********************************************************************
3794  *           INTERNET_AsyncCall (internal)
3795  *
3796  * Retrieves work request from queue
3797  *
3798  * RETURNS
3799  *
3800  */
3801 DWORD INTERNET_AsyncCall(task_header_t *task)
3802 {
3803     BOOL bSuccess;
3804 
3805     TRACE("\n");
3806 
3807     bSuccess = QueueUserWorkItem(INTERNET_WorkerThreadFunc, task, WT_EXECUTELONGFUNCTION);
3808     if (!bSuccess)
3809     {
3810         heap_free(task);
3811         return ERROR_INTERNET_ASYNC_THREAD_FAILED;
3812     }
3813     return ERROR_SUCCESS;
3814 }
3815 
3816 
3817 /***********************************************************************
3818  *          INTERNET_GetResponseBuffer  (internal)
3819  *
3820  * RETURNS
3821  *
3822  */
3823 LPSTR INTERNET_GetResponseBuffer(void)
3824 {
3825     LPWITHREADERROR lpwite = TlsGetValue(g_dwTlsErrIndex);
3826     if (!lpwite)
3827         lpwite = INTERNET_AllocThreadError();
3828     TRACE("\n");
3829     return lpwite->response;
3830 }
3831 
3832 /**********************************************************
3833  *	InternetQueryDataAvailable (WININET.@)
3834  *
3835  * Determines how much data is available to be read.
3836  *
3837  * RETURNS
3838  *   TRUE on success, FALSE if an error occurred. If
3839  *   INTERNET_FLAG_ASYNC was specified in InternetOpen, and
3840  *   no data is presently available, FALSE is returned with
3841  *   the last error ERROR_IO_PENDING; a callback with status
3842  *   INTERNET_STATUS_REQUEST_COMPLETE will be sent when more
3843  *   data is available.
3844  */
3845 BOOL WINAPI InternetQueryDataAvailable( HINTERNET hFile,
3846                                 LPDWORD lpdwNumberOfBytesAvailable,
3847                                 DWORD dwFlags, DWORD_PTR dwContext)
3848 {
3849     object_header_t *hdr;
3850     DWORD res;
3851 
3852     TRACE("(%p %p %x %lx)\n", hFile, lpdwNumberOfBytesAvailable, dwFlags, dwContext);
3853 
3854     hdr = get_handle_object( hFile );
3855     if (!hdr) {
3856         SetLastError(ERROR_INVALID_HANDLE);
3857         return FALSE;
3858     }
3859 
3860     if(hdr->vtbl->QueryDataAvailable) {
3861         res = hdr->vtbl->QueryDataAvailable(hdr, lpdwNumberOfBytesAvailable, dwFlags, dwContext);
3862     }else {
3863         WARN("wrong handle\n");
3864         res = ERROR_INTERNET_INCORRECT_HANDLE_TYPE;
3865     }
3866 
3867     WININET_Release(hdr);
3868 
3869     if(res != ERROR_SUCCESS)
3870         SetLastError(res);
3871     return res == ERROR_SUCCESS;
3872 }
3873 
3874 DWORD create_req_file(const WCHAR *file_name, req_file_t **ret)
3875 {
3876     req_file_t *req_file;
3877 
3878     req_file = heap_alloc_zero(sizeof(*req_file));
3879     if(!req_file)
3880         return ERROR_NOT_ENOUGH_MEMORY;
3881 
3882     req_file->ref = 1;
3883 
3884     req_file->file_name = heap_strdupW(file_name);
3885     if(!req_file->file_name) {
3886         heap_free(req_file);
3887         return ERROR_NOT_ENOUGH_MEMORY;
3888     }
3889 
3890     req_file->file_handle = CreateFileW(req_file->file_name, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE,
3891               NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
3892     if(req_file->file_handle == INVALID_HANDLE_VALUE) {
3893         req_file_release(req_file);
3894         return GetLastError();
3895     }
3896 
3897     *ret = req_file;
3898     return ERROR_SUCCESS;
3899 }
3900 
3901 void req_file_release(req_file_t *req_file)
3902 {
3903     if(InterlockedDecrement(&req_file->ref))
3904         return;
3905 
3906     if(!req_file->is_committed)
3907         DeleteFileW(req_file->file_name);
3908     if(req_file->file_handle && req_file->file_handle != INVALID_HANDLE_VALUE)
3909         CloseHandle(req_file->file_handle);
3910     heap_free(req_file->file_name);
3911     heap_free(req_file->url);
3912     heap_free(req_file);
3913 }
3914 
3915 /***********************************************************************
3916  *      InternetLockRequestFile (WININET.@)
3917  */
3918 BOOL WINAPI InternetLockRequestFile(HINTERNET hInternet, HANDLE *lphLockReqHandle)
3919 {
3920     req_file_t *req_file = NULL;
3921     object_header_t *hdr;
3922     DWORD res;
3923 
3924     TRACE("(%p %p)\n", hInternet, lphLockReqHandle);
3925 
3926     hdr = get_handle_object(hInternet);
3927     if (!hdr) {
3928         SetLastError(ERROR_INVALID_HANDLE);
3929         return FALSE;
3930     }
3931 
3932     if(hdr->vtbl->LockRequestFile) {
3933         res = hdr->vtbl->LockRequestFile(hdr, &req_file);
3934     }else {
3935         WARN("wrong handle\n");
3936         res = ERROR_INTERNET_INCORRECT_HANDLE_TYPE;
3937     }
3938 
3939     WININET_Release(hdr);
3940 
3941     *lphLockReqHandle = req_file;
3942     if(res != ERROR_SUCCESS)
3943         SetLastError(res);
3944     return res == ERROR_SUCCESS;
3945 }
3946 
3947 BOOL WINAPI InternetUnlockRequestFile(HANDLE hLockHandle)
3948 {
3949     TRACE("(%p)\n", hLockHandle);
3950 
3951     req_file_release(hLockHandle);
3952     return TRUE;
3953 }
3954 
3955 
3956 /***********************************************************************
3957  *      InternetAutodial (WININET.@)
3958  *
3959  * On windows this function is supposed to dial the default internet
3960  * connection. We don't want to have Wine dial out to the internet so
3961  * we return TRUE by default. It might be nice to check if we are connected.
3962  *
3963  * RETURNS
3964  *   TRUE on success
3965  *   FALSE on failure
3966  *
3967  */
3968 BOOL WINAPI InternetAutodial(DWORD dwFlags, HWND hwndParent)
3969 {
3970     FIXME("STUB\n");
3971 
3972     /* Tell that we are connected to the internet. */
3973     return TRUE;
3974 }
3975 
3976 /***********************************************************************
3977  *      InternetAutodialHangup (WININET.@)
3978  *
3979  * Hangs up a connection made with InternetAutodial
3980  *
3981  * PARAM
3982  *    dwReserved
3983  * RETURNS
3984  *   TRUE on success
3985  *   FALSE on failure
3986  *
3987  */
3988 BOOL WINAPI InternetAutodialHangup(DWORD dwReserved)
3989 {
3990     FIXME("STUB\n");
3991 
3992     /* we didn't dial, we don't disconnect */
3993     return TRUE;
3994 }
3995 
3996 /***********************************************************************
3997  *      InternetCombineUrlA (WININET.@)
3998  *
3999  * Combine a base URL with a relative URL
4000  *
4001  * RETURNS
4002  *   TRUE on success
4003  *   FALSE on failure
4004  *
4005  */
4006 
4007 BOOL WINAPI InternetCombineUrlA(LPCSTR lpszBaseUrl, LPCSTR lpszRelativeUrl,
4008                                 LPSTR lpszBuffer, LPDWORD lpdwBufferLength,
4009                                 DWORD dwFlags)
4010 {
4011     HRESULT hr=S_OK;
4012 
4013     TRACE("(%s, %s, %p, %p, 0x%08x)\n", debugstr_a(lpszBaseUrl), debugstr_a(lpszRelativeUrl), lpszBuffer, lpdwBufferLength, dwFlags);
4014 
4015     /* Flip this bit to correspond to URL_ESCAPE_UNSAFE */
4016     dwFlags ^= ICU_NO_ENCODE;
4017     hr=UrlCombineA(lpszBaseUrl,lpszRelativeUrl,lpszBuffer,lpdwBufferLength,dwFlags);
4018 
4019     return (hr==S_OK);
4020 }
4021 
4022 /***********************************************************************
4023  *      InternetCombineUrlW (WININET.@)
4024  *
4025  * Combine a base URL with a relative URL
4026  *
4027  * RETURNS
4028  *   TRUE on success
4029  *   FALSE on failure
4030  *
4031  */
4032 
4033 BOOL WINAPI InternetCombineUrlW(LPCWSTR lpszBaseUrl, LPCWSTR lpszRelativeUrl,
4034                                 LPWSTR lpszBuffer, LPDWORD lpdwBufferLength,
4035                                 DWORD dwFlags)
4036 {
4037     HRESULT hr=S_OK;
4038 
4039     TRACE("(%s, %s, %p, %p, 0x%08x)\n", debugstr_w(lpszBaseUrl), debugstr_w(lpszRelativeUrl), lpszBuffer, lpdwBufferLength, dwFlags);
4040 
4041     /* Flip this bit to correspond to URL_ESCAPE_UNSAFE */
4042     dwFlags ^= ICU_NO_ENCODE;
4043     hr=UrlCombineW(lpszBaseUrl,lpszRelativeUrl,lpszBuffer,lpdwBufferLength,dwFlags);
4044 
4045     return (hr==S_OK);
4046 }
4047 
4048 /* max port num is 65535 => 5 digits */
4049 #define MAX_WORD_DIGITS 5
4050 
4051 #define URL_GET_COMP_LENGTH(url, component) ((url)->dw##component##Length ? \
4052     (url)->dw##component##Length : strlenW((url)->lpsz##component))
4053 #define URL_GET_COMP_LENGTHA(url, component) ((url)->dw##component##Length ? \
4054     (url)->dw##component##Length : strlen((url)->lpsz##component))
4055 
4056 static BOOL url_uses_default_port(INTERNET_SCHEME nScheme, INTERNET_PORT nPort)
4057 {
4058     if ((nScheme == INTERNET_SCHEME_HTTP) &&
4059         (nPort == INTERNET_DEFAULT_HTTP_PORT))
4060         return TRUE;
4061     if ((nScheme == INTERNET_SCHEME_HTTPS) &&
4062         (nPort == INTERNET_DEFAULT_HTTPS_PORT))
4063         return TRUE;
4064     if ((nScheme == INTERNET_SCHEME_FTP) &&
4065         (nPort == INTERNET_DEFAULT_FTP_PORT))
4066         return TRUE;
4067     if ((nScheme == INTERNET_SCHEME_GOPHER) &&
4068         (nPort == INTERNET_DEFAULT_GOPHER_PORT))
4069         return TRUE;
4070 
4071     if (nPort == INTERNET_INVALID_PORT_NUMBER)
4072         return TRUE;
4073 
4074     return FALSE;
4075 }
4076 
4077 /* opaque urls do not fit into the standard url hierarchy and don't have
4078  * two following slashes */
4079 static inline BOOL scheme_is_opaque(INTERNET_SCHEME nScheme)
4080 {
4081     return (nScheme != INTERNET_SCHEME_FTP) &&
4082            (nScheme != INTERNET_SCHEME_GOPHER) &&
4083            (nScheme != INTERNET_SCHEME_HTTP) &&
4084            (nScheme != INTERNET_SCHEME_HTTPS) &&
4085            (nScheme != INTERNET_SCHEME_FILE);
4086 }
4087 
4088 static LPCWSTR INTERNET_GetSchemeString(INTERNET_SCHEME scheme)
4089 {
4090     int index;
4091     if (scheme < INTERNET_SCHEME_FIRST)
4092         return NULL;
4093     index = scheme - INTERNET_SCHEME_FIRST;
4094     if (index >= sizeof(url_schemes)/sizeof(url_schemes[0]))
4095         return NULL;
4096     return (LPCWSTR)url_schemes[index];
4097 }
4098 
4099 /* we can calculate using ansi strings because we're just
4100  * calculating string length, not size
4101  */
4102 static BOOL calc_url_length(LPURL_COMPONENTSW lpUrlComponents,
4103                             LPDWORD lpdwUrlLength)
4104 {
4105     INTERNET_SCHEME nScheme;
4106 
4107     *lpdwUrlLength = 0;
4108 
4109     if (lpUrlComponents->lpszScheme)
4110     {
4111         DWORD dwLen = URL_GET_COMP_LENGTH(lpUrlComponents, Scheme);
4112         *lpdwUrlLength += dwLen;
4113         nScheme = GetInternetSchemeW(lpUrlComponents->lpszScheme, dwLen);
4114     }
4115     else
4116     {
4117         LPCWSTR scheme;
4118 
4119         nScheme = lpUrlComponents->nScheme;
4120 
4121         if (nScheme == INTERNET_SCHEME_DEFAULT)
4122             nScheme = INTERNET_SCHEME_HTTP;
4123         scheme = INTERNET_GetSchemeString(nScheme);
4124         *lpdwUrlLength += strlenW(scheme);
4125     }
4126 
4127     (*lpdwUrlLength)++; /* ':' */
4128     if (!scheme_is_opaque(nScheme) || lpUrlComponents->lpszHostName)
4129         *lpdwUrlLength += strlen("//");
4130 
4131     if (lpUrlComponents->lpszUserName)
4132     {
4133         *lpdwUrlLength += URL_GET_COMP_LENGTH(lpUrlComponents, UserName);
4134         *lpdwUrlLength += strlen("@");
4135     }
4136     else
4137     {
4138         if (lpUrlComponents->lpszPassword)
4139         {
4140             INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
4141             return FALSE;
4142         }
4143     }
4144 
4145     if (lpUrlComponents->lpszPassword)
4146     {
4147         *lpdwUrlLength += strlen(":");
4148         *lpdwUrlLength += URL_GET_COMP_LENGTH(lpUrlComponents, Password);
4149     }
4150 
4151     if (lpUrlComponents->lpszHostName)
4152     {
4153         *lpdwUrlLength += URL_GET_COMP_LENGTH(lpUrlComponents, HostName);
4154 
4155         if (!url_uses_default_port(nScheme, lpUrlComponents->nPort))
4156         {
4157             char szPort[MAX_WORD_DIGITS+1];
4158 
4159             *lpdwUrlLength += sprintf(szPort, "%d", lpUrlComponents->nPort);
4160             *lpdwUrlLength += strlen(":");
4161         }
4162 
4163         if (lpUrlComponents->lpszUrlPath && *lpUrlComponents->lpszUrlPath != '/')
4164             (*lpdwUrlLength)++; /* '/' */
4165     }
4166 
4167     if (lpUrlComponents->lpszUrlPath)
4168         *lpdwUrlLength += URL_GET_COMP_LENGTH(lpUrlComponents, UrlPath);
4169 
4170     if (lpUrlComponents->lpszExtraInfo)
4171         *lpdwUrlLength += URL_GET_COMP_LENGTH(lpUrlComponents, ExtraInfo);
4172 
4173     return TRUE;
4174 }
4175 
4176 static void convert_urlcomp_atow(LPURL_COMPONENTSA lpUrlComponents, LPURL_COMPONENTSW urlCompW)
4177 {
4178     INT len;
4179 
4180     ZeroMemory(urlCompW, sizeof(URL_COMPONENTSW));
4181 
4182     urlCompW->dwStructSize = sizeof(URL_COMPONENTSW);
4183     urlCompW->dwSchemeLength = lpUrlComponents->dwSchemeLength;
4184     urlCompW->nScheme = lpUrlComponents->nScheme;
4185     urlCompW->dwHostNameLength = lpUrlComponents->dwHostNameLength;
4186     urlCompW->nPort = lpUrlComponents->nPort;
4187     urlCompW->dwUserNameLength = lpUrlComponents->dwUserNameLength;
4188     urlCompW->dwPasswordLength = lpUrlComponents->dwPasswordLength;
4189     urlCompW->dwUrlPathLength = lpUrlComponents->dwUrlPathLength;
4190     urlCompW->dwExtraInfoLength = lpUrlComponents->dwExtraInfoLength;
4191 
4192     if (lpUrlComponents->lpszScheme)
4193     {
4194         len = URL_GET_COMP_LENGTHA(lpUrlComponents, Scheme) + 1;
4195         urlCompW->lpszScheme = heap_alloc(len * sizeof(WCHAR));
4196         MultiByteToWideChar(CP_ACP, 0, lpUrlComponents->lpszScheme,
4197                             -1, urlCompW->lpszScheme, len);
4198     }
4199 
4200     if (lpUrlComponents->lpszHostName)
4201     {
4202         len = URL_GET_COMP_LENGTHA(lpUrlComponents, HostName) + 1;
4203         urlCompW->lpszHostName = heap_alloc(len * sizeof(WCHAR));
4204         MultiByteToWideChar(CP_ACP, 0, lpUrlComponents->lpszHostName,
4205                             -1, urlCompW->lpszHostName, len);
4206     }
4207 
4208     if (lpUrlComponents->lpszUserName)
4209     {
4210         len = URL_GET_COMP_LENGTHA(lpUrlComponents, UserName) + 1;
4211         urlCompW->lpszUserName = heap_alloc(len * sizeof(WCHAR));
4212         MultiByteToWideChar(CP_ACP, 0, lpUrlComponents->lpszUserName,
4213                             -1, urlCompW->lpszUserName, len);
4214     }
4215 
4216     if (lpUrlComponents->lpszPassword)
4217     {
4218         len = URL_GET_COMP_LENGTHA(lpUrlComponents, Password) + 1;
4219         urlCompW->lpszPassword = heap_alloc(len * sizeof(WCHAR));
4220         MultiByteToWideChar(CP_ACP, 0, lpUrlComponents->lpszPassword,
4221                             -1, urlCompW->lpszPassword, len);
4222     }
4223 
4224     if (lpUrlComponents->lpszUrlPath)
4225     {
4226         len = URL_GET_COMP_LENGTHA(lpUrlComponents, UrlPath) + 1;
4227         urlCompW->lpszUrlPath = heap_alloc(len * sizeof(WCHAR));
4228         MultiByteToWideChar(CP_ACP, 0, lpUrlComponents->lpszUrlPath,
4229                             -1, urlCompW->lpszUrlPath, len);
4230     }
4231 
4232     if (lpUrlComponents->lpszExtraInfo)
4233     {
4234         len = URL_GET_COMP_LENGTHA(lpUrlComponents, ExtraInfo) + 1;
4235         urlCompW->lpszExtraInfo = heap_alloc(len * sizeof(WCHAR));
4236         MultiByteToWideChar(CP_ACP, 0, lpUrlComponents->lpszExtraInfo,
4237                             -1, urlCompW->lpszExtraInfo, len);
4238     }
4239 }
4240 
4241 /***********************************************************************
4242  *      InternetCreateUrlA (WININET.@)
4243  *
4244  * See InternetCreateUrlW.
4245  */
4246 BOOL WINAPI InternetCreateUrlA(LPURL_COMPONENTSA lpUrlComponents, DWORD dwFlags,
4247                                LPSTR lpszUrl, LPDWORD lpdwUrlLength)
4248 {
4249     BOOL ret;
4250     LPWSTR urlW = NULL;
4251     URL_COMPONENTSW urlCompW;
4252 
4253     TRACE("(%p,%d,%p,%p)\n", lpUrlComponents, dwFlags, lpszUrl, lpdwUrlLength);
4254 
4255     if (!lpUrlComponents || lpUrlComponents->dwStructSize != sizeof(URL_COMPONENTSW) || !lpdwUrlLength)
4256     {
4257         SetLastError(ERROR_INVALID_PARAMETER);
4258         return FALSE;
4259     }
4260 
4261     convert_urlcomp_atow(lpUrlComponents, &urlCompW);
4262 
4263     if (lpszUrl)
4264         urlW = heap_alloc(*lpdwUrlLength * sizeof(WCHAR));
4265 
4266     ret = InternetCreateUrlW(&urlCompW, dwFlags, urlW, lpdwUrlLength);
4267 
4268     if (!ret && (GetLastError() == ERROR_INSUFFICIENT_BUFFER))
4269         *lpdwUrlLength /= sizeof(WCHAR);
4270 
4271     /* on success, lpdwUrlLength points to the size of urlW in WCHARS
4272     * minus one, so add one to leave room for NULL terminator
4273     */
4274     if (ret)
4275         WideCharToMultiByte(CP_ACP, 0, urlW, -1, lpszUrl, *lpdwUrlLength + 1, NULL, NULL);
4276 
4277     heap_free(urlCompW.lpszScheme);
4278     heap_free(urlCompW.lpszHostName);
4279     heap_free(urlCompW.lpszUserName);
4280     heap_free(urlCompW.lpszPassword);
4281     heap_free(urlCompW.lpszUrlPath);
4282     heap_free(urlCompW.lpszExtraInfo);
4283     heap_free(urlW);
4284     return ret;
4285 }
4286 
4287 /***********************************************************************
4288  *      InternetCreateUrlW (WININET.@)
4289  *
4290  * Creates a URL from its component parts.
4291  *
4292  * PARAMS
4293  *  lpUrlComponents [I] URL Components.
4294  *  dwFlags         [I] Flags. See notes.
4295  *  lpszUrl         [I] Buffer in which to store the created URL.
4296  *  lpdwUrlLength   [I/O] On input, the length of the buffer pointed to by
4297  *                        lpszUrl in characters. On output, the number of bytes
4298  *                        required to store the URL including terminator.
4299  *
4300  * NOTES
4301  *
4302  * The dwFlags parameter can be zero or more of the following:
4303  *|ICU_ESCAPE - Generates escape sequences for unsafe characters in the path and extra info of the URL.
4304  *
4305  * RETURNS
4306  *   TRUE on success
4307  *   FALSE on failure
4308  *
4309  */
4310 BOOL WINAPI InternetCreateUrlW(LPURL_COMPONENTSW lpUrlComponents, DWORD dwFlags,
4311                                LPWSTR lpszUrl, LPDWORD lpdwUrlLength)
4312 {
4313     DWORD dwLen;
4314     INTERNET_SCHEME nScheme;
4315 
4316     static const WCHAR slashSlashW[] = {'/','/'};
4317     static const WCHAR fmtW[] = {'%','u',0};
4318 
4319     TRACE("(%p,%d,%p,%p)\n", lpUrlComponents, dwFlags, lpszUrl, lpdwUrlLength);
4320 
4321     if (!lpUrlComponents || lpUrlComponents->dwStructSize != sizeof(URL_COMPONENTSW) || !lpdwUrlLength)
4322     {
4323         INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
4324         return FALSE;
4325     }
4326 
4327     if (!calc_url_length(lpUrlComponents, &dwLen))
4328         return FALSE;
4329 
4330     if (!lpszUrl || *lpdwUrlLength < dwLen)
4331     {
4332         *lpdwUrlLength = (dwLen + 1) * sizeof(WCHAR);
4333         INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
4334         return FALSE;
4335     }
4336 
4337     *lpdwUrlLength = dwLen;
4338     lpszUrl[0] = 0x00;
4339 
4340     dwLen = 0;
4341 
4342     if (lpUrlComponents->lpszScheme)
4343     {
4344         dwLen = URL_GET_COMP_LENGTH(lpUrlComponents, Scheme);
4345         memcpy(lpszUrl, lpUrlComponents->lpszScheme, dwLen * sizeof(WCHAR));
4346         lpszUrl += dwLen;
4347 
4348         nScheme = GetInternetSchemeW(lpUrlComponents->lpszScheme, dwLen);
4349     }
4350     else
4351     {
4352         LPCWSTR scheme;
4353         nScheme = lpUrlComponents->nScheme;
4354 
4355         if (nScheme == INTERNET_SCHEME_DEFAULT)
4356             nScheme = INTERNET_SCHEME_HTTP;
4357 
4358         scheme = INTERNET_GetSchemeString(nScheme);
4359         dwLen = strlenW(scheme);
4360         memcpy(lpszUrl, scheme, dwLen * sizeof(WCHAR));
4361         lpszUrl += dwLen;
4362     }
4363 
4364     /* all schemes are followed by at least a colon */
4365     *lpszUrl = ':';
4366     lpszUrl++;
4367 
4368     if (!scheme_is_opaque(nScheme) || lpUrlComponents->lpszHostName)
4369     {
4370         memcpy(lpszUrl, slashSlashW, sizeof(slashSlashW));
4371         lpszUrl += sizeof(slashSlashW)/sizeof(slashSlashW[0]);
4372     }
4373 
4374     if (lpUrlComponents->lpszUserName)
4375     {
4376         dwLen = URL_GET_COMP_LENGTH(lpUrlComponents, UserName);
4377         memcpy(lpszUrl, lpUrlComponents->lpszUserName, dwLen * sizeof(WCHAR));
4378         lpszUrl += dwLen;
4379 
4380         if (lpUrlComponents->lpszPassword)
4381         {
4382             *lpszUrl = ':';
4383             lpszUrl++;
4384 
4385             dwLen = URL_GET_COMP_LENGTH(lpUrlComponents, Password);
4386             memcpy(lpszUrl, lpUrlComponents->lpszPassword, dwLen * sizeof(WCHAR));
4387             lpszUrl += dwLen;
4388         }
4389 
4390         *lpszUrl = '@';
4391         lpszUrl++;
4392     }
4393 
4394     if (lpUrlComponents->lpszHostName)
4395     {
4396         dwLen = URL_GET_COMP_LENGTH(lpUrlComponents, HostName);
4397         memcpy(lpszUrl, lpUrlComponents->lpszHostName, dwLen * sizeof(WCHAR));
4398         lpszUrl += dwLen;
4399 
4400         if (!url_uses_default_port(nScheme, lpUrlComponents->nPort))
4401         {
4402             *lpszUrl = ':';
4403             lpszUrl++;
4404             lpszUrl += sprintfW(lpszUrl, fmtW, lpUrlComponents->nPort);
4405         }
4406 
4407         /* add slash between hostname and path if necessary */
4408         if (lpUrlComponents->lpszUrlPath && *lpUrlComponents->lpszUrlPath != '/')
4409         {
4410             *lpszUrl = '/';
4411             lpszUrl++;
4412         }
4413     }
4414 
4415     if (lpUrlComponents->lpszUrlPath)
4416     {
4417         dwLen = URL_GET_COMP_LENGTH(lpUrlComponents, UrlPath);
4418         memcpy(lpszUrl, lpUrlComponents->lpszUrlPath, dwLen * sizeof(WCHAR));
4419         lpszUrl += dwLen;
4420     }
4421 
4422     if (lpUrlComponents->lpszExtraInfo)
4423     {
4424         dwLen = URL_GET_COMP_LENGTH(lpUrlComponents, ExtraInfo);
4425         memcpy(lpszUrl, lpUrlComponents->lpszExtraInfo, dwLen * sizeof(WCHAR));
4426         lpszUrl += dwLen;
4427     }
4428 
4429     *lpszUrl = '\0';
4430 
4431     return TRUE;
4432 }
4433 
4434 /***********************************************************************
4435  *      InternetConfirmZoneCrossingA (WININET.@)
4436  *
4437  */
4438 DWORD WINAPI InternetConfirmZoneCrossingA( HWND hWnd, LPSTR szUrlPrev, LPSTR szUrlNew, BOOL bPost )
4439 {
4440     FIXME("(%p, %s, %s, %x) stub\n", hWnd, debugstr_a(szUrlPrev), debugstr_a(szUrlNew), bPost);
4441     return ERROR_SUCCESS;
4442 }
4443 
4444 /***********************************************************************
4445  *      InternetConfirmZoneCrossingW (WININET.@)
4446  *
4447  */
4448 DWORD WINAPI InternetConfirmZoneCrossingW( HWND hWnd, LPWSTR szUrlPrev, LPWSTR szUrlNew, BOOL bPost )
4449 {
4450     FIXME("(%p, %s, %s, %x) stub\n", hWnd, debugstr_w(szUrlPrev), debugstr_w(szUrlNew), bPost);
4451     return ERROR_SUCCESS;
4452 }
4453 
4454 static DWORD zone_preference = 3;
4455 
4456 /***********************************************************************
4457  *      PrivacySetZonePreferenceW (WININET.@)
4458  */
4459 DWORD WINAPI PrivacySetZonePreferenceW( DWORD zone, DWORD type, DWORD template, LPCWSTR preference )
4460 {
4461     FIXME( "%x %x %x %s: stub\n", zone, type, template, debugstr_w(preference) );
4462 
4463     zone_preference = template;
4464     return 0;
4465 }
4466 
4467 /***********************************************************************
4468  *      PrivacyGetZonePreferenceW (WININET.@)
4469  */
4470 DWORD WINAPI PrivacyGetZonePreferenceW( DWORD zone, DWORD type, LPDWORD template,
4471                                         LPWSTR preference, LPDWORD length )
4472 {
4473     FIXME( "%x %x %p %p %p: stub\n", zone, type, template, preference, length );
4474 
4475     if (template) *template = zone_preference;
4476     return 0;
4477 }
4478 
4479 /***********************************************************************
4480  *      InternetGetSecurityInfoByURLA (WININET.@)
4481  */
4482 BOOL WINAPI InternetGetSecurityInfoByURLA(LPSTR lpszURL, PCCERT_CHAIN_CONTEXT *ppCertChain, DWORD *pdwSecureFlags)
4483 {
4484     WCHAR *url;
4485     BOOL res;
4486 
4487     TRACE("(%s %p %p)\n", debugstr_a(lpszURL), ppCertChain, pdwSecureFlags);
4488 
4489     url = heap_strdupAtoW(lpszURL);
4490     if(!url)
4491         return FALSE;
4492 
4493     res = InternetGetSecurityInfoByURLW(url, ppCertChain, pdwSecureFlags);
4494     heap_free(url);
4495     return res;
4496 }
4497 
4498 /***********************************************************************
4499  *      InternetGetSecurityInfoByURLW (WININET.@)
4500  */
4501 BOOL WINAPI InternetGetSecurityInfoByURLW(LPCWSTR lpszURL, PCCERT_CHAIN_CONTEXT *ppCertChain, DWORD *pdwSecureFlags)
4502 {
4503     URL_COMPONENTSW url = {sizeof(url)};
4504     server_t *server;
4505     BOOL res;
4506 
4507     TRACE("(%s %p %p)\n", debugstr_w(lpszURL), ppCertChain, pdwSecureFlags);
4508 
4509     if (!ppCertChain && !pdwSecureFlags) {
4510         SetLastError(ERROR_INVALID_PARAMETER);
4511         return FALSE;
4512     }
4513 
4514     url.dwHostNameLength = 1;
4515     res = InternetCrackUrlW(lpszURL, 0, 0, &url);
4516     if(!res || url.nScheme != INTERNET_SCHEME_HTTPS) {
4517         SetLastError(ERROR_INTERNET_ITEM_NOT_FOUND);
4518         return FALSE;
4519     }
4520 
4521     server = get_server(substr(url.lpszHostName, url.dwHostNameLength), url.nPort, TRUE, FALSE);
4522     if(!server) {
4523         SetLastError(ERROR_INTERNET_ITEM_NOT_FOUND);
4524         return FALSE;
4525     }
4526 
4527     if(server->cert_chain) {
4528         if(pdwSecureFlags)
4529             *pdwSecureFlags = server->security_flags & _SECURITY_ERROR_FLAGS_MASK;
4530 
4531         if(ppCertChain && !(*ppCertChain = CertDuplicateCertificateChain(server->cert_chain)))
4532             res = FALSE;
4533     }else {
4534         SetLastError(ERROR_INTERNET_ITEM_NOT_FOUND);
4535         res = FALSE;
4536     }
4537 
4538     server_release(server);
4539     return res;
4540 }
4541 
4542 DWORD WINAPI InternetDialA( HWND hwndParent, LPSTR lpszConnectoid, DWORD dwFlags,
4543                             DWORD_PTR* lpdwConnection, DWORD dwReserved )
4544 {
4545     FIXME("(%p, %p, 0x%08x, %p, 0x%08x) stub\n", hwndParent, lpszConnectoid, dwFlags,
4546           lpdwConnection, dwReserved);
4547     return ERROR_SUCCESS;
4548 }
4549 
4550 DWORD WINAPI InternetDialW( HWND hwndParent, LPWSTR lpszConnectoid, DWORD dwFlags,
4551                             DWORD_PTR* lpdwConnection, DWORD dwReserved )
4552 {
4553     FIXME("(%p, %p, 0x%08x, %p, 0x%08x) stub\n", hwndParent, lpszConnectoid, dwFlags,
4554           lpdwConnection, dwReserved);
4555     return ERROR_SUCCESS;
4556 }
4557 
4558 BOOL WINAPI InternetGoOnlineA( LPSTR lpszURL, HWND hwndParent, DWORD dwReserved )
4559 {
4560     FIXME("(%s, %p, 0x%08x) stub\n", debugstr_a(lpszURL), hwndParent, dwReserved);
4561     return TRUE;
4562 }
4563 
4564 BOOL WINAPI InternetGoOnlineW( LPWSTR lpszURL, HWND hwndParent, DWORD dwReserved )
4565 {
4566     FIXME("(%s, %p, 0x%08x) stub\n", debugstr_w(lpszURL), hwndParent, dwReserved);
4567     return TRUE;
4568 }
4569 
4570 DWORD WINAPI InternetHangUp( DWORD_PTR dwConnection, DWORD dwReserved )
4571 {
4572     FIXME("(0x%08lx, 0x%08x) stub\n", dwConnection, dwReserved);
4573     return ERROR_SUCCESS;
4574 }
4575 
4576 BOOL WINAPI CreateMD5SSOHash( PWSTR pszChallengeInfo, PWSTR pwszRealm, PWSTR pwszTarget,
4577                               PBYTE pbHexHash )
4578 {
4579     FIXME("(%s, %s, %s, %p) stub\n", debugstr_w(pszChallengeInfo), debugstr_w(pwszRealm),
4580           debugstr_w(pwszTarget), pbHexHash);
4581     return FALSE;
4582 }
4583 
4584 BOOL WINAPI ResumeSuspendedDownload( HINTERNET hInternet, DWORD dwError )
4585 {
4586     FIXME("(%p, 0x%08x) stub\n", hInternet, dwError);
4587     return FALSE;
4588 }
4589 
4590 BOOL WINAPI InternetQueryFortezzaStatus(DWORD *a, DWORD_PTR b)
4591 {
4592     FIXME("(%p, %08lx) stub\n", a, b);
4593     return FALSE;
4594 }
4595 
4596 DWORD WINAPI ShowClientAuthCerts(HWND parent)
4597 {
4598     FIXME("%p: stub\n", parent);
4599     return 0;
4600 }
4601