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