Added more implementation of IDocumentView.
[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  * RETURNS
1199  *    TRUE on success
1200  *    FALSE on failure
1201  *
1202  */
1203 static BOOL SetUrlComponentValueW(LPWSTR* lppszComponent, LPDWORD dwComponentLen, LPCWSTR lpszStart, DWORD len)
1204 {
1205     TRACE("%s (%ld)\n", debugstr_wn(lpszStart,len), len);
1206
1207     if ( (*dwComponentLen == 0) && (*lppszComponent == NULL) )
1208         return FALSE;
1209
1210     if (*dwComponentLen != 0 || *lppszComponent == NULL)
1211     {
1212         if (*lppszComponent == NULL)
1213         {
1214             *lppszComponent = (LPWSTR)lpszStart;
1215             *dwComponentLen = len;
1216         }
1217         else
1218         {
1219             DWORD ncpylen = min((*dwComponentLen)-1, len);
1220             strncpyW(*lppszComponent, lpszStart, ncpylen);
1221             (*lppszComponent)[ncpylen] = '\0';
1222             *dwComponentLen = ncpylen;
1223         }
1224     }
1225
1226     return TRUE;
1227 }
1228
1229 /***********************************************************************
1230  *           InternetCrackUrlW   (WININET.@)
1231  */
1232 BOOL WINAPI InternetCrackUrlW(LPCWSTR lpszUrl, DWORD dwUrlLength, DWORD dwFlags,
1233                               LPURL_COMPONENTSW lpUC)
1234 {
1235   /*
1236    * RFC 1808
1237    * <protocol>:[//<net_loc>][/path][;<params>][?<query>][#<fragment>]
1238    *
1239    */
1240     LPCWSTR lpszParam    = NULL;
1241     BOOL  bIsAbsolute = FALSE;
1242     LPCWSTR lpszap = lpszUrl;
1243     LPCWSTR lpszcp = NULL;
1244     const WCHAR lpszSeparators[3]={';','?',0};
1245     const WCHAR lpszSlash[2]={'/',0};
1246     if(dwUrlLength==0)
1247         dwUrlLength=strlenW(lpszUrl);
1248
1249     TRACE("(%s %lu %lx %p)\n", debugstr_w(lpszUrl), dwUrlLength, dwFlags, lpUC);
1250
1251     /* Determine if the URI is absolute. */
1252     while (*lpszap != '\0')
1253     {
1254         if (isalnumW(*lpszap))
1255         {
1256             lpszap++;
1257             continue;
1258         }
1259         if ((*lpszap == ':') && (lpszap - lpszUrl >= 2))
1260         {
1261             bIsAbsolute = TRUE;
1262             lpszcp = lpszap;
1263         }
1264         else
1265         {
1266             lpszcp = lpszUrl; /* Relative url */
1267         }
1268
1269         break;
1270     }
1271
1272     /* Parse <params> */
1273     lpszParam = strpbrkW(lpszap, lpszSeparators);
1274     if (lpszParam != NULL)
1275     {
1276         SetUrlComponentValueW(&lpUC->lpszExtraInfo, &lpUC->dwExtraInfoLength,
1277                                    lpszParam, dwUrlLength-(lpszParam-lpszUrl));
1278     }
1279
1280     if (bIsAbsolute) /* Parse <protocol>:[//<net_loc>] */
1281     {
1282         LPCWSTR lpszNetLoc;
1283         static const WCHAR wszAbout[]={'a','b','o','u','t',':',0};
1284
1285         /* Get scheme first. */
1286         lpUC->nScheme = GetInternetSchemeW(lpszUrl, lpszcp - lpszUrl);
1287         SetUrlComponentValueW(&lpUC->lpszScheme, &lpUC->dwSchemeLength,
1288                                    lpszUrl, lpszcp - lpszUrl);
1289
1290         /* Eat ':' in protocol. */
1291         lpszcp++;
1292
1293         /* if the scheme is "about", there is no host */
1294         if(strncmpW(wszAbout,lpszUrl, lpszcp - lpszUrl)==0)
1295         {
1296             SetUrlComponentValueW(&lpUC->lpszUserName, &lpUC->dwUserNameLength, NULL, 0);
1297             SetUrlComponentValueW(&lpUC->lpszPassword, &lpUC->dwPasswordLength, NULL, 0);
1298             SetUrlComponentValueW(&lpUC->lpszHostName, &lpUC->dwHostNameLength, NULL, 0);
1299             lpUC->nPort = 0;
1300         }
1301         else
1302         {
1303             /* Skip over slashes. */
1304             if (*lpszcp == '/')
1305             {
1306                 lpszcp++;
1307                 if (*lpszcp == '/')
1308                 {
1309                     lpszcp++;
1310                     if (*lpszcp == '/')
1311                         lpszcp++;
1312                 }
1313             }
1314
1315             lpszNetLoc = strpbrkW(lpszcp, lpszSlash);
1316             if (lpszParam)
1317             {
1318                 if (lpszNetLoc)
1319                     lpszNetLoc = min(lpszNetLoc, lpszParam);
1320                 else
1321                     lpszNetLoc = lpszParam;
1322             }
1323             else if (!lpszNetLoc)
1324                 lpszNetLoc = lpszcp + dwUrlLength-(lpszcp-lpszUrl);
1325
1326             /* Parse net-loc */
1327             if (lpszNetLoc)
1328             {
1329                 LPCWSTR lpszHost;
1330                 LPCWSTR lpszPort;
1331
1332                 /* [<user>[<:password>]@]<host>[:<port>] */
1333                 /* First find the user and password if they exist */
1334
1335                 lpszHost = strchrW(lpszcp, '@');
1336                 if (lpszHost == NULL || lpszHost > lpszNetLoc)
1337                 {
1338                     /* username and password not specified. */
1339                     SetUrlComponentValueW(&lpUC->lpszUserName, &lpUC->dwUserNameLength, NULL, 0);
1340                     SetUrlComponentValueW(&lpUC->lpszPassword, &lpUC->dwPasswordLength, NULL, 0);
1341                 }
1342                 else /* Parse out username and password */
1343                 {
1344                     LPCWSTR lpszUser = lpszcp;
1345                     LPCWSTR lpszPasswd = lpszHost;
1346
1347                     while (lpszcp < lpszHost)
1348                     {
1349                         if (*lpszcp == ':')
1350                             lpszPasswd = lpszcp;
1351
1352                         lpszcp++;
1353                     }
1354
1355                     SetUrlComponentValueW(&lpUC->lpszUserName, &lpUC->dwUserNameLength,
1356                                           lpszUser, lpszPasswd - lpszUser);
1357
1358                     if (lpszPasswd != lpszHost)
1359                         lpszPasswd++;
1360                     SetUrlComponentValueW(&lpUC->lpszPassword, &lpUC->dwPasswordLength,
1361                                           lpszPasswd == lpszHost ? NULL : lpszPasswd,
1362                                           lpszHost - lpszPasswd);
1363
1364                     lpszcp++; /* Advance to beginning of host */
1365                 }
1366
1367                 /* Parse <host><:port> */
1368
1369                 lpszHost = lpszcp;
1370                 lpszPort = lpszNetLoc;
1371
1372                 /* special case for res:// URLs: there is no port here, so the host is the
1373                    entire string up to the first '/' */
1374                 if(lpUC->nScheme==INTERNET_SCHEME_RES)
1375                 {
1376                     SetUrlComponentValueW(&lpUC->lpszHostName, &lpUC->dwHostNameLength,
1377                                           lpszHost, lpszPort - lpszHost);
1378                     lpUC->nPort = 0;
1379                     lpszcp=lpszNetLoc;
1380                 }
1381                 else
1382                 {
1383                     while (lpszcp < lpszNetLoc)
1384                     {
1385                         if (*lpszcp == ':')
1386                             lpszPort = lpszcp;
1387
1388                         lpszcp++;
1389                     }
1390
1391                     /* If the scheme is "file" and the host is just one letter, it's not a host */
1392                     if(lpUC->nScheme==INTERNET_SCHEME_FILE && (lpszPort-lpszHost)==1)
1393                     {
1394                         lpszcp=lpszHost;
1395                         SetUrlComponentValueW(&lpUC->lpszHostName, &lpUC->dwHostNameLength,
1396                                               NULL, 0);
1397                         lpUC->nPort = 0;
1398                     }
1399                     else
1400                     {
1401                         SetUrlComponentValueW(&lpUC->lpszHostName, &lpUC->dwHostNameLength,
1402                                               lpszHost, lpszPort - lpszHost);
1403                         if (lpszPort != lpszNetLoc)
1404                             lpUC->nPort = atoiW(++lpszPort);
1405                         else
1406                             lpUC->nPort = 0;
1407                     }
1408                 }
1409             }
1410         }
1411     }
1412
1413     /* Here lpszcp points to:
1414      *
1415      * <protocol>:[//<net_loc>][/path][;<params>][?<query>][#<fragment>]
1416      *                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1417      */
1418     if (lpszcp != 0 && *lpszcp != '\0' && (!lpszParam || lpszcp < lpszParam))
1419     {
1420         INT len;
1421
1422         /* Only truncate the parameter list if it's already been saved
1423          * in lpUC->lpszExtraInfo.
1424          */
1425         if (lpszParam && lpUC->dwExtraInfoLength && lpUC->lpszExtraInfo)
1426             len = lpszParam - lpszcp;
1427         else
1428         {
1429             /* Leave the parameter list in lpszUrlPath.  Strip off any trailing
1430              * newlines if necessary.
1431              */
1432             LPWSTR lpsznewline = strchrW(lpszcp, '\n');
1433             if (lpsznewline != NULL)
1434                 len = lpsznewline - lpszcp;
1435             else
1436                 len = dwUrlLength-(lpszcp-lpszUrl);
1437         }
1438
1439         SetUrlComponentValueW(&lpUC->lpszUrlPath, &lpUC->dwUrlPathLength,
1440                                    lpszcp, len);
1441     }
1442     else
1443     {
1444         lpUC->dwUrlPathLength = 0;
1445     }
1446
1447     TRACE("%s: host(%s) path(%s) extra(%s)\n", debugstr_wn(lpszUrl,dwUrlLength),
1448              debugstr_wn(lpUC->lpszHostName,lpUC->dwHostNameLength),
1449              debugstr_wn(lpUC->lpszUrlPath,lpUC->dwUrlPathLength),
1450              debugstr_wn(lpUC->lpszExtraInfo,lpUC->dwExtraInfoLength));
1451
1452     return TRUE;
1453 }
1454
1455 /***********************************************************************
1456  *           InternetAttemptConnect (WININET.@)
1457  *
1458  * Attempt to make a connection to the internet
1459  *
1460  * RETURNS
1461  *    ERROR_SUCCESS on success
1462  *    Error value   on failure
1463  *
1464  */
1465 DWORD WINAPI InternetAttemptConnect(DWORD dwReserved)
1466 {
1467     FIXME("Stub\n");
1468     return ERROR_SUCCESS;
1469 }
1470
1471
1472 /***********************************************************************
1473  *           InternetCanonicalizeUrlA (WININET.@)
1474  *
1475  * Escape unsafe characters and spaces
1476  *
1477  * RETURNS
1478  *    TRUE on success
1479  *    FALSE on failure
1480  *
1481  */
1482 BOOL WINAPI InternetCanonicalizeUrlA(LPCSTR lpszUrl, LPSTR lpszBuffer,
1483         LPDWORD lpdwBufferLength, DWORD dwFlags)
1484 {
1485     HRESULT hr;
1486     TRACE("%s %p %p %08lx\n",debugstr_a(lpszUrl), lpszBuffer,
1487           lpdwBufferLength, dwFlags);
1488
1489     /* Flip this bit to correspond to URL_ESCAPE_UNSAFE */
1490     dwFlags ^= ICU_NO_ENCODE;
1491
1492     dwFlags |= 0x80000000; /* Don't know what this means */
1493
1494     hr = UrlCanonicalizeA(lpszUrl, lpszBuffer, lpdwBufferLength, dwFlags);
1495
1496     return (hr == S_OK) ? TRUE : FALSE;
1497 }
1498
1499 /***********************************************************************
1500  *           InternetCanonicalizeUrlW (WININET.@)
1501  *
1502  * Escape unsafe characters and spaces
1503  *
1504  * RETURNS
1505  *    TRUE on success
1506  *    FALSE on failure
1507  *
1508  */
1509 BOOL WINAPI InternetCanonicalizeUrlW(LPCWSTR lpszUrl, LPWSTR lpszBuffer,
1510     LPDWORD lpdwBufferLength, DWORD dwFlags)
1511 {
1512     HRESULT hr;
1513     TRACE("%s %p %p %08lx\n", debugstr_w(lpszUrl), lpszBuffer,
1514         lpdwBufferLength, dwFlags);
1515
1516     /* Flip this bit to correspond to URL_ESCAPE_UNSAFE */
1517     dwFlags ^= ICU_NO_ENCODE;
1518
1519     dwFlags |= 0x80000000; /* Don't know what this means */
1520
1521     hr = UrlCanonicalizeW(lpszUrl, lpszBuffer, lpdwBufferLength, dwFlags);
1522
1523     return (hr == S_OK) ? TRUE : FALSE;
1524 }
1525
1526
1527 /***********************************************************************
1528  *           InternetSetStatusCallbackA (WININET.@)
1529  *
1530  * Sets up a callback function which is called as progress is made
1531  * during an operation.
1532  *
1533  * RETURNS
1534  *    Previous callback or NULL         on success
1535  *    INTERNET_INVALID_STATUS_CALLBACK  on failure
1536  *
1537  */
1538 INTERNET_STATUS_CALLBACK WINAPI InternetSetStatusCallbackA(
1539         HINTERNET hInternet ,INTERNET_STATUS_CALLBACK lpfnIntCB)
1540 {
1541     INTERNET_STATUS_CALLBACK retVal;
1542     LPWININETHANDLEHEADER lpwh;
1543
1544     TRACE("0x%08lx\n", (ULONG)hInternet);
1545     
1546     lpwh = WININET_GetObject(hInternet);
1547     if (!lpwh)
1548         return INTERNET_INVALID_STATUS_CALLBACK;
1549
1550     lpwh->dwInternalFlags &= ~INET_CALLBACKW;
1551     retVal = lpwh->lpfnStatusCB;
1552     lpwh->lpfnStatusCB = lpfnIntCB;
1553
1554     WININET_Release( lpwh );
1555
1556     return retVal;
1557 }
1558
1559 /***********************************************************************
1560  *           InternetSetStatusCallbackW (WININET.@)
1561  *
1562  * Sets up a callback function which is called as progress is made
1563  * during an operation.
1564  *
1565  * RETURNS
1566  *    Previous callback or NULL         on success
1567  *    INTERNET_INVALID_STATUS_CALLBACK  on failure
1568  *
1569  */
1570 INTERNET_STATUS_CALLBACK WINAPI InternetSetStatusCallbackW(
1571         HINTERNET hInternet ,INTERNET_STATUS_CALLBACK lpfnIntCB)
1572 {
1573     INTERNET_STATUS_CALLBACK retVal;
1574     LPWININETHANDLEHEADER lpwh;
1575
1576     TRACE("0x%08lx\n", (ULONG)hInternet);
1577     
1578     lpwh = WININET_GetObject(hInternet);
1579     if (!lpwh)
1580         return INTERNET_INVALID_STATUS_CALLBACK;
1581
1582     lpwh->dwInternalFlags |= INET_CALLBACKW;
1583     retVal = lpwh->lpfnStatusCB;
1584     lpwh->lpfnStatusCB = lpfnIntCB;
1585
1586     WININET_Release( lpwh );
1587
1588     return retVal;
1589 }
1590
1591 /***********************************************************************
1592  *           InternetSetFilePointer (WININET.@)
1593  */
1594 DWORD WINAPI InternetSetFilePointer(HINTERNET f1, LONG f2, PVOID f3, DWORD f4, DWORD f5)
1595 {
1596     FIXME("stub\n");
1597     return FALSE;
1598 }
1599
1600 /***********************************************************************
1601  *           InternetWriteFile (WININET.@)
1602  *
1603  * Write data to an open internet file
1604  *
1605  * RETURNS
1606  *    TRUE  on success
1607  *    FALSE on failure
1608  *
1609  */
1610 BOOL WINAPI InternetWriteFile(HINTERNET hFile, LPCVOID lpBuffer ,
1611         DWORD dwNumOfBytesToWrite, LPDWORD lpdwNumOfBytesWritten)
1612 {
1613     BOOL retval = FALSE;
1614     int nSocket = -1;
1615     LPWININETHANDLEHEADER lpwh;
1616
1617     TRACE("\n");
1618     lpwh = (LPWININETHANDLEHEADER) WININET_GetObject( hFile );
1619     if (NULL == lpwh)
1620         return FALSE;
1621
1622     switch (lpwh->htype)
1623     {
1624         case WH_HHTTPREQ:
1625             FIXME("This shouldn't be here! We don't support this kind"
1626                   " of connection anymore. Must use NETCON functions,"
1627                   " especially if using SSL\n");
1628             nSocket = ((LPWININETHTTPREQW)lpwh)->netConnection.socketFD;
1629             break;
1630
1631         case WH_HFILE:
1632             nSocket = ((LPWININETFILE)lpwh)->nDataSocket;
1633             break;
1634
1635         default:
1636             break;
1637     }
1638
1639     if (nSocket != -1)
1640     {
1641         int res = send(nSocket, lpBuffer, dwNumOfBytesToWrite, 0);
1642         retval = (res >= 0);
1643         *lpdwNumOfBytesWritten = retval ? res : 0;
1644     }
1645     WININET_Release( lpwh );
1646
1647     return retval;
1648 }
1649
1650
1651 /***********************************************************************
1652  *           InternetReadFile (WININET.@)
1653  *
1654  * Read data from an open internet file
1655  *
1656  * RETURNS
1657  *    TRUE  on success
1658  *    FALSE on failure
1659  *
1660  */
1661 BOOL WINAPI InternetReadFile(HINTERNET hFile, LPVOID lpBuffer,
1662         DWORD dwNumOfBytesToRead, LPDWORD dwNumOfBytesRead)
1663 {
1664     BOOL retval = FALSE;
1665     int nSocket = -1;
1666     LPWININETHANDLEHEADER lpwh;
1667
1668     TRACE("%p %p %ld %p\n", hFile, lpBuffer, dwNumOfBytesToRead, dwNumOfBytesRead);
1669
1670     lpwh = (LPWININETHANDLEHEADER) WININET_GetObject( hFile );
1671     if (NULL == lpwh)
1672         return FALSE;
1673
1674     /* FIXME: this should use NETCON functions! */
1675     switch (lpwh->htype)
1676     {
1677         case WH_HHTTPREQ:
1678             if (!NETCON_recv(&((LPWININETHTTPREQW)lpwh)->netConnection, lpBuffer,
1679                              dwNumOfBytesToRead, MSG_WAITALL, (int *)dwNumOfBytesRead))
1680             {
1681                 *dwNumOfBytesRead = 0;
1682                 retval = TRUE; /* Under windows, it seems to return 0 even if nothing was read... */
1683             }
1684             else
1685                 retval = TRUE;
1686             break;
1687
1688         case WH_HFILE:
1689             /* FIXME: FTP should use NETCON_ stuff */
1690             nSocket = ((LPWININETFILE)lpwh)->nDataSocket;
1691             if (nSocket != -1)
1692             {
1693                 int res = recv(nSocket, lpBuffer, dwNumOfBytesToRead, MSG_WAITALL);
1694                 retval = (res >= 0);
1695                 *dwNumOfBytesRead = retval ? res : 0;
1696             }
1697             break;
1698
1699         default:
1700             break;
1701     }
1702     WININET_Release( lpwh );
1703
1704     TRACE("-- %s (bytes read: %ld)\n", retval ? "TRUE": "FALSE", dwNumOfBytesRead ? *dwNumOfBytesRead : -1);
1705     return retval;
1706 }
1707
1708 /***********************************************************************
1709  *           InternetReadFileExA (WININET.@)
1710  *
1711  * Read data from an open internet file
1712  *
1713  * RETURNS
1714  *    TRUE  on success
1715  *    FALSE on failure
1716  *
1717  */
1718 BOOL WINAPI InternetReadFileExA(HINTERNET hFile, LPINTERNET_BUFFERSA lpBuffer,
1719         DWORD dwFlags, DWORD dwContext)
1720 {
1721   FIXME("stub\n");
1722   return FALSE;
1723 }
1724
1725 /***********************************************************************
1726  *           InternetReadFileExW (WININET.@)
1727  *
1728  * Read data from an open internet file
1729  *
1730  * RETURNS
1731  *    TRUE  on success
1732  *    FALSE on failure
1733  *
1734  */
1735 BOOL WINAPI InternetReadFileExW(HINTERNET hFile, LPINTERNET_BUFFERSW lpBuffer,
1736         DWORD dwFlags, DWORD dwContext)
1737 {
1738   FIXME("stub\n");
1739
1740   INTERNET_SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1741   return FALSE;
1742 }
1743
1744 /***********************************************************************
1745  *           INET_QueryOptionHelper (internal)
1746  */
1747 static BOOL INET_QueryOptionHelper(BOOL bIsUnicode, HINTERNET hInternet, DWORD dwOption,
1748                                    LPVOID lpBuffer, LPDWORD lpdwBufferLength)
1749 {
1750     LPWININETHANDLEHEADER lpwhh;
1751     BOOL bSuccess = FALSE;
1752
1753     TRACE("(%p, 0x%08lx, %p, %p)\n", hInternet, dwOption, lpBuffer, lpdwBufferLength);
1754
1755     lpwhh = (LPWININETHANDLEHEADER) WININET_GetObject( hInternet );
1756
1757     switch (dwOption)
1758     {
1759         case INTERNET_OPTION_HANDLE_TYPE:
1760         {
1761             ULONG type;
1762
1763             if (!lpwhh)
1764             {
1765                 WARN("Invalid hInternet handle\n");
1766                 SetLastError(ERROR_INVALID_HANDLE);
1767                 return FALSE;
1768             }
1769
1770             type = lpwhh->htype;
1771
1772             TRACE("INTERNET_OPTION_HANDLE_TYPE: %ld\n", type);
1773
1774             if (*lpdwBufferLength < sizeof(ULONG))
1775                 INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
1776             else
1777             {
1778                 memcpy(lpBuffer, &type, sizeof(ULONG));
1779                 bSuccess = TRUE;
1780             }
1781             *lpdwBufferLength = sizeof(ULONG);
1782             break;
1783         }
1784
1785         case INTERNET_OPTION_REQUEST_FLAGS:
1786         {
1787             ULONG flags = 4;
1788             TRACE("INTERNET_OPTION_REQUEST_FLAGS: %ld\n", flags);
1789             if (*lpdwBufferLength < sizeof(ULONG))
1790                 INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
1791             else
1792             {
1793                 memcpy(lpBuffer, &flags, sizeof(ULONG));
1794                 bSuccess = TRUE;
1795             }
1796             *lpdwBufferLength = sizeof(ULONG);
1797             break;
1798         }
1799
1800         case INTERNET_OPTION_URL:
1801         case INTERNET_OPTION_DATAFILE_NAME:
1802         {
1803             if (!lpwhh)
1804             {
1805                 WARN("Invalid hInternet handle\n");
1806                 SetLastError(ERROR_INVALID_HANDLE);
1807                 return FALSE;
1808             }
1809             if (lpwhh->htype == WH_HHTTPREQ)
1810             {
1811                 LPWININETHTTPREQW lpreq = (LPWININETHTTPREQW) lpwhh;
1812                 WCHAR url[1023];
1813                 static const WCHAR szFmt[] = {'h','t','t','p',':','/','/','%','s','%','s',0};
1814                 DWORD sizeRequired;
1815
1816                 sprintfW(url,szFmt,lpreq->StdHeaders[HTTP_QUERY_HOST].lpszValue,lpreq->lpszPath);
1817                 TRACE("INTERNET_OPTION_URL: %s\n",debugstr_w(url));
1818                 if(!bIsUnicode)
1819                 {
1820                     sizeRequired = WideCharToMultiByte(CP_ACP,0,url,-1,
1821                      lpBuffer,*lpdwBufferLength,NULL,NULL);
1822                     if (sizeRequired > *lpdwBufferLength)
1823                         INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
1824                     else
1825                         bSuccess = TRUE;
1826                     *lpdwBufferLength = sizeRequired;
1827                 }
1828                 else
1829                 {
1830                     sizeRequired = (lstrlenW(url)+1) * sizeof(WCHAR);
1831                     if (*lpdwBufferLength < sizeRequired)
1832                         INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
1833                     else
1834                     {
1835                         strcpyW(lpBuffer, url);
1836                         bSuccess = TRUE;
1837                     }
1838                     *lpdwBufferLength = sizeRequired;
1839                 }
1840             }
1841             break;
1842         }
1843         case INTERNET_OPTION_HTTP_VERSION:
1844         {
1845             if (*lpdwBufferLength < sizeof(HTTP_VERSION_INFO))
1846                 INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
1847             else
1848             {
1849                 /*
1850                  * Presently hardcoded to 1.1
1851                  */
1852                 ((HTTP_VERSION_INFO*)lpBuffer)->dwMajorVersion = 1;
1853                 ((HTTP_VERSION_INFO*)lpBuffer)->dwMinorVersion = 1;
1854                 bSuccess = TRUE;
1855             }
1856             *lpdwBufferLength = sizeof(HTTP_VERSION_INFO);
1857             break;
1858         }
1859        case INTERNET_OPTION_CONNECTED_STATE:
1860        {
1861             INTERNET_CONNECTED_INFO * pCi = (INTERNET_CONNECTED_INFO *)lpBuffer;
1862             FIXME("INTERNET_OPTION_CONNECTED_STATE: semi-stub\n");
1863
1864             if (*lpdwBufferLength < sizeof(INTERNET_CONNECTED_INFO))
1865                  INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
1866             else
1867             {
1868                 pCi->dwConnectedState = INTERNET_STATE_CONNECTED;
1869                 pCi->dwFlags = 0;
1870                 bSuccess = TRUE;
1871             }
1872             *lpdwBufferLength = sizeof(INTERNET_CONNECTED_INFO);
1873             break;
1874         }
1875         case INTERNET_OPTION_PROXY:
1876         {
1877             LPWININETAPPINFOW lpwai = (LPWININETAPPINFOW)lpwhh;
1878
1879             if (!lpwhh)
1880             {
1881                 WARN("Invalid hInternet handle\n");
1882                 SetLastError(ERROR_INVALID_HANDLE);
1883                 return FALSE;
1884             }
1885
1886             if (bIsUnicode)
1887             {
1888                 INTERNET_PROXY_INFOW *pPI = (INTERNET_PROXY_INFOW *)lpBuffer;
1889                 DWORD proxyBytesRequired = 0, proxyBypassBytesRequired = 0;
1890
1891                 if (lpwai->lpszProxy)
1892                     proxyBytesRequired = (lstrlenW(lpwai->lpszProxy) + 1) *
1893                      sizeof(WCHAR);
1894                 if (lpwai->lpszProxyBypass)
1895                     proxyBypassBytesRequired =
1896                      (lstrlenW(lpwai->lpszProxyBypass) + 1) * sizeof(WCHAR);
1897                 if (*lpdwBufferLength < sizeof(INTERNET_PROXY_INFOW) +
1898                  proxyBytesRequired + proxyBypassBytesRequired)
1899                     INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
1900                 else
1901                 {
1902                     pPI->dwAccessType = lpwai->dwAccessType;
1903                     if (lpwai->lpszProxy)
1904                     {
1905                         pPI->lpszProxy = (LPWSTR)((LPBYTE)lpBuffer +
1906                          sizeof(INTERNET_PROXY_INFOW));
1907                         lstrcpyW((LPWSTR)pPI->lpszProxy, lpwai->lpszProxy);
1908                     }
1909                     else
1910                         pPI->lpszProxy = NULL;
1911                     if (lpwai->lpszProxyBypass)
1912                     {
1913                         pPI->lpszProxyBypass = (LPWSTR)((LPBYTE)lpBuffer +
1914                          sizeof(INTERNET_PROXY_INFOW) + proxyBytesRequired);
1915                         lstrcpyW((LPWSTR)pPI->lpszProxyBypass,
1916                          lpwai->lpszProxyBypass);
1917                     }
1918                     else
1919                         pPI->lpszProxyBypass = NULL;
1920                     bSuccess = TRUE;
1921                 }
1922                 *lpdwBufferLength = sizeof(INTERNET_PROXY_INFOW) +
1923                  proxyBytesRequired + proxyBypassBytesRequired;
1924             }
1925             else
1926             {
1927                 INTERNET_PROXY_INFOA *pPI = (INTERNET_PROXY_INFOA *)lpBuffer;
1928                 DWORD proxyBytesRequired = 0, proxyBypassBytesRequired = 0;
1929
1930                 if (lpwai->lpszProxy)
1931                     proxyBytesRequired = WideCharToMultiByte(CP_ACP, 0,
1932                      lpwai->lpszProxy, -1, NULL, 0, NULL, NULL);
1933                 if (lpwai->lpszProxyBypass)
1934                     proxyBypassBytesRequired = WideCharToMultiByte(CP_ACP, 0,
1935                      lpwai->lpszProxyBypass, -1, NULL, 0, NULL, NULL);
1936                 if (*lpdwBufferLength < sizeof(INTERNET_PROXY_INFOA) +
1937                  proxyBytesRequired + proxyBypassBytesRequired)
1938                     INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
1939                 else
1940                 {
1941                     pPI->dwAccessType = lpwai->dwAccessType;
1942                     FIXME("INTERNET_OPTION_PROXY: Stub\n");
1943                     if (lpwai->lpszProxy)
1944                     {
1945                         pPI->lpszProxy = (LPSTR)((LPBYTE)lpBuffer +
1946                          sizeof(INTERNET_PROXY_INFOA));
1947                         WideCharToMultiByte(CP_ACP, 0, lpwai->lpszProxy, -1,
1948                          (LPSTR)pPI->lpszProxy, proxyBytesRequired, NULL, NULL);
1949                     }
1950                     else
1951                         pPI->lpszProxy = NULL;
1952                     if (lpwai->lpszProxyBypass)
1953                     {
1954                         pPI->lpszProxyBypass = (LPSTR)((LPBYTE)lpBuffer +
1955                          sizeof(INTERNET_PROXY_INFOA) + proxyBytesRequired);
1956                         WideCharToMultiByte(CP_ACP, 0, lpwai->lpszProxyBypass,
1957                          -1, (LPSTR)pPI->lpszProxyBypass,
1958                          proxyBypassBytesRequired,
1959                          NULL, NULL);
1960                     }
1961                     else
1962                         pPI->lpszProxyBypass = NULL;
1963                     bSuccess = TRUE;
1964                 }
1965                 *lpdwBufferLength = sizeof(INTERNET_PROXY_INFOA) +
1966                  proxyBytesRequired + proxyBypassBytesRequired;
1967             }
1968             break;
1969         }
1970         case INTERNET_OPTION_SECURITY_FLAGS:
1971             FIXME("INTERNET_OPTION_SECURITY_FLAGS: Stub\n");
1972             break;
1973
1974         default:
1975             FIXME("Stub! %ld \n",dwOption);
1976             break;
1977     }
1978     if (lpwhh)
1979         WININET_Release( lpwhh );
1980
1981     return bSuccess;
1982 }
1983
1984 /***********************************************************************
1985  *           InternetQueryOptionW (WININET.@)
1986  *
1987  * Queries an options on the specified handle
1988  *
1989  * RETURNS
1990  *    TRUE  on success
1991  *    FALSE on failure
1992  *
1993  */
1994 BOOL WINAPI InternetQueryOptionW(HINTERNET hInternet, DWORD dwOption,
1995                                  LPVOID lpBuffer, LPDWORD lpdwBufferLength)
1996 {
1997     return INET_QueryOptionHelper(TRUE, hInternet, dwOption, lpBuffer, lpdwBufferLength);
1998 }
1999
2000 /***********************************************************************
2001  *           InternetQueryOptionA (WININET.@)
2002  *
2003  * Queries an options on the specified handle
2004  *
2005  * RETURNS
2006  *    TRUE  on success
2007  *    FALSE on failure
2008  *
2009  */
2010 BOOL WINAPI InternetQueryOptionA(HINTERNET hInternet, DWORD dwOption,
2011                                  LPVOID lpBuffer, LPDWORD lpdwBufferLength)
2012 {
2013     return INET_QueryOptionHelper(FALSE, hInternet, dwOption, lpBuffer, lpdwBufferLength);
2014 }
2015
2016
2017 /***********************************************************************
2018  *           InternetSetOptionW (WININET.@)
2019  *
2020  * Sets an options on the specified handle
2021  *
2022  * RETURNS
2023  *    TRUE  on success
2024  *    FALSE on failure
2025  *
2026  */
2027 BOOL WINAPI InternetSetOptionW(HINTERNET hInternet, DWORD dwOption,
2028                            LPVOID lpBuffer, DWORD dwBufferLength)
2029 {
2030     LPWININETHANDLEHEADER lpwhh;
2031     BOOL ret = TRUE;
2032
2033     TRACE("0x%08lx\n", dwOption);
2034
2035     lpwhh = (LPWININETHANDLEHEADER) WININET_GetObject( hInternet );
2036     if( !lpwhh )
2037         return FALSE;
2038
2039     switch (dwOption)
2040     {
2041     case INTERNET_OPTION_HTTP_VERSION:
2042       {
2043         HTTP_VERSION_INFO* pVersion=(HTTP_VERSION_INFO*)lpBuffer;
2044         FIXME("Option INTERNET_OPTION_HTTP_VERSION(%ld,%ld): STUB\n",pVersion->dwMajorVersion,pVersion->dwMinorVersion);
2045       }
2046       break;
2047     case INTERNET_OPTION_ERROR_MASK:
2048       {
2049         unsigned long flags=*(unsigned long*)lpBuffer;
2050         FIXME("Option INTERNET_OPTION_ERROR_MASK(%ld): STUB\n",flags);
2051       }
2052       break;
2053     case INTERNET_OPTION_CODEPAGE:
2054       {
2055         unsigned long codepage=*(unsigned long*)lpBuffer;
2056         FIXME("Option INTERNET_OPTION_CODEPAGE (%ld): STUB\n",codepage);
2057       }
2058       break;
2059     case INTERNET_OPTION_REQUEST_PRIORITY:
2060       {
2061         unsigned long priority=*(unsigned long*)lpBuffer;
2062         FIXME("Option INTERNET_OPTION_REQUEST_PRIORITY (%ld): STUB\n",priority);
2063       }
2064       break;
2065     case INTERNET_OPTION_CONNECT_TIMEOUT:
2066       {
2067         unsigned long connecttimeout=*(unsigned long*)lpBuffer;
2068         FIXME("Option INTERNET_OPTION_CONNECT_TIMEOUT (%ld): STUB\n",connecttimeout);
2069       }
2070       break;
2071     case INTERNET_OPTION_DATA_RECEIVE_TIMEOUT:
2072       {
2073         unsigned long receivetimeout=*(unsigned long*)lpBuffer;
2074         FIXME("Option INTERNET_OPTION_DATA_RECEIVE_TIMEOUT (%ld): STUB\n",receivetimeout);
2075       }
2076       break;
2077     case INTERNET_OPTION_RESET_URLCACHE_SESSION:
2078         FIXME("Option INTERNET_OPTION_RESET_URLCACHE_SESSION: STUB\n");
2079         break;
2080     case INTERNET_OPTION_END_BROWSER_SESSION:
2081         FIXME("Option INTERNET_OPTION_END_BROWSER_SESSION: STUB\n");
2082         break;
2083     case INTERNET_OPTION_CONNECTED_STATE:
2084         FIXME("Option INTERNET_OPTION_CONNECTED_STATE: STUB\n");
2085         break;
2086     default:
2087         FIXME("Option %ld STUB\n",dwOption);
2088         INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
2089         ret = FALSE;
2090         break;
2091     }
2092     WININET_Release( lpwhh );
2093
2094     return TRUE;
2095 }
2096
2097
2098 /***********************************************************************
2099  *           InternetSetOptionA (WININET.@)
2100  *
2101  * Sets an options on the specified handle.
2102  *
2103  * RETURNS
2104  *    TRUE  on success
2105  *    FALSE on failure
2106  *
2107  */
2108 BOOL WINAPI InternetSetOptionA(HINTERNET hInternet, DWORD dwOption,
2109                            LPVOID lpBuffer, DWORD dwBufferLength)
2110 {
2111     LPVOID wbuffer;
2112     DWORD wlen;
2113     BOOL r;
2114
2115     switch( dwOption )
2116     {
2117     case INTERNET_OPTION_PROXY:
2118         {
2119         LPINTERNET_PROXY_INFOA pi = (LPINTERNET_PROXY_INFOA) lpBuffer;
2120         LPINTERNET_PROXY_INFOW piw;
2121         DWORD proxlen, prbylen;
2122         LPWSTR prox, prby;
2123
2124         proxlen = MultiByteToWideChar( CP_ACP, 0, pi->lpszProxy, -1, NULL, 0);
2125         prbylen= MultiByteToWideChar( CP_ACP, 0, pi->lpszProxyBypass, -1, NULL, 0);
2126         wlen = sizeof(*piw) + proxlen + prbylen;
2127         wbuffer = HeapAlloc( GetProcessHeap(), 0, wlen*sizeof(WCHAR) );
2128         piw = (LPINTERNET_PROXY_INFOW) wbuffer;
2129         piw->dwAccessType = pi->dwAccessType;
2130         prox = (LPWSTR) &piw[1];
2131         prby = &prox[proxlen+1];
2132         MultiByteToWideChar( CP_ACP, 0, pi->lpszProxy, -1, prox, proxlen);
2133         MultiByteToWideChar( CP_ACP, 0, pi->lpszProxyBypass, -1, prby, prbylen);
2134         piw->lpszProxy = prox;
2135         piw->lpszProxyBypass = prby;
2136         }
2137         break;
2138     case INTERNET_OPTION_USER_AGENT:
2139     case INTERNET_OPTION_USERNAME:
2140     case INTERNET_OPTION_PASSWORD:
2141         wlen = MultiByteToWideChar( CP_ACP, 0, lpBuffer, dwBufferLength,
2142                                    NULL, 0 );
2143         wbuffer = HeapAlloc( GetProcessHeap(), 0, wlen*sizeof(WCHAR) );
2144         MultiByteToWideChar( CP_ACP, 0, lpBuffer, dwBufferLength,
2145                                    wbuffer, wlen );
2146         break;
2147     default:
2148         wbuffer = lpBuffer;
2149         wlen = dwBufferLength;
2150     }
2151
2152     r = InternetSetOptionW(hInternet,dwOption, wbuffer, wlen);
2153
2154     if( lpBuffer != wbuffer )
2155         HeapFree( GetProcessHeap(), 0, wbuffer );
2156
2157     return r;
2158 }
2159
2160
2161 /***********************************************************************
2162  *           InternetSetOptionExA (WININET.@)
2163  */
2164 BOOL WINAPI InternetSetOptionExA(HINTERNET hInternet, DWORD dwOption,
2165                            LPVOID lpBuffer, DWORD dwBufferLength, DWORD dwFlags)
2166 {
2167     FIXME("Flags %08lx ignored\n", dwFlags);
2168     return InternetSetOptionA( hInternet, dwOption, lpBuffer, dwBufferLength );
2169 }
2170
2171 /***********************************************************************
2172  *           InternetSetOptionExW (WININET.@)
2173  */
2174 BOOL WINAPI InternetSetOptionExW(HINTERNET hInternet, DWORD dwOption,
2175                            LPVOID lpBuffer, DWORD dwBufferLength, DWORD dwFlags)
2176 {
2177     FIXME("Flags %08lx ignored\n", dwFlags);
2178     if( dwFlags & ~ISO_VALID_FLAGS )
2179     {
2180         SetLastError( ERROR_INVALID_PARAMETER );
2181         return FALSE;
2182     }
2183     return InternetSetOptionW( hInternet, dwOption, lpBuffer, dwBufferLength );
2184 }
2185
2186 static const WCHAR WININET_wkday[7][4] =
2187     { { 'S','u','n', 0 }, { 'M','o','n', 0 }, { 'T','u','e', 0 }, { 'W','e','d', 0 },
2188       { 'T','h','u', 0 }, { 'F','r','i', 0 }, { 'S','a','t', 0 } };
2189 static const WCHAR WININET_month[12][4] =
2190     { { 'J','a','n', 0 }, { 'F','e','b', 0 }, { 'M','a','r', 0 }, { 'A','p','r', 0 },
2191       { 'M','a','y', 0 }, { 'J','u','n', 0 }, { 'J','u','l', 0 }, { 'A','u','g', 0 },
2192       { 'S','e','p', 0 }, { 'O','c','t', 0 }, { 'N','o','v', 0 }, { 'D','e','c', 0 } };
2193
2194 /***********************************************************************
2195  *           InternetTimeFromSystemTimeA (WININET.@)
2196  */
2197 BOOL WINAPI InternetTimeFromSystemTimeA( const SYSTEMTIME* time, DWORD format, LPSTR string, DWORD size )
2198 {
2199     BOOL ret;
2200     WCHAR stringW[INTERNET_RFC1123_BUFSIZE];
2201
2202     TRACE( "%p 0x%08lx %p 0x%08lx\n", time, format, string, size );
2203
2204     ret = InternetTimeFromSystemTimeW( time, format, stringW, sizeof(stringW) );
2205     if (ret) WideCharToMultiByte( CP_ACP, 0, stringW, -1, string, size, NULL, NULL );
2206
2207     return ret;
2208 }
2209
2210 /***********************************************************************
2211  *           InternetTimeFromSystemTimeW (WININET.@)
2212  */
2213 BOOL WINAPI InternetTimeFromSystemTimeW( const SYSTEMTIME* time, DWORD format, LPWSTR string, DWORD size )
2214 {
2215     static const WCHAR date[] =
2216         { '%','s',',',' ','%','0','2','d',' ','%','s',' ','%','4','d',' ','%','0',
2217           '2','d',':','%','0','2','d',':','%','0','2','d',' ','G','M','T', 0 };
2218
2219     TRACE( "%p 0x%08lx %p 0x%08lx\n", time, format, string, size );
2220
2221     if (!time || !string) return FALSE;
2222
2223     if (format != INTERNET_RFC1123_FORMAT || size < INTERNET_RFC1123_BUFSIZE * sizeof(WCHAR))
2224         return FALSE;
2225
2226     sprintfW( string, date,
2227               WININET_wkday[time->wDayOfWeek],
2228               time->wDay,
2229               WININET_month[time->wMonth - 1],
2230               time->wYear,
2231               time->wHour,
2232               time->wMinute,
2233               time->wSecond );
2234
2235     return TRUE;
2236 }
2237
2238 /***********************************************************************
2239  *           InternetTimeToSystemTimeA (WININET.@)
2240  */
2241 BOOL WINAPI InternetTimeToSystemTimeA( LPCSTR string, SYSTEMTIME* time, DWORD reserved )
2242 {
2243     BOOL ret = FALSE;
2244     WCHAR *stringW;
2245     int len;
2246
2247     TRACE( "%s %p 0x%08lx\n", debugstr_a(string), time, reserved );
2248
2249     len = MultiByteToWideChar( CP_ACP, 0, string, -1, NULL, 0 );
2250     stringW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
2251
2252     if (stringW)
2253     {
2254         MultiByteToWideChar( CP_ACP, 0, string, -1, stringW, len );
2255         ret = InternetTimeToSystemTimeW( stringW, time, reserved );
2256         HeapFree( GetProcessHeap(), 0, stringW );
2257     }
2258     return ret;
2259 }
2260
2261 /***********************************************************************
2262  *           InternetTimeToSystemTimeW (WININET.@)
2263  */
2264 BOOL WINAPI InternetTimeToSystemTimeW( LPCWSTR string, SYSTEMTIME* time, DWORD reserved )
2265 {
2266     unsigned int i;
2267     WCHAR *s = (LPWSTR)string;
2268
2269     TRACE( "%s %p 0x%08lx\n", debugstr_w(string), time, reserved );
2270
2271     if (!string || !time) return FALSE;
2272
2273     /* Windows does this too */
2274     GetSystemTime( time );
2275
2276     /*  Convert an RFC1123 time such as 'Fri, 07 Jan 2005 12:06:35 GMT' into
2277      *  a SYSTEMTIME structure.
2278      */
2279
2280     while (*s && !isalphaW( *s )) s++;
2281     if (s[0] == '\0' || s[1] == '\0' || s[2] == '\0') return TRUE;
2282     time->wDayOfWeek = 7;
2283
2284     for (i = 0; i < 7; i++)
2285     {
2286         if (toupperW( WININET_wkday[i][0] ) == toupperW( s[0] ) &&
2287             toupperW( WININET_wkday[i][1] ) == toupperW( s[1] ) &&
2288             toupperW( WININET_wkday[i][2] ) == toupperW( s[2] ) )
2289         {
2290             time->wDayOfWeek = i;
2291             break;
2292         }
2293     }
2294
2295     if (time->wDayOfWeek > 6) return TRUE;
2296     while (*s && !isdigitW( *s )) s++;
2297     time->wDay = strtolW( s, &s, 10 );
2298
2299     while (*s && !isalphaW( *s )) s++;
2300     if (s[0] == '\0' || s[1] == '\0' || s[2] == '\0') return TRUE;
2301     time->wMonth = 0;
2302
2303     for (i = 0; i < 12; i++)
2304     {
2305         if (toupperW( WININET_month[i][0]) == toupperW( s[0] ) &&
2306             toupperW( WININET_month[i][1]) == toupperW( s[1] ) &&
2307             toupperW( WININET_month[i][2]) == toupperW( s[2] ) )
2308         {
2309             time->wMonth = i + 1;
2310             break;
2311         }
2312     }
2313     if (time->wMonth == 0) return TRUE;
2314
2315     while (*s && !isdigitW( *s )) s++;
2316     if (*s == '\0') return TRUE;
2317     time->wYear = strtolW( s, &s, 10 );
2318
2319     while (*s && !isdigitW( *s )) s++;
2320     if (*s == '\0') return TRUE;
2321     time->wHour = strtolW( s, &s, 10 );
2322
2323     while (*s && !isdigitW( *s )) s++;
2324     if (*s == '\0') return TRUE;
2325     time->wMinute = strtolW( s, &s, 10 );
2326
2327     while (*s && !isdigitW( *s )) s++;
2328     if (*s == '\0') return TRUE;
2329     time->wSecond = strtolW( s, &s, 10 );
2330
2331     time->wMilliseconds = 0;
2332     return TRUE;
2333 }
2334
2335 /***********************************************************************
2336  *      InternetCheckConnectionA (WININET.@)
2337  *
2338  * Pings a requested host to check internet connection
2339  *
2340  * RETURNS
2341  *   TRUE on success and FALSE on failure. If a failure then
2342  *   ERROR_NOT_CONNECTED is placesd into GetLastError
2343  *
2344  */
2345 BOOL WINAPI InternetCheckConnectionA( LPCSTR lpszUrl, DWORD dwFlags, DWORD dwReserved )
2346 {
2347 /*
2348  * this is a kludge which runs the resident ping program and reads the output.
2349  *
2350  * Anyone have a better idea?
2351  */
2352
2353   BOOL   rc = FALSE;
2354   char command[1024];
2355   char host[1024];
2356   int status = -1;
2357
2358   FIXME("\n");
2359
2360   /*
2361    * Crack or set the Address
2362    */
2363   if (lpszUrl == NULL)
2364   {
2365      /*
2366       * According to the doc we are supost to use the ip for the next
2367       * server in the WnInet internal server database. I have
2368       * no idea what that is or how to get it.
2369       *
2370       * So someone needs to implement this.
2371       */
2372      FIXME("Unimplemented with URL of NULL\n");
2373      return TRUE;
2374   }
2375   else
2376   {
2377      URL_COMPONENTSA components;
2378
2379      ZeroMemory(&components,sizeof(URL_COMPONENTSA));
2380      components.lpszHostName = (LPSTR)&host;
2381      components.dwHostNameLength = 1024;
2382
2383      if (!InternetCrackUrlA(lpszUrl,0,0,&components))
2384        goto End;
2385
2386      TRACE("host name : %s\n",components.lpszHostName);
2387   }
2388
2389   /*
2390    * Build our ping command
2391    */
2392   strcpy(command,"ping -w 1 ");
2393   strcat(command,host);
2394   strcat(command," >/dev/null 2>/dev/null");
2395
2396   TRACE("Ping command is : %s\n",command);
2397
2398   status = system(command);
2399
2400   TRACE("Ping returned a code of %i \n",status);
2401
2402   /* Ping return code of 0 indicates success */
2403   if (status == 0)
2404      rc = TRUE;
2405
2406 End:
2407
2408   if (rc == FALSE)
2409     SetLastError(ERROR_NOT_CONNECTED);
2410
2411   return rc;
2412 }
2413
2414
2415 /***********************************************************************
2416  *      InternetCheckConnectionW (WININET.@)
2417  *
2418  * Pings a requested host to check internet connection
2419  *
2420  * RETURNS
2421  *   TRUE on success and FALSE on failure. If a failure then
2422  *   ERROR_NOT_CONNECTED is placed into GetLastError
2423  *
2424  */
2425 BOOL WINAPI InternetCheckConnectionW(LPCWSTR lpszUrl, DWORD dwFlags, DWORD dwReserved)
2426 {
2427     CHAR *szUrl;
2428     INT len;
2429     BOOL rc;
2430
2431     len = WideCharToMultiByte(CP_ACP, 0, lpszUrl, -1, NULL, 0, NULL, NULL);
2432     if (!(szUrl = HeapAlloc(GetProcessHeap(), 0, len*sizeof(CHAR))))
2433         return FALSE;
2434     WideCharToMultiByte(CP_ACP, 0, lpszUrl, -1, szUrl, len, NULL, NULL);
2435     rc = InternetCheckConnectionA((LPCSTR)szUrl, dwFlags, dwReserved);
2436     HeapFree(GetProcessHeap(), 0, szUrl);
2437     
2438     return rc;
2439 }
2440
2441
2442 /**********************************************************
2443  *      INTERNET_InternetOpenUrlW (internal)
2444  *
2445  * Opens an URL
2446  *
2447  * RETURNS
2448  *   handle of connection or NULL on failure
2449  */
2450 HINTERNET WINAPI INTERNET_InternetOpenUrlW(LPWININETAPPINFOW hIC, LPCWSTR lpszUrl,
2451     LPCWSTR lpszHeaders, DWORD dwHeadersLength, DWORD dwFlags, DWORD dwContext)
2452 {
2453     URL_COMPONENTSW urlComponents;
2454     WCHAR protocol[32], hostName[MAXHOSTNAME], userName[1024];
2455     WCHAR password[1024], path[2048], extra[1024];
2456     HINTERNET client = NULL, client1 = NULL;
2457     
2458     TRACE("(%p, %s, %s, %08lx, %08lx, %08lx)\n", hIC, debugstr_w(lpszUrl), debugstr_w(lpszHeaders),
2459           dwHeadersLength, dwFlags, dwContext);
2460     
2461     urlComponents.dwStructSize = sizeof(URL_COMPONENTSW);
2462     urlComponents.lpszScheme = protocol;
2463     urlComponents.dwSchemeLength = 32;
2464     urlComponents.lpszHostName = hostName;
2465     urlComponents.dwHostNameLength = MAXHOSTNAME;
2466     urlComponents.lpszUserName = userName;
2467     urlComponents.dwUserNameLength = 1024;
2468     urlComponents.lpszPassword = password;
2469     urlComponents.dwPasswordLength = 1024;
2470     urlComponents.lpszUrlPath = path;
2471     urlComponents.dwUrlPathLength = 2048;
2472     urlComponents.lpszExtraInfo = extra;
2473     urlComponents.dwExtraInfoLength = 1024;
2474     if(!InternetCrackUrlW(lpszUrl, strlenW(lpszUrl), 0, &urlComponents))
2475         return NULL;
2476     switch(urlComponents.nScheme) {
2477     case INTERNET_SCHEME_FTP:
2478         if(urlComponents.nPort == 0)
2479             urlComponents.nPort = INTERNET_DEFAULT_FTP_PORT;
2480         client = FTP_Connect(hIC, hostName, urlComponents.nPort,
2481                              userName, password, dwFlags, dwContext, INET_OPENURL);
2482         if(client == NULL)
2483             break;
2484         client1 = FtpOpenFileW(client, path, GENERIC_READ, dwFlags, dwContext);
2485         if(client1 == NULL) {
2486             InternetCloseHandle(client);
2487             break;
2488         }
2489         break;
2490         
2491     case INTERNET_SCHEME_HTTP:
2492     case INTERNET_SCHEME_HTTPS: {
2493         static const WCHAR szStars[] = { '*','/','*', 0 };
2494         LPCWSTR accept[2] = { szStars, NULL };
2495         if(urlComponents.nPort == 0) {
2496             if(urlComponents.nScheme == INTERNET_SCHEME_HTTP)
2497                 urlComponents.nPort = INTERNET_DEFAULT_HTTP_PORT;
2498             else
2499                 urlComponents.nPort = INTERNET_DEFAULT_HTTPS_PORT;
2500         }
2501         /* FIXME: should use pointers, not handles, as handles are not thread-safe */
2502         client = HTTP_Connect(hIC, hostName, urlComponents.nPort,
2503                               userName, password, dwFlags, dwContext, INET_OPENURL);
2504         if(client == NULL)
2505             break;
2506         client1 = HttpOpenRequestW(client, NULL, path, NULL, NULL, accept, dwFlags, dwContext);
2507         if(client1 == NULL) {
2508             InternetCloseHandle(client);
2509             break;
2510         }
2511         HttpAddRequestHeadersW(client1, lpszHeaders, dwHeadersLength, HTTP_ADDREQ_FLAG_ADD);
2512         if (!HttpSendRequestW(client1, NULL, 0, NULL, 0)) {
2513             InternetCloseHandle(client1);
2514             client1 = NULL;
2515             break;
2516         }
2517     }
2518     case INTERNET_SCHEME_GOPHER:
2519         /* gopher doesn't seem to be implemented in wine, but it's supposed
2520          * to be supported by InternetOpenUrlA. */
2521     default:
2522         break;
2523     }
2524
2525     TRACE(" %p <--\n", client1);
2526     
2527     return client1;
2528 }
2529
2530 /**********************************************************
2531  *      InternetOpenUrlW (WININET.@)
2532  *
2533  * Opens an URL
2534  *
2535  * RETURNS
2536  *   handle of connection or NULL on failure
2537  */
2538 HINTERNET WINAPI InternetOpenUrlW(HINTERNET hInternet, LPCWSTR lpszUrl,
2539     LPCWSTR lpszHeaders, DWORD dwHeadersLength, DWORD dwFlags, DWORD dwContext)
2540 {
2541     HINTERNET ret = NULL;
2542     LPWININETAPPINFOW hIC = NULL;
2543
2544     if (TRACE_ON(wininet)) {
2545         TRACE("(%p, %s, %s, %08lx, %08lx, %08lx)\n", hInternet, debugstr_w(lpszUrl), debugstr_w(lpszHeaders),
2546               dwHeadersLength, dwFlags, dwContext);
2547         TRACE("  flags :");
2548         dump_INTERNET_FLAGS(dwFlags);
2549     }
2550
2551     hIC = (LPWININETAPPINFOW) WININET_GetObject( hInternet );
2552     if (NULL == hIC ||  hIC->hdr.htype != WH_HINIT) {
2553         INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
2554         goto lend;
2555     }
2556     
2557     if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC) {
2558         WORKREQUEST workRequest;
2559         struct WORKREQ_INTERNETOPENURLW *req;
2560         
2561         workRequest.asyncall = INTERNETOPENURLW;
2562         workRequest.hdr = WININET_AddRef( &hIC->hdr );
2563         req = &workRequest.u.InternetOpenUrlW;
2564         if (lpszUrl)
2565             req->lpszUrl = WININET_strdupW(lpszUrl);
2566         else
2567             req->lpszUrl = 0;
2568         if (lpszHeaders)
2569             req->lpszHeaders = WININET_strdupW(lpszHeaders);
2570         else
2571             req->lpszHeaders = 0;
2572         req->dwHeadersLength = dwHeadersLength;
2573         req->dwFlags = dwFlags;
2574         req->dwContext = dwContext;
2575         
2576         INTERNET_AsyncCall(&workRequest);
2577         /*
2578          * This is from windows.
2579          */
2580         SetLastError(ERROR_IO_PENDING);
2581     } else {
2582         ret = INTERNET_InternetOpenUrlW(hIC, lpszUrl, lpszHeaders, dwHeadersLength, dwFlags, dwContext);
2583     }
2584     
2585   lend:
2586     if( hIC )
2587         WININET_Release( &hIC->hdr );
2588     TRACE(" %p <--\n", ret);
2589     
2590     return ret;
2591 }
2592
2593 /**********************************************************
2594  *      InternetOpenUrlA (WININET.@)
2595  *
2596  * Opens an URL
2597  *
2598  * RETURNS
2599  *   handle of connection or NULL on failure
2600  */
2601 HINTERNET WINAPI InternetOpenUrlA(HINTERNET hInternet, LPCSTR lpszUrl,
2602     LPCSTR lpszHeaders, DWORD dwHeadersLength, DWORD dwFlags, DWORD dwContext)
2603 {
2604     HINTERNET rc = (HINTERNET)NULL;
2605
2606     INT lenUrl;
2607     INT lenHeaders = 0;
2608     LPWSTR szUrl = NULL;
2609     LPWSTR szHeaders = NULL;
2610
2611     TRACE("\n");
2612
2613     if(lpszUrl) {
2614         lenUrl = MultiByteToWideChar(CP_ACP, 0, lpszUrl, -1, NULL, 0 );
2615         szUrl = HeapAlloc(GetProcessHeap(), 0, lenUrl*sizeof(WCHAR));
2616         if(!szUrl)
2617             return (HINTERNET)NULL;
2618         MultiByteToWideChar(CP_ACP, 0, lpszUrl, -1, szUrl, lenUrl);
2619     }
2620     
2621     if(lpszHeaders) {
2622         lenHeaders = MultiByteToWideChar(CP_ACP, 0, lpszHeaders, dwHeadersLength, NULL, 0 );
2623         szHeaders = HeapAlloc(GetProcessHeap(), 0, lenHeaders*sizeof(WCHAR));
2624         if(!szHeaders) {
2625             HeapFree(GetProcessHeap(), 0, szUrl);
2626             return (HINTERNET)NULL;
2627         }
2628         MultiByteToWideChar(CP_ACP, 0, lpszHeaders, dwHeadersLength, szHeaders, lenHeaders);
2629     }
2630     
2631     rc = InternetOpenUrlW(hInternet, szUrl, szHeaders,
2632         lenHeaders, dwFlags, dwContext);
2633
2634     HeapFree(GetProcessHeap(), 0, szUrl);
2635     HeapFree(GetProcessHeap(), 0, szHeaders);
2636
2637     return rc;
2638 }
2639
2640
2641 /***********************************************************************
2642  *           INTERNET_SetLastError (internal)
2643  *
2644  * Set last thread specific error
2645  *
2646  * RETURNS
2647  *
2648  */
2649 void INTERNET_SetLastError(DWORD dwError)
2650 {
2651     LPWITHREADERROR lpwite = (LPWITHREADERROR)TlsGetValue(g_dwTlsErrIndex);
2652
2653     SetLastError(dwError);
2654     if(lpwite)
2655         lpwite->dwError = dwError;
2656 }
2657
2658
2659 /***********************************************************************
2660  *           INTERNET_GetLastError (internal)
2661  *
2662  * Get last thread specific error
2663  *
2664  * RETURNS
2665  *
2666  */
2667 DWORD INTERNET_GetLastError(void)
2668 {
2669     LPWITHREADERROR lpwite = (LPWITHREADERROR)TlsGetValue(g_dwTlsErrIndex);
2670     return lpwite->dwError;
2671 }
2672
2673
2674 /***********************************************************************
2675  *           INTERNET_WorkerThreadFunc (internal)
2676  *
2677  * Worker thread execution function
2678  *
2679  * RETURNS
2680  *
2681  */
2682 static DWORD INTERNET_WorkerThreadFunc(LPVOID *lpvParam)
2683 {
2684     DWORD dwWaitRes;
2685
2686     while (1)
2687     {
2688         if(dwNumJobs > 0) {
2689             INTERNET_ExecuteWork();
2690             continue;
2691         }
2692         dwWaitRes = WaitForMultipleObjects(2, hEventArray, FALSE, MAX_IDLE_WORKER);
2693
2694         if (dwWaitRes == WAIT_OBJECT_0 + 1)
2695             INTERNET_ExecuteWork();
2696         else
2697             break;
2698
2699         InterlockedIncrement(&dwNumIdleThreads);
2700     }
2701
2702     InterlockedDecrement(&dwNumIdleThreads);
2703     InterlockedDecrement(&dwNumThreads);
2704     TRACE("Worker thread exiting\n");
2705     return TRUE;
2706 }
2707
2708
2709 /***********************************************************************
2710  *           INTERNET_InsertWorkRequest (internal)
2711  *
2712  * Insert work request into queue
2713  *
2714  * RETURNS
2715  *
2716  */
2717 static BOOL INTERNET_InsertWorkRequest(LPWORKREQUEST lpWorkRequest)
2718 {
2719     BOOL bSuccess = FALSE;
2720     LPWORKREQUEST lpNewRequest;
2721
2722     TRACE("\n");
2723
2724     lpNewRequest = HeapAlloc(GetProcessHeap(), 0, sizeof(WORKREQUEST));
2725     if (lpNewRequest)
2726     {
2727         memcpy(lpNewRequest, lpWorkRequest, sizeof(WORKREQUEST));
2728         lpNewRequest->prev = NULL;
2729
2730         EnterCriticalSection(&csQueue);
2731
2732         lpNewRequest->next = lpWorkQueueTail;
2733         if (lpWorkQueueTail)
2734             lpWorkQueueTail->prev = lpNewRequest;
2735         lpWorkQueueTail = lpNewRequest;
2736         if (!lpHeadWorkQueue)
2737             lpHeadWorkQueue = lpWorkQueueTail;
2738
2739         LeaveCriticalSection(&csQueue);
2740
2741         bSuccess = TRUE;
2742         InterlockedIncrement(&dwNumJobs);
2743     }
2744
2745     return bSuccess;
2746 }
2747
2748
2749 /***********************************************************************
2750  *           INTERNET_GetWorkRequest (internal)
2751  *
2752  * Retrieves work request from queue
2753  *
2754  * RETURNS
2755  *
2756  */
2757 static BOOL INTERNET_GetWorkRequest(LPWORKREQUEST lpWorkRequest)
2758 {
2759     BOOL bSuccess = FALSE;
2760     LPWORKREQUEST lpRequest = NULL;
2761
2762     TRACE("\n");
2763
2764     EnterCriticalSection(&csQueue);
2765
2766     if (lpHeadWorkQueue)
2767     {
2768         lpRequest = lpHeadWorkQueue;
2769         lpHeadWorkQueue = lpHeadWorkQueue->prev;
2770         if (lpRequest == lpWorkQueueTail)
2771             lpWorkQueueTail = lpHeadWorkQueue;
2772     }
2773
2774     LeaveCriticalSection(&csQueue);
2775
2776     if (lpRequest)
2777     {
2778         memcpy(lpWorkRequest, lpRequest, sizeof(WORKREQUEST));
2779         HeapFree(GetProcessHeap(), 0, lpRequest);
2780         bSuccess = TRUE;
2781         InterlockedDecrement(&dwNumJobs);
2782     }
2783
2784     return bSuccess;
2785 }
2786
2787
2788 /***********************************************************************
2789  *           INTERNET_AsyncCall (internal)
2790  *
2791  * Retrieves work request from queue
2792  *
2793  * RETURNS
2794  *
2795  */
2796 BOOL INTERNET_AsyncCall(LPWORKREQUEST lpWorkRequest)
2797 {
2798     HANDLE hThread;
2799     DWORD dwTID;
2800     BOOL bSuccess = FALSE;
2801
2802     TRACE("\n");
2803
2804     if (InterlockedDecrement(&dwNumIdleThreads) < 0)
2805     {
2806         InterlockedIncrement(&dwNumIdleThreads);
2807
2808         if (InterlockedIncrement(&dwNumThreads) > MAX_WORKER_THREADS ||
2809             !(hThread = CreateThread(NULL, 0,
2810             (LPTHREAD_START_ROUTINE)INTERNET_WorkerThreadFunc, NULL, 0, &dwTID)))
2811         {
2812             InterlockedDecrement(&dwNumThreads);
2813             INTERNET_SetLastError(ERROR_INTERNET_ASYNC_THREAD_FAILED);
2814             goto lerror;
2815         }
2816
2817         TRACE("Created new thread\n");
2818     }
2819
2820     bSuccess = TRUE;
2821     INTERNET_InsertWorkRequest(lpWorkRequest);
2822     SetEvent(hWorkEvent);
2823
2824 lerror:
2825
2826     return bSuccess;
2827 }
2828
2829
2830 /***********************************************************************
2831  *           INTERNET_ExecuteWork (internal)
2832  *
2833  * RETURNS
2834  *
2835  */
2836 static VOID INTERNET_ExecuteWork(void)
2837 {
2838     WORKREQUEST workRequest;
2839
2840     TRACE("\n");
2841
2842     if (!INTERNET_GetWorkRequest(&workRequest))
2843         return;
2844
2845     switch (workRequest.asyncall)
2846     {
2847     case FTPPUTFILEW:
2848         {
2849         struct WORKREQ_FTPPUTFILEW *req = &workRequest.u.FtpPutFileW;
2850         LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest.hdr;
2851
2852         TRACE("FTPPUTFILEW %p\n", lpwfs);
2853
2854         FTP_FtpPutFileW(lpwfs, req->lpszLocalFile,
2855                    req->lpszNewRemoteFile, req->dwFlags, req->dwContext);
2856
2857         HeapFree(GetProcessHeap(), 0, req->lpszLocalFile);
2858         HeapFree(GetProcessHeap(), 0, req->lpszNewRemoteFile);
2859         }
2860         break;
2861
2862     case FTPSETCURRENTDIRECTORYW:
2863         {
2864         struct WORKREQ_FTPSETCURRENTDIRECTORYW *req;
2865         LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest.hdr;
2866
2867         TRACE("FTPSETCURRENTDIRECTORYW %p\n", lpwfs);
2868
2869         req = &workRequest.u.FtpSetCurrentDirectoryW;
2870         FTP_FtpSetCurrentDirectoryW(lpwfs, req->lpszDirectory);
2871         HeapFree(GetProcessHeap(), 0, req->lpszDirectory);
2872         }
2873         break;
2874
2875     case FTPCREATEDIRECTORYW:
2876         {
2877         struct WORKREQ_FTPCREATEDIRECTORYW *req;
2878         LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest.hdr;
2879
2880         TRACE("FTPCREATEDIRECTORYW %p\n", lpwfs);
2881
2882         req = &workRequest.u.FtpCreateDirectoryW;
2883         FTP_FtpCreateDirectoryW(lpwfs, req->lpszDirectory);
2884         HeapFree(GetProcessHeap(), 0, req->lpszDirectory);
2885         }
2886         break;
2887
2888     case FTPFINDFIRSTFILEW:
2889         {
2890         struct WORKREQ_FTPFINDFIRSTFILEW *req;
2891         LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest.hdr;
2892
2893         TRACE("FTPFINDFIRSTFILEW %p\n", lpwfs);
2894
2895         req = &workRequest.u.FtpFindFirstFileW;
2896         FTP_FtpFindFirstFileW(lpwfs, req->lpszSearchFile,
2897            req->lpFindFileData, req->dwFlags, req->dwContext);
2898         HeapFree(GetProcessHeap(), 0, req->lpszSearchFile);
2899         }
2900         break;
2901
2902     case FTPGETCURRENTDIRECTORYW:
2903         {
2904         struct WORKREQ_FTPGETCURRENTDIRECTORYW *req;
2905         LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest.hdr;
2906
2907         TRACE("FTPGETCURRENTDIRECTORYW %p\n", lpwfs);
2908
2909         req = &workRequest.u.FtpGetCurrentDirectoryW;
2910         FTP_FtpGetCurrentDirectoryW(lpwfs,
2911                 req->lpszDirectory, req->lpdwDirectory);
2912         }
2913         break;
2914
2915     case FTPOPENFILEW:
2916         {
2917         struct WORKREQ_FTPOPENFILEW *req = &workRequest.u.FtpOpenFileW;
2918         LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest.hdr;
2919
2920         TRACE("FTPOPENFILEW %p\n", lpwfs);
2921
2922         FTP_FtpOpenFileW(lpwfs, req->lpszFilename,
2923             req->dwAccess, req->dwFlags, req->dwContext);
2924         HeapFree(GetProcessHeap(), 0, req->lpszFilename);
2925         }
2926         break;
2927
2928     case FTPGETFILEW:
2929         {
2930         struct WORKREQ_FTPGETFILEW *req = &workRequest.u.FtpGetFileW;
2931         LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest.hdr;
2932
2933         TRACE("FTPGETFILEW %p\n", lpwfs);
2934
2935         FTP_FtpGetFileW(lpwfs, req->lpszRemoteFile,
2936                  req->lpszNewFile, req->fFailIfExists,
2937                  req->dwLocalFlagsAttribute, req->dwFlags, req->dwContext);
2938         HeapFree(GetProcessHeap(), 0, req->lpszRemoteFile);
2939         HeapFree(GetProcessHeap(), 0, req->lpszNewFile);
2940         }
2941         break;
2942
2943     case FTPDELETEFILEW:
2944         {
2945         struct WORKREQ_FTPDELETEFILEW *req = &workRequest.u.FtpDeleteFileW;
2946         LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest.hdr;
2947
2948         TRACE("FTPDELETEFILEW %p\n", lpwfs);
2949
2950         FTP_FtpDeleteFileW(lpwfs, req->lpszFilename);
2951         HeapFree(GetProcessHeap(), 0, req->lpszFilename);
2952         }
2953         break;
2954
2955     case FTPREMOVEDIRECTORYW:
2956         {
2957         struct WORKREQ_FTPREMOVEDIRECTORYW *req;
2958         LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest.hdr;
2959
2960         TRACE("FTPREMOVEDIRECTORYW %p\n", lpwfs);
2961
2962         req = &workRequest.u.FtpRemoveDirectoryW;
2963         FTP_FtpRemoveDirectoryW(lpwfs, req->lpszDirectory);
2964         HeapFree(GetProcessHeap(), 0, req->lpszDirectory);
2965         }
2966         break;
2967
2968     case FTPRENAMEFILEW:
2969         {
2970         struct WORKREQ_FTPRENAMEFILEW *req = &workRequest.u.FtpRenameFileW;
2971         LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest.hdr;
2972
2973         TRACE("FTPRENAMEFILEW %p\n", lpwfs);
2974
2975         FTP_FtpRenameFileW(lpwfs, req->lpszSrcFile, req->lpszDestFile);
2976         HeapFree(GetProcessHeap(), 0, req->lpszSrcFile);
2977         HeapFree(GetProcessHeap(), 0, req->lpszDestFile);
2978         }
2979         break;
2980
2981     case INTERNETFINDNEXTW:
2982         {
2983         struct WORKREQ_INTERNETFINDNEXTW *req;
2984         LPWININETFINDNEXTW lpwh = (LPWININETFINDNEXTW) workRequest.hdr;
2985
2986         TRACE("INTERNETFINDNEXTW %p\n", lpwh);
2987
2988         req = &workRequest.u.InternetFindNextW;
2989         INTERNET_FindNextFileW(lpwh, req->lpFindFileData);
2990         }
2991         break;
2992
2993     case HTTPSENDREQUESTW:
2994         {
2995         struct WORKREQ_HTTPSENDREQUESTW *req = &workRequest.u.HttpSendRequestW;
2996         LPWININETHTTPREQW lpwhr = (LPWININETHTTPREQW) workRequest.hdr;
2997
2998         TRACE("HTTPSENDREQUESTW %p\n", lpwhr);
2999
3000         HTTP_HttpSendRequestW(lpwhr, req->lpszHeader,
3001                 req->dwHeaderLength, req->lpOptional, req->dwOptionalLength);
3002
3003         HeapFree(GetProcessHeap(), 0, req->lpszHeader);
3004         }
3005         break;
3006
3007     case HTTPOPENREQUESTW:
3008         {
3009         struct WORKREQ_HTTPOPENREQUESTW *req = &workRequest.u.HttpOpenRequestW;
3010         LPWININETHTTPSESSIONW lpwhs = (LPWININETHTTPSESSIONW) workRequest.hdr;
3011
3012         TRACE("HTTPOPENREQUESTW %p\n", lpwhs);
3013
3014         HTTP_HttpOpenRequestW(lpwhs, req->lpszVerb,
3015             req->lpszObjectName, req->lpszVersion, req->lpszReferrer,
3016             req->lpszAcceptTypes, req->dwFlags, req->dwContext);
3017
3018         HeapFree(GetProcessHeap(), 0, req->lpszVerb);
3019         HeapFree(GetProcessHeap(), 0, req->lpszObjectName);
3020         HeapFree(GetProcessHeap(), 0, req->lpszVersion);
3021         HeapFree(GetProcessHeap(), 0, req->lpszReferrer);
3022         }
3023         break;
3024
3025     case SENDCALLBACK:
3026         {
3027         struct WORKREQ_SENDCALLBACK *req = &workRequest.u.SendCallback;
3028
3029         TRACE("SENDCALLBACK %p\n", workRequest.hdr);
3030
3031         SendSyncCallback(workRequest.hdr,
3032                          req->dwContext, req->dwInternetStatus, req->lpvStatusInfo,
3033                          req->dwStatusInfoLength);
3034
3035         /* And frees the copy of the status info */
3036         HeapFree(GetProcessHeap(), 0, req->lpvStatusInfo);
3037         }
3038         break;
3039
3040     case INTERNETOPENURLW:
3041         {
3042         struct WORKREQ_INTERNETOPENURLW *req = &workRequest.u.InternetOpenUrlW;
3043         LPWININETAPPINFOW hIC = (LPWININETAPPINFOW) workRequest.hdr;
3044         
3045         TRACE("INTERNETOPENURLW %p\n", hIC);
3046
3047         INTERNET_InternetOpenUrlW(hIC, req->lpszUrl,
3048                                   req->lpszHeaders, req->dwHeadersLength, req->dwFlags, req->dwContext);
3049         HeapFree(GetProcessHeap(), 0, req->lpszUrl);
3050         HeapFree(GetProcessHeap(), 0, req->lpszHeaders);
3051         }
3052         break;
3053     }
3054     WININET_Release( workRequest.hdr );
3055 }
3056
3057
3058 /***********************************************************************
3059  *          INTERNET_GetResponseBuffer
3060  *
3061  * RETURNS
3062  *
3063  */
3064 LPSTR INTERNET_GetResponseBuffer(void)
3065 {
3066     LPWITHREADERROR lpwite = (LPWITHREADERROR)TlsGetValue(g_dwTlsErrIndex);
3067     TRACE("\n");
3068     return lpwite->response;
3069 }
3070
3071 /***********************************************************************
3072  *           INTERNET_GetNextLine  (internal)
3073  *
3074  * Parse next line in directory string listing
3075  *
3076  * RETURNS
3077  *   Pointer to beginning of next line
3078  *   NULL on failure
3079  *
3080  */
3081
3082 LPSTR INTERNET_GetNextLine(INT nSocket, LPDWORD dwLen)
3083 {
3084     struct timeval tv;
3085     fd_set infd;
3086     BOOL bSuccess = FALSE;
3087     INT nRecv = 0;
3088     LPSTR lpszBuffer = INTERNET_GetResponseBuffer();
3089
3090     TRACE("\n");
3091
3092     FD_ZERO(&infd);
3093     FD_SET(nSocket, &infd);
3094     tv.tv_sec=RESPONSE_TIMEOUT;
3095     tv.tv_usec=0;
3096
3097     while (nRecv < MAX_REPLY_LEN)
3098     {
3099         if (select(nSocket+1,&infd,NULL,NULL,&tv) > 0)
3100         {
3101             if (recv(nSocket, &lpszBuffer[nRecv], 1, 0) <= 0)
3102             {
3103                 INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS);
3104                 goto lend;
3105             }
3106
3107             if (lpszBuffer[nRecv] == '\n')
3108             {
3109                 bSuccess = TRUE;
3110                 break;
3111             }
3112             if (lpszBuffer[nRecv] != '\r')
3113                 nRecv++;
3114         }
3115         else
3116         {
3117             INTERNET_SetLastError(ERROR_INTERNET_TIMEOUT);
3118             goto lend;
3119         }
3120     }
3121
3122 lend:
3123     if (bSuccess)
3124     {
3125         lpszBuffer[nRecv] = '\0';
3126         *dwLen = nRecv - 1;
3127         TRACE(":%d %s\n", nRecv, lpszBuffer);
3128         return lpszBuffer;
3129     }
3130     else
3131     {
3132         return NULL;
3133     }
3134 }
3135
3136 /***********************************************************************
3137  *
3138  */
3139 BOOL WINAPI InternetQueryDataAvailable( HINTERNET hFile,
3140                                 LPDWORD lpdwNumberOfBytesAvailble,
3141                                 DWORD dwFlags, DWORD dwConext)
3142 {
3143     LPWININETHTTPREQW lpwhr;
3144     INT retval = -1;
3145     char buffer[4048];
3146
3147     lpwhr = (LPWININETHTTPREQW) WININET_GetObject( hFile );
3148     if (NULL == lpwhr)
3149     {
3150         SetLastError(ERROR_NO_MORE_FILES);
3151         return FALSE;
3152     }
3153
3154     TRACE("-->  %p %i\n",lpwhr,lpwhr->hdr.htype);
3155
3156     switch (lpwhr->hdr.htype)
3157     {
3158     case WH_HHTTPREQ:
3159         if (!NETCON_recv(&lpwhr->netConnection, buffer,
3160                          4048, MSG_PEEK, (int *)lpdwNumberOfBytesAvailble))
3161         {
3162             SetLastError(ERROR_NO_MORE_FILES);
3163             retval = FALSE;
3164         }
3165         else
3166             retval = TRUE;
3167         break;
3168
3169     default:
3170         FIXME("unsupported file type\n");
3171         break;
3172     }
3173     WININET_Release( &lpwhr->hdr );
3174
3175     TRACE("<-- %i\n",retval);
3176     return (retval+1);
3177 }
3178
3179
3180 /***********************************************************************
3181  *
3182  */
3183 BOOL WINAPI InternetLockRequestFile( HINTERNET hInternet, HANDLE
3184 *lphLockReqHandle)
3185 {
3186     FIXME("STUB\n");
3187     return FALSE;
3188 }
3189
3190 BOOL WINAPI InternetUnlockRequestFile( HANDLE hLockHandle)
3191 {
3192     FIXME("STUB\n");
3193     return FALSE;
3194 }
3195
3196
3197 /***********************************************************************
3198  *           InternetAutodial
3199  *
3200  * On windows this function is supposed to dial the default internet
3201  * connection. We don't want to have Wine dial out to the internet so
3202  * we return TRUE by default. It might be nice to check if we are connected.
3203  *
3204  * RETURNS
3205  *   TRUE on success
3206  *   FALSE on failure
3207  *
3208  */
3209 BOOL WINAPI InternetAutodial(DWORD dwFlags, HWND hwndParent)
3210 {
3211     FIXME("STUB\n");
3212
3213     /* Tell that we are connected to the internet. */
3214     return TRUE;
3215 }
3216
3217 /***********************************************************************
3218  *           InternetAutodialHangup
3219  *
3220  * Hangs up a connection made with InternetAutodial
3221  *
3222  * PARAM
3223  *    dwReserved
3224  * RETURNS
3225  *   TRUE on success
3226  *   FALSE on failure
3227  *
3228  */
3229 BOOL WINAPI InternetAutodialHangup(DWORD dwReserved)
3230 {
3231     FIXME("STUB\n");
3232
3233     /* we didn't dial, we don't disconnect */
3234     return TRUE;
3235 }
3236
3237 /***********************************************************************
3238  *
3239  *         InternetCombineUrlA
3240  *
3241  * Combine a base URL with a relative URL
3242  *
3243  * RETURNS
3244  *   TRUE on success
3245  *   FALSE on failure
3246  *
3247  */
3248
3249 BOOL WINAPI InternetCombineUrlA(LPCSTR lpszBaseUrl, LPCSTR lpszRelativeUrl,
3250                                 LPSTR lpszBuffer, LPDWORD lpdwBufferLength,
3251                                 DWORD dwFlags)
3252 {
3253     HRESULT hr=S_OK;
3254
3255     TRACE("(%s, %s, %p, %p, 0x%08lx)\n", debugstr_a(lpszBaseUrl), debugstr_a(lpszRelativeUrl), lpszBuffer, lpdwBufferLength, dwFlags);
3256
3257     /* Flip this bit to correspond to URL_ESCAPE_UNSAFE */
3258     dwFlags ^= ICU_NO_ENCODE;
3259     hr=UrlCombineA(lpszBaseUrl,lpszRelativeUrl,lpszBuffer,lpdwBufferLength,dwFlags);
3260
3261     return (hr==S_OK);
3262 }
3263
3264 /***********************************************************************
3265  *
3266  *         InternetCombineUrlW
3267  *
3268  * Combine a base URL with a relative URL
3269  *
3270  * RETURNS
3271  *   TRUE on success
3272  *   FALSE on failure
3273  *
3274  */
3275
3276 BOOL WINAPI InternetCombineUrlW(LPCWSTR lpszBaseUrl, LPCWSTR lpszRelativeUrl,
3277                                 LPWSTR lpszBuffer, LPDWORD lpdwBufferLength,
3278                                 DWORD dwFlags)
3279 {
3280     HRESULT hr=S_OK;
3281
3282     TRACE("(%s, %s, %p, %p, 0x%08lx)\n", debugstr_w(lpszBaseUrl), debugstr_w(lpszRelativeUrl), lpszBuffer, lpdwBufferLength, dwFlags);
3283
3284     /* Flip this bit to correspond to URL_ESCAPE_UNSAFE */
3285     dwFlags ^= ICU_NO_ENCODE;
3286     hr=UrlCombineW(lpszBaseUrl,lpszRelativeUrl,lpszBuffer,lpdwBufferLength,dwFlags);
3287
3288     return (hr==S_OK);
3289 }
3290
3291 /***********************************************************************
3292  *
3293  *         InternetCreateUrlA
3294  *
3295  * RETURNS
3296  *   TRUE on success
3297  *   FALSE on failure
3298  *
3299  */
3300 BOOL WINAPI InternetCreateUrlA(LPURL_COMPONENTSA lpUrlComponents, DWORD dwFlags,
3301                                LPSTR lpszUrl, LPDWORD lpdwUrlLength)
3302 {
3303     FIXME("\n");
3304     return FALSE;
3305 }
3306
3307 DWORD WINAPI InternetConfirmZoneCrossingA( HWND hWnd, LPSTR szUrlPrev, LPSTR szUrlNew, BOOL bPost )
3308 {
3309     FIXME("(%p, %s, %s, %x) stub\n", hWnd, debugstr_a(szUrlPrev), debugstr_a(szUrlNew), bPost);
3310     return ERROR_SUCCESS;
3311 }
3312
3313 DWORD WINAPI InternetConfirmZoneCrossingW( HWND hWnd, LPWSTR szUrlPrev, LPWSTR szUrlNew, BOOL bPost )
3314 {
3315     FIXME("(%p, %s, %s, %x) stub\n", hWnd, debugstr_w(szUrlPrev), debugstr_w(szUrlNew), bPost);
3316     return ERROR_SUCCESS;
3317 }
3318
3319 DWORD WINAPI InternetDialA( HWND hwndParent, LPSTR lpszConnectoid, DWORD dwFlags,
3320                             LPDWORD lpdwConnection, DWORD dwReserved )
3321 {
3322     FIXME("(%p, %p, 0x%08lx, %p, 0x%08lx) stub\n", hwndParent, lpszConnectoid, dwFlags,
3323           lpdwConnection, dwReserved);
3324     return ERROR_SUCCESS;
3325 }
3326
3327 DWORD WINAPI InternetDialW( HWND hwndParent, LPWSTR lpszConnectoid, DWORD dwFlags,
3328                             LPDWORD lpdwConnection, DWORD dwReserved )
3329 {
3330     FIXME("(%p, %p, 0x%08lx, %p, 0x%08lx) stub\n", hwndParent, lpszConnectoid, dwFlags,
3331           lpdwConnection, dwReserved);
3332     return ERROR_SUCCESS;
3333 }
3334
3335 BOOL WINAPI InternetGoOnlineA( LPSTR lpszURL, HWND hwndParent, DWORD dwReserved )
3336 {
3337     FIXME("(%s, %p, 0x%08lx) stub\n", debugstr_a(lpszURL), hwndParent, dwReserved);
3338     return TRUE;
3339 }
3340
3341 BOOL WINAPI InternetGoOnlineW( LPWSTR lpszURL, HWND hwndParent, DWORD dwReserved )
3342 {
3343     FIXME("(%s, %p, 0x%08lx) stub\n", debugstr_w(lpszURL), hwndParent, dwReserved);
3344     return TRUE;
3345 }
3346
3347 DWORD WINAPI InternetHangUp( DWORD dwConnection, DWORD dwReserved )
3348 {
3349     FIXME("(0x%08lx, 0x%08lx) stub\n", dwConnection, dwReserved);
3350     return ERROR_SUCCESS;
3351 }
3352
3353 BOOL WINAPI CreateMD5SSOHash( PWSTR pszChallengeInfo, PWSTR pwszRealm, PWSTR pwszTarget,
3354                               PBYTE pbHexHash )
3355 {
3356     FIXME("(%s, %s, %s, %p) stub\n", debugstr_w(pszChallengeInfo), debugstr_w(pwszRealm),
3357           debugstr_w(pwszTarget), pbHexHash);
3358     return FALSE;
3359 }
3360
3361 BOOL WINAPI InternetClearAllPerSiteCookieDecisions( VOID )
3362 {
3363     FIXME("stub\n");
3364     return TRUE;
3365 }
3366
3367 BOOL WINAPI InternetEnumPerSiteCookieDecisionA( LPSTR pszSiteName, unsigned long *pcSiteNameSize,
3368                                                 unsigned long *pdwDecision, unsigned long dwIndex )
3369 {
3370     FIXME("(%s, %p, %p, 0x%08lx) stub\n",
3371           debugstr_a(pszSiteName), pcSiteNameSize, pdwDecision, dwIndex);
3372     return FALSE;
3373 }
3374
3375 BOOL WINAPI InternetEnumPerSiteCookieDecisionW( LPWSTR pszSiteName, unsigned long *pcSiteNameSize,
3376                                                 unsigned long *pdwDecision, unsigned long dwIndex )
3377 {
3378     FIXME("(%s, %p, %p, 0x%08lx) stub\n",
3379           debugstr_w(pszSiteName), pcSiteNameSize, pdwDecision, dwIndex);
3380     return FALSE;
3381 }
3382
3383 BOOL WINAPI InternetGetCookieExA( LPCSTR pchURL, LPCSTR pchCookieName, LPSTR pchCookieData,
3384                                   LPDWORD pcchCookieData, DWORD dwFlags, LPVOID lpReserved)
3385 {
3386     FIXME("(%s, %s, %s, %p, 0x%08lx, %p) stub\n",
3387           debugstr_a(pchURL), debugstr_a(pchCookieName), debugstr_a(pchCookieData),
3388           pcchCookieData, dwFlags, lpReserved);
3389     return FALSE;
3390 }
3391
3392 BOOL WINAPI InternetGetCookieExW( LPCWSTR pchURL, LPCWSTR pchCookieName, LPWSTR pchCookieData,
3393                                   LPDWORD pcchCookieData, DWORD dwFlags, LPVOID lpReserved)
3394 {
3395     FIXME("(%s, %s, %s, %p, 0x%08lx, %p) stub\n",
3396           debugstr_w(pchURL), debugstr_w(pchCookieName), debugstr_w(pchCookieData),
3397           pcchCookieData, dwFlags, lpReserved);
3398     return FALSE;
3399 }
3400
3401 BOOL WINAPI InternetGetPerSiteCookieDecisionA( LPCSTR pwchHostName, unsigned long *pResult )
3402 {
3403     FIXME("(%s, %p) stub\n", debugstr_a(pwchHostName), pResult);
3404     return FALSE;
3405 }
3406
3407 BOOL WINAPI InternetGetPerSiteCookieDecisionW( LPCWSTR pwchHostName, unsigned long *pResult )
3408 {
3409     FIXME("(%s, %p) stub\n", debugstr_w(pwchHostName), pResult);
3410     return FALSE;
3411 }
3412
3413 BOOL WINAPI InternetSetPerSiteCookieDecisionA( LPCSTR pchHostName, DWORD dwDecision )
3414 {
3415     FIXME("(%s, 0x%08lx) stub\n", debugstr_a(pchHostName), dwDecision);
3416     return FALSE;
3417 }
3418
3419 BOOL WINAPI InternetSetPerSiteCookieDecisionW( LPCWSTR pchHostName, DWORD dwDecision )
3420 {
3421     FIXME("(%s, 0x%08lx) stub\n", debugstr_w(pchHostName), dwDecision);
3422     return FALSE;
3423 }
3424
3425 DWORD WINAPI InternetSetCookieExA( LPCSTR lpszURL, LPCSTR lpszCookieName, LPCSTR lpszCookieData,
3426                                    DWORD dwFlags, DWORD_PTR dwReserved)
3427 {
3428     FIXME("(%s, %s, %s, 0x%08lx, 0x%08lx) stub\n",
3429           debugstr_a(lpszURL), debugstr_a(lpszCookieName), debugstr_a(lpszCookieData),
3430           dwFlags, dwReserved);
3431     return TRUE;
3432 }
3433
3434 DWORD WINAPI InternetSetCookieExW( LPCWSTR lpszURL, LPCWSTR lpszCookieName, LPCWSTR lpszCookieData,
3435                                    DWORD dwFlags, DWORD_PTR dwReserved)
3436 {
3437     FIXME("(%s, %s, %s, 0x%08lx, 0x%08lx) stub\n",
3438           debugstr_w(lpszURL), debugstr_w(lpszCookieName), debugstr_w(lpszCookieData),
3439           dwFlags, dwReserved);
3440     return TRUE;
3441 }
3442
3443 BOOL WINAPI ResumeSuspendedDownload( HINTERNET hInternet, DWORD dwError )
3444 {
3445     FIXME("(%p, 0x%08lx) stub\n", hInternet, dwError);
3446     return FALSE;
3447 }
3448  
3449 /***********************************************************************
3450  *
3451  *         InternetCreateUrlW
3452  *
3453  * RETURNS
3454  *   TRUE on success
3455  *   FALSE on failure
3456  *
3457  */
3458 BOOL WINAPI InternetCreateUrlW(LPURL_COMPONENTSW lpUrlComponents, DWORD dwFlags,
3459                                LPWSTR lpszUrl, LPDWORD lpdwUrlLength)
3460 {
3461     FIXME("\n");
3462     return FALSE;
3463 }
3464
3465 /***********************************************************************
3466  *           dump_INTERNET_FLAGS
3467  *
3468  * Helper function to TRACE the internet flags.
3469  *
3470  * RETURNS
3471  *    None
3472  *
3473  */
3474 void dump_INTERNET_FLAGS(DWORD dwFlags) 
3475 {
3476 #define FE(x) { x, #x }
3477     static const wininet_flag_info flag[] = {
3478         FE(INTERNET_FLAG_RELOAD),
3479         FE(INTERNET_FLAG_RAW_DATA),
3480         FE(INTERNET_FLAG_EXISTING_CONNECT),
3481         FE(INTERNET_FLAG_ASYNC),
3482         FE(INTERNET_FLAG_PASSIVE),
3483         FE(INTERNET_FLAG_NO_CACHE_WRITE),
3484         FE(INTERNET_FLAG_MAKE_PERSISTENT),
3485         FE(INTERNET_FLAG_FROM_CACHE),
3486         FE(INTERNET_FLAG_SECURE),
3487         FE(INTERNET_FLAG_KEEP_CONNECTION),
3488         FE(INTERNET_FLAG_NO_AUTO_REDIRECT),
3489         FE(INTERNET_FLAG_READ_PREFETCH),
3490         FE(INTERNET_FLAG_NO_COOKIES),
3491         FE(INTERNET_FLAG_NO_AUTH),
3492         FE(INTERNET_FLAG_CACHE_IF_NET_FAIL),
3493         FE(INTERNET_FLAG_IGNORE_REDIRECT_TO_HTTP),
3494         FE(INTERNET_FLAG_IGNORE_REDIRECT_TO_HTTPS),
3495         FE(INTERNET_FLAG_IGNORE_CERT_DATE_INVALID),
3496         FE(INTERNET_FLAG_IGNORE_CERT_CN_INVALID),
3497         FE(INTERNET_FLAG_RESYNCHRONIZE),
3498         FE(INTERNET_FLAG_HYPERLINK),
3499         FE(INTERNET_FLAG_NO_UI),
3500         FE(INTERNET_FLAG_PRAGMA_NOCACHE),
3501         FE(INTERNET_FLAG_CACHE_ASYNC),
3502         FE(INTERNET_FLAG_FORMS_SUBMIT),
3503         FE(INTERNET_FLAG_NEED_FILE),
3504         FE(INTERNET_FLAG_TRANSFER_ASCII),
3505         FE(INTERNET_FLAG_TRANSFER_BINARY)
3506     };
3507 #undef FE
3508     int i;
3509     
3510     for (i = 0; i < (sizeof(flag) / sizeof(flag[0])); i++) {
3511         if (flag[i].val & dwFlags) {
3512             TRACE(" %s", flag[i].name);
3513             dwFlags &= ~flag[i].val;
3514         }
3515     }   
3516     if (dwFlags)
3517         TRACE(" Unknown flags (%08lx)\n", dwFlags);
3518     else
3519         TRACE("\n");
3520 }