Correct tooltips behavior.
[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 "ntstatus.h"
52 #include "windef.h"
53 #include "winbase.h"
54 #include "winreg.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
67 #include "wine/unicode.h"
68
69 WINE_DEFAULT_DEBUG_CHANNEL(wininet);
70
71 #define MAX_IDLE_WORKER 1000*60*1
72 #define MAX_WORKER_THREADS 10
73 #define RESPONSE_TIMEOUT        30
74
75 #define GET_HWININET_FROM_LPWININETFINDNEXT(lpwh) \
76 (LPWININETAPPINFOW)(((LPWININETFTPSESSIONW)(lpwh->hdr.lpwhparent))->hdr.lpwhparent)
77
78
79 typedef struct
80 {
81     DWORD  dwError;
82     CHAR   response[MAX_REPLY_LEN];
83 } WITHREADERROR, *LPWITHREADERROR;
84
85 static VOID INTERNET_CloseHandle(LPWININETHANDLEHEADER hdr);
86 BOOL WINAPI INTERNET_FindNextFileW(LPWININETFINDNEXTW lpwh, LPVOID lpvFindData);
87 HINTERNET WINAPI INTERNET_InternetOpenUrlW(LPWININETAPPINFOW hIC, LPCWSTR lpszUrl,
88               LPCWSTR lpszHeaders, DWORD dwHeadersLength, DWORD dwFlags, DWORD dwContext);
89 static VOID INTERNET_ExecuteWork();
90
91 DWORD g_dwTlsErrIndex = TLS_OUT_OF_INDEXES;
92 DWORD dwNumThreads;
93 DWORD dwNumIdleThreads;
94 DWORD dwNumJobs;
95 HANDLE hEventArray[2];
96 #define hQuitEvent hEventArray[0]
97 #define hWorkEvent hEventArray[1]
98 CRITICAL_SECTION csQueue;
99 LPWORKREQUEST lpHeadWorkQueue;
100 LPWORKREQUEST lpWorkQueueTail;
101
102 extern void URLCacheContainers_CreateDefaults();
103 extern void URLCacheContainers_DeleteAll();
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, { 0, (DWORD)(__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         info = WININET_AddRef( WININET_Handles[handle-1] );
197
198     LeaveCriticalSection( &WININET_cs );
199
200     TRACE("handle %d -> %p\n", handle, info);
201
202     return info;
203 }
204
205 BOOL WININET_Release( LPWININETHANDLEHEADER info )
206 {
207     info->dwRefCount--;
208     TRACE( "object %p refcount = %ld\n", info, info->dwRefCount );
209     if( !info->dwRefCount )
210     {
211         TRACE( "destroying object %p\n", info);
212         info->destroy( info );
213     }
214     return TRUE;
215 }
216
217 BOOL WININET_FreeHandle( HINTERNET hinternet )
218 {
219     BOOL ret = FALSE;
220     UINT handle = (UINT) hinternet;
221     LPWININETHANDLEHEADER info = NULL;
222
223     EnterCriticalSection( &WININET_cs );
224
225     if( (handle > 0) && ( handle <= WININET_dwMaxHandles ) )
226     {
227         handle--;
228         if( WININET_Handles[handle] )
229         {
230             info = WININET_Handles[handle];
231             TRACE( "destroying handle %d for object %p\n", handle+1, info);
232             WININET_Handles[handle] = NULL;
233             ret = TRUE;
234             if( WININET_dwNextHandle > handle )
235                 WININET_dwNextHandle = handle;
236         }
237     }
238
239     LeaveCriticalSection( &WININET_cs );
240
241     if( info )
242         WININET_Release( info );
243
244     return ret;
245 }
246
247 /***********************************************************************
248  * DllMain [Internal] Initializes the internal 'WININET.DLL'.
249  *
250  * PARAMS
251  *     hinstDLL    [I] handle to the DLL's instance
252  *     fdwReason   [I]
253  *     lpvReserved [I] reserved, must be NULL
254  *
255  * RETURNS
256  *     Success: TRUE
257  *     Failure: FALSE
258  */
259
260 BOOL WINAPI DllMain (HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
261 {
262     TRACE("%p,%lx,%p\n", hinstDLL, fdwReason, lpvReserved);
263
264     switch (fdwReason) {
265         case DLL_PROCESS_ATTACH:
266
267             g_dwTlsErrIndex = TlsAlloc();
268
269             if (g_dwTlsErrIndex == TLS_OUT_OF_INDEXES)
270                 return FALSE;
271
272             hQuitEvent = CreateEventA(0, TRUE, FALSE, NULL);
273             hWorkEvent = CreateEventA(0, FALSE, FALSE, NULL);
274             InitializeCriticalSection(&csQueue);
275
276             URLCacheContainers_CreateDefaults();
277
278             dwNumThreads = 0;
279             dwNumIdleThreads = 0;
280             dwNumJobs = 0;
281
282         case DLL_THREAD_ATTACH:
283             {
284                 LPWITHREADERROR lpwite = HeapAlloc(GetProcessHeap(), 0, sizeof(WITHREADERROR));
285                 if (NULL == lpwite)
286                     return FALSE;
287
288                 TlsSetValue(g_dwTlsErrIndex, (LPVOID)lpwite);
289             }
290             break;
291
292         case DLL_THREAD_DETACH:
293             if (g_dwTlsErrIndex != TLS_OUT_OF_INDEXES)
294                         {
295                                 LPVOID lpwite = TlsGetValue(g_dwTlsErrIndex);
296                                 if (lpwite)
297                    HeapFree(GetProcessHeap(), 0, lpwite);
298                         }
299             break;
300
301         case DLL_PROCESS_DETACH:
302
303             URLCacheContainers_DeleteAll();
304
305             if (g_dwTlsErrIndex != TLS_OUT_OF_INDEXES)
306             {
307                 HeapFree(GetProcessHeap(), 0, TlsGetValue(g_dwTlsErrIndex));
308                 TlsFree(g_dwTlsErrIndex);
309             }
310
311             SetEvent(hQuitEvent);
312
313             CloseHandle(hQuitEvent);
314             CloseHandle(hWorkEvent);
315             DeleteCriticalSection(&csQueue);
316             break;
317     }
318
319     return TRUE;
320 }
321
322
323 /***********************************************************************
324  *           InternetInitializeAutoProxyDll   (WININET.@)
325  *
326  * Setup the internal proxy
327  *
328  * PARAMETERS
329  *     dwReserved
330  *
331  * RETURNS
332  *     FALSE on failure
333  *
334  */
335 BOOL WINAPI InternetInitializeAutoProxyDll(DWORD dwReserved)
336 {
337     FIXME("STUB\n");
338     INTERNET_SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
339     return FALSE;
340 }
341
342 /***********************************************************************
343  *           DetectAutoProxyUrl   (WININET.@)
344  *
345  * Auto detect the proxy url
346  *
347  * RETURNS
348  *     FALSE on failure
349  *
350  */
351 BOOL WINAPI DetectAutoProxyUrl(LPSTR lpszAutoProxyUrl,
352         DWORD dwAutoProxyUrlLength, DWORD dwDetectFlags)
353 {
354     FIXME("STUB\n");
355     INTERNET_SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
356     return FALSE;
357 }
358
359
360 /***********************************************************************
361  *           INTERNET_ConfigureProxyFromReg
362  *
363  * FIXME:
364  * The proxy may be specified in the form 'http=proxy.my.org'
365  * Presumably that means there can be ftp=ftpproxy.my.org too.
366  */
367 static BOOL INTERNET_ConfigureProxyFromReg( LPWININETAPPINFOW lpwai )
368 {
369     HKEY key;
370     DWORD r, keytype, len, enabled;
371     LPSTR lpszInternetSettings =
372         "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings";
373     static const WCHAR szProxyServer[] = { 'P','r','o','x','y','S','e','r','v','e','r', 0 };
374
375     r = RegOpenKeyA(HKEY_CURRENT_USER, lpszInternetSettings, &key);
376     if ( r != ERROR_SUCCESS )
377         return FALSE;
378
379     len = sizeof enabled;
380     r = RegQueryValueExA( key, "ProxyEnable", NULL, &keytype,
381                           (BYTE*)&enabled, &len);
382     if( (r == ERROR_SUCCESS) && enabled )
383     {
384         TRACE("Proxy is enabled.\n");
385
386         /* figure out how much memory the proxy setting takes */
387         r = RegQueryValueExW( key, szProxyServer, NULL, &keytype, 
388                               NULL, &len);
389         if( (r == ERROR_SUCCESS) && len && (keytype == REG_SZ) )
390         {
391             LPWSTR szProxy, p;
392             static const WCHAR szHttp[] = {'h','t','t','p','=',0};
393
394             szProxy=HeapAlloc( GetProcessHeap(), 0, len );
395             RegQueryValueExW( key, szProxyServer, NULL, &keytype,
396                               (BYTE*)szProxy, &len);
397
398             /* find the http proxy, and strip away everything else */
399             p = strstrW( szProxy, szHttp );
400             if( p )
401             {
402                  p += lstrlenW(szHttp);
403                  lstrcpyW( szProxy, p );
404             }
405             p = strchrW( szProxy, ' ' );
406             if( p )
407                 *p = 0;
408
409             lpwai->dwAccessType = INTERNET_OPEN_TYPE_PROXY;
410             lpwai->lpszProxy = szProxy;
411
412             TRACE("http proxy = %s\n", debugstr_w(lpwai->lpszProxy));
413         }
414         else
415             ERR("Couldn't read proxy server settings.\n");
416     }
417     else
418         TRACE("Proxy is not enabled.\n");
419     RegCloseKey(key);
420
421     return enabled;
422 }
423
424 /***********************************************************************
425  *           InternetOpenW   (WININET.@)
426  *
427  * Per-application initialization of wininet
428  *
429  * RETURNS
430  *    HINTERNET on success
431  *    NULL on failure
432  *
433  */
434 HINTERNET WINAPI InternetOpenW(LPCWSTR lpszAgent, DWORD dwAccessType,
435     LPCWSTR lpszProxy, LPCWSTR lpszProxyBypass, DWORD dwFlags)
436 {
437     LPWININETAPPINFOW lpwai = NULL;
438     HINTERNET handle = NULL;
439
440     if (TRACE_ON(wininet)) {
441 #define FE(x) { x, #x }
442         static const wininet_flag_info access_type[] = {
443             FE(INTERNET_OPEN_TYPE_PRECONFIG),
444             FE(INTERNET_OPEN_TYPE_DIRECT),
445             FE(INTERNET_OPEN_TYPE_PROXY),
446             FE(INTERNET_OPEN_TYPE_PRECONFIG_WITH_NO_AUTOPROXY)
447         };
448         static const wininet_flag_info flag[] = {
449             FE(INTERNET_FLAG_ASYNC),
450             FE(INTERNET_FLAG_FROM_CACHE),
451             FE(INTERNET_FLAG_OFFLINE)
452         };
453 #undef FE
454         DWORD i;
455         const char *access_type_str = "Unknown";
456         DWORD flag_val = dwFlags;
457         
458         TRACE("(%s, %li, %s, %s, %li)\n", debugstr_w(lpszAgent), dwAccessType,
459               debugstr_w(lpszProxy), debugstr_w(lpszProxyBypass), dwFlags);
460         for (i = 0; i < (sizeof(access_type) / sizeof(access_type[0])); i++) {
461             if (access_type[i].val == dwAccessType) {
462                 access_type_str = access_type[i].name;
463                 break;
464             }
465         }
466         TRACE("  access type : %s\n", access_type_str);
467         TRACE("  flags       :");
468         for (i = 0; i < (sizeof(flag) / sizeof(flag[0])); i++) {
469             if (flag[i].val & flag_val) {
470                 DPRINTF(" %s", flag[i].name);
471                 flag_val &= ~flag[i].val;
472             }
473         }       
474         if (flag_val) DPRINTF(" Unknown flags (%08lx)", flag_val);
475         DPRINTF("\n");
476     }
477
478     /* Clear any error information */
479     INTERNET_SetLastError(0);
480
481     lpwai = HeapAlloc(GetProcessHeap(), 0, sizeof(WININETAPPINFOW));
482     if (NULL == lpwai)
483     {
484         INTERNET_SetLastError(ERROR_OUTOFMEMORY);
485         goto lend;
486     }
487  
488     memset(lpwai, 0, sizeof(WININETAPPINFOW));
489     lpwai->hdr.htype = WH_HINIT;
490     lpwai->hdr.lpwhparent = NULL;
491     lpwai->hdr.dwFlags = dwFlags;
492     lpwai->hdr.dwRefCount = 1;
493     lpwai->hdr.destroy = INTERNET_CloseHandle;
494     lpwai->dwAccessType = dwAccessType;
495     lpwai->lpszProxyUsername = NULL;
496     lpwai->lpszProxyPassword = NULL;
497
498     handle = WININET_AllocHandle( &lpwai->hdr );
499     if( !handle )
500     {
501         HeapFree( GetProcessHeap(), 0, lpwai );
502         INTERNET_SetLastError(ERROR_OUTOFMEMORY);
503         goto lend;
504     }
505
506     if (NULL != lpszAgent)
507     {
508         lpwai->lpszAgent = HeapAlloc( GetProcessHeap(),0,
509                                       (strlenW(lpszAgent)+1)*sizeof(WCHAR));
510         if (lpwai->lpszAgent)
511             lstrcpyW( lpwai->lpszAgent, lpszAgent );
512     }
513     if(dwAccessType == INTERNET_OPEN_TYPE_PRECONFIG)
514         INTERNET_ConfigureProxyFromReg( lpwai );
515     else if (NULL != lpszProxy)
516     {
517         lpwai->lpszProxy = HeapAlloc( GetProcessHeap(), 0,
518                                       (strlenW(lpszProxy)+1)*sizeof(WCHAR));
519         if (lpwai->lpszProxy)
520             lstrcpyW( lpwai->lpszProxy, lpszProxy );
521     }
522
523     if (NULL != lpszProxyBypass)
524     {
525         lpwai->lpszProxyBypass = HeapAlloc( GetProcessHeap(), 0,
526                                      (strlenW(lpszProxyBypass)+1)*sizeof(WCHAR));
527         if (lpwai->lpszProxyBypass)
528             lstrcpyW( lpwai->lpszProxyBypass, lpszProxyBypass );
529     }
530
531 lend:
532     if( lpwai )
533         WININET_Release( &lpwai->hdr );
534
535     TRACE("returning %p\n", lpwai);
536
537     return handle;
538 }
539
540
541 /***********************************************************************
542  *           InternetOpenA   (WININET.@)
543  *
544  * Per-application initialization of wininet
545  *
546  * RETURNS
547  *    HINTERNET on success
548  *    NULL on failure
549  *
550  */
551 HINTERNET WINAPI InternetOpenA(LPCSTR lpszAgent, DWORD dwAccessType,
552     LPCSTR lpszProxy, LPCSTR lpszProxyBypass, DWORD dwFlags)
553 {
554     HINTERNET rc = (HINTERNET)NULL;
555     INT len;
556     WCHAR *szAgent = NULL, *szProxy = NULL, *szBypass = NULL;
557
558     TRACE("(%s, 0x%08lx, %s, %s, 0x%08lx)\n", debugstr_a(lpszAgent),
559        dwAccessType, debugstr_a(lpszProxy), debugstr_a(lpszProxyBypass), dwFlags);
560
561     if( lpszAgent )
562     {
563         len = MultiByteToWideChar(CP_ACP, 0, lpszAgent, -1, NULL, 0);
564         szAgent = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR));
565         MultiByteToWideChar(CP_ACP, 0, lpszAgent, -1, szAgent, len);
566     }
567
568     if( lpszProxy )
569     {
570         len = MultiByteToWideChar(CP_ACP, 0, lpszProxy, -1, NULL, 0);
571         szProxy = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR));
572         MultiByteToWideChar(CP_ACP, 0, lpszProxy, -1, szProxy, len);
573     }
574
575     if( lpszProxyBypass )
576     {
577         len = MultiByteToWideChar(CP_ACP, 0, lpszProxyBypass, -1, NULL, 0);
578         szBypass = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR));
579         MultiByteToWideChar(CP_ACP, 0, lpszProxyBypass, -1, szBypass, len);
580     }
581
582     rc = InternetOpenW(szAgent, dwAccessType, szProxy, szBypass, dwFlags);
583
584     if( szAgent )
585         HeapFree(GetProcessHeap(), 0, szAgent);
586     if( szProxy )
587         HeapFree(GetProcessHeap(), 0, szProxy);
588     if( szBypass )
589         HeapFree(GetProcessHeap(), 0, szBypass);
590
591     return rc;
592 }
593
594 /***********************************************************************
595  *           InternetGetLastResponseInfoA (WININET.@)
596  *
597  * Return last wininet error description on the calling thread
598  *
599  * RETURNS
600  *    TRUE on success of writing to buffer
601  *    FALSE on failure
602  *
603  */
604 BOOL WINAPI InternetGetLastResponseInfoA(LPDWORD lpdwError,
605     LPSTR lpszBuffer, LPDWORD lpdwBufferLength)
606 {
607     LPWITHREADERROR lpwite = (LPWITHREADERROR)TlsGetValue(g_dwTlsErrIndex);
608
609     TRACE("\n");
610
611     *lpdwError = lpwite->dwError;
612     if (lpwite->dwError)
613     {
614         strncpy(lpszBuffer, lpwite->response, *lpdwBufferLength);
615         *lpdwBufferLength = strlen(lpszBuffer);
616     }
617     else
618         *lpdwBufferLength = 0;
619
620     return TRUE;
621 }
622
623
624 /***********************************************************************
625  *           InternetGetConnectedState (WININET.@)
626  *
627  * Return connected state
628  *
629  * RETURNS
630  *    TRUE if connected
631  *    if lpdwStatus is not null, return the status (off line,
632  *    modem, lan...) in it.
633  *    FALSE if not connected
634  */
635 BOOL WINAPI InternetGetConnectedState(LPDWORD lpdwStatus, DWORD dwReserved)
636 {
637     TRACE("(%p, 0x%08lx)\n", lpdwStatus, dwReserved);
638
639     if (lpdwStatus) {
640         FIXME("always returning LAN connection.\n");
641         *lpdwStatus = INTERNET_CONNECTION_LAN;
642     }
643     return TRUE;
644 }
645
646 /***********************************************************************
647  *           InternetGetConnectedStateEx (WININET.@)
648  *
649  * Return connected state
650  *
651  * RETURNS
652  *    TRUE if connected
653  *    if lpdwStatus is not null, return the status (off line,
654  *    modem, lan...) in it.
655  *    FALSE if not connected
656  */
657 BOOL WINAPI InternetGetConnectedStateExW(LPDWORD lpdwStatus, LPWSTR lpszConnectionName,
658                                          DWORD dwNameLen, DWORD dwReserved)
659 {
660     TRACE("(%p, %s, %ld, 0x%08lx)\n", lpdwStatus, debugstr_w(lpszConnectionName), dwNameLen, dwReserved);
661
662     /* Must be zero */
663     if(dwReserved)
664         return FALSE;
665
666     if (lpdwStatus) {
667         FIXME("always returning LAN connection.\n");
668         *lpdwStatus = INTERNET_CONNECTION_LAN;
669     }
670     return TRUE;
671 }
672
673 /***********************************************************************
674  *           InternetConnectW (WININET.@)
675  *
676  * Open a ftp, gopher or http session
677  *
678  * RETURNS
679  *    HINTERNET a session handle on success
680  *    NULL on failure
681  *
682  */
683 HINTERNET WINAPI InternetConnectW(HINTERNET hInternet,
684     LPCWSTR lpszServerName, INTERNET_PORT nServerPort,
685     LPCWSTR lpszUserName, LPCWSTR lpszPassword,
686     DWORD dwService, DWORD dwFlags, DWORD dwContext)
687 {
688     LPWININETAPPINFOW hIC;
689     HINTERNET rc = (HINTERNET) NULL;
690
691     TRACE("(%p, %s, %i, %s, %s, %li, %li, %li)\n", hInternet, debugstr_w(lpszServerName),
692           nServerPort, debugstr_w(lpszUserName), debugstr_w(lpszPassword),
693           dwService, dwFlags, dwContext);
694
695     /* Clear any error information */
696     INTERNET_SetLastError(0);
697     hIC = (LPWININETAPPINFOW) WININET_GetObject( hInternet );
698     if ( (hIC == NULL) || (hIC->hdr.htype != WH_HINIT) )
699         goto lend;
700
701     switch (dwService)
702     {
703         case INTERNET_SERVICE_FTP:
704             rc = FTP_Connect(hIC, lpszServerName, nServerPort,
705             lpszUserName, lpszPassword, dwFlags, dwContext, 0);
706             break;
707
708         case INTERNET_SERVICE_HTTP:
709             rc = HTTP_Connect(hIC, lpszServerName, nServerPort,
710             lpszUserName, lpszPassword, dwFlags, dwContext, 0);
711             break;
712
713         case INTERNET_SERVICE_GOPHER:
714         default:
715             break;
716     }
717 lend:
718     if( hIC )
719         WININET_Release( &hIC->hdr );
720
721     TRACE("returning %p\n", rc);
722     return rc;
723 }
724
725
726 /***********************************************************************
727  *           InternetConnectA (WININET.@)
728  *
729  * Open a ftp, gopher or http session
730  *
731  * RETURNS
732  *    HINTERNET a session handle on success
733  *    NULL on failure
734  *
735  */
736 HINTERNET WINAPI InternetConnectA(HINTERNET hInternet,
737     LPCSTR lpszServerName, INTERNET_PORT nServerPort,
738     LPCSTR lpszUserName, LPCSTR lpszPassword,
739     DWORD dwService, DWORD dwFlags, DWORD dwContext)
740 {
741     HINTERNET rc = (HINTERNET)NULL;
742     INT len = 0;
743     LPWSTR szServerName = NULL;
744     LPWSTR szUserName = NULL;
745     LPWSTR szPassword = NULL;
746
747     if (lpszServerName)
748     {
749         len = MultiByteToWideChar(CP_ACP, 0, lpszServerName, -1, NULL, 0);
750         szServerName = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR));
751         MultiByteToWideChar(CP_ACP, 0, lpszServerName, -1, szServerName, len);
752     }
753     if (lpszUserName)
754     {
755         len = MultiByteToWideChar(CP_ACP, 0, lpszUserName, -1, NULL, 0);
756         szUserName = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR));
757         MultiByteToWideChar(CP_ACP, 0, lpszUserName, -1, szUserName, len);
758     }
759     if (lpszPassword)
760     {
761         len = MultiByteToWideChar(CP_ACP, 0, lpszPassword, -1, NULL, 0);
762         szPassword = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR));
763         MultiByteToWideChar(CP_ACP, 0, lpszPassword, -1, szPassword, len);
764     }
765
766
767     rc = InternetConnectW(hInternet, szServerName, nServerPort,
768         szUserName, szPassword, dwService, dwFlags, dwContext);
769
770     if (szServerName) HeapFree(GetProcessHeap(), 0, szServerName);
771     if (szUserName) HeapFree(GetProcessHeap(), 0, szUserName);
772     if (szPassword) HeapFree(GetProcessHeap(), 0, szPassword);
773     return rc;
774 }
775
776
777 /***********************************************************************
778  *           InternetFindNextFileA (WININET.@)
779  *
780  * Continues a file search from a previous call to FindFirstFile
781  *
782  * RETURNS
783  *    TRUE on success
784  *    FALSE on failure
785  *
786  */
787 BOOL WINAPI InternetFindNextFileA(HINTERNET hFind, LPVOID lpvFindData)
788 {
789     BOOL ret;
790     WIN32_FIND_DATAW fd;
791     
792     ret = InternetFindNextFileW(hFind, lpvFindData?&fd:NULL);
793     if(lpvFindData)
794         WININET_find_data_WtoA(&fd, (LPWIN32_FIND_DATAA)lpvFindData);
795     return ret;
796 }
797
798 /***********************************************************************
799  *           InternetFindNextFileW (WININET.@)
800  *
801  * Continues a file search from a previous call to FindFirstFile
802  *
803  * RETURNS
804  *    TRUE on success
805  *    FALSE on failure
806  *
807  */
808 BOOL WINAPI InternetFindNextFileW(HINTERNET hFind, LPVOID lpvFindData)
809 {
810     LPWININETAPPINFOW hIC = NULL;
811     LPWININETFINDNEXTW lpwh;
812     BOOL bSuccess = FALSE;
813
814     TRACE("\n");
815
816     lpwh = (LPWININETFINDNEXTW) WININET_GetObject( hFind );
817     if (NULL == lpwh || lpwh->hdr.htype != WH_HFINDNEXT)
818     {
819         INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
820         goto lend;
821     }
822
823     hIC = GET_HWININET_FROM_LPWININETFINDNEXT(lpwh);
824     if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
825     {
826         WORKREQUEST workRequest;
827         struct WORKREQ_INTERNETFINDNEXTW *req;
828
829         workRequest.asyncall = INTERNETFINDNEXTW;
830         workRequest.hdr = WININET_AddRef( &lpwh->hdr );
831         req = &workRequest.u.InternetFindNextW;
832         req->lpFindFileData = lpvFindData;
833
834         bSuccess = INTERNET_AsyncCall(&workRequest);
835     }
836     else
837     {
838         bSuccess = INTERNET_FindNextFileW(lpwh, lpvFindData);
839     }
840 lend:
841     if( lpwh )
842         WININET_Release( &lpwh->hdr );
843     return bSuccess;
844 }
845
846 /***********************************************************************
847  *           INTERNET_FindNextFileW (Internal)
848  *
849  * Continues a file search from a previous call to FindFirstFile
850  *
851  * RETURNS
852  *    TRUE on success
853  *    FALSE on failure
854  *
855  */
856 BOOL WINAPI INTERNET_FindNextFileW(LPWININETFINDNEXTW lpwh, LPVOID lpvFindData)
857 {
858     BOOL bSuccess = TRUE;
859     LPWININETAPPINFOW hIC = NULL;
860     LPWIN32_FIND_DATAW lpFindFileData;
861
862     TRACE("\n");
863
864     assert (lpwh->hdr.htype == WH_HFINDNEXT);
865
866     /* Clear any error information */
867     INTERNET_SetLastError(0);
868
869     if (lpwh->hdr.lpwhparent->htype != WH_HFTPSESSION)
870     {
871         FIXME("Only FTP find next supported\n");
872         INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
873         return FALSE;
874     }
875
876     TRACE("index(%ld) size(%ld)\n", lpwh->index, lpwh->size);
877
878     lpFindFileData = (LPWIN32_FIND_DATAW) lpvFindData;
879     ZeroMemory(lpFindFileData, sizeof(WIN32_FIND_DATAA));
880
881     if (lpwh->index >= lpwh->size)
882     {
883         INTERNET_SetLastError(ERROR_NO_MORE_FILES);
884         bSuccess = FALSE;
885         goto lend;
886     }
887
888     FTP_ConvertFileProp(&lpwh->lpafp[lpwh->index], lpFindFileData);
889     lpwh->index++;
890
891     TRACE("\nName: %s\nSize: %ld\n", debugstr_w(lpFindFileData->cFileName), lpFindFileData->nFileSizeLow);
892
893 lend:
894
895     hIC = GET_HWININET_FROM_LPWININETFINDNEXT(lpwh);
896     if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
897     {
898         INTERNET_ASYNC_RESULT iar;
899
900         iar.dwResult = (DWORD)bSuccess;
901         iar.dwError = iar.dwError = bSuccess ? ERROR_SUCCESS :
902                                                INTERNET_GetLastError();
903
904         SendAsyncCallback(hIC, &lpwh->hdr, lpwh->hdr.dwContext,
905                       INTERNET_STATUS_REQUEST_COMPLETE, &iar,
906                        sizeof(INTERNET_ASYNC_RESULT));
907     }
908
909     return bSuccess;
910 }
911
912
913 /***********************************************************************
914  *           INTERNET_CloseHandle (internal)
915  *
916  * Close internet handle
917  *
918  * RETURNS
919  *    Void
920  *
921  */
922 static VOID INTERNET_CloseHandle(LPWININETHANDLEHEADER hdr)
923 {
924     LPWININETAPPINFOW lpwai = (LPWININETAPPINFOW) hdr;
925
926     TRACE("%p\n",lpwai);
927
928     if (lpwai->lpszAgent)
929         HeapFree(GetProcessHeap(), 0, lpwai->lpszAgent);
930
931     if (lpwai->lpszProxy)
932         HeapFree(GetProcessHeap(), 0, lpwai->lpszProxy);
933
934     if (lpwai->lpszProxyBypass)
935         HeapFree(GetProcessHeap(), 0, lpwai->lpszProxyBypass);
936
937     if (lpwai->lpszProxyUsername)
938         HeapFree(GetProcessHeap(), 0, lpwai->lpszProxyUsername);
939
940     if (lpwai->lpszProxyPassword)
941         HeapFree(GetProcessHeap(), 0, lpwai->lpszProxyPassword);
942
943     HeapFree(GetProcessHeap(), 0, lpwai);
944 }
945
946
947 /***********************************************************************
948  *           InternetCloseHandle (WININET.@)
949  *
950  * Generic close handle function
951  *
952  * RETURNS
953  *    TRUE on success
954  *    FALSE on failure
955  *
956  */
957 BOOL WINAPI InternetCloseHandle(HINTERNET hInternet)
958 {
959     LPWININETHANDLEHEADER lpwh, parent;
960     LPWININETAPPINFOW hIC;
961     
962     TRACE("%p\n",hInternet);
963
964     lpwh = WININET_GetObject( hInternet );
965     if (NULL == lpwh)
966     {
967         INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
968         return FALSE;
969     }
970
971     parent = lpwh;
972     while( parent && (parent->htype != WH_HINIT ) )
973         parent = parent->lpwhparent;
974
975     hIC = (LPWININETAPPINFOW) parent;
976     SendAsyncCallback(hIC, lpwh, lpwh->dwContext,
977                       INTERNET_STATUS_HANDLE_CLOSING, hInternet,
978                       sizeof(HINTERNET));
979
980     if( lpwh->lpwhparent )
981         WININET_Release( lpwh->lpwhparent );
982     WININET_FreeHandle( hInternet );
983     WININET_Release( lpwh );
984
985     return TRUE;
986 }
987
988
989 /***********************************************************************
990  *           ConvertUrlComponentValue (Internal)
991  *
992  * Helper function for InternetCrackUrlW
993  *
994  */
995 void ConvertUrlComponentValue(LPSTR* lppszComponent, LPDWORD dwComponentLen,
996                               LPWSTR lpwszComponent, DWORD dwwComponentLen,
997                               LPCSTR lpszStart,
998                               LPCWSTR lpwszStart)
999 {
1000     if (*dwComponentLen != 0)
1001     {
1002         DWORD nASCIILength=WideCharToMultiByte(CP_ACP,0,lpwszComponent,dwwComponentLen,NULL,0,NULL,NULL);
1003         if (*lppszComponent == NULL)
1004         {
1005             int nASCIIOffset=WideCharToMultiByte(CP_ACP,0,lpwszStart,lpwszComponent-lpwszStart,NULL,0,NULL,NULL);
1006             *lppszComponent = (LPSTR)lpszStart+nASCIIOffset;
1007             *dwComponentLen = nASCIILength;
1008         }
1009         else
1010         {
1011             DWORD ncpylen = min((*dwComponentLen)-1, nASCIILength);
1012             WideCharToMultiByte(CP_ACP,0,lpwszComponent,dwwComponentLen,*lppszComponent,ncpylen+1,NULL,NULL);
1013             (*lppszComponent)[ncpylen]=0;
1014             *dwComponentLen = ncpylen;
1015         }
1016     }
1017 }
1018
1019
1020 /***********************************************************************
1021  *           InternetCrackUrlA (WININET.@)
1022  *
1023  * Break up URL into its components
1024  *
1025  * TODO: Handle dwFlags
1026  *
1027  * RETURNS
1028  *    TRUE on success
1029  *    FALSE on failure
1030  *
1031  */
1032 BOOL WINAPI InternetCrackUrlA(LPCSTR lpszUrl, DWORD dwUrlLength, DWORD dwFlags,
1033     LPURL_COMPONENTSA lpUrlComponents)
1034 {
1035   DWORD nLength;
1036   URL_COMPONENTSW UCW;
1037   WCHAR* lpwszUrl;
1038
1039   if(dwUrlLength<=0)
1040       dwUrlLength=-1;
1041   nLength=MultiByteToWideChar(CP_ACP,0,lpszUrl,dwUrlLength,NULL,0);
1042   lpwszUrl=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WCHAR)*nLength);
1043   MultiByteToWideChar(CP_ACP,0,lpszUrl,dwUrlLength,lpwszUrl,nLength);
1044
1045   memset(&UCW,0,sizeof(UCW));
1046   if(lpUrlComponents->dwHostNameLength!=0)
1047       UCW.dwHostNameLength=1;
1048   if(lpUrlComponents->dwUserNameLength!=0)
1049       UCW.dwUserNameLength=1;
1050   if(lpUrlComponents->dwPasswordLength!=0)
1051       UCW.dwPasswordLength=1;
1052   if(lpUrlComponents->dwUrlPathLength!=0)
1053       UCW.dwUrlPathLength=1;
1054   if(lpUrlComponents->dwSchemeLength!=0)
1055       UCW.dwSchemeLength=1;
1056   if(lpUrlComponents->dwExtraInfoLength!=0)
1057       UCW.dwExtraInfoLength=1;
1058   if(!InternetCrackUrlW(lpwszUrl,nLength,dwFlags,&UCW))
1059   {
1060       HeapFree(GetProcessHeap(), 0, lpwszUrl);
1061       return FALSE;
1062   }
1063   ConvertUrlComponentValue(&lpUrlComponents->lpszHostName, &lpUrlComponents->dwHostNameLength,
1064                            UCW.lpszHostName, UCW.dwHostNameLength,
1065                            lpszUrl, lpwszUrl);
1066   ConvertUrlComponentValue(&lpUrlComponents->lpszUserName, &lpUrlComponents->dwUserNameLength,
1067                            UCW.lpszUserName, UCW.dwUserNameLength,
1068                            lpszUrl, lpwszUrl);
1069   ConvertUrlComponentValue(&lpUrlComponents->lpszPassword, &lpUrlComponents->dwPasswordLength,
1070                            UCW.lpszPassword, UCW.dwPasswordLength,
1071                            lpszUrl, lpwszUrl);
1072   ConvertUrlComponentValue(&lpUrlComponents->lpszUrlPath, &lpUrlComponents->dwUrlPathLength,
1073                            UCW.lpszUrlPath, UCW.dwUrlPathLength,
1074                            lpszUrl, lpwszUrl);
1075   ConvertUrlComponentValue(&lpUrlComponents->lpszScheme, &lpUrlComponents->dwSchemeLength,
1076                            UCW.lpszScheme, UCW.dwSchemeLength,
1077                            lpszUrl, lpwszUrl);
1078   ConvertUrlComponentValue(&lpUrlComponents->lpszExtraInfo, &lpUrlComponents->dwExtraInfoLength,
1079                            UCW.lpszExtraInfo, UCW.dwExtraInfoLength,
1080                            lpszUrl, lpwszUrl);
1081   lpUrlComponents->nScheme=UCW.nScheme;
1082   lpUrlComponents->nPort=UCW.nPort;
1083   HeapFree(GetProcessHeap(), 0, lpwszUrl);
1084   
1085   TRACE("%s: scheme(%s) host(%s) path(%s) extra(%s)\n", lpszUrl,
1086           debugstr_an(lpUrlComponents->lpszScheme,lpUrlComponents->dwSchemeLength),
1087           debugstr_an(lpUrlComponents->lpszHostName,lpUrlComponents->dwHostNameLength),
1088           debugstr_an(lpUrlComponents->lpszUrlPath,lpUrlComponents->dwUrlPathLength),
1089           debugstr_an(lpUrlComponents->lpszExtraInfo,lpUrlComponents->dwExtraInfoLength));
1090
1091   return TRUE;
1092 }
1093
1094 /***********************************************************************
1095  *           GetInternetSchemeW (internal)
1096  *
1097  * Get scheme of url
1098  *
1099  * RETURNS
1100  *    scheme on success
1101  *    INTERNET_SCHEME_UNKNOWN on failure
1102  *
1103  */
1104 static INTERNET_SCHEME GetInternetSchemeW(LPCWSTR lpszScheme, DWORD nMaxCmp)
1105 {
1106     INTERNET_SCHEME iScheme=INTERNET_SCHEME_UNKNOWN;
1107     static const WCHAR lpszFtp[]={'f','t','p',0};
1108     static const WCHAR lpszGopher[]={'g','o','p','h','e','r',0};
1109     static const WCHAR lpszHttp[]={'h','t','t','p',0};
1110     static const WCHAR lpszHttps[]={'h','t','t','p','s',0};
1111     static const WCHAR lpszFile[]={'f','i','l','e',0};
1112     static const WCHAR lpszNews[]={'n','e','w','s',0};
1113     static const WCHAR lpszMailto[]={'m','a','i','l','t','o',0};
1114     static const WCHAR lpszRes[]={'r','e','s',0};
1115     WCHAR* tempBuffer=NULL;
1116     TRACE("\n");
1117     if(lpszScheme==NULL)
1118         return INTERNET_SCHEME_UNKNOWN;
1119
1120     tempBuffer=HeapAlloc(GetProcessHeap(),0,(nMaxCmp+1)*sizeof(WCHAR));
1121     strncpyW(tempBuffer,lpszScheme,nMaxCmp);
1122     tempBuffer[nMaxCmp]=0;
1123     strlwrW(tempBuffer);
1124     if (nMaxCmp==strlenW(lpszFtp) && !strncmpW(lpszFtp, tempBuffer, nMaxCmp))
1125         iScheme=INTERNET_SCHEME_FTP;
1126     else if (nMaxCmp==strlenW(lpszGopher) && !strncmpW(lpszGopher, tempBuffer, nMaxCmp))
1127         iScheme=INTERNET_SCHEME_GOPHER;
1128     else if (nMaxCmp==strlenW(lpszHttp) && !strncmpW(lpszHttp, tempBuffer, nMaxCmp))
1129         iScheme=INTERNET_SCHEME_HTTP;
1130     else if (nMaxCmp==strlenW(lpszHttps) && !strncmpW(lpszHttps, tempBuffer, nMaxCmp))
1131         iScheme=INTERNET_SCHEME_HTTPS;
1132     else if (nMaxCmp==strlenW(lpszFile) && !strncmpW(lpszFile, tempBuffer, nMaxCmp))
1133         iScheme=INTERNET_SCHEME_FILE;
1134     else if (nMaxCmp==strlenW(lpszNews) && !strncmpW(lpszNews, tempBuffer, nMaxCmp))
1135         iScheme=INTERNET_SCHEME_NEWS;
1136     else if (nMaxCmp==strlenW(lpszMailto) && !strncmpW(lpszMailto, tempBuffer, nMaxCmp))
1137         iScheme=INTERNET_SCHEME_MAILTO;
1138     else if (nMaxCmp==strlenW(lpszRes) && !strncmpW(lpszRes, tempBuffer, nMaxCmp))
1139         iScheme=INTERNET_SCHEME_RES;
1140     HeapFree(GetProcessHeap(),0,tempBuffer);
1141     return iScheme;
1142 }
1143
1144 /***********************************************************************
1145  *           SetUrlComponentValueW (Internal)
1146  *
1147  * Helper function for InternetCrackUrlW
1148  *
1149  * RETURNS
1150  *    TRUE on success
1151  *    FALSE on failure
1152  *
1153  */
1154 static BOOL SetUrlComponentValueW(LPWSTR* lppszComponent, LPDWORD dwComponentLen, LPCWSTR lpszStart, DWORD len)
1155 {
1156     TRACE("%s (%ld)\n", debugstr_wn(lpszStart,len), len);
1157
1158     if ( (*dwComponentLen == 0) && (*lppszComponent == NULL) )
1159         return FALSE;
1160
1161     if (*dwComponentLen != 0 || *lppszComponent == NULL)
1162     {
1163         if (*lppszComponent == NULL)
1164         {
1165             *lppszComponent = (LPWSTR)lpszStart;
1166             *dwComponentLen = len;
1167         }
1168         else
1169         {
1170             DWORD ncpylen = min((*dwComponentLen)-1, len);
1171             strncpyW(*lppszComponent, lpszStart, ncpylen);
1172             (*lppszComponent)[ncpylen] = '\0';
1173             *dwComponentLen = ncpylen;
1174         }
1175     }
1176
1177     return TRUE;
1178 }
1179
1180 /***********************************************************************
1181  *           InternetCrackUrlW   (WININET.@)
1182  */
1183 BOOL WINAPI InternetCrackUrlW(LPCWSTR lpszUrl, DWORD dwUrlLength, DWORD dwFlags,
1184                               LPURL_COMPONENTSW lpUC)
1185 {
1186   /*
1187    * RFC 1808
1188    * <protocol>:[//<net_loc>][/path][;<params>][?<query>][#<fragment>]
1189    *
1190    */
1191     LPCWSTR lpszParam    = NULL;
1192     BOOL  bIsAbsolute = FALSE;
1193     LPCWSTR lpszap = lpszUrl;
1194     LPCWSTR lpszcp = NULL;
1195     const WCHAR lpszSeparators[3]={';','?',0};
1196     const WCHAR lpszSlash[2]={'/',0};
1197     if(dwUrlLength==0)
1198         dwUrlLength=strlenW(lpszUrl);
1199
1200     TRACE("\n");
1201
1202     /* Determine if the URI is absolute. */
1203     while (*lpszap != '\0')
1204     {
1205         if (isalnumW(*lpszap))
1206         {
1207             lpszap++;
1208             continue;
1209         }
1210         if ((*lpszap == ':') && (lpszap - lpszUrl >= 2))
1211         {
1212             bIsAbsolute = TRUE;
1213             lpszcp = lpszap;
1214         }
1215         else
1216         {
1217             lpszcp = lpszUrl; /* Relative url */
1218         }
1219
1220         break;
1221     }
1222
1223     /* Parse <params> */
1224     lpszParam = strpbrkW(lpszap, lpszSeparators);
1225     if (lpszParam != NULL)
1226     {
1227         SetUrlComponentValueW(&lpUC->lpszExtraInfo, &lpUC->dwExtraInfoLength,
1228                                    lpszParam, dwUrlLength-(lpszParam-lpszUrl));
1229     }
1230
1231     if (bIsAbsolute) /* Parse <protocol>:[//<net_loc>] */
1232     {
1233         LPCWSTR lpszNetLoc;
1234         static const WCHAR wszAbout[]={'a','b','o','u','t',':',0};
1235
1236         /* Get scheme first. */
1237         lpUC->nScheme = GetInternetSchemeW(lpszUrl, lpszcp - lpszUrl);
1238         SetUrlComponentValueW(&lpUC->lpszScheme, &lpUC->dwSchemeLength,
1239                                    lpszUrl, lpszcp - lpszUrl);
1240
1241         /* Eat ':' in protocol. */
1242         lpszcp++;
1243
1244         /* if the scheme is "about", there is no host */
1245         if(strncmpW(wszAbout,lpszUrl, lpszcp - lpszUrl)==0)
1246         {
1247             SetUrlComponentValueW(&lpUC->lpszUserName, &lpUC->dwUserNameLength, NULL, 0);
1248             SetUrlComponentValueW(&lpUC->lpszPassword, &lpUC->dwPasswordLength, NULL, 0);
1249             SetUrlComponentValueW(&lpUC->lpszHostName, &lpUC->dwHostNameLength, NULL, 0);
1250             lpUC->nPort = 0;
1251         }
1252         else
1253         {
1254             /* Skip over slashes. */
1255             if (*lpszcp == '/')
1256             {
1257                 lpszcp++;
1258                 if (*lpszcp == '/')
1259                 {
1260                     lpszcp++;
1261                     if (*lpszcp == '/')
1262                         lpszcp++;
1263                 }
1264             }
1265
1266             lpszNetLoc = strpbrkW(lpszcp, lpszSlash);
1267             if (lpszParam)
1268             {
1269                 if (lpszNetLoc)
1270                     lpszNetLoc = min(lpszNetLoc, lpszParam);
1271                 else
1272                     lpszNetLoc = lpszParam;
1273             }
1274             else if (!lpszNetLoc)
1275                 lpszNetLoc = lpszcp + dwUrlLength-(lpszcp-lpszUrl);
1276
1277             /* Parse net-loc */
1278             if (lpszNetLoc)
1279             {
1280                 LPCWSTR lpszHost;
1281                 LPCWSTR lpszPort;
1282
1283                 /* [<user>[<:password>]@]<host>[:<port>] */
1284                 /* First find the user and password if they exist */
1285
1286                 lpszHost = strchrW(lpszcp, '@');
1287                 if (lpszHost == NULL || lpszHost > lpszNetLoc)
1288                 {
1289                     /* username and password not specified. */
1290                     SetUrlComponentValueW(&lpUC->lpszUserName, &lpUC->dwUserNameLength, NULL, 0);
1291                     SetUrlComponentValueW(&lpUC->lpszPassword, &lpUC->dwPasswordLength, NULL, 0);
1292                 }
1293                 else /* Parse out username and password */
1294                 {
1295                     LPCWSTR lpszUser = lpszcp;
1296                     LPCWSTR lpszPasswd = lpszHost;
1297
1298                     while (lpszcp < lpszHost)
1299                     {
1300                         if (*lpszcp == ':')
1301                             lpszPasswd = lpszcp;
1302
1303                         lpszcp++;
1304                     }
1305
1306                     SetUrlComponentValueW(&lpUC->lpszUserName, &lpUC->dwUserNameLength,
1307                                           lpszUser, lpszPasswd - lpszUser);
1308
1309                     if (lpszPasswd != lpszHost)
1310                         lpszPasswd++;
1311                     SetUrlComponentValueW(&lpUC->lpszPassword, &lpUC->dwPasswordLength,
1312                                           lpszPasswd == lpszHost ? NULL : lpszPasswd,
1313                                           lpszHost - lpszPasswd);
1314
1315                     lpszcp++; /* Advance to beginning of host */
1316                 }
1317
1318                 /* Parse <host><:port> */
1319
1320                 lpszHost = lpszcp;
1321                 lpszPort = lpszNetLoc;
1322
1323                 /* special case for res:// URLs: there is no port here, so the host is the
1324                    entire string up to the first '/' */
1325                 if(lpUC->nScheme==INTERNET_SCHEME_RES)
1326                 {
1327                     SetUrlComponentValueW(&lpUC->lpszHostName, &lpUC->dwHostNameLength,
1328                                           lpszHost, lpszPort - lpszHost);
1329                     lpUC->nPort = 0;
1330                     lpszcp=lpszNetLoc;
1331                 }
1332                 else
1333                 {
1334                     while (lpszcp < lpszNetLoc)
1335                     {
1336                         if (*lpszcp == ':')
1337                             lpszPort = lpszcp;
1338
1339                         lpszcp++;
1340                     }
1341
1342                     /* If the scheme is "file" and the host is just one letter, it's not a host */
1343                     if(lpUC->nScheme==INTERNET_SCHEME_FILE && (lpszPort-lpszHost)==1)
1344                     {
1345                         lpszcp=lpszHost;
1346                         SetUrlComponentValueW(&lpUC->lpszHostName, &lpUC->dwHostNameLength,
1347                                               NULL, 0);
1348                         lpUC->nPort = 0;
1349                     }
1350                     else
1351                     {
1352                         SetUrlComponentValueW(&lpUC->lpszHostName, &lpUC->dwHostNameLength,
1353                                               lpszHost, lpszPort - lpszHost);
1354                         if (lpszPort != lpszNetLoc)
1355                             lpUC->nPort = atoiW(++lpszPort);
1356                         else
1357                             lpUC->nPort = 0;
1358                     }
1359                 }
1360             }
1361         }
1362     }
1363
1364     /* Here lpszcp points to:
1365      *
1366      * <protocol>:[//<net_loc>][/path][;<params>][?<query>][#<fragment>]
1367      *                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1368      */
1369     if (lpszcp != 0 && *lpszcp != '\0' && (!lpszParam || lpszcp < lpszParam))
1370     {
1371         INT len;
1372
1373         /* Only truncate the parameter list if it's already been saved
1374          * in lpUC->lpszExtraInfo.
1375          */
1376         if (lpszParam && lpUC->dwExtraInfoLength && lpUC->lpszExtraInfo)
1377             len = lpszParam - lpszcp;
1378         else
1379         {
1380             /* Leave the parameter list in lpszUrlPath.  Strip off any trailing
1381              * newlines if necessary.
1382              */
1383             LPWSTR lpsznewline = strchrW(lpszcp, '\n');
1384             if (lpsznewline != NULL)
1385                 len = lpsznewline - lpszcp;
1386             else
1387                 len = dwUrlLength-(lpszcp-lpszUrl);
1388         }
1389
1390         SetUrlComponentValueW(&lpUC->lpszUrlPath, &lpUC->dwUrlPathLength,
1391                                    lpszcp, len);
1392     }
1393     else
1394     {
1395         lpUC->dwUrlPathLength = 0;
1396     }
1397
1398     TRACE("%s: host(%s) path(%s) extra(%s)\n", debugstr_wn(lpszUrl,dwUrlLength),
1399              debugstr_wn(lpUC->lpszHostName,lpUC->dwHostNameLength),
1400              debugstr_wn(lpUC->lpszUrlPath,lpUC->dwUrlPathLength),
1401              debugstr_wn(lpUC->lpszExtraInfo,lpUC->dwExtraInfoLength));
1402
1403     return TRUE;
1404 }
1405
1406 /***********************************************************************
1407  *           InternetAttemptConnect (WININET.@)
1408  *
1409  * Attempt to make a connection to the internet
1410  *
1411  * RETURNS
1412  *    ERROR_SUCCESS on success
1413  *    Error value   on failure
1414  *
1415  */
1416 DWORD WINAPI InternetAttemptConnect(DWORD dwReserved)
1417 {
1418     FIXME("Stub\n");
1419     return ERROR_SUCCESS;
1420 }
1421
1422
1423 /***********************************************************************
1424  *           InternetCanonicalizeUrlA (WININET.@)
1425  *
1426  * Escape unsafe characters and spaces
1427  *
1428  * RETURNS
1429  *    TRUE on success
1430  *    FALSE on failure
1431  *
1432  */
1433 BOOL WINAPI InternetCanonicalizeUrlA(LPCSTR lpszUrl, LPSTR lpszBuffer,
1434         LPDWORD lpdwBufferLength, DWORD dwFlags)
1435 {
1436     HRESULT hr;
1437     TRACE("%s %p %p %08lx\n",debugstr_a(lpszUrl), lpszBuffer,
1438           lpdwBufferLength, dwFlags);
1439
1440     /* Flip this bit to correspond to URL_ESCAPE_UNSAFE */
1441     dwFlags ^= ICU_NO_ENCODE;
1442
1443     dwFlags |= 0x80000000; /* Don't know what this means */
1444
1445     hr = UrlCanonicalizeA(lpszUrl, lpszBuffer, lpdwBufferLength, dwFlags);
1446
1447     return (hr == S_OK) ? TRUE : FALSE;
1448 }
1449
1450 /***********************************************************************
1451  *           InternetCanonicalizeUrlW (WININET.@)
1452  *
1453  * Escape unsafe characters and spaces
1454  *
1455  * RETURNS
1456  *    TRUE on success
1457  *    FALSE on failure
1458  *
1459  */
1460 BOOL WINAPI InternetCanonicalizeUrlW(LPCWSTR lpszUrl, LPWSTR lpszBuffer,
1461     LPDWORD lpdwBufferLength, DWORD dwFlags)
1462 {
1463     HRESULT hr;
1464     TRACE("%s %p %p %08lx\n", debugstr_w(lpszUrl), lpszBuffer,
1465         lpdwBufferLength, dwFlags);
1466
1467     /* Flip this bit to correspond to URL_ESCAPE_UNSAFE */
1468     dwFlags ^= ICU_NO_ENCODE;
1469
1470     dwFlags |= 0x80000000; /* Don't know what this means */
1471
1472     hr = UrlCanonicalizeW(lpszUrl, lpszBuffer, lpdwBufferLength, dwFlags);
1473
1474     return (hr == S_OK) ? TRUE : FALSE;
1475 }
1476
1477
1478 /***********************************************************************
1479  *           InternetSetStatusCallbackA (WININET.@)
1480  *
1481  * Sets up a callback function which is called as progress is made
1482  * during an operation.
1483  *
1484  * RETURNS
1485  *    Previous callback or NULL         on success
1486  *    INTERNET_INVALID_STATUS_CALLBACK  on failure
1487  *
1488  */
1489 INTERNET_STATUS_CALLBACK WINAPI InternetSetStatusCallbackA(
1490         HINTERNET hInternet ,INTERNET_STATUS_CALLBACK lpfnIntCB)
1491 {
1492     INTERNET_STATUS_CALLBACK retVal = INTERNET_INVALID_STATUS_CALLBACK;
1493     LPWININETAPPINFOW lpwai;
1494
1495     TRACE("0x%08lx\n", (ULONG)hInternet);
1496     
1497     lpwai = (LPWININETAPPINFOW)WININET_GetObject(hInternet);
1498     if (!lpwai)
1499         return retVal;
1500
1501     if (lpwai->hdr.htype == WH_HINIT)
1502     {
1503         lpwai->hdr.dwInternalFlags &= ~INET_CALLBACKW;
1504         retVal = lpwai->lpfnStatusCB;
1505         lpwai->lpfnStatusCB = lpfnIntCB;
1506     }
1507     WININET_Release( &lpwai->hdr );
1508
1509     return retVal;
1510 }
1511
1512 /***********************************************************************
1513  *           InternetSetStatusCallbackW (WININET.@)
1514  *
1515  * Sets up a callback function which is called as progress is made
1516  * during an operation.
1517  *
1518  * RETURNS
1519  *    Previous callback or NULL         on success
1520  *    INTERNET_INVALID_STATUS_CALLBACK  on failure
1521  *
1522  */
1523 INTERNET_STATUS_CALLBACK WINAPI InternetSetStatusCallbackW(
1524         HINTERNET hInternet ,INTERNET_STATUS_CALLBACK lpfnIntCB)
1525 {
1526     INTERNET_STATUS_CALLBACK retVal = INTERNET_INVALID_STATUS_CALLBACK;
1527     LPWININETAPPINFOW lpwai;
1528
1529     TRACE("0x%08lx\n", (ULONG)hInternet);
1530     
1531     lpwai = (LPWININETAPPINFOW)WININET_GetObject(hInternet);
1532     if (!lpwai)
1533         return retVal;
1534
1535     if (lpwai->hdr.htype == WH_HINIT)
1536     {
1537         lpwai->hdr.dwInternalFlags |= INET_CALLBACKW;
1538         retVal = lpwai->lpfnStatusCB;
1539         lpwai->lpfnStatusCB = lpfnIntCB;
1540     }
1541
1542     WININET_Release( &lpwai->hdr );
1543
1544     return retVal;
1545 }
1546
1547 /***********************************************************************
1548  *           InternetSetFilePointer (WININET.@)
1549  */
1550 DWORD WINAPI InternetSetFilePointer(HINTERNET f1, LONG f2, PVOID f3, DWORD f4, DWORD f5)
1551 {
1552     FIXME("stub\n");
1553     return FALSE;
1554 }
1555
1556 /***********************************************************************
1557  *           InternetWriteFile (WININET.@)
1558  *
1559  * Write data to an open internet file
1560  *
1561  * RETURNS
1562  *    TRUE  on success
1563  *    FALSE on failure
1564  *
1565  */
1566 BOOL WINAPI InternetWriteFile(HINTERNET hFile, LPCVOID lpBuffer ,
1567         DWORD dwNumOfBytesToWrite, LPDWORD lpdwNumOfBytesWritten)
1568 {
1569     BOOL retval = FALSE;
1570     int nSocket = -1;
1571     LPWININETHANDLEHEADER lpwh;
1572
1573     TRACE("\n");
1574     lpwh = (LPWININETHANDLEHEADER) WININET_GetObject( hFile );
1575     if (NULL == lpwh)
1576         return FALSE;
1577
1578     switch (lpwh->htype)
1579     {
1580         case WH_HHTTPREQ:
1581             FIXME("This shouldn't be here! We don't support this kind"
1582                   " of connection anymore. Must use NETCON functions,"
1583                   " especially if using SSL\n");
1584             nSocket = ((LPWININETHTTPREQW)lpwh)->netConnection.socketFD;
1585             break;
1586
1587         case WH_HFILE:
1588             nSocket = ((LPWININETFILE)lpwh)->nDataSocket;
1589             break;
1590
1591         default:
1592             break;
1593     }
1594
1595     if (nSocket != -1)
1596     {
1597         int res = send(nSocket, lpBuffer, dwNumOfBytesToWrite, 0);
1598         retval = (res >= 0);
1599         *lpdwNumOfBytesWritten = retval ? res : 0;
1600     }
1601     WININET_Release( lpwh );
1602
1603     return retval;
1604 }
1605
1606
1607 /***********************************************************************
1608  *           InternetReadFile (WININET.@)
1609  *
1610  * Read data from an open internet file
1611  *
1612  * RETURNS
1613  *    TRUE  on success
1614  *    FALSE on failure
1615  *
1616  */
1617 BOOL WINAPI InternetReadFile(HINTERNET hFile, LPVOID lpBuffer,
1618         DWORD dwNumOfBytesToRead, LPDWORD dwNumOfBytesRead)
1619 {
1620     BOOL retval = FALSE;
1621     int nSocket = -1;
1622     LPWININETHANDLEHEADER lpwh;
1623
1624     TRACE("%p %p %ld %p\n", hFile, lpBuffer, dwNumOfBytesToRead, dwNumOfBytesRead);
1625
1626     lpwh = (LPWININETHANDLEHEADER) WININET_GetObject( hFile );
1627     if (NULL == lpwh)
1628         return FALSE;
1629
1630     /* FIXME: this should use NETCON functions! */
1631     switch (lpwh->htype)
1632     {
1633         case WH_HHTTPREQ:
1634             if (!NETCON_recv(&((LPWININETHTTPREQW)lpwh)->netConnection, lpBuffer,
1635                              dwNumOfBytesToRead, 0, (int *)dwNumOfBytesRead))
1636             {
1637                 *dwNumOfBytesRead = 0;
1638                 retval = TRUE; /* Under windows, it seems to return 0 even if nothing was read... */
1639             }
1640             else
1641                 retval = TRUE;
1642             break;
1643
1644         case WH_HFILE:
1645             /* FIXME: FTP should use NETCON_ stuff */
1646             nSocket = ((LPWININETFILE)lpwh)->nDataSocket;
1647             if (nSocket != -1)
1648             {
1649                 int res = recv(nSocket, lpBuffer, dwNumOfBytesToRead, 0);
1650                 retval = (res >= 0);
1651                 *dwNumOfBytesRead = retval ? res : 0;
1652             }
1653             break;
1654
1655         default:
1656             break;
1657     }
1658     WININET_Release( lpwh );
1659
1660     return retval;
1661 }
1662
1663 /***********************************************************************
1664  *           InternetReadFileExA (WININET.@)
1665  *
1666  * Read data from an open internet file
1667  *
1668  * RETURNS
1669  *    TRUE  on success
1670  *    FALSE on failure
1671  *
1672  */
1673 BOOL WINAPI InternetReadFileExA(HINTERNET hFile, LPINTERNET_BUFFERSA lpBuffer,
1674         DWORD dwFlags, DWORD dwContext)
1675 {
1676   FIXME("stub\n");
1677   return FALSE;
1678 }
1679
1680 /***********************************************************************
1681  *           InternetReadFileExW (WININET.@)
1682  *
1683  * Read data from an open internet file
1684  *
1685  * RETURNS
1686  *    TRUE  on success
1687  *    FALSE on failure
1688  *
1689  */
1690 BOOL WINAPI InternetReadFileExW(HINTERNET hFile, LPINTERNET_BUFFERSW lpBuffer,
1691         DWORD dwFlags, DWORD dwContext)
1692 {
1693   FIXME("stub\n");
1694
1695   INTERNET_SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1696   return FALSE;
1697 }
1698
1699 /***********************************************************************
1700  *           INET_QueryOptionHelper (internal)
1701  */
1702 static BOOL INET_QueryOptionHelper(BOOL bIsUnicode, HINTERNET hInternet, DWORD dwOption,
1703                                    LPVOID lpBuffer, LPDWORD lpdwBufferLength)
1704 {
1705     LPWININETHANDLEHEADER lpwhh;
1706     BOOL bSuccess = FALSE;
1707
1708     TRACE("(%p, 0x%08lx, %p, %p)\n", hInternet, dwOption, lpBuffer, lpdwBufferLength);
1709
1710     lpwhh = (LPWININETHANDLEHEADER) WININET_GetObject( hInternet );
1711
1712     switch (dwOption)
1713     {
1714         case INTERNET_OPTION_HANDLE_TYPE:
1715         {
1716             ULONG type;
1717
1718             if (!lpwhh)
1719             {
1720                 WARN("Invalid hInternet handle\n");
1721                 SetLastError(ERROR_INVALID_HANDLE);
1722                 return FALSE;
1723             }
1724
1725             type = lpwhh->htype;
1726
1727             TRACE("INTERNET_OPTION_HANDLE_TYPE: %ld\n", type);
1728
1729             if (*lpdwBufferLength < sizeof(ULONG))
1730                 INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
1731             else
1732             {
1733                 memcpy(lpBuffer, &type, sizeof(ULONG));
1734                     *lpdwBufferLength = sizeof(ULONG);
1735                 bSuccess = TRUE;
1736             }
1737             break;
1738         }
1739
1740         case INTERNET_OPTION_REQUEST_FLAGS:
1741         {
1742             ULONG flags = 4;
1743             TRACE("INTERNET_OPTION_REQUEST_FLAGS: %ld\n", flags);
1744             if (*lpdwBufferLength < sizeof(ULONG))
1745                 INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
1746             else
1747             {
1748                 memcpy(lpBuffer, &flags, sizeof(ULONG));
1749                     *lpdwBufferLength = sizeof(ULONG);
1750                 bSuccess = TRUE;
1751             }
1752             break;
1753         }
1754
1755         case INTERNET_OPTION_URL:
1756         case INTERNET_OPTION_DATAFILE_NAME:
1757         {
1758             if (!lpwhh)
1759             {
1760                 WARN("Invalid hInternet handle\n");
1761                 SetLastError(ERROR_INVALID_HANDLE);
1762                 return FALSE;
1763             }
1764             if (lpwhh->htype == WH_HHTTPREQ)
1765             {
1766                 LPWININETHTTPREQW lpreq = (LPWININETHTTPREQW) lpwhh;
1767                 WCHAR url[1023];
1768                 static const WCHAR szFmt[] = {'h','t','t','p',':','/','/','%','s','%','s',0};
1769
1770                 sprintfW(url,szFmt,lpreq->lpszHostName,lpreq->lpszPath);
1771                 TRACE("INTERNET_OPTION_URL: %s\n",debugstr_w(url));
1772                 if (*lpdwBufferLength < strlenW(url)+1)
1773                     INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
1774                 else
1775                 {
1776                     if(!bIsUnicode)
1777                     {
1778                         *lpdwBufferLength=WideCharToMultiByte(CP_ACP,0,url,-1,lpBuffer,*lpdwBufferLength,NULL,NULL);
1779                     }
1780                     else
1781                     {
1782                         strcpyW(lpBuffer, url);
1783                         *lpdwBufferLength = strlenW(url)+1;
1784                     }
1785                     bSuccess = TRUE;
1786                 }
1787             }
1788             break;
1789         }
1790        case INTERNET_OPTION_HTTP_VERSION:
1791        {
1792             /*
1793              * Presently hardcoded to 1.1
1794              */
1795             ((HTTP_VERSION_INFO*)lpBuffer)->dwMajorVersion = 1;
1796             ((HTTP_VERSION_INFO*)lpBuffer)->dwMinorVersion = 1;
1797             bSuccess = TRUE;
1798             break;
1799        }
1800        case INTERNET_OPTION_CONNECTED_STATE:
1801        {
1802            INTERNET_CONNECTED_INFO * pCi = (INTERNET_CONNECTED_INFO *)lpBuffer;
1803            FIXME("INTERNET_OPTION_CONNECTED_STATE: semi-stub\n");
1804            pCi->dwConnectedState = INTERNET_STATE_CONNECTED;
1805            pCi->dwFlags = 0;
1806            bSuccess = TRUE;
1807            break;
1808        }
1809        case INTERNET_OPTION_SECURITY_FLAGS:
1810          FIXME("INTERNET_OPTION_SECURITY_FLAGS: Stub\n");
1811          break;
1812
1813        default:
1814          FIXME("Stub! %ld \n",dwOption);
1815          break;
1816     }
1817     if (lpwhh)
1818         WININET_Release( lpwhh );
1819
1820     return bSuccess;
1821 }
1822
1823 /***********************************************************************
1824  *           InternetQueryOptionW (WININET.@)
1825  *
1826  * Queries an options on the specified handle
1827  *
1828  * RETURNS
1829  *    TRUE  on success
1830  *    FALSE on failure
1831  *
1832  */
1833 BOOL WINAPI InternetQueryOptionW(HINTERNET hInternet, DWORD dwOption,
1834                                  LPVOID lpBuffer, LPDWORD lpdwBufferLength)
1835 {
1836     return INET_QueryOptionHelper(TRUE, hInternet, dwOption, lpBuffer, lpdwBufferLength);
1837 }
1838
1839 /***********************************************************************
1840  *           InternetQueryOptionA (WININET.@)
1841  *
1842  * Queries an options on the specified handle
1843  *
1844  * RETURNS
1845  *    TRUE  on success
1846  *    FALSE on failure
1847  *
1848  */
1849 BOOL WINAPI InternetQueryOptionA(HINTERNET hInternet, DWORD dwOption,
1850                                  LPVOID lpBuffer, LPDWORD lpdwBufferLength)
1851 {
1852     return INET_QueryOptionHelper(FALSE, hInternet, dwOption, lpBuffer, lpdwBufferLength);
1853 }
1854
1855
1856 /***********************************************************************
1857  *           InternetSetOptionW (WININET.@)
1858  *
1859  * Sets an options on the specified handle
1860  *
1861  * RETURNS
1862  *    TRUE  on success
1863  *    FALSE on failure
1864  *
1865  */
1866 BOOL WINAPI InternetSetOptionW(HINTERNET hInternet, DWORD dwOption,
1867                            LPVOID lpBuffer, DWORD dwBufferLength)
1868 {
1869     LPWININETHANDLEHEADER lpwhh;
1870     BOOL ret = TRUE;
1871
1872     TRACE("0x%08lx\n", dwOption);
1873
1874     lpwhh = (LPWININETHANDLEHEADER) WININET_GetObject( hInternet );
1875     if( !lpwhh )
1876         return FALSE;
1877
1878     switch (dwOption)
1879     {
1880     case INTERNET_OPTION_HTTP_VERSION:
1881       {
1882         HTTP_VERSION_INFO* pVersion=(HTTP_VERSION_INFO*)lpBuffer;
1883         FIXME("Option INTERNET_OPTION_HTTP_VERSION(%ld,%ld): STUB\n",pVersion->dwMajorVersion,pVersion->dwMinorVersion);
1884       }
1885       break;
1886     case INTERNET_OPTION_ERROR_MASK:
1887       {
1888         unsigned long flags=*(unsigned long*)lpBuffer;
1889         FIXME("Option INTERNET_OPTION_ERROR_MASK(%ld): STUB\n",flags);
1890       }
1891       break;
1892     case INTERNET_OPTION_CODEPAGE:
1893       {
1894         unsigned long codepage=*(unsigned long*)lpBuffer;
1895         FIXME("Option INTERNET_OPTION_CODEPAGE (%ld): STUB\n",codepage);
1896       }
1897       break;
1898     case INTERNET_OPTION_REQUEST_PRIORITY:
1899       {
1900         unsigned long priority=*(unsigned long*)lpBuffer;
1901         FIXME("Option INTERNET_OPTION_REQUEST_PRIORITY (%ld): STUB\n",priority);
1902       }
1903       break;
1904     case INTERNET_OPTION_CONNECT_TIMEOUT:
1905       {
1906         unsigned long connecttimeout=*(unsigned long*)lpBuffer;
1907         FIXME("Option INTERNET_OPTION_CONNECT_TIMEOUT (%ld): STUB\n",connecttimeout);
1908       }
1909       break;
1910     case INTERNET_OPTION_DATA_RECEIVE_TIMEOUT:
1911       {
1912         unsigned long receivetimeout=*(unsigned long*)lpBuffer;
1913         FIXME("Option INTERNET_OPTION_DATA_RECEIVE_TIMEOUT (%ld): STUB\n",receivetimeout);
1914       }
1915       break;
1916     case INTERNET_OPTION_RESET_URLCACHE_SESSION:
1917         FIXME("Option INTERNET_OPTION_RESET_URLCACHE_SESSION: STUB\n");
1918         break;
1919     case INTERNET_OPTION_END_BROWSER_SESSION:
1920         FIXME("Option INTERNET_OPTION_END_BROWSER_SESSION: STUB\n");
1921         break;
1922     case INTERNET_OPTION_CONNECTED_STATE:
1923         FIXME("Option INTERNET_OPTION_CONNECTED_STATE: STUB\n");
1924         break;
1925     default:
1926         FIXME("Option %ld STUB\n",dwOption);
1927         INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
1928         ret = FALSE;
1929         break;
1930     }
1931     WININET_Release( lpwhh );
1932
1933     return TRUE;
1934 }
1935
1936
1937 /***********************************************************************
1938  *           InternetSetOptionA (WININET.@)
1939  *
1940  * Sets an options on the specified handle.
1941  *
1942  * RETURNS
1943  *    TRUE  on success
1944  *    FALSE on failure
1945  *
1946  */
1947 BOOL WINAPI InternetSetOptionA(HINTERNET hInternet, DWORD dwOption,
1948                            LPVOID lpBuffer, DWORD dwBufferLength)
1949 {
1950     LPVOID wbuffer;
1951     DWORD wlen;
1952     BOOL r;
1953
1954     switch( dwOption )
1955     {
1956     case INTERNET_OPTION_PROXY:
1957         {
1958         LPINTERNET_PROXY_INFOA pi = (LPINTERNET_PROXY_INFOA) lpBuffer;
1959         LPINTERNET_PROXY_INFOW piw;
1960         DWORD proxlen, prbylen;
1961         LPWSTR prox, prby;
1962
1963         proxlen = MultiByteToWideChar( CP_ACP, 0, pi->lpszProxy, -1, NULL, 0);
1964         prbylen= MultiByteToWideChar( CP_ACP, 0, pi->lpszProxyBypass, -1, NULL, 0);
1965         wlen = sizeof(*piw) + proxlen + prbylen;
1966         wbuffer = HeapAlloc( GetProcessHeap(), 0, wlen*sizeof(WCHAR) );
1967         piw = (LPINTERNET_PROXY_INFOW) wbuffer;
1968         piw->dwAccessType = pi->dwAccessType;
1969         prox = (LPWSTR) &piw[1];
1970         prby = &prox[proxlen+1];
1971         MultiByteToWideChar( CP_ACP, 0, pi->lpszProxy, -1, prox, proxlen);
1972         MultiByteToWideChar( CP_ACP, 0, pi->lpszProxyBypass, -1, prby, prbylen);
1973         piw->lpszProxy = prox;
1974         piw->lpszProxyBypass = prby;
1975         }
1976         break;
1977     case INTERNET_OPTION_USER_AGENT:
1978     case INTERNET_OPTION_USERNAME:
1979     case INTERNET_OPTION_PASSWORD:
1980         wlen = MultiByteToWideChar( CP_ACP, 0, lpBuffer, dwBufferLength,
1981                                    NULL, 0 );
1982         wbuffer = HeapAlloc( GetProcessHeap(), 0, wlen*sizeof(WCHAR) );
1983         MultiByteToWideChar( CP_ACP, 0, lpBuffer, dwBufferLength,
1984                                    wbuffer, wlen );
1985         break;
1986     default:
1987         wbuffer = lpBuffer;
1988         wlen = dwBufferLength;
1989     }
1990
1991     r = InternetSetOptionW(hInternet,dwOption, wbuffer, wlen);
1992
1993     if( lpBuffer != wbuffer )
1994         HeapFree( GetProcessHeap(), 0, wbuffer );
1995
1996     return r;
1997 }
1998
1999
2000 /***********************************************************************
2001  *           InternetSetOptionExA (WININET.@)
2002  */
2003 BOOL WINAPI InternetSetOptionExA(HINTERNET hInternet, DWORD dwOption,
2004                            LPVOID lpBuffer, DWORD dwBufferLength, DWORD dwFlags)
2005 {
2006     FIXME("Flags %08lx ignored\n", dwFlags);
2007     return InternetSetOptionA( hInternet, dwOption, lpBuffer, dwBufferLength );
2008 }
2009
2010 /***********************************************************************
2011  *           InternetSetOptionExW (WININET.@)
2012  */
2013 BOOL WINAPI InternetSetOptionExW(HINTERNET hInternet, DWORD dwOption,
2014                            LPVOID lpBuffer, DWORD dwBufferLength, DWORD dwFlags)
2015 {
2016     FIXME("Flags %08lx ignored\n", dwFlags);
2017     if( dwFlags & ~ISO_VALID_FLAGS )
2018     {
2019         SetLastError( ERROR_INVALID_PARAMETER );
2020         return FALSE;
2021     }
2022     return InternetSetOptionW( hInternet, dwOption, lpBuffer, dwBufferLength );
2023 }
2024
2025
2026 /***********************************************************************
2027  *      InternetCheckConnectionA (WININET.@)
2028  *
2029  * Pings a requested host to check internet connection
2030  *
2031  * RETURNS
2032  *   TRUE on success and FALSE on failure. If a failure then
2033  *   ERROR_NOT_CONNECTED is placesd into GetLastError
2034  *
2035  */
2036 BOOL WINAPI InternetCheckConnectionA( LPCSTR lpszUrl, DWORD dwFlags, DWORD dwReserved )
2037 {
2038 /*
2039  * this is a kludge which runs the resident ping program and reads the output.
2040  *
2041  * Anyone have a better idea?
2042  */
2043
2044   BOOL   rc = FALSE;
2045   char command[1024];
2046   char host[1024];
2047   int status = -1;
2048
2049   FIXME("\n");
2050
2051   /*
2052    * Crack or set the Address
2053    */
2054   if (lpszUrl == NULL)
2055   {
2056      /*
2057       * According to the doc we are supost to use the ip for the next
2058       * server in the WnInet internal server database. I have
2059       * no idea what that is or how to get it.
2060       *
2061       * So someone needs to implement this.
2062       */
2063      FIXME("Unimplemented with URL of NULL\n");
2064      return TRUE;
2065   }
2066   else
2067   {
2068      URL_COMPONENTSA componets;
2069
2070      ZeroMemory(&componets,sizeof(URL_COMPONENTSA));
2071      componets.lpszHostName = (LPSTR)&host;
2072      componets.dwHostNameLength = 1024;
2073
2074      if (!InternetCrackUrlA(lpszUrl,0,0,&componets))
2075        goto End;
2076
2077      TRACE("host name : %s\n",componets.lpszHostName);
2078   }
2079
2080   /*
2081    * Build our ping command
2082    */
2083   strcpy(command,"ping -w 1 ");
2084   strcat(command,host);
2085   strcat(command," >/dev/null 2>/dev/null");
2086
2087   TRACE("Ping command is : %s\n",command);
2088
2089   status = system(command);
2090
2091   TRACE("Ping returned a code of %i \n",status);
2092
2093   /* Ping return code of 0 indicates success */
2094   if (status == 0)
2095      rc = TRUE;
2096
2097 End:
2098
2099   if (rc == FALSE)
2100     SetLastError(ERROR_NOT_CONNECTED);
2101
2102   return rc;
2103 }
2104
2105
2106 /***********************************************************************
2107  *      InternetCheckConnectionW (WININET.@)
2108  *
2109  * Pings a requested host to check internet connection
2110  *
2111  * RETURNS
2112  *   TRUE on success and FALSE on failure. If a failure then
2113  *   ERROR_NOT_CONNECTED is placed into GetLastError
2114  *
2115  */
2116 BOOL WINAPI InternetCheckConnectionW(LPCWSTR lpszUrl, DWORD dwFlags, DWORD dwReserved)
2117 {
2118     CHAR *szUrl;
2119     INT len;
2120     BOOL rc;
2121
2122     len = WideCharToMultiByte(CP_ACP, 0, lpszUrl, -1, NULL, 0, NULL, NULL);
2123     if (!(szUrl = (CHAR *)HeapAlloc(GetProcessHeap(), 0, len*sizeof(CHAR))))
2124         return FALSE;
2125     WideCharToMultiByte(CP_ACP, 0, lpszUrl, -1, szUrl, len, NULL, NULL);
2126     rc = InternetCheckConnectionA((LPCSTR)szUrl, dwFlags, dwReserved);
2127     HeapFree(GetProcessHeap(), 0, szUrl);
2128     
2129     return rc;
2130 }
2131
2132
2133 /**********************************************************
2134  *      INTERNET_InternetOpenUrlW (internal)
2135  *
2136  * Opens an URL
2137  *
2138  * RETURNS
2139  *   handle of connection or NULL on failure
2140  */
2141 HINTERNET WINAPI INTERNET_InternetOpenUrlW(LPWININETAPPINFOW hIC, LPCWSTR lpszUrl,
2142     LPCWSTR lpszHeaders, DWORD dwHeadersLength, DWORD dwFlags, DWORD dwContext)
2143 {
2144     URL_COMPONENTSW urlComponents;
2145     WCHAR protocol[32], hostName[MAXHOSTNAME], userName[1024];
2146     WCHAR password[1024], path[2048], extra[1024];
2147     HINTERNET client = NULL, client1 = NULL;
2148     
2149     TRACE("(%p, %s, %s, %08lx, %08lx, %08lx\n", hIC, debugstr_w(lpszUrl), debugstr_w(lpszHeaders),
2150           dwHeadersLength, dwFlags, dwContext);
2151     
2152     urlComponents.dwStructSize = sizeof(URL_COMPONENTSW);
2153     urlComponents.lpszScheme = protocol;
2154     urlComponents.dwSchemeLength = 32;
2155     urlComponents.lpszHostName = hostName;
2156     urlComponents.dwHostNameLength = MAXHOSTNAME;
2157     urlComponents.lpszUserName = userName;
2158     urlComponents.dwUserNameLength = 1024;
2159     urlComponents.lpszPassword = password;
2160     urlComponents.dwPasswordLength = 1024;
2161     urlComponents.lpszUrlPath = path;
2162     urlComponents.dwUrlPathLength = 2048;
2163     urlComponents.lpszExtraInfo = extra;
2164     urlComponents.dwExtraInfoLength = 1024;
2165     if(!InternetCrackUrlW(lpszUrl, strlenW(lpszUrl), 0, &urlComponents))
2166         return NULL;
2167     switch(urlComponents.nScheme) {
2168     case INTERNET_SCHEME_FTP:
2169         if(urlComponents.nPort == 0)
2170             urlComponents.nPort = INTERNET_DEFAULT_FTP_PORT;
2171         client = FTP_Connect(hIC, hostName, urlComponents.nPort,
2172                              userName, password, dwFlags, dwContext, INET_OPENURL);
2173         if(client == NULL)
2174             break;
2175         client1 = FtpOpenFileW(client, path, GENERIC_READ, dwFlags, dwContext);
2176         if(client1 == NULL) {
2177             InternetCloseHandle(client);
2178             break;
2179         }
2180         break;
2181         
2182     case INTERNET_SCHEME_HTTP:
2183     case INTERNET_SCHEME_HTTPS: {
2184         static const WCHAR szStars[] = { '*','/','*', 0 };
2185         LPCWSTR accept[2] = { szStars, NULL };
2186         if(urlComponents.nPort == 0) {
2187             if(urlComponents.nScheme == INTERNET_SCHEME_HTTP)
2188                 urlComponents.nPort = INTERNET_DEFAULT_HTTP_PORT;
2189             else
2190                 urlComponents.nPort = INTERNET_DEFAULT_HTTPS_PORT;
2191         }
2192         /* FIXME: should use pointers, not handles, as handles are not thread-safe */
2193         client = HTTP_Connect(hIC, hostName, urlComponents.nPort,
2194                               userName, password, dwFlags, dwContext, INET_OPENURL);
2195         if(client == NULL)
2196             break;
2197         client1 = HttpOpenRequestW(client, NULL, path, NULL, NULL, accept, dwFlags, dwContext);
2198         if(client1 == NULL) {
2199             InternetCloseHandle(client);
2200             break;
2201         }
2202         HttpAddRequestHeadersW(client1, lpszHeaders, dwHeadersLength, HTTP_ADDREQ_FLAG_ADD);
2203         if (!HttpSendRequestW(client1, NULL, 0, NULL, 0)) {
2204             InternetCloseHandle(client1);
2205             client1 = NULL;
2206             break;
2207         }
2208     }
2209     case INTERNET_SCHEME_GOPHER:
2210         /* gopher doesn't seem to be implemented in wine, but it's supposed
2211          * to be supported by InternetOpenUrlA. */
2212     default:
2213         break;
2214     }
2215
2216     TRACE(" %p <--\n", client1);
2217     
2218     return client1;
2219 }
2220
2221 /**********************************************************
2222  *      InternetOpenUrlW (WININET.@)
2223  *
2224  * Opens an URL
2225  *
2226  * RETURNS
2227  *   handle of connection or NULL on failure
2228  */
2229 HINTERNET WINAPI InternetOpenUrlW(HINTERNET hInternet, LPCWSTR lpszUrl,
2230     LPCWSTR lpszHeaders, DWORD dwHeadersLength, DWORD dwFlags, DWORD dwContext)
2231 {
2232     HINTERNET ret = NULL;
2233     LPWININETAPPINFOW hIC = NULL;
2234
2235     TRACE("(%p, %s, %s, %08lx, %08lx, %08lx\n", hInternet, debugstr_w(lpszUrl), debugstr_w(lpszHeaders),
2236           dwHeadersLength, dwFlags, dwContext);
2237  
2238     hIC = (LPWININETAPPINFOW) WININET_GetObject( hInternet );
2239     if (NULL == hIC ||  hIC->hdr.htype != WH_HINIT) {
2240         INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
2241         goto lend;
2242     }
2243     
2244     if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC) {
2245         WORKREQUEST workRequest;
2246         struct WORKREQ_INTERNETOPENURLW *req;
2247         
2248         workRequest.asyncall = INTERNETOPENURLW;
2249         workRequest.hdr = WININET_AddRef( &hIC->hdr );
2250         req = &workRequest.u.InternetOpenUrlW;
2251         if (lpszUrl)
2252             req->lpszUrl = WININET_strdupW(lpszUrl);
2253         else
2254             req->lpszUrl = 0;
2255         if (lpszHeaders)
2256             req->lpszHeaders = WININET_strdupW(lpszHeaders);
2257         else
2258             req->lpszHeaders = 0;
2259         req->dwHeadersLength = dwHeadersLength;
2260         req->dwFlags = dwFlags;
2261         req->dwContext = dwContext;
2262         
2263         INTERNET_AsyncCall(&workRequest);
2264         /*
2265          * This is from windows.
2266          */
2267         SetLastError(ERROR_IO_PENDING);
2268     } else {
2269         ret = INTERNET_InternetOpenUrlW(hIC, lpszUrl, lpszHeaders, dwHeadersLength, dwFlags, dwContext);
2270     }
2271     
2272   lend:
2273     if( hIC )
2274         WININET_Release( &hIC->hdr );
2275     TRACE(" %p <--\n", ret);
2276     
2277     return ret;
2278 }
2279
2280 /**********************************************************
2281  *      InternetOpenUrlA (WININET.@)
2282  *
2283  * Opens an URL
2284  *
2285  * RETURNS
2286  *   handle of connection or NULL on failure
2287  */
2288 HINTERNET WINAPI InternetOpenUrlA(HINTERNET hInternet, LPCSTR lpszUrl,
2289     LPCSTR lpszHeaders, DWORD dwHeadersLength, DWORD dwFlags, DWORD dwContext)
2290 {
2291     HINTERNET rc = (HINTERNET)NULL;
2292
2293     INT lenUrl;
2294     INT lenHeaders = 0;
2295     LPWSTR szUrl = NULL;
2296     LPWSTR szHeaders = NULL;
2297
2298     TRACE("\n");
2299
2300     if(lpszUrl) {
2301         lenUrl = MultiByteToWideChar(CP_ACP, 0, lpszUrl, -1, NULL, 0 );
2302         szUrl = HeapAlloc(GetProcessHeap(), 0, lenUrl*sizeof(WCHAR));
2303         if(!szUrl)
2304             return (HINTERNET)NULL;
2305         MultiByteToWideChar(CP_ACP, 0, lpszUrl, -1, szUrl, lenUrl);
2306     }
2307     
2308     if(lpszHeaders) {
2309         lenHeaders = MultiByteToWideChar(CP_ACP, 0, lpszHeaders, dwHeadersLength, NULL, 0 );
2310         szHeaders = HeapAlloc(GetProcessHeap(), 0, lenHeaders*sizeof(WCHAR));
2311         if(!szHeaders) {
2312             if(szUrl) HeapFree(GetProcessHeap(), 0, szUrl);
2313             return (HINTERNET)NULL;
2314         }
2315         MultiByteToWideChar(CP_ACP, 0, lpszHeaders, dwHeadersLength, szHeaders, lenHeaders);
2316     }
2317     
2318     rc = InternetOpenUrlW(hInternet, szUrl, szHeaders,
2319         lenHeaders, dwFlags, dwContext);
2320
2321     if(szUrl) HeapFree(GetProcessHeap(), 0, szUrl);
2322     if(szHeaders) HeapFree(GetProcessHeap(), 0, szHeaders);
2323
2324     return rc;
2325 }
2326
2327
2328 /***********************************************************************
2329  *           INTERNET_SetLastError (internal)
2330  *
2331  * Set last thread specific error
2332  *
2333  * RETURNS
2334  *
2335  */
2336 void INTERNET_SetLastError(DWORD dwError)
2337 {
2338     LPWITHREADERROR lpwite = (LPWITHREADERROR)TlsGetValue(g_dwTlsErrIndex);
2339
2340     SetLastError(dwError);
2341     if(lpwite)
2342         lpwite->dwError = dwError;
2343 }
2344
2345
2346 /***********************************************************************
2347  *           INTERNET_GetLastError (internal)
2348  *
2349  * Get last thread specific error
2350  *
2351  * RETURNS
2352  *
2353  */
2354 DWORD INTERNET_GetLastError()
2355 {
2356     LPWITHREADERROR lpwite = (LPWITHREADERROR)TlsGetValue(g_dwTlsErrIndex);
2357     return lpwite->dwError;
2358 }
2359
2360
2361 /***********************************************************************
2362  *           INTERNET_WorkerThreadFunc (internal)
2363  *
2364  * Worker thread execution function
2365  *
2366  * RETURNS
2367  *
2368  */
2369 DWORD INTERNET_WorkerThreadFunc(LPVOID *lpvParam)
2370 {
2371     DWORD dwWaitRes;
2372
2373     while (1)
2374     {
2375         if(dwNumJobs > 0) {
2376             INTERNET_ExecuteWork();
2377             continue;
2378         }
2379         dwWaitRes = WaitForMultipleObjects(2, hEventArray, FALSE, MAX_IDLE_WORKER);
2380
2381         if (dwWaitRes == WAIT_OBJECT_0 + 1)
2382             INTERNET_ExecuteWork();
2383         else
2384             break;
2385
2386         InterlockedIncrement(&dwNumIdleThreads);
2387     }
2388
2389     InterlockedDecrement(&dwNumIdleThreads);
2390     InterlockedDecrement(&dwNumThreads);
2391     TRACE("Worker thread exiting\n");
2392     return TRUE;
2393 }
2394
2395
2396 /***********************************************************************
2397  *           INTERNET_InsertWorkRequest (internal)
2398  *
2399  * Insert work request into queue
2400  *
2401  * RETURNS
2402  *
2403  */
2404 BOOL INTERNET_InsertWorkRequest(LPWORKREQUEST lpWorkRequest)
2405 {
2406     BOOL bSuccess = FALSE;
2407     LPWORKREQUEST lpNewRequest;
2408
2409     TRACE("\n");
2410
2411     lpNewRequest = HeapAlloc(GetProcessHeap(), 0, sizeof(WORKREQUEST));
2412     if (lpNewRequest)
2413     {
2414         memcpy(lpNewRequest, lpWorkRequest, sizeof(WORKREQUEST));
2415         lpNewRequest->prev = NULL;
2416
2417         EnterCriticalSection(&csQueue);
2418
2419         lpNewRequest->next = lpWorkQueueTail;
2420         if (lpWorkQueueTail)
2421             lpWorkQueueTail->prev = lpNewRequest;
2422         lpWorkQueueTail = lpNewRequest;
2423         if (!lpHeadWorkQueue)
2424             lpHeadWorkQueue = lpWorkQueueTail;
2425
2426         LeaveCriticalSection(&csQueue);
2427
2428         bSuccess = TRUE;
2429         InterlockedIncrement(&dwNumJobs);
2430     }
2431
2432     return bSuccess;
2433 }
2434
2435
2436 /***********************************************************************
2437  *           INTERNET_GetWorkRequest (internal)
2438  *
2439  * Retrieves work request from queue
2440  *
2441  * RETURNS
2442  *
2443  */
2444 BOOL INTERNET_GetWorkRequest(LPWORKREQUEST lpWorkRequest)
2445 {
2446     BOOL bSuccess = FALSE;
2447     LPWORKREQUEST lpRequest = NULL;
2448
2449     TRACE("\n");
2450
2451     EnterCriticalSection(&csQueue);
2452
2453     if (lpHeadWorkQueue)
2454     {
2455         lpRequest = lpHeadWorkQueue;
2456         lpHeadWorkQueue = lpHeadWorkQueue->prev;
2457         if (lpRequest == lpWorkQueueTail)
2458             lpWorkQueueTail = lpHeadWorkQueue;
2459     }
2460
2461     LeaveCriticalSection(&csQueue);
2462
2463     if (lpRequest)
2464     {
2465         memcpy(lpWorkRequest, lpRequest, sizeof(WORKREQUEST));
2466         HeapFree(GetProcessHeap(), 0, lpRequest);
2467         bSuccess = TRUE;
2468         InterlockedDecrement(&dwNumJobs);
2469     }
2470
2471     return bSuccess;
2472 }
2473
2474
2475 /***********************************************************************
2476  *           INTERNET_AsyncCall (internal)
2477  *
2478  * Retrieves work request from queue
2479  *
2480  * RETURNS
2481  *
2482  */
2483 BOOL INTERNET_AsyncCall(LPWORKREQUEST lpWorkRequest)
2484 {
2485     HANDLE hThread;
2486     DWORD dwTID;
2487     BOOL bSuccess = FALSE;
2488
2489     TRACE("\n");
2490
2491     if (InterlockedDecrement(&dwNumIdleThreads) < 0)
2492     {
2493         InterlockedIncrement(&dwNumIdleThreads);
2494
2495         if (InterlockedIncrement(&dwNumThreads) > MAX_WORKER_THREADS ||
2496             !(hThread = CreateThread(NULL, 0,
2497             (LPTHREAD_START_ROUTINE)INTERNET_WorkerThreadFunc, NULL, 0, &dwTID)))
2498         {
2499             InterlockedDecrement(&dwNumThreads);
2500             INTERNET_SetLastError(ERROR_INTERNET_ASYNC_THREAD_FAILED);
2501             goto lerror;
2502         }
2503
2504         TRACE("Created new thread\n");
2505     }
2506
2507     bSuccess = TRUE;
2508     INTERNET_InsertWorkRequest(lpWorkRequest);
2509     SetEvent(hWorkEvent);
2510
2511 lerror:
2512
2513     return bSuccess;
2514 }
2515
2516
2517 /***********************************************************************
2518  *           INTERNET_ExecuteWork (internal)
2519  *
2520  * RETURNS
2521  *
2522  */
2523 static VOID INTERNET_ExecuteWork()
2524 {
2525     WORKREQUEST workRequest;
2526
2527     TRACE("\n");
2528
2529     if (!INTERNET_GetWorkRequest(&workRequest))
2530         return;
2531
2532     switch (workRequest.asyncall)
2533     {
2534     case FTPPUTFILEW:
2535         {
2536         struct WORKREQ_FTPPUTFILEW *req = &workRequest.u.FtpPutFileW;
2537         LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest.hdr;
2538
2539         TRACE("FTPPUTFILEW %p\n", lpwfs);
2540
2541         FTP_FtpPutFileW(lpwfs, req->lpszLocalFile,
2542                    req->lpszNewRemoteFile, req->dwFlags, req->dwContext);
2543
2544         HeapFree(GetProcessHeap(), 0, req->lpszLocalFile);
2545         HeapFree(GetProcessHeap(), 0, req->lpszNewRemoteFile);
2546         }
2547         break;
2548
2549     case FTPSETCURRENTDIRECTORYW:
2550         {
2551         struct WORKREQ_FTPSETCURRENTDIRECTORYW *req;
2552         LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest.hdr;
2553
2554         TRACE("FTPSETCURRENTDIRECTORYW %p\n", lpwfs);
2555
2556         req = &workRequest.u.FtpSetCurrentDirectoryW;
2557         FTP_FtpSetCurrentDirectoryW(lpwfs, req->lpszDirectory);
2558         HeapFree(GetProcessHeap(), 0, req->lpszDirectory);
2559         }
2560         break;
2561
2562     case FTPCREATEDIRECTORYW:
2563         {
2564         struct WORKREQ_FTPCREATEDIRECTORYW *req;
2565         LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest.hdr;
2566
2567         TRACE("FTPCREATEDIRECTORYW %p\n", lpwfs);
2568
2569         req = &workRequest.u.FtpCreateDirectoryW;
2570         FTP_FtpCreateDirectoryW(lpwfs, req->lpszDirectory);
2571         HeapFree(GetProcessHeap(), 0, req->lpszDirectory);
2572         }
2573         break;
2574
2575     case FTPFINDFIRSTFILEW:
2576         {
2577         struct WORKREQ_FTPFINDFIRSTFILEW *req;
2578         LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest.hdr;
2579
2580         TRACE("FTPFINDFIRSTFILEW %p\n", lpwfs);
2581
2582         req = &workRequest.u.FtpFindFirstFileW;
2583         FTP_FtpFindFirstFileW(lpwfs, req->lpszSearchFile,
2584            req->lpFindFileData, req->dwFlags, req->dwContext);
2585         if (req->lpszSearchFile != NULL)
2586             HeapFree(GetProcessHeap(), 0, req->lpszSearchFile);
2587         }
2588         break;
2589
2590     case FTPGETCURRENTDIRECTORYW:
2591         {
2592         struct WORKREQ_FTPGETCURRENTDIRECTORYW *req;
2593         LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest.hdr;
2594
2595         TRACE("FTPGETCURRENTDIRECTORYW %p\n", lpwfs);
2596
2597         req = &workRequest.u.FtpGetCurrentDirectoryW;
2598         FTP_FtpGetCurrentDirectoryW(lpwfs,
2599                 req->lpszDirectory, req->lpdwDirectory);
2600         }
2601         break;
2602
2603     case FTPOPENFILEW:
2604         {
2605         struct WORKREQ_FTPOPENFILEW *req = &workRequest.u.FtpOpenFileW;
2606         LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest.hdr;
2607
2608         TRACE("FTPOPENFILEW %p\n", lpwfs);
2609
2610         FTP_FtpOpenFileW(lpwfs, req->lpszFilename,
2611             req->dwAccess, req->dwFlags, req->dwContext);
2612         HeapFree(GetProcessHeap(), 0, req->lpszFilename);
2613         }
2614         break;
2615
2616     case FTPGETFILEW:
2617         {
2618         struct WORKREQ_FTPGETFILEW *req = &workRequest.u.FtpGetFileW;
2619         LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest.hdr;
2620
2621         TRACE("FTPGETFILEW %p\n", lpwfs);
2622
2623         FTP_FtpGetFileW(lpwfs, req->lpszRemoteFile,
2624                  req->lpszNewFile, req->fFailIfExists,
2625                  req->dwLocalFlagsAttribute, req->dwFlags, req->dwContext);
2626         HeapFree(GetProcessHeap(), 0, req->lpszRemoteFile);
2627         HeapFree(GetProcessHeap(), 0, req->lpszNewFile);
2628         }
2629         break;
2630
2631     case FTPDELETEFILEW:
2632         {
2633         struct WORKREQ_FTPDELETEFILEW *req = &workRequest.u.FtpDeleteFileW;
2634         LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest.hdr;
2635
2636         TRACE("FTPDELETEFILEW %p\n", lpwfs);
2637
2638         FTP_FtpDeleteFileW(lpwfs, req->lpszFilename);
2639         HeapFree(GetProcessHeap(), 0, req->lpszFilename);
2640         }
2641         break;
2642
2643     case FTPREMOVEDIRECTORYW:
2644         {
2645         struct WORKREQ_FTPREMOVEDIRECTORYW *req;
2646         LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest.hdr;
2647
2648         TRACE("FTPREMOVEDIRECTORYW %p\n", lpwfs);
2649
2650         req = &workRequest.u.FtpRemoveDirectoryW;
2651         FTP_FtpRemoveDirectoryW(lpwfs, req->lpszDirectory);
2652         HeapFree(GetProcessHeap(), 0, req->lpszDirectory);
2653         }
2654         break;
2655
2656     case FTPRENAMEFILEW:
2657         {
2658         struct WORKREQ_FTPRENAMEFILEW *req = &workRequest.u.FtpRenameFileW;
2659         LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest.hdr;
2660
2661         TRACE("FTPRENAMEFILEW %p\n", lpwfs);
2662
2663         FTP_FtpRenameFileW(lpwfs, req->lpszSrcFile, req->lpszDestFile);
2664         HeapFree(GetProcessHeap(), 0, req->lpszSrcFile);
2665         HeapFree(GetProcessHeap(), 0, req->lpszDestFile);
2666         }
2667         break;
2668
2669     case INTERNETFINDNEXTW:
2670         {
2671         struct WORKREQ_INTERNETFINDNEXTW *req;
2672         LPWININETFINDNEXTW lpwh = (LPWININETFINDNEXTW) workRequest.hdr;
2673
2674         TRACE("INTERNETFINDNEXTW %p\n", lpwh);
2675
2676         req = &workRequest.u.InternetFindNextW;
2677         INTERNET_FindNextFileW(lpwh, req->lpFindFileData);
2678         }
2679         break;
2680
2681     case HTTPSENDREQUESTW:
2682         {
2683         struct WORKREQ_HTTPSENDREQUESTW *req = &workRequest.u.HttpSendRequestW;
2684         LPWININETHTTPREQW lpwhr = (LPWININETHTTPREQW) workRequest.hdr;
2685
2686         TRACE("HTTPSENDREQUESTW %p\n", lpwhr);
2687
2688         HTTP_HttpSendRequestW(lpwhr, req->lpszHeader,
2689                 req->dwHeaderLength, req->lpOptional, req->dwOptionalLength);
2690
2691         HeapFree(GetProcessHeap(), 0, req->lpszHeader);
2692         }
2693         break;
2694
2695     case HTTPOPENREQUESTW:
2696         {
2697         struct WORKREQ_HTTPOPENREQUESTW *req = &workRequest.u.HttpOpenRequestW;
2698         LPWININETHTTPSESSIONW lpwhs = (LPWININETHTTPSESSIONW) workRequest.hdr;
2699
2700         TRACE("HTTPOPENREQUESTW %p\n", lpwhs);
2701
2702         HTTP_HttpOpenRequestW(lpwhs, req->lpszVerb,
2703             req->lpszObjectName, req->lpszVersion, req->lpszReferrer,
2704             req->lpszAcceptTypes, req->dwFlags, req->dwContext);
2705
2706         HeapFree(GetProcessHeap(), 0, req->lpszVerb);
2707         HeapFree(GetProcessHeap(), 0, req->lpszObjectName);
2708         HeapFree(GetProcessHeap(), 0, req->lpszVersion);
2709         HeapFree(GetProcessHeap(), 0, req->lpszReferrer);
2710         }
2711         break;
2712
2713     case SENDCALLBACK:
2714         {
2715         struct WORKREQ_SENDCALLBACK *req = &workRequest.u.SendCallback;
2716         LPWININETAPPINFOW hIC = (LPWININETAPPINFOW) workRequest.hdr;
2717
2718         TRACE("SENDCALLBACK %p\n", hIC);
2719
2720         SendAsyncCallbackInt(hIC, req->hdr,
2721                 req->dwContext, req->dwInternetStatus, req->lpvStatusInfo,
2722                 req->dwStatusInfoLength);
2723         }
2724         break;
2725
2726     case INTERNETOPENURLW:
2727         {
2728         struct WORKREQ_INTERNETOPENURLW *req = &workRequest.u.InternetOpenUrlW;
2729         LPWININETAPPINFOW hIC = (LPWININETAPPINFOW) workRequest.hdr;
2730         
2731         TRACE("INTERNETOPENURLW %p\n", hIC);
2732
2733         INTERNET_InternetOpenUrlW(hIC, req->lpszUrl,
2734                                   req->lpszHeaders, req->dwHeadersLength, req->dwFlags, req->dwContext);
2735         HeapFree(GetProcessHeap(), 0, req->lpszUrl);
2736         HeapFree(GetProcessHeap(), 0, req->lpszHeaders);
2737         }
2738         break;
2739     }
2740     WININET_Release( workRequest.hdr );
2741 }
2742
2743
2744 /***********************************************************************
2745  *          INTERNET_GetResponseBuffer
2746  *
2747  * RETURNS
2748  *
2749  */
2750 LPSTR INTERNET_GetResponseBuffer()
2751 {
2752     LPWITHREADERROR lpwite = (LPWITHREADERROR)TlsGetValue(g_dwTlsErrIndex);
2753     TRACE("\n");
2754     return lpwite->response;
2755 }
2756
2757 /***********************************************************************
2758  *           INTERNET_GetNextLine  (internal)
2759  *
2760  * Parse next line in directory string listing
2761  *
2762  * RETURNS
2763  *   Pointer to beginning of next line
2764  *   NULL on failure
2765  *
2766  */
2767
2768 LPSTR INTERNET_GetNextLine(INT nSocket, LPDWORD dwLen)
2769 {
2770     struct timeval tv;
2771     fd_set infd;
2772     BOOL bSuccess = FALSE;
2773     INT nRecv = 0;
2774     LPSTR lpszBuffer = INTERNET_GetResponseBuffer();
2775
2776     TRACE("\n");
2777
2778     FD_ZERO(&infd);
2779     FD_SET(nSocket, &infd);
2780     tv.tv_sec=RESPONSE_TIMEOUT;
2781     tv.tv_usec=0;
2782
2783     while (nRecv < MAX_REPLY_LEN)
2784     {
2785         if (select(nSocket+1,&infd,NULL,NULL,&tv) > 0)
2786         {
2787             if (recv(nSocket, &lpszBuffer[nRecv], 1, 0) <= 0)
2788             {
2789                 INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS);
2790                 goto lend;
2791             }
2792
2793             if (lpszBuffer[nRecv] == '\n')
2794             {
2795                 bSuccess = TRUE;
2796                 break;
2797             }
2798             if (lpszBuffer[nRecv] != '\r')
2799                 nRecv++;
2800         }
2801         else
2802         {
2803             INTERNET_SetLastError(ERROR_INTERNET_TIMEOUT);
2804             goto lend;
2805         }
2806     }
2807
2808 lend:
2809     if (bSuccess)
2810     {
2811         lpszBuffer[nRecv] = '\0';
2812         *dwLen = nRecv - 1;
2813         TRACE(":%d %s\n", nRecv, lpszBuffer);
2814         return lpszBuffer;
2815     }
2816     else
2817     {
2818         return NULL;
2819     }
2820 }
2821
2822 /***********************************************************************
2823  *
2824  */
2825 BOOL WINAPI InternetQueryDataAvailable( HINTERNET hFile,
2826                                 LPDWORD lpdwNumberOfBytesAvailble,
2827                                 DWORD dwFlags, DWORD dwConext)
2828 {
2829     LPWININETHTTPREQW lpwhr;
2830     INT retval = -1;
2831     char buffer[4048];
2832
2833     lpwhr = (LPWININETHTTPREQW) WININET_GetObject( hFile );
2834     if (NULL == lpwhr)
2835     {
2836         SetLastError(ERROR_NO_MORE_FILES);
2837         return FALSE;
2838     }
2839
2840     TRACE("-->  %p %i\n",lpwhr,lpwhr->hdr.htype);
2841
2842     switch (lpwhr->hdr.htype)
2843     {
2844     case WH_HHTTPREQ:
2845         if (!NETCON_recv(&lpwhr->netConnection, buffer,
2846                          4048, MSG_PEEK, (int *)lpdwNumberOfBytesAvailble))
2847         {
2848             SetLastError(ERROR_NO_MORE_FILES);
2849             retval = FALSE;
2850         }
2851         else
2852             retval = TRUE;
2853         break;
2854
2855     default:
2856         FIXME("unsupported file type\n");
2857         break;
2858     }
2859     WININET_Release( &lpwhr->hdr );
2860
2861     TRACE("<-- %i\n",retval);
2862     return (retval+1);
2863 }
2864
2865
2866 /***********************************************************************
2867  *
2868  */
2869 BOOL WINAPI InternetLockRequestFile( HINTERNET hInternet, HANDLE
2870 *lphLockReqHandle)
2871 {
2872     FIXME("STUB\n");
2873     return FALSE;
2874 }
2875
2876 BOOL WINAPI InternetUnlockRequestFile( HANDLE hLockHandle)
2877 {
2878     FIXME("STUB\n");
2879     return FALSE;
2880 }
2881
2882
2883 /***********************************************************************
2884  *           InternetAutodial
2885  *
2886  * On windows this function is supposed to dial the default internet
2887  * connection. We don't want to have Wine dial out to the internet so
2888  * we return TRUE by default. It might be nice to check if we are connected.
2889  *
2890  * RETURNS
2891  *   TRUE on success
2892  *   FALSE on failure
2893  *
2894  */
2895 BOOL WINAPI InternetAutodial(DWORD dwFlags, HWND hwndParent)
2896 {
2897     FIXME("STUB\n");
2898
2899     /* Tell that we are connected to the internet. */
2900     return TRUE;
2901 }
2902
2903 /***********************************************************************
2904  *           InternetAutodialHangup
2905  *
2906  * Hangs up an connection made with InternetAutodial
2907  *
2908  * PARAM
2909  *    dwReserved
2910  * RETURNS
2911  *   TRUE on success
2912  *   FALSE on failure
2913  *
2914  */
2915 BOOL WINAPI InternetAutodialHangup(DWORD dwReserved)
2916 {
2917     FIXME("STUB\n");
2918
2919     /* we didn't dial, we don't disconnect */
2920     return TRUE;
2921 }
2922
2923 /***********************************************************************
2924  *
2925  *         InternetCombineUrlA
2926  *
2927  * Combine a base URL with a relative URL
2928  *
2929  * RETURNS
2930  *   TRUE on success
2931  *   FALSE on failure
2932  *
2933  */
2934
2935 BOOL WINAPI InternetCombineUrlA(LPCSTR lpszBaseUrl, LPCSTR lpszRelativeUrl,
2936                                 LPSTR lpszBuffer, LPDWORD lpdwBufferLength,
2937                                 DWORD dwFlags)
2938 {
2939     HRESULT hr=S_OK;
2940
2941     TRACE("(%s, %s, %p, %p, 0x%08lx)\n", debugstr_a(lpszBaseUrl), debugstr_a(lpszRelativeUrl), lpszBuffer, lpdwBufferLength, dwFlags);
2942
2943     /* Flip this bit to correspond to URL_ESCAPE_UNSAFE */
2944     dwFlags ^= ICU_NO_ENCODE;
2945     hr=UrlCombineA(lpszBaseUrl,lpszRelativeUrl,lpszBuffer,lpdwBufferLength,dwFlags);
2946
2947     return (hr==S_OK);
2948 }
2949
2950 /***********************************************************************
2951  *
2952  *         InternetCombineUrlW
2953  *
2954  * Combine a base URL with a relative URL
2955  *
2956  * RETURNS
2957  *   TRUE on success
2958  *   FALSE on failure
2959  *
2960  */
2961
2962 BOOL WINAPI InternetCombineUrlW(LPCWSTR lpszBaseUrl, LPCWSTR lpszRelativeUrl,
2963                                 LPWSTR lpszBuffer, LPDWORD lpdwBufferLength,
2964                                 DWORD dwFlags)
2965 {
2966     HRESULT hr=S_OK;
2967
2968     TRACE("(%s, %s, %p, %p, 0x%08lx)\n", debugstr_w(lpszBaseUrl), debugstr_w(lpszRelativeUrl), lpszBuffer, lpdwBufferLength, dwFlags);
2969
2970     /* Flip this bit to correspond to URL_ESCAPE_UNSAFE */
2971     dwFlags ^= ICU_NO_ENCODE;
2972     hr=UrlCombineW(lpszBaseUrl,lpszRelativeUrl,lpszBuffer,lpdwBufferLength,dwFlags);
2973
2974     return (hr==S_OK);
2975 }
2976
2977 /***********************************************************************
2978  *
2979  *         InternetCreateUrlA
2980  *
2981  * RETURNS
2982  *   TRUE on success
2983  *   FALSE on failure
2984  *
2985  */
2986 BOOL WINAPI InternetCreateUrlA(LPURL_COMPONENTSA lpUrlComponents, DWORD dwFlags,
2987                                LPSTR lpszUrl, LPDWORD lpdwUrlLength)
2988 {
2989     FIXME("\n");
2990     return FALSE;
2991 }
2992
2993 /***********************************************************************
2994  *
2995  *         InternetCreateUrlW
2996  *
2997  * RETURNS
2998  *   TRUE on success
2999  *   FALSE on failure
3000  *
3001  */
3002 BOOL WINAPI InternetCreateUrlW(LPURL_COMPONENTSW lpUrlComponents, DWORD dwFlags,
3003                                LPWSTR lpszUrl, LPDWORD lpdwUrlLength)
3004 {
3005     FIXME("\n");
3006     return FALSE;
3007 }