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