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