wininet: Avoid a crash on an invalid handle in InternetQueryOption.
[wine] / dlls / wininet / internet.c
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 #include "wine/port.h"
31
32 #define MAXHOSTNAME 100 /* from http.c */
33
34 #include <string.h>
35 #include <stdarg.h>
36 #include <stdio.h>
37 #include <sys/types.h>
38 #ifdef HAVE_SYS_SOCKET_H
39 # include <sys/socket.h>
40 #endif
41 #ifdef HAVE_POLL_H
42 #include <poll.h>
43 #endif
44 #ifdef HAVE_SYS_POLL_H
45 # include <sys/poll.h>
46 #endif
47 #ifdef HAVE_SYS_TIME_H
48 # include <sys/time.h>
49 #endif
50 #include <stdlib.h>
51 #include <ctype.h>
52 #ifdef HAVE_UNISTD_H
53 # include <unistd.h>
54 #endif
55 #include <assert.h>
56
57 #include "windef.h"
58 #include "winbase.h"
59 #include "winreg.h"
60 #include "winuser.h"
61 #include "wininet.h"
62 #include "winineti.h"
63 #include "winnls.h"
64 #include "wine/debug.h"
65 #include "winerror.h"
66 #define NO_SHLWAPI_STREAM
67 #include "shlwapi.h"
68
69 #include "wine/exception.h"
70
71 #include "internet.h"
72 #include "resource.h"
73
74 #include "wine/unicode.h"
75
76 WINE_DEFAULT_DEBUG_CHANNEL(wininet);
77
78 #define RESPONSE_TIMEOUT        30
79
80 typedef struct
81 {
82     DWORD  dwError;
83     CHAR   response[MAX_REPLY_LEN];
84 } WITHREADERROR, *LPWITHREADERROR;
85
86 static DWORD g_dwTlsErrIndex = TLS_OUT_OF_INDEXES;
87 static HMODULE WININET_hModule;
88
89 #define HANDLE_CHUNK_SIZE 0x10
90
91 static CRITICAL_SECTION WININET_cs;
92 static CRITICAL_SECTION_DEBUG WININET_cs_debug = 
93 {
94     0, 0, &WININET_cs,
95     { &WININET_cs_debug.ProcessLocksList, &WININET_cs_debug.ProcessLocksList },
96       0, 0, { (DWORD_PTR)(__FILE__ ": WININET_cs") }
97 };
98 static CRITICAL_SECTION WININET_cs = { &WININET_cs_debug, -1, 0, 0, 0, 0 };
99
100 static LPWININETHANDLEHEADER *WININET_Handles;
101 static UINT WININET_dwNextHandle;
102 static UINT WININET_dwMaxHandles;
103
104 HINTERNET WININET_AllocHandle( LPWININETHANDLEHEADER info )
105 {
106     LPWININETHANDLEHEADER *p;
107     UINT handle = 0, num;
108
109     list_init( &info->children );
110
111     EnterCriticalSection( &WININET_cs );
112     if( !WININET_dwMaxHandles )
113     {
114         num = HANDLE_CHUNK_SIZE;
115         p = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, 
116                    sizeof (UINT)* num);
117         if( !p )
118             goto end;
119         WININET_Handles = p;
120         WININET_dwMaxHandles = num;
121     }
122     if( WININET_dwMaxHandles == WININET_dwNextHandle )
123     {
124         num = WININET_dwMaxHandles + HANDLE_CHUNK_SIZE;
125         p = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
126                    WININET_Handles, sizeof (UINT)* num);
127         if( !p )
128             goto end;
129         WININET_Handles = p;
130         WININET_dwMaxHandles = num;
131     }
132
133     handle = WININET_dwNextHandle;
134     if( WININET_Handles[handle] )
135         ERR("handle isn't free but should be\n");
136     WININET_Handles[handle] = WININET_AddRef( info );
137
138     while( WININET_Handles[WININET_dwNextHandle] && 
139            (WININET_dwNextHandle < WININET_dwMaxHandles ) )
140         WININET_dwNextHandle++;
141     
142 end:
143     LeaveCriticalSection( &WININET_cs );
144
145     return info->hInternet = (HINTERNET) (handle+1);
146 }
147
148 LPWININETHANDLEHEADER WININET_AddRef( LPWININETHANDLEHEADER info )
149 {
150     ULONG refs = InterlockedIncrement(&info->refs);
151     TRACE("%p -> refcount = %d\n", info, refs );
152     return info;
153 }
154
155 LPWININETHANDLEHEADER WININET_GetObject( HINTERNET hinternet )
156 {
157     LPWININETHANDLEHEADER info = NULL;
158     UINT handle = (UINT) hinternet;
159
160     EnterCriticalSection( &WININET_cs );
161
162     if( (handle > 0) && ( handle <= WININET_dwMaxHandles ) && 
163         WININET_Handles[handle-1] )
164         info = WININET_AddRef( WININET_Handles[handle-1] );
165
166     LeaveCriticalSection( &WININET_cs );
167
168     TRACE("handle %d -> %p\n", handle, info);
169
170     return info;
171 }
172
173 BOOL WININET_Release( LPWININETHANDLEHEADER info )
174 {
175     ULONG refs = InterlockedDecrement(&info->refs);
176     TRACE( "object %p refcount = %d\n", info, refs );
177     if( !refs )
178     {
179         if ( info->vtbl->CloseConnection )
180         {
181             TRACE( "closing connection %p\n", info);
182             info->vtbl->CloseConnection( info );
183         }
184         /* Don't send a callback if this is a session handle created with InternetOpenUrl */
185         if (info->htype != WH_HHTTPSESSION || !(info->dwInternalFlags & INET_OPENURL))
186         {
187             INTERNET_SendCallback(info, info->dwContext,
188                                   INTERNET_STATUS_HANDLE_CLOSING, &info->hInternet,
189                                   sizeof(HINTERNET));
190         }
191         TRACE( "destroying object %p\n", info);
192         if ( info->htype != WH_HINIT )
193             list_remove( &info->entry );
194         info->vtbl->Destroy( info );
195     }
196     return TRUE;
197 }
198
199 BOOL WININET_FreeHandle( HINTERNET hinternet )
200 {
201     BOOL ret = FALSE;
202     UINT handle = (UINT) hinternet;
203     LPWININETHANDLEHEADER info = NULL, child, next;
204
205     EnterCriticalSection( &WININET_cs );
206
207     if( (handle > 0) && ( handle <= WININET_dwMaxHandles ) )
208     {
209         handle--;
210         if( WININET_Handles[handle] )
211         {
212             info = WININET_Handles[handle];
213             TRACE( "destroying handle %d for object %p\n", handle+1, info);
214             WININET_Handles[handle] = NULL;
215             ret = TRUE;
216         }
217     }
218
219     LeaveCriticalSection( &WININET_cs );
220
221     /* As on native when the equivalent of WININET_Release is called, the handle
222      * is already invalid, but if a new handle is created at this time it does
223      * not yet get assigned the freed handle number */
224     if( info )
225     {
226         /* Free all children as native does */
227         LIST_FOR_EACH_ENTRY_SAFE( child, next, &info->children, WININETHANDLEHEADER, entry )
228         {
229             TRACE( "freeing child handle %d for parent handle %d\n",
230                    (UINT)child->hInternet, handle+1);
231             WININET_FreeHandle( child->hInternet );
232         }
233         WININET_Release( info );
234     }
235
236     EnterCriticalSection( &WININET_cs );
237
238     if( WININET_dwNextHandle > handle && !WININET_Handles[handle] )
239         WININET_dwNextHandle = handle;
240
241     LeaveCriticalSection( &WININET_cs );
242
243     return ret;
244 }
245
246 /***********************************************************************
247  * DllMain [Internal] Initializes the internal 'WININET.DLL'.
248  *
249  * PARAMS
250  *     hinstDLL    [I] handle to the DLL's instance
251  *     fdwReason   [I]
252  *     lpvReserved [I] reserved, must be NULL
253  *
254  * RETURNS
255  *     Success: TRUE
256  *     Failure: FALSE
257  */
258
259 BOOL WINAPI DllMain (HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
260 {
261     TRACE("%p,%x,%p\n", hinstDLL, fdwReason, lpvReserved);
262
263     switch (fdwReason) {
264         case DLL_PROCESS_ATTACH:
265
266             g_dwTlsErrIndex = TlsAlloc();
267
268             if (g_dwTlsErrIndex == TLS_OUT_OF_INDEXES)
269                 return FALSE;
270
271             URLCacheContainers_CreateDefaults();
272
273             WININET_hModule = hinstDLL;
274
275         case DLL_THREAD_ATTACH:
276             break;
277
278         case DLL_THREAD_DETACH:
279             if (g_dwTlsErrIndex != TLS_OUT_OF_INDEXES)
280                         {
281                                 LPVOID lpwite = TlsGetValue(g_dwTlsErrIndex);
282                                 HeapFree(GetProcessHeap(), 0, lpwite);
283                         }
284             break;
285
286         case DLL_PROCESS_DETACH:
287
288             URLCacheContainers_DeleteAll();
289
290             if (g_dwTlsErrIndex != TLS_OUT_OF_INDEXES)
291             {
292                 HeapFree(GetProcessHeap(), 0, TlsGetValue(g_dwTlsErrIndex));
293                 TlsFree(g_dwTlsErrIndex);
294             }
295             break;
296     }
297
298     return TRUE;
299 }
300
301
302 /***********************************************************************
303  *           InternetInitializeAutoProxyDll   (WININET.@)
304  *
305  * Setup the internal proxy
306  *
307  * PARAMETERS
308  *     dwReserved
309  *
310  * RETURNS
311  *     FALSE on failure
312  *
313  */
314 BOOL WINAPI InternetInitializeAutoProxyDll(DWORD dwReserved)
315 {
316     FIXME("STUB\n");
317     INTERNET_SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
318     return FALSE;
319 }
320
321 /***********************************************************************
322  *           DetectAutoProxyUrl   (WININET.@)
323  *
324  * Auto detect the proxy url
325  *
326  * RETURNS
327  *     FALSE on failure
328  *
329  */
330 BOOL WINAPI DetectAutoProxyUrl(LPSTR lpszAutoProxyUrl,
331         DWORD dwAutoProxyUrlLength, DWORD dwDetectFlags)
332 {
333     FIXME("STUB\n");
334     INTERNET_SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
335     return FALSE;
336 }
337
338
339 /***********************************************************************
340  *           INTERNET_ConfigureProxy
341  *
342  * FIXME:
343  * The proxy may be specified in the form 'http=proxy.my.org'
344  * Presumably that means there can be ftp=ftpproxy.my.org too.
345  */
346 static BOOL INTERNET_ConfigureProxy( LPWININETAPPINFOW lpwai )
347 {
348     HKEY key;
349     DWORD type, len, enabled = 0;
350     LPCSTR envproxy;
351     static const WCHAR szInternetSettings[] =
352         { 'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
353           'W','i','n','d','o','w','s','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
354           'I','n','t','e','r','n','e','t',' ','S','e','t','t','i','n','g','s',0 };
355     static const WCHAR szProxyServer[] = { 'P','r','o','x','y','S','e','r','v','e','r', 0 };
356     static const WCHAR szProxyEnable[] = { 'P','r','o','x','y','E','n','a','b','l','e', 0 };
357
358     if (RegOpenKeyW( HKEY_CURRENT_USER, szInternetSettings, &key )) return FALSE;
359
360     len = sizeof enabled;
361     if (RegQueryValueExW( key, szProxyEnable, NULL, &type, (BYTE *)&enabled, &len ) || type != REG_DWORD)
362         RegSetValueExW( key, szProxyEnable, 0, REG_DWORD, (BYTE *)&enabled, sizeof(REG_DWORD) );
363
364     if (enabled)
365     {
366         TRACE("Proxy is enabled.\n");
367
368         /* figure out how much memory the proxy setting takes */
369         if (!RegQueryValueExW( key, szProxyServer, NULL, &type, NULL, &len ) && len && (type == REG_SZ))
370         {
371             LPWSTR szProxy, p;
372             static const WCHAR szHttp[] = {'h','t','t','p','=',0};
373
374             if (!(szProxy = HeapAlloc( GetProcessHeap(), 0, len )))
375             {
376                 RegCloseKey( key );
377                 return FALSE;
378             }
379             RegQueryValueExW( key, szProxyServer, NULL, &type, (BYTE*)szProxy, &len );
380
381             /* find the http proxy, and strip away everything else */
382             p = strstrW( szProxy, szHttp );
383             if (p)
384             {
385                 p += lstrlenW( szHttp );
386                 lstrcpyW( szProxy, p );
387             }
388             p = strchrW( szProxy, ' ' );
389             if (p) *p = 0;
390
391             lpwai->dwAccessType = INTERNET_OPEN_TYPE_PROXY;
392             lpwai->lpszProxy = szProxy;
393
394             TRACE("http proxy = %s\n", debugstr_w(lpwai->lpszProxy));
395         }
396         else
397             ERR("Couldn't read proxy server settings from registry.\n");
398     }
399     else if ((envproxy = getenv( "http_proxy" )))
400     {
401         WCHAR *envproxyW;
402
403         len = MultiByteToWideChar( CP_UNIXCP, 0, envproxy, -1, NULL, 0 );
404         if (!(envproxyW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR)))) return FALSE;
405         MultiByteToWideChar( CP_UNIXCP, 0, envproxy, -1, envproxyW, len );
406
407         lpwai->dwAccessType = INTERNET_OPEN_TYPE_PROXY;
408         lpwai->lpszProxy = envproxyW;
409
410         TRACE("http proxy (from environment) = %s\n", debugstr_w(lpwai->lpszProxy));
411         enabled = 1;
412     }
413     if (!enabled) TRACE("Proxy is not enabled.\n");
414
415     RegCloseKey( key );
416     return (enabled > 0);
417 }
418
419 /***********************************************************************
420  *           dump_INTERNET_FLAGS
421  *
422  * Helper function to TRACE the internet flags.
423  *
424  * RETURNS
425  *    None
426  *
427  */
428 static void dump_INTERNET_FLAGS(DWORD dwFlags) 
429 {
430 #define FE(x) { x, #x }
431     static const wininet_flag_info flag[] = {
432         FE(INTERNET_FLAG_RELOAD),
433         FE(INTERNET_FLAG_RAW_DATA),
434         FE(INTERNET_FLAG_EXISTING_CONNECT),
435         FE(INTERNET_FLAG_ASYNC),
436         FE(INTERNET_FLAG_PASSIVE),
437         FE(INTERNET_FLAG_NO_CACHE_WRITE),
438         FE(INTERNET_FLAG_MAKE_PERSISTENT),
439         FE(INTERNET_FLAG_FROM_CACHE),
440         FE(INTERNET_FLAG_SECURE),
441         FE(INTERNET_FLAG_KEEP_CONNECTION),
442         FE(INTERNET_FLAG_NO_AUTO_REDIRECT),
443         FE(INTERNET_FLAG_READ_PREFETCH),
444         FE(INTERNET_FLAG_NO_COOKIES),
445         FE(INTERNET_FLAG_NO_AUTH),
446         FE(INTERNET_FLAG_CACHE_IF_NET_FAIL),
447         FE(INTERNET_FLAG_IGNORE_REDIRECT_TO_HTTP),
448         FE(INTERNET_FLAG_IGNORE_REDIRECT_TO_HTTPS),
449         FE(INTERNET_FLAG_IGNORE_CERT_DATE_INVALID),
450         FE(INTERNET_FLAG_IGNORE_CERT_CN_INVALID),
451         FE(INTERNET_FLAG_RESYNCHRONIZE),
452         FE(INTERNET_FLAG_HYPERLINK),
453         FE(INTERNET_FLAG_NO_UI),
454         FE(INTERNET_FLAG_PRAGMA_NOCACHE),
455         FE(INTERNET_FLAG_CACHE_ASYNC),
456         FE(INTERNET_FLAG_FORMS_SUBMIT),
457         FE(INTERNET_FLAG_NEED_FILE),
458         FE(INTERNET_FLAG_TRANSFER_ASCII),
459         FE(INTERNET_FLAG_TRANSFER_BINARY)
460     };
461 #undef FE
462     int i;
463     
464     for (i = 0; i < (sizeof(flag) / sizeof(flag[0])); i++) {
465         if (flag[i].val & dwFlags) {
466             TRACE(" %s", flag[i].name);
467             dwFlags &= ~flag[i].val;
468         }
469     }   
470     if (dwFlags)
471         TRACE(" Unknown flags (%08x)\n", dwFlags);
472     else
473         TRACE("\n");
474 }
475
476 /***********************************************************************
477  *           INTERNET_CloseHandle (internal)
478  *
479  * Close internet handle
480  *
481  */
482 static VOID APPINFO_Destroy(WININETHANDLEHEADER *hdr)
483 {
484     LPWININETAPPINFOW lpwai = (LPWININETAPPINFOW) hdr;
485
486     TRACE("%p\n",lpwai);
487
488     HeapFree(GetProcessHeap(), 0, lpwai->lpszAgent);
489     HeapFree(GetProcessHeap(), 0, lpwai->lpszProxy);
490     HeapFree(GetProcessHeap(), 0, lpwai->lpszProxyBypass);
491     HeapFree(GetProcessHeap(), 0, lpwai->lpszProxyUsername);
492     HeapFree(GetProcessHeap(), 0, lpwai->lpszProxyPassword);
493     HeapFree(GetProcessHeap(), 0, lpwai);
494 }
495
496 static DWORD APPINFO_QueryOption(WININETHANDLEHEADER *hdr, DWORD option, void *buffer, DWORD *size, BOOL unicode)
497 {
498     switch(option) {
499     case INTERNET_OPTION_HANDLE_TYPE:
500         TRACE("INTERNET_OPTION_HANDLE_TYPE\n");
501
502         if (*size < sizeof(ULONG))
503             return ERROR_INSUFFICIENT_BUFFER;
504
505         *size = sizeof(DWORD);
506         *(DWORD*)buffer = INTERNET_HANDLE_TYPE_INTERNET;
507         return ERROR_SUCCESS;
508     }
509
510     FIXME("Not implemented option %d\n", option);
511     return ERROR_INTERNET_INVALID_OPTION;
512 }
513
514 static const HANDLEHEADERVtbl APPINFOVtbl = {
515     APPINFO_Destroy,
516     NULL,
517     APPINFO_QueryOption,
518     NULL,
519     NULL,
520     NULL,
521     NULL,
522     NULL,
523     NULL
524 };
525
526
527 /***********************************************************************
528  *           InternetOpenW   (WININET.@)
529  *
530  * Per-application initialization of wininet
531  *
532  * RETURNS
533  *    HINTERNET on success
534  *    NULL on failure
535  *
536  */
537 HINTERNET WINAPI InternetOpenW(LPCWSTR lpszAgent, DWORD dwAccessType,
538     LPCWSTR lpszProxy, LPCWSTR lpszProxyBypass, DWORD dwFlags)
539 {
540     LPWININETAPPINFOW lpwai = NULL;
541     HINTERNET handle = NULL;
542
543     if (TRACE_ON(wininet)) {
544 #define FE(x) { x, #x }
545         static const wininet_flag_info access_type[] = {
546             FE(INTERNET_OPEN_TYPE_PRECONFIG),
547             FE(INTERNET_OPEN_TYPE_DIRECT),
548             FE(INTERNET_OPEN_TYPE_PROXY),
549             FE(INTERNET_OPEN_TYPE_PRECONFIG_WITH_NO_AUTOPROXY)
550         };
551 #undef FE
552         DWORD i;
553         const char *access_type_str = "Unknown";
554         
555         TRACE("(%s, %i, %s, %s, %i)\n", debugstr_w(lpszAgent), dwAccessType,
556               debugstr_w(lpszProxy), debugstr_w(lpszProxyBypass), dwFlags);
557         for (i = 0; i < (sizeof(access_type) / sizeof(access_type[0])); i++) {
558             if (access_type[i].val == dwAccessType) {
559                 access_type_str = access_type[i].name;
560                 break;
561             }
562         }
563         TRACE("  access type : %s\n", access_type_str);
564         TRACE("  flags       :");
565         dump_INTERNET_FLAGS(dwFlags);
566     }
567
568     /* Clear any error information */
569     INTERNET_SetLastError(0);
570
571     lpwai = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WININETAPPINFOW));
572     if (NULL == lpwai)
573     {
574         INTERNET_SetLastError(ERROR_OUTOFMEMORY);
575         goto lend;
576     }
577
578     lpwai->hdr.htype = WH_HINIT;
579     lpwai->hdr.vtbl = &APPINFOVtbl;
580     lpwai->hdr.dwFlags = dwFlags;
581     lpwai->hdr.refs = 1;
582     lpwai->dwAccessType = dwAccessType;
583     lpwai->lpszProxyUsername = NULL;
584     lpwai->lpszProxyPassword = NULL;
585
586     handle = WININET_AllocHandle( &lpwai->hdr );
587     if( !handle )
588     {
589         HeapFree( GetProcessHeap(), 0, lpwai );
590         INTERNET_SetLastError(ERROR_OUTOFMEMORY);
591         goto lend;
592     }
593
594     if (NULL != lpszAgent)
595     {
596         lpwai->lpszAgent = HeapAlloc( GetProcessHeap(),0,
597                                       (strlenW(lpszAgent)+1)*sizeof(WCHAR));
598         if (lpwai->lpszAgent)
599             lstrcpyW( lpwai->lpszAgent, lpszAgent );
600     }
601     if(dwAccessType == INTERNET_OPEN_TYPE_PRECONFIG)
602         INTERNET_ConfigureProxy( lpwai );
603     else if (NULL != lpszProxy)
604     {
605         lpwai->lpszProxy = HeapAlloc( GetProcessHeap(), 0,
606                                       (strlenW(lpszProxy)+1)*sizeof(WCHAR));
607         if (lpwai->lpszProxy)
608             lstrcpyW( lpwai->lpszProxy, lpszProxy );
609     }
610
611     if (NULL != lpszProxyBypass)
612     {
613         lpwai->lpszProxyBypass = HeapAlloc( GetProcessHeap(), 0,
614                                      (strlenW(lpszProxyBypass)+1)*sizeof(WCHAR));
615         if (lpwai->lpszProxyBypass)
616             lstrcpyW( lpwai->lpszProxyBypass, lpszProxyBypass );
617     }
618
619 lend:
620     if( lpwai )
621         WININET_Release( &lpwai->hdr );
622
623     TRACE("returning %p\n", lpwai);
624
625     return handle;
626 }
627
628
629 /***********************************************************************
630  *           InternetOpenA   (WININET.@)
631  *
632  * Per-application initialization of wininet
633  *
634  * RETURNS
635  *    HINTERNET on success
636  *    NULL on failure
637  *
638  */
639 HINTERNET WINAPI InternetOpenA(LPCSTR lpszAgent, DWORD dwAccessType,
640     LPCSTR lpszProxy, LPCSTR lpszProxyBypass, DWORD dwFlags)
641 {
642     HINTERNET rc = NULL;
643     INT len;
644     WCHAR *szAgent = NULL, *szProxy = NULL, *szBypass = NULL;
645
646     TRACE("(%s, 0x%08x, %s, %s, 0x%08x)\n", debugstr_a(lpszAgent),
647        dwAccessType, debugstr_a(lpszProxy), debugstr_a(lpszProxyBypass), dwFlags);
648
649     if( lpszAgent )
650     {
651         len = MultiByteToWideChar(CP_ACP, 0, lpszAgent, -1, NULL, 0);
652         szAgent = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR));
653         MultiByteToWideChar(CP_ACP, 0, lpszAgent, -1, szAgent, len);
654     }
655
656     if( lpszProxy )
657     {
658         len = MultiByteToWideChar(CP_ACP, 0, lpszProxy, -1, NULL, 0);
659         szProxy = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR));
660         MultiByteToWideChar(CP_ACP, 0, lpszProxy, -1, szProxy, len);
661     }
662
663     if( lpszProxyBypass )
664     {
665         len = MultiByteToWideChar(CP_ACP, 0, lpszProxyBypass, -1, NULL, 0);
666         szBypass = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR));
667         MultiByteToWideChar(CP_ACP, 0, lpszProxyBypass, -1, szBypass, len);
668     }
669
670     rc = InternetOpenW(szAgent, dwAccessType, szProxy, szBypass, dwFlags);
671
672     HeapFree(GetProcessHeap(), 0, szAgent);
673     HeapFree(GetProcessHeap(), 0, szProxy);
674     HeapFree(GetProcessHeap(), 0, szBypass);
675
676     return rc;
677 }
678
679 /***********************************************************************
680  *           InternetGetLastResponseInfoA (WININET.@)
681  *
682  * Return last wininet error description on the calling thread
683  *
684  * RETURNS
685  *    TRUE on success of writing to buffer
686  *    FALSE on failure
687  *
688  */
689 BOOL WINAPI InternetGetLastResponseInfoA(LPDWORD lpdwError,
690     LPSTR lpszBuffer, LPDWORD lpdwBufferLength)
691 {
692     LPWITHREADERROR lpwite = (LPWITHREADERROR)TlsGetValue(g_dwTlsErrIndex);
693
694     TRACE("\n");
695
696     if (lpwite)
697     {
698         *lpdwError = lpwite->dwError;
699         if (lpwite->dwError)
700         {
701             memcpy(lpszBuffer, lpwite->response, *lpdwBufferLength);
702             *lpdwBufferLength = strlen(lpszBuffer);
703         }
704         else
705             *lpdwBufferLength = 0;
706     }
707     else
708     {
709         *lpdwError = 0;
710         *lpdwBufferLength = 0;
711     }
712
713     return TRUE;
714 }
715
716 /***********************************************************************
717  *           InternetGetLastResponseInfoW (WININET.@)
718  *
719  * Return last wininet error description on the calling thread
720  *
721  * RETURNS
722  *    TRUE on success of writing to buffer
723  *    FALSE on failure
724  *
725  */
726 BOOL WINAPI InternetGetLastResponseInfoW(LPDWORD lpdwError,
727     LPWSTR lpszBuffer, LPDWORD lpdwBufferLength)
728 {
729     LPWITHREADERROR lpwite = (LPWITHREADERROR)TlsGetValue(g_dwTlsErrIndex);
730
731     TRACE("\n");
732
733     if (lpwite)
734     {
735         *lpdwError = lpwite->dwError;
736         if (lpwite->dwError)
737         {
738             memcpy(lpszBuffer, lpwite->response, *lpdwBufferLength);
739             *lpdwBufferLength = lstrlenW(lpszBuffer);
740         }
741         else
742             *lpdwBufferLength = 0;
743     }
744     else
745     {
746         *lpdwError = 0;
747         *lpdwBufferLength = 0;
748     }
749
750     return TRUE;
751 }
752
753 /***********************************************************************
754  *           InternetGetConnectedState (WININET.@)
755  *
756  * Return connected state
757  *
758  * RETURNS
759  *    TRUE if connected
760  *    if lpdwStatus is not null, return the status (off line,
761  *    modem, lan...) in it.
762  *    FALSE if not connected
763  */
764 BOOL WINAPI InternetGetConnectedState(LPDWORD lpdwStatus, DWORD dwReserved)
765 {
766     TRACE("(%p, 0x%08x)\n", lpdwStatus, dwReserved);
767
768     if (lpdwStatus) {
769         FIXME("always returning LAN connection.\n");
770         *lpdwStatus = INTERNET_CONNECTION_LAN;
771     }
772     return TRUE;
773 }
774
775
776 /***********************************************************************
777  *           InternetGetConnectedStateExW (WININET.@)
778  *
779  * Return connected state
780  *
781  * PARAMS
782  *
783  * lpdwStatus         [O] Flags specifying the status of the internet connection.
784  * lpszConnectionName [O] Pointer to buffer to receive the friendly name of the internet connection.
785  * dwNameLen          [I] Size of the buffer, in characters.
786  * dwReserved         [I] Reserved. Must be set to 0.
787  *
788  * RETURNS
789  *    TRUE if connected
790  *    if lpdwStatus is not null, return the status (off line,
791  *    modem, lan...) in it.
792  *    FALSE if not connected
793  *
794  * NOTES
795  *   If the system has no available network connections, an empty string is
796  *   stored in lpszConnectionName. If there is a LAN connection, a localized
797  *   "LAN Connection" string is stored. Presumably, if only a dial-up
798  *   connection is available then the name of the dial-up connection is
799  *   returned. Why any application, other than the "Internet Settings" CPL,
800  *   would want to use this function instead of the simpler InternetGetConnectedStateW
801  *   function is beyond me.
802  */
803 BOOL WINAPI InternetGetConnectedStateExW(LPDWORD lpdwStatus, LPWSTR lpszConnectionName,
804                                          DWORD dwNameLen, DWORD dwReserved)
805 {
806     TRACE("(%p, %p, %d, 0x%08x)\n", lpdwStatus, lpszConnectionName, dwNameLen, dwReserved);
807
808     /* Must be zero */
809     if(dwReserved)
810         return FALSE;
811
812     if (lpdwStatus) {
813         FIXME("always returning LAN connection.\n");
814         *lpdwStatus = INTERNET_CONNECTION_LAN;
815     }
816     return LoadStringW(WININET_hModule, IDS_LANCONNECTION, lpszConnectionName, dwNameLen);
817 }
818
819
820 /***********************************************************************
821  *           InternetGetConnectedStateExA (WININET.@)
822  */
823 BOOL WINAPI InternetGetConnectedStateExA(LPDWORD lpdwStatus, LPSTR lpszConnectionName,
824                                          DWORD dwNameLen, DWORD dwReserved)
825 {
826     LPWSTR lpwszConnectionName = NULL;
827     BOOL rc;
828
829     TRACE("(%p, %p, %d, 0x%08x)\n", lpdwStatus, lpszConnectionName, dwNameLen, dwReserved);
830
831     if (lpszConnectionName && dwNameLen > 0)
832         lpwszConnectionName= HeapAlloc(GetProcessHeap(), 0, dwNameLen * sizeof(WCHAR));
833
834     rc = InternetGetConnectedStateExW(lpdwStatus,lpwszConnectionName, dwNameLen,
835                                       dwReserved);
836     if (rc && lpwszConnectionName)
837     {
838         WideCharToMultiByte(CP_ACP,0,lpwszConnectionName,-1,lpszConnectionName,
839                             dwNameLen, NULL, NULL);
840
841         HeapFree(GetProcessHeap(),0,lpwszConnectionName);
842     }
843
844     return rc;
845 }
846
847
848 /***********************************************************************
849  *           InternetConnectW (WININET.@)
850  *
851  * Open a ftp, gopher or http session
852  *
853  * RETURNS
854  *    HINTERNET a session handle on success
855  *    NULL on failure
856  *
857  */
858 HINTERNET WINAPI InternetConnectW(HINTERNET hInternet,
859     LPCWSTR lpszServerName, INTERNET_PORT nServerPort,
860     LPCWSTR lpszUserName, LPCWSTR lpszPassword,
861     DWORD dwService, DWORD dwFlags, DWORD_PTR dwContext)
862 {
863     LPWININETAPPINFOW hIC;
864     HINTERNET rc = NULL;
865
866     TRACE("(%p, %s, %i, %s, %s, %i, %i, %lx)\n", hInternet, debugstr_w(lpszServerName),
867           nServerPort, debugstr_w(lpszUserName), debugstr_w(lpszPassword),
868           dwService, dwFlags, dwContext);
869
870     if (!lpszServerName)
871     {
872         INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
873         return NULL;
874     }
875
876     /* Clear any error information */
877     INTERNET_SetLastError(0);
878     hIC = (LPWININETAPPINFOW) WININET_GetObject( hInternet );
879     if ( (hIC == NULL) || (hIC->hdr.htype != WH_HINIT) )
880     {
881         INTERNET_SetLastError(ERROR_INVALID_HANDLE);
882         goto lend;
883     }
884
885     switch (dwService)
886     {
887         case INTERNET_SERVICE_FTP:
888             rc = FTP_Connect(hIC, lpszServerName, nServerPort,
889             lpszUserName, lpszPassword, dwFlags, dwContext, 0);
890             break;
891
892         case INTERNET_SERVICE_HTTP:
893             rc = HTTP_Connect(hIC, lpszServerName, nServerPort,
894             lpszUserName, lpszPassword, dwFlags, dwContext, 0);
895             break;
896
897         case INTERNET_SERVICE_GOPHER:
898         default:
899             break;
900     }
901 lend:
902     if( hIC )
903         WININET_Release( &hIC->hdr );
904
905     TRACE("returning %p\n", rc);
906     return rc;
907 }
908
909
910 /***********************************************************************
911  *           InternetConnectA (WININET.@)
912  *
913  * Open a ftp, gopher or http session
914  *
915  * RETURNS
916  *    HINTERNET a session handle on success
917  *    NULL on failure
918  *
919  */
920 HINTERNET WINAPI InternetConnectA(HINTERNET hInternet,
921     LPCSTR lpszServerName, INTERNET_PORT nServerPort,
922     LPCSTR lpszUserName, LPCSTR lpszPassword,
923     DWORD dwService, DWORD dwFlags, DWORD_PTR dwContext)
924 {
925     HINTERNET rc = NULL;
926     INT len = 0;
927     LPWSTR szServerName = NULL;
928     LPWSTR szUserName = NULL;
929     LPWSTR szPassword = NULL;
930
931     if (lpszServerName)
932     {
933         len = MultiByteToWideChar(CP_ACP, 0, lpszServerName, -1, NULL, 0);
934         szServerName = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR));
935         MultiByteToWideChar(CP_ACP, 0, lpszServerName, -1, szServerName, len);
936     }
937     if (lpszUserName)
938     {
939         len = MultiByteToWideChar(CP_ACP, 0, lpszUserName, -1, NULL, 0);
940         szUserName = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR));
941         MultiByteToWideChar(CP_ACP, 0, lpszUserName, -1, szUserName, len);
942     }
943     if (lpszPassword)
944     {
945         len = MultiByteToWideChar(CP_ACP, 0, lpszPassword, -1, NULL, 0);
946         szPassword = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR));
947         MultiByteToWideChar(CP_ACP, 0, lpszPassword, -1, szPassword, len);
948     }
949
950
951     rc = InternetConnectW(hInternet, szServerName, nServerPort,
952         szUserName, szPassword, dwService, dwFlags, dwContext);
953
954     HeapFree(GetProcessHeap(), 0, szServerName);
955     HeapFree(GetProcessHeap(), 0, szUserName);
956     HeapFree(GetProcessHeap(), 0, szPassword);
957     return rc;
958 }
959
960
961 /***********************************************************************
962  *           InternetFindNextFileA (WININET.@)
963  *
964  * Continues a file search from a previous call to FindFirstFile
965  *
966  * RETURNS
967  *    TRUE on success
968  *    FALSE on failure
969  *
970  */
971 BOOL WINAPI InternetFindNextFileA(HINTERNET hFind, LPVOID lpvFindData)
972 {
973     BOOL ret;
974     WIN32_FIND_DATAW fd;
975     
976     ret = InternetFindNextFileW(hFind, lpvFindData?&fd:NULL);
977     if(lpvFindData)
978         WININET_find_data_WtoA(&fd, (LPWIN32_FIND_DATAA)lpvFindData);
979     return ret;
980 }
981
982 /***********************************************************************
983  *           InternetFindNextFileW (WININET.@)
984  *
985  * Continues a file search from a previous call to FindFirstFile
986  *
987  * RETURNS
988  *    TRUE on success
989  *    FALSE on failure
990  *
991  */
992 BOOL WINAPI InternetFindNextFileW(HINTERNET hFind, LPVOID lpvFindData)
993 {
994     WININETHANDLEHEADER *hdr;
995     DWORD res;
996
997     TRACE("\n");
998
999     hdr = WININET_GetObject(hFind);
1000     if(!hdr) {
1001         WARN("Invalid handle\n");
1002         SetLastError(ERROR_INVALID_HANDLE);
1003         return FALSE;
1004     }
1005
1006     if(hdr->vtbl->FindNextFileW) {
1007         res = hdr->vtbl->FindNextFileW(hdr, lpvFindData);
1008     }else {
1009         WARN("Handle doesn't support NextFile\n");
1010         res = ERROR_INTERNET_INCORRECT_HANDLE_TYPE;
1011     }
1012
1013     WININET_Release(hdr);
1014
1015     if(res != ERROR_SUCCESS)
1016         SetLastError(res);
1017     return res == ERROR_SUCCESS;
1018 }
1019
1020 /***********************************************************************
1021  *           InternetCloseHandle (WININET.@)
1022  *
1023  * Generic close handle function
1024  *
1025  * RETURNS
1026  *    TRUE on success
1027  *    FALSE on failure
1028  *
1029  */
1030 BOOL WINAPI InternetCloseHandle(HINTERNET hInternet)
1031 {
1032     LPWININETHANDLEHEADER lpwh;
1033     
1034     TRACE("%p\n",hInternet);
1035
1036     lpwh = WININET_GetObject( hInternet );
1037     if (NULL == lpwh)
1038     {
1039         INTERNET_SetLastError(ERROR_INVALID_HANDLE);
1040         return FALSE;
1041     }
1042
1043     WININET_Release( lpwh );
1044     WININET_FreeHandle( hInternet );
1045
1046     return TRUE;
1047 }
1048
1049
1050 /***********************************************************************
1051  *           ConvertUrlComponentValue (Internal)
1052  *
1053  * Helper function for InternetCrackUrlW
1054  *
1055  */
1056 static void ConvertUrlComponentValue(LPSTR* lppszComponent, LPDWORD dwComponentLen,
1057                                      LPWSTR lpwszComponent, DWORD dwwComponentLen,
1058                                      LPCSTR lpszStart, LPCWSTR lpwszStart)
1059 {
1060     TRACE("%p %d %p %d %p %p\n", lppszComponent, *dwComponentLen, lpwszComponent, dwwComponentLen, lpszStart, lpwszStart);
1061     if (*dwComponentLen != 0)
1062     {
1063         DWORD nASCIILength=WideCharToMultiByte(CP_ACP,0,lpwszComponent,dwwComponentLen,NULL,0,NULL,NULL);
1064         if (*lppszComponent == NULL)
1065         {
1066             int nASCIIOffset=WideCharToMultiByte(CP_ACP,0,lpwszStart,lpwszComponent-lpwszStart,NULL,0,NULL,NULL);
1067             if (lpwszComponent)
1068                 *lppszComponent = (LPSTR)lpszStart+nASCIIOffset;
1069             else
1070                 *lppszComponent = NULL;
1071             *dwComponentLen = nASCIILength;
1072         }
1073         else
1074         {
1075             DWORD ncpylen = min((*dwComponentLen)-1, nASCIILength);
1076             WideCharToMultiByte(CP_ACP,0,lpwszComponent,dwwComponentLen,*lppszComponent,ncpylen+1,NULL,NULL);
1077             (*lppszComponent)[ncpylen]=0;
1078             *dwComponentLen = ncpylen;
1079         }
1080     }
1081 }
1082
1083
1084 /***********************************************************************
1085  *           InternetCrackUrlA (WININET.@)
1086  *
1087  * See InternetCrackUrlW.
1088  */
1089 BOOL WINAPI InternetCrackUrlA(LPCSTR lpszUrl, DWORD dwUrlLength, DWORD dwFlags,
1090     LPURL_COMPONENTSA lpUrlComponents)
1091 {
1092   DWORD nLength;
1093   URL_COMPONENTSW UCW;
1094   WCHAR* lpwszUrl;
1095
1096   TRACE("(%s %u %x %p)\n", debugstr_a(lpszUrl), dwUrlLength, dwFlags, lpUrlComponents);
1097
1098   if (!lpszUrl || !*lpszUrl || !lpUrlComponents ||
1099           lpUrlComponents->dwStructSize != sizeof(URL_COMPONENTSA))
1100   {
1101       INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
1102       return FALSE;
1103   }
1104
1105   if(dwUrlLength<=0)
1106       dwUrlLength=-1;
1107   nLength=MultiByteToWideChar(CP_ACP,0,lpszUrl,dwUrlLength,NULL,0);
1108
1109   /* if dwUrlLength=-1 then nLength includes null but length to 
1110        InternetCrackUrlW should not include it                  */
1111   if (dwUrlLength == -1) nLength--;
1112
1113   lpwszUrl=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WCHAR)*nLength);
1114   MultiByteToWideChar(CP_ACP,0,lpszUrl,dwUrlLength,lpwszUrl,nLength);
1115
1116   memset(&UCW,0,sizeof(UCW));
1117   UCW.dwStructSize = sizeof(URL_COMPONENTSW);
1118   if(lpUrlComponents->dwHostNameLength!=0)
1119       UCW.dwHostNameLength= lpUrlComponents->dwHostNameLength;
1120   if(lpUrlComponents->dwUserNameLength!=0)
1121       UCW.dwUserNameLength=lpUrlComponents->dwUserNameLength;
1122   if(lpUrlComponents->dwPasswordLength!=0)
1123       UCW.dwPasswordLength=lpUrlComponents->dwPasswordLength;
1124   if(lpUrlComponents->dwUrlPathLength!=0)
1125       UCW.dwUrlPathLength=lpUrlComponents->dwUrlPathLength;
1126   if(lpUrlComponents->dwSchemeLength!=0)
1127       UCW.dwSchemeLength=lpUrlComponents->dwSchemeLength;
1128   if(lpUrlComponents->dwExtraInfoLength!=0)
1129       UCW.dwExtraInfoLength=lpUrlComponents->dwExtraInfoLength;
1130   if(!InternetCrackUrlW(lpwszUrl,nLength,dwFlags,&UCW))
1131   {
1132       HeapFree(GetProcessHeap(), 0, lpwszUrl);
1133       return FALSE;
1134   }
1135
1136   ConvertUrlComponentValue(&lpUrlComponents->lpszHostName, &lpUrlComponents->dwHostNameLength,
1137                            UCW.lpszHostName, UCW.dwHostNameLength,
1138                            lpszUrl, lpwszUrl);
1139   ConvertUrlComponentValue(&lpUrlComponents->lpszUserName, &lpUrlComponents->dwUserNameLength,
1140                            UCW.lpszUserName, UCW.dwUserNameLength,
1141                            lpszUrl, lpwszUrl);
1142   ConvertUrlComponentValue(&lpUrlComponents->lpszPassword, &lpUrlComponents->dwPasswordLength,
1143                            UCW.lpszPassword, UCW.dwPasswordLength,
1144                            lpszUrl, lpwszUrl);
1145   ConvertUrlComponentValue(&lpUrlComponents->lpszUrlPath, &lpUrlComponents->dwUrlPathLength,
1146                            UCW.lpszUrlPath, UCW.dwUrlPathLength,
1147                            lpszUrl, lpwszUrl);
1148   ConvertUrlComponentValue(&lpUrlComponents->lpszScheme, &lpUrlComponents->dwSchemeLength,
1149                            UCW.lpszScheme, UCW.dwSchemeLength,
1150                            lpszUrl, lpwszUrl);
1151   ConvertUrlComponentValue(&lpUrlComponents->lpszExtraInfo, &lpUrlComponents->dwExtraInfoLength,
1152                            UCW.lpszExtraInfo, UCW.dwExtraInfoLength,
1153                            lpszUrl, lpwszUrl);
1154   lpUrlComponents->nScheme=UCW.nScheme;
1155   lpUrlComponents->nPort=UCW.nPort;
1156   HeapFree(GetProcessHeap(), 0, lpwszUrl);
1157   
1158   TRACE("%s: scheme(%s) host(%s) path(%s) extra(%s)\n", lpszUrl,
1159           debugstr_an(lpUrlComponents->lpszScheme,lpUrlComponents->dwSchemeLength),
1160           debugstr_an(lpUrlComponents->lpszHostName,lpUrlComponents->dwHostNameLength),
1161           debugstr_an(lpUrlComponents->lpszUrlPath,lpUrlComponents->dwUrlPathLength),
1162           debugstr_an(lpUrlComponents->lpszExtraInfo,lpUrlComponents->dwExtraInfoLength));
1163
1164   return TRUE;
1165 }
1166
1167 static const WCHAR url_schemes[][7] =
1168 {
1169     {'f','t','p',0},
1170     {'g','o','p','h','e','r',0},
1171     {'h','t','t','p',0},
1172     {'h','t','t','p','s',0},
1173     {'f','i','l','e',0},
1174     {'n','e','w','s',0},
1175     {'m','a','i','l','t','o',0},
1176     {'r','e','s',0},
1177 };
1178
1179 /***********************************************************************
1180  *           GetInternetSchemeW (internal)
1181  *
1182  * Get scheme of url
1183  *
1184  * RETURNS
1185  *    scheme on success
1186  *    INTERNET_SCHEME_UNKNOWN on failure
1187  *
1188  */
1189 static INTERNET_SCHEME GetInternetSchemeW(LPCWSTR lpszScheme, DWORD nMaxCmp)
1190 {
1191     int i;
1192
1193     TRACE("%s %d\n",debugstr_wn(lpszScheme, nMaxCmp), nMaxCmp);
1194
1195     if(lpszScheme==NULL)
1196         return INTERNET_SCHEME_UNKNOWN;
1197
1198     for (i = 0; i < sizeof(url_schemes)/sizeof(url_schemes[0]); i++)
1199         if (!strncmpW(lpszScheme, url_schemes[i], nMaxCmp))
1200             return INTERNET_SCHEME_FIRST + i;
1201
1202     return INTERNET_SCHEME_UNKNOWN;
1203 }
1204
1205 /***********************************************************************
1206  *           SetUrlComponentValueW (Internal)
1207  *
1208  * Helper function for InternetCrackUrlW
1209  *
1210  * PARAMS
1211  *     lppszComponent [O] Holds the returned string
1212  *     dwComponentLen [I] Holds the size of lppszComponent
1213  *                    [O] Holds the length of the string in lppszComponent without '\0'
1214  *     lpszStart      [I] Holds the string to copy from
1215  *     len            [I] Holds the length of lpszStart without '\0'
1216  *
1217  * RETURNS
1218  *    TRUE on success
1219  *    FALSE on failure
1220  *
1221  */
1222 static BOOL SetUrlComponentValueW(LPWSTR* lppszComponent, LPDWORD dwComponentLen, LPCWSTR lpszStart, DWORD len)
1223 {
1224     TRACE("%s (%d)\n", debugstr_wn(lpszStart,len), len);
1225
1226     if ( (*dwComponentLen == 0) && (*lppszComponent == NULL) )
1227         return FALSE;
1228
1229     if (*dwComponentLen != 0 || *lppszComponent == NULL)
1230     {
1231         if (*lppszComponent == NULL)
1232         {
1233             *lppszComponent = (LPWSTR)lpszStart;
1234             *dwComponentLen = len;
1235         }
1236         else
1237         {
1238             DWORD ncpylen = min((*dwComponentLen)-1, len);
1239             memcpy(*lppszComponent, lpszStart, ncpylen*sizeof(WCHAR));
1240             (*lppszComponent)[ncpylen] = '\0';
1241             *dwComponentLen = ncpylen;
1242         }
1243     }
1244
1245     return TRUE;
1246 }
1247
1248 /***********************************************************************
1249  *           InternetCrackUrlW   (WININET.@)
1250  *
1251  * Break up URL into its components
1252  *
1253  * RETURNS
1254  *    TRUE on success
1255  *    FALSE on failure
1256  */
1257 BOOL WINAPI InternetCrackUrlW(LPCWSTR lpszUrl_orig, DWORD dwUrlLength_orig, DWORD dwFlags,
1258                               LPURL_COMPONENTSW lpUC)
1259 {
1260   /*
1261    * RFC 1808
1262    * <protocol>:[//<net_loc>][/path][;<params>][?<query>][#<fragment>]
1263    *
1264    */
1265     LPCWSTR lpszParam    = NULL;
1266     BOOL  bIsAbsolute = FALSE;
1267     LPCWSTR lpszap, lpszUrl = lpszUrl_orig;
1268     LPCWSTR lpszcp = NULL;
1269     LPWSTR  lpszUrl_decode = NULL;
1270     DWORD dwUrlLength = dwUrlLength_orig;
1271     const WCHAR lpszSeparators[3]={';','?',0};
1272     const WCHAR lpszSlash[2]={'/',0};
1273
1274     TRACE("(%s %u %x %p)\n", debugstr_w(lpszUrl), dwUrlLength, dwFlags, lpUC);
1275
1276     if (!lpszUrl_orig || !*lpszUrl_orig || !lpUC)
1277     {
1278         INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
1279         return FALSE;
1280     }
1281     if (!dwUrlLength) dwUrlLength = strlenW(lpszUrl);
1282
1283     if (dwFlags & ICU_DECODE)
1284     {
1285         lpszUrl_decode=HeapAlloc( GetProcessHeap(), 0,  dwUrlLength * sizeof (WCHAR) );
1286         if( InternetCanonicalizeUrlW(lpszUrl_orig, lpszUrl_decode, &dwUrlLength, dwFlags))
1287         {
1288             lpszUrl =  lpszUrl_decode;
1289         }
1290     }
1291     lpszap = lpszUrl;
1292     
1293     /* Determine if the URI is absolute. */
1294     while (*lpszap != '\0')
1295     {
1296         if (isalnumW(*lpszap))
1297         {
1298             lpszap++;
1299             continue;
1300         }
1301         if ((*lpszap == ':') && (lpszap - lpszUrl >= 2))
1302         {
1303             bIsAbsolute = TRUE;
1304             lpszcp = lpszap;
1305         }
1306         else
1307         {
1308             lpszcp = lpszUrl; /* Relative url */
1309         }
1310
1311         break;
1312     }
1313
1314     lpUC->nScheme = INTERNET_SCHEME_UNKNOWN;
1315     lpUC->nPort = INTERNET_INVALID_PORT_NUMBER;
1316
1317     /* Parse <params> */
1318     lpszParam = strpbrkW(lpszap, lpszSeparators);
1319     SetUrlComponentValueW(&lpUC->lpszExtraInfo, &lpUC->dwExtraInfoLength,
1320                           lpszParam, lpszParam ? dwUrlLength-(lpszParam-lpszUrl) : 0);
1321
1322     if (bIsAbsolute) /* Parse <protocol>:[//<net_loc>] */
1323     {
1324         LPCWSTR lpszNetLoc;
1325
1326         /* Get scheme first. */
1327         lpUC->nScheme = GetInternetSchemeW(lpszUrl, lpszcp - lpszUrl);
1328         SetUrlComponentValueW(&lpUC->lpszScheme, &lpUC->dwSchemeLength,
1329                                    lpszUrl, lpszcp - lpszUrl);
1330
1331         /* Eat ':' in protocol. */
1332         lpszcp++;
1333
1334         /* double slash indicates the net_loc portion is present */
1335         if ((lpszcp[0] == '/') && (lpszcp[1] == '/'))
1336         {
1337             lpszcp += 2;
1338
1339             lpszNetLoc = strpbrkW(lpszcp, lpszSlash);
1340             if (lpszParam)
1341             {
1342                 if (lpszNetLoc)
1343                     lpszNetLoc = min(lpszNetLoc, lpszParam);
1344                 else
1345                     lpszNetLoc = lpszParam;
1346             }
1347             else if (!lpszNetLoc)
1348                 lpszNetLoc = lpszcp + dwUrlLength-(lpszcp-lpszUrl);
1349
1350             /* Parse net-loc */
1351             if (lpszNetLoc)
1352             {
1353                 LPCWSTR lpszHost;
1354                 LPCWSTR lpszPort;
1355
1356                 /* [<user>[<:password>]@]<host>[:<port>] */
1357                 /* First find the user and password if they exist */
1358
1359                 lpszHost = strchrW(lpszcp, '@');
1360                 if (lpszHost == NULL || lpszHost > lpszNetLoc)
1361                 {
1362                     /* username and password not specified. */
1363                     SetUrlComponentValueW(&lpUC->lpszUserName, &lpUC->dwUserNameLength, NULL, 0);
1364                     SetUrlComponentValueW(&lpUC->lpszPassword, &lpUC->dwPasswordLength, NULL, 0);
1365                 }
1366                 else /* Parse out username and password */
1367                 {
1368                     LPCWSTR lpszUser = lpszcp;
1369                     LPCWSTR lpszPasswd = lpszHost;
1370
1371                     while (lpszcp < lpszHost)
1372                     {
1373                         if (*lpszcp == ':')
1374                             lpszPasswd = lpszcp;
1375
1376                         lpszcp++;
1377                     }
1378
1379                     SetUrlComponentValueW(&lpUC->lpszUserName, &lpUC->dwUserNameLength,
1380                                           lpszUser, lpszPasswd - lpszUser);
1381
1382                     if (lpszPasswd != lpszHost)
1383                         lpszPasswd++;
1384                     SetUrlComponentValueW(&lpUC->lpszPassword, &lpUC->dwPasswordLength,
1385                                           lpszPasswd == lpszHost ? NULL : lpszPasswd,
1386                                           lpszHost - lpszPasswd);
1387
1388                     lpszcp++; /* Advance to beginning of host */
1389                 }
1390
1391                 /* Parse <host><:port> */
1392
1393                 lpszHost = lpszcp;
1394                 lpszPort = lpszNetLoc;
1395
1396                 /* special case for res:// URLs: there is no port here, so the host is the
1397                    entire string up to the first '/' */
1398                 if(lpUC->nScheme==INTERNET_SCHEME_RES)
1399                 {
1400                     SetUrlComponentValueW(&lpUC->lpszHostName, &lpUC->dwHostNameLength,
1401                                           lpszHost, lpszPort - lpszHost);
1402                     lpszcp=lpszNetLoc;
1403                 }
1404                 else
1405                 {
1406                     while (lpszcp < lpszNetLoc)
1407                     {
1408                         if (*lpszcp == ':')
1409                             lpszPort = lpszcp;
1410
1411                         lpszcp++;
1412                     }
1413
1414                     /* If the scheme is "file" and the host is just one letter, it's not a host */
1415                     if(lpUC->nScheme==INTERNET_SCHEME_FILE && (lpszPort-lpszHost)==1)
1416                     {
1417                         lpszcp=lpszHost;
1418                         SetUrlComponentValueW(&lpUC->lpszHostName, &lpUC->dwHostNameLength,
1419                                               NULL, 0);
1420                     }
1421                     else
1422                     {
1423                         SetUrlComponentValueW(&lpUC->lpszHostName, &lpUC->dwHostNameLength,
1424                                               lpszHost, lpszPort - lpszHost);
1425                         if (lpszPort != lpszNetLoc)
1426                             lpUC->nPort = atoiW(++lpszPort);
1427                         else switch (lpUC->nScheme)
1428                         {
1429                         case INTERNET_SCHEME_HTTP:
1430                             lpUC->nPort = INTERNET_DEFAULT_HTTP_PORT;
1431                             break;
1432                         case INTERNET_SCHEME_HTTPS:
1433                             lpUC->nPort = INTERNET_DEFAULT_HTTPS_PORT;
1434                             break;
1435                         case INTERNET_SCHEME_FTP:
1436                             lpUC->nPort = INTERNET_DEFAULT_FTP_PORT;
1437                             break;
1438                         case INTERNET_SCHEME_GOPHER:
1439                             lpUC->nPort = INTERNET_DEFAULT_GOPHER_PORT;
1440                             break;
1441                         default:
1442                             break;
1443                         }
1444                     }
1445                 }
1446             }
1447         }
1448         else
1449         {
1450             SetUrlComponentValueW(&lpUC->lpszUserName, &lpUC->dwUserNameLength, NULL, 0);
1451             SetUrlComponentValueW(&lpUC->lpszPassword, &lpUC->dwPasswordLength, NULL, 0);
1452             SetUrlComponentValueW(&lpUC->lpszHostName, &lpUC->dwHostNameLength, NULL, 0);
1453         }
1454     }
1455     else
1456     {
1457         SetUrlComponentValueW(&lpUC->lpszScheme, &lpUC->dwSchemeLength, NULL, 0);
1458         SetUrlComponentValueW(&lpUC->lpszUserName, &lpUC->dwUserNameLength, NULL, 0);
1459         SetUrlComponentValueW(&lpUC->lpszPassword, &lpUC->dwPasswordLength, NULL, 0);
1460         SetUrlComponentValueW(&lpUC->lpszHostName, &lpUC->dwHostNameLength, NULL, 0);
1461     }
1462
1463     /* Here lpszcp points to:
1464      *
1465      * <protocol>:[//<net_loc>][/path][;<params>][?<query>][#<fragment>]
1466      *                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1467      */
1468     if (lpszcp != 0 && *lpszcp != '\0' && (!lpszParam || lpszcp < lpszParam))
1469     {
1470         INT len;
1471
1472         /* Only truncate the parameter list if it's already been saved
1473          * in lpUC->lpszExtraInfo.
1474          */
1475         if (lpszParam && lpUC->dwExtraInfoLength && lpUC->lpszExtraInfo)
1476             len = lpszParam - lpszcp;
1477         else
1478         {
1479             /* Leave the parameter list in lpszUrlPath.  Strip off any trailing
1480              * newlines if necessary.
1481              */
1482             LPWSTR lpsznewline = strchrW(lpszcp, '\n');
1483             if (lpsznewline != NULL)
1484                 len = lpsznewline - lpszcp;
1485             else
1486                 len = dwUrlLength-(lpszcp-lpszUrl);
1487         }
1488         SetUrlComponentValueW(&lpUC->lpszUrlPath, &lpUC->dwUrlPathLength,
1489                                    lpszcp, len);
1490     }
1491     else
1492     {
1493         if (lpUC->lpszUrlPath && (lpUC->dwUrlPathLength > 0))
1494             lpUC->lpszUrlPath[0] = 0;
1495         lpUC->dwUrlPathLength = 0;
1496     }
1497
1498     TRACE("%s: scheme(%s) host(%s) path(%s) extra(%s)\n", debugstr_wn(lpszUrl,dwUrlLength),
1499              debugstr_wn(lpUC->lpszScheme,lpUC->dwSchemeLength),
1500              debugstr_wn(lpUC->lpszHostName,lpUC->dwHostNameLength),
1501              debugstr_wn(lpUC->lpszUrlPath,lpUC->dwUrlPathLength),
1502              debugstr_wn(lpUC->lpszExtraInfo,lpUC->dwExtraInfoLength));
1503
1504     HeapFree(GetProcessHeap(), 0, lpszUrl_decode );
1505     return TRUE;
1506 }
1507
1508 /***********************************************************************
1509  *           InternetAttemptConnect (WININET.@)
1510  *
1511  * Attempt to make a connection to the internet
1512  *
1513  * RETURNS
1514  *    ERROR_SUCCESS on success
1515  *    Error value   on failure
1516  *
1517  */
1518 DWORD WINAPI InternetAttemptConnect(DWORD dwReserved)
1519 {
1520     FIXME("Stub\n");
1521     return ERROR_SUCCESS;
1522 }
1523
1524
1525 /***********************************************************************
1526  *           InternetCanonicalizeUrlA (WININET.@)
1527  *
1528  * Escape unsafe characters and spaces
1529  *
1530  * RETURNS
1531  *    TRUE on success
1532  *    FALSE on failure
1533  *
1534  */
1535 BOOL WINAPI InternetCanonicalizeUrlA(LPCSTR lpszUrl, LPSTR lpszBuffer,
1536         LPDWORD lpdwBufferLength, DWORD dwFlags)
1537 {
1538     HRESULT hr;
1539     DWORD dwURLFlags = URL_WININET_COMPATIBILITY | URL_ESCAPE_UNSAFE;
1540
1541     TRACE("(%s, %p, %p, 0x%08x) bufferlength: %d\n", debugstr_a(lpszUrl), lpszBuffer,
1542         lpdwBufferLength, lpdwBufferLength ? *lpdwBufferLength : -1, dwFlags);
1543
1544     if(dwFlags & ICU_DECODE)
1545     {
1546         dwURLFlags |= URL_UNESCAPE;
1547         dwFlags &= ~ICU_DECODE;
1548     }
1549
1550     if(dwFlags & ICU_ESCAPE)
1551     {
1552         dwURLFlags |= URL_UNESCAPE;
1553         dwFlags &= ~ICU_ESCAPE;
1554     }
1555
1556     if(dwFlags & ICU_BROWSER_MODE)
1557     {
1558         dwURLFlags |= URL_BROWSER_MODE;
1559         dwFlags &= ~ICU_BROWSER_MODE;
1560     }
1561
1562     if(dwFlags & ICU_NO_ENCODE)
1563     {
1564         /* Flip this bit to correspond to URL_ESCAPE_UNSAFE */
1565         dwURLFlags ^= URL_ESCAPE_UNSAFE;
1566         dwFlags &= ~ICU_NO_ENCODE;
1567     }
1568
1569     if (dwFlags) FIXME("Unhandled flags 0x%08x\n", dwFlags);
1570
1571     hr = UrlCanonicalizeA(lpszUrl, lpszBuffer, lpdwBufferLength, dwURLFlags);
1572     if (hr == E_POINTER) SetLastError(ERROR_INSUFFICIENT_BUFFER);
1573     if (hr == E_INVALIDARG) SetLastError(ERROR_INVALID_PARAMETER);
1574
1575     return (hr == S_OK) ? TRUE : FALSE;
1576 }
1577
1578 /***********************************************************************
1579  *           InternetCanonicalizeUrlW (WININET.@)
1580  *
1581  * Escape unsafe characters and spaces
1582  *
1583  * RETURNS
1584  *    TRUE on success
1585  *    FALSE on failure
1586  *
1587  */
1588 BOOL WINAPI InternetCanonicalizeUrlW(LPCWSTR lpszUrl, LPWSTR lpszBuffer,
1589     LPDWORD lpdwBufferLength, DWORD dwFlags)
1590 {
1591     HRESULT hr;
1592     DWORD dwURLFlags = URL_WININET_COMPATIBILITY | URL_ESCAPE_UNSAFE;
1593
1594     TRACE("(%s, %p, %p, 0x%08x) bufferlength: %d\n", debugstr_w(lpszUrl), lpszBuffer,
1595         lpdwBufferLength, lpdwBufferLength ? *lpdwBufferLength : -1, dwFlags);
1596
1597     if(dwFlags & ICU_DECODE)
1598     {
1599         dwURLFlags |= URL_UNESCAPE;
1600         dwFlags &= ~ICU_DECODE;
1601     }
1602
1603     if(dwFlags & ICU_ESCAPE)
1604     {
1605         dwURLFlags |= URL_UNESCAPE;
1606         dwFlags &= ~ICU_ESCAPE;
1607     }
1608
1609     if(dwFlags & ICU_BROWSER_MODE)
1610     {
1611         dwURLFlags |= URL_BROWSER_MODE;
1612         dwFlags &= ~ICU_BROWSER_MODE;
1613     }
1614
1615     if(dwFlags & ICU_NO_ENCODE)
1616     {
1617         /* Flip this bit to correspond to URL_ESCAPE_UNSAFE */
1618         dwURLFlags ^= URL_ESCAPE_UNSAFE;
1619         dwFlags &= ~ICU_NO_ENCODE;
1620     }
1621
1622     if (dwFlags) FIXME("Unhandled flags 0x%08x\n", dwFlags);
1623
1624     hr = UrlCanonicalizeW(lpszUrl, lpszBuffer, lpdwBufferLength, dwURLFlags);
1625     if (hr == E_POINTER) SetLastError(ERROR_INSUFFICIENT_BUFFER);
1626     if (hr == E_INVALIDARG) SetLastError(ERROR_INVALID_PARAMETER);
1627
1628     return (hr == S_OK) ? TRUE : FALSE;
1629 }
1630
1631 /* #################################################### */
1632
1633 static INTERNET_STATUS_CALLBACK set_status_callback(
1634     LPWININETHANDLEHEADER lpwh, INTERNET_STATUS_CALLBACK callback, BOOL unicode)
1635 {
1636     INTERNET_STATUS_CALLBACK ret;
1637
1638     if (unicode) lpwh->dwInternalFlags |= INET_CALLBACKW;
1639     else lpwh->dwInternalFlags &= ~INET_CALLBACKW;
1640
1641     ret = lpwh->lpfnStatusCB;
1642     lpwh->lpfnStatusCB = callback;
1643
1644     return ret;
1645 }
1646
1647 /***********************************************************************
1648  *           InternetSetStatusCallbackA (WININET.@)
1649  *
1650  * Sets up a callback function which is called as progress is made
1651  * during an operation.
1652  *
1653  * RETURNS
1654  *    Previous callback or NULL         on success
1655  *    INTERNET_INVALID_STATUS_CALLBACK  on failure
1656  *
1657  */
1658 INTERNET_STATUS_CALLBACK WINAPI InternetSetStatusCallbackA(
1659         HINTERNET hInternet ,INTERNET_STATUS_CALLBACK lpfnIntCB)
1660 {
1661     INTERNET_STATUS_CALLBACK retVal;
1662     LPWININETHANDLEHEADER lpwh;
1663
1664     TRACE("0x%08x\n", (ULONG)hInternet);
1665     
1666     if (!(lpwh = WININET_GetObject(hInternet)))
1667         return INTERNET_INVALID_STATUS_CALLBACK;
1668
1669     retVal = set_status_callback(lpwh, lpfnIntCB, FALSE);
1670
1671     WININET_Release( lpwh );
1672     return retVal;
1673 }
1674
1675 /***********************************************************************
1676  *           InternetSetStatusCallbackW (WININET.@)
1677  *
1678  * Sets up a callback function which is called as progress is made
1679  * during an operation.
1680  *
1681  * RETURNS
1682  *    Previous callback or NULL         on success
1683  *    INTERNET_INVALID_STATUS_CALLBACK  on failure
1684  *
1685  */
1686 INTERNET_STATUS_CALLBACK WINAPI InternetSetStatusCallbackW(
1687         HINTERNET hInternet ,INTERNET_STATUS_CALLBACK lpfnIntCB)
1688 {
1689     INTERNET_STATUS_CALLBACK retVal;
1690     LPWININETHANDLEHEADER lpwh;
1691
1692     TRACE("0x%08x\n", (ULONG)hInternet);
1693
1694     if (!(lpwh = WININET_GetObject(hInternet)))
1695         return INTERNET_INVALID_STATUS_CALLBACK;
1696
1697     retVal = set_status_callback(lpwh, lpfnIntCB, TRUE);
1698
1699     WININET_Release( lpwh );
1700     return retVal;
1701 }
1702
1703 /***********************************************************************
1704  *           InternetSetFilePointer (WININET.@)
1705  */
1706 DWORD WINAPI InternetSetFilePointer(HINTERNET hFile, LONG lDistanceToMove,
1707     PVOID pReserved, DWORD dwMoveContext, DWORD_PTR dwContext)
1708 {
1709     FIXME("stub\n");
1710     return FALSE;
1711 }
1712
1713 /***********************************************************************
1714  *           InternetWriteFile (WININET.@)
1715  *
1716  * Write data to an open internet file
1717  *
1718  * RETURNS
1719  *    TRUE  on success
1720  *    FALSE on failure
1721  *
1722  */
1723 BOOL WINAPI InternetWriteFile(HINTERNET hFile, LPCVOID lpBuffer,
1724         DWORD dwNumOfBytesToWrite, LPDWORD lpdwNumOfBytesWritten)
1725 {
1726     LPWININETHANDLEHEADER lpwh;
1727     BOOL retval = FALSE;
1728
1729     TRACE("(%p %p %d %p)\n", hFile, lpBuffer, dwNumOfBytesToWrite, lpdwNumOfBytesWritten);
1730
1731     lpwh = WININET_GetObject( hFile );
1732     if (!lpwh) {
1733         WARN("Invalid handle\n");
1734         SetLastError(ERROR_INVALID_HANDLE);
1735         return FALSE;
1736     }
1737
1738     if(lpwh->vtbl->WriteFile) {
1739         retval = lpwh->vtbl->WriteFile(lpwh, lpBuffer, dwNumOfBytesToWrite, lpdwNumOfBytesWritten);
1740     }else {
1741         WARN("No Writefile method.\n");
1742         SetLastError(ERROR_INVALID_HANDLE);
1743         retval = FALSE;
1744     }
1745
1746     WININET_Release( lpwh );
1747
1748     return retval;
1749 }
1750
1751
1752 /***********************************************************************
1753  *           InternetReadFile (WININET.@)
1754  *
1755  * Read data from an open internet file
1756  *
1757  * RETURNS
1758  *    TRUE  on success
1759  *    FALSE on failure
1760  *
1761  */
1762 BOOL WINAPI InternetReadFile(HINTERNET hFile, LPVOID lpBuffer,
1763         DWORD dwNumOfBytesToRead, LPDWORD pdwNumOfBytesRead)
1764 {
1765     LPWININETHANDLEHEADER hdr;
1766     DWORD res = ERROR_INTERNET_INCORRECT_HANDLE_TYPE;
1767
1768     TRACE("%p %p %d %p\n", hFile, lpBuffer, dwNumOfBytesToRead, pdwNumOfBytesRead);
1769
1770     hdr = WININET_GetObject(hFile);
1771     if (!hdr) {
1772         INTERNET_SetLastError(ERROR_INVALID_HANDLE);
1773         return FALSE;
1774     }
1775
1776     if(hdr->vtbl->ReadFile)
1777         res = hdr->vtbl->ReadFile(hdr, lpBuffer, dwNumOfBytesToRead, pdwNumOfBytesRead);
1778
1779     WININET_Release(hdr);
1780
1781     TRACE("-- %s (%u) (bytes read: %d)\n", res == ERROR_SUCCESS ? "TRUE": "FALSE", res,
1782           pdwNumOfBytesRead ? *pdwNumOfBytesRead : -1);
1783
1784     if(res != ERROR_SUCCESS)
1785         SetLastError(res);
1786     return res == ERROR_SUCCESS;
1787 }
1788
1789 /***********************************************************************
1790  *           InternetReadFileExA (WININET.@)
1791  *
1792  * Read data from an open internet file
1793  *
1794  * PARAMS
1795  *  hFile         [I] Handle returned by InternetOpenUrl or HttpOpenRequest.
1796  *  lpBuffersOut  [I/O] Buffer.
1797  *  dwFlags       [I] Flags. See notes.
1798  *  dwContext     [I] Context for callbacks.
1799  *
1800  * RETURNS
1801  *    TRUE  on success
1802  *    FALSE on failure
1803  *
1804  * NOTES
1805  *  The parameter dwFlags include zero or more of the following flags:
1806  *|IRF_ASYNC - Makes the call asynchronous.
1807  *|IRF_SYNC - Makes the call synchronous.
1808  *|IRF_USE_CONTEXT - Forces dwContext to be used.
1809  *|IRF_NO_WAIT - Don't block if the data is not available, just return what is available.
1810  *
1811  * However, in testing IRF_USE_CONTEXT seems to have no effect - dwContext isn't used.
1812  *
1813  * SEE
1814  *  InternetOpenUrlA(), HttpOpenRequestA()
1815  */
1816 BOOL WINAPI InternetReadFileExA(HINTERNET hFile, LPINTERNET_BUFFERSA lpBuffersOut,
1817         DWORD dwFlags, DWORD_PTR dwContext)
1818 {
1819     LPWININETHANDLEHEADER hdr;
1820     DWORD res = ERROR_INTERNET_INCORRECT_HANDLE_TYPE;
1821
1822     TRACE("(%p %p 0x%x 0x%lx)\n", hFile, lpBuffersOut, dwFlags, dwContext);
1823
1824     hdr = WININET_GetObject(hFile);
1825     if (!hdr) {
1826         INTERNET_SetLastError(ERROR_INVALID_HANDLE);
1827         return FALSE;
1828     }
1829
1830     if(hdr->vtbl->ReadFileExA)
1831         res = hdr->vtbl->ReadFileExA(hdr, lpBuffersOut, dwFlags, dwContext);
1832
1833     WININET_Release(hdr);
1834
1835     TRACE("-- %s (%u, bytes read: %d)\n", res == ERROR_SUCCESS ? "TRUE": "FALSE",
1836           res, lpBuffersOut->dwBufferLength);
1837
1838     if(res != ERROR_SUCCESS)
1839         SetLastError(res);
1840     return res == ERROR_SUCCESS;
1841 }
1842
1843 /***********************************************************************
1844  *           InternetReadFileExW (WININET.@)
1845  *
1846  * Read data from an open internet file.
1847  *
1848  * PARAMS
1849  *  hFile         [I] Handle returned by InternetOpenUrl() or HttpOpenRequest().
1850  *  lpBuffersOut  [I/O] Buffer.
1851  *  dwFlags       [I] Flags.
1852  *  dwContext     [I] Context for callbacks.
1853  *
1854  * RETURNS
1855  *    FALSE, last error is set to ERROR_CALL_NOT_IMPLEMENTED
1856  *
1857  * NOTES
1858  *  Not implemented in Wine or native either (as of IE6 SP2).
1859  *
1860  */
1861 BOOL WINAPI InternetReadFileExW(HINTERNET hFile, LPINTERNET_BUFFERSW lpBuffer,
1862         DWORD dwFlags, DWORD_PTR dwContext)
1863 {
1864   ERR("(%p, %p, 0x%x, 0x%lx): not implemented in native\n", hFile, lpBuffer, dwFlags, dwContext);
1865
1866   INTERNET_SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1867   return FALSE;
1868 }
1869
1870 /***********************************************************************
1871  *           INET_QueryOptionHelper (internal)
1872  */
1873 static BOOL INET_QueryOptionHelper(BOOL bIsUnicode, HINTERNET hInternet, DWORD dwOption,
1874                                    LPVOID lpBuffer, LPDWORD lpdwBufferLength)
1875 {
1876     LPWININETHANDLEHEADER lpwhh;
1877     BOOL bSuccess = FALSE;
1878
1879     TRACE("(%p, 0x%08x, %p, %p)\n", hInternet, dwOption, lpBuffer, lpdwBufferLength);
1880
1881     lpwhh = WININET_GetObject( hInternet );
1882
1883     switch (dwOption)
1884     {
1885         case INTERNET_OPTION_REQUEST_FLAGS:
1886         {
1887             ULONG flags = 4;
1888             TRACE("INTERNET_OPTION_REQUEST_FLAGS: %d\n", flags);
1889             if (*lpdwBufferLength < sizeof(ULONG))
1890                 INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
1891             else
1892             {
1893                 memcpy(lpBuffer, &flags, sizeof(ULONG));
1894                 bSuccess = TRUE;
1895             }
1896             *lpdwBufferLength = sizeof(ULONG);
1897             break;
1898         }
1899
1900         case INTERNET_OPTION_USER_AGENT:
1901         {
1902             DWORD required;
1903             LPWININETAPPINFOW ai = (LPWININETAPPINFOW)lpwhh;
1904
1905             TRACE("INTERNET_OPTION_USER_AGENT\n");
1906
1907             if (!lpwhh || lpwhh->htype != INTERNET_HANDLE_TYPE_INTERNET)
1908             {
1909                 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1910                 return FALSE;
1911             }
1912             if (bIsUnicode)
1913             {
1914                 required = (strlenW(ai->lpszAgent) + 1) * sizeof(WCHAR);
1915                 if (*lpdwBufferLength < required)
1916                     INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
1917                 else if (lpBuffer)
1918                 {
1919                     strcpyW(lpBuffer, ai->lpszAgent);
1920                     bSuccess = TRUE;
1921                 }
1922             }
1923             else
1924             {
1925                 required = WideCharToMultiByte(CP_ACP, 0, ai->lpszAgent, -1, NULL, 0, NULL, NULL);
1926                 if (*lpdwBufferLength < required)
1927                     INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
1928                 else if (lpBuffer)
1929                 {
1930                     WideCharToMultiByte(CP_ACP, 0, ai->lpszAgent, -1, lpBuffer, required, NULL, NULL);
1931                     bSuccess = TRUE;
1932                 }
1933             }
1934             *lpdwBufferLength = required;
1935             break;
1936         }
1937         case INTERNET_OPTION_HTTP_VERSION:
1938         {
1939             if (*lpdwBufferLength < sizeof(HTTP_VERSION_INFO))
1940                 INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
1941             else
1942             {
1943                 /*
1944                  * Presently hardcoded to 1.1
1945                  */
1946                 ((HTTP_VERSION_INFO*)lpBuffer)->dwMajorVersion = 1;
1947                 ((HTTP_VERSION_INFO*)lpBuffer)->dwMinorVersion = 1;
1948                 bSuccess = TRUE;
1949             }
1950             *lpdwBufferLength = sizeof(HTTP_VERSION_INFO);
1951             break;
1952         }
1953        case INTERNET_OPTION_CONNECTED_STATE:
1954        {
1955             DWORD *pdwConnectedState = (DWORD *)lpBuffer;
1956             FIXME("INTERNET_OPTION_CONNECTED_STATE: semi-stub\n");
1957
1958             if (*lpdwBufferLength < sizeof(*pdwConnectedState))
1959                  INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
1960             else
1961             {
1962                 *pdwConnectedState = INTERNET_STATE_CONNECTED;
1963                 bSuccess = TRUE;
1964             }
1965             *lpdwBufferLength = sizeof(*pdwConnectedState);
1966             break;
1967         }
1968         case INTERNET_OPTION_PROXY:
1969         {
1970             LPWININETAPPINFOW lpwai = (LPWININETAPPINFOW)lpwhh;
1971             WININETAPPINFOW wai;
1972
1973             if (lpwai == NULL)
1974             {
1975                 TRACE("Getting global proxy info\n");
1976                 memset(&wai, 0, sizeof(WININETAPPINFOW));
1977                 INTERNET_ConfigureProxy( &wai );
1978                 lpwai = &wai;
1979             }
1980
1981             if (bIsUnicode)
1982             {
1983                 INTERNET_PROXY_INFOW *pPI = (INTERNET_PROXY_INFOW *)lpBuffer;
1984                 DWORD proxyBytesRequired = 0, proxyBypassBytesRequired = 0;
1985
1986                 if (lpwai->lpszProxy)
1987                     proxyBytesRequired = (lstrlenW(lpwai->lpszProxy) + 1) *
1988                      sizeof(WCHAR);
1989                 if (lpwai->lpszProxyBypass)
1990                     proxyBypassBytesRequired =
1991                      (lstrlenW(lpwai->lpszProxyBypass) + 1) * sizeof(WCHAR);
1992                 if (*lpdwBufferLength < sizeof(INTERNET_PROXY_INFOW) +
1993                  proxyBytesRequired + proxyBypassBytesRequired)
1994                     INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
1995                 else
1996                 {
1997                     LPWSTR proxy = (LPWSTR)((LPBYTE)lpBuffer +
1998                                             sizeof(INTERNET_PROXY_INFOW));
1999                     LPWSTR proxy_bypass = (LPWSTR)((LPBYTE)lpBuffer +
2000                                                    sizeof(INTERNET_PROXY_INFOW) +
2001                                                    proxyBytesRequired);
2002
2003                     pPI->dwAccessType = lpwai->dwAccessType;
2004                     pPI->lpszProxy = NULL;
2005                     pPI->lpszProxyBypass = NULL;
2006                     if (lpwai->lpszProxy)
2007                     {
2008                         lstrcpyW(proxy, lpwai->lpszProxy);
2009                         pPI->lpszProxy = proxy;
2010                     }
2011
2012                     if (lpwai->lpszProxyBypass)
2013                     {
2014                         lstrcpyW(proxy_bypass, lpwai->lpszProxyBypass);
2015                         pPI->lpszProxyBypass = proxy_bypass;
2016                     }
2017                     bSuccess = TRUE;
2018                 }
2019                 *lpdwBufferLength = sizeof(INTERNET_PROXY_INFOW) +
2020                  proxyBytesRequired + proxyBypassBytesRequired;
2021             }
2022             else
2023             {
2024                 INTERNET_PROXY_INFOA *pPI = (INTERNET_PROXY_INFOA *)lpBuffer;
2025                 DWORD proxyBytesRequired = 0, proxyBypassBytesRequired = 0;
2026
2027                 if (lpwai->lpszProxy)
2028                     proxyBytesRequired = WideCharToMultiByte(CP_ACP, 0,
2029                      lpwai->lpszProxy, -1, NULL, 0, NULL, NULL);
2030                 if (lpwai->lpszProxyBypass)
2031                     proxyBypassBytesRequired = WideCharToMultiByte(CP_ACP, 0,
2032                      lpwai->lpszProxyBypass, -1, NULL, 0, NULL, NULL);
2033                 if (*lpdwBufferLength < sizeof(INTERNET_PROXY_INFOA) +
2034                  proxyBytesRequired + proxyBypassBytesRequired)
2035                     INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
2036                 else
2037                 {
2038                     LPSTR proxy = (LPSTR)((LPBYTE)lpBuffer +
2039                                           sizeof(INTERNET_PROXY_INFOA));
2040                     LPSTR proxy_bypass = (LPSTR)((LPBYTE)lpBuffer +
2041                                                  sizeof(INTERNET_PROXY_INFOA) +
2042                                                  proxyBytesRequired);
2043
2044                     pPI->dwAccessType = lpwai->dwAccessType;
2045                     pPI->lpszProxy = NULL;
2046                     pPI->lpszProxyBypass = NULL;
2047                     if (lpwai->lpszProxy)
2048                     {
2049                         WideCharToMultiByte(CP_ACP, 0, lpwai->lpszProxy, -1,
2050                                             proxy, proxyBytesRequired, NULL, NULL);
2051                         pPI->lpszProxy = proxy;
2052                     }
2053
2054                     if (lpwai->lpszProxyBypass)
2055                     {
2056                         WideCharToMultiByte(CP_ACP, 0, lpwai->lpszProxyBypass,
2057                                             -1, proxy_bypass, proxyBypassBytesRequired,
2058                                             NULL, NULL);
2059                         pPI->lpszProxyBypass = proxy_bypass;
2060                     }
2061                     bSuccess = TRUE;
2062                 }
2063                 *lpdwBufferLength = sizeof(INTERNET_PROXY_INFOA) +
2064                  proxyBytesRequired + proxyBypassBytesRequired;
2065             }
2066             break;
2067         }
2068         case INTERNET_OPTION_MAX_CONNS_PER_SERVER:
2069         {
2070             ULONG conn = 2;
2071             TRACE("INTERNET_OPTION_MAX_CONNS_PER_SERVER: %d\n", conn);
2072             if (*lpdwBufferLength < sizeof(ULONG))
2073                 INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
2074             else
2075             {
2076                 memcpy(lpBuffer, &conn, sizeof(ULONG));
2077                 bSuccess = TRUE;
2078             }
2079             *lpdwBufferLength = sizeof(ULONG);
2080             break;
2081         }
2082         case INTERNET_OPTION_MAX_CONNS_PER_1_0_SERVER:
2083         {
2084             ULONG conn = 4;
2085             TRACE("INTERNET_OPTION_MAX_CONNS_1_0_SERVER: %d\n", conn);
2086             if (*lpdwBufferLength < sizeof(ULONG))
2087                 INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
2088             else
2089             {
2090                 memcpy(lpBuffer, &conn, sizeof(ULONG));
2091                 bSuccess = TRUE;
2092             }
2093             *lpdwBufferLength = sizeof(ULONG);
2094             break;
2095         }
2096         case INTERNET_OPTION_SECURITY_FLAGS:
2097             FIXME("INTERNET_OPTION_SECURITY_FLAGS: Stub\n");
2098             bSuccess = TRUE;
2099             break;
2100
2101         case INTERNET_OPTION_VERSION:
2102         {
2103             TRACE("INTERNET_OPTION_VERSION\n");
2104             if (*lpdwBufferLength < sizeof(INTERNET_VERSION_INFO))
2105                 INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
2106             else
2107             {
2108                 static const INTERNET_VERSION_INFO info = { 1, 2 };
2109                 memcpy(lpBuffer, &info, sizeof(info));
2110                 *lpdwBufferLength = sizeof(info);
2111                 bSuccess = TRUE;
2112             }
2113             break;
2114         }
2115         case INTERNET_OPTION_PER_CONNECTION_OPTION:
2116             FIXME("INTERNET_OPTION_PER_CONNECTION_OPTION stub\n");
2117             if (*lpdwBufferLength < sizeof(INTERNET_PER_CONN_OPTION_LISTW))
2118                 INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
2119             else
2120             {
2121                 INTERNET_PER_CONN_OPTION_LISTW *con = lpBuffer;
2122                 int x;
2123                 bSuccess = TRUE;
2124                 for (x = 0; x < con->dwOptionCount; ++x)
2125                 {
2126                     INTERNET_PER_CONN_OPTIONW *option = con->pOptions + x;
2127                     switch (option->dwOption)
2128                     {
2129                     case INTERNET_PER_CONN_FLAGS:
2130                         option->Value.dwValue = PROXY_TYPE_DIRECT;
2131                         break;
2132
2133                     case INTERNET_PER_CONN_PROXY_SERVER:
2134                     case INTERNET_PER_CONN_PROXY_BYPASS:
2135                     case INTERNET_PER_CONN_AUTOCONFIG_URL:
2136                     case INTERNET_PER_CONN_AUTODISCOVERY_FLAGS:
2137                     case INTERNET_PER_CONN_AUTOCONFIG_SECONDARY_URL:
2138                     case INTERNET_PER_CONN_AUTOCONFIG_RELOAD_DELAY_MINS:
2139                     case INTERNET_PER_CONN_AUTOCONFIG_LAST_DETECT_TIME:
2140                     case INTERNET_PER_CONN_AUTOCONFIG_LAST_DETECT_URL:
2141                         FIXME("Unhandled dwOption %d\n", option->dwOption);
2142                         option->Value.dwValue = 0;
2143                         bSuccess = FALSE;
2144                         break;
2145
2146                     default:
2147                         FIXME("Unknown dwOption %d\n", option->dwOption);
2148                         bSuccess = FALSE;
2149                         break;
2150                     }
2151                 }
2152                 if (!bSuccess)
2153                     INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
2154             }
2155             break;
2156     case 66:
2157         FIXME("66\n");
2158         bSuccess = TRUE;
2159         break;
2160         default: {
2161             if(lpwhh) {
2162                 DWORD res;
2163
2164                 res = lpwhh->vtbl->QueryOption(lpwhh, dwOption, lpBuffer, lpdwBufferLength, bIsUnicode);
2165                 if(res == ERROR_SUCCESS)
2166                     bSuccess = TRUE;
2167                 else
2168                     SetLastError(res);
2169             }else {
2170                 FIXME("Stub! %d\n", dwOption);
2171                 break;
2172             }
2173         }
2174     }
2175     if (lpwhh)
2176         WININET_Release( lpwhh );
2177
2178     return bSuccess;
2179 }
2180
2181 /***********************************************************************
2182  *           InternetQueryOptionW (WININET.@)
2183  *
2184  * Queries an options on the specified handle
2185  *
2186  * RETURNS
2187  *    TRUE  on success
2188  *    FALSE on failure
2189  *
2190  */
2191 BOOL WINAPI InternetQueryOptionW(HINTERNET hInternet, DWORD dwOption,
2192                                  LPVOID lpBuffer, LPDWORD lpdwBufferLength)
2193 {
2194     return INET_QueryOptionHelper(TRUE, hInternet, dwOption, lpBuffer, lpdwBufferLength);
2195 }
2196
2197 /***********************************************************************
2198  *           InternetQueryOptionA (WININET.@)
2199  *
2200  * Queries an options on the specified handle
2201  *
2202  * RETURNS
2203  *    TRUE  on success
2204  *    FALSE on failure
2205  *
2206  */
2207 BOOL WINAPI InternetQueryOptionA(HINTERNET hInternet, DWORD dwOption,
2208                                  LPVOID lpBuffer, LPDWORD lpdwBufferLength)
2209 {
2210     return INET_QueryOptionHelper(FALSE, hInternet, dwOption, lpBuffer, lpdwBufferLength);
2211 }
2212
2213
2214 /***********************************************************************
2215  *           InternetSetOptionW (WININET.@)
2216  *
2217  * Sets an options on the specified handle
2218  *
2219  * RETURNS
2220  *    TRUE  on success
2221  *    FALSE on failure
2222  *
2223  */
2224 BOOL WINAPI InternetSetOptionW(HINTERNET hInternet, DWORD dwOption,
2225                            LPVOID lpBuffer, DWORD dwBufferLength)
2226 {
2227     LPWININETHANDLEHEADER lpwhh;
2228     BOOL ret = TRUE;
2229
2230     TRACE("(%p %d %p %d)\n", hInternet, dwOption, lpBuffer, dwBufferLength);
2231
2232     lpwhh = (LPWININETHANDLEHEADER) WININET_GetObject( hInternet );
2233     if(lpwhh && lpwhh->vtbl->SetOption) {
2234         DWORD res;
2235
2236         res = lpwhh->vtbl->SetOption(lpwhh, dwOption, lpBuffer, dwBufferLength);
2237         if(res != ERROR_INTERNET_INVALID_OPTION) {
2238             WININET_Release( lpwhh );
2239
2240             if(res != ERROR_SUCCESS)
2241                 SetLastError(res);
2242
2243             return res == ERROR_SUCCESS;
2244         }
2245     }
2246
2247     switch (dwOption)
2248     {
2249     case INTERNET_OPTION_CALLBACK:
2250       {
2251         INTERNET_STATUS_CALLBACK callback = *(INTERNET_STATUS_CALLBACK *)lpBuffer;
2252         ret = (set_status_callback(lpwhh, callback, TRUE) != INTERNET_INVALID_STATUS_CALLBACK);
2253         break;
2254       }
2255     case INTERNET_OPTION_HTTP_VERSION:
2256       {
2257         HTTP_VERSION_INFO* pVersion=(HTTP_VERSION_INFO*)lpBuffer;
2258         FIXME("Option INTERNET_OPTION_HTTP_VERSION(%d,%d): STUB\n",pVersion->dwMajorVersion,pVersion->dwMinorVersion);
2259       }
2260       break;
2261     case INTERNET_OPTION_ERROR_MASK:
2262       {
2263         ULONG flags = *(ULONG *)lpBuffer;
2264         FIXME("Option INTERNET_OPTION_ERROR_MASK(%d): STUB\n", flags);
2265       }
2266       break;
2267     case INTERNET_OPTION_CODEPAGE:
2268       {
2269         ULONG codepage = *(ULONG *)lpBuffer;
2270         FIXME("Option INTERNET_OPTION_CODEPAGE (%d): STUB\n", codepage);
2271       }
2272       break;
2273     case INTERNET_OPTION_REQUEST_PRIORITY:
2274       {
2275         ULONG priority = *(ULONG *)lpBuffer;
2276         FIXME("Option INTERNET_OPTION_REQUEST_PRIORITY (%d): STUB\n", priority);
2277       }
2278       break;
2279     case INTERNET_OPTION_CONNECT_TIMEOUT:
2280       {
2281         ULONG connecttimeout = *(ULONG *)lpBuffer;
2282         FIXME("Option INTERNET_OPTION_CONNECT_TIMEOUT (%d): STUB\n", connecttimeout);
2283       }
2284       break;
2285     case INTERNET_OPTION_DATA_RECEIVE_TIMEOUT:
2286       {
2287         ULONG receivetimeout = *(ULONG *)lpBuffer;
2288         FIXME("Option INTERNET_OPTION_DATA_RECEIVE_TIMEOUT (%d): STUB\n", receivetimeout);
2289       }
2290       break;
2291     case INTERNET_OPTION_MAX_CONNS_PER_SERVER:
2292       {
2293         ULONG conns = *(ULONG *)lpBuffer;
2294         FIXME("Option INTERNET_OPTION_MAX_CONNS_PER_SERVER (%d): STUB\n", conns);
2295       }
2296       break;
2297     case INTERNET_OPTION_MAX_CONNS_PER_1_0_SERVER:
2298       {
2299         ULONG conns = *(ULONG *)lpBuffer;
2300         FIXME("Option INTERNET_OPTION_MAX_CONNS_PER_1_0_SERVER (%d): STUB\n", conns);
2301       }
2302       break;
2303     case INTERNET_OPTION_RESET_URLCACHE_SESSION:
2304         FIXME("Option INTERNET_OPTION_RESET_URLCACHE_SESSION: STUB\n");
2305         break;
2306     case INTERNET_OPTION_END_BROWSER_SESSION:
2307         FIXME("Option INTERNET_OPTION_END_BROWSER_SESSION: STUB\n");
2308         break;
2309     case INTERNET_OPTION_CONNECTED_STATE:
2310         FIXME("Option INTERNET_OPTION_CONNECTED_STATE: STUB\n");
2311         break;
2312     case INTERNET_OPTION_DISABLE_PASSPORT_AUTH:
2313         TRACE("Option INTERNET_OPTION_DISABLE_PASSPORT_AUTH: harmless stub, since not enabled\n");
2314         break;
2315     case INTERNET_OPTION_SEND_TIMEOUT:
2316     case INTERNET_OPTION_RECEIVE_TIMEOUT:
2317     {
2318         ULONG timeout = *(ULONG *)lpBuffer;
2319         FIXME("INTERNET_OPTION_SEND/RECEIVE_TIMEOUT %d\n", timeout);
2320         break;
2321     }
2322     case INTERNET_OPTION_CONNECT_RETRIES:
2323     {
2324         ULONG retries = *(ULONG *)lpBuffer;
2325         FIXME("INTERNET_OPTION_CONNECT_RETRIES %d\n", retries);
2326         break;
2327     }
2328     case INTERNET_OPTION_CONTEXT_VALUE:
2329          FIXME("Option INTERNET_OPTION_CONTEXT_VALUE; STUB\n");
2330          break;
2331     case INTERNET_OPTION_SECURITY_FLAGS:
2332          FIXME("Option INTERNET_OPTION_SECURITY_FLAGS; STUB\n");
2333          break;
2334     case INTERNET_OPTION_DISABLE_AUTODIAL:
2335          FIXME("Option INTERNET_OPTION_DISABLE_AUTODIAL; STUB\n");
2336          break;
2337     case 86:
2338         FIXME("86\n");
2339         break;
2340     default:
2341         FIXME("Option %d STUB\n",dwOption);
2342         INTERNET_SetLastError(ERROR_INTERNET_INVALID_OPTION);
2343         ret = FALSE;
2344         break;
2345     }
2346
2347     if(lpwhh)
2348         WININET_Release( lpwhh );
2349
2350     return ret;
2351 }
2352
2353
2354 /***********************************************************************
2355  *           InternetSetOptionA (WININET.@)
2356  *
2357  * Sets an options on the specified handle.
2358  *
2359  * RETURNS
2360  *    TRUE  on success
2361  *    FALSE on failure
2362  *
2363  */
2364 BOOL WINAPI InternetSetOptionA(HINTERNET hInternet, DWORD dwOption,
2365                            LPVOID lpBuffer, DWORD dwBufferLength)
2366 {
2367     LPVOID wbuffer;
2368     DWORD wlen;
2369     BOOL r;
2370
2371     switch( dwOption )
2372     {
2373     case INTERNET_OPTION_CALLBACK:
2374         {
2375         LPWININETHANDLEHEADER lpwh;
2376         INTERNET_STATUS_CALLBACK callback = *(INTERNET_STATUS_CALLBACK *)lpBuffer;
2377
2378         if (!(lpwh = WININET_GetObject(hInternet))) return FALSE;
2379         r = (set_status_callback(lpwh, callback, FALSE) != INTERNET_INVALID_STATUS_CALLBACK);
2380         WININET_Release(lpwh);
2381         return r;
2382         }
2383     case INTERNET_OPTION_PROXY:
2384         {
2385         LPINTERNET_PROXY_INFOA pi = (LPINTERNET_PROXY_INFOA) lpBuffer;
2386         LPINTERNET_PROXY_INFOW piw;
2387         DWORD proxlen, prbylen;
2388         LPWSTR prox, prby;
2389
2390         proxlen = MultiByteToWideChar( CP_ACP, 0, pi->lpszProxy, -1, NULL, 0);
2391         prbylen= MultiByteToWideChar( CP_ACP, 0, pi->lpszProxyBypass, -1, NULL, 0);
2392         wlen = sizeof(*piw) + proxlen + prbylen;
2393         wbuffer = HeapAlloc( GetProcessHeap(), 0, wlen*sizeof(WCHAR) );
2394         piw = (LPINTERNET_PROXY_INFOW) wbuffer;
2395         piw->dwAccessType = pi->dwAccessType;
2396         prox = (LPWSTR) &piw[1];
2397         prby = &prox[proxlen+1];
2398         MultiByteToWideChar( CP_ACP, 0, pi->lpszProxy, -1, prox, proxlen);
2399         MultiByteToWideChar( CP_ACP, 0, pi->lpszProxyBypass, -1, prby, prbylen);
2400         piw->lpszProxy = prox;
2401         piw->lpszProxyBypass = prby;
2402         }
2403         break;
2404     case INTERNET_OPTION_USER_AGENT:
2405     case INTERNET_OPTION_USERNAME:
2406     case INTERNET_OPTION_PASSWORD:
2407         wlen = MultiByteToWideChar( CP_ACP, 0, lpBuffer, dwBufferLength,
2408                                    NULL, 0 );
2409         wbuffer = HeapAlloc( GetProcessHeap(), 0, wlen*sizeof(WCHAR) );
2410         MultiByteToWideChar( CP_ACP, 0, lpBuffer, dwBufferLength,
2411                                    wbuffer, wlen );
2412         break;
2413     default:
2414         wbuffer = lpBuffer;
2415         wlen = dwBufferLength;
2416     }
2417
2418     r = InternetSetOptionW(hInternet,dwOption, wbuffer, wlen);
2419
2420     if( lpBuffer != wbuffer )
2421         HeapFree( GetProcessHeap(), 0, wbuffer );
2422
2423     return r;
2424 }
2425
2426
2427 /***********************************************************************
2428  *           InternetSetOptionExA (WININET.@)
2429  */
2430 BOOL WINAPI InternetSetOptionExA(HINTERNET hInternet, DWORD dwOption,
2431                            LPVOID lpBuffer, DWORD dwBufferLength, DWORD dwFlags)
2432 {
2433     FIXME("Flags %08x ignored\n", dwFlags);
2434     return InternetSetOptionA( hInternet, dwOption, lpBuffer, dwBufferLength );
2435 }
2436
2437 /***********************************************************************
2438  *           InternetSetOptionExW (WININET.@)
2439  */
2440 BOOL WINAPI InternetSetOptionExW(HINTERNET hInternet, DWORD dwOption,
2441                            LPVOID lpBuffer, DWORD dwBufferLength, DWORD dwFlags)
2442 {
2443     FIXME("Flags %08x ignored\n", dwFlags);
2444     if( dwFlags & ~ISO_VALID_FLAGS )
2445     {
2446         INTERNET_SetLastError( ERROR_INVALID_PARAMETER );
2447         return FALSE;
2448     }
2449     return InternetSetOptionW( hInternet, dwOption, lpBuffer, dwBufferLength );
2450 }
2451
2452 static const WCHAR WININET_wkday[7][4] =
2453     { { 'S','u','n', 0 }, { 'M','o','n', 0 }, { 'T','u','e', 0 }, { 'W','e','d', 0 },
2454       { 'T','h','u', 0 }, { 'F','r','i', 0 }, { 'S','a','t', 0 } };
2455 static const WCHAR WININET_month[12][4] =
2456     { { 'J','a','n', 0 }, { 'F','e','b', 0 }, { 'M','a','r', 0 }, { 'A','p','r', 0 },
2457       { 'M','a','y', 0 }, { 'J','u','n', 0 }, { 'J','u','l', 0 }, { 'A','u','g', 0 },
2458       { 'S','e','p', 0 }, { 'O','c','t', 0 }, { 'N','o','v', 0 }, { 'D','e','c', 0 } };
2459
2460 /***********************************************************************
2461  *           InternetTimeFromSystemTimeA (WININET.@)
2462  */
2463 BOOL WINAPI InternetTimeFromSystemTimeA( const SYSTEMTIME* time, DWORD format, LPSTR string, DWORD size )
2464 {
2465     BOOL ret;
2466     WCHAR stringW[INTERNET_RFC1123_BUFSIZE];
2467
2468     TRACE( "%p 0x%08x %p 0x%08x\n", time, format, string, size );
2469
2470     ret = InternetTimeFromSystemTimeW( time, format, stringW, sizeof(stringW) );
2471     if (ret) WideCharToMultiByte( CP_ACP, 0, stringW, -1, string, size, NULL, NULL );
2472
2473     return ret;
2474 }
2475
2476 /***********************************************************************
2477  *           InternetTimeFromSystemTimeW (WININET.@)
2478  */
2479 BOOL WINAPI InternetTimeFromSystemTimeW( const SYSTEMTIME* time, DWORD format, LPWSTR string, DWORD size )
2480 {
2481     static const WCHAR date[] =
2482         { '%','s',',',' ','%','0','2','d',' ','%','s',' ','%','4','d',' ','%','0',
2483           '2','d',':','%','0','2','d',':','%','0','2','d',' ','G','M','T', 0 };
2484
2485     TRACE( "%p 0x%08x %p 0x%08x\n", time, format, string, size );
2486
2487     if (!time || !string) return FALSE;
2488
2489     if (format != INTERNET_RFC1123_FORMAT || size < INTERNET_RFC1123_BUFSIZE * sizeof(WCHAR))
2490         return FALSE;
2491
2492     sprintfW( string, date,
2493               WININET_wkday[time->wDayOfWeek],
2494               time->wDay,
2495               WININET_month[time->wMonth - 1],
2496               time->wYear,
2497               time->wHour,
2498               time->wMinute,
2499               time->wSecond );
2500
2501     return TRUE;
2502 }
2503
2504 /***********************************************************************
2505  *           InternetTimeToSystemTimeA (WININET.@)
2506  */
2507 BOOL WINAPI InternetTimeToSystemTimeA( LPCSTR string, SYSTEMTIME* time, DWORD reserved )
2508 {
2509     BOOL ret = FALSE;
2510     WCHAR *stringW;
2511     int len;
2512
2513     TRACE( "%s %p 0x%08x\n", debugstr_a(string), time, reserved );
2514
2515     len = MultiByteToWideChar( CP_ACP, 0, string, -1, NULL, 0 );
2516     stringW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
2517
2518     if (stringW)
2519     {
2520         MultiByteToWideChar( CP_ACP, 0, string, -1, stringW, len );
2521         ret = InternetTimeToSystemTimeW( stringW, time, reserved );
2522         HeapFree( GetProcessHeap(), 0, stringW );
2523     }
2524     return ret;
2525 }
2526
2527 /***********************************************************************
2528  *           InternetTimeToSystemTimeW (WININET.@)
2529  */
2530 BOOL WINAPI InternetTimeToSystemTimeW( LPCWSTR string, SYSTEMTIME* time, DWORD reserved )
2531 {
2532     unsigned int i;
2533     const WCHAR *s = string;
2534     WCHAR       *end;
2535
2536     TRACE( "%s %p 0x%08x\n", debugstr_w(string), time, reserved );
2537
2538     if (!string || !time) return FALSE;
2539
2540     /* Windows does this too */
2541     GetSystemTime( time );
2542
2543     /*  Convert an RFC1123 time such as 'Fri, 07 Jan 2005 12:06:35 GMT' into
2544      *  a SYSTEMTIME structure.
2545      */
2546
2547     while (*s && !isalphaW( *s )) s++;
2548     if (s[0] == '\0' || s[1] == '\0' || s[2] == '\0') return TRUE;
2549     time->wDayOfWeek = 7;
2550
2551     for (i = 0; i < 7; i++)
2552     {
2553         if (toupperW( WININET_wkday[i][0] ) == toupperW( s[0] ) &&
2554             toupperW( WININET_wkday[i][1] ) == toupperW( s[1] ) &&
2555             toupperW( WININET_wkday[i][2] ) == toupperW( s[2] ) )
2556         {
2557             time->wDayOfWeek = i;
2558             break;
2559         }
2560     }
2561
2562     if (time->wDayOfWeek > 6) return TRUE;
2563     while (*s && !isdigitW( *s )) s++;
2564     time->wDay = strtolW( s, &end, 10 );
2565     s = end;
2566
2567     while (*s && !isalphaW( *s )) s++;
2568     if (s[0] == '\0' || s[1] == '\0' || s[2] == '\0') return TRUE;
2569     time->wMonth = 0;
2570
2571     for (i = 0; i < 12; i++)
2572     {
2573         if (toupperW( WININET_month[i][0]) == toupperW( s[0] ) &&
2574             toupperW( WININET_month[i][1]) == toupperW( s[1] ) &&
2575             toupperW( WININET_month[i][2]) == toupperW( s[2] ) )
2576         {
2577             time->wMonth = i + 1;
2578             break;
2579         }
2580     }
2581     if (time->wMonth == 0) return TRUE;
2582
2583     while (*s && !isdigitW( *s )) s++;
2584     if (*s == '\0') return TRUE;
2585     time->wYear = strtolW( s, &end, 10 );
2586     s = end;
2587
2588     while (*s && !isdigitW( *s )) s++;
2589     if (*s == '\0') return TRUE;
2590     time->wHour = strtolW( s, &end, 10 );
2591     s = end;
2592
2593     while (*s && !isdigitW( *s )) s++;
2594     if (*s == '\0') return TRUE;
2595     time->wMinute = strtolW( s, &end, 10 );
2596     s = end;
2597
2598     while (*s && !isdigitW( *s )) s++;
2599     if (*s == '\0') return TRUE;
2600     time->wSecond = strtolW( s, &end, 10 );
2601     s = end;
2602
2603     time->wMilliseconds = 0;
2604     return TRUE;
2605 }
2606
2607 /***********************************************************************
2608  *      InternetCheckConnectionW (WININET.@)
2609  *
2610  * Pings a requested host to check internet connection
2611  *
2612  * RETURNS
2613  *   TRUE on success and FALSE on failure. If a failure then
2614  *   ERROR_NOT_CONNECTED is placed into GetLastError
2615  *
2616  */
2617 BOOL WINAPI InternetCheckConnectionW( LPCWSTR lpszUrl, DWORD dwFlags, DWORD dwReserved )
2618 {
2619 /*
2620  * this is a kludge which runs the resident ping program and reads the output.
2621  *
2622  * Anyone have a better idea?
2623  */
2624
2625   BOOL   rc = FALSE;
2626   static const CHAR ping[] = "ping -c 1 ";
2627   static const CHAR redirect[] = " >/dev/null 2>/dev/null";
2628   CHAR *command = NULL;
2629   WCHAR hostW[1024];
2630   DWORD len;
2631   INTERNET_PORT port;
2632   int status = -1;
2633
2634   FIXME("\n");
2635
2636   /*
2637    * Crack or set the Address
2638    */
2639   if (lpszUrl == NULL)
2640   {
2641      /*
2642       * According to the doc we are supposed to use the ip for the next
2643       * server in the WnInet internal server database. I have
2644       * no idea what that is or how to get it.
2645       *
2646       * So someone needs to implement this.
2647       */
2648      FIXME("Unimplemented with URL of NULL\n");
2649      return TRUE;
2650   }
2651   else
2652   {
2653      URL_COMPONENTSW components;
2654
2655      ZeroMemory(&components,sizeof(URL_COMPONENTSW));
2656      components.lpszHostName = (LPWSTR)&hostW;
2657      components.dwHostNameLength = 1024;
2658
2659      if (!InternetCrackUrlW(lpszUrl,0,0,&components))
2660        goto End;
2661
2662      TRACE("host name : %s\n",debugstr_w(components.lpszHostName));
2663      port = components.nPort;
2664      TRACE("port: %d\n", port);
2665   }
2666
2667   if (dwFlags & FLAG_ICC_FORCE_CONNECTION)
2668   {
2669       struct sockaddr_in sin;
2670       int fd;
2671
2672       if (!GetAddress(hostW, port, &sin))
2673           goto End;
2674       fd = socket(sin.sin_family, SOCK_STREAM, 0);
2675       if (fd != -1)
2676       {
2677           if (connect(fd, (struct sockaddr *)&sin, sizeof(sin)) == 0)
2678               rc = TRUE;
2679           close(fd);
2680       }
2681   }
2682   else
2683   {
2684       /*
2685        * Build our ping command
2686        */
2687       len = WideCharToMultiByte(CP_UNIXCP, 0, hostW, -1, NULL, 0, NULL, NULL);
2688       command = HeapAlloc( GetProcessHeap(), 0, strlen(ping)+len+strlen(redirect) );
2689       strcpy(command,ping);
2690       WideCharToMultiByte(CP_UNIXCP, 0, hostW, -1, command+strlen(ping), len, NULL, NULL);
2691       strcat(command,redirect);
2692
2693       TRACE("Ping command is : %s\n",command);
2694
2695       status = system(command);
2696
2697       TRACE("Ping returned a code of %i\n",status);
2698
2699       /* Ping return code of 0 indicates success */
2700       if (status == 0)
2701          rc = TRUE;
2702   }
2703
2704 End:
2705
2706   HeapFree( GetProcessHeap(), 0, command );
2707   if (rc == FALSE)
2708     INTERNET_SetLastError(ERROR_NOT_CONNECTED);
2709
2710   return rc;
2711 }
2712
2713
2714 /***********************************************************************
2715  *      InternetCheckConnectionA (WININET.@)
2716  *
2717  * Pings a requested host to check internet connection
2718  *
2719  * RETURNS
2720  *   TRUE on success and FALSE on failure. If a failure then
2721  *   ERROR_NOT_CONNECTED is placed into GetLastError
2722  *
2723  */
2724 BOOL WINAPI InternetCheckConnectionA(LPCSTR lpszUrl, DWORD dwFlags, DWORD dwReserved)
2725 {
2726     WCHAR *szUrl;
2727     INT len;
2728     BOOL rc;
2729
2730     len = MultiByteToWideChar(CP_ACP, 0, lpszUrl, -1, NULL, 0);
2731     if (!(szUrl = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR))))
2732         return FALSE;
2733     MultiByteToWideChar(CP_ACP, 0, lpszUrl, -1, szUrl, len);
2734     rc = InternetCheckConnectionW(szUrl, dwFlags, dwReserved);
2735     HeapFree(GetProcessHeap(), 0, szUrl);
2736     
2737     return rc;
2738 }
2739
2740
2741 /**********************************************************
2742  *      INTERNET_InternetOpenUrlW (internal)
2743  *
2744  * Opens an URL
2745  *
2746  * RETURNS
2747  *   handle of connection or NULL on failure
2748  */
2749 static HINTERNET INTERNET_InternetOpenUrlW(LPWININETAPPINFOW hIC, LPCWSTR lpszUrl,
2750     LPCWSTR lpszHeaders, DWORD dwHeadersLength, DWORD dwFlags, DWORD_PTR dwContext)
2751 {
2752     URL_COMPONENTSW urlComponents;
2753     WCHAR protocol[32], hostName[MAXHOSTNAME], userName[1024];
2754     WCHAR password[1024], path[2048], extra[1024];
2755     HINTERNET client = NULL, client1 = NULL;
2756     
2757     TRACE("(%p, %s, %s, %08x, %08x, %08lx)\n", hIC, debugstr_w(lpszUrl), debugstr_w(lpszHeaders),
2758           dwHeadersLength, dwFlags, dwContext);
2759     
2760     urlComponents.dwStructSize = sizeof(URL_COMPONENTSW);
2761     urlComponents.lpszScheme = protocol;
2762     urlComponents.dwSchemeLength = 32;
2763     urlComponents.lpszHostName = hostName;
2764     urlComponents.dwHostNameLength = MAXHOSTNAME;
2765     urlComponents.lpszUserName = userName;
2766     urlComponents.dwUserNameLength = 1024;
2767     urlComponents.lpszPassword = password;
2768     urlComponents.dwPasswordLength = 1024;
2769     urlComponents.lpszUrlPath = path;
2770     urlComponents.dwUrlPathLength = 2048;
2771     urlComponents.lpszExtraInfo = extra;
2772     urlComponents.dwExtraInfoLength = 1024;
2773     if(!InternetCrackUrlW(lpszUrl, strlenW(lpszUrl), 0, &urlComponents))
2774         return NULL;
2775     switch(urlComponents.nScheme) {
2776     case INTERNET_SCHEME_FTP:
2777         if(urlComponents.nPort == 0)
2778             urlComponents.nPort = INTERNET_DEFAULT_FTP_PORT;
2779         client = FTP_Connect(hIC, hostName, urlComponents.nPort,
2780                              userName, password, dwFlags, dwContext, INET_OPENURL);
2781         if(client == NULL)
2782             break;
2783         client1 = FtpOpenFileW(client, path, GENERIC_READ, dwFlags, dwContext);
2784         if(client1 == NULL) {
2785             InternetCloseHandle(client);
2786             break;
2787         }
2788         break;
2789         
2790     case INTERNET_SCHEME_HTTP:
2791     case INTERNET_SCHEME_HTTPS: {
2792         static const WCHAR szStars[] = { '*','/','*', 0 };
2793         LPCWSTR accept[2] = { szStars, NULL };
2794         if(urlComponents.nPort == 0) {
2795             if(urlComponents.nScheme == INTERNET_SCHEME_HTTP)
2796                 urlComponents.nPort = INTERNET_DEFAULT_HTTP_PORT;
2797             else
2798                 urlComponents.nPort = INTERNET_DEFAULT_HTTPS_PORT;
2799         }
2800         /* FIXME: should use pointers, not handles, as handles are not thread-safe */
2801         client = HTTP_Connect(hIC, hostName, urlComponents.nPort,
2802                               userName, password, dwFlags, dwContext, INET_OPENURL);
2803         if(client == NULL)
2804             break;
2805
2806         if (urlComponents.dwExtraInfoLength) {
2807                 WCHAR *path_extra;
2808                 DWORD len = urlComponents.dwUrlPathLength + urlComponents.dwExtraInfoLength + 1;
2809
2810                 if (!(path_extra = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR))))
2811                 {
2812                         InternetCloseHandle(client);
2813                         break;
2814                 }
2815                 strcpyW(path_extra, urlComponents.lpszUrlPath);
2816                 strcatW(path_extra, urlComponents.lpszExtraInfo);
2817                 client1 = HttpOpenRequestW(client, NULL, path_extra, NULL, NULL, accept, dwFlags, dwContext);
2818                 HeapFree(GetProcessHeap(), 0, path_extra);
2819         }
2820         else
2821                 client1 = HttpOpenRequestW(client, NULL, path, NULL, NULL, accept, dwFlags, dwContext);
2822
2823         if(client1 == NULL) {
2824             InternetCloseHandle(client);
2825             break;
2826         }
2827         HttpAddRequestHeadersW(client1, lpszHeaders, dwHeadersLength, HTTP_ADDREQ_FLAG_ADD);
2828         if (!HttpSendRequestW(client1, NULL, 0, NULL, 0) &&
2829             GetLastError() != ERROR_IO_PENDING) {
2830             InternetCloseHandle(client1);
2831             client1 = NULL;
2832             break;
2833         }
2834     }
2835     case INTERNET_SCHEME_GOPHER:
2836         /* gopher doesn't seem to be implemented in wine, but it's supposed
2837          * to be supported by InternetOpenUrlA. */
2838     default:
2839         INTERNET_SetLastError(ERROR_INTERNET_UNRECOGNIZED_SCHEME);
2840         break;
2841     }
2842
2843     TRACE(" %p <--\n", client1);
2844     
2845     return client1;
2846 }
2847
2848 /**********************************************************
2849  *      InternetOpenUrlW (WININET.@)
2850  *
2851  * Opens an URL
2852  *
2853  * RETURNS
2854  *   handle of connection or NULL on failure
2855  */
2856 static void AsyncInternetOpenUrlProc(WORKREQUEST *workRequest)
2857 {
2858     struct WORKREQ_INTERNETOPENURLW const *req = &workRequest->u.InternetOpenUrlW;
2859     LPWININETAPPINFOW hIC = (LPWININETAPPINFOW) workRequest->hdr;
2860
2861     TRACE("%p\n", hIC);
2862
2863     INTERNET_InternetOpenUrlW(hIC, req->lpszUrl,
2864                               req->lpszHeaders, req->dwHeadersLength, req->dwFlags, req->dwContext);
2865     HeapFree(GetProcessHeap(), 0, req->lpszUrl);
2866     HeapFree(GetProcessHeap(), 0, req->lpszHeaders);
2867 }
2868
2869 HINTERNET WINAPI InternetOpenUrlW(HINTERNET hInternet, LPCWSTR lpszUrl,
2870     LPCWSTR lpszHeaders, DWORD dwHeadersLength, DWORD dwFlags, DWORD_PTR dwContext)
2871 {
2872     HINTERNET ret = NULL;
2873     LPWININETAPPINFOW hIC = NULL;
2874
2875     if (TRACE_ON(wininet)) {
2876         TRACE("(%p, %s, %s, %08x, %08x, %08lx)\n", hInternet, debugstr_w(lpszUrl), debugstr_w(lpszHeaders),
2877               dwHeadersLength, dwFlags, dwContext);
2878         TRACE("  flags :");
2879         dump_INTERNET_FLAGS(dwFlags);
2880     }
2881
2882     if (!lpszUrl)
2883     {
2884         INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
2885         goto lend;
2886     }
2887
2888     hIC = (LPWININETAPPINFOW) WININET_GetObject( hInternet );
2889     if (NULL == hIC ||  hIC->hdr.htype != WH_HINIT) {
2890         INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
2891         goto lend;
2892     }
2893     
2894     if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC) {
2895         WORKREQUEST workRequest;
2896         struct WORKREQ_INTERNETOPENURLW *req;
2897
2898         workRequest.asyncproc = AsyncInternetOpenUrlProc;
2899         workRequest.hdr = WININET_AddRef( &hIC->hdr );
2900         req = &workRequest.u.InternetOpenUrlW;
2901         req->lpszUrl = WININET_strdupW(lpszUrl);
2902         if (lpszHeaders)
2903             req->lpszHeaders = WININET_strdupW(lpszHeaders);
2904         else
2905             req->lpszHeaders = 0;
2906         req->dwHeadersLength = dwHeadersLength;
2907         req->dwFlags = dwFlags;
2908         req->dwContext = dwContext;
2909         
2910         INTERNET_AsyncCall(&workRequest);
2911         /*
2912          * This is from windows.
2913          */
2914         INTERNET_SetLastError(ERROR_IO_PENDING);
2915     } else {
2916         ret = INTERNET_InternetOpenUrlW(hIC, lpszUrl, lpszHeaders, dwHeadersLength, dwFlags, dwContext);
2917     }
2918     
2919   lend:
2920     if( hIC )
2921         WININET_Release( &hIC->hdr );
2922     TRACE(" %p <--\n", ret);
2923     
2924     return ret;
2925 }
2926
2927 /**********************************************************
2928  *      InternetOpenUrlA (WININET.@)
2929  *
2930  * Opens an URL
2931  *
2932  * RETURNS
2933  *   handle of connection or NULL on failure
2934  */
2935 HINTERNET WINAPI InternetOpenUrlA(HINTERNET hInternet, LPCSTR lpszUrl,
2936     LPCSTR lpszHeaders, DWORD dwHeadersLength, DWORD dwFlags, DWORD_PTR dwContext)
2937 {
2938     HINTERNET rc = NULL;
2939
2940     INT lenUrl;
2941     INT lenHeaders = 0;
2942     LPWSTR szUrl = NULL;
2943     LPWSTR szHeaders = NULL;
2944
2945     TRACE("\n");
2946
2947     if(lpszUrl) {
2948         lenUrl = MultiByteToWideChar(CP_ACP, 0, lpszUrl, -1, NULL, 0 );
2949         szUrl = HeapAlloc(GetProcessHeap(), 0, lenUrl*sizeof(WCHAR));
2950         if(!szUrl)
2951             return NULL;
2952         MultiByteToWideChar(CP_ACP, 0, lpszUrl, -1, szUrl, lenUrl);
2953     }
2954
2955     if(lpszHeaders) {
2956         lenHeaders = MultiByteToWideChar(CP_ACP, 0, lpszHeaders, dwHeadersLength, NULL, 0 );
2957         szHeaders = HeapAlloc(GetProcessHeap(), 0, lenHeaders*sizeof(WCHAR));
2958         if(!szHeaders) {
2959             HeapFree(GetProcessHeap(), 0, szUrl);
2960             return NULL;
2961         }
2962         MultiByteToWideChar(CP_ACP, 0, lpszHeaders, dwHeadersLength, szHeaders, lenHeaders);
2963     }
2964     
2965     rc = InternetOpenUrlW(hInternet, szUrl, szHeaders,
2966         lenHeaders, dwFlags, dwContext);
2967
2968     HeapFree(GetProcessHeap(), 0, szUrl);
2969     HeapFree(GetProcessHeap(), 0, szHeaders);
2970
2971     return rc;
2972 }
2973
2974
2975 static LPWITHREADERROR INTERNET_AllocThreadError(void)
2976 {
2977     LPWITHREADERROR lpwite = HeapAlloc(GetProcessHeap(), 0, sizeof(*lpwite));
2978
2979     if (lpwite)
2980     {
2981         lpwite->dwError = 0;
2982         lpwite->response[0] = '\0';
2983     }
2984
2985     if (!TlsSetValue(g_dwTlsErrIndex, lpwite))
2986     {
2987         HeapFree(GetProcessHeap(), 0, lpwite);
2988         return NULL;
2989     }
2990
2991     return lpwite;
2992 }
2993
2994
2995 /***********************************************************************
2996  *           INTERNET_SetLastError (internal)
2997  *
2998  * Set last thread specific error
2999  *
3000  * RETURNS
3001  *
3002  */
3003 void INTERNET_SetLastError(DWORD dwError)
3004 {
3005     LPWITHREADERROR lpwite = (LPWITHREADERROR)TlsGetValue(g_dwTlsErrIndex);
3006
3007     if (!lpwite)
3008         lpwite = INTERNET_AllocThreadError();
3009
3010     SetLastError(dwError);
3011     if(lpwite)
3012         lpwite->dwError = dwError;
3013 }
3014
3015
3016 /***********************************************************************
3017  *           INTERNET_GetLastError (internal)
3018  *
3019  * Get last thread specific error
3020  *
3021  * RETURNS
3022  *
3023  */
3024 DWORD INTERNET_GetLastError(void)
3025 {
3026     LPWITHREADERROR lpwite = (LPWITHREADERROR)TlsGetValue(g_dwTlsErrIndex);
3027     if (!lpwite) return 0;
3028     /* TlsGetValue clears last error, so set it again here */
3029     SetLastError(lpwite->dwError);
3030     return lpwite->dwError;
3031 }
3032
3033
3034 /***********************************************************************
3035  *           INTERNET_WorkerThreadFunc (internal)
3036  *
3037  * Worker thread execution function
3038  *
3039  * RETURNS
3040  *
3041  */
3042 static DWORD CALLBACK INTERNET_WorkerThreadFunc(LPVOID lpvParam)
3043 {
3044     LPWORKREQUEST lpRequest = lpvParam;
3045     WORKREQUEST workRequest;
3046
3047     TRACE("\n");
3048
3049     workRequest = *lpRequest;
3050     HeapFree(GetProcessHeap(), 0, lpRequest);
3051
3052     workRequest.asyncproc(&workRequest);
3053
3054     WININET_Release( workRequest.hdr );
3055     return TRUE;
3056 }
3057
3058
3059 /***********************************************************************
3060  *           INTERNET_AsyncCall (internal)
3061  *
3062  * Retrieves work request from queue
3063  *
3064  * RETURNS
3065  *
3066  */
3067 BOOL INTERNET_AsyncCall(LPWORKREQUEST lpWorkRequest)
3068 {
3069     BOOL bSuccess;
3070     LPWORKREQUEST lpNewRequest;
3071
3072     TRACE("\n");
3073
3074     lpNewRequest = HeapAlloc(GetProcessHeap(), 0, sizeof(WORKREQUEST));
3075     if (!lpNewRequest)
3076         return FALSE;
3077
3078     *lpNewRequest = *lpWorkRequest;
3079
3080     bSuccess = QueueUserWorkItem(INTERNET_WorkerThreadFunc, lpNewRequest, WT_EXECUTELONGFUNCTION);
3081     if (!bSuccess)
3082     {
3083         HeapFree(GetProcessHeap(), 0, lpNewRequest);
3084         INTERNET_SetLastError(ERROR_INTERNET_ASYNC_THREAD_FAILED);
3085     }
3086
3087     return bSuccess;
3088 }
3089
3090
3091 /***********************************************************************
3092  *          INTERNET_GetResponseBuffer  (internal)
3093  *
3094  * RETURNS
3095  *
3096  */
3097 LPSTR INTERNET_GetResponseBuffer(void)
3098 {
3099     LPWITHREADERROR lpwite = (LPWITHREADERROR)TlsGetValue(g_dwTlsErrIndex);
3100     if (!lpwite)
3101         lpwite = INTERNET_AllocThreadError();
3102     TRACE("\n");
3103     return lpwite->response;
3104 }
3105
3106 /***********************************************************************
3107  *           INTERNET_GetNextLine  (internal)
3108  *
3109  * Parse next line in directory string listing
3110  *
3111  * RETURNS
3112  *   Pointer to beginning of next line
3113  *   NULL on failure
3114  *
3115  */
3116
3117 LPSTR INTERNET_GetNextLine(INT nSocket, LPDWORD dwLen)
3118 {
3119     struct pollfd pfd;
3120     BOOL bSuccess = FALSE;
3121     INT nRecv = 0;
3122     LPSTR lpszBuffer = INTERNET_GetResponseBuffer();
3123
3124     TRACE("\n");
3125
3126     pfd.fd = nSocket;
3127     pfd.events = POLLIN;
3128
3129     while (nRecv < MAX_REPLY_LEN)
3130     {
3131         if (poll(&pfd,1, RESPONSE_TIMEOUT * 1000) > 0)
3132         {
3133             if (recv(nSocket, &lpszBuffer[nRecv], 1, 0) <= 0)
3134             {
3135                 INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS);
3136                 goto lend;
3137             }
3138
3139             if (lpszBuffer[nRecv] == '\n')
3140             {
3141                 bSuccess = TRUE;
3142                 break;
3143             }
3144             if (lpszBuffer[nRecv] != '\r')
3145                 nRecv++;
3146         }
3147         else
3148         {
3149             INTERNET_SetLastError(ERROR_INTERNET_TIMEOUT);
3150             goto lend;
3151         }
3152     }
3153
3154 lend:
3155     if (bSuccess)
3156     {
3157         lpszBuffer[nRecv] = '\0';
3158         *dwLen = nRecv - 1;
3159         TRACE(":%d %s\n", nRecv, lpszBuffer);
3160         return lpszBuffer;
3161     }
3162     else
3163     {
3164         return NULL;
3165     }
3166 }
3167
3168 /**********************************************************
3169  *      InternetQueryDataAvailable (WININET.@)
3170  *
3171  * Determines how much data is available to be read.
3172  *
3173  * RETURNS
3174  *   TRUE on success, FALSE if an error occurred. If
3175  *   INTERNET_FLAG_ASYNC was specified in InternetOpen, and
3176  *   no data is presently available, FALSE is returned with
3177  *   the last error ERROR_IO_PENDING; a callback with status
3178  *   INTERNET_STATUS_REQUEST_COMPLETE will be sent when more
3179  *   data is available.
3180  */
3181 BOOL WINAPI InternetQueryDataAvailable( HINTERNET hFile,
3182                                 LPDWORD lpdwNumberOfBytesAvailble,
3183                                 DWORD dwFlags, DWORD_PTR dwContext)
3184 {
3185     WININETHANDLEHEADER *hdr;
3186     DWORD res;
3187
3188     TRACE("(%p %p %x %lx)\n", hFile, lpdwNumberOfBytesAvailble, dwFlags, dwContext);
3189
3190     hdr = WININET_GetObject( hFile );
3191     if (!hdr) {
3192         INTERNET_SetLastError(ERROR_INVALID_HANDLE);
3193         return FALSE;
3194     }
3195
3196     if(hdr->vtbl->QueryDataAvailable) {
3197         res = hdr->vtbl->QueryDataAvailable(hdr, lpdwNumberOfBytesAvailble, dwFlags, dwContext);
3198     }else {
3199         WARN("wrong handle\n");
3200         res = ERROR_INTERNET_INCORRECT_HANDLE_TYPE;
3201     }
3202
3203     WININET_Release(hdr);
3204
3205     if(res != ERROR_SUCCESS)
3206         SetLastError(res);
3207     return res == ERROR_SUCCESS;
3208 }
3209
3210
3211 /***********************************************************************
3212  *      InternetLockRequestFile (WININET.@)
3213  */
3214 BOOL WINAPI InternetLockRequestFile( HINTERNET hInternet, HANDLE
3215 *lphLockReqHandle)
3216 {
3217     FIXME("STUB\n");
3218     return FALSE;
3219 }
3220
3221 BOOL WINAPI InternetUnlockRequestFile( HANDLE hLockHandle)
3222 {
3223     FIXME("STUB\n");
3224     return FALSE;
3225 }
3226
3227
3228 /***********************************************************************
3229  *      InternetAutodial (WININET.@)
3230  *
3231  * On windows this function is supposed to dial the default internet
3232  * connection. We don't want to have Wine dial out to the internet so
3233  * we return TRUE by default. It might be nice to check if we are connected.
3234  *
3235  * RETURNS
3236  *   TRUE on success
3237  *   FALSE on failure
3238  *
3239  */
3240 BOOL WINAPI InternetAutodial(DWORD dwFlags, HWND hwndParent)
3241 {
3242     FIXME("STUB\n");
3243
3244     /* Tell that we are connected to the internet. */
3245     return TRUE;
3246 }
3247
3248 /***********************************************************************
3249  *      InternetAutodialHangup (WININET.@)
3250  *
3251  * Hangs up a connection made with InternetAutodial
3252  *
3253  * PARAM
3254  *    dwReserved
3255  * RETURNS
3256  *   TRUE on success
3257  *   FALSE on failure
3258  *
3259  */
3260 BOOL WINAPI InternetAutodialHangup(DWORD dwReserved)
3261 {
3262     FIXME("STUB\n");
3263
3264     /* we didn't dial, we don't disconnect */
3265     return TRUE;
3266 }
3267
3268 /***********************************************************************
3269  *      InternetCombineUrlA (WININET.@)
3270  *
3271  * Combine a base URL with a relative URL
3272  *
3273  * RETURNS
3274  *   TRUE on success
3275  *   FALSE on failure
3276  *
3277  */
3278
3279 BOOL WINAPI InternetCombineUrlA(LPCSTR lpszBaseUrl, LPCSTR lpszRelativeUrl,
3280                                 LPSTR lpszBuffer, LPDWORD lpdwBufferLength,
3281                                 DWORD dwFlags)
3282 {
3283     HRESULT hr=S_OK;
3284
3285     TRACE("(%s, %s, %p, %p, 0x%08x)\n", debugstr_a(lpszBaseUrl), debugstr_a(lpszRelativeUrl), lpszBuffer, lpdwBufferLength, dwFlags);
3286
3287     /* Flip this bit to correspond to URL_ESCAPE_UNSAFE */
3288     dwFlags ^= ICU_NO_ENCODE;
3289     hr=UrlCombineA(lpszBaseUrl,lpszRelativeUrl,lpszBuffer,lpdwBufferLength,dwFlags);
3290
3291     return (hr==S_OK);
3292 }
3293
3294 /***********************************************************************
3295  *      InternetCombineUrlW (WININET.@)
3296  *
3297  * Combine a base URL with a relative URL
3298  *
3299  * RETURNS
3300  *   TRUE on success
3301  *   FALSE on failure
3302  *
3303  */
3304
3305 BOOL WINAPI InternetCombineUrlW(LPCWSTR lpszBaseUrl, LPCWSTR lpszRelativeUrl,
3306                                 LPWSTR lpszBuffer, LPDWORD lpdwBufferLength,
3307                                 DWORD dwFlags)
3308 {
3309     HRESULT hr=S_OK;
3310
3311     TRACE("(%s, %s, %p, %p, 0x%08x)\n", debugstr_w(lpszBaseUrl), debugstr_w(lpszRelativeUrl), lpszBuffer, lpdwBufferLength, dwFlags);
3312
3313     /* Flip this bit to correspond to URL_ESCAPE_UNSAFE */
3314     dwFlags ^= ICU_NO_ENCODE;
3315     hr=UrlCombineW(lpszBaseUrl,lpszRelativeUrl,lpszBuffer,lpdwBufferLength,dwFlags);
3316
3317     return (hr==S_OK);
3318 }
3319
3320 /* max port num is 65535 => 5 digits */
3321 #define MAX_WORD_DIGITS 5
3322
3323 #define URL_GET_COMP_LENGTH(url, component) ((url)->dw##component##Length ? \
3324     (url)->dw##component##Length : strlenW((url)->lpsz##component))
3325 #define URL_GET_COMP_LENGTHA(url, component) ((url)->dw##component##Length ? \
3326     (url)->dw##component##Length : strlen((url)->lpsz##component))
3327
3328 static BOOL url_uses_default_port(INTERNET_SCHEME nScheme, INTERNET_PORT nPort)
3329 {
3330     if ((nScheme == INTERNET_SCHEME_HTTP) &&
3331         (nPort == INTERNET_DEFAULT_HTTP_PORT))
3332         return TRUE;
3333     if ((nScheme == INTERNET_SCHEME_HTTPS) &&
3334         (nPort == INTERNET_DEFAULT_HTTPS_PORT))
3335         return TRUE;
3336     if ((nScheme == INTERNET_SCHEME_FTP) &&
3337         (nPort == INTERNET_DEFAULT_FTP_PORT))
3338         return TRUE;
3339     if ((nScheme == INTERNET_SCHEME_GOPHER) &&
3340         (nPort == INTERNET_DEFAULT_GOPHER_PORT))
3341         return TRUE;
3342
3343     if (nPort == INTERNET_INVALID_PORT_NUMBER)
3344         return TRUE;
3345
3346     return FALSE;
3347 }
3348
3349 /* opaque urls do not fit into the standard url hierarchy and don't have
3350  * two following slashes */
3351 static inline BOOL scheme_is_opaque(INTERNET_SCHEME nScheme)
3352 {
3353     return (nScheme != INTERNET_SCHEME_FTP) &&
3354            (nScheme != INTERNET_SCHEME_GOPHER) &&
3355            (nScheme != INTERNET_SCHEME_HTTP) &&
3356            (nScheme != INTERNET_SCHEME_HTTPS) &&
3357            (nScheme != INTERNET_SCHEME_FILE);
3358 }
3359
3360 static LPCWSTR INTERNET_GetSchemeString(INTERNET_SCHEME scheme)
3361 {
3362     int index;
3363     if (scheme < INTERNET_SCHEME_FIRST)
3364         return NULL;
3365     index = scheme - INTERNET_SCHEME_FIRST;
3366     if (index >= sizeof(url_schemes)/sizeof(url_schemes[0]))
3367         return NULL;
3368     return (LPCWSTR)&url_schemes[index];
3369 }
3370
3371 /* we can calculate using ansi strings because we're just
3372  * calculating string length, not size
3373  */
3374 static BOOL calc_url_length(LPURL_COMPONENTSW lpUrlComponents,
3375                             LPDWORD lpdwUrlLength)
3376 {
3377     INTERNET_SCHEME nScheme;
3378
3379     *lpdwUrlLength = 0;
3380
3381     if (lpUrlComponents->lpszScheme)
3382     {
3383         DWORD dwLen = URL_GET_COMP_LENGTH(lpUrlComponents, Scheme);
3384         *lpdwUrlLength += dwLen;
3385         nScheme = GetInternetSchemeW(lpUrlComponents->lpszScheme, dwLen);
3386     }
3387     else
3388     {
3389         LPCWSTR scheme;
3390
3391         nScheme = lpUrlComponents->nScheme;
3392
3393         if (nScheme == INTERNET_SCHEME_DEFAULT)
3394             nScheme = INTERNET_SCHEME_HTTP;
3395         scheme = INTERNET_GetSchemeString(nScheme);
3396         *lpdwUrlLength += strlenW(scheme);
3397     }
3398
3399     (*lpdwUrlLength)++; /* ':' */
3400     if (!scheme_is_opaque(nScheme) || lpUrlComponents->lpszHostName)
3401         *lpdwUrlLength += strlen("//");
3402
3403     if (lpUrlComponents->lpszUserName)
3404     {
3405         *lpdwUrlLength += URL_GET_COMP_LENGTH(lpUrlComponents, UserName);
3406         *lpdwUrlLength += strlen("@");
3407     }
3408     else
3409     {
3410         if (lpUrlComponents->lpszPassword)
3411         {
3412             INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
3413             return FALSE;
3414         }
3415     }
3416
3417     if (lpUrlComponents->lpszPassword)
3418     {
3419         *lpdwUrlLength += strlen(":");
3420         *lpdwUrlLength += URL_GET_COMP_LENGTH(lpUrlComponents, Password);
3421     }
3422
3423     if (lpUrlComponents->lpszHostName)
3424     {
3425         *lpdwUrlLength += URL_GET_COMP_LENGTH(lpUrlComponents, HostName);
3426
3427         if (!url_uses_default_port(nScheme, lpUrlComponents->nPort))
3428         {
3429             char szPort[MAX_WORD_DIGITS+1];
3430
3431             sprintf(szPort, "%d", lpUrlComponents->nPort);
3432             *lpdwUrlLength += strlen(szPort);
3433             *lpdwUrlLength += strlen(":");
3434         }
3435
3436         if (lpUrlComponents->lpszUrlPath && *lpUrlComponents->lpszUrlPath != '/')
3437             (*lpdwUrlLength)++; /* '/' */
3438     }
3439
3440     if (lpUrlComponents->lpszUrlPath)
3441         *lpdwUrlLength += URL_GET_COMP_LENGTH(lpUrlComponents, UrlPath);
3442
3443     return TRUE;
3444 }
3445
3446 static void convert_urlcomp_atow(LPURL_COMPONENTSA lpUrlComponents, LPURL_COMPONENTSW urlCompW)
3447 {
3448     INT len;
3449
3450     ZeroMemory(urlCompW, sizeof(URL_COMPONENTSW));
3451
3452     urlCompW->dwStructSize = sizeof(URL_COMPONENTSW);
3453     urlCompW->dwSchemeLength = lpUrlComponents->dwSchemeLength;
3454     urlCompW->nScheme = lpUrlComponents->nScheme;
3455     urlCompW->dwHostNameLength = lpUrlComponents->dwHostNameLength;
3456     urlCompW->nPort = lpUrlComponents->nPort;
3457     urlCompW->dwUserNameLength = lpUrlComponents->dwUserNameLength;
3458     urlCompW->dwPasswordLength = lpUrlComponents->dwPasswordLength;
3459     urlCompW->dwUrlPathLength = lpUrlComponents->dwUrlPathLength;
3460     urlCompW->dwExtraInfoLength = lpUrlComponents->dwExtraInfoLength;
3461
3462     if (lpUrlComponents->lpszScheme)
3463     {
3464         len = URL_GET_COMP_LENGTHA(lpUrlComponents, Scheme) + 1;
3465         urlCompW->lpszScheme = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
3466         MultiByteToWideChar(CP_ACP, 0, lpUrlComponents->lpszScheme,
3467                             -1, urlCompW->lpszScheme, len);
3468     }
3469
3470     if (lpUrlComponents->lpszHostName)
3471     {
3472         len = URL_GET_COMP_LENGTHA(lpUrlComponents, HostName) + 1;
3473         urlCompW->lpszHostName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
3474         MultiByteToWideChar(CP_ACP, 0, lpUrlComponents->lpszHostName,
3475                             -1, urlCompW->lpszHostName, len);
3476     }
3477
3478     if (lpUrlComponents->lpszUserName)
3479     {
3480         len = URL_GET_COMP_LENGTHA(lpUrlComponents, UserName) + 1;
3481         urlCompW->lpszUserName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
3482         MultiByteToWideChar(CP_ACP, 0, lpUrlComponents->lpszUserName,
3483                             -1, urlCompW->lpszUserName, len);
3484     }
3485
3486     if (lpUrlComponents->lpszPassword)
3487     {
3488         len = URL_GET_COMP_LENGTHA(lpUrlComponents, Password) + 1;
3489         urlCompW->lpszPassword = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
3490         MultiByteToWideChar(CP_ACP, 0, lpUrlComponents->lpszPassword,
3491                             -1, urlCompW->lpszPassword, len);
3492     }
3493
3494     if (lpUrlComponents->lpszUrlPath)
3495     {
3496         len = URL_GET_COMP_LENGTHA(lpUrlComponents, UrlPath) + 1;
3497         urlCompW->lpszUrlPath = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
3498         MultiByteToWideChar(CP_ACP, 0, lpUrlComponents->lpszUrlPath,
3499                             -1, urlCompW->lpszUrlPath, len);
3500     }
3501
3502     if (lpUrlComponents->lpszExtraInfo)
3503     {
3504         len = URL_GET_COMP_LENGTHA(lpUrlComponents, ExtraInfo) + 1;
3505         urlCompW->lpszExtraInfo = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
3506         MultiByteToWideChar(CP_ACP, 0, lpUrlComponents->lpszExtraInfo,
3507                             -1, urlCompW->lpszExtraInfo, len);
3508     }
3509 }
3510
3511 /***********************************************************************
3512  *      InternetCreateUrlA (WININET.@)
3513  *
3514  * See InternetCreateUrlW.
3515  */
3516 BOOL WINAPI InternetCreateUrlA(LPURL_COMPONENTSA lpUrlComponents, DWORD dwFlags,
3517                                LPSTR lpszUrl, LPDWORD lpdwUrlLength)
3518 {
3519     BOOL ret;
3520     LPWSTR urlW = NULL;
3521     URL_COMPONENTSW urlCompW;
3522
3523     TRACE("(%p,%d,%p,%p)\n", lpUrlComponents, dwFlags, lpszUrl, lpdwUrlLength);
3524
3525     if (!lpUrlComponents || lpUrlComponents->dwStructSize != sizeof(URL_COMPONENTSW) || !lpdwUrlLength)
3526     {
3527         INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
3528         return FALSE;
3529     }
3530
3531     convert_urlcomp_atow(lpUrlComponents, &urlCompW);
3532
3533     if (lpszUrl)
3534         urlW = HeapAlloc(GetProcessHeap(), 0, *lpdwUrlLength * sizeof(WCHAR));
3535
3536     ret = InternetCreateUrlW(&urlCompW, dwFlags, urlW, lpdwUrlLength);
3537
3538     if (!ret && (GetLastError() == ERROR_INSUFFICIENT_BUFFER))
3539         *lpdwUrlLength /= sizeof(WCHAR);
3540
3541     /* on success, lpdwUrlLength points to the size of urlW in WCHARS
3542     * minus one, so add one to leave room for NULL terminator
3543     */
3544     if (ret)
3545         WideCharToMultiByte(CP_ACP, 0, urlW, -1, lpszUrl, *lpdwUrlLength + 1, NULL, NULL);
3546
3547     HeapFree(GetProcessHeap(), 0, urlCompW.lpszScheme);
3548     HeapFree(GetProcessHeap(), 0, urlCompW.lpszHostName);
3549     HeapFree(GetProcessHeap(), 0, urlCompW.lpszUserName);
3550     HeapFree(GetProcessHeap(), 0, urlCompW.lpszPassword);
3551     HeapFree(GetProcessHeap(), 0, urlCompW.lpszUrlPath);
3552     HeapFree(GetProcessHeap(), 0, urlCompW.lpszExtraInfo);
3553     HeapFree(GetProcessHeap(), 0, urlW);
3554
3555     return ret;
3556 }
3557
3558 /***********************************************************************
3559  *      InternetCreateUrlW (WININET.@)
3560  *
3561  * Creates a URL from its component parts.
3562  *
3563  * PARAMS
3564  *  lpUrlComponents [I] URL Components.
3565  *  dwFlags         [I] Flags. See notes.
3566  *  lpszUrl         [I] Buffer in which to store the created URL.
3567  *  lpdwUrlLength   [I/O] On input, the length of the buffer pointed to by
3568  *                        lpszUrl in characters. On output, the number of bytes
3569  *                        required to store the URL including terminator.
3570  *
3571  * NOTES
3572  *
3573  * The dwFlags parameter can be zero or more of the following:
3574  *|ICU_ESCAPE - Generates escape sequences for unsafe characters in the path and extra info of the URL.
3575  *
3576  * RETURNS
3577  *   TRUE on success
3578  *   FALSE on failure
3579  *
3580  */
3581 BOOL WINAPI InternetCreateUrlW(LPURL_COMPONENTSW lpUrlComponents, DWORD dwFlags,
3582                                LPWSTR lpszUrl, LPDWORD lpdwUrlLength)
3583 {
3584     DWORD dwLen;
3585     INTERNET_SCHEME nScheme;
3586
3587     static const WCHAR slashSlashW[] = {'/','/'};
3588     static const WCHAR percentD[] = {'%','d',0};
3589
3590     TRACE("(%p,%d,%p,%p)\n", lpUrlComponents, dwFlags, lpszUrl, lpdwUrlLength);
3591
3592     if (!lpUrlComponents || lpUrlComponents->dwStructSize != sizeof(URL_COMPONENTSW) || !lpdwUrlLength)
3593     {
3594         INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
3595         return FALSE;
3596     }
3597
3598     if (!calc_url_length(lpUrlComponents, &dwLen))
3599         return FALSE;
3600
3601     if (!lpszUrl || *lpdwUrlLength < dwLen)
3602     {
3603         *lpdwUrlLength = (dwLen + 1) * sizeof(WCHAR);
3604         INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
3605         return FALSE;
3606     }
3607
3608     *lpdwUrlLength = dwLen;
3609     lpszUrl[0] = 0x00;
3610
3611     dwLen = 0;
3612
3613     if (lpUrlComponents->lpszScheme)
3614     {
3615         dwLen = URL_GET_COMP_LENGTH(lpUrlComponents, Scheme);
3616         memcpy(lpszUrl, lpUrlComponents->lpszScheme, dwLen * sizeof(WCHAR));
3617         lpszUrl += dwLen;
3618
3619         nScheme = GetInternetSchemeW(lpUrlComponents->lpszScheme, dwLen);
3620     }
3621     else
3622     {
3623         LPCWSTR scheme;
3624         nScheme = lpUrlComponents->nScheme;
3625
3626         if (nScheme == INTERNET_SCHEME_DEFAULT)
3627             nScheme = INTERNET_SCHEME_HTTP;
3628
3629         scheme = INTERNET_GetSchemeString(nScheme);
3630         dwLen = strlenW(scheme);
3631         memcpy(lpszUrl, scheme, dwLen * sizeof(WCHAR));
3632         lpszUrl += dwLen;
3633     }
3634
3635     /* all schemes are followed by at least a colon */
3636     *lpszUrl = ':';
3637     lpszUrl++;
3638
3639     if (!scheme_is_opaque(nScheme) || lpUrlComponents->lpszHostName)
3640     {
3641         memcpy(lpszUrl, slashSlashW, sizeof(slashSlashW));
3642         lpszUrl += sizeof(slashSlashW)/sizeof(slashSlashW[0]);
3643     }
3644
3645     if (lpUrlComponents->lpszUserName)
3646     {
3647         dwLen = URL_GET_COMP_LENGTH(lpUrlComponents, UserName);
3648         memcpy(lpszUrl, lpUrlComponents->lpszUserName, dwLen * sizeof(WCHAR));
3649         lpszUrl += dwLen;
3650
3651         if (lpUrlComponents->lpszPassword)
3652         {
3653             *lpszUrl = ':';
3654             lpszUrl++;
3655
3656             dwLen = URL_GET_COMP_LENGTH(lpUrlComponents, Password);
3657             memcpy(lpszUrl, lpUrlComponents->lpszPassword, dwLen * sizeof(WCHAR));
3658             lpszUrl += dwLen;
3659         }
3660
3661         *lpszUrl = '@';
3662         lpszUrl++;
3663     }
3664
3665     if (lpUrlComponents->lpszHostName)
3666     {
3667         dwLen = URL_GET_COMP_LENGTH(lpUrlComponents, HostName);
3668         memcpy(lpszUrl, lpUrlComponents->lpszHostName, dwLen * sizeof(WCHAR));
3669         lpszUrl += dwLen;
3670
3671         if (!url_uses_default_port(nScheme, lpUrlComponents->nPort))
3672         {
3673             WCHAR szPort[MAX_WORD_DIGITS+1];
3674
3675             sprintfW(szPort, percentD, lpUrlComponents->nPort);
3676             *lpszUrl = ':';
3677             lpszUrl++;
3678             dwLen = strlenW(szPort);
3679             memcpy(lpszUrl, szPort, dwLen * sizeof(WCHAR));
3680             lpszUrl += dwLen;
3681         }
3682
3683         /* add slash between hostname and path if necessary */
3684         if (lpUrlComponents->lpszUrlPath && *lpUrlComponents->lpszUrlPath != '/')
3685         {
3686             *lpszUrl = '/';
3687             lpszUrl++;
3688         }
3689     }
3690
3691
3692     if (lpUrlComponents->lpszUrlPath)
3693     {
3694         dwLen = URL_GET_COMP_LENGTH(lpUrlComponents, UrlPath);
3695         memcpy(lpszUrl, lpUrlComponents->lpszUrlPath, dwLen * sizeof(WCHAR));
3696         lpszUrl += dwLen;
3697     }
3698
3699     *lpszUrl = '\0';
3700
3701     return TRUE;
3702 }
3703
3704 /***********************************************************************
3705  *      InternetConfirmZoneCrossingA (WININET.@)
3706  *
3707  */
3708 DWORD WINAPI InternetConfirmZoneCrossingA( HWND hWnd, LPSTR szUrlPrev, LPSTR szUrlNew, BOOL bPost )
3709 {
3710     FIXME("(%p, %s, %s, %x) stub\n", hWnd, debugstr_a(szUrlPrev), debugstr_a(szUrlNew), bPost);
3711     return ERROR_SUCCESS;
3712 }
3713
3714 /***********************************************************************
3715  *      InternetConfirmZoneCrossingW (WININET.@)
3716  *
3717  */
3718 DWORD WINAPI InternetConfirmZoneCrossingW( HWND hWnd, LPWSTR szUrlPrev, LPWSTR szUrlNew, BOOL bPost )
3719 {
3720     FIXME("(%p, %s, %s, %x) stub\n", hWnd, debugstr_w(szUrlPrev), debugstr_w(szUrlNew), bPost);
3721     return ERROR_SUCCESS;
3722 }
3723
3724 DWORD WINAPI InternetDialA( HWND hwndParent, LPSTR lpszConnectoid, DWORD dwFlags,
3725                             DWORD_PTR* lpdwConnection, DWORD dwReserved )
3726 {
3727     FIXME("(%p, %p, 0x%08x, %p, 0x%08x) stub\n", hwndParent, lpszConnectoid, dwFlags,
3728           lpdwConnection, dwReserved);
3729     return ERROR_SUCCESS;
3730 }
3731
3732 DWORD WINAPI InternetDialW( HWND hwndParent, LPWSTR lpszConnectoid, DWORD dwFlags,
3733                             DWORD_PTR* lpdwConnection, DWORD dwReserved )
3734 {
3735     FIXME("(%p, %p, 0x%08x, %p, 0x%08x) stub\n", hwndParent, lpszConnectoid, dwFlags,
3736           lpdwConnection, dwReserved);
3737     return ERROR_SUCCESS;
3738 }
3739
3740 BOOL WINAPI InternetGoOnlineA( LPSTR lpszURL, HWND hwndParent, DWORD dwReserved )
3741 {
3742     FIXME("(%s, %p, 0x%08x) stub\n", debugstr_a(lpszURL), hwndParent, dwReserved);
3743     return TRUE;
3744 }
3745
3746 BOOL WINAPI InternetGoOnlineW( LPWSTR lpszURL, HWND hwndParent, DWORD dwReserved )
3747 {
3748     FIXME("(%s, %p, 0x%08x) stub\n", debugstr_w(lpszURL), hwndParent, dwReserved);
3749     return TRUE;
3750 }
3751
3752 DWORD WINAPI InternetHangUp( DWORD_PTR dwConnection, DWORD dwReserved )
3753 {
3754     FIXME("(0x%08lx, 0x%08x) stub\n", dwConnection, dwReserved);
3755     return ERROR_SUCCESS;
3756 }
3757
3758 BOOL WINAPI CreateMD5SSOHash( PWSTR pszChallengeInfo, PWSTR pwszRealm, PWSTR pwszTarget,
3759                               PBYTE pbHexHash )
3760 {
3761     FIXME("(%s, %s, %s, %p) stub\n", debugstr_w(pszChallengeInfo), debugstr_w(pwszRealm),
3762           debugstr_w(pwszTarget), pbHexHash);
3763     return FALSE;
3764 }
3765
3766 BOOL WINAPI ResumeSuspendedDownload( HINTERNET hInternet, DWORD dwError )
3767 {
3768     FIXME("(%p, 0x%08x) stub\n", hInternet, dwError);
3769     return FALSE;
3770 }
3771
3772 BOOL WINAPI InternetQueryFortezzaStatus(DWORD *a, DWORD_PTR b)
3773 {
3774     FIXME("(%p, %08lx) stub\n", a, b);
3775     return 0;
3776 }