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