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