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