wined3d: Remove an unneeded atifs hack.
[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 InternetCrackUrlA
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   BOOL ret = FALSE;
1095   WCHAR *lpwszUrl, *hostname = NULL, *username = NULL, *password = NULL, *path = NULL,
1096         *scheme = NULL, *extra = NULL;
1097
1098   TRACE("(%s %u %x %p)\n",
1099         lpszUrl ? debugstr_an(lpszUrl, dwUrlLength ? dwUrlLength : strlen(lpszUrl)) : "(null)",
1100         dwUrlLength, dwFlags, lpUrlComponents);
1101
1102   if (!lpszUrl || !*lpszUrl || !lpUrlComponents ||
1103           lpUrlComponents->dwStructSize != sizeof(URL_COMPONENTSA))
1104   {
1105       INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
1106       return FALSE;
1107   }
1108
1109   if(dwUrlLength<=0)
1110       dwUrlLength=-1;
1111   nLength=MultiByteToWideChar(CP_ACP,0,lpszUrl,dwUrlLength,NULL,0);
1112
1113   /* if dwUrlLength=-1 then nLength includes null but length to 
1114        InternetCrackUrlW should not include it                  */
1115   if (dwUrlLength == -1) nLength--;
1116
1117   lpwszUrl=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WCHAR)*nLength);
1118   MultiByteToWideChar(CP_ACP,0,lpszUrl,dwUrlLength,lpwszUrl,nLength);
1119
1120   memset(&UCW,0,sizeof(UCW));
1121   UCW.dwStructSize = sizeof(URL_COMPONENTSW);
1122   if (lpUrlComponents->dwHostNameLength)
1123   {
1124     UCW.dwHostNameLength = lpUrlComponents->dwHostNameLength;
1125     if (lpUrlComponents->lpszHostName)
1126     {
1127       hostname = HeapAlloc(GetProcessHeap(), 0, UCW.dwHostNameLength * sizeof(WCHAR));
1128       UCW.lpszHostName = hostname;
1129     }
1130   }
1131   if (lpUrlComponents->dwUserNameLength)
1132   {
1133     UCW.dwUserNameLength = lpUrlComponents->dwUserNameLength;
1134     if (lpUrlComponents->lpszUserName)
1135     {
1136       username = HeapAlloc(GetProcessHeap(), 0, UCW.dwUserNameLength * sizeof(WCHAR));
1137       UCW.lpszUserName = username;
1138     }
1139   }
1140   if (lpUrlComponents->dwPasswordLength)
1141   {
1142     UCW.dwPasswordLength = lpUrlComponents->dwPasswordLength;
1143     if (lpUrlComponents->lpszPassword)
1144     {
1145       password = HeapAlloc(GetProcessHeap(), 0, UCW.dwPasswordLength * sizeof(WCHAR));
1146       UCW.lpszPassword = password;
1147     }
1148   }
1149   if (lpUrlComponents->dwUrlPathLength)
1150   {
1151     UCW.dwUrlPathLength = lpUrlComponents->dwUrlPathLength;
1152     if (lpUrlComponents->lpszUrlPath)
1153     {
1154       path = HeapAlloc(GetProcessHeap(), 0, UCW.dwUrlPathLength * sizeof(WCHAR));
1155       UCW.lpszUrlPath = path;
1156     }
1157   }
1158   if (lpUrlComponents->dwSchemeLength)
1159   {
1160     UCW.dwSchemeLength = lpUrlComponents->dwSchemeLength;
1161     if (lpUrlComponents->lpszScheme)
1162     {
1163       scheme = HeapAlloc(GetProcessHeap(), 0, UCW.dwSchemeLength * sizeof(WCHAR));
1164       UCW.lpszScheme = scheme;
1165     }
1166   }
1167   if (lpUrlComponents->dwExtraInfoLength)
1168   {
1169     UCW.dwExtraInfoLength = lpUrlComponents->dwExtraInfoLength;
1170     if (lpUrlComponents->lpszExtraInfo)
1171     {
1172       extra = HeapAlloc(GetProcessHeap(), 0, UCW.dwExtraInfoLength * sizeof(WCHAR));
1173       UCW.lpszExtraInfo = extra;
1174     }
1175   }
1176   if ((ret = InternetCrackUrlW(lpwszUrl, nLength, dwFlags, &UCW)))
1177   {
1178     ConvertUrlComponentValue(&lpUrlComponents->lpszHostName, &lpUrlComponents->dwHostNameLength,
1179                              UCW.lpszHostName, UCW.dwHostNameLength, lpszUrl, lpwszUrl);
1180     ConvertUrlComponentValue(&lpUrlComponents->lpszUserName, &lpUrlComponents->dwUserNameLength,
1181                              UCW.lpszUserName, UCW.dwUserNameLength, lpszUrl, lpwszUrl);
1182     ConvertUrlComponentValue(&lpUrlComponents->lpszPassword, &lpUrlComponents->dwPasswordLength,
1183                              UCW.lpszPassword, UCW.dwPasswordLength, lpszUrl, lpwszUrl);
1184     ConvertUrlComponentValue(&lpUrlComponents->lpszUrlPath, &lpUrlComponents->dwUrlPathLength,
1185                              UCW.lpszUrlPath, UCW.dwUrlPathLength, lpszUrl, lpwszUrl);
1186     ConvertUrlComponentValue(&lpUrlComponents->lpszScheme, &lpUrlComponents->dwSchemeLength,
1187                              UCW.lpszScheme, UCW.dwSchemeLength, lpszUrl, lpwszUrl);
1188     ConvertUrlComponentValue(&lpUrlComponents->lpszExtraInfo, &lpUrlComponents->dwExtraInfoLength,
1189                              UCW.lpszExtraInfo, UCW.dwExtraInfoLength, lpszUrl, lpwszUrl);
1190
1191     lpUrlComponents->nScheme = UCW.nScheme;
1192     lpUrlComponents->nPort = UCW.nPort;
1193
1194     TRACE("%s: scheme(%s) host(%s) path(%s) extra(%s)\n", lpszUrl,
1195           debugstr_an(lpUrlComponents->lpszScheme, lpUrlComponents->dwSchemeLength),
1196           debugstr_an(lpUrlComponents->lpszHostName, lpUrlComponents->dwHostNameLength),
1197           debugstr_an(lpUrlComponents->lpszUrlPath, lpUrlComponents->dwUrlPathLength),
1198           debugstr_an(lpUrlComponents->lpszExtraInfo, lpUrlComponents->dwExtraInfoLength));
1199   }
1200   HeapFree(GetProcessHeap(), 0, lpwszUrl);
1201   HeapFree(GetProcessHeap(), 0, hostname);
1202   HeapFree(GetProcessHeap(), 0, username);
1203   HeapFree(GetProcessHeap(), 0, password);
1204   HeapFree(GetProcessHeap(), 0, path);
1205   HeapFree(GetProcessHeap(), 0, scheme);
1206   HeapFree(GetProcessHeap(), 0, extra);
1207   return ret;
1208 }
1209
1210 static const WCHAR url_schemes[][7] =
1211 {
1212     {'f','t','p',0},
1213     {'g','o','p','h','e','r',0},
1214     {'h','t','t','p',0},
1215     {'h','t','t','p','s',0},
1216     {'f','i','l','e',0},
1217     {'n','e','w','s',0},
1218     {'m','a','i','l','t','o',0},
1219     {'r','e','s',0},
1220 };
1221
1222 /***********************************************************************
1223  *           GetInternetSchemeW (internal)
1224  *
1225  * Get scheme of url
1226  *
1227  * RETURNS
1228  *    scheme on success
1229  *    INTERNET_SCHEME_UNKNOWN on failure
1230  *
1231  */
1232 static INTERNET_SCHEME GetInternetSchemeW(LPCWSTR lpszScheme, DWORD nMaxCmp)
1233 {
1234     int i;
1235
1236     TRACE("%s %d\n",debugstr_wn(lpszScheme, nMaxCmp), nMaxCmp);
1237
1238     if(lpszScheme==NULL)
1239         return INTERNET_SCHEME_UNKNOWN;
1240
1241     for (i = 0; i < sizeof(url_schemes)/sizeof(url_schemes[0]); i++)
1242         if (!strncmpW(lpszScheme, url_schemes[i], nMaxCmp))
1243             return INTERNET_SCHEME_FIRST + i;
1244
1245     return INTERNET_SCHEME_UNKNOWN;
1246 }
1247
1248 /***********************************************************************
1249  *           SetUrlComponentValueW (Internal)
1250  *
1251  * Helper function for InternetCrackUrlW
1252  *
1253  * PARAMS
1254  *     lppszComponent [O] Holds the returned string
1255  *     dwComponentLen [I] Holds the size of lppszComponent
1256  *                    [O] Holds the length of the string in lppszComponent without '\0'
1257  *     lpszStart      [I] Holds the string to copy from
1258  *     len            [I] Holds the length of lpszStart without '\0'
1259  *
1260  * RETURNS
1261  *    TRUE on success
1262  *    FALSE on failure
1263  *
1264  */
1265 static BOOL SetUrlComponentValueW(LPWSTR* lppszComponent, LPDWORD dwComponentLen, LPCWSTR lpszStart, DWORD len)
1266 {
1267     TRACE("%s (%d)\n", debugstr_wn(lpszStart,len), len);
1268
1269     if ( (*dwComponentLen == 0) && (*lppszComponent == NULL) )
1270         return FALSE;
1271
1272     if (*dwComponentLen != 0 || *lppszComponent == NULL)
1273     {
1274         if (*lppszComponent == NULL)
1275         {
1276             *lppszComponent = (LPWSTR)lpszStart;
1277             *dwComponentLen = len;
1278         }
1279         else
1280         {
1281             DWORD ncpylen = min((*dwComponentLen)-1, len);
1282             memcpy(*lppszComponent, lpszStart, ncpylen*sizeof(WCHAR));
1283             (*lppszComponent)[ncpylen] = '\0';
1284             *dwComponentLen = ncpylen;
1285         }
1286     }
1287
1288     return TRUE;
1289 }
1290
1291 /***********************************************************************
1292  *           InternetCrackUrlW   (WININET.@)
1293  *
1294  * Break up URL into its components
1295  *
1296  * RETURNS
1297  *    TRUE on success
1298  *    FALSE on failure
1299  */
1300 BOOL WINAPI InternetCrackUrlW(LPCWSTR lpszUrl_orig, DWORD dwUrlLength_orig, DWORD dwFlags,
1301                               LPURL_COMPONENTSW lpUC)
1302 {
1303   /*
1304    * RFC 1808
1305    * <protocol>:[//<net_loc>][/path][;<params>][?<query>][#<fragment>]
1306    *
1307    */
1308     LPCWSTR lpszParam    = NULL;
1309     BOOL  bIsAbsolute = FALSE;
1310     LPCWSTR lpszap, lpszUrl = lpszUrl_orig;
1311     LPCWSTR lpszcp = NULL;
1312     LPWSTR  lpszUrl_decode = NULL;
1313     DWORD dwUrlLength = dwUrlLength_orig;
1314
1315     TRACE("(%s %u %x %p)\n",
1316           lpszUrl ? debugstr_wn(lpszUrl, dwUrlLength ? dwUrlLength : strlenW(lpszUrl)) : "(null)",
1317           dwUrlLength, dwFlags, lpUC);
1318
1319     if (!lpszUrl_orig || !*lpszUrl_orig || !lpUC)
1320     {
1321         INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
1322         return FALSE;
1323     }
1324     if (!dwUrlLength) dwUrlLength = strlenW(lpszUrl);
1325
1326     if (dwFlags & ICU_DECODE)
1327     {
1328         WCHAR *url_tmp;
1329         DWORD len = dwUrlLength + 1;
1330
1331         if (!(url_tmp = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR))))
1332         {
1333             INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1334             return FALSE;
1335         }
1336         memcpy(url_tmp, lpszUrl_orig, dwUrlLength * sizeof(WCHAR));
1337         url_tmp[dwUrlLength] = 0;
1338         if (!(lpszUrl_decode = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR))))
1339         {
1340             HeapFree(GetProcessHeap(), 0, url_tmp);
1341             INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1342             return FALSE;
1343         }
1344         if (InternetCanonicalizeUrlW(url_tmp, lpszUrl_decode, &len, ICU_DECODE | ICU_NO_ENCODE))
1345         {
1346             dwUrlLength = len;
1347             lpszUrl = lpszUrl_decode;
1348         }
1349         HeapFree(GetProcessHeap(), 0, url_tmp);
1350     }
1351     lpszap = lpszUrl;
1352     
1353     /* Determine if the URI is absolute. */
1354     while (lpszap - lpszUrl < dwUrlLength)
1355     {
1356         if (isalnumW(*lpszap))
1357         {
1358             lpszap++;
1359             continue;
1360         }
1361         if ((*lpszap == ':') && (lpszap - lpszUrl >= 2))
1362         {
1363             bIsAbsolute = TRUE;
1364             lpszcp = lpszap;
1365         }
1366         else
1367         {
1368             lpszcp = lpszUrl; /* Relative url */
1369         }
1370
1371         break;
1372     }
1373
1374     lpUC->nScheme = INTERNET_SCHEME_UNKNOWN;
1375     lpUC->nPort = INTERNET_INVALID_PORT_NUMBER;
1376
1377     /* Parse <params> */
1378     if (!(lpszParam = memchrW(lpszap, ';', dwUrlLength - (lpszap - lpszUrl))))
1379         lpszParam = memchrW(lpszap, '?', dwUrlLength - (lpszap - lpszUrl));
1380
1381     SetUrlComponentValueW(&lpUC->lpszExtraInfo, &lpUC->dwExtraInfoLength,
1382                           lpszParam, lpszParam ? dwUrlLength-(lpszParam-lpszUrl) : 0);
1383
1384     if (bIsAbsolute) /* Parse <protocol>:[//<net_loc>] */
1385     {
1386         LPCWSTR lpszNetLoc;
1387
1388         /* Get scheme first. */
1389         lpUC->nScheme = GetInternetSchemeW(lpszUrl, lpszcp - lpszUrl);
1390         SetUrlComponentValueW(&lpUC->lpszScheme, &lpUC->dwSchemeLength,
1391                                    lpszUrl, lpszcp - lpszUrl);
1392
1393         /* Eat ':' in protocol. */
1394         lpszcp++;
1395
1396         /* double slash indicates the net_loc portion is present */
1397         if ((lpszcp[0] == '/') && (lpszcp[1] == '/'))
1398         {
1399             lpszcp += 2;
1400
1401             lpszNetLoc = memchrW(lpszcp, '/', dwUrlLength - (lpszcp - lpszUrl));
1402             if (lpszParam)
1403             {
1404                 if (lpszNetLoc)
1405                     lpszNetLoc = min(lpszNetLoc, lpszParam);
1406                 else
1407                     lpszNetLoc = lpszParam;
1408             }
1409             else if (!lpszNetLoc)
1410                 lpszNetLoc = lpszcp + dwUrlLength-(lpszcp-lpszUrl);
1411
1412             /* Parse net-loc */
1413             if (lpszNetLoc)
1414             {
1415                 LPCWSTR lpszHost;
1416                 LPCWSTR lpszPort;
1417
1418                 /* [<user>[<:password>]@]<host>[:<port>] */
1419                 /* First find the user and password if they exist */
1420
1421                 lpszHost = memchrW(lpszcp, '@', dwUrlLength - (lpszcp - lpszUrl));
1422                 if (lpszHost == NULL || lpszHost > lpszNetLoc)
1423                 {
1424                     /* username and password not specified. */
1425                     SetUrlComponentValueW(&lpUC->lpszUserName, &lpUC->dwUserNameLength, NULL, 0);
1426                     SetUrlComponentValueW(&lpUC->lpszPassword, &lpUC->dwPasswordLength, NULL, 0);
1427                 }
1428                 else /* Parse out username and password */
1429                 {
1430                     LPCWSTR lpszUser = lpszcp;
1431                     LPCWSTR lpszPasswd = lpszHost;
1432
1433                     while (lpszcp < lpszHost)
1434                     {
1435                         if (*lpszcp == ':')
1436                             lpszPasswd = lpszcp;
1437
1438                         lpszcp++;
1439                     }
1440
1441                     SetUrlComponentValueW(&lpUC->lpszUserName, &lpUC->dwUserNameLength,
1442                                           lpszUser, lpszPasswd - lpszUser);
1443
1444                     if (lpszPasswd != lpszHost)
1445                         lpszPasswd++;
1446                     SetUrlComponentValueW(&lpUC->lpszPassword, &lpUC->dwPasswordLength,
1447                                           lpszPasswd == lpszHost ? NULL : lpszPasswd,
1448                                           lpszHost - lpszPasswd);
1449
1450                     lpszcp++; /* Advance to beginning of host */
1451                 }
1452
1453                 /* Parse <host><:port> */
1454
1455                 lpszHost = lpszcp;
1456                 lpszPort = lpszNetLoc;
1457
1458                 /* special case for res:// URLs: there is no port here, so the host is the
1459                    entire string up to the first '/' */
1460                 if(lpUC->nScheme==INTERNET_SCHEME_RES)
1461                 {
1462                     SetUrlComponentValueW(&lpUC->lpszHostName, &lpUC->dwHostNameLength,
1463                                           lpszHost, lpszPort - lpszHost);
1464                     lpszcp=lpszNetLoc;
1465                 }
1466                 else
1467                 {
1468                     while (lpszcp < lpszNetLoc)
1469                     {
1470                         if (*lpszcp == ':')
1471                             lpszPort = lpszcp;
1472
1473                         lpszcp++;
1474                     }
1475
1476                     /* If the scheme is "file" and the host is just one letter, it's not a host */
1477                     if(lpUC->nScheme==INTERNET_SCHEME_FILE && (lpszPort-lpszHost)==1)
1478                     {
1479                         lpszcp=lpszHost;
1480                         SetUrlComponentValueW(&lpUC->lpszHostName, &lpUC->dwHostNameLength,
1481                                               NULL, 0);
1482                     }
1483                     else
1484                     {
1485                         SetUrlComponentValueW(&lpUC->lpszHostName, &lpUC->dwHostNameLength,
1486                                               lpszHost, lpszPort - lpszHost);
1487                         if (lpszPort != lpszNetLoc)
1488                             lpUC->nPort = atoiW(++lpszPort);
1489                         else switch (lpUC->nScheme)
1490                         {
1491                         case INTERNET_SCHEME_HTTP:
1492                             lpUC->nPort = INTERNET_DEFAULT_HTTP_PORT;
1493                             break;
1494                         case INTERNET_SCHEME_HTTPS:
1495                             lpUC->nPort = INTERNET_DEFAULT_HTTPS_PORT;
1496                             break;
1497                         case INTERNET_SCHEME_FTP:
1498                             lpUC->nPort = INTERNET_DEFAULT_FTP_PORT;
1499                             break;
1500                         case INTERNET_SCHEME_GOPHER:
1501                             lpUC->nPort = INTERNET_DEFAULT_GOPHER_PORT;
1502                             break;
1503                         default:
1504                             break;
1505                         }
1506                     }
1507                 }
1508             }
1509         }
1510         else
1511         {
1512             SetUrlComponentValueW(&lpUC->lpszUserName, &lpUC->dwUserNameLength, NULL, 0);
1513             SetUrlComponentValueW(&lpUC->lpszPassword, &lpUC->dwPasswordLength, NULL, 0);
1514             SetUrlComponentValueW(&lpUC->lpszHostName, &lpUC->dwHostNameLength, NULL, 0);
1515         }
1516     }
1517     else
1518     {
1519         SetUrlComponentValueW(&lpUC->lpszScheme, &lpUC->dwSchemeLength, NULL, 0);
1520         SetUrlComponentValueW(&lpUC->lpszUserName, &lpUC->dwUserNameLength, NULL, 0);
1521         SetUrlComponentValueW(&lpUC->lpszPassword, &lpUC->dwPasswordLength, NULL, 0);
1522         SetUrlComponentValueW(&lpUC->lpszHostName, &lpUC->dwHostNameLength, NULL, 0);
1523     }
1524
1525     /* Here lpszcp points to:
1526      *
1527      * <protocol>:[//<net_loc>][/path][;<params>][?<query>][#<fragment>]
1528      *                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1529      */
1530     if (lpszcp != 0 && lpszcp - lpszUrl < dwUrlLength && (!lpszParam || lpszcp < lpszParam))
1531     {
1532         INT len;
1533
1534         /* Only truncate the parameter list if it's already been saved
1535          * in lpUC->lpszExtraInfo.
1536          */
1537         if (lpszParam && lpUC->dwExtraInfoLength && lpUC->lpszExtraInfo)
1538             len = lpszParam - lpszcp;
1539         else
1540         {
1541             /* Leave the parameter list in lpszUrlPath.  Strip off any trailing
1542              * newlines if necessary.
1543              */
1544             LPWSTR lpsznewline = memchrW(lpszcp, '\n', dwUrlLength - (lpszcp - lpszUrl));
1545             if (lpsznewline != NULL)
1546                 len = lpsznewline - lpszcp;
1547             else
1548                 len = dwUrlLength-(lpszcp-lpszUrl);
1549         }
1550         SetUrlComponentValueW(&lpUC->lpszUrlPath, &lpUC->dwUrlPathLength,
1551                                    lpszcp, len);
1552     }
1553     else
1554     {
1555         if (lpUC->lpszUrlPath && (lpUC->dwUrlPathLength > 0))
1556             lpUC->lpszUrlPath[0] = 0;
1557         lpUC->dwUrlPathLength = 0;
1558     }
1559
1560     TRACE("%s: scheme(%s) host(%s) path(%s) extra(%s)\n", debugstr_wn(lpszUrl,dwUrlLength),
1561              debugstr_wn(lpUC->lpszScheme,lpUC->dwSchemeLength),
1562              debugstr_wn(lpUC->lpszHostName,lpUC->dwHostNameLength),
1563              debugstr_wn(lpUC->lpszUrlPath,lpUC->dwUrlPathLength),
1564              debugstr_wn(lpUC->lpszExtraInfo,lpUC->dwExtraInfoLength));
1565
1566     HeapFree(GetProcessHeap(), 0, lpszUrl_decode );
1567     return TRUE;
1568 }
1569
1570 /***********************************************************************
1571  *           InternetAttemptConnect (WININET.@)
1572  *
1573  * Attempt to make a connection to the internet
1574  *
1575  * RETURNS
1576  *    ERROR_SUCCESS on success
1577  *    Error value   on failure
1578  *
1579  */
1580 DWORD WINAPI InternetAttemptConnect(DWORD dwReserved)
1581 {
1582     FIXME("Stub\n");
1583     return ERROR_SUCCESS;
1584 }
1585
1586
1587 /***********************************************************************
1588  *           InternetCanonicalizeUrlA (WININET.@)
1589  *
1590  * Escape unsafe characters and spaces
1591  *
1592  * RETURNS
1593  *    TRUE on success
1594  *    FALSE on failure
1595  *
1596  */
1597 BOOL WINAPI InternetCanonicalizeUrlA(LPCSTR lpszUrl, LPSTR lpszBuffer,
1598         LPDWORD lpdwBufferLength, DWORD dwFlags)
1599 {
1600     HRESULT hr;
1601     DWORD dwURLFlags = URL_WININET_COMPATIBILITY | URL_ESCAPE_UNSAFE;
1602
1603     TRACE("(%s, %p, %p, 0x%08x) bufferlength: %d\n", debugstr_a(lpszUrl), lpszBuffer,
1604         lpdwBufferLength, lpdwBufferLength ? *lpdwBufferLength : -1, dwFlags);
1605
1606     if(dwFlags & ICU_DECODE)
1607     {
1608         dwURLFlags |= URL_UNESCAPE;
1609         dwFlags &= ~ICU_DECODE;
1610     }
1611
1612     if(dwFlags & ICU_ESCAPE)
1613     {
1614         dwURLFlags |= URL_UNESCAPE;
1615         dwFlags &= ~ICU_ESCAPE;
1616     }
1617
1618     if(dwFlags & ICU_BROWSER_MODE)
1619     {
1620         dwURLFlags |= URL_BROWSER_MODE;
1621         dwFlags &= ~ICU_BROWSER_MODE;
1622     }
1623
1624     if(dwFlags & ICU_NO_ENCODE)
1625     {
1626         /* Flip this bit to correspond to URL_ESCAPE_UNSAFE */
1627         dwURLFlags ^= URL_ESCAPE_UNSAFE;
1628         dwFlags &= ~ICU_NO_ENCODE;
1629     }
1630
1631     if (dwFlags) FIXME("Unhandled flags 0x%08x\n", dwFlags);
1632
1633     hr = UrlCanonicalizeA(lpszUrl, lpszBuffer, lpdwBufferLength, dwURLFlags);
1634     if (hr == E_POINTER) SetLastError(ERROR_INSUFFICIENT_BUFFER);
1635     if (hr == E_INVALIDARG) SetLastError(ERROR_INVALID_PARAMETER);
1636
1637     return (hr == S_OK) ? TRUE : FALSE;
1638 }
1639
1640 /***********************************************************************
1641  *           InternetCanonicalizeUrlW (WININET.@)
1642  *
1643  * Escape unsafe characters and spaces
1644  *
1645  * RETURNS
1646  *    TRUE on success
1647  *    FALSE on failure
1648  *
1649  */
1650 BOOL WINAPI InternetCanonicalizeUrlW(LPCWSTR lpszUrl, LPWSTR lpszBuffer,
1651     LPDWORD lpdwBufferLength, DWORD dwFlags)
1652 {
1653     HRESULT hr;
1654     DWORD dwURLFlags = URL_WININET_COMPATIBILITY | URL_ESCAPE_UNSAFE;
1655
1656     TRACE("(%s, %p, %p, 0x%08x) bufferlength: %d\n", debugstr_w(lpszUrl), lpszBuffer,
1657           lpdwBufferLength, dwFlags, lpdwBufferLength ? *lpdwBufferLength : -1);
1658
1659     if(dwFlags & ICU_DECODE)
1660     {
1661         dwURLFlags |= URL_UNESCAPE;
1662         dwFlags &= ~ICU_DECODE;
1663     }
1664
1665     if(dwFlags & ICU_ESCAPE)
1666     {
1667         dwURLFlags |= URL_UNESCAPE;
1668         dwFlags &= ~ICU_ESCAPE;
1669     }
1670
1671     if(dwFlags & ICU_BROWSER_MODE)
1672     {
1673         dwURLFlags |= URL_BROWSER_MODE;
1674         dwFlags &= ~ICU_BROWSER_MODE;
1675     }
1676
1677     if(dwFlags & ICU_NO_ENCODE)
1678     {
1679         /* Flip this bit to correspond to URL_ESCAPE_UNSAFE */
1680         dwURLFlags ^= URL_ESCAPE_UNSAFE;
1681         dwFlags &= ~ICU_NO_ENCODE;
1682     }
1683
1684     if (dwFlags) FIXME("Unhandled flags 0x%08x\n", dwFlags);
1685
1686     hr = UrlCanonicalizeW(lpszUrl, lpszBuffer, lpdwBufferLength, dwURLFlags);
1687     if (hr == E_POINTER) SetLastError(ERROR_INSUFFICIENT_BUFFER);
1688     if (hr == E_INVALIDARG) SetLastError(ERROR_INVALID_PARAMETER);
1689
1690     return (hr == S_OK) ? TRUE : FALSE;
1691 }
1692
1693 /* #################################################### */
1694
1695 static INTERNET_STATUS_CALLBACK set_status_callback(
1696     LPWININETHANDLEHEADER lpwh, INTERNET_STATUS_CALLBACK callback, BOOL unicode)
1697 {
1698     INTERNET_STATUS_CALLBACK ret;
1699
1700     if (unicode) lpwh->dwInternalFlags |= INET_CALLBACKW;
1701     else lpwh->dwInternalFlags &= ~INET_CALLBACKW;
1702
1703     ret = lpwh->lpfnStatusCB;
1704     lpwh->lpfnStatusCB = callback;
1705
1706     return ret;
1707 }
1708
1709 /***********************************************************************
1710  *           InternetSetStatusCallbackA (WININET.@)
1711  *
1712  * Sets up a callback function which is called as progress is made
1713  * during an operation.
1714  *
1715  * RETURNS
1716  *    Previous callback or NULL         on success
1717  *    INTERNET_INVALID_STATUS_CALLBACK  on failure
1718  *
1719  */
1720 INTERNET_STATUS_CALLBACK WINAPI InternetSetStatusCallbackA(
1721         HINTERNET hInternet ,INTERNET_STATUS_CALLBACK lpfnIntCB)
1722 {
1723     INTERNET_STATUS_CALLBACK retVal;
1724     LPWININETHANDLEHEADER lpwh;
1725
1726     TRACE("0x%08x\n", (ULONG)hInternet);
1727     
1728     if (!(lpwh = WININET_GetObject(hInternet)))
1729         return INTERNET_INVALID_STATUS_CALLBACK;
1730
1731     retVal = set_status_callback(lpwh, lpfnIntCB, FALSE);
1732
1733     WININET_Release( lpwh );
1734     return retVal;
1735 }
1736
1737 /***********************************************************************
1738  *           InternetSetStatusCallbackW (WININET.@)
1739  *
1740  * Sets up a callback function which is called as progress is made
1741  * during an operation.
1742  *
1743  * RETURNS
1744  *    Previous callback or NULL         on success
1745  *    INTERNET_INVALID_STATUS_CALLBACK  on failure
1746  *
1747  */
1748 INTERNET_STATUS_CALLBACK WINAPI InternetSetStatusCallbackW(
1749         HINTERNET hInternet ,INTERNET_STATUS_CALLBACK lpfnIntCB)
1750 {
1751     INTERNET_STATUS_CALLBACK retVal;
1752     LPWININETHANDLEHEADER lpwh;
1753
1754     TRACE("0x%08x\n", (ULONG)hInternet);
1755
1756     if (!(lpwh = WININET_GetObject(hInternet)))
1757         return INTERNET_INVALID_STATUS_CALLBACK;
1758
1759     retVal = set_status_callback(lpwh, lpfnIntCB, TRUE);
1760
1761     WININET_Release( lpwh );
1762     return retVal;
1763 }
1764
1765 /***********************************************************************
1766  *           InternetSetFilePointer (WININET.@)
1767  */
1768 DWORD WINAPI InternetSetFilePointer(HINTERNET hFile, LONG lDistanceToMove,
1769     PVOID pReserved, DWORD dwMoveContext, DWORD_PTR dwContext)
1770 {
1771     FIXME("stub\n");
1772     return FALSE;
1773 }
1774
1775 /***********************************************************************
1776  *           InternetWriteFile (WININET.@)
1777  *
1778  * Write data to an open internet file
1779  *
1780  * RETURNS
1781  *    TRUE  on success
1782  *    FALSE on failure
1783  *
1784  */
1785 BOOL WINAPI InternetWriteFile(HINTERNET hFile, LPCVOID lpBuffer,
1786         DWORD dwNumOfBytesToWrite, LPDWORD lpdwNumOfBytesWritten)
1787 {
1788     LPWININETHANDLEHEADER lpwh;
1789     BOOL retval = FALSE;
1790
1791     TRACE("(%p %p %d %p)\n", hFile, lpBuffer, dwNumOfBytesToWrite, lpdwNumOfBytesWritten);
1792
1793     lpwh = WININET_GetObject( hFile );
1794     if (!lpwh) {
1795         WARN("Invalid handle\n");
1796         SetLastError(ERROR_INVALID_HANDLE);
1797         return FALSE;
1798     }
1799
1800     if(lpwh->vtbl->WriteFile) {
1801         retval = lpwh->vtbl->WriteFile(lpwh, lpBuffer, dwNumOfBytesToWrite, lpdwNumOfBytesWritten);
1802     }else {
1803         WARN("No Writefile method.\n");
1804         SetLastError(ERROR_INVALID_HANDLE);
1805         retval = FALSE;
1806     }
1807
1808     WININET_Release( lpwh );
1809
1810     return retval;
1811 }
1812
1813
1814 /***********************************************************************
1815  *           InternetReadFile (WININET.@)
1816  *
1817  * Read data from an open internet file
1818  *
1819  * RETURNS
1820  *    TRUE  on success
1821  *    FALSE on failure
1822  *
1823  */
1824 BOOL WINAPI InternetReadFile(HINTERNET hFile, LPVOID lpBuffer,
1825         DWORD dwNumOfBytesToRead, LPDWORD pdwNumOfBytesRead)
1826 {
1827     LPWININETHANDLEHEADER hdr;
1828     DWORD res = ERROR_INTERNET_INCORRECT_HANDLE_TYPE;
1829
1830     TRACE("%p %p %d %p\n", hFile, lpBuffer, dwNumOfBytesToRead, pdwNumOfBytesRead);
1831
1832     hdr = WININET_GetObject(hFile);
1833     if (!hdr) {
1834         INTERNET_SetLastError(ERROR_INVALID_HANDLE);
1835         return FALSE;
1836     }
1837
1838     if(hdr->vtbl->ReadFile)
1839         res = hdr->vtbl->ReadFile(hdr, lpBuffer, dwNumOfBytesToRead, pdwNumOfBytesRead);
1840
1841     WININET_Release(hdr);
1842
1843     TRACE("-- %s (%u) (bytes read: %d)\n", res == ERROR_SUCCESS ? "TRUE": "FALSE", res,
1844           pdwNumOfBytesRead ? *pdwNumOfBytesRead : -1);
1845
1846     if(res != ERROR_SUCCESS)
1847         SetLastError(res);
1848     return res == ERROR_SUCCESS;
1849 }
1850
1851 /***********************************************************************
1852  *           InternetReadFileExA (WININET.@)
1853  *
1854  * Read data from an open internet file
1855  *
1856  * PARAMS
1857  *  hFile         [I] Handle returned by InternetOpenUrl or HttpOpenRequest.
1858  *  lpBuffersOut  [I/O] Buffer.
1859  *  dwFlags       [I] Flags. See notes.
1860  *  dwContext     [I] Context for callbacks.
1861  *
1862  * RETURNS
1863  *    TRUE  on success
1864  *    FALSE on failure
1865  *
1866  * NOTES
1867  *  The parameter dwFlags include zero or more of the following flags:
1868  *|IRF_ASYNC - Makes the call asynchronous.
1869  *|IRF_SYNC - Makes the call synchronous.
1870  *|IRF_USE_CONTEXT - Forces dwContext to be used.
1871  *|IRF_NO_WAIT - Don't block if the data is not available, just return what is available.
1872  *
1873  * However, in testing IRF_USE_CONTEXT seems to have no effect - dwContext isn't used.
1874  *
1875  * SEE
1876  *  InternetOpenUrlA(), HttpOpenRequestA()
1877  */
1878 BOOL WINAPI InternetReadFileExA(HINTERNET hFile, LPINTERNET_BUFFERSA lpBuffersOut,
1879         DWORD dwFlags, DWORD_PTR dwContext)
1880 {
1881     LPWININETHANDLEHEADER hdr;
1882     DWORD res = ERROR_INTERNET_INCORRECT_HANDLE_TYPE;
1883
1884     TRACE("(%p %p 0x%x 0x%lx)\n", hFile, lpBuffersOut, dwFlags, dwContext);
1885
1886     hdr = WININET_GetObject(hFile);
1887     if (!hdr) {
1888         INTERNET_SetLastError(ERROR_INVALID_HANDLE);
1889         return FALSE;
1890     }
1891
1892     if(hdr->vtbl->ReadFileExA)
1893         res = hdr->vtbl->ReadFileExA(hdr, lpBuffersOut, dwFlags, dwContext);
1894
1895     WININET_Release(hdr);
1896
1897     TRACE("-- %s (%u, bytes read: %d)\n", res == ERROR_SUCCESS ? "TRUE": "FALSE",
1898           res, lpBuffersOut->dwBufferLength);
1899
1900     if(res != ERROR_SUCCESS)
1901         SetLastError(res);
1902     return res == ERROR_SUCCESS;
1903 }
1904
1905 /***********************************************************************
1906  *           InternetReadFileExW (WININET.@)
1907  *
1908  * Read data from an open internet file.
1909  *
1910  * PARAMS
1911  *  hFile         [I] Handle returned by InternetOpenUrl() or HttpOpenRequest().
1912  *  lpBuffersOut  [I/O] Buffer.
1913  *  dwFlags       [I] Flags.
1914  *  dwContext     [I] Context for callbacks.
1915  *
1916  * RETURNS
1917  *    FALSE, last error is set to ERROR_CALL_NOT_IMPLEMENTED
1918  *
1919  * NOTES
1920  *  Not implemented in Wine or native either (as of IE6 SP2).
1921  *
1922  */
1923 BOOL WINAPI InternetReadFileExW(HINTERNET hFile, LPINTERNET_BUFFERSW lpBuffer,
1924         DWORD dwFlags, DWORD_PTR dwContext)
1925 {
1926   ERR("(%p, %p, 0x%x, 0x%lx): not implemented in native\n", hFile, lpBuffer, dwFlags, dwContext);
1927
1928   INTERNET_SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1929   return FALSE;
1930 }
1931
1932 /***********************************************************************
1933  *           INET_QueryOptionHelper (internal)
1934  */
1935 static BOOL INET_QueryOptionHelper(BOOL bIsUnicode, HINTERNET hInternet, DWORD dwOption,
1936                                    LPVOID lpBuffer, LPDWORD lpdwBufferLength)
1937 {
1938     LPWININETHANDLEHEADER lpwhh;
1939     BOOL bSuccess = FALSE;
1940
1941     TRACE("(%p, 0x%08x, %p, %p)\n", hInternet, dwOption, lpBuffer, lpdwBufferLength);
1942
1943     lpwhh = WININET_GetObject( hInternet );
1944
1945     switch (dwOption)
1946     {
1947         case INTERNET_OPTION_REQUEST_FLAGS:
1948         {
1949             ULONG flags = 4;
1950             TRACE("INTERNET_OPTION_REQUEST_FLAGS: %d\n", flags);
1951             if (*lpdwBufferLength < sizeof(ULONG))
1952                 INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
1953             else
1954             {
1955                 memcpy(lpBuffer, &flags, sizeof(ULONG));
1956                 bSuccess = TRUE;
1957             }
1958             *lpdwBufferLength = sizeof(ULONG);
1959             break;
1960         }
1961
1962         case INTERNET_OPTION_USER_AGENT:
1963         {
1964             DWORD required;
1965             LPWININETAPPINFOW ai = (LPWININETAPPINFOW)lpwhh;
1966
1967             TRACE("INTERNET_OPTION_USER_AGENT\n");
1968
1969             if (!lpwhh || lpwhh->htype != INTERNET_HANDLE_TYPE_INTERNET)
1970             {
1971                 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1972                 return FALSE;
1973             }
1974             if (bIsUnicode)
1975             {
1976                 required = (strlenW(ai->lpszAgent) + 1) * sizeof(WCHAR);
1977                 if (*lpdwBufferLength < required)
1978                     INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
1979                 else if (lpBuffer)
1980                 {
1981                     strcpyW(lpBuffer, ai->lpszAgent);
1982                     bSuccess = TRUE;
1983                 }
1984             }
1985             else
1986             {
1987                 required = WideCharToMultiByte(CP_ACP, 0, ai->lpszAgent, -1, NULL, 0, NULL, NULL);
1988                 if (*lpdwBufferLength < required)
1989                     INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
1990                 else if (lpBuffer)
1991                 {
1992                     WideCharToMultiByte(CP_ACP, 0, ai->lpszAgent, -1, lpBuffer, required, NULL, NULL);
1993                     bSuccess = TRUE;
1994                 }
1995             }
1996             *lpdwBufferLength = required;
1997             break;
1998         }
1999         case INTERNET_OPTION_HTTP_VERSION:
2000         {
2001             if (*lpdwBufferLength < sizeof(HTTP_VERSION_INFO))
2002                 INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
2003             else
2004             {
2005                 /*
2006                  * Presently hardcoded to 1.1
2007                  */
2008                 ((HTTP_VERSION_INFO*)lpBuffer)->dwMajorVersion = 1;
2009                 ((HTTP_VERSION_INFO*)lpBuffer)->dwMinorVersion = 1;
2010                 bSuccess = TRUE;
2011             }
2012             *lpdwBufferLength = sizeof(HTTP_VERSION_INFO);
2013             break;
2014         }
2015        case INTERNET_OPTION_CONNECTED_STATE:
2016        {
2017             DWORD *pdwConnectedState = (DWORD *)lpBuffer;
2018             FIXME("INTERNET_OPTION_CONNECTED_STATE: semi-stub\n");
2019
2020             if (*lpdwBufferLength < sizeof(*pdwConnectedState))
2021                  INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
2022             else
2023             {
2024                 *pdwConnectedState = INTERNET_STATE_CONNECTED;
2025                 bSuccess = TRUE;
2026             }
2027             *lpdwBufferLength = sizeof(*pdwConnectedState);
2028             break;
2029         }
2030         case INTERNET_OPTION_PROXY:
2031         {
2032             LPWININETAPPINFOW lpwai = (LPWININETAPPINFOW)lpwhh;
2033             WININETAPPINFOW wai;
2034
2035             if (lpwai == NULL)
2036             {
2037                 TRACE("Getting global proxy info\n");
2038                 memset(&wai, 0, sizeof(WININETAPPINFOW));
2039                 INTERNET_ConfigureProxy( &wai );
2040                 lpwai = &wai;
2041             }
2042
2043             if (bIsUnicode)
2044             {
2045                 INTERNET_PROXY_INFOW *pPI = (INTERNET_PROXY_INFOW *)lpBuffer;
2046                 DWORD proxyBytesRequired = 0, proxyBypassBytesRequired = 0;
2047
2048                 if (lpwai->lpszProxy)
2049                     proxyBytesRequired = (lstrlenW(lpwai->lpszProxy) + 1) *
2050                      sizeof(WCHAR);
2051                 if (lpwai->lpszProxyBypass)
2052                     proxyBypassBytesRequired =
2053                      (lstrlenW(lpwai->lpszProxyBypass) + 1) * sizeof(WCHAR);
2054                 if (*lpdwBufferLength < sizeof(INTERNET_PROXY_INFOW) +
2055                  proxyBytesRequired + proxyBypassBytesRequired)
2056                     INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
2057                 else
2058                 {
2059                     LPWSTR proxy = (LPWSTR)((LPBYTE)lpBuffer +
2060                                             sizeof(INTERNET_PROXY_INFOW));
2061                     LPWSTR proxy_bypass = (LPWSTR)((LPBYTE)lpBuffer +
2062                                                    sizeof(INTERNET_PROXY_INFOW) +
2063                                                    proxyBytesRequired);
2064
2065                     pPI->dwAccessType = lpwai->dwAccessType;
2066                     pPI->lpszProxy = NULL;
2067                     pPI->lpszProxyBypass = NULL;
2068                     if (lpwai->lpszProxy)
2069                     {
2070                         lstrcpyW(proxy, lpwai->lpszProxy);
2071                         pPI->lpszProxy = proxy;
2072                     }
2073
2074                     if (lpwai->lpszProxyBypass)
2075                     {
2076                         lstrcpyW(proxy_bypass, lpwai->lpszProxyBypass);
2077                         pPI->lpszProxyBypass = proxy_bypass;
2078                     }
2079                     bSuccess = TRUE;
2080                 }
2081                 *lpdwBufferLength = sizeof(INTERNET_PROXY_INFOW) +
2082                  proxyBytesRequired + proxyBypassBytesRequired;
2083             }
2084             else
2085             {
2086                 INTERNET_PROXY_INFOA *pPI = (INTERNET_PROXY_INFOA *)lpBuffer;
2087                 DWORD proxyBytesRequired = 0, proxyBypassBytesRequired = 0;
2088
2089                 if (lpwai->lpszProxy)
2090                     proxyBytesRequired = WideCharToMultiByte(CP_ACP, 0,
2091                      lpwai->lpszProxy, -1, NULL, 0, NULL, NULL);
2092                 if (lpwai->lpszProxyBypass)
2093                     proxyBypassBytesRequired = WideCharToMultiByte(CP_ACP, 0,
2094                      lpwai->lpszProxyBypass, -1, NULL, 0, NULL, NULL);
2095                 if (*lpdwBufferLength < sizeof(INTERNET_PROXY_INFOA) +
2096                  proxyBytesRequired + proxyBypassBytesRequired)
2097                     INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
2098                 else
2099                 {
2100                     LPSTR proxy = (LPSTR)((LPBYTE)lpBuffer +
2101                                           sizeof(INTERNET_PROXY_INFOA));
2102                     LPSTR proxy_bypass = (LPSTR)((LPBYTE)lpBuffer +
2103                                                  sizeof(INTERNET_PROXY_INFOA) +
2104                                                  proxyBytesRequired);
2105
2106                     pPI->dwAccessType = lpwai->dwAccessType;
2107                     pPI->lpszProxy = NULL;
2108                     pPI->lpszProxyBypass = NULL;
2109                     if (lpwai->lpszProxy)
2110                     {
2111                         WideCharToMultiByte(CP_ACP, 0, lpwai->lpszProxy, -1,
2112                                             proxy, proxyBytesRequired, NULL, NULL);
2113                         pPI->lpszProxy = proxy;
2114                     }
2115
2116                     if (lpwai->lpszProxyBypass)
2117                     {
2118                         WideCharToMultiByte(CP_ACP, 0, lpwai->lpszProxyBypass,
2119                                             -1, proxy_bypass, proxyBypassBytesRequired,
2120                                             NULL, NULL);
2121                         pPI->lpszProxyBypass = proxy_bypass;
2122                     }
2123                     bSuccess = TRUE;
2124                 }
2125                 *lpdwBufferLength = sizeof(INTERNET_PROXY_INFOA) +
2126                  proxyBytesRequired + proxyBypassBytesRequired;
2127             }
2128             break;
2129         }
2130         case INTERNET_OPTION_MAX_CONNS_PER_SERVER:
2131         {
2132             ULONG conn = 2;
2133             TRACE("INTERNET_OPTION_MAX_CONNS_PER_SERVER: %d\n", conn);
2134             if (*lpdwBufferLength < sizeof(ULONG))
2135                 INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
2136             else
2137             {
2138                 memcpy(lpBuffer, &conn, sizeof(ULONG));
2139                 bSuccess = TRUE;
2140             }
2141             *lpdwBufferLength = sizeof(ULONG);
2142             break;
2143         }
2144         case INTERNET_OPTION_MAX_CONNS_PER_1_0_SERVER:
2145         {
2146             ULONG conn = 4;
2147             TRACE("INTERNET_OPTION_MAX_CONNS_1_0_SERVER: %d\n", conn);
2148             if (*lpdwBufferLength < sizeof(ULONG))
2149                 INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
2150             else
2151             {
2152                 memcpy(lpBuffer, &conn, sizeof(ULONG));
2153                 bSuccess = TRUE;
2154             }
2155             *lpdwBufferLength = sizeof(ULONG);
2156             break;
2157         }
2158         case INTERNET_OPTION_SECURITY_FLAGS:
2159             FIXME("INTERNET_OPTION_SECURITY_FLAGS: Stub\n");
2160             bSuccess = TRUE;
2161             break;
2162
2163         case INTERNET_OPTION_VERSION:
2164         {
2165             TRACE("INTERNET_OPTION_VERSION\n");
2166             if (*lpdwBufferLength < sizeof(INTERNET_VERSION_INFO))
2167                 INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
2168             else
2169             {
2170                 static const INTERNET_VERSION_INFO info = { 1, 2 };
2171                 memcpy(lpBuffer, &info, sizeof(info));
2172                 *lpdwBufferLength = sizeof(info);
2173                 bSuccess = TRUE;
2174             }
2175             break;
2176         }
2177         case INTERNET_OPTION_PER_CONNECTION_OPTION:
2178             FIXME("INTERNET_OPTION_PER_CONNECTION_OPTION stub\n");
2179             if (*lpdwBufferLength < sizeof(INTERNET_PER_CONN_OPTION_LISTW))
2180                 INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
2181             else
2182             {
2183                 INTERNET_PER_CONN_OPTION_LISTW *con = lpBuffer;
2184                 int x;
2185                 bSuccess = TRUE;
2186                 for (x = 0; x < con->dwOptionCount; ++x)
2187                 {
2188                     INTERNET_PER_CONN_OPTIONW *option = con->pOptions + x;
2189                     switch (option->dwOption)
2190                     {
2191                     case INTERNET_PER_CONN_FLAGS:
2192                         option->Value.dwValue = PROXY_TYPE_DIRECT;
2193                         break;
2194
2195                     case INTERNET_PER_CONN_PROXY_SERVER:
2196                     case INTERNET_PER_CONN_PROXY_BYPASS:
2197                     case INTERNET_PER_CONN_AUTOCONFIG_URL:
2198                     case INTERNET_PER_CONN_AUTODISCOVERY_FLAGS:
2199                     case INTERNET_PER_CONN_AUTOCONFIG_SECONDARY_URL:
2200                     case INTERNET_PER_CONN_AUTOCONFIG_RELOAD_DELAY_MINS:
2201                     case INTERNET_PER_CONN_AUTOCONFIG_LAST_DETECT_TIME:
2202                     case INTERNET_PER_CONN_AUTOCONFIG_LAST_DETECT_URL:
2203                         FIXME("Unhandled dwOption %d\n", option->dwOption);
2204                         option->Value.dwValue = 0;
2205                         bSuccess = FALSE;
2206                         break;
2207
2208                     default:
2209                         FIXME("Unknown dwOption %d\n", option->dwOption);
2210                         bSuccess = FALSE;
2211                         break;
2212                     }
2213                 }
2214                 if (!bSuccess)
2215                     INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
2216             }
2217             break;
2218     case 66:
2219         FIXME("66\n");
2220         bSuccess = TRUE;
2221         break;
2222         default: {
2223             if(lpwhh) {
2224                 DWORD res;
2225
2226                 res = lpwhh->vtbl->QueryOption(lpwhh, dwOption, lpBuffer, lpdwBufferLength, bIsUnicode);
2227                 if(res == ERROR_SUCCESS)
2228                     bSuccess = TRUE;
2229                 else
2230                     SetLastError(res);
2231             }else {
2232                 FIXME("Stub! %d\n", dwOption);
2233                 break;
2234             }
2235         }
2236     }
2237     if (lpwhh)
2238         WININET_Release( lpwhh );
2239
2240     return bSuccess;
2241 }
2242
2243 /***********************************************************************
2244  *           InternetQueryOptionW (WININET.@)
2245  *
2246  * Queries an options on the specified handle
2247  *
2248  * RETURNS
2249  *    TRUE  on success
2250  *    FALSE on failure
2251  *
2252  */
2253 BOOL WINAPI InternetQueryOptionW(HINTERNET hInternet, DWORD dwOption,
2254                                  LPVOID lpBuffer, LPDWORD lpdwBufferLength)
2255 {
2256     return INET_QueryOptionHelper(TRUE, hInternet, dwOption, lpBuffer, lpdwBufferLength);
2257 }
2258
2259 /***********************************************************************
2260  *           InternetQueryOptionA (WININET.@)
2261  *
2262  * Queries an options on the specified handle
2263  *
2264  * RETURNS
2265  *    TRUE  on success
2266  *    FALSE on failure
2267  *
2268  */
2269 BOOL WINAPI InternetQueryOptionA(HINTERNET hInternet, DWORD dwOption,
2270                                  LPVOID lpBuffer, LPDWORD lpdwBufferLength)
2271 {
2272     return INET_QueryOptionHelper(FALSE, hInternet, dwOption, lpBuffer, lpdwBufferLength);
2273 }
2274
2275
2276 /***********************************************************************
2277  *           InternetSetOptionW (WININET.@)
2278  *
2279  * Sets an options on the specified handle
2280  *
2281  * RETURNS
2282  *    TRUE  on success
2283  *    FALSE on failure
2284  *
2285  */
2286 BOOL WINAPI InternetSetOptionW(HINTERNET hInternet, DWORD dwOption,
2287                            LPVOID lpBuffer, DWORD dwBufferLength)
2288 {
2289     LPWININETHANDLEHEADER lpwhh;
2290     BOOL ret = TRUE;
2291
2292     TRACE("(%p %d %p %d)\n", hInternet, dwOption, lpBuffer, dwBufferLength);
2293
2294     lpwhh = (LPWININETHANDLEHEADER) WININET_GetObject( hInternet );
2295     if(lpwhh && lpwhh->vtbl->SetOption) {
2296         DWORD res;
2297
2298         res = lpwhh->vtbl->SetOption(lpwhh, dwOption, lpBuffer, dwBufferLength);
2299         if(res != ERROR_INTERNET_INVALID_OPTION) {
2300             WININET_Release( lpwhh );
2301
2302             if(res != ERROR_SUCCESS)
2303                 SetLastError(res);
2304
2305             return res == ERROR_SUCCESS;
2306         }
2307     }
2308
2309     switch (dwOption)
2310     {
2311     case INTERNET_OPTION_CALLBACK:
2312       {
2313         INTERNET_STATUS_CALLBACK callback = *(INTERNET_STATUS_CALLBACK *)lpBuffer;
2314         ret = (set_status_callback(lpwhh, callback, TRUE) != INTERNET_INVALID_STATUS_CALLBACK);
2315         break;
2316       }
2317     case INTERNET_OPTION_HTTP_VERSION:
2318       {
2319         HTTP_VERSION_INFO* pVersion=(HTTP_VERSION_INFO*)lpBuffer;
2320         FIXME("Option INTERNET_OPTION_HTTP_VERSION(%d,%d): STUB\n",pVersion->dwMajorVersion,pVersion->dwMinorVersion);
2321       }
2322       break;
2323     case INTERNET_OPTION_ERROR_MASK:
2324       {
2325         ULONG flags = *(ULONG *)lpBuffer;
2326         FIXME("Option INTERNET_OPTION_ERROR_MASK(%d): STUB\n", flags);
2327       }
2328       break;
2329     case INTERNET_OPTION_CODEPAGE:
2330       {
2331         ULONG codepage = *(ULONG *)lpBuffer;
2332         FIXME("Option INTERNET_OPTION_CODEPAGE (%d): STUB\n", codepage);
2333       }
2334       break;
2335     case INTERNET_OPTION_REQUEST_PRIORITY:
2336       {
2337         ULONG priority = *(ULONG *)lpBuffer;
2338         FIXME("Option INTERNET_OPTION_REQUEST_PRIORITY (%d): STUB\n", priority);
2339       }
2340       break;
2341     case INTERNET_OPTION_CONNECT_TIMEOUT:
2342       {
2343         ULONG connecttimeout = *(ULONG *)lpBuffer;
2344         FIXME("Option INTERNET_OPTION_CONNECT_TIMEOUT (%d): STUB\n", connecttimeout);
2345       }
2346       break;
2347     case INTERNET_OPTION_DATA_RECEIVE_TIMEOUT:
2348       {
2349         ULONG receivetimeout = *(ULONG *)lpBuffer;
2350         FIXME("Option INTERNET_OPTION_DATA_RECEIVE_TIMEOUT (%d): STUB\n", receivetimeout);
2351       }
2352       break;
2353     case INTERNET_OPTION_MAX_CONNS_PER_SERVER:
2354       {
2355         ULONG conns = *(ULONG *)lpBuffer;
2356         FIXME("Option INTERNET_OPTION_MAX_CONNS_PER_SERVER (%d): STUB\n", conns);
2357       }
2358       break;
2359     case INTERNET_OPTION_MAX_CONNS_PER_1_0_SERVER:
2360       {
2361         ULONG conns = *(ULONG *)lpBuffer;
2362         FIXME("Option INTERNET_OPTION_MAX_CONNS_PER_1_0_SERVER (%d): STUB\n", conns);
2363       }
2364       break;
2365     case INTERNET_OPTION_RESET_URLCACHE_SESSION:
2366         FIXME("Option INTERNET_OPTION_RESET_URLCACHE_SESSION: STUB\n");
2367         break;
2368     case INTERNET_OPTION_END_BROWSER_SESSION:
2369         FIXME("Option INTERNET_OPTION_END_BROWSER_SESSION: STUB\n");
2370         break;
2371     case INTERNET_OPTION_CONNECTED_STATE:
2372         FIXME("Option INTERNET_OPTION_CONNECTED_STATE: STUB\n");
2373         break;
2374     case INTERNET_OPTION_DISABLE_PASSPORT_AUTH:
2375         TRACE("Option INTERNET_OPTION_DISABLE_PASSPORT_AUTH: harmless stub, since not enabled\n");
2376         break;
2377     case INTERNET_OPTION_SEND_TIMEOUT:
2378     case INTERNET_OPTION_RECEIVE_TIMEOUT:
2379     {
2380         ULONG timeout = *(ULONG *)lpBuffer;
2381         FIXME("INTERNET_OPTION_SEND/RECEIVE_TIMEOUT %d\n", timeout);
2382         break;
2383     }
2384     case INTERNET_OPTION_CONNECT_RETRIES:
2385     {
2386         ULONG retries = *(ULONG *)lpBuffer;
2387         FIXME("INTERNET_OPTION_CONNECT_RETRIES %d\n", retries);
2388         break;
2389     }
2390     case INTERNET_OPTION_CONTEXT_VALUE:
2391          FIXME("Option INTERNET_OPTION_CONTEXT_VALUE; STUB\n");
2392          break;
2393     case INTERNET_OPTION_SECURITY_FLAGS:
2394          FIXME("Option INTERNET_OPTION_SECURITY_FLAGS; STUB\n");
2395          break;
2396     case INTERNET_OPTION_DISABLE_AUTODIAL:
2397          FIXME("Option INTERNET_OPTION_DISABLE_AUTODIAL; STUB\n");
2398          break;
2399     case 86:
2400         FIXME("86\n");
2401         break;
2402     default:
2403         FIXME("Option %d STUB\n",dwOption);
2404         INTERNET_SetLastError(ERROR_INTERNET_INVALID_OPTION);
2405         ret = FALSE;
2406         break;
2407     }
2408
2409     if(lpwhh)
2410         WININET_Release( lpwhh );
2411
2412     return ret;
2413 }
2414
2415
2416 /***********************************************************************
2417  *           InternetSetOptionA (WININET.@)
2418  *
2419  * Sets an options on the specified handle.
2420  *
2421  * RETURNS
2422  *    TRUE  on success
2423  *    FALSE on failure
2424  *
2425  */
2426 BOOL WINAPI InternetSetOptionA(HINTERNET hInternet, DWORD dwOption,
2427                            LPVOID lpBuffer, DWORD dwBufferLength)
2428 {
2429     LPVOID wbuffer;
2430     DWORD wlen;
2431     BOOL r;
2432
2433     switch( dwOption )
2434     {
2435     case INTERNET_OPTION_CALLBACK:
2436         {
2437         LPWININETHANDLEHEADER lpwh;
2438         INTERNET_STATUS_CALLBACK callback = *(INTERNET_STATUS_CALLBACK *)lpBuffer;
2439
2440         if (!(lpwh = WININET_GetObject(hInternet))) return FALSE;
2441         r = (set_status_callback(lpwh, callback, FALSE) != INTERNET_INVALID_STATUS_CALLBACK);
2442         WININET_Release(lpwh);
2443         return r;
2444         }
2445     case INTERNET_OPTION_PROXY:
2446         {
2447         LPINTERNET_PROXY_INFOA pi = (LPINTERNET_PROXY_INFOA) lpBuffer;
2448         LPINTERNET_PROXY_INFOW piw;
2449         DWORD proxlen, prbylen;
2450         LPWSTR prox, prby;
2451
2452         proxlen = MultiByteToWideChar( CP_ACP, 0, pi->lpszProxy, -1, NULL, 0);
2453         prbylen= MultiByteToWideChar( CP_ACP, 0, pi->lpszProxyBypass, -1, NULL, 0);
2454         wlen = sizeof(*piw) + proxlen + prbylen;
2455         wbuffer = HeapAlloc( GetProcessHeap(), 0, wlen*sizeof(WCHAR) );
2456         piw = (LPINTERNET_PROXY_INFOW) wbuffer;
2457         piw->dwAccessType = pi->dwAccessType;
2458         prox = (LPWSTR) &piw[1];
2459         prby = &prox[proxlen+1];
2460         MultiByteToWideChar( CP_ACP, 0, pi->lpszProxy, -1, prox, proxlen);
2461         MultiByteToWideChar( CP_ACP, 0, pi->lpszProxyBypass, -1, prby, prbylen);
2462         piw->lpszProxy = prox;
2463         piw->lpszProxyBypass = prby;
2464         }
2465         break;
2466     case INTERNET_OPTION_USER_AGENT:
2467     case INTERNET_OPTION_USERNAME:
2468     case INTERNET_OPTION_PASSWORD:
2469         wlen = MultiByteToWideChar( CP_ACP, 0, lpBuffer, dwBufferLength,
2470                                    NULL, 0 );
2471         wbuffer = HeapAlloc( GetProcessHeap(), 0, wlen*sizeof(WCHAR) );
2472         MultiByteToWideChar( CP_ACP, 0, lpBuffer, dwBufferLength,
2473                                    wbuffer, wlen );
2474         break;
2475     default:
2476         wbuffer = lpBuffer;
2477         wlen = dwBufferLength;
2478     }
2479
2480     r = InternetSetOptionW(hInternet,dwOption, wbuffer, wlen);
2481
2482     if( lpBuffer != wbuffer )
2483         HeapFree( GetProcessHeap(), 0, wbuffer );
2484
2485     return r;
2486 }
2487
2488
2489 /***********************************************************************
2490  *           InternetSetOptionExA (WININET.@)
2491  */
2492 BOOL WINAPI InternetSetOptionExA(HINTERNET hInternet, DWORD dwOption,
2493                            LPVOID lpBuffer, DWORD dwBufferLength, DWORD dwFlags)
2494 {
2495     FIXME("Flags %08x ignored\n", dwFlags);
2496     return InternetSetOptionA( hInternet, dwOption, lpBuffer, dwBufferLength );
2497 }
2498
2499 /***********************************************************************
2500  *           InternetSetOptionExW (WININET.@)
2501  */
2502 BOOL WINAPI InternetSetOptionExW(HINTERNET hInternet, DWORD dwOption,
2503                            LPVOID lpBuffer, DWORD dwBufferLength, DWORD dwFlags)
2504 {
2505     FIXME("Flags %08x ignored\n", dwFlags);
2506     if( dwFlags & ~ISO_VALID_FLAGS )
2507     {
2508         INTERNET_SetLastError( ERROR_INVALID_PARAMETER );
2509         return FALSE;
2510     }
2511     return InternetSetOptionW( hInternet, dwOption, lpBuffer, dwBufferLength );
2512 }
2513
2514 static const WCHAR WININET_wkday[7][4] =
2515     { { 'S','u','n', 0 }, { 'M','o','n', 0 }, { 'T','u','e', 0 }, { 'W','e','d', 0 },
2516       { 'T','h','u', 0 }, { 'F','r','i', 0 }, { 'S','a','t', 0 } };
2517 static const WCHAR WININET_month[12][4] =
2518     { { 'J','a','n', 0 }, { 'F','e','b', 0 }, { 'M','a','r', 0 }, { 'A','p','r', 0 },
2519       { 'M','a','y', 0 }, { 'J','u','n', 0 }, { 'J','u','l', 0 }, { 'A','u','g', 0 },
2520       { 'S','e','p', 0 }, { 'O','c','t', 0 }, { 'N','o','v', 0 }, { 'D','e','c', 0 } };
2521
2522 /***********************************************************************
2523  *           InternetTimeFromSystemTimeA (WININET.@)
2524  */
2525 BOOL WINAPI InternetTimeFromSystemTimeA( const SYSTEMTIME* time, DWORD format, LPSTR string, DWORD size )
2526 {
2527     BOOL ret;
2528     WCHAR stringW[INTERNET_RFC1123_BUFSIZE];
2529
2530     TRACE( "%p 0x%08x %p 0x%08x\n", time, format, string, size );
2531
2532     ret = InternetTimeFromSystemTimeW( time, format, stringW, sizeof(stringW) );
2533     if (ret) WideCharToMultiByte( CP_ACP, 0, stringW, -1, string, size, NULL, NULL );
2534
2535     return ret;
2536 }
2537
2538 /***********************************************************************
2539  *           InternetTimeFromSystemTimeW (WININET.@)
2540  */
2541 BOOL WINAPI InternetTimeFromSystemTimeW( const SYSTEMTIME* time, DWORD format, LPWSTR string, DWORD size )
2542 {
2543     static const WCHAR date[] =
2544         { '%','s',',',' ','%','0','2','d',' ','%','s',' ','%','4','d',' ','%','0',
2545           '2','d',':','%','0','2','d',':','%','0','2','d',' ','G','M','T', 0 };
2546
2547     TRACE( "%p 0x%08x %p 0x%08x\n", time, format, string, size );
2548
2549     if (!time || !string) return FALSE;
2550
2551     if (format != INTERNET_RFC1123_FORMAT || size < INTERNET_RFC1123_BUFSIZE * sizeof(WCHAR))
2552         return FALSE;
2553
2554     sprintfW( string, date,
2555               WININET_wkday[time->wDayOfWeek],
2556               time->wDay,
2557               WININET_month[time->wMonth - 1],
2558               time->wYear,
2559               time->wHour,
2560               time->wMinute,
2561               time->wSecond );
2562
2563     return TRUE;
2564 }
2565
2566 /***********************************************************************
2567  *           InternetTimeToSystemTimeA (WININET.@)
2568  */
2569 BOOL WINAPI InternetTimeToSystemTimeA( LPCSTR string, SYSTEMTIME* time, DWORD reserved )
2570 {
2571     BOOL ret = FALSE;
2572     WCHAR *stringW;
2573     int len;
2574
2575     TRACE( "%s %p 0x%08x\n", debugstr_a(string), time, reserved );
2576
2577     len = MultiByteToWideChar( CP_ACP, 0, string, -1, NULL, 0 );
2578     stringW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
2579
2580     if (stringW)
2581     {
2582         MultiByteToWideChar( CP_ACP, 0, string, -1, stringW, len );
2583         ret = InternetTimeToSystemTimeW( stringW, time, reserved );
2584         HeapFree( GetProcessHeap(), 0, stringW );
2585     }
2586     return ret;
2587 }
2588
2589 /***********************************************************************
2590  *           InternetTimeToSystemTimeW (WININET.@)
2591  */
2592 BOOL WINAPI InternetTimeToSystemTimeW( LPCWSTR string, SYSTEMTIME* time, DWORD reserved )
2593 {
2594     unsigned int i;
2595     const WCHAR *s = string;
2596     WCHAR       *end;
2597
2598     TRACE( "%s %p 0x%08x\n", debugstr_w(string), time, reserved );
2599
2600     if (!string || !time) return FALSE;
2601
2602     /* Windows does this too */
2603     GetSystemTime( time );
2604
2605     /*  Convert an RFC1123 time such as 'Fri, 07 Jan 2005 12:06:35 GMT' into
2606      *  a SYSTEMTIME structure.
2607      */
2608
2609     while (*s && !isalphaW( *s )) s++;
2610     if (s[0] == '\0' || s[1] == '\0' || s[2] == '\0') return TRUE;
2611     time->wDayOfWeek = 7;
2612
2613     for (i = 0; i < 7; i++)
2614     {
2615         if (toupperW( WININET_wkday[i][0] ) == toupperW( s[0] ) &&
2616             toupperW( WININET_wkday[i][1] ) == toupperW( s[1] ) &&
2617             toupperW( WININET_wkday[i][2] ) == toupperW( s[2] ) )
2618         {
2619             time->wDayOfWeek = i;
2620             break;
2621         }
2622     }
2623
2624     if (time->wDayOfWeek > 6) return TRUE;
2625     while (*s && !isdigitW( *s )) s++;
2626     time->wDay = strtolW( s, &end, 10 );
2627     s = end;
2628
2629     while (*s && !isalphaW( *s )) s++;
2630     if (s[0] == '\0' || s[1] == '\0' || s[2] == '\0') return TRUE;
2631     time->wMonth = 0;
2632
2633     for (i = 0; i < 12; i++)
2634     {
2635         if (toupperW( WININET_month[i][0]) == toupperW( s[0] ) &&
2636             toupperW( WININET_month[i][1]) == toupperW( s[1] ) &&
2637             toupperW( WININET_month[i][2]) == toupperW( s[2] ) )
2638         {
2639             time->wMonth = i + 1;
2640             break;
2641         }
2642     }
2643     if (time->wMonth == 0) return TRUE;
2644
2645     while (*s && !isdigitW( *s )) s++;
2646     if (*s == '\0') return TRUE;
2647     time->wYear = strtolW( s, &end, 10 );
2648     s = end;
2649
2650     while (*s && !isdigitW( *s )) s++;
2651     if (*s == '\0') return TRUE;
2652     time->wHour = strtolW( s, &end, 10 );
2653     s = end;
2654
2655     while (*s && !isdigitW( *s )) s++;
2656     if (*s == '\0') return TRUE;
2657     time->wMinute = strtolW( s, &end, 10 );
2658     s = end;
2659
2660     while (*s && !isdigitW( *s )) s++;
2661     if (*s == '\0') return TRUE;
2662     time->wSecond = strtolW( s, &end, 10 );
2663     s = end;
2664
2665     time->wMilliseconds = 0;
2666     return TRUE;
2667 }
2668
2669 /***********************************************************************
2670  *      InternetCheckConnectionW (WININET.@)
2671  *
2672  * Pings a requested host to check internet connection
2673  *
2674  * RETURNS
2675  *   TRUE on success and FALSE on failure. If a failure then
2676  *   ERROR_NOT_CONNECTED is placed into GetLastError
2677  *
2678  */
2679 BOOL WINAPI InternetCheckConnectionW( LPCWSTR lpszUrl, DWORD dwFlags, DWORD dwReserved )
2680 {
2681 /*
2682  * this is a kludge which runs the resident ping program and reads the output.
2683  *
2684  * Anyone have a better idea?
2685  */
2686
2687   BOOL   rc = FALSE;
2688   static const CHAR ping[] = "ping -c 1 ";
2689   static const CHAR redirect[] = " >/dev/null 2>/dev/null";
2690   CHAR *command = NULL;
2691   WCHAR hostW[1024];
2692   DWORD len;
2693   INTERNET_PORT port;
2694   int status = -1;
2695
2696   FIXME("\n");
2697
2698   /*
2699    * Crack or set the Address
2700    */
2701   if (lpszUrl == NULL)
2702   {
2703      /*
2704       * According to the doc we are supposed to use the ip for the next
2705       * server in the WnInet internal server database. I have
2706       * no idea what that is or how to get it.
2707       *
2708       * So someone needs to implement this.
2709       */
2710      FIXME("Unimplemented with URL of NULL\n");
2711      return TRUE;
2712   }
2713   else
2714   {
2715      URL_COMPONENTSW components;
2716
2717      ZeroMemory(&components,sizeof(URL_COMPONENTSW));
2718      components.lpszHostName = (LPWSTR)&hostW;
2719      components.dwHostNameLength = 1024;
2720
2721      if (!InternetCrackUrlW(lpszUrl,0,0,&components))
2722        goto End;
2723
2724      TRACE("host name : %s\n",debugstr_w(components.lpszHostName));
2725      port = components.nPort;
2726      TRACE("port: %d\n", port);
2727   }
2728
2729   if (dwFlags & FLAG_ICC_FORCE_CONNECTION)
2730   {
2731       struct sockaddr_in sin;
2732       int fd;
2733
2734       if (!GetAddress(hostW, port, &sin))
2735           goto End;
2736       fd = socket(sin.sin_family, SOCK_STREAM, 0);
2737       if (fd != -1)
2738       {
2739           if (connect(fd, (struct sockaddr *)&sin, sizeof(sin)) == 0)
2740               rc = TRUE;
2741           close(fd);
2742       }
2743   }
2744   else
2745   {
2746       /*
2747        * Build our ping command
2748        */
2749       len = WideCharToMultiByte(CP_UNIXCP, 0, hostW, -1, NULL, 0, NULL, NULL);
2750       command = HeapAlloc( GetProcessHeap(), 0, strlen(ping)+len+strlen(redirect) );
2751       strcpy(command,ping);
2752       WideCharToMultiByte(CP_UNIXCP, 0, hostW, -1, command+strlen(ping), len, NULL, NULL);
2753       strcat(command,redirect);
2754
2755       TRACE("Ping command is : %s\n",command);
2756
2757       status = system(command);
2758
2759       TRACE("Ping returned a code of %i\n",status);
2760
2761       /* Ping return code of 0 indicates success */
2762       if (status == 0)
2763          rc = TRUE;
2764   }
2765
2766 End:
2767
2768   HeapFree( GetProcessHeap(), 0, command );
2769   if (rc == FALSE)
2770     INTERNET_SetLastError(ERROR_NOT_CONNECTED);
2771
2772   return rc;
2773 }
2774
2775
2776 /***********************************************************************
2777  *      InternetCheckConnectionA (WININET.@)
2778  *
2779  * Pings a requested host to check internet connection
2780  *
2781  * RETURNS
2782  *   TRUE on success and FALSE on failure. If a failure then
2783  *   ERROR_NOT_CONNECTED is placed into GetLastError
2784  *
2785  */
2786 BOOL WINAPI InternetCheckConnectionA(LPCSTR lpszUrl, DWORD dwFlags, DWORD dwReserved)
2787 {
2788     WCHAR *szUrl;
2789     INT len;
2790     BOOL rc;
2791
2792     len = MultiByteToWideChar(CP_ACP, 0, lpszUrl, -1, NULL, 0);
2793     if (!(szUrl = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR))))
2794         return FALSE;
2795     MultiByteToWideChar(CP_ACP, 0, lpszUrl, -1, szUrl, len);
2796     rc = InternetCheckConnectionW(szUrl, dwFlags, dwReserved);
2797     HeapFree(GetProcessHeap(), 0, szUrl);
2798     
2799     return rc;
2800 }
2801
2802
2803 /**********************************************************
2804  *      INTERNET_InternetOpenUrlW (internal)
2805  *
2806  * Opens an URL
2807  *
2808  * RETURNS
2809  *   handle of connection or NULL on failure
2810  */
2811 static HINTERNET INTERNET_InternetOpenUrlW(LPWININETAPPINFOW hIC, LPCWSTR lpszUrl,
2812     LPCWSTR lpszHeaders, DWORD dwHeadersLength, DWORD dwFlags, DWORD_PTR dwContext)
2813 {
2814     URL_COMPONENTSW urlComponents;
2815     WCHAR protocol[32], hostName[MAXHOSTNAME], userName[1024];
2816     WCHAR password[1024], path[2048], extra[1024];
2817     HINTERNET client = NULL, client1 = NULL;
2818     
2819     TRACE("(%p, %s, %s, %08x, %08x, %08lx)\n", hIC, debugstr_w(lpszUrl), debugstr_w(lpszHeaders),
2820           dwHeadersLength, dwFlags, dwContext);
2821     
2822     urlComponents.dwStructSize = sizeof(URL_COMPONENTSW);
2823     urlComponents.lpszScheme = protocol;
2824     urlComponents.dwSchemeLength = 32;
2825     urlComponents.lpszHostName = hostName;
2826     urlComponents.dwHostNameLength = MAXHOSTNAME;
2827     urlComponents.lpszUserName = userName;
2828     urlComponents.dwUserNameLength = 1024;
2829     urlComponents.lpszPassword = password;
2830     urlComponents.dwPasswordLength = 1024;
2831     urlComponents.lpszUrlPath = path;
2832     urlComponents.dwUrlPathLength = 2048;
2833     urlComponents.lpszExtraInfo = extra;
2834     urlComponents.dwExtraInfoLength = 1024;
2835     if(!InternetCrackUrlW(lpszUrl, strlenW(lpszUrl), 0, &urlComponents))
2836         return NULL;
2837     switch(urlComponents.nScheme) {
2838     case INTERNET_SCHEME_FTP:
2839         if(urlComponents.nPort == 0)
2840             urlComponents.nPort = INTERNET_DEFAULT_FTP_PORT;
2841         client = FTP_Connect(hIC, hostName, urlComponents.nPort,
2842                              userName, password, dwFlags, dwContext, INET_OPENURL);
2843         if(client == NULL)
2844             break;
2845         client1 = FtpOpenFileW(client, path, GENERIC_READ, dwFlags, dwContext);
2846         if(client1 == NULL) {
2847             InternetCloseHandle(client);
2848             break;
2849         }
2850         break;
2851         
2852     case INTERNET_SCHEME_HTTP:
2853     case INTERNET_SCHEME_HTTPS: {
2854         static const WCHAR szStars[] = { '*','/','*', 0 };
2855         LPCWSTR accept[2] = { szStars, NULL };
2856         if(urlComponents.nPort == 0) {
2857             if(urlComponents.nScheme == INTERNET_SCHEME_HTTP)
2858                 urlComponents.nPort = INTERNET_DEFAULT_HTTP_PORT;
2859             else
2860                 urlComponents.nPort = INTERNET_DEFAULT_HTTPS_PORT;
2861         }
2862         /* FIXME: should use pointers, not handles, as handles are not thread-safe */
2863         client = HTTP_Connect(hIC, hostName, urlComponents.nPort,
2864                               userName, password, dwFlags, dwContext, INET_OPENURL);
2865         if(client == NULL)
2866             break;
2867
2868         if (urlComponents.dwExtraInfoLength) {
2869                 WCHAR *path_extra;
2870                 DWORD len = urlComponents.dwUrlPathLength + urlComponents.dwExtraInfoLength + 1;
2871
2872                 if (!(path_extra = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR))))
2873                 {
2874                         InternetCloseHandle(client);
2875                         break;
2876                 }
2877                 strcpyW(path_extra, urlComponents.lpszUrlPath);
2878                 strcatW(path_extra, urlComponents.lpszExtraInfo);
2879                 client1 = HttpOpenRequestW(client, NULL, path_extra, NULL, NULL, accept, dwFlags, dwContext);
2880                 HeapFree(GetProcessHeap(), 0, path_extra);
2881         }
2882         else
2883                 client1 = HttpOpenRequestW(client, NULL, path, NULL, NULL, accept, dwFlags, dwContext);
2884
2885         if(client1 == NULL) {
2886             InternetCloseHandle(client);
2887             break;
2888         }
2889         HttpAddRequestHeadersW(client1, lpszHeaders, dwHeadersLength, HTTP_ADDREQ_FLAG_ADD);
2890         if (!HttpSendRequestW(client1, NULL, 0, NULL, 0) &&
2891             GetLastError() != ERROR_IO_PENDING) {
2892             InternetCloseHandle(client1);
2893             client1 = NULL;
2894             break;
2895         }
2896     }
2897     case INTERNET_SCHEME_GOPHER:
2898         /* gopher doesn't seem to be implemented in wine, but it's supposed
2899          * to be supported by InternetOpenUrlA. */
2900     default:
2901         INTERNET_SetLastError(ERROR_INTERNET_UNRECOGNIZED_SCHEME);
2902         break;
2903     }
2904
2905     TRACE(" %p <--\n", client1);
2906     
2907     return client1;
2908 }
2909
2910 /**********************************************************
2911  *      InternetOpenUrlW (WININET.@)
2912  *
2913  * Opens an URL
2914  *
2915  * RETURNS
2916  *   handle of connection or NULL on failure
2917  */
2918 static void AsyncInternetOpenUrlProc(WORKREQUEST *workRequest)
2919 {
2920     struct WORKREQ_INTERNETOPENURLW const *req = &workRequest->u.InternetOpenUrlW;
2921     LPWININETAPPINFOW hIC = (LPWININETAPPINFOW) workRequest->hdr;
2922
2923     TRACE("%p\n", hIC);
2924
2925     INTERNET_InternetOpenUrlW(hIC, req->lpszUrl,
2926                               req->lpszHeaders, req->dwHeadersLength, req->dwFlags, req->dwContext);
2927     HeapFree(GetProcessHeap(), 0, req->lpszUrl);
2928     HeapFree(GetProcessHeap(), 0, req->lpszHeaders);
2929 }
2930
2931 HINTERNET WINAPI InternetOpenUrlW(HINTERNET hInternet, LPCWSTR lpszUrl,
2932     LPCWSTR lpszHeaders, DWORD dwHeadersLength, DWORD dwFlags, DWORD_PTR dwContext)
2933 {
2934     HINTERNET ret = NULL;
2935     LPWININETAPPINFOW hIC = NULL;
2936
2937     if (TRACE_ON(wininet)) {
2938         TRACE("(%p, %s, %s, %08x, %08x, %08lx)\n", hInternet, debugstr_w(lpszUrl), debugstr_w(lpszHeaders),
2939               dwHeadersLength, dwFlags, dwContext);
2940         TRACE("  flags :");
2941         dump_INTERNET_FLAGS(dwFlags);
2942     }
2943
2944     if (!lpszUrl)
2945     {
2946         INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
2947         goto lend;
2948     }
2949
2950     hIC = (LPWININETAPPINFOW) WININET_GetObject( hInternet );
2951     if (NULL == hIC ||  hIC->hdr.htype != WH_HINIT) {
2952         INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
2953         goto lend;
2954     }
2955     
2956     if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC) {
2957         WORKREQUEST workRequest;
2958         struct WORKREQ_INTERNETOPENURLW *req;
2959
2960         workRequest.asyncproc = AsyncInternetOpenUrlProc;
2961         workRequest.hdr = WININET_AddRef( &hIC->hdr );
2962         req = &workRequest.u.InternetOpenUrlW;
2963         req->lpszUrl = WININET_strdupW(lpszUrl);
2964         if (lpszHeaders)
2965             req->lpszHeaders = WININET_strdupW(lpszHeaders);
2966         else
2967             req->lpszHeaders = 0;
2968         req->dwHeadersLength = dwHeadersLength;
2969         req->dwFlags = dwFlags;
2970         req->dwContext = dwContext;
2971         
2972         INTERNET_AsyncCall(&workRequest);
2973         /*
2974          * This is from windows.
2975          */
2976         INTERNET_SetLastError(ERROR_IO_PENDING);
2977     } else {
2978         ret = INTERNET_InternetOpenUrlW(hIC, lpszUrl, lpszHeaders, dwHeadersLength, dwFlags, dwContext);
2979     }
2980     
2981   lend:
2982     if( hIC )
2983         WININET_Release( &hIC->hdr );
2984     TRACE(" %p <--\n", ret);
2985     
2986     return ret;
2987 }
2988
2989 /**********************************************************
2990  *      InternetOpenUrlA (WININET.@)
2991  *
2992  * Opens an URL
2993  *
2994  * RETURNS
2995  *   handle of connection or NULL on failure
2996  */
2997 HINTERNET WINAPI InternetOpenUrlA(HINTERNET hInternet, LPCSTR lpszUrl,
2998     LPCSTR lpszHeaders, DWORD dwHeadersLength, DWORD dwFlags, DWORD_PTR dwContext)
2999 {
3000     HINTERNET rc = NULL;
3001
3002     INT lenUrl;
3003     INT lenHeaders = 0;
3004     LPWSTR szUrl = NULL;
3005     LPWSTR szHeaders = NULL;
3006
3007     TRACE("\n");
3008
3009     if(lpszUrl) {
3010         lenUrl = MultiByteToWideChar(CP_ACP, 0, lpszUrl, -1, NULL, 0 );
3011         szUrl = HeapAlloc(GetProcessHeap(), 0, lenUrl*sizeof(WCHAR));
3012         if(!szUrl)
3013             return NULL;
3014         MultiByteToWideChar(CP_ACP, 0, lpszUrl, -1, szUrl, lenUrl);
3015     }
3016
3017     if(lpszHeaders) {
3018         lenHeaders = MultiByteToWideChar(CP_ACP, 0, lpszHeaders, dwHeadersLength, NULL, 0 );
3019         szHeaders = HeapAlloc(GetProcessHeap(), 0, lenHeaders*sizeof(WCHAR));
3020         if(!szHeaders) {
3021             HeapFree(GetProcessHeap(), 0, szUrl);
3022             return NULL;
3023         }
3024         MultiByteToWideChar(CP_ACP, 0, lpszHeaders, dwHeadersLength, szHeaders, lenHeaders);
3025     }
3026     
3027     rc = InternetOpenUrlW(hInternet, szUrl, szHeaders,
3028         lenHeaders, dwFlags, dwContext);
3029
3030     HeapFree(GetProcessHeap(), 0, szUrl);
3031     HeapFree(GetProcessHeap(), 0, szHeaders);
3032
3033     return rc;
3034 }
3035
3036
3037 static LPWITHREADERROR INTERNET_AllocThreadError(void)
3038 {
3039     LPWITHREADERROR lpwite = HeapAlloc(GetProcessHeap(), 0, sizeof(*lpwite));
3040
3041     if (lpwite)
3042     {
3043         lpwite->dwError = 0;
3044         lpwite->response[0] = '\0';
3045     }
3046
3047     if (!TlsSetValue(g_dwTlsErrIndex, lpwite))
3048     {
3049         HeapFree(GetProcessHeap(), 0, lpwite);
3050         return NULL;
3051     }
3052
3053     return lpwite;
3054 }
3055
3056
3057 /***********************************************************************
3058  *           INTERNET_SetLastError (internal)
3059  *
3060  * Set last thread specific error
3061  *
3062  * RETURNS
3063  *
3064  */
3065 void INTERNET_SetLastError(DWORD dwError)
3066 {
3067     LPWITHREADERROR lpwite = (LPWITHREADERROR)TlsGetValue(g_dwTlsErrIndex);
3068
3069     if (!lpwite)
3070         lpwite = INTERNET_AllocThreadError();
3071
3072     SetLastError(dwError);
3073     if(lpwite)
3074         lpwite->dwError = dwError;
3075 }
3076
3077
3078 /***********************************************************************
3079  *           INTERNET_GetLastError (internal)
3080  *
3081  * Get last thread specific error
3082  *
3083  * RETURNS
3084  *
3085  */
3086 DWORD INTERNET_GetLastError(void)
3087 {
3088     LPWITHREADERROR lpwite = (LPWITHREADERROR)TlsGetValue(g_dwTlsErrIndex);
3089     if (!lpwite) return 0;
3090     /* TlsGetValue clears last error, so set it again here */
3091     SetLastError(lpwite->dwError);
3092     return lpwite->dwError;
3093 }
3094
3095
3096 /***********************************************************************
3097  *           INTERNET_WorkerThreadFunc (internal)
3098  *
3099  * Worker thread execution function
3100  *
3101  * RETURNS
3102  *
3103  */
3104 static DWORD CALLBACK INTERNET_WorkerThreadFunc(LPVOID lpvParam)
3105 {
3106     LPWORKREQUEST lpRequest = lpvParam;
3107     WORKREQUEST workRequest;
3108
3109     TRACE("\n");
3110
3111     workRequest = *lpRequest;
3112     HeapFree(GetProcessHeap(), 0, lpRequest);
3113
3114     workRequest.asyncproc(&workRequest);
3115
3116     WININET_Release( workRequest.hdr );
3117     return TRUE;
3118 }
3119
3120
3121 /***********************************************************************
3122  *           INTERNET_AsyncCall (internal)
3123  *
3124  * Retrieves work request from queue
3125  *
3126  * RETURNS
3127  *
3128  */
3129 BOOL INTERNET_AsyncCall(LPWORKREQUEST lpWorkRequest)
3130 {
3131     BOOL bSuccess;
3132     LPWORKREQUEST lpNewRequest;
3133
3134     TRACE("\n");
3135
3136     lpNewRequest = HeapAlloc(GetProcessHeap(), 0, sizeof(WORKREQUEST));
3137     if (!lpNewRequest)
3138         return FALSE;
3139
3140     *lpNewRequest = *lpWorkRequest;
3141
3142     bSuccess = QueueUserWorkItem(INTERNET_WorkerThreadFunc, lpNewRequest, WT_EXECUTELONGFUNCTION);
3143     if (!bSuccess)
3144     {
3145         HeapFree(GetProcessHeap(), 0, lpNewRequest);
3146         INTERNET_SetLastError(ERROR_INTERNET_ASYNC_THREAD_FAILED);
3147     }
3148
3149     return bSuccess;
3150 }
3151
3152
3153 /***********************************************************************
3154  *          INTERNET_GetResponseBuffer  (internal)
3155  *
3156  * RETURNS
3157  *
3158  */
3159 LPSTR INTERNET_GetResponseBuffer(void)
3160 {
3161     LPWITHREADERROR lpwite = (LPWITHREADERROR)TlsGetValue(g_dwTlsErrIndex);
3162     if (!lpwite)
3163         lpwite = INTERNET_AllocThreadError();
3164     TRACE("\n");
3165     return lpwite->response;
3166 }
3167
3168 /***********************************************************************
3169  *           INTERNET_GetNextLine  (internal)
3170  *
3171  * Parse next line in directory string listing
3172  *
3173  * RETURNS
3174  *   Pointer to beginning of next line
3175  *   NULL on failure
3176  *
3177  */
3178
3179 LPSTR INTERNET_GetNextLine(INT nSocket, LPDWORD dwLen)
3180 {
3181     struct pollfd pfd;
3182     BOOL bSuccess = FALSE;
3183     INT nRecv = 0;
3184     LPSTR lpszBuffer = INTERNET_GetResponseBuffer();
3185
3186     TRACE("\n");
3187
3188     pfd.fd = nSocket;
3189     pfd.events = POLLIN;
3190
3191     while (nRecv < MAX_REPLY_LEN)
3192     {
3193         if (poll(&pfd,1, RESPONSE_TIMEOUT * 1000) > 0)
3194         {
3195             if (recv(nSocket, &lpszBuffer[nRecv], 1, 0) <= 0)
3196             {
3197                 INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS);
3198                 goto lend;
3199             }
3200
3201             if (lpszBuffer[nRecv] == '\n')
3202             {
3203                 bSuccess = TRUE;
3204                 break;
3205             }
3206             if (lpszBuffer[nRecv] != '\r')
3207                 nRecv++;
3208         }
3209         else
3210         {
3211             INTERNET_SetLastError(ERROR_INTERNET_TIMEOUT);
3212             goto lend;
3213         }
3214     }
3215
3216 lend:
3217     if (bSuccess)
3218     {
3219         lpszBuffer[nRecv] = '\0';
3220         *dwLen = nRecv - 1;
3221         TRACE(":%d %s\n", nRecv, lpszBuffer);
3222         return lpszBuffer;
3223     }
3224     else
3225     {
3226         return NULL;
3227     }
3228 }
3229
3230 /**********************************************************
3231  *      InternetQueryDataAvailable (WININET.@)
3232  *
3233  * Determines how much data is available to be read.
3234  *
3235  * RETURNS
3236  *   TRUE on success, FALSE if an error occurred. If
3237  *   INTERNET_FLAG_ASYNC was specified in InternetOpen, and
3238  *   no data is presently available, FALSE is returned with
3239  *   the last error ERROR_IO_PENDING; a callback with status
3240  *   INTERNET_STATUS_REQUEST_COMPLETE will be sent when more
3241  *   data is available.
3242  */
3243 BOOL WINAPI InternetQueryDataAvailable( HINTERNET hFile,
3244                                 LPDWORD lpdwNumberOfBytesAvailble,
3245                                 DWORD dwFlags, DWORD_PTR dwContext)
3246 {
3247     WININETHANDLEHEADER *hdr;
3248     DWORD res;
3249
3250     TRACE("(%p %p %x %lx)\n", hFile, lpdwNumberOfBytesAvailble, dwFlags, dwContext);
3251
3252     hdr = WININET_GetObject( hFile );
3253     if (!hdr) {
3254         INTERNET_SetLastError(ERROR_INVALID_HANDLE);
3255         return FALSE;
3256     }
3257
3258     if(hdr->vtbl->QueryDataAvailable) {
3259         res = hdr->vtbl->QueryDataAvailable(hdr, lpdwNumberOfBytesAvailble, dwFlags, dwContext);
3260     }else {
3261         WARN("wrong handle\n");
3262         res = ERROR_INTERNET_INCORRECT_HANDLE_TYPE;
3263     }
3264
3265     WININET_Release(hdr);
3266
3267     if(res != ERROR_SUCCESS)
3268         SetLastError(res);
3269     return res == ERROR_SUCCESS;
3270 }
3271
3272
3273 /***********************************************************************
3274  *      InternetLockRequestFile (WININET.@)
3275  */
3276 BOOL WINAPI InternetLockRequestFile( HINTERNET hInternet, HANDLE
3277 *lphLockReqHandle)
3278 {
3279     FIXME("STUB\n");
3280     return FALSE;
3281 }
3282
3283 BOOL WINAPI InternetUnlockRequestFile( HANDLE hLockHandle)
3284 {
3285     FIXME("STUB\n");
3286     return FALSE;
3287 }
3288
3289
3290 /***********************************************************************
3291  *      InternetAutodial (WININET.@)
3292  *
3293  * On windows this function is supposed to dial the default internet
3294  * connection. We don't want to have Wine dial out to the internet so
3295  * we return TRUE by default. It might be nice to check if we are connected.
3296  *
3297  * RETURNS
3298  *   TRUE on success
3299  *   FALSE on failure
3300  *
3301  */
3302 BOOL WINAPI InternetAutodial(DWORD dwFlags, HWND hwndParent)
3303 {
3304     FIXME("STUB\n");
3305
3306     /* Tell that we are connected to the internet. */
3307     return TRUE;
3308 }
3309
3310 /***********************************************************************
3311  *      InternetAutodialHangup (WININET.@)
3312  *
3313  * Hangs up a connection made with InternetAutodial
3314  *
3315  * PARAM
3316  *    dwReserved
3317  * RETURNS
3318  *   TRUE on success
3319  *   FALSE on failure
3320  *
3321  */
3322 BOOL WINAPI InternetAutodialHangup(DWORD dwReserved)
3323 {
3324     FIXME("STUB\n");
3325
3326     /* we didn't dial, we don't disconnect */
3327     return TRUE;
3328 }
3329
3330 /***********************************************************************
3331  *      InternetCombineUrlA (WININET.@)
3332  *
3333  * Combine a base URL with a relative URL
3334  *
3335  * RETURNS
3336  *   TRUE on success
3337  *   FALSE on failure
3338  *
3339  */
3340
3341 BOOL WINAPI InternetCombineUrlA(LPCSTR lpszBaseUrl, LPCSTR lpszRelativeUrl,
3342                                 LPSTR lpszBuffer, LPDWORD lpdwBufferLength,
3343                                 DWORD dwFlags)
3344 {
3345     HRESULT hr=S_OK;
3346
3347     TRACE("(%s, %s, %p, %p, 0x%08x)\n", debugstr_a(lpszBaseUrl), debugstr_a(lpszRelativeUrl), lpszBuffer, lpdwBufferLength, dwFlags);
3348
3349     /* Flip this bit to correspond to URL_ESCAPE_UNSAFE */
3350     dwFlags ^= ICU_NO_ENCODE;
3351     hr=UrlCombineA(lpszBaseUrl,lpszRelativeUrl,lpszBuffer,lpdwBufferLength,dwFlags);
3352
3353     return (hr==S_OK);
3354 }
3355
3356 /***********************************************************************
3357  *      InternetCombineUrlW (WININET.@)
3358  *
3359  * Combine a base URL with a relative URL
3360  *
3361  * RETURNS
3362  *   TRUE on success
3363  *   FALSE on failure
3364  *
3365  */
3366
3367 BOOL WINAPI InternetCombineUrlW(LPCWSTR lpszBaseUrl, LPCWSTR lpszRelativeUrl,
3368                                 LPWSTR lpszBuffer, LPDWORD lpdwBufferLength,
3369                                 DWORD dwFlags)
3370 {
3371     HRESULT hr=S_OK;
3372
3373     TRACE("(%s, %s, %p, %p, 0x%08x)\n", debugstr_w(lpszBaseUrl), debugstr_w(lpszRelativeUrl), lpszBuffer, lpdwBufferLength, dwFlags);
3374
3375     /* Flip this bit to correspond to URL_ESCAPE_UNSAFE */
3376     dwFlags ^= ICU_NO_ENCODE;
3377     hr=UrlCombineW(lpszBaseUrl,lpszRelativeUrl,lpszBuffer,lpdwBufferLength,dwFlags);
3378
3379     return (hr==S_OK);
3380 }
3381
3382 /* max port num is 65535 => 5 digits */
3383 #define MAX_WORD_DIGITS 5
3384
3385 #define URL_GET_COMP_LENGTH(url, component) ((url)->dw##component##Length ? \
3386     (url)->dw##component##Length : strlenW((url)->lpsz##component))
3387 #define URL_GET_COMP_LENGTHA(url, component) ((url)->dw##component##Length ? \
3388     (url)->dw##component##Length : strlen((url)->lpsz##component))
3389
3390 static BOOL url_uses_default_port(INTERNET_SCHEME nScheme, INTERNET_PORT nPort)
3391 {
3392     if ((nScheme == INTERNET_SCHEME_HTTP) &&
3393         (nPort == INTERNET_DEFAULT_HTTP_PORT))
3394         return TRUE;
3395     if ((nScheme == INTERNET_SCHEME_HTTPS) &&
3396         (nPort == INTERNET_DEFAULT_HTTPS_PORT))
3397         return TRUE;
3398     if ((nScheme == INTERNET_SCHEME_FTP) &&
3399         (nPort == INTERNET_DEFAULT_FTP_PORT))
3400         return TRUE;
3401     if ((nScheme == INTERNET_SCHEME_GOPHER) &&
3402         (nPort == INTERNET_DEFAULT_GOPHER_PORT))
3403         return TRUE;
3404
3405     if (nPort == INTERNET_INVALID_PORT_NUMBER)
3406         return TRUE;
3407
3408     return FALSE;
3409 }
3410
3411 /* opaque urls do not fit into the standard url hierarchy and don't have
3412  * two following slashes */
3413 static inline BOOL scheme_is_opaque(INTERNET_SCHEME nScheme)
3414 {
3415     return (nScheme != INTERNET_SCHEME_FTP) &&
3416            (nScheme != INTERNET_SCHEME_GOPHER) &&
3417            (nScheme != INTERNET_SCHEME_HTTP) &&
3418            (nScheme != INTERNET_SCHEME_HTTPS) &&
3419            (nScheme != INTERNET_SCHEME_FILE);
3420 }
3421
3422 static LPCWSTR INTERNET_GetSchemeString(INTERNET_SCHEME scheme)
3423 {
3424     int index;
3425     if (scheme < INTERNET_SCHEME_FIRST)
3426         return NULL;
3427     index = scheme - INTERNET_SCHEME_FIRST;
3428     if (index >= sizeof(url_schemes)/sizeof(url_schemes[0]))
3429         return NULL;
3430     return (LPCWSTR)&url_schemes[index];
3431 }
3432
3433 /* we can calculate using ansi strings because we're just
3434  * calculating string length, not size
3435  */
3436 static BOOL calc_url_length(LPURL_COMPONENTSW lpUrlComponents,
3437                             LPDWORD lpdwUrlLength)
3438 {
3439     INTERNET_SCHEME nScheme;
3440
3441     *lpdwUrlLength = 0;
3442
3443     if (lpUrlComponents->lpszScheme)
3444     {
3445         DWORD dwLen = URL_GET_COMP_LENGTH(lpUrlComponents, Scheme);
3446         *lpdwUrlLength += dwLen;
3447         nScheme = GetInternetSchemeW(lpUrlComponents->lpszScheme, dwLen);
3448     }
3449     else
3450     {
3451         LPCWSTR scheme;
3452
3453         nScheme = lpUrlComponents->nScheme;
3454
3455         if (nScheme == INTERNET_SCHEME_DEFAULT)
3456             nScheme = INTERNET_SCHEME_HTTP;
3457         scheme = INTERNET_GetSchemeString(nScheme);
3458         *lpdwUrlLength += strlenW(scheme);
3459     }
3460
3461     (*lpdwUrlLength)++; /* ':' */
3462     if (!scheme_is_opaque(nScheme) || lpUrlComponents->lpszHostName)
3463         *lpdwUrlLength += strlen("//");
3464
3465     if (lpUrlComponents->lpszUserName)
3466     {
3467         *lpdwUrlLength += URL_GET_COMP_LENGTH(lpUrlComponents, UserName);
3468         *lpdwUrlLength += strlen("@");
3469     }
3470     else
3471     {
3472         if (lpUrlComponents->lpszPassword)
3473         {
3474             INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
3475             return FALSE;
3476         }
3477     }
3478
3479     if (lpUrlComponents->lpszPassword)
3480     {
3481         *lpdwUrlLength += strlen(":");
3482         *lpdwUrlLength += URL_GET_COMP_LENGTH(lpUrlComponents, Password);
3483     }
3484
3485     if (lpUrlComponents->lpszHostName)
3486     {
3487         *lpdwUrlLength += URL_GET_COMP_LENGTH(lpUrlComponents, HostName);
3488
3489         if (!url_uses_default_port(nScheme, lpUrlComponents->nPort))
3490         {
3491             char szPort[MAX_WORD_DIGITS+1];
3492
3493             sprintf(szPort, "%d", lpUrlComponents->nPort);
3494             *lpdwUrlLength += strlen(szPort);
3495             *lpdwUrlLength += strlen(":");
3496         }
3497
3498         if (lpUrlComponents->lpszUrlPath && *lpUrlComponents->lpszUrlPath != '/')
3499             (*lpdwUrlLength)++; /* '/' */
3500     }
3501
3502     if (lpUrlComponents->lpszUrlPath)
3503         *lpdwUrlLength += URL_GET_COMP_LENGTH(lpUrlComponents, UrlPath);
3504
3505     return TRUE;
3506 }
3507
3508 static void convert_urlcomp_atow(LPURL_COMPONENTSA lpUrlComponents, LPURL_COMPONENTSW urlCompW)
3509 {
3510     INT len;
3511
3512     ZeroMemory(urlCompW, sizeof(URL_COMPONENTSW));
3513
3514     urlCompW->dwStructSize = sizeof(URL_COMPONENTSW);
3515     urlCompW->dwSchemeLength = lpUrlComponents->dwSchemeLength;
3516     urlCompW->nScheme = lpUrlComponents->nScheme;
3517     urlCompW->dwHostNameLength = lpUrlComponents->dwHostNameLength;
3518     urlCompW->nPort = lpUrlComponents->nPort;
3519     urlCompW->dwUserNameLength = lpUrlComponents->dwUserNameLength;
3520     urlCompW->dwPasswordLength = lpUrlComponents->dwPasswordLength;
3521     urlCompW->dwUrlPathLength = lpUrlComponents->dwUrlPathLength;
3522     urlCompW->dwExtraInfoLength = lpUrlComponents->dwExtraInfoLength;
3523
3524     if (lpUrlComponents->lpszScheme)
3525     {
3526         len = URL_GET_COMP_LENGTHA(lpUrlComponents, Scheme) + 1;
3527         urlCompW->lpszScheme = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
3528         MultiByteToWideChar(CP_ACP, 0, lpUrlComponents->lpszScheme,
3529                             -1, urlCompW->lpszScheme, len);
3530     }
3531
3532     if (lpUrlComponents->lpszHostName)
3533     {
3534         len = URL_GET_COMP_LENGTHA(lpUrlComponents, HostName) + 1;
3535         urlCompW->lpszHostName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
3536         MultiByteToWideChar(CP_ACP, 0, lpUrlComponents->lpszHostName,
3537                             -1, urlCompW->lpszHostName, len);
3538     }
3539
3540     if (lpUrlComponents->lpszUserName)
3541     {
3542         len = URL_GET_COMP_LENGTHA(lpUrlComponents, UserName) + 1;
3543         urlCompW->lpszUserName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
3544         MultiByteToWideChar(CP_ACP, 0, lpUrlComponents->lpszUserName,
3545                             -1, urlCompW->lpszUserName, len);
3546     }
3547
3548     if (lpUrlComponents->lpszPassword)
3549     {
3550         len = URL_GET_COMP_LENGTHA(lpUrlComponents, Password) + 1;
3551         urlCompW->lpszPassword = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
3552         MultiByteToWideChar(CP_ACP, 0, lpUrlComponents->lpszPassword,
3553                             -1, urlCompW->lpszPassword, len);
3554     }
3555
3556     if (lpUrlComponents->lpszUrlPath)
3557     {
3558         len = URL_GET_COMP_LENGTHA(lpUrlComponents, UrlPath) + 1;
3559         urlCompW->lpszUrlPath = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
3560         MultiByteToWideChar(CP_ACP, 0, lpUrlComponents->lpszUrlPath,
3561                             -1, urlCompW->lpszUrlPath, len);
3562     }
3563
3564     if (lpUrlComponents->lpszExtraInfo)
3565     {
3566         len = URL_GET_COMP_LENGTHA(lpUrlComponents, ExtraInfo) + 1;
3567         urlCompW->lpszExtraInfo = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
3568         MultiByteToWideChar(CP_ACP, 0, lpUrlComponents->lpszExtraInfo,
3569                             -1, urlCompW->lpszExtraInfo, len);
3570     }
3571 }
3572
3573 /***********************************************************************
3574  *      InternetCreateUrlA (WININET.@)
3575  *
3576  * See InternetCreateUrlW.
3577  */
3578 BOOL WINAPI InternetCreateUrlA(LPURL_COMPONENTSA lpUrlComponents, DWORD dwFlags,
3579                                LPSTR lpszUrl, LPDWORD lpdwUrlLength)
3580 {
3581     BOOL ret;
3582     LPWSTR urlW = NULL;
3583     URL_COMPONENTSW urlCompW;
3584
3585     TRACE("(%p,%d,%p,%p)\n", lpUrlComponents, dwFlags, lpszUrl, lpdwUrlLength);
3586
3587     if (!lpUrlComponents || lpUrlComponents->dwStructSize != sizeof(URL_COMPONENTSW) || !lpdwUrlLength)
3588     {
3589         INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
3590         return FALSE;
3591     }
3592
3593     convert_urlcomp_atow(lpUrlComponents, &urlCompW);
3594
3595     if (lpszUrl)
3596         urlW = HeapAlloc(GetProcessHeap(), 0, *lpdwUrlLength * sizeof(WCHAR));
3597
3598     ret = InternetCreateUrlW(&urlCompW, dwFlags, urlW, lpdwUrlLength);
3599
3600     if (!ret && (GetLastError() == ERROR_INSUFFICIENT_BUFFER))
3601         *lpdwUrlLength /= sizeof(WCHAR);
3602
3603     /* on success, lpdwUrlLength points to the size of urlW in WCHARS
3604     * minus one, so add one to leave room for NULL terminator
3605     */
3606     if (ret)
3607         WideCharToMultiByte(CP_ACP, 0, urlW, -1, lpszUrl, *lpdwUrlLength + 1, NULL, NULL);
3608
3609     HeapFree(GetProcessHeap(), 0, urlCompW.lpszScheme);
3610     HeapFree(GetProcessHeap(), 0, urlCompW.lpszHostName);
3611     HeapFree(GetProcessHeap(), 0, urlCompW.lpszUserName);
3612     HeapFree(GetProcessHeap(), 0, urlCompW.lpszPassword);
3613     HeapFree(GetProcessHeap(), 0, urlCompW.lpszUrlPath);
3614     HeapFree(GetProcessHeap(), 0, urlCompW.lpszExtraInfo);
3615     HeapFree(GetProcessHeap(), 0, urlW);
3616
3617     return ret;
3618 }
3619
3620 /***********************************************************************
3621  *      InternetCreateUrlW (WININET.@)
3622  *
3623  * Creates a URL from its component parts.
3624  *
3625  * PARAMS
3626  *  lpUrlComponents [I] URL Components.
3627  *  dwFlags         [I] Flags. See notes.
3628  *  lpszUrl         [I] Buffer in which to store the created URL.
3629  *  lpdwUrlLength   [I/O] On input, the length of the buffer pointed to by
3630  *                        lpszUrl in characters. On output, the number of bytes
3631  *                        required to store the URL including terminator.
3632  *
3633  * NOTES
3634  *
3635  * The dwFlags parameter can be zero or more of the following:
3636  *|ICU_ESCAPE - Generates escape sequences for unsafe characters in the path and extra info of the URL.
3637  *
3638  * RETURNS
3639  *   TRUE on success
3640  *   FALSE on failure
3641  *
3642  */
3643 BOOL WINAPI InternetCreateUrlW(LPURL_COMPONENTSW lpUrlComponents, DWORD dwFlags,
3644                                LPWSTR lpszUrl, LPDWORD lpdwUrlLength)
3645 {
3646     DWORD dwLen;
3647     INTERNET_SCHEME nScheme;
3648
3649     static const WCHAR slashSlashW[] = {'/','/'};
3650     static const WCHAR percentD[] = {'%','d',0};
3651
3652     TRACE("(%p,%d,%p,%p)\n", lpUrlComponents, dwFlags, lpszUrl, lpdwUrlLength);
3653
3654     if (!lpUrlComponents || lpUrlComponents->dwStructSize != sizeof(URL_COMPONENTSW) || !lpdwUrlLength)
3655     {
3656         INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
3657         return FALSE;
3658     }
3659
3660     if (!calc_url_length(lpUrlComponents, &dwLen))
3661         return FALSE;
3662
3663     if (!lpszUrl || *lpdwUrlLength < dwLen)
3664     {
3665         *lpdwUrlLength = (dwLen + 1) * sizeof(WCHAR);
3666         INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
3667         return FALSE;
3668     }
3669
3670     *lpdwUrlLength = dwLen;
3671     lpszUrl[0] = 0x00;
3672
3673     dwLen = 0;
3674
3675     if (lpUrlComponents->lpszScheme)
3676     {
3677         dwLen = URL_GET_COMP_LENGTH(lpUrlComponents, Scheme);
3678         memcpy(lpszUrl, lpUrlComponents->lpszScheme, dwLen * sizeof(WCHAR));
3679         lpszUrl += dwLen;
3680
3681         nScheme = GetInternetSchemeW(lpUrlComponents->lpszScheme, dwLen);
3682     }
3683     else
3684     {
3685         LPCWSTR scheme;
3686         nScheme = lpUrlComponents->nScheme;
3687
3688         if (nScheme == INTERNET_SCHEME_DEFAULT)
3689             nScheme = INTERNET_SCHEME_HTTP;
3690
3691         scheme = INTERNET_GetSchemeString(nScheme);
3692         dwLen = strlenW(scheme);
3693         memcpy(lpszUrl, scheme, dwLen * sizeof(WCHAR));
3694         lpszUrl += dwLen;
3695     }
3696
3697     /* all schemes are followed by at least a colon */
3698     *lpszUrl = ':';
3699     lpszUrl++;
3700
3701     if (!scheme_is_opaque(nScheme) || lpUrlComponents->lpszHostName)
3702     {
3703         memcpy(lpszUrl, slashSlashW, sizeof(slashSlashW));
3704         lpszUrl += sizeof(slashSlashW)/sizeof(slashSlashW[0]);
3705     }
3706
3707     if (lpUrlComponents->lpszUserName)
3708     {
3709         dwLen = URL_GET_COMP_LENGTH(lpUrlComponents, UserName);
3710         memcpy(lpszUrl, lpUrlComponents->lpszUserName, dwLen * sizeof(WCHAR));
3711         lpszUrl += dwLen;
3712
3713         if (lpUrlComponents->lpszPassword)
3714         {
3715             *lpszUrl = ':';
3716             lpszUrl++;
3717
3718             dwLen = URL_GET_COMP_LENGTH(lpUrlComponents, Password);
3719             memcpy(lpszUrl, lpUrlComponents->lpszPassword, dwLen * sizeof(WCHAR));
3720             lpszUrl += dwLen;
3721         }
3722
3723         *lpszUrl = '@';
3724         lpszUrl++;
3725     }
3726
3727     if (lpUrlComponents->lpszHostName)
3728     {
3729         dwLen = URL_GET_COMP_LENGTH(lpUrlComponents, HostName);
3730         memcpy(lpszUrl, lpUrlComponents->lpszHostName, dwLen * sizeof(WCHAR));
3731         lpszUrl += dwLen;
3732
3733         if (!url_uses_default_port(nScheme, lpUrlComponents->nPort))
3734         {
3735             WCHAR szPort[MAX_WORD_DIGITS+1];
3736
3737             sprintfW(szPort, percentD, lpUrlComponents->nPort);
3738             *lpszUrl = ':';
3739             lpszUrl++;
3740             dwLen = strlenW(szPort);
3741             memcpy(lpszUrl, szPort, dwLen * sizeof(WCHAR));
3742             lpszUrl += dwLen;
3743         }
3744
3745         /* add slash between hostname and path if necessary */
3746         if (lpUrlComponents->lpszUrlPath && *lpUrlComponents->lpszUrlPath != '/')
3747         {
3748             *lpszUrl = '/';
3749             lpszUrl++;
3750         }
3751     }
3752
3753
3754     if (lpUrlComponents->lpszUrlPath)
3755     {
3756         dwLen = URL_GET_COMP_LENGTH(lpUrlComponents, UrlPath);
3757         memcpy(lpszUrl, lpUrlComponents->lpszUrlPath, dwLen * sizeof(WCHAR));
3758         lpszUrl += dwLen;
3759     }
3760
3761     *lpszUrl = '\0';
3762
3763     return TRUE;
3764 }
3765
3766 /***********************************************************************
3767  *      InternetConfirmZoneCrossingA (WININET.@)
3768  *
3769  */
3770 DWORD WINAPI InternetConfirmZoneCrossingA( HWND hWnd, LPSTR szUrlPrev, LPSTR szUrlNew, BOOL bPost )
3771 {
3772     FIXME("(%p, %s, %s, %x) stub\n", hWnd, debugstr_a(szUrlPrev), debugstr_a(szUrlNew), bPost);
3773     return ERROR_SUCCESS;
3774 }
3775
3776 /***********************************************************************
3777  *      InternetConfirmZoneCrossingW (WININET.@)
3778  *
3779  */
3780 DWORD WINAPI InternetConfirmZoneCrossingW( HWND hWnd, LPWSTR szUrlPrev, LPWSTR szUrlNew, BOOL bPost )
3781 {
3782     FIXME("(%p, %s, %s, %x) stub\n", hWnd, debugstr_w(szUrlPrev), debugstr_w(szUrlNew), bPost);
3783     return ERROR_SUCCESS;
3784 }
3785
3786 DWORD WINAPI InternetDialA( HWND hwndParent, LPSTR lpszConnectoid, DWORD dwFlags,
3787                             DWORD_PTR* lpdwConnection, DWORD dwReserved )
3788 {
3789     FIXME("(%p, %p, 0x%08x, %p, 0x%08x) stub\n", hwndParent, lpszConnectoid, dwFlags,
3790           lpdwConnection, dwReserved);
3791     return ERROR_SUCCESS;
3792 }
3793
3794 DWORD WINAPI InternetDialW( HWND hwndParent, LPWSTR lpszConnectoid, DWORD dwFlags,
3795                             DWORD_PTR* lpdwConnection, DWORD dwReserved )
3796 {
3797     FIXME("(%p, %p, 0x%08x, %p, 0x%08x) stub\n", hwndParent, lpszConnectoid, dwFlags,
3798           lpdwConnection, dwReserved);
3799     return ERROR_SUCCESS;
3800 }
3801
3802 BOOL WINAPI InternetGoOnlineA( LPSTR lpszURL, HWND hwndParent, DWORD dwReserved )
3803 {
3804     FIXME("(%s, %p, 0x%08x) stub\n", debugstr_a(lpszURL), hwndParent, dwReserved);
3805     return TRUE;
3806 }
3807
3808 BOOL WINAPI InternetGoOnlineW( LPWSTR lpszURL, HWND hwndParent, DWORD dwReserved )
3809 {
3810     FIXME("(%s, %p, 0x%08x) stub\n", debugstr_w(lpszURL), hwndParent, dwReserved);
3811     return TRUE;
3812 }
3813
3814 DWORD WINAPI InternetHangUp( DWORD_PTR dwConnection, DWORD dwReserved )
3815 {
3816     FIXME("(0x%08lx, 0x%08x) stub\n", dwConnection, dwReserved);
3817     return ERROR_SUCCESS;
3818 }
3819
3820 BOOL WINAPI CreateMD5SSOHash( PWSTR pszChallengeInfo, PWSTR pwszRealm, PWSTR pwszTarget,
3821                               PBYTE pbHexHash )
3822 {
3823     FIXME("(%s, %s, %s, %p) stub\n", debugstr_w(pszChallengeInfo), debugstr_w(pwszRealm),
3824           debugstr_w(pwszTarget), pbHexHash);
3825     return FALSE;
3826 }
3827
3828 BOOL WINAPI ResumeSuspendedDownload( HINTERNET hInternet, DWORD dwError )
3829 {
3830     FIXME("(%p, 0x%08x) stub\n", hInternet, dwError);
3831     return FALSE;
3832 }
3833
3834 BOOL WINAPI InternetQueryFortezzaStatus(DWORD *a, DWORD_PTR b)
3835 {
3836     FIXME("(%p, %08lx) stub\n", a, b);
3837     return 0;
3838 }