Implement A->W call for GetNamedSecurityInfo.
[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         int 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(%d) 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         int 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             INT 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 INTERNET_SCHEME GetInternetSchemeW(LPCWSTR lpszScheme, INT 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 BOOL SetUrlComponentValueW(LPWSTR* lppszComponent, LPDWORD dwComponentLen, LPCWSTR lpszStart, INT len)
1155 {
1156     TRACE("%s (%d)\n", debugstr_wn(lpszStart,len), len);
1157
1158     if (*dwComponentLen != 0 || *lppszComponent == NULL)
1159     {
1160         if (*lppszComponent == NULL)
1161         {
1162             *lppszComponent = (LPWSTR)lpszStart;
1163             *dwComponentLen = len;
1164         }
1165         else
1166         {
1167             INT ncpylen = min((*dwComponentLen)-1, len);
1168             strncpyW(*lppszComponent, lpszStart, ncpylen);
1169             (*lppszComponent)[ncpylen] = '\0';
1170             *dwComponentLen = ncpylen;
1171         }
1172     }
1173
1174     return TRUE;
1175 }
1176
1177 /***********************************************************************
1178  *           InternetCrackUrlW   (WININET.@)
1179  */
1180 BOOL WINAPI InternetCrackUrlW(LPCWSTR lpszUrl, DWORD dwUrlLength, DWORD dwFlags,
1181                               LPURL_COMPONENTSW lpUC)
1182 {
1183   /*
1184    * RFC 1808
1185    * <protocol>:[//<net_loc>][/path][;<params>][?<query>][#<fragment>]
1186    *
1187    */
1188     LPCWSTR lpszParam    = NULL;
1189     BOOL  bIsAbsolute = FALSE;
1190     LPCWSTR lpszap = lpszUrl;
1191     LPCWSTR lpszcp = NULL;
1192     const WCHAR lpszSeparators[3]={';','?',0};
1193     const WCHAR lpszSlash[2]={'/',0};
1194     if(dwUrlLength==0)
1195         dwUrlLength=strlenW(lpszUrl);
1196
1197     TRACE("\n");
1198
1199     /* Determine if the URI is absolute. */
1200     while (*lpszap != '\0')
1201     {
1202         if (isalnumW(*lpszap))
1203         {
1204             lpszap++;
1205             continue;
1206         }
1207         if ((*lpszap == ':') && (lpszap - lpszUrl >= 2))
1208         {
1209             bIsAbsolute = TRUE;
1210             lpszcp = lpszap;
1211         }
1212         else
1213         {
1214             lpszcp = lpszUrl; /* Relative url */
1215         }
1216
1217         break;
1218     }
1219
1220     /* Parse <params> */
1221     lpszParam = strpbrkW(lpszap, lpszSeparators);
1222     if (lpszParam != NULL)
1223     {
1224         if (!SetUrlComponentValueW(&lpUC->lpszExtraInfo, &lpUC->dwExtraInfoLength,
1225                                    lpszParam, dwUrlLength-(lpszParam-lpszUrl)))
1226         {
1227             return FALSE;
1228         }
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         if (!SetUrlComponentValueW(&lpUC->lpszScheme, &lpUC->dwSchemeLength,
1239                                    lpszUrl, lpszcp - lpszUrl))
1240             return FALSE;
1241
1242         /* Eat ':' in protocol. */
1243         lpszcp++;
1244
1245         /* if the scheme is "about", there is no host */
1246         if(strncmpW(wszAbout,lpszUrl, lpszcp - lpszUrl)==0)
1247         {
1248             SetUrlComponentValueW(&lpUC->lpszUserName, &lpUC->dwUserNameLength, NULL, 0);
1249             SetUrlComponentValueW(&lpUC->lpszPassword, &lpUC->dwPasswordLength, NULL, 0);
1250             SetUrlComponentValueW(&lpUC->lpszHostName, &lpUC->dwHostNameLength, NULL, 0);
1251             lpUC->nPort = 0;
1252         }
1253         else
1254         {
1255             /* Skip over slashes. */
1256             if (*lpszcp == '/')
1257             {
1258                 lpszcp++;
1259                 if (*lpszcp == '/')
1260                 {
1261                     lpszcp++;
1262                     if (*lpszcp == '/')
1263                         lpszcp++;
1264                 }
1265             }
1266
1267             lpszNetLoc = strpbrkW(lpszcp, lpszSlash);
1268             if (lpszParam)
1269             {
1270                 if (lpszNetLoc)
1271                     lpszNetLoc = min(lpszNetLoc, lpszParam);
1272                 else
1273                     lpszNetLoc = lpszParam;
1274             }
1275             else if (!lpszNetLoc)
1276                 lpszNetLoc = lpszcp + dwUrlLength-(lpszcp-lpszUrl);
1277
1278             /* Parse net-loc */
1279             if (lpszNetLoc)
1280             {
1281                 LPCWSTR lpszHost;
1282                 LPCWSTR lpszPort;
1283
1284                 /* [<user>[<:password>]@]<host>[:<port>] */
1285                 /* First find the user and password if they exist */
1286
1287                 lpszHost = strchrW(lpszcp, '@');
1288                 if (lpszHost == NULL || lpszHost > lpszNetLoc)
1289                 {
1290                     /* username and password not specified. */
1291                     SetUrlComponentValueW(&lpUC->lpszUserName, &lpUC->dwUserNameLength, NULL, 0);
1292                     SetUrlComponentValueW(&lpUC->lpszPassword, &lpUC->dwPasswordLength, NULL, 0);
1293                 }
1294                 else /* Parse out username and password */
1295                 {
1296                     LPCWSTR lpszUser = lpszcp;
1297                     LPCWSTR lpszPasswd = lpszHost;
1298
1299                     while (lpszcp < lpszHost)
1300                     {
1301                         if (*lpszcp == ':')
1302                             lpszPasswd = lpszcp;
1303
1304                         lpszcp++;
1305                     }
1306
1307                     SetUrlComponentValueW(&lpUC->lpszUserName, &lpUC->dwUserNameLength,
1308                                           lpszUser, lpszPasswd - lpszUser);
1309
1310                     if (lpszPasswd != lpszHost)
1311                         lpszPasswd++;
1312                     SetUrlComponentValueW(&lpUC->lpszPassword, &lpUC->dwPasswordLength,
1313                                           lpszPasswd == lpszHost ? NULL : lpszPasswd,
1314                                           lpszHost - lpszPasswd);
1315
1316                     lpszcp++; /* Advance to beginning of host */
1317                 }
1318
1319                 /* Parse <host><:port> */
1320
1321                 lpszHost = lpszcp;
1322                 lpszPort = lpszNetLoc;
1323
1324                 /* special case for res:// URLs: there is no port here, so the host is the
1325                    entire string up to the first '/' */
1326                 if(lpUC->nScheme==INTERNET_SCHEME_RES)
1327                 {
1328                     SetUrlComponentValueW(&lpUC->lpszHostName, &lpUC->dwHostNameLength,
1329                                           lpszHost, lpszPort - lpszHost);
1330                     lpUC->nPort = 0;
1331                     lpszcp=lpszNetLoc;
1332                 }
1333                 else
1334                 {
1335                     while (lpszcp < lpszNetLoc)
1336                     {
1337                         if (*lpszcp == ':')
1338                             lpszPort = lpszcp;
1339
1340                         lpszcp++;
1341                     }
1342
1343                     /* If the scheme is "file" and the host is just one letter, it's not a host */
1344                     if(lpUC->nScheme==INTERNET_SCHEME_FILE && (lpszPort-lpszHost)==1)
1345                     {
1346                         lpszcp=lpszHost;
1347                         SetUrlComponentValueW(&lpUC->lpszHostName, &lpUC->dwHostNameLength,
1348                                               NULL, 0);
1349                         lpUC->nPort = 0;
1350                     }
1351                     else
1352                     {
1353                         SetUrlComponentValueW(&lpUC->lpszHostName, &lpUC->dwHostNameLength,
1354                                               lpszHost, lpszPort - lpszHost);
1355                         if (lpszPort != lpszNetLoc)
1356                             lpUC->nPort = atoiW(++lpszPort);
1357                         else
1358                             lpUC->nPort = 0;
1359                     }
1360                 }
1361             }
1362         }
1363     }
1364
1365     /* Here lpszcp points to:
1366      *
1367      * <protocol>:[//<net_loc>][/path][;<params>][?<query>][#<fragment>]
1368      *                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1369      */
1370     if (lpszcp != 0 && *lpszcp != '\0' && (!lpszParam || lpszcp < lpszParam))
1371     {
1372         INT len;
1373
1374         /* Only truncate the parameter list if it's already been saved
1375          * in lpUC->lpszExtraInfo.
1376          */
1377         if (lpszParam && lpUC->dwExtraInfoLength)
1378             len = lpszParam - lpszcp;
1379         else
1380         {
1381             /* Leave the parameter list in lpszUrlPath.  Strip off any trailing
1382              * newlines if necessary.
1383              */
1384             LPWSTR lpsznewline = strchrW(lpszcp, '\n');
1385             if (lpsznewline != NULL)
1386                 len = lpsznewline - lpszcp;
1387             else
1388                 len = dwUrlLength-(lpszcp-lpszUrl);
1389         }
1390
1391         if (!SetUrlComponentValueW(&lpUC->lpszUrlPath, &lpUC->dwUrlPathLength,
1392                                    lpszcp, len))
1393             return FALSE;
1394     }
1395     else
1396     {
1397         lpUC->dwUrlPathLength = 0;
1398     }
1399
1400     TRACE("%s: host(%s) path(%s) extra(%s)\n", debugstr_wn(lpszUrl,dwUrlLength),
1401              debugstr_wn(lpUC->lpszHostName,lpUC->dwHostNameLength),
1402              debugstr_wn(lpUC->lpszUrlPath,lpUC->dwUrlPathLength),
1403              debugstr_wn(lpUC->lpszExtraInfo,lpUC->dwExtraInfoLength));
1404
1405     return TRUE;
1406 }
1407
1408 /***********************************************************************
1409  *           InternetAttemptConnect (WININET.@)
1410  *
1411  * Attempt to make a connection to the internet
1412  *
1413  * RETURNS
1414  *    ERROR_SUCCESS on success
1415  *    Error value   on failure
1416  *
1417  */
1418 DWORD WINAPI InternetAttemptConnect(DWORD dwReserved)
1419 {
1420     FIXME("Stub\n");
1421     return ERROR_SUCCESS;
1422 }
1423
1424
1425 /***********************************************************************
1426  *           InternetCanonicalizeUrlA (WININET.@)
1427  *
1428  * Escape unsafe characters and spaces
1429  *
1430  * RETURNS
1431  *    TRUE on success
1432  *    FALSE on failure
1433  *
1434  */
1435 BOOL WINAPI InternetCanonicalizeUrlA(LPCSTR lpszUrl, LPSTR lpszBuffer,
1436         LPDWORD lpdwBufferLength, DWORD dwFlags)
1437 {
1438     HRESULT hr;
1439     TRACE("%s %p %p %08lx\n",debugstr_a(lpszUrl), lpszBuffer,
1440           lpdwBufferLength, dwFlags);
1441
1442     /* Flip this bit to correspond to URL_ESCAPE_UNSAFE */
1443     dwFlags ^= ICU_NO_ENCODE;
1444
1445     dwFlags |= 0x80000000; /* Don't know what this means */
1446
1447     hr = UrlCanonicalizeA(lpszUrl, lpszBuffer, lpdwBufferLength, dwFlags);
1448
1449     return (hr == S_OK) ? TRUE : FALSE;
1450 }
1451
1452 /***********************************************************************
1453  *           InternetCanonicalizeUrlW (WININET.@)
1454  *
1455  * Escape unsafe characters and spaces
1456  *
1457  * RETURNS
1458  *    TRUE on success
1459  *    FALSE on failure
1460  *
1461  */
1462 BOOL WINAPI InternetCanonicalizeUrlW(LPCWSTR lpszUrl, LPWSTR lpszBuffer,
1463     LPDWORD lpdwBufferLength, DWORD dwFlags)
1464 {
1465     HRESULT hr;
1466     TRACE("%s %p %p %08lx\n", debugstr_w(lpszUrl), lpszBuffer,
1467         lpdwBufferLength, dwFlags);
1468
1469     /* Flip this bit to correspond to URL_ESCAPE_UNSAFE */
1470     dwFlags ^= ICU_NO_ENCODE;
1471
1472     dwFlags |= 0x80000000; /* Don't know what this means */
1473
1474     hr = UrlCanonicalizeW(lpszUrl, lpszBuffer, lpdwBufferLength, dwFlags);
1475
1476     return (hr == S_OK) ? TRUE : FALSE;
1477 }
1478
1479
1480 /***********************************************************************
1481  *           InternetSetStatusCallbackA (WININET.@)
1482  *
1483  * Sets up a callback function which is called as progress is made
1484  * during an operation.
1485  *
1486  * RETURNS
1487  *    Previous callback or NULL         on success
1488  *    INTERNET_INVALID_STATUS_CALLBACK  on failure
1489  *
1490  */
1491 INTERNET_STATUS_CALLBACK WINAPI InternetSetStatusCallbackA(
1492         HINTERNET hInternet ,INTERNET_STATUS_CALLBACK lpfnIntCB)
1493 {
1494     INTERNET_STATUS_CALLBACK retVal = INTERNET_INVALID_STATUS_CALLBACK;
1495     LPWININETAPPINFOW lpwai;
1496
1497     TRACE("0x%08lx\n", (ULONG)hInternet);
1498     
1499     lpwai = (LPWININETAPPINFOW)WININET_GetObject(hInternet);
1500     if (!lpwai)
1501         return retVal;
1502
1503     if (lpwai->hdr.htype == WH_HINIT)
1504     {
1505         lpwai->hdr.dwInternalFlags &= ~INET_CALLBACKW;
1506         retVal = lpwai->lpfnStatusCB;
1507         lpwai->lpfnStatusCB = lpfnIntCB;
1508     }
1509     WININET_Release( &lpwai->hdr );
1510
1511     return retVal;
1512 }
1513
1514 /***********************************************************************
1515  *           InternetSetStatusCallbackW (WININET.@)
1516  *
1517  * Sets up a callback function which is called as progress is made
1518  * during an operation.
1519  *
1520  * RETURNS
1521  *    Previous callback or NULL         on success
1522  *    INTERNET_INVALID_STATUS_CALLBACK  on failure
1523  *
1524  */
1525 INTERNET_STATUS_CALLBACK WINAPI InternetSetStatusCallbackW(
1526         HINTERNET hInternet ,INTERNET_STATUS_CALLBACK lpfnIntCB)
1527 {
1528     INTERNET_STATUS_CALLBACK retVal = INTERNET_INVALID_STATUS_CALLBACK;
1529     LPWININETAPPINFOW lpwai;
1530
1531     TRACE("0x%08lx\n", (ULONG)hInternet);
1532     
1533     lpwai = (LPWININETAPPINFOW)WININET_GetObject(hInternet);
1534     if (!lpwai)
1535         return retVal;
1536
1537     if (lpwai->hdr.htype == WH_HINIT)
1538     {
1539         lpwai->hdr.dwInternalFlags |= INET_CALLBACKW;
1540         retVal = lpwai->lpfnStatusCB;
1541         lpwai->lpfnStatusCB = lpfnIntCB;
1542     }
1543
1544     WININET_Release( &lpwai->hdr );
1545
1546     return retVal;
1547 }
1548
1549 /***********************************************************************
1550  *           InternetSetFilePointer (WININET.@)
1551  */
1552 DWORD WINAPI InternetSetFilePointer(HINTERNET f1, LONG f2, PVOID f3, DWORD f4, DWORD f5)
1553 {
1554     FIXME("stub\n");
1555     return FALSE;
1556 }
1557
1558 /***********************************************************************
1559  *           InternetWriteFile (WININET.@)
1560  *
1561  * Write data to an open internet file
1562  *
1563  * RETURNS
1564  *    TRUE  on success
1565  *    FALSE on failure
1566  *
1567  */
1568 BOOL WINAPI InternetWriteFile(HINTERNET hFile, LPCVOID lpBuffer ,
1569         DWORD dwNumOfBytesToWrite, LPDWORD lpdwNumOfBytesWritten)
1570 {
1571     BOOL retval = FALSE;
1572     int nSocket = -1;
1573     LPWININETHANDLEHEADER lpwh;
1574
1575     TRACE("\n");
1576     lpwh = (LPWININETHANDLEHEADER) WININET_GetObject( hFile );
1577     if (NULL == lpwh)
1578         return FALSE;
1579
1580     switch (lpwh->htype)
1581     {
1582         case WH_HHTTPREQ:
1583             FIXME("This shouldn't be here! We don't support this kind"
1584                   " of connection anymore. Must use NETCON functions,"
1585                   " especially if using SSL\n");
1586             nSocket = ((LPWININETHTTPREQW)lpwh)->netConnection.socketFD;
1587             break;
1588
1589         case WH_HFILE:
1590             nSocket = ((LPWININETFILE)lpwh)->nDataSocket;
1591             break;
1592
1593         default:
1594             break;
1595     }
1596
1597     if (nSocket != -1)
1598     {
1599         int res = send(nSocket, lpBuffer, dwNumOfBytesToWrite, 0);
1600         retval = (res >= 0);
1601         *lpdwNumOfBytesWritten = retval ? res : 0;
1602     }
1603     WININET_Release( lpwh );
1604
1605     return retval;
1606 }
1607
1608
1609 /***********************************************************************
1610  *           InternetReadFile (WININET.@)
1611  *
1612  * Read data from an open internet file
1613  *
1614  * RETURNS
1615  *    TRUE  on success
1616  *    FALSE on failure
1617  *
1618  */
1619 BOOL WINAPI InternetReadFile(HINTERNET hFile, LPVOID lpBuffer,
1620         DWORD dwNumOfBytesToRead, LPDWORD dwNumOfBytesRead)
1621 {
1622     BOOL retval = FALSE;
1623     int nSocket = -1;
1624     LPWININETHANDLEHEADER lpwh;
1625
1626     TRACE("%p %p %ld %p\n", hFile, lpBuffer, dwNumOfBytesToRead, dwNumOfBytesRead);
1627
1628     lpwh = (LPWININETHANDLEHEADER) WININET_GetObject( hFile );
1629     if (NULL == lpwh)
1630         return FALSE;
1631
1632     /* FIXME: this should use NETCON functions! */
1633     switch (lpwh->htype)
1634     {
1635         case WH_HHTTPREQ:
1636             if (!NETCON_recv(&((LPWININETHTTPREQW)lpwh)->netConnection, lpBuffer,
1637                              dwNumOfBytesToRead, 0, (int *)dwNumOfBytesRead))
1638             {
1639                 *dwNumOfBytesRead = 0;
1640                 retval = TRUE; /* Under windows, it seems to return 0 even if nothing was read... */
1641             }
1642             else
1643                 retval = TRUE;
1644             break;
1645
1646         case WH_HFILE:
1647             /* FIXME: FTP should use NETCON_ stuff */
1648             nSocket = ((LPWININETFILE)lpwh)->nDataSocket;
1649             if (nSocket != -1)
1650             {
1651                 int res = recv(nSocket, lpBuffer, dwNumOfBytesToRead, 0);
1652                 retval = (res >= 0);
1653                 *dwNumOfBytesRead = retval ? res : 0;
1654             }
1655             break;
1656
1657         default:
1658             break;
1659     }
1660     WININET_Release( lpwh );
1661
1662     return retval;
1663 }
1664
1665 /***********************************************************************
1666  *           InternetReadFileExA (WININET.@)
1667  *
1668  * Read data from an open internet file
1669  *
1670  * RETURNS
1671  *    TRUE  on success
1672  *    FALSE on failure
1673  *
1674  */
1675 BOOL WINAPI InternetReadFileExA(HINTERNET hFile, LPINTERNET_BUFFERSA lpBuffer,
1676         DWORD dwFlags, DWORD dwContext)
1677 {
1678   FIXME("stub\n");
1679   return FALSE;
1680 }
1681
1682 /***********************************************************************
1683  *           InternetReadFileExW (WININET.@)
1684  *
1685  * Read data from an open internet file
1686  *
1687  * RETURNS
1688  *    TRUE  on success
1689  *    FALSE on failure
1690  *
1691  */
1692 BOOL WINAPI InternetReadFileExW(HINTERNET hFile, LPINTERNET_BUFFERSW lpBuffer,
1693         DWORD dwFlags, DWORD dwContext)
1694 {
1695   FIXME("stub\n");
1696
1697   INTERNET_SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1698   return FALSE;
1699 }
1700
1701 /***********************************************************************
1702  *           INET_QueryOptionHelper (internal)
1703  */
1704 static BOOL INET_QueryOptionHelper(BOOL bIsUnicode, HINTERNET hInternet, DWORD dwOption,
1705                                    LPVOID lpBuffer, LPDWORD lpdwBufferLength)
1706 {
1707     LPWININETHANDLEHEADER lpwhh;
1708     BOOL bSuccess = FALSE;
1709
1710     TRACE("(%p, 0x%08lx, %p, %p)\n", hInternet, dwOption, lpBuffer, lpdwBufferLength);
1711
1712     lpwhh = (LPWININETHANDLEHEADER) WININET_GetObject( hInternet );
1713
1714     switch (dwOption)
1715     {
1716         case INTERNET_OPTION_HANDLE_TYPE:
1717         {
1718             ULONG type;
1719
1720             if (!lpwhh)
1721             {
1722                 WARN("Invalid hInternet handle\n");
1723                 SetLastError(ERROR_INVALID_HANDLE);
1724                 return FALSE;
1725             }
1726
1727             type = lpwhh->htype;
1728
1729             TRACE("INTERNET_OPTION_HANDLE_TYPE: %ld\n", type);
1730
1731             if (*lpdwBufferLength < sizeof(ULONG))
1732                 INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
1733             else
1734             {
1735                 memcpy(lpBuffer, &type, sizeof(ULONG));
1736                     *lpdwBufferLength = sizeof(ULONG);
1737                 bSuccess = TRUE;
1738             }
1739             break;
1740         }
1741
1742         case INTERNET_OPTION_REQUEST_FLAGS:
1743         {
1744             ULONG flags = 4;
1745             TRACE("INTERNET_OPTION_REQUEST_FLAGS: %ld\n", flags);
1746             if (*lpdwBufferLength < sizeof(ULONG))
1747                 INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
1748             else
1749             {
1750                 memcpy(lpBuffer, &flags, sizeof(ULONG));
1751                     *lpdwBufferLength = sizeof(ULONG);
1752                 bSuccess = TRUE;
1753             }
1754             break;
1755         }
1756
1757         case INTERNET_OPTION_URL:
1758         case INTERNET_OPTION_DATAFILE_NAME:
1759         {
1760             if (!lpwhh)
1761             {
1762                 WARN("Invalid hInternet handle\n");
1763                 SetLastError(ERROR_INVALID_HANDLE);
1764                 return FALSE;
1765             }
1766             if (lpwhh->htype == WH_HHTTPREQ)
1767             {
1768                 LPWININETHTTPREQW lpreq = (LPWININETHTTPREQW) lpwhh;
1769                 WCHAR url[1023];
1770                 static const WCHAR szFmt[] = {'h','t','t','p',':','/','/','%','s','%','s',0};
1771
1772                 sprintfW(url,szFmt,lpreq->lpszHostName,lpreq->lpszPath);
1773                 TRACE("INTERNET_OPTION_URL: %s\n",debugstr_w(url));
1774                 if (*lpdwBufferLength < strlenW(url)+1)
1775                     INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
1776                 else
1777                 {
1778                     if(!bIsUnicode)
1779                     {
1780                         *lpdwBufferLength=WideCharToMultiByte(CP_ACP,0,url,-1,lpBuffer,*lpdwBufferLength,NULL,NULL);
1781                     }
1782                     else
1783                     {
1784                         strcpyW(lpBuffer, url);
1785                         *lpdwBufferLength = strlenW(url)+1;
1786                     }
1787                     bSuccess = TRUE;
1788                 }
1789             }
1790             break;
1791         }
1792        case INTERNET_OPTION_HTTP_VERSION:
1793        {
1794             /*
1795              * Presently hardcoded to 1.1
1796              */
1797             ((HTTP_VERSION_INFO*)lpBuffer)->dwMajorVersion = 1;
1798             ((HTTP_VERSION_INFO*)lpBuffer)->dwMinorVersion = 1;
1799             bSuccess = TRUE;
1800             break;
1801        }
1802        case INTERNET_OPTION_CONNECTED_STATE:
1803        {
1804            INTERNET_CONNECTED_INFO * pCi = (INTERNET_CONNECTED_INFO *)lpBuffer;
1805            FIXME("INTERNET_OPTION_CONNECTED_STATE: semi-stub\n");
1806            pCi->dwConnectedState = INTERNET_STATE_CONNECTED;
1807            pCi->dwFlags = 0;
1808            bSuccess = TRUE;
1809            break;
1810        }
1811        case INTERNET_OPTION_SECURITY_FLAGS:
1812          FIXME("INTERNET_OPTION_SECURITY_FLAGS: Stub\n");
1813          break;
1814
1815        default:
1816          FIXME("Stub! %ld \n",dwOption);
1817          break;
1818     }
1819     if (lpwhh)
1820         WININET_Release( lpwhh );
1821
1822     return bSuccess;
1823 }
1824
1825 /***********************************************************************
1826  *           InternetQueryOptionW (WININET.@)
1827  *
1828  * Queries an options on the specified handle
1829  *
1830  * RETURNS
1831  *    TRUE  on success
1832  *    FALSE on failure
1833  *
1834  */
1835 BOOL WINAPI InternetQueryOptionW(HINTERNET hInternet, DWORD dwOption,
1836                                  LPVOID lpBuffer, LPDWORD lpdwBufferLength)
1837 {
1838     return INET_QueryOptionHelper(TRUE, hInternet, dwOption, lpBuffer, lpdwBufferLength);
1839 }
1840
1841 /***********************************************************************
1842  *           InternetQueryOptionA (WININET.@)
1843  *
1844  * Queries an options on the specified handle
1845  *
1846  * RETURNS
1847  *    TRUE  on success
1848  *    FALSE on failure
1849  *
1850  */
1851 BOOL WINAPI InternetQueryOptionA(HINTERNET hInternet, DWORD dwOption,
1852                                  LPVOID lpBuffer, LPDWORD lpdwBufferLength)
1853 {
1854     return INET_QueryOptionHelper(FALSE, hInternet, dwOption, lpBuffer, lpdwBufferLength);
1855 }
1856
1857
1858 /***********************************************************************
1859  *           InternetSetOptionW (WININET.@)
1860  *
1861  * Sets an options on the specified handle
1862  *
1863  * RETURNS
1864  *    TRUE  on success
1865  *    FALSE on failure
1866  *
1867  */
1868 BOOL WINAPI InternetSetOptionW(HINTERNET hInternet, DWORD dwOption,
1869                            LPVOID lpBuffer, DWORD dwBufferLength)
1870 {
1871     LPWININETHANDLEHEADER lpwhh;
1872     BOOL ret = TRUE;
1873
1874     TRACE("0x%08lx\n", dwOption);
1875
1876     lpwhh = (LPWININETHANDLEHEADER) WININET_GetObject( hInternet );
1877     if( !lpwhh )
1878         return FALSE;
1879
1880     switch (dwOption)
1881     {
1882     case INTERNET_OPTION_HTTP_VERSION:
1883       {
1884         HTTP_VERSION_INFO* pVersion=(HTTP_VERSION_INFO*)lpBuffer;
1885         FIXME("Option INTERNET_OPTION_HTTP_VERSION(%ld,%ld): STUB\n",pVersion->dwMajorVersion,pVersion->dwMinorVersion);
1886       }
1887       break;
1888     case INTERNET_OPTION_ERROR_MASK:
1889       {
1890         unsigned long flags=*(unsigned long*)lpBuffer;
1891         FIXME("Option INTERNET_OPTION_ERROR_MASK(%ld): STUB\n",flags);
1892       }
1893       break;
1894     case INTERNET_OPTION_CODEPAGE:
1895       {
1896         unsigned long codepage=*(unsigned long*)lpBuffer;
1897         FIXME("Option INTERNET_OPTION_CODEPAGE (%ld): STUB\n",codepage);
1898       }
1899       break;
1900     case INTERNET_OPTION_REQUEST_PRIORITY:
1901       {
1902         unsigned long priority=*(unsigned long*)lpBuffer;
1903         FIXME("Option INTERNET_OPTION_REQUEST_PRIORITY (%ld): STUB\n",priority);
1904       }
1905       break;
1906     case INTERNET_OPTION_CONNECT_TIMEOUT:
1907       {
1908         unsigned long connecttimeout=*(unsigned long*)lpBuffer;
1909         FIXME("Option INTERNET_OPTION_CONNECT_TIMEOUT (%ld): STUB\n",connecttimeout);
1910       }
1911       break;
1912     case INTERNET_OPTION_DATA_RECEIVE_TIMEOUT:
1913       {
1914         unsigned long receivetimeout=*(unsigned long*)lpBuffer;
1915         FIXME("Option INTERNET_OPTION_DATA_RECEIVE_TIMEOUT (%ld): STUB\n",receivetimeout);
1916       }
1917       break;
1918     case INTERNET_OPTION_RESET_URLCACHE_SESSION:
1919         FIXME("Option INTERNET_OPTION_RESET_URLCACHE_SESSION: STUB\n");
1920         break;
1921     case INTERNET_OPTION_END_BROWSER_SESSION:
1922         FIXME("Option INTERNET_OPTION_END_BROWSER_SESSION: STUB\n");
1923         break;
1924     case INTERNET_OPTION_CONNECTED_STATE:
1925         FIXME("Option INTERNET_OPTION_CONNECTED_STATE: STUB\n");
1926         break;
1927     default:
1928         FIXME("Option %ld STUB\n",dwOption);
1929         INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
1930         ret = FALSE;
1931         break;
1932     }
1933     WININET_Release( lpwhh );
1934
1935     return TRUE;
1936 }
1937
1938
1939 /***********************************************************************
1940  *           InternetSetOptionA (WININET.@)
1941  *
1942  * Sets an options on the specified handle.
1943  *
1944  * RETURNS
1945  *    TRUE  on success
1946  *    FALSE on failure
1947  *
1948  */
1949 BOOL WINAPI InternetSetOptionA(HINTERNET hInternet, DWORD dwOption,
1950                            LPVOID lpBuffer, DWORD dwBufferLength)
1951 {
1952     LPVOID wbuffer;
1953     DWORD wlen;
1954     BOOL r;
1955
1956     switch( dwOption )
1957     {
1958     case INTERNET_OPTION_PROXY:
1959         {
1960         LPINTERNET_PROXY_INFOA pi = (LPINTERNET_PROXY_INFOA) lpBuffer;
1961         LPINTERNET_PROXY_INFOW piw;
1962         DWORD proxlen, prbylen;
1963         LPWSTR prox, prby;
1964
1965         proxlen = MultiByteToWideChar( CP_ACP, 0, pi->lpszProxy, -1, NULL, 0);
1966         prbylen= MultiByteToWideChar( CP_ACP, 0, pi->lpszProxyBypass, -1, NULL, 0);
1967         wlen = sizeof(*piw) + proxlen + prbylen;
1968         wbuffer = HeapAlloc( GetProcessHeap(), 0, wlen*sizeof(WCHAR) );
1969         piw = (LPINTERNET_PROXY_INFOW) wbuffer;
1970         piw->dwAccessType = pi->dwAccessType;
1971         prox = (LPWSTR) &piw[1];
1972         prby = &prox[proxlen+1];
1973         MultiByteToWideChar( CP_ACP, 0, pi->lpszProxy, -1, prox, proxlen);
1974         MultiByteToWideChar( CP_ACP, 0, pi->lpszProxyBypass, -1, prby, prbylen);
1975         piw->lpszProxy = prox;
1976         piw->lpszProxyBypass = prby;
1977         }
1978         break;
1979     case INTERNET_OPTION_USER_AGENT:
1980     case INTERNET_OPTION_USERNAME:
1981     case INTERNET_OPTION_PASSWORD:
1982         wlen = MultiByteToWideChar( CP_ACP, 0, lpBuffer, dwBufferLength,
1983                                    NULL, 0 );
1984         wbuffer = HeapAlloc( GetProcessHeap(), 0, wlen*sizeof(WCHAR) );
1985         MultiByteToWideChar( CP_ACP, 0, lpBuffer, dwBufferLength,
1986                                    wbuffer, wlen );
1987         break;
1988     default:
1989         wbuffer = lpBuffer;
1990         wlen = dwBufferLength;
1991     }
1992
1993     r = InternetSetOptionW(hInternet,dwOption, wbuffer, wlen);
1994
1995     if( lpBuffer != wbuffer )
1996         HeapFree( GetProcessHeap(), 0, wbuffer );
1997
1998     return r;
1999 }
2000
2001
2002 /***********************************************************************
2003  *           InternetSetOptionExA (WININET.@)
2004  */
2005 BOOL WINAPI InternetSetOptionExA(HINTERNET hInternet, DWORD dwOption,
2006                            LPVOID lpBuffer, DWORD dwBufferLength, DWORD dwFlags)
2007 {
2008     FIXME("Flags %08lx ignored\n", dwFlags);
2009     return InternetSetOptionA( hInternet, dwOption, lpBuffer, dwBufferLength );
2010 }
2011
2012 /***********************************************************************
2013  *           InternetSetOptionExW (WININET.@)
2014  */
2015 BOOL WINAPI InternetSetOptionExW(HINTERNET hInternet, DWORD dwOption,
2016                            LPVOID lpBuffer, DWORD dwBufferLength, DWORD dwFlags)
2017 {
2018     FIXME("Flags %08lx ignored\n", dwFlags);
2019     if( dwFlags & ~ISO_VALID_FLAGS )
2020     {
2021         SetLastError( ERROR_INVALID_PARAMETER );
2022         return FALSE;
2023     }
2024     return InternetSetOptionW( hInternet, dwOption, lpBuffer, dwBufferLength );
2025 }
2026
2027
2028 /***********************************************************************
2029  *      InternetCheckConnectionA (WININET.@)
2030  *
2031  * Pings a requested host to check internet connection
2032  *
2033  * RETURNS
2034  *   TRUE on success and FALSE on failure. If a failure then
2035  *   ERROR_NOT_CONNECTED is placesd into GetLastError
2036  *
2037  */
2038 BOOL WINAPI InternetCheckConnectionA( LPCSTR lpszUrl, DWORD dwFlags, DWORD dwReserved )
2039 {
2040 /*
2041  * this is a kludge which runs the resident ping program and reads the output.
2042  *
2043  * Anyone have a better idea?
2044  */
2045
2046   BOOL   rc = FALSE;
2047   char command[1024];
2048   char host[1024];
2049   int status = -1;
2050
2051   FIXME("\n");
2052
2053   /*
2054    * Crack or set the Address
2055    */
2056   if (lpszUrl == NULL)
2057   {
2058      /*
2059       * According to the doc we are supost to use the ip for the next
2060       * server in the WnInet internal server database. I have
2061       * no idea what that is or how to get it.
2062       *
2063       * So someone needs to implement this.
2064       */
2065      FIXME("Unimplemented with URL of NULL\n");
2066      return TRUE;
2067   }
2068   else
2069   {
2070      URL_COMPONENTSA componets;
2071
2072      ZeroMemory(&componets,sizeof(URL_COMPONENTSA));
2073      componets.lpszHostName = (LPSTR)&host;
2074      componets.dwHostNameLength = 1024;
2075
2076      if (!InternetCrackUrlA(lpszUrl,0,0,&componets))
2077        goto End;
2078
2079      TRACE("host name : %s\n",componets.lpszHostName);
2080   }
2081
2082   /*
2083    * Build our ping command
2084    */
2085   strcpy(command,"ping -w 1 ");
2086   strcat(command,host);
2087   strcat(command," >/dev/null 2>/dev/null");
2088
2089   TRACE("Ping command is : %s\n",command);
2090
2091   status = system(command);
2092
2093   TRACE("Ping returned a code of %i \n",status);
2094
2095   /* Ping return code of 0 indicates success */
2096   if (status == 0)
2097      rc = TRUE;
2098
2099 End:
2100
2101   if (rc == FALSE)
2102     SetLastError(ERROR_NOT_CONNECTED);
2103
2104   return rc;
2105 }
2106
2107
2108 /***********************************************************************
2109  *      InternetCheckConnectionW (WININET.@)
2110  *
2111  * Pings a requested host to check internet connection
2112  *
2113  * RETURNS
2114  *   TRUE on success and FALSE on failure. If a failure then
2115  *   ERROR_NOT_CONNECTED is placed into GetLastError
2116  *
2117  */
2118 BOOL WINAPI InternetCheckConnectionW(LPCWSTR lpszUrl, DWORD dwFlags, DWORD dwReserved)
2119 {
2120     CHAR *szUrl;
2121     INT len;
2122     BOOL rc;
2123
2124     len = WideCharToMultiByte(CP_ACP, 0, lpszUrl, -1, NULL, 0, NULL, NULL);
2125     if (!(szUrl = (CHAR *)HeapAlloc(GetProcessHeap(), 0, len*sizeof(CHAR))))
2126         return FALSE;
2127     WideCharToMultiByte(CP_ACP, 0, lpszUrl, -1, szUrl, len, NULL, NULL);
2128     rc = InternetCheckConnectionA((LPCSTR)szUrl, dwFlags, dwReserved);
2129     HeapFree(GetProcessHeap(), 0, szUrl);
2130     
2131     return rc;
2132 }
2133
2134
2135 /**********************************************************
2136  *      INTERNET_InternetOpenUrlW (internal)
2137  *
2138  * Opens an URL
2139  *
2140  * RETURNS
2141  *   handle of connection or NULL on failure
2142  */
2143 HINTERNET WINAPI INTERNET_InternetOpenUrlW(LPWININETAPPINFOW hIC, LPCWSTR lpszUrl,
2144     LPCWSTR lpszHeaders, DWORD dwHeadersLength, DWORD dwFlags, DWORD dwContext)
2145 {
2146     URL_COMPONENTSW urlComponents;
2147     WCHAR protocol[32], hostName[MAXHOSTNAME], userName[1024];
2148     WCHAR password[1024], path[2048], extra[1024];
2149     HINTERNET client = NULL, client1 = NULL;
2150     
2151     TRACE("(%p, %s, %s, %08lx, %08lx, %08lx\n", hIC, debugstr_w(lpszUrl), debugstr_w(lpszHeaders),
2152           dwHeadersLength, dwFlags, dwContext);
2153     
2154     urlComponents.dwStructSize = sizeof(URL_COMPONENTSW);
2155     urlComponents.lpszScheme = protocol;
2156     urlComponents.dwSchemeLength = 32;
2157     urlComponents.lpszHostName = hostName;
2158     urlComponents.dwHostNameLength = MAXHOSTNAME;
2159     urlComponents.lpszUserName = userName;
2160     urlComponents.dwUserNameLength = 1024;
2161     urlComponents.lpszPassword = password;
2162     urlComponents.dwPasswordLength = 1024;
2163     urlComponents.lpszUrlPath = path;
2164     urlComponents.dwUrlPathLength = 2048;
2165     urlComponents.lpszExtraInfo = extra;
2166     urlComponents.dwExtraInfoLength = 1024;
2167     if(!InternetCrackUrlW(lpszUrl, strlenW(lpszUrl), 0, &urlComponents))
2168         return NULL;
2169     switch(urlComponents.nScheme) {
2170     case INTERNET_SCHEME_FTP:
2171         if(urlComponents.nPort == 0)
2172             urlComponents.nPort = INTERNET_DEFAULT_FTP_PORT;
2173         client = FTP_Connect(hIC, hostName, urlComponents.nPort,
2174                              userName, password, dwFlags, dwContext, INET_OPENURL);
2175         if(client == NULL)
2176             break;
2177         client1 = FtpOpenFileW(client, path, GENERIC_READ, dwFlags, dwContext);
2178         if(client1 == NULL) {
2179             InternetCloseHandle(client);
2180             break;
2181         }
2182         break;
2183         
2184     case INTERNET_SCHEME_HTTP:
2185     case INTERNET_SCHEME_HTTPS: {
2186         static const WCHAR szStars[] = { '*','/','*', 0 };
2187         LPCWSTR accept[2] = { szStars, NULL };
2188         if(urlComponents.nPort == 0) {
2189             if(urlComponents.nScheme == INTERNET_SCHEME_HTTP)
2190                 urlComponents.nPort = INTERNET_DEFAULT_HTTP_PORT;
2191             else
2192                 urlComponents.nPort = INTERNET_DEFAULT_HTTPS_PORT;
2193         }
2194         /* FIXME: should use pointers, not handles, as handles are not thread-safe */
2195         client = HTTP_Connect(hIC, hostName, urlComponents.nPort,
2196                               userName, password, dwFlags, dwContext, INET_OPENURL);
2197         if(client == NULL)
2198             break;
2199         client1 = HttpOpenRequestW(client, NULL, path, NULL, NULL, accept, dwFlags, dwContext);
2200         if(client1 == NULL) {
2201             InternetCloseHandle(client);
2202             break;
2203         }
2204         HttpAddRequestHeadersW(client1, lpszHeaders, dwHeadersLength, HTTP_ADDREQ_FLAG_ADD);
2205         if (!HttpSendRequestW(client1, NULL, 0, NULL, 0)) {
2206             InternetCloseHandle(client1);
2207             client1 = NULL;
2208             break;
2209         }
2210     }
2211     case INTERNET_SCHEME_GOPHER:
2212         /* gopher doesn't seem to be implemented in wine, but it's supposed
2213          * to be supported by InternetOpenUrlA. */
2214     default:
2215         break;
2216     }
2217
2218     TRACE(" %p <--\n", client1);
2219     
2220     return client1;
2221 }
2222
2223 /**********************************************************
2224  *      InternetOpenUrlW (WININET.@)
2225  *
2226  * Opens an URL
2227  *
2228  * RETURNS
2229  *   handle of connection or NULL on failure
2230  */
2231 HINTERNET WINAPI InternetOpenUrlW(HINTERNET hInternet, LPCWSTR lpszUrl,
2232     LPCWSTR lpszHeaders, DWORD dwHeadersLength, DWORD dwFlags, DWORD dwContext)
2233 {
2234     HINTERNET ret = NULL;
2235     LPWININETAPPINFOW hIC = NULL;
2236
2237     TRACE("(%p, %s, %s, %08lx, %08lx, %08lx\n", hInternet, debugstr_w(lpszUrl), debugstr_w(lpszHeaders),
2238           dwHeadersLength, dwFlags, dwContext);
2239  
2240     hIC = (LPWININETAPPINFOW) WININET_GetObject( hInternet );
2241     if (NULL == hIC ||  hIC->hdr.htype != WH_HINIT) {
2242         INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
2243         goto lend;
2244     }
2245     
2246     if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC) {
2247         WORKREQUEST workRequest;
2248         struct WORKREQ_INTERNETOPENURLW *req;
2249         
2250         workRequest.asyncall = INTERNETOPENURLW;
2251         workRequest.hdr = WININET_AddRef( &hIC->hdr );
2252         req = &workRequest.u.InternetOpenUrlW;
2253         if (lpszUrl)
2254             req->lpszUrl = WININET_strdupW(lpszUrl);
2255         else
2256             req->lpszUrl = 0;
2257         if (lpszHeaders)
2258             req->lpszHeaders = WININET_strdupW(lpszHeaders);
2259         else
2260             req->lpszHeaders = 0;
2261         req->dwHeadersLength = dwHeadersLength;
2262         req->dwFlags = dwFlags;
2263         req->dwContext = dwContext;
2264         
2265         INTERNET_AsyncCall(&workRequest);
2266         /*
2267          * This is from windows.
2268          */
2269         SetLastError(ERROR_IO_PENDING);
2270     } else {
2271         ret = INTERNET_InternetOpenUrlW(hIC, lpszUrl, lpszHeaders, dwHeadersLength, dwFlags, dwContext);
2272     }
2273     
2274   lend:
2275     if( hIC )
2276         WININET_Release( &hIC->hdr );
2277     TRACE(" %p <--\n", ret);
2278     
2279     return ret;
2280 }
2281
2282 /**********************************************************
2283  *      InternetOpenUrlA (WININET.@)
2284  *
2285  * Opens an URL
2286  *
2287  * RETURNS
2288  *   handle of connection or NULL on failure
2289  */
2290 HINTERNET WINAPI InternetOpenUrlA(HINTERNET hInternet, LPCSTR lpszUrl,
2291     LPCSTR lpszHeaders, DWORD dwHeadersLength, DWORD dwFlags, DWORD dwContext)
2292 {
2293     HINTERNET rc = (HINTERNET)NULL;
2294
2295     INT lenUrl;
2296     INT lenHeaders = 0;
2297     LPWSTR szUrl = NULL;
2298     LPWSTR szHeaders = NULL;
2299
2300     TRACE("\n");
2301
2302     if(lpszUrl) {
2303         lenUrl = MultiByteToWideChar(CP_ACP, 0, lpszUrl, -1, NULL, 0 );
2304         szUrl = HeapAlloc(GetProcessHeap(), 0, lenUrl*sizeof(WCHAR));
2305         if(!szUrl)
2306             return (HINTERNET)NULL;
2307         MultiByteToWideChar(CP_ACP, 0, lpszUrl, -1, szUrl, lenUrl);
2308     }
2309     
2310     if(lpszHeaders) {
2311         lenHeaders = MultiByteToWideChar(CP_ACP, 0, lpszHeaders, dwHeadersLength, NULL, 0 );
2312         szHeaders = HeapAlloc(GetProcessHeap(), 0, lenHeaders*sizeof(WCHAR));
2313         if(!szHeaders) {
2314             if(szUrl) HeapFree(GetProcessHeap(), 0, szUrl);
2315             return (HINTERNET)NULL;
2316         }
2317         MultiByteToWideChar(CP_ACP, 0, lpszHeaders, dwHeadersLength, szHeaders, lenHeaders);
2318     }
2319     
2320     rc = InternetOpenUrlW(hInternet, szUrl, szHeaders,
2321         lenHeaders, dwFlags, dwContext);
2322
2323     if(szUrl) HeapFree(GetProcessHeap(), 0, szUrl);
2324     if(szHeaders) HeapFree(GetProcessHeap(), 0, szHeaders);
2325
2326     return rc;
2327 }
2328
2329
2330 /***********************************************************************
2331  *           INTERNET_SetLastError (internal)
2332  *
2333  * Set last thread specific error
2334  *
2335  * RETURNS
2336  *
2337  */
2338 void INTERNET_SetLastError(DWORD dwError)
2339 {
2340     LPWITHREADERROR lpwite = (LPWITHREADERROR)TlsGetValue(g_dwTlsErrIndex);
2341
2342     SetLastError(dwError);
2343     if(lpwite)
2344         lpwite->dwError = dwError;
2345 }
2346
2347
2348 /***********************************************************************
2349  *           INTERNET_GetLastError (internal)
2350  *
2351  * Get last thread specific error
2352  *
2353  * RETURNS
2354  *
2355  */
2356 DWORD INTERNET_GetLastError()
2357 {
2358     LPWITHREADERROR lpwite = (LPWITHREADERROR)TlsGetValue(g_dwTlsErrIndex);
2359     return lpwite->dwError;
2360 }
2361
2362
2363 /***********************************************************************
2364  *           INTERNET_WorkerThreadFunc (internal)
2365  *
2366  * Worker thread execution function
2367  *
2368  * RETURNS
2369  *
2370  */
2371 DWORD INTERNET_WorkerThreadFunc(LPVOID *lpvParam)
2372 {
2373     DWORD dwWaitRes;
2374
2375     while (1)
2376     {
2377         if(dwNumJobs > 0) {
2378             INTERNET_ExecuteWork();
2379             continue;
2380         }
2381         dwWaitRes = WaitForMultipleObjects(2, hEventArray, FALSE, MAX_IDLE_WORKER);
2382
2383         if (dwWaitRes == WAIT_OBJECT_0 + 1)
2384             INTERNET_ExecuteWork();
2385         else
2386             break;
2387
2388         InterlockedIncrement(&dwNumIdleThreads);
2389     }
2390
2391     InterlockedDecrement(&dwNumIdleThreads);
2392     InterlockedDecrement(&dwNumThreads);
2393     TRACE("Worker thread exiting\n");
2394     return TRUE;
2395 }
2396
2397
2398 /***********************************************************************
2399  *           INTERNET_InsertWorkRequest (internal)
2400  *
2401  * Insert work request into queue
2402  *
2403  * RETURNS
2404  *
2405  */
2406 BOOL INTERNET_InsertWorkRequest(LPWORKREQUEST lpWorkRequest)
2407 {
2408     BOOL bSuccess = FALSE;
2409     LPWORKREQUEST lpNewRequest;
2410
2411     TRACE("\n");
2412
2413     lpNewRequest = HeapAlloc(GetProcessHeap(), 0, sizeof(WORKREQUEST));
2414     if (lpNewRequest)
2415     {
2416         memcpy(lpNewRequest, lpWorkRequest, sizeof(WORKREQUEST));
2417         lpNewRequest->prev = NULL;
2418
2419         EnterCriticalSection(&csQueue);
2420
2421         lpNewRequest->next = lpWorkQueueTail;
2422         if (lpWorkQueueTail)
2423             lpWorkQueueTail->prev = lpNewRequest;
2424         lpWorkQueueTail = lpNewRequest;
2425         if (!lpHeadWorkQueue)
2426             lpHeadWorkQueue = lpWorkQueueTail;
2427
2428         LeaveCriticalSection(&csQueue);
2429
2430         bSuccess = TRUE;
2431         InterlockedIncrement(&dwNumJobs);
2432     }
2433
2434     return bSuccess;
2435 }
2436
2437
2438 /***********************************************************************
2439  *           INTERNET_GetWorkRequest (internal)
2440  *
2441  * Retrieves work request from queue
2442  *
2443  * RETURNS
2444  *
2445  */
2446 BOOL INTERNET_GetWorkRequest(LPWORKREQUEST lpWorkRequest)
2447 {
2448     BOOL bSuccess = FALSE;
2449     LPWORKREQUEST lpRequest = NULL;
2450
2451     TRACE("\n");
2452
2453     EnterCriticalSection(&csQueue);
2454
2455     if (lpHeadWorkQueue)
2456     {
2457         lpRequest = lpHeadWorkQueue;
2458         lpHeadWorkQueue = lpHeadWorkQueue->prev;
2459         if (lpRequest == lpWorkQueueTail)
2460             lpWorkQueueTail = lpHeadWorkQueue;
2461     }
2462
2463     LeaveCriticalSection(&csQueue);
2464
2465     if (lpRequest)
2466     {
2467         memcpy(lpWorkRequest, lpRequest, sizeof(WORKREQUEST));
2468         HeapFree(GetProcessHeap(), 0, lpRequest);
2469         bSuccess = TRUE;
2470         InterlockedDecrement(&dwNumJobs);
2471     }
2472
2473     return bSuccess;
2474 }
2475
2476
2477 /***********************************************************************
2478  *           INTERNET_AsyncCall (internal)
2479  *
2480  * Retrieves work request from queue
2481  *
2482  * RETURNS
2483  *
2484  */
2485 BOOL INTERNET_AsyncCall(LPWORKREQUEST lpWorkRequest)
2486 {
2487     HANDLE hThread;
2488     DWORD dwTID;
2489     BOOL bSuccess = FALSE;
2490
2491     TRACE("\n");
2492
2493     if (InterlockedDecrement(&dwNumIdleThreads) < 0)
2494     {
2495         InterlockedIncrement(&dwNumIdleThreads);
2496
2497         if (InterlockedIncrement(&dwNumThreads) > MAX_WORKER_THREADS ||
2498             !(hThread = CreateThread(NULL, 0,
2499             (LPTHREAD_START_ROUTINE)INTERNET_WorkerThreadFunc, NULL, 0, &dwTID)))
2500         {
2501             InterlockedDecrement(&dwNumThreads);
2502             INTERNET_SetLastError(ERROR_INTERNET_ASYNC_THREAD_FAILED);
2503             goto lerror;
2504         }
2505
2506         TRACE("Created new thread\n");
2507     }
2508
2509     bSuccess = TRUE;
2510     INTERNET_InsertWorkRequest(lpWorkRequest);
2511     SetEvent(hWorkEvent);
2512
2513 lerror:
2514
2515     return bSuccess;
2516 }
2517
2518
2519 /***********************************************************************
2520  *           INTERNET_ExecuteWork (internal)
2521  *
2522  * RETURNS
2523  *
2524  */
2525 static VOID INTERNET_ExecuteWork()
2526 {
2527     WORKREQUEST workRequest;
2528
2529     TRACE("\n");
2530
2531     if (!INTERNET_GetWorkRequest(&workRequest))
2532         return;
2533
2534     switch (workRequest.asyncall)
2535     {
2536     case FTPPUTFILEW:
2537         {
2538         struct WORKREQ_FTPPUTFILEW *req = &workRequest.u.FtpPutFileW;
2539         LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest.hdr;
2540
2541         TRACE("FTPPUTFILEW %p\n", lpwfs);
2542
2543         FTP_FtpPutFileW(lpwfs, req->lpszLocalFile,
2544                    req->lpszNewRemoteFile, req->dwFlags, req->dwContext);
2545
2546         HeapFree(GetProcessHeap(), 0, req->lpszLocalFile);
2547         HeapFree(GetProcessHeap(), 0, req->lpszNewRemoteFile);
2548         }
2549         break;
2550
2551     case FTPSETCURRENTDIRECTORYW:
2552         {
2553         struct WORKREQ_FTPSETCURRENTDIRECTORYW *req;
2554         LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest.hdr;
2555
2556         TRACE("FTPSETCURRENTDIRECTORYW %p\n", lpwfs);
2557
2558         req = &workRequest.u.FtpSetCurrentDirectoryW;
2559         FTP_FtpSetCurrentDirectoryW(lpwfs, req->lpszDirectory);
2560         HeapFree(GetProcessHeap(), 0, req->lpszDirectory);
2561         }
2562         break;
2563
2564     case FTPCREATEDIRECTORYW:
2565         {
2566         struct WORKREQ_FTPCREATEDIRECTORYW *req;
2567         LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest.hdr;
2568
2569         TRACE("FTPCREATEDIRECTORYW %p\n", lpwfs);
2570
2571         req = &workRequest.u.FtpCreateDirectoryW;
2572         FTP_FtpCreateDirectoryW(lpwfs, req->lpszDirectory);
2573         HeapFree(GetProcessHeap(), 0, req->lpszDirectory);
2574         }
2575         break;
2576
2577     case FTPFINDFIRSTFILEW:
2578         {
2579         struct WORKREQ_FTPFINDFIRSTFILEW *req;
2580         LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest.hdr;
2581
2582         TRACE("FTPFINDFIRSTFILEW %p\n", lpwfs);
2583
2584         req = &workRequest.u.FtpFindFirstFileW;
2585         FTP_FtpFindFirstFileW(lpwfs, req->lpszSearchFile,
2586            req->lpFindFileData, req->dwFlags, req->dwContext);
2587         if (req->lpszSearchFile != NULL)
2588             HeapFree(GetProcessHeap(), 0, req->lpszSearchFile);
2589         }
2590         break;
2591
2592     case FTPGETCURRENTDIRECTORYW:
2593         {
2594         struct WORKREQ_FTPGETCURRENTDIRECTORYW *req;
2595         LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest.hdr;
2596
2597         TRACE("FTPGETCURRENTDIRECTORYW %p\n", lpwfs);
2598
2599         req = &workRequest.u.FtpGetCurrentDirectoryW;
2600         FTP_FtpGetCurrentDirectoryW(lpwfs,
2601                 req->lpszDirectory, req->lpdwDirectory);
2602         }
2603         break;
2604
2605     case FTPOPENFILEW:
2606         {
2607         struct WORKREQ_FTPOPENFILEW *req = &workRequest.u.FtpOpenFileW;
2608         LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest.hdr;
2609
2610         TRACE("FTPOPENFILEW %p\n", lpwfs);
2611
2612         FTP_FtpOpenFileW(lpwfs, req->lpszFilename,
2613             req->dwAccess, req->dwFlags, req->dwContext);
2614         HeapFree(GetProcessHeap(), 0, req->lpszFilename);
2615         }
2616         break;
2617
2618     case FTPGETFILEW:
2619         {
2620         struct WORKREQ_FTPGETFILEW *req = &workRequest.u.FtpGetFileW;
2621         LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest.hdr;
2622
2623         TRACE("FTPGETFILEW %p\n", lpwfs);
2624
2625         FTP_FtpGetFileW(lpwfs, req->lpszRemoteFile,
2626                  req->lpszNewFile, req->fFailIfExists,
2627                  req->dwLocalFlagsAttribute, req->dwFlags, req->dwContext);
2628         HeapFree(GetProcessHeap(), 0, req->lpszRemoteFile);
2629         HeapFree(GetProcessHeap(), 0, req->lpszNewFile);
2630         }
2631         break;
2632
2633     case FTPDELETEFILEW:
2634         {
2635         struct WORKREQ_FTPDELETEFILEW *req = &workRequest.u.FtpDeleteFileW;
2636         LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest.hdr;
2637
2638         TRACE("FTPDELETEFILEW %p\n", lpwfs);
2639
2640         FTP_FtpDeleteFileW(lpwfs, req->lpszFilename);
2641         HeapFree(GetProcessHeap(), 0, req->lpszFilename);
2642         }
2643         break;
2644
2645     case FTPREMOVEDIRECTORYW:
2646         {
2647         struct WORKREQ_FTPREMOVEDIRECTORYW *req;
2648         LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest.hdr;
2649
2650         TRACE("FTPREMOVEDIRECTORYW %p\n", lpwfs);
2651
2652         req = &workRequest.u.FtpRemoveDirectoryW;
2653         FTP_FtpRemoveDirectoryW(lpwfs, req->lpszDirectory);
2654         HeapFree(GetProcessHeap(), 0, req->lpszDirectory);
2655         }
2656         break;
2657
2658     case FTPRENAMEFILEW:
2659         {
2660         struct WORKREQ_FTPRENAMEFILEW *req = &workRequest.u.FtpRenameFileW;
2661         LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest.hdr;
2662
2663         TRACE("FTPRENAMEFILEW %p\n", lpwfs);
2664
2665         FTP_FtpRenameFileW(lpwfs, req->lpszSrcFile, req->lpszDestFile);
2666         HeapFree(GetProcessHeap(), 0, req->lpszSrcFile);
2667         HeapFree(GetProcessHeap(), 0, req->lpszDestFile);
2668         }
2669         break;
2670
2671     case INTERNETFINDNEXTW:
2672         {
2673         struct WORKREQ_INTERNETFINDNEXTW *req;
2674         LPWININETFINDNEXTW lpwh = (LPWININETFINDNEXTW) workRequest.hdr;
2675
2676         TRACE("INTERNETFINDNEXTW %p\n", lpwh);
2677
2678         req = &workRequest.u.InternetFindNextW;
2679         INTERNET_FindNextFileW(lpwh, req->lpFindFileData);
2680         }
2681         break;
2682
2683     case HTTPSENDREQUESTW:
2684         {
2685         struct WORKREQ_HTTPSENDREQUESTW *req = &workRequest.u.HttpSendRequestW;
2686         LPWININETHTTPREQW lpwhr = (LPWININETHTTPREQW) workRequest.hdr;
2687
2688         TRACE("HTTPSENDREQUESTW %p\n", lpwhr);
2689
2690         HTTP_HttpSendRequestW(lpwhr, req->lpszHeader,
2691                 req->dwHeaderLength, req->lpOptional, req->dwOptionalLength);
2692
2693         HeapFree(GetProcessHeap(), 0, req->lpszHeader);
2694         }
2695         break;
2696
2697     case HTTPOPENREQUESTW:
2698         {
2699         struct WORKREQ_HTTPOPENREQUESTW *req = &workRequest.u.HttpOpenRequestW;
2700         LPWININETHTTPSESSIONW lpwhs = (LPWININETHTTPSESSIONW) workRequest.hdr;
2701
2702         TRACE("HTTPOPENREQUESTW %p\n", lpwhs);
2703
2704         HTTP_HttpOpenRequestW(lpwhs, req->lpszVerb,
2705             req->lpszObjectName, req->lpszVersion, req->lpszReferrer,
2706             req->lpszAcceptTypes, req->dwFlags, req->dwContext);
2707
2708         HeapFree(GetProcessHeap(), 0, req->lpszVerb);
2709         HeapFree(GetProcessHeap(), 0, req->lpszObjectName);
2710         HeapFree(GetProcessHeap(), 0, req->lpszVersion);
2711         HeapFree(GetProcessHeap(), 0, req->lpszReferrer);
2712         }
2713         break;
2714
2715     case SENDCALLBACK:
2716         {
2717         struct WORKREQ_SENDCALLBACK *req = &workRequest.u.SendCallback;
2718         LPWININETAPPINFOW hIC = (LPWININETAPPINFOW) workRequest.hdr;
2719
2720         TRACE("SENDCALLBACK %p\n", hIC);
2721
2722         SendAsyncCallbackInt(hIC, req->hdr,
2723                 req->dwContext, req->dwInternetStatus, req->lpvStatusInfo,
2724                 req->dwStatusInfoLength);
2725         }
2726         break;
2727
2728     case INTERNETOPENURLW:
2729         {
2730         struct WORKREQ_INTERNETOPENURLW *req = &workRequest.u.InternetOpenUrlW;
2731         LPWININETAPPINFOW hIC = (LPWININETAPPINFOW) workRequest.hdr;
2732         
2733         TRACE("INTERNETOPENURLW %p\n", hIC);
2734
2735         INTERNET_InternetOpenUrlW(hIC, req->lpszUrl,
2736                                   req->lpszHeaders, req->dwHeadersLength, req->dwFlags, req->dwContext);
2737         HeapFree(GetProcessHeap(), 0, req->lpszUrl);
2738         HeapFree(GetProcessHeap(), 0, req->lpszHeaders);
2739         }
2740         break;
2741     }
2742     WININET_Release( workRequest.hdr );
2743 }
2744
2745
2746 /***********************************************************************
2747  *          INTERNET_GetResponseBuffer
2748  *
2749  * RETURNS
2750  *
2751  */
2752 LPSTR INTERNET_GetResponseBuffer()
2753 {
2754     LPWITHREADERROR lpwite = (LPWITHREADERROR)TlsGetValue(g_dwTlsErrIndex);
2755     TRACE("\n");
2756     return lpwite->response;
2757 }
2758
2759 /***********************************************************************
2760  *           INTERNET_GetNextLine  (internal)
2761  *
2762  * Parse next line in directory string listing
2763  *
2764  * RETURNS
2765  *   Pointer to beginning of next line
2766  *   NULL on failure
2767  *
2768  */
2769
2770 LPSTR INTERNET_GetNextLine(INT nSocket, LPDWORD dwLen)
2771 {
2772     struct timeval tv;
2773     fd_set infd;
2774     BOOL bSuccess = FALSE;
2775     INT nRecv = 0;
2776     LPSTR lpszBuffer = INTERNET_GetResponseBuffer();
2777
2778     TRACE("\n");
2779
2780     FD_ZERO(&infd);
2781     FD_SET(nSocket, &infd);
2782     tv.tv_sec=RESPONSE_TIMEOUT;
2783     tv.tv_usec=0;
2784
2785     while (nRecv < MAX_REPLY_LEN)
2786     {
2787         if (select(nSocket+1,&infd,NULL,NULL,&tv) > 0)
2788         {
2789             if (recv(nSocket, &lpszBuffer[nRecv], 1, 0) <= 0)
2790             {
2791                 INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS);
2792                 goto lend;
2793             }
2794
2795             if (lpszBuffer[nRecv] == '\n')
2796             {
2797                 bSuccess = TRUE;
2798                 break;
2799             }
2800             if (lpszBuffer[nRecv] != '\r')
2801                 nRecv++;
2802         }
2803         else
2804         {
2805             INTERNET_SetLastError(ERROR_INTERNET_TIMEOUT);
2806             goto lend;
2807         }
2808     }
2809
2810 lend:
2811     if (bSuccess)
2812     {
2813         lpszBuffer[nRecv] = '\0';
2814         *dwLen = nRecv - 1;
2815         TRACE(":%d %s\n", nRecv, lpszBuffer);
2816         return lpszBuffer;
2817     }
2818     else
2819     {
2820         return NULL;
2821     }
2822 }
2823
2824 /***********************************************************************
2825  *
2826  */
2827 BOOL WINAPI InternetQueryDataAvailable( HINTERNET hFile,
2828                                 LPDWORD lpdwNumberOfBytesAvailble,
2829                                 DWORD dwFlags, DWORD dwConext)
2830 {
2831     LPWININETHTTPREQW lpwhr;
2832     INT retval = -1;
2833     char buffer[4048];
2834
2835     lpwhr = (LPWININETHTTPREQW) WININET_GetObject( hFile );
2836     if (NULL == lpwhr)
2837     {
2838         SetLastError(ERROR_NO_MORE_FILES);
2839         return FALSE;
2840     }
2841
2842     TRACE("-->  %p %i\n",lpwhr,lpwhr->hdr.htype);
2843
2844     switch (lpwhr->hdr.htype)
2845     {
2846     case WH_HHTTPREQ:
2847         if (!NETCON_recv(&lpwhr->netConnection, buffer,
2848                          4048, MSG_PEEK, (int *)lpdwNumberOfBytesAvailble))
2849         {
2850             SetLastError(ERROR_NO_MORE_FILES);
2851             retval = FALSE;
2852         }
2853         else
2854             retval = TRUE;
2855         break;
2856
2857     default:
2858         FIXME("unsupported file type\n");
2859         break;
2860     }
2861     WININET_Release( &lpwhr->hdr );
2862
2863     TRACE("<-- %i\n",retval);
2864     return (retval+1);
2865 }
2866
2867
2868 /***********************************************************************
2869  *
2870  */
2871 BOOL WINAPI InternetLockRequestFile( HINTERNET hInternet, HANDLE
2872 *lphLockReqHandle)
2873 {
2874     FIXME("STUB\n");
2875     return FALSE;
2876 }
2877
2878 BOOL WINAPI InternetUnlockRequestFile( HANDLE hLockHandle)
2879 {
2880     FIXME("STUB\n");
2881     return FALSE;
2882 }
2883
2884
2885 /***********************************************************************
2886  *           InternetAutodial
2887  *
2888  * On windows this function is supposed to dial the default internet
2889  * connection. We don't want to have Wine dial out to the internet so
2890  * we return TRUE by default. It might be nice to check if we are connected.
2891  *
2892  * RETURNS
2893  *   TRUE on success
2894  *   FALSE on failure
2895  *
2896  */
2897 BOOL WINAPI InternetAutodial(DWORD dwFlags, HWND hwndParent)
2898 {
2899     FIXME("STUB\n");
2900
2901     /* Tell that we are connected to the internet. */
2902     return TRUE;
2903 }
2904
2905 /***********************************************************************
2906  *           InternetAutodialHangup
2907  *
2908  * Hangs up an connection made with InternetAutodial
2909  *
2910  * PARAM
2911  *    dwReserved
2912  * RETURNS
2913  *   TRUE on success
2914  *   FALSE on failure
2915  *
2916  */
2917 BOOL WINAPI InternetAutodialHangup(DWORD dwReserved)
2918 {
2919     FIXME("STUB\n");
2920
2921     /* we didn't dial, we don't disconnect */
2922     return TRUE;
2923 }
2924
2925 /***********************************************************************
2926  *
2927  *         InternetCombineUrlA
2928  *
2929  * Combine a base URL with a relative URL
2930  *
2931  * RETURNS
2932  *   TRUE on success
2933  *   FALSE on failure
2934  *
2935  */
2936
2937 BOOL WINAPI InternetCombineUrlA(LPCSTR lpszBaseUrl, LPCSTR lpszRelativeUrl,
2938                                 LPSTR lpszBuffer, LPDWORD lpdwBufferLength,
2939                                 DWORD dwFlags)
2940 {
2941     HRESULT hr=S_OK;
2942
2943     TRACE("(%s, %s, %p, %p, 0x%08lx)\n", debugstr_a(lpszBaseUrl), debugstr_a(lpszRelativeUrl), lpszBuffer, lpdwBufferLength, dwFlags);
2944
2945     /* Flip this bit to correspond to URL_ESCAPE_UNSAFE */
2946     dwFlags ^= ICU_NO_ENCODE;
2947     hr=UrlCombineA(lpszBaseUrl,lpszRelativeUrl,lpszBuffer,lpdwBufferLength,dwFlags);
2948
2949     return (hr==S_OK);
2950 }
2951
2952 /***********************************************************************
2953  *
2954  *         InternetCombineUrlW
2955  *
2956  * Combine a base URL with a relative URL
2957  *
2958  * RETURNS
2959  *   TRUE on success
2960  *   FALSE on failure
2961  *
2962  */
2963
2964 BOOL WINAPI InternetCombineUrlW(LPCWSTR lpszBaseUrl, LPCWSTR lpszRelativeUrl,
2965                                 LPWSTR lpszBuffer, LPDWORD lpdwBufferLength,
2966                                 DWORD dwFlags)
2967 {
2968     HRESULT hr=S_OK;
2969
2970     TRACE("(%s, %s, %p, %p, 0x%08lx)\n", debugstr_w(lpszBaseUrl), debugstr_w(lpszRelativeUrl), lpszBuffer, lpdwBufferLength, dwFlags);
2971
2972     /* Flip this bit to correspond to URL_ESCAPE_UNSAFE */
2973     dwFlags ^= ICU_NO_ENCODE;
2974     hr=UrlCombineW(lpszBaseUrl,lpszRelativeUrl,lpszBuffer,lpdwBufferLength,dwFlags);
2975
2976     return (hr==S_OK);
2977 }
2978
2979 /***********************************************************************
2980  *
2981  *         InternetCreateUrlA
2982  *
2983  * RETURNS
2984  *   TRUE on success
2985  *   FALSE on failure
2986  *
2987  */
2988 BOOL WINAPI InternetCreateUrlA(LPURL_COMPONENTSA lpUrlComponents, DWORD dwFlags,
2989                                LPSTR lpszUrl, LPDWORD lpdwUrlLength)
2990 {
2991     FIXME("\n");
2992     return FALSE;
2993 }
2994
2995 /***********************************************************************
2996  *
2997  *         InternetCreateUrlW
2998  *
2999  * RETURNS
3000  *   TRUE on success
3001  *   FALSE on failure
3002  *
3003  */
3004 BOOL WINAPI InternetCreateUrlW(LPURL_COMPONENTSW lpUrlComponents, DWORD dwFlags,
3005                                LPWSTR lpszUrl, LPDWORD lpdwUrlLength)
3006 {
3007     FIXME("\n");
3008     return FALSE;
3009 }