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