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