Don't open device if already open.
[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                     {
1959                         pPI->lpszProxy = (LPWSTR)((LPBYTE)lpBuffer +
1960                                                   sizeof(INTERNET_PROXY_INFOW));
1961                         *((LPWSTR)(pPI->lpszProxy)) = 0;
1962                     }
1963
1964                     if (lpwai->lpszProxyBypass)
1965                     {
1966                         pPI->lpszProxyBypass = (LPWSTR)((LPBYTE)lpBuffer +
1967                                                         sizeof(INTERNET_PROXY_INFOW) +
1968                                                         proxyBytesRequired);
1969                         lstrcpyW((LPWSTR)pPI->lpszProxyBypass,
1970                          lpwai->lpszProxyBypass);
1971                     }
1972                     else
1973                     {
1974                         pPI->lpszProxyBypass = (LPWSTR)((LPBYTE)lpBuffer +
1975                                                         sizeof(INTERNET_PROXY_INFOW) +
1976                                                         proxyBytesRequired);
1977                         *((LPWSTR)(pPI->lpszProxyBypass)) = 0;
1978                     }
1979                     bSuccess = TRUE;
1980                 }
1981                 *lpdwBufferLength = sizeof(INTERNET_PROXY_INFOW) +
1982                  proxyBytesRequired + proxyBypassBytesRequired;
1983             }
1984             else
1985             {
1986                 INTERNET_PROXY_INFOA *pPI = (INTERNET_PROXY_INFOA *)lpBuffer;
1987                 DWORD proxyBytesRequired = 0, proxyBypassBytesRequired = 0;
1988
1989                 if (lpwai->lpszProxy)
1990                     proxyBytesRequired = WideCharToMultiByte(CP_ACP, 0,
1991                      lpwai->lpszProxy, -1, NULL, 0, NULL, NULL);
1992                 if (lpwai->lpszProxyBypass)
1993                     proxyBypassBytesRequired = WideCharToMultiByte(CP_ACP, 0,
1994                      lpwai->lpszProxyBypass, -1, NULL, 0, NULL, NULL);
1995                 if (*lpdwBufferLength < sizeof(INTERNET_PROXY_INFOA) +
1996                  proxyBytesRequired + proxyBypassBytesRequired)
1997                     INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
1998                 else
1999                 {
2000                     pPI->dwAccessType = lpwai->dwAccessType;
2001                     if (lpwai->lpszProxy)
2002                     {
2003                         pPI->lpszProxy = (LPSTR)((LPBYTE)lpBuffer +
2004                                                  sizeof(INTERNET_PROXY_INFOA));
2005                         WideCharToMultiByte(CP_ACP, 0, lpwai->lpszProxy, -1,
2006                          (LPSTR)pPI->lpszProxy, proxyBytesRequired, NULL, NULL);
2007                     }
2008                     else
2009                     {
2010                         pPI->lpszProxy = (LPSTR)((LPBYTE)lpBuffer +
2011                                                  sizeof(INTERNET_PROXY_INFOA));
2012                         *((LPSTR)(pPI->lpszProxy)) = '\0';
2013                     }
2014                     
2015                     if (lpwai->lpszProxyBypass)
2016                     {
2017                         pPI->lpszProxyBypass = (LPSTR)((LPBYTE)lpBuffer +
2018                          sizeof(INTERNET_PROXY_INFOA) + proxyBytesRequired);
2019                         WideCharToMultiByte(CP_ACP, 0, lpwai->lpszProxyBypass,
2020                          -1, (LPSTR)pPI->lpszProxyBypass,
2021                          proxyBypassBytesRequired,
2022                          NULL, NULL);
2023                     }
2024                     else
2025                     {
2026                         pPI->lpszProxyBypass = (LPSTR)((LPBYTE)lpBuffer +
2027                                                        sizeof(INTERNET_PROXY_INFOA) +
2028                                                        proxyBytesRequired);
2029                         *((LPSTR)(pPI->lpszProxyBypass)) = '\0';
2030                     }
2031                     bSuccess = TRUE;
2032                 }
2033                 *lpdwBufferLength = sizeof(INTERNET_PROXY_INFOA) +
2034                  proxyBytesRequired + proxyBypassBytesRequired;
2035             }
2036             break;
2037         }
2038         case INTERNET_OPTION_SECURITY_FLAGS:
2039             FIXME("INTERNET_OPTION_SECURITY_FLAGS: Stub\n");
2040             break;
2041
2042         default:
2043             FIXME("Stub! %ld \n",dwOption);
2044             break;
2045     }
2046     if (lpwhh)
2047         WININET_Release( lpwhh );
2048
2049     return bSuccess;
2050 }
2051
2052 /***********************************************************************
2053  *           InternetQueryOptionW (WININET.@)
2054  *
2055  * Queries an options on the specified handle
2056  *
2057  * RETURNS
2058  *    TRUE  on success
2059  *    FALSE on failure
2060  *
2061  */
2062 BOOL WINAPI InternetQueryOptionW(HINTERNET hInternet, DWORD dwOption,
2063                                  LPVOID lpBuffer, LPDWORD lpdwBufferLength)
2064 {
2065     return INET_QueryOptionHelper(TRUE, hInternet, dwOption, lpBuffer, lpdwBufferLength);
2066 }
2067
2068 /***********************************************************************
2069  *           InternetQueryOptionA (WININET.@)
2070  *
2071  * Queries an options on the specified handle
2072  *
2073  * RETURNS
2074  *    TRUE  on success
2075  *    FALSE on failure
2076  *
2077  */
2078 BOOL WINAPI InternetQueryOptionA(HINTERNET hInternet, DWORD dwOption,
2079                                  LPVOID lpBuffer, LPDWORD lpdwBufferLength)
2080 {
2081     return INET_QueryOptionHelper(FALSE, hInternet, dwOption, lpBuffer, lpdwBufferLength);
2082 }
2083
2084
2085 /***********************************************************************
2086  *           InternetSetOptionW (WININET.@)
2087  *
2088  * Sets an options on the specified handle
2089  *
2090  * RETURNS
2091  *    TRUE  on success
2092  *    FALSE on failure
2093  *
2094  */
2095 BOOL WINAPI InternetSetOptionW(HINTERNET hInternet, DWORD dwOption,
2096                            LPVOID lpBuffer, DWORD dwBufferLength)
2097 {
2098     LPWININETHANDLEHEADER lpwhh;
2099     BOOL ret = TRUE;
2100
2101     TRACE("0x%08lx\n", dwOption);
2102
2103     lpwhh = (LPWININETHANDLEHEADER) WININET_GetObject( hInternet );
2104     if( !lpwhh )
2105         return FALSE;
2106
2107     switch (dwOption)
2108     {
2109     case INTERNET_OPTION_HTTP_VERSION:
2110       {
2111         HTTP_VERSION_INFO* pVersion=(HTTP_VERSION_INFO*)lpBuffer;
2112         FIXME("Option INTERNET_OPTION_HTTP_VERSION(%ld,%ld): STUB\n",pVersion->dwMajorVersion,pVersion->dwMinorVersion);
2113       }
2114       break;
2115     case INTERNET_OPTION_ERROR_MASK:
2116       {
2117         unsigned long flags=*(unsigned long*)lpBuffer;
2118         FIXME("Option INTERNET_OPTION_ERROR_MASK(%ld): STUB\n",flags);
2119       }
2120       break;
2121     case INTERNET_OPTION_CODEPAGE:
2122       {
2123         unsigned long codepage=*(unsigned long*)lpBuffer;
2124         FIXME("Option INTERNET_OPTION_CODEPAGE (%ld): STUB\n",codepage);
2125       }
2126       break;
2127     case INTERNET_OPTION_REQUEST_PRIORITY:
2128       {
2129         unsigned long priority=*(unsigned long*)lpBuffer;
2130         FIXME("Option INTERNET_OPTION_REQUEST_PRIORITY (%ld): STUB\n",priority);
2131       }
2132       break;
2133     case INTERNET_OPTION_CONNECT_TIMEOUT:
2134       {
2135         unsigned long connecttimeout=*(unsigned long*)lpBuffer;
2136         FIXME("Option INTERNET_OPTION_CONNECT_TIMEOUT (%ld): STUB\n",connecttimeout);
2137       }
2138       break;
2139     case INTERNET_OPTION_DATA_RECEIVE_TIMEOUT:
2140       {
2141         unsigned long receivetimeout=*(unsigned long*)lpBuffer;
2142         FIXME("Option INTERNET_OPTION_DATA_RECEIVE_TIMEOUT (%ld): STUB\n",receivetimeout);
2143       }
2144       break;
2145     case INTERNET_OPTION_RESET_URLCACHE_SESSION:
2146         FIXME("Option INTERNET_OPTION_RESET_URLCACHE_SESSION: STUB\n");
2147         break;
2148     case INTERNET_OPTION_END_BROWSER_SESSION:
2149         FIXME("Option INTERNET_OPTION_END_BROWSER_SESSION: STUB\n");
2150         break;
2151     case INTERNET_OPTION_CONNECTED_STATE:
2152         FIXME("Option INTERNET_OPTION_CONNECTED_STATE: STUB\n");
2153         break;
2154     default:
2155         FIXME("Option %ld STUB\n",dwOption);
2156         INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
2157         ret = FALSE;
2158         break;
2159     }
2160     WININET_Release( lpwhh );
2161
2162     return TRUE;
2163 }
2164
2165
2166 /***********************************************************************
2167  *           InternetSetOptionA (WININET.@)
2168  *
2169  * Sets an options on the specified handle.
2170  *
2171  * RETURNS
2172  *    TRUE  on success
2173  *    FALSE on failure
2174  *
2175  */
2176 BOOL WINAPI InternetSetOptionA(HINTERNET hInternet, DWORD dwOption,
2177                            LPVOID lpBuffer, DWORD dwBufferLength)
2178 {
2179     LPVOID wbuffer;
2180     DWORD wlen;
2181     BOOL r;
2182
2183     switch( dwOption )
2184     {
2185     case INTERNET_OPTION_PROXY:
2186         {
2187         LPINTERNET_PROXY_INFOA pi = (LPINTERNET_PROXY_INFOA) lpBuffer;
2188         LPINTERNET_PROXY_INFOW piw;
2189         DWORD proxlen, prbylen;
2190         LPWSTR prox, prby;
2191
2192         proxlen = MultiByteToWideChar( CP_ACP, 0, pi->lpszProxy, -1, NULL, 0);
2193         prbylen= MultiByteToWideChar( CP_ACP, 0, pi->lpszProxyBypass, -1, NULL, 0);
2194         wlen = sizeof(*piw) + proxlen + prbylen;
2195         wbuffer = HeapAlloc( GetProcessHeap(), 0, wlen*sizeof(WCHAR) );
2196         piw = (LPINTERNET_PROXY_INFOW) wbuffer;
2197         piw->dwAccessType = pi->dwAccessType;
2198         prox = (LPWSTR) &piw[1];
2199         prby = &prox[proxlen+1];
2200         MultiByteToWideChar( CP_ACP, 0, pi->lpszProxy, -1, prox, proxlen);
2201         MultiByteToWideChar( CP_ACP, 0, pi->lpszProxyBypass, -1, prby, prbylen);
2202         piw->lpszProxy = prox;
2203         piw->lpszProxyBypass = prby;
2204         }
2205         break;
2206     case INTERNET_OPTION_USER_AGENT:
2207     case INTERNET_OPTION_USERNAME:
2208     case INTERNET_OPTION_PASSWORD:
2209         wlen = MultiByteToWideChar( CP_ACP, 0, lpBuffer, dwBufferLength,
2210                                    NULL, 0 );
2211         wbuffer = HeapAlloc( GetProcessHeap(), 0, wlen*sizeof(WCHAR) );
2212         MultiByteToWideChar( CP_ACP, 0, lpBuffer, dwBufferLength,
2213                                    wbuffer, wlen );
2214         break;
2215     default:
2216         wbuffer = lpBuffer;
2217         wlen = dwBufferLength;
2218     }
2219
2220     r = InternetSetOptionW(hInternet,dwOption, wbuffer, wlen);
2221
2222     if( lpBuffer != wbuffer )
2223         HeapFree( GetProcessHeap(), 0, wbuffer );
2224
2225     return r;
2226 }
2227
2228
2229 /***********************************************************************
2230  *           InternetSetOptionExA (WININET.@)
2231  */
2232 BOOL WINAPI InternetSetOptionExA(HINTERNET hInternet, DWORD dwOption,
2233                            LPVOID lpBuffer, DWORD dwBufferLength, DWORD dwFlags)
2234 {
2235     FIXME("Flags %08lx ignored\n", dwFlags);
2236     return InternetSetOptionA( hInternet, dwOption, lpBuffer, dwBufferLength );
2237 }
2238
2239 /***********************************************************************
2240  *           InternetSetOptionExW (WININET.@)
2241  */
2242 BOOL WINAPI InternetSetOptionExW(HINTERNET hInternet, DWORD dwOption,
2243                            LPVOID lpBuffer, DWORD dwBufferLength, DWORD dwFlags)
2244 {
2245     FIXME("Flags %08lx ignored\n", dwFlags);
2246     if( dwFlags & ~ISO_VALID_FLAGS )
2247     {
2248         SetLastError( ERROR_INVALID_PARAMETER );
2249         return FALSE;
2250     }
2251     return InternetSetOptionW( hInternet, dwOption, lpBuffer, dwBufferLength );
2252 }
2253
2254 static const WCHAR WININET_wkday[7][4] =
2255     { { 'S','u','n', 0 }, { 'M','o','n', 0 }, { 'T','u','e', 0 }, { 'W','e','d', 0 },
2256       { 'T','h','u', 0 }, { 'F','r','i', 0 }, { 'S','a','t', 0 } };
2257 static const WCHAR WININET_month[12][4] =
2258     { { 'J','a','n', 0 }, { 'F','e','b', 0 }, { 'M','a','r', 0 }, { 'A','p','r', 0 },
2259       { 'M','a','y', 0 }, { 'J','u','n', 0 }, { 'J','u','l', 0 }, { 'A','u','g', 0 },
2260       { 'S','e','p', 0 }, { 'O','c','t', 0 }, { 'N','o','v', 0 }, { 'D','e','c', 0 } };
2261
2262 /***********************************************************************
2263  *           InternetTimeFromSystemTimeA (WININET.@)
2264  */
2265 BOOL WINAPI InternetTimeFromSystemTimeA( const SYSTEMTIME* time, DWORD format, LPSTR string, DWORD size )
2266 {
2267     BOOL ret;
2268     WCHAR stringW[INTERNET_RFC1123_BUFSIZE];
2269
2270     TRACE( "%p 0x%08lx %p 0x%08lx\n", time, format, string, size );
2271
2272     ret = InternetTimeFromSystemTimeW( time, format, stringW, sizeof(stringW) );
2273     if (ret) WideCharToMultiByte( CP_ACP, 0, stringW, -1, string, size, NULL, NULL );
2274
2275     return ret;
2276 }
2277
2278 /***********************************************************************
2279  *           InternetTimeFromSystemTimeW (WININET.@)
2280  */
2281 BOOL WINAPI InternetTimeFromSystemTimeW( const SYSTEMTIME* time, DWORD format, LPWSTR string, DWORD size )
2282 {
2283     static const WCHAR date[] =
2284         { '%','s',',',' ','%','0','2','d',' ','%','s',' ','%','4','d',' ','%','0',
2285           '2','d',':','%','0','2','d',':','%','0','2','d',' ','G','M','T', 0 };
2286
2287     TRACE( "%p 0x%08lx %p 0x%08lx\n", time, format, string, size );
2288
2289     if (!time || !string) return FALSE;
2290
2291     if (format != INTERNET_RFC1123_FORMAT || size < INTERNET_RFC1123_BUFSIZE * sizeof(WCHAR))
2292         return FALSE;
2293
2294     sprintfW( string, date,
2295               WININET_wkday[time->wDayOfWeek],
2296               time->wDay,
2297               WININET_month[time->wMonth - 1],
2298               time->wYear,
2299               time->wHour,
2300               time->wMinute,
2301               time->wSecond );
2302
2303     return TRUE;
2304 }
2305
2306 /***********************************************************************
2307  *           InternetTimeToSystemTimeA (WININET.@)
2308  */
2309 BOOL WINAPI InternetTimeToSystemTimeA( LPCSTR string, SYSTEMTIME* time, DWORD reserved )
2310 {
2311     BOOL ret = FALSE;
2312     WCHAR *stringW;
2313     int len;
2314
2315     TRACE( "%s %p 0x%08lx\n", debugstr_a(string), time, reserved );
2316
2317     len = MultiByteToWideChar( CP_ACP, 0, string, -1, NULL, 0 );
2318     stringW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
2319
2320     if (stringW)
2321     {
2322         MultiByteToWideChar( CP_ACP, 0, string, -1, stringW, len );
2323         ret = InternetTimeToSystemTimeW( stringW, time, reserved );
2324         HeapFree( GetProcessHeap(), 0, stringW );
2325     }
2326     return ret;
2327 }
2328
2329 /***********************************************************************
2330  *           InternetTimeToSystemTimeW (WININET.@)
2331  */
2332 BOOL WINAPI InternetTimeToSystemTimeW( LPCWSTR string, SYSTEMTIME* time, DWORD reserved )
2333 {
2334     unsigned int i;
2335     WCHAR *s = (LPWSTR)string;
2336
2337     TRACE( "%s %p 0x%08lx\n", debugstr_w(string), time, reserved );
2338
2339     if (!string || !time) return FALSE;
2340
2341     /* Windows does this too */
2342     GetSystemTime( time );
2343
2344     /*  Convert an RFC1123 time such as 'Fri, 07 Jan 2005 12:06:35 GMT' into
2345      *  a SYSTEMTIME structure.
2346      */
2347
2348     while (*s && !isalphaW( *s )) s++;
2349     if (s[0] == '\0' || s[1] == '\0' || s[2] == '\0') return TRUE;
2350     time->wDayOfWeek = 7;
2351
2352     for (i = 0; i < 7; i++)
2353     {
2354         if (toupperW( WININET_wkday[i][0] ) == toupperW( s[0] ) &&
2355             toupperW( WININET_wkday[i][1] ) == toupperW( s[1] ) &&
2356             toupperW( WININET_wkday[i][2] ) == toupperW( s[2] ) )
2357         {
2358             time->wDayOfWeek = i;
2359             break;
2360         }
2361     }
2362
2363     if (time->wDayOfWeek > 6) return TRUE;
2364     while (*s && !isdigitW( *s )) s++;
2365     time->wDay = strtolW( s, &s, 10 );
2366
2367     while (*s && !isalphaW( *s )) s++;
2368     if (s[0] == '\0' || s[1] == '\0' || s[2] == '\0') return TRUE;
2369     time->wMonth = 0;
2370
2371     for (i = 0; i < 12; i++)
2372     {
2373         if (toupperW( WININET_month[i][0]) == toupperW( s[0] ) &&
2374             toupperW( WININET_month[i][1]) == toupperW( s[1] ) &&
2375             toupperW( WININET_month[i][2]) == toupperW( s[2] ) )
2376         {
2377             time->wMonth = i + 1;
2378             break;
2379         }
2380     }
2381     if (time->wMonth == 0) return TRUE;
2382
2383     while (*s && !isdigitW( *s )) s++;
2384     if (*s == '\0') return TRUE;
2385     time->wYear = strtolW( s, &s, 10 );
2386
2387     while (*s && !isdigitW( *s )) s++;
2388     if (*s == '\0') return TRUE;
2389     time->wHour = strtolW( s, &s, 10 );
2390
2391     while (*s && !isdigitW( *s )) s++;
2392     if (*s == '\0') return TRUE;
2393     time->wMinute = strtolW( s, &s, 10 );
2394
2395     while (*s && !isdigitW( *s )) s++;
2396     if (*s == '\0') return TRUE;
2397     time->wSecond = strtolW( s, &s, 10 );
2398
2399     time->wMilliseconds = 0;
2400     return TRUE;
2401 }
2402
2403 /***********************************************************************
2404  *      InternetCheckConnectionA (WININET.@)
2405  *
2406  * Pings a requested host to check internet connection
2407  *
2408  * RETURNS
2409  *   TRUE on success and FALSE on failure. If a failure then
2410  *   ERROR_NOT_CONNECTED is placesd into GetLastError
2411  *
2412  */
2413 BOOL WINAPI InternetCheckConnectionA( LPCSTR lpszUrl, DWORD dwFlags, DWORD dwReserved )
2414 {
2415 /*
2416  * this is a kludge which runs the resident ping program and reads the output.
2417  *
2418  * Anyone have a better idea?
2419  */
2420
2421   BOOL   rc = FALSE;
2422   char command[1024];
2423   char host[1024];
2424   int status = -1;
2425
2426   FIXME("\n");
2427
2428   /*
2429    * Crack or set the Address
2430    */
2431   if (lpszUrl == NULL)
2432   {
2433      /*
2434       * According to the doc we are supost to use the ip for the next
2435       * server in the WnInet internal server database. I have
2436       * no idea what that is or how to get it.
2437       *
2438       * So someone needs to implement this.
2439       */
2440      FIXME("Unimplemented with URL of NULL\n");
2441      return TRUE;
2442   }
2443   else
2444   {
2445      URL_COMPONENTSA components;
2446
2447      ZeroMemory(&components,sizeof(URL_COMPONENTSA));
2448      components.lpszHostName = (LPSTR)&host;
2449      components.dwHostNameLength = 1024;
2450
2451      if (!InternetCrackUrlA(lpszUrl,0,0,&components))
2452        goto End;
2453
2454      TRACE("host name : %s\n",components.lpszHostName);
2455   }
2456
2457   /*
2458    * Build our ping command
2459    */
2460   strcpy(command,"ping -w 1 ");
2461   strcat(command,host);
2462   strcat(command," >/dev/null 2>/dev/null");
2463
2464   TRACE("Ping command is : %s\n",command);
2465
2466   status = system(command);
2467
2468   TRACE("Ping returned a code of %i \n",status);
2469
2470   /* Ping return code of 0 indicates success */
2471   if (status == 0)
2472      rc = TRUE;
2473
2474 End:
2475
2476   if (rc == FALSE)
2477     SetLastError(ERROR_NOT_CONNECTED);
2478
2479   return rc;
2480 }
2481
2482
2483 /***********************************************************************
2484  *      InternetCheckConnectionW (WININET.@)
2485  *
2486  * Pings a requested host to check internet connection
2487  *
2488  * RETURNS
2489  *   TRUE on success and FALSE on failure. If a failure then
2490  *   ERROR_NOT_CONNECTED is placed into GetLastError
2491  *
2492  */
2493 BOOL WINAPI InternetCheckConnectionW(LPCWSTR lpszUrl, DWORD dwFlags, DWORD dwReserved)
2494 {
2495     CHAR *szUrl;
2496     INT len;
2497     BOOL rc;
2498
2499     len = WideCharToMultiByte(CP_ACP, 0, lpszUrl, -1, NULL, 0, NULL, NULL);
2500     if (!(szUrl = HeapAlloc(GetProcessHeap(), 0, len*sizeof(CHAR))))
2501         return FALSE;
2502     WideCharToMultiByte(CP_ACP, 0, lpszUrl, -1, szUrl, len, NULL, NULL);
2503     rc = InternetCheckConnectionA((LPCSTR)szUrl, dwFlags, dwReserved);
2504     HeapFree(GetProcessHeap(), 0, szUrl);
2505     
2506     return rc;
2507 }
2508
2509
2510 /**********************************************************
2511  *      INTERNET_InternetOpenUrlW (internal)
2512  *
2513  * Opens an URL
2514  *
2515  * RETURNS
2516  *   handle of connection or NULL on failure
2517  */
2518 HINTERNET WINAPI INTERNET_InternetOpenUrlW(LPWININETAPPINFOW hIC, LPCWSTR lpszUrl,
2519     LPCWSTR lpszHeaders, DWORD dwHeadersLength, DWORD dwFlags, DWORD dwContext)
2520 {
2521     URL_COMPONENTSW urlComponents;
2522     WCHAR protocol[32], hostName[MAXHOSTNAME], userName[1024];
2523     WCHAR password[1024], path[2048], extra[1024];
2524     HINTERNET client = NULL, client1 = NULL;
2525     
2526     TRACE("(%p, %s, %s, %08lx, %08lx, %08lx)\n", hIC, debugstr_w(lpszUrl), debugstr_w(lpszHeaders),
2527           dwHeadersLength, dwFlags, dwContext);
2528     
2529     urlComponents.dwStructSize = sizeof(URL_COMPONENTSW);
2530     urlComponents.lpszScheme = protocol;
2531     urlComponents.dwSchemeLength = 32;
2532     urlComponents.lpszHostName = hostName;
2533     urlComponents.dwHostNameLength = MAXHOSTNAME;
2534     urlComponents.lpszUserName = userName;
2535     urlComponents.dwUserNameLength = 1024;
2536     urlComponents.lpszPassword = password;
2537     urlComponents.dwPasswordLength = 1024;
2538     urlComponents.lpszUrlPath = path;
2539     urlComponents.dwUrlPathLength = 2048;
2540     urlComponents.lpszExtraInfo = extra;
2541     urlComponents.dwExtraInfoLength = 1024;
2542     if(!InternetCrackUrlW(lpszUrl, strlenW(lpszUrl), 0, &urlComponents))
2543         return NULL;
2544     switch(urlComponents.nScheme) {
2545     case INTERNET_SCHEME_FTP:
2546         if(urlComponents.nPort == 0)
2547             urlComponents.nPort = INTERNET_DEFAULT_FTP_PORT;
2548         client = FTP_Connect(hIC, hostName, urlComponents.nPort,
2549                              userName, password, dwFlags, dwContext, INET_OPENURL);
2550         if(client == NULL)
2551             break;
2552         client1 = FtpOpenFileW(client, path, GENERIC_READ, dwFlags, dwContext);
2553         if(client1 == NULL) {
2554             InternetCloseHandle(client);
2555             break;
2556         }
2557         break;
2558         
2559     case INTERNET_SCHEME_HTTP:
2560     case INTERNET_SCHEME_HTTPS: {
2561         static const WCHAR szStars[] = { '*','/','*', 0 };
2562         LPCWSTR accept[2] = { szStars, NULL };
2563         if(urlComponents.nPort == 0) {
2564             if(urlComponents.nScheme == INTERNET_SCHEME_HTTP)
2565                 urlComponents.nPort = INTERNET_DEFAULT_HTTP_PORT;
2566             else
2567                 urlComponents.nPort = INTERNET_DEFAULT_HTTPS_PORT;
2568         }
2569         /* FIXME: should use pointers, not handles, as handles are not thread-safe */
2570         client = HTTP_Connect(hIC, hostName, urlComponents.nPort,
2571                               userName, password, dwFlags, dwContext, INET_OPENURL);
2572         if(client == NULL)
2573             break;
2574         client1 = HttpOpenRequestW(client, NULL, path, NULL, NULL, accept, dwFlags, dwContext);
2575         if(client1 == NULL) {
2576             InternetCloseHandle(client);
2577             break;
2578         }
2579         HttpAddRequestHeadersW(client1, lpszHeaders, dwHeadersLength, HTTP_ADDREQ_FLAG_ADD);
2580         if (!HttpSendRequestW(client1, NULL, 0, NULL, 0)) {
2581             InternetCloseHandle(client1);
2582             client1 = NULL;
2583             break;
2584         }
2585     }
2586     case INTERNET_SCHEME_GOPHER:
2587         /* gopher doesn't seem to be implemented in wine, but it's supposed
2588          * to be supported by InternetOpenUrlA. */
2589     default:
2590         break;
2591     }
2592
2593     TRACE(" %p <--\n", client1);
2594     
2595     return client1;
2596 }
2597
2598 /**********************************************************
2599  *      InternetOpenUrlW (WININET.@)
2600  *
2601  * Opens an URL
2602  *
2603  * RETURNS
2604  *   handle of connection or NULL on failure
2605  */
2606 HINTERNET WINAPI InternetOpenUrlW(HINTERNET hInternet, LPCWSTR lpszUrl,
2607     LPCWSTR lpszHeaders, DWORD dwHeadersLength, DWORD dwFlags, DWORD dwContext)
2608 {
2609     HINTERNET ret = NULL;
2610     LPWININETAPPINFOW hIC = NULL;
2611
2612     if (TRACE_ON(wininet)) {
2613         TRACE("(%p, %s, %s, %08lx, %08lx, %08lx)\n", hInternet, debugstr_w(lpszUrl), debugstr_w(lpszHeaders),
2614               dwHeadersLength, dwFlags, dwContext);
2615         TRACE("  flags :");
2616         dump_INTERNET_FLAGS(dwFlags);
2617     }
2618
2619     hIC = (LPWININETAPPINFOW) WININET_GetObject( hInternet );
2620     if (NULL == hIC ||  hIC->hdr.htype != WH_HINIT) {
2621         INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
2622         goto lend;
2623     }
2624     
2625     if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC) {
2626         WORKREQUEST workRequest;
2627         struct WORKREQ_INTERNETOPENURLW *req;
2628         
2629         workRequest.asyncall = INTERNETOPENURLW;
2630         workRequest.hdr = WININET_AddRef( &hIC->hdr );
2631         req = &workRequest.u.InternetOpenUrlW;
2632         if (lpszUrl)
2633             req->lpszUrl = WININET_strdupW(lpszUrl);
2634         else
2635             req->lpszUrl = 0;
2636         if (lpszHeaders)
2637             req->lpszHeaders = WININET_strdupW(lpszHeaders);
2638         else
2639             req->lpszHeaders = 0;
2640         req->dwHeadersLength = dwHeadersLength;
2641         req->dwFlags = dwFlags;
2642         req->dwContext = dwContext;
2643         
2644         INTERNET_AsyncCall(&workRequest);
2645         /*
2646          * This is from windows.
2647          */
2648         SetLastError(ERROR_IO_PENDING);
2649     } else {
2650         ret = INTERNET_InternetOpenUrlW(hIC, lpszUrl, lpszHeaders, dwHeadersLength, dwFlags, dwContext);
2651     }
2652     
2653   lend:
2654     if( hIC )
2655         WININET_Release( &hIC->hdr );
2656     TRACE(" %p <--\n", ret);
2657     
2658     return ret;
2659 }
2660
2661 /**********************************************************
2662  *      InternetOpenUrlA (WININET.@)
2663  *
2664  * Opens an URL
2665  *
2666  * RETURNS
2667  *   handle of connection or NULL on failure
2668  */
2669 HINTERNET WINAPI InternetOpenUrlA(HINTERNET hInternet, LPCSTR lpszUrl,
2670     LPCSTR lpszHeaders, DWORD dwHeadersLength, DWORD dwFlags, DWORD dwContext)
2671 {
2672     HINTERNET rc = (HINTERNET)NULL;
2673
2674     INT lenUrl;
2675     INT lenHeaders = 0;
2676     LPWSTR szUrl = NULL;
2677     LPWSTR szHeaders = NULL;
2678
2679     TRACE("\n");
2680
2681     if(lpszUrl) {
2682         lenUrl = MultiByteToWideChar(CP_ACP, 0, lpszUrl, -1, NULL, 0 );
2683         szUrl = HeapAlloc(GetProcessHeap(), 0, lenUrl*sizeof(WCHAR));
2684         if(!szUrl)
2685             return (HINTERNET)NULL;
2686         MultiByteToWideChar(CP_ACP, 0, lpszUrl, -1, szUrl, lenUrl);
2687     }
2688     
2689     if(lpszHeaders) {
2690         lenHeaders = MultiByteToWideChar(CP_ACP, 0, lpszHeaders, dwHeadersLength, NULL, 0 );
2691         szHeaders = HeapAlloc(GetProcessHeap(), 0, lenHeaders*sizeof(WCHAR));
2692         if(!szHeaders) {
2693             HeapFree(GetProcessHeap(), 0, szUrl);
2694             return (HINTERNET)NULL;
2695         }
2696         MultiByteToWideChar(CP_ACP, 0, lpszHeaders, dwHeadersLength, szHeaders, lenHeaders);
2697     }
2698     
2699     rc = InternetOpenUrlW(hInternet, szUrl, szHeaders,
2700         lenHeaders, dwFlags, dwContext);
2701
2702     HeapFree(GetProcessHeap(), 0, szUrl);
2703     HeapFree(GetProcessHeap(), 0, szHeaders);
2704
2705     return rc;
2706 }
2707
2708
2709 /***********************************************************************
2710  *           INTERNET_SetLastError (internal)
2711  *
2712  * Set last thread specific error
2713  *
2714  * RETURNS
2715  *
2716  */
2717 void INTERNET_SetLastError(DWORD dwError)
2718 {
2719     LPWITHREADERROR lpwite = (LPWITHREADERROR)TlsGetValue(g_dwTlsErrIndex);
2720
2721     SetLastError(dwError);
2722     if(lpwite)
2723         lpwite->dwError = dwError;
2724 }
2725
2726
2727 /***********************************************************************
2728  *           INTERNET_GetLastError (internal)
2729  *
2730  * Get last thread specific error
2731  *
2732  * RETURNS
2733  *
2734  */
2735 DWORD INTERNET_GetLastError(void)
2736 {
2737     LPWITHREADERROR lpwite = (LPWITHREADERROR)TlsGetValue(g_dwTlsErrIndex);
2738     return lpwite->dwError;
2739 }
2740
2741
2742 /***********************************************************************
2743  *           INTERNET_WorkerThreadFunc (internal)
2744  *
2745  * Worker thread execution function
2746  *
2747  * RETURNS
2748  *
2749  */
2750 static DWORD INTERNET_WorkerThreadFunc(LPVOID *lpvParam)
2751 {
2752     DWORD dwWaitRes;
2753
2754     while (1)
2755     {
2756         if(dwNumJobs > 0) {
2757             INTERNET_ExecuteWork();
2758             continue;
2759         }
2760         dwWaitRes = WaitForMultipleObjects(2, hEventArray, FALSE, MAX_IDLE_WORKER);
2761
2762         if (dwWaitRes == WAIT_OBJECT_0 + 1)
2763             INTERNET_ExecuteWork();
2764         else
2765             break;
2766
2767         InterlockedIncrement(&dwNumIdleThreads);
2768     }
2769
2770     InterlockedDecrement(&dwNumIdleThreads);
2771     InterlockedDecrement(&dwNumThreads);
2772     TRACE("Worker thread exiting\n");
2773     return TRUE;
2774 }
2775
2776
2777 /***********************************************************************
2778  *           INTERNET_InsertWorkRequest (internal)
2779  *
2780  * Insert work request into queue
2781  *
2782  * RETURNS
2783  *
2784  */
2785 static BOOL INTERNET_InsertWorkRequest(LPWORKREQUEST lpWorkRequest)
2786 {
2787     BOOL bSuccess = FALSE;
2788     LPWORKREQUEST lpNewRequest;
2789
2790     TRACE("\n");
2791
2792     lpNewRequest = HeapAlloc(GetProcessHeap(), 0, sizeof(WORKREQUEST));
2793     if (lpNewRequest)
2794     {
2795         memcpy(lpNewRequest, lpWorkRequest, sizeof(WORKREQUEST));
2796         lpNewRequest->prev = NULL;
2797
2798         EnterCriticalSection(&csQueue);
2799
2800         lpNewRequest->next = lpWorkQueueTail;
2801         if (lpWorkQueueTail)
2802             lpWorkQueueTail->prev = lpNewRequest;
2803         lpWorkQueueTail = lpNewRequest;
2804         if (!lpHeadWorkQueue)
2805             lpHeadWorkQueue = lpWorkQueueTail;
2806
2807         LeaveCriticalSection(&csQueue);
2808
2809         bSuccess = TRUE;
2810         InterlockedIncrement(&dwNumJobs);
2811     }
2812
2813     return bSuccess;
2814 }
2815
2816
2817 /***********************************************************************
2818  *           INTERNET_GetWorkRequest (internal)
2819  *
2820  * Retrieves work request from queue
2821  *
2822  * RETURNS
2823  *
2824  */
2825 static BOOL INTERNET_GetWorkRequest(LPWORKREQUEST lpWorkRequest)
2826 {
2827     BOOL bSuccess = FALSE;
2828     LPWORKREQUEST lpRequest = NULL;
2829
2830     TRACE("\n");
2831
2832     EnterCriticalSection(&csQueue);
2833
2834     if (lpHeadWorkQueue)
2835     {
2836         lpRequest = lpHeadWorkQueue;
2837         lpHeadWorkQueue = lpHeadWorkQueue->prev;
2838         if (lpRequest == lpWorkQueueTail)
2839             lpWorkQueueTail = lpHeadWorkQueue;
2840     }
2841
2842     LeaveCriticalSection(&csQueue);
2843
2844     if (lpRequest)
2845     {
2846         memcpy(lpWorkRequest, lpRequest, sizeof(WORKREQUEST));
2847         HeapFree(GetProcessHeap(), 0, lpRequest);
2848         bSuccess = TRUE;
2849         InterlockedDecrement(&dwNumJobs);
2850     }
2851
2852     return bSuccess;
2853 }
2854
2855
2856 /***********************************************************************
2857  *           INTERNET_AsyncCall (internal)
2858  *
2859  * Retrieves work request from queue
2860  *
2861  * RETURNS
2862  *
2863  */
2864 BOOL INTERNET_AsyncCall(LPWORKREQUEST lpWorkRequest)
2865 {
2866     HANDLE hThread;
2867     DWORD dwTID;
2868     BOOL bSuccess = FALSE;
2869
2870     TRACE("\n");
2871
2872     if (InterlockedDecrement(&dwNumIdleThreads) < 0)
2873     {
2874         InterlockedIncrement(&dwNumIdleThreads);
2875
2876         if (InterlockedIncrement(&dwNumThreads) > MAX_WORKER_THREADS ||
2877             !(hThread = CreateThread(NULL, 0,
2878             (LPTHREAD_START_ROUTINE)INTERNET_WorkerThreadFunc, NULL, 0, &dwTID)))
2879         {
2880             InterlockedDecrement(&dwNumThreads);
2881             INTERNET_SetLastError(ERROR_INTERNET_ASYNC_THREAD_FAILED);
2882             goto lerror;
2883         }
2884
2885         TRACE("Created new thread\n");
2886     }
2887
2888     bSuccess = TRUE;
2889     INTERNET_InsertWorkRequest(lpWorkRequest);
2890     SetEvent(hWorkEvent);
2891
2892 lerror:
2893
2894     return bSuccess;
2895 }
2896
2897
2898 /***********************************************************************
2899  *           INTERNET_ExecuteWork (internal)
2900  *
2901  * RETURNS
2902  *
2903  */
2904 static VOID INTERNET_ExecuteWork(void)
2905 {
2906     WORKREQUEST workRequest;
2907
2908     TRACE("\n");
2909
2910     if (!INTERNET_GetWorkRequest(&workRequest))
2911         return;
2912
2913     switch (workRequest.asyncall)
2914     {
2915     case FTPPUTFILEW:
2916         {
2917         struct WORKREQ_FTPPUTFILEW *req = &workRequest.u.FtpPutFileW;
2918         LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest.hdr;
2919
2920         TRACE("FTPPUTFILEW %p\n", lpwfs);
2921
2922         FTP_FtpPutFileW(lpwfs, req->lpszLocalFile,
2923                    req->lpszNewRemoteFile, req->dwFlags, req->dwContext);
2924
2925         HeapFree(GetProcessHeap(), 0, req->lpszLocalFile);
2926         HeapFree(GetProcessHeap(), 0, req->lpszNewRemoteFile);
2927         }
2928         break;
2929
2930     case FTPSETCURRENTDIRECTORYW:
2931         {
2932         struct WORKREQ_FTPSETCURRENTDIRECTORYW *req;
2933         LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest.hdr;
2934
2935         TRACE("FTPSETCURRENTDIRECTORYW %p\n", lpwfs);
2936
2937         req = &workRequest.u.FtpSetCurrentDirectoryW;
2938         FTP_FtpSetCurrentDirectoryW(lpwfs, req->lpszDirectory);
2939         HeapFree(GetProcessHeap(), 0, req->lpszDirectory);
2940         }
2941         break;
2942
2943     case FTPCREATEDIRECTORYW:
2944         {
2945         struct WORKREQ_FTPCREATEDIRECTORYW *req;
2946         LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest.hdr;
2947
2948         TRACE("FTPCREATEDIRECTORYW %p\n", lpwfs);
2949
2950         req = &workRequest.u.FtpCreateDirectoryW;
2951         FTP_FtpCreateDirectoryW(lpwfs, req->lpszDirectory);
2952         HeapFree(GetProcessHeap(), 0, req->lpszDirectory);
2953         }
2954         break;
2955
2956     case FTPFINDFIRSTFILEW:
2957         {
2958         struct WORKREQ_FTPFINDFIRSTFILEW *req;
2959         LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest.hdr;
2960
2961         TRACE("FTPFINDFIRSTFILEW %p\n", lpwfs);
2962
2963         req = &workRequest.u.FtpFindFirstFileW;
2964         FTP_FtpFindFirstFileW(lpwfs, req->lpszSearchFile,
2965            req->lpFindFileData, req->dwFlags, req->dwContext);
2966         HeapFree(GetProcessHeap(), 0, req->lpszSearchFile);
2967         }
2968         break;
2969
2970     case FTPGETCURRENTDIRECTORYW:
2971         {
2972         struct WORKREQ_FTPGETCURRENTDIRECTORYW *req;
2973         LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest.hdr;
2974
2975         TRACE("FTPGETCURRENTDIRECTORYW %p\n", lpwfs);
2976
2977         req = &workRequest.u.FtpGetCurrentDirectoryW;
2978         FTP_FtpGetCurrentDirectoryW(lpwfs,
2979                 req->lpszDirectory, req->lpdwDirectory);
2980         }
2981         break;
2982
2983     case FTPOPENFILEW:
2984         {
2985         struct WORKREQ_FTPOPENFILEW *req = &workRequest.u.FtpOpenFileW;
2986         LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest.hdr;
2987
2988         TRACE("FTPOPENFILEW %p\n", lpwfs);
2989
2990         FTP_FtpOpenFileW(lpwfs, req->lpszFilename,
2991             req->dwAccess, req->dwFlags, req->dwContext);
2992         HeapFree(GetProcessHeap(), 0, req->lpszFilename);
2993         }
2994         break;
2995
2996     case FTPGETFILEW:
2997         {
2998         struct WORKREQ_FTPGETFILEW *req = &workRequest.u.FtpGetFileW;
2999         LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest.hdr;
3000
3001         TRACE("FTPGETFILEW %p\n", lpwfs);
3002
3003         FTP_FtpGetFileW(lpwfs, req->lpszRemoteFile,
3004                  req->lpszNewFile, req->fFailIfExists,
3005                  req->dwLocalFlagsAttribute, req->dwFlags, req->dwContext);
3006         HeapFree(GetProcessHeap(), 0, req->lpszRemoteFile);
3007         HeapFree(GetProcessHeap(), 0, req->lpszNewFile);
3008         }
3009         break;
3010
3011     case FTPDELETEFILEW:
3012         {
3013         struct WORKREQ_FTPDELETEFILEW *req = &workRequest.u.FtpDeleteFileW;
3014         LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest.hdr;
3015
3016         TRACE("FTPDELETEFILEW %p\n", lpwfs);
3017
3018         FTP_FtpDeleteFileW(lpwfs, req->lpszFilename);
3019         HeapFree(GetProcessHeap(), 0, req->lpszFilename);
3020         }
3021         break;
3022
3023     case FTPREMOVEDIRECTORYW:
3024         {
3025         struct WORKREQ_FTPREMOVEDIRECTORYW *req;
3026         LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest.hdr;
3027
3028         TRACE("FTPREMOVEDIRECTORYW %p\n", lpwfs);
3029
3030         req = &workRequest.u.FtpRemoveDirectoryW;
3031         FTP_FtpRemoveDirectoryW(lpwfs, req->lpszDirectory);
3032         HeapFree(GetProcessHeap(), 0, req->lpszDirectory);
3033         }
3034         break;
3035
3036     case FTPRENAMEFILEW:
3037         {
3038         struct WORKREQ_FTPRENAMEFILEW *req = &workRequest.u.FtpRenameFileW;
3039         LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest.hdr;
3040
3041         TRACE("FTPRENAMEFILEW %p\n", lpwfs);
3042
3043         FTP_FtpRenameFileW(lpwfs, req->lpszSrcFile, req->lpszDestFile);
3044         HeapFree(GetProcessHeap(), 0, req->lpszSrcFile);
3045         HeapFree(GetProcessHeap(), 0, req->lpszDestFile);
3046         }
3047         break;
3048
3049     case INTERNETFINDNEXTW:
3050         {
3051         struct WORKREQ_INTERNETFINDNEXTW *req;
3052         LPWININETFINDNEXTW lpwh = (LPWININETFINDNEXTW) workRequest.hdr;
3053
3054         TRACE("INTERNETFINDNEXTW %p\n", lpwh);
3055
3056         req = &workRequest.u.InternetFindNextW;
3057         INTERNET_FindNextFileW(lpwh, req->lpFindFileData);
3058         }
3059         break;
3060
3061     case HTTPSENDREQUESTW:
3062         {
3063         struct WORKREQ_HTTPSENDREQUESTW *req = &workRequest.u.HttpSendRequestW;
3064         LPWININETHTTPREQW lpwhr = (LPWININETHTTPREQW) workRequest.hdr;
3065
3066         TRACE("HTTPSENDREQUESTW %p\n", lpwhr);
3067
3068         HTTP_HttpSendRequestW(lpwhr, req->lpszHeader,
3069                 req->dwHeaderLength, req->lpOptional, req->dwOptionalLength);
3070
3071         HeapFree(GetProcessHeap(), 0, req->lpszHeader);
3072         }
3073         break;
3074
3075     case HTTPOPENREQUESTW:
3076         {
3077         struct WORKREQ_HTTPOPENREQUESTW *req = &workRequest.u.HttpOpenRequestW;
3078         LPWININETHTTPSESSIONW lpwhs = (LPWININETHTTPSESSIONW) workRequest.hdr;
3079
3080         TRACE("HTTPOPENREQUESTW %p\n", lpwhs);
3081
3082         HTTP_HttpOpenRequestW(lpwhs, req->lpszVerb,
3083             req->lpszObjectName, req->lpszVersion, req->lpszReferrer,
3084             req->lpszAcceptTypes, req->dwFlags, req->dwContext);
3085
3086         HeapFree(GetProcessHeap(), 0, req->lpszVerb);
3087         HeapFree(GetProcessHeap(), 0, req->lpszObjectName);
3088         HeapFree(GetProcessHeap(), 0, req->lpszVersion);
3089         HeapFree(GetProcessHeap(), 0, req->lpszReferrer);
3090         }
3091         break;
3092
3093     case SENDCALLBACK:
3094         {
3095         struct WORKREQ_SENDCALLBACK *req = &workRequest.u.SendCallback;
3096
3097         TRACE("SENDCALLBACK %p\n", workRequest.hdr);
3098
3099         SendSyncCallback(workRequest.hdr,
3100                          req->dwContext, req->dwInternetStatus, req->lpvStatusInfo,
3101                          req->dwStatusInfoLength);
3102
3103         /* And frees the copy of the status info */
3104         HeapFree(GetProcessHeap(), 0, req->lpvStatusInfo);
3105         }
3106         break;
3107
3108     case INTERNETOPENURLW:
3109         {
3110         struct WORKREQ_INTERNETOPENURLW *req = &workRequest.u.InternetOpenUrlW;
3111         LPWININETAPPINFOW hIC = (LPWININETAPPINFOW) workRequest.hdr;
3112         
3113         TRACE("INTERNETOPENURLW %p\n", hIC);
3114
3115         INTERNET_InternetOpenUrlW(hIC, req->lpszUrl,
3116                                   req->lpszHeaders, req->dwHeadersLength, req->dwFlags, req->dwContext);
3117         HeapFree(GetProcessHeap(), 0, req->lpszUrl);
3118         HeapFree(GetProcessHeap(), 0, req->lpszHeaders);
3119         }
3120         break;
3121     }
3122     WININET_Release( workRequest.hdr );
3123 }
3124
3125
3126 /***********************************************************************
3127  *          INTERNET_GetResponseBuffer
3128  *
3129  * RETURNS
3130  *
3131  */
3132 LPSTR INTERNET_GetResponseBuffer(void)
3133 {
3134     LPWITHREADERROR lpwite = (LPWITHREADERROR)TlsGetValue(g_dwTlsErrIndex);
3135     TRACE("\n");
3136     return lpwite->response;
3137 }
3138
3139 /***********************************************************************
3140  *           INTERNET_GetNextLine  (internal)
3141  *
3142  * Parse next line in directory string listing
3143  *
3144  * RETURNS
3145  *   Pointer to beginning of next line
3146  *   NULL on failure
3147  *
3148  */
3149
3150 LPSTR INTERNET_GetNextLine(INT nSocket, LPDWORD dwLen)
3151 {
3152     struct timeval tv;
3153     fd_set infd;
3154     BOOL bSuccess = FALSE;
3155     INT nRecv = 0;
3156     LPSTR lpszBuffer = INTERNET_GetResponseBuffer();
3157
3158     TRACE("\n");
3159
3160     FD_ZERO(&infd);
3161     FD_SET(nSocket, &infd);
3162     tv.tv_sec=RESPONSE_TIMEOUT;
3163     tv.tv_usec=0;
3164
3165     while (nRecv < MAX_REPLY_LEN)
3166     {
3167         if (select(nSocket+1,&infd,NULL,NULL,&tv) > 0)
3168         {
3169             if (recv(nSocket, &lpszBuffer[nRecv], 1, 0) <= 0)
3170             {
3171                 INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS);
3172                 goto lend;
3173             }
3174
3175             if (lpszBuffer[nRecv] == '\n')
3176             {
3177                 bSuccess = TRUE;
3178                 break;
3179             }
3180             if (lpszBuffer[nRecv] != '\r')
3181                 nRecv++;
3182         }
3183         else
3184         {
3185             INTERNET_SetLastError(ERROR_INTERNET_TIMEOUT);
3186             goto lend;
3187         }
3188     }
3189
3190 lend:
3191     if (bSuccess)
3192     {
3193         lpszBuffer[nRecv] = '\0';
3194         *dwLen = nRecv - 1;
3195         TRACE(":%d %s\n", nRecv, lpszBuffer);
3196         return lpszBuffer;
3197     }
3198     else
3199     {
3200         return NULL;
3201     }
3202 }
3203
3204 /***********************************************************************
3205  *
3206  */
3207 BOOL WINAPI InternetQueryDataAvailable( HINTERNET hFile,
3208                                 LPDWORD lpdwNumberOfBytesAvailble,
3209                                 DWORD dwFlags, DWORD dwConext)
3210 {
3211     LPWININETHTTPREQW lpwhr;
3212     INT retval = -1;
3213     char buffer[4048];
3214
3215     lpwhr = (LPWININETHTTPREQW) WININET_GetObject( hFile );
3216     if (NULL == lpwhr)
3217     {
3218         SetLastError(ERROR_NO_MORE_FILES);
3219         return FALSE;
3220     }
3221
3222     TRACE("-->  %p %i\n",lpwhr,lpwhr->hdr.htype);
3223
3224     switch (lpwhr->hdr.htype)
3225     {
3226     case WH_HHTTPREQ:
3227         if (!NETCON_recv(&lpwhr->netConnection, buffer,
3228                          4048, MSG_PEEK, (int *)lpdwNumberOfBytesAvailble))
3229         {
3230             SetLastError(ERROR_NO_MORE_FILES);
3231             retval = FALSE;
3232         }
3233         else
3234             retval = TRUE;
3235         break;
3236
3237     default:
3238         FIXME("unsupported file type\n");
3239         break;
3240     }
3241     WININET_Release( &lpwhr->hdr );
3242
3243     TRACE("<-- %i\n",retval);
3244     return (retval+1);
3245 }
3246
3247
3248 /***********************************************************************
3249  *
3250  */
3251 BOOL WINAPI InternetLockRequestFile( HINTERNET hInternet, HANDLE
3252 *lphLockReqHandle)
3253 {
3254     FIXME("STUB\n");
3255     return FALSE;
3256 }
3257
3258 BOOL WINAPI InternetUnlockRequestFile( HANDLE hLockHandle)
3259 {
3260     FIXME("STUB\n");
3261     return FALSE;
3262 }
3263
3264
3265 /***********************************************************************
3266  *           InternetAutodial
3267  *
3268  * On windows this function is supposed to dial the default internet
3269  * connection. We don't want to have Wine dial out to the internet so
3270  * we return TRUE by default. It might be nice to check if we are connected.
3271  *
3272  * RETURNS
3273  *   TRUE on success
3274  *   FALSE on failure
3275  *
3276  */
3277 BOOL WINAPI InternetAutodial(DWORD dwFlags, HWND hwndParent)
3278 {
3279     FIXME("STUB\n");
3280
3281     /* Tell that we are connected to the internet. */
3282     return TRUE;
3283 }
3284
3285 /***********************************************************************
3286  *           InternetAutodialHangup
3287  *
3288  * Hangs up a connection made with InternetAutodial
3289  *
3290  * PARAM
3291  *    dwReserved
3292  * RETURNS
3293  *   TRUE on success
3294  *   FALSE on failure
3295  *
3296  */
3297 BOOL WINAPI InternetAutodialHangup(DWORD dwReserved)
3298 {
3299     FIXME("STUB\n");
3300
3301     /* we didn't dial, we don't disconnect */
3302     return TRUE;
3303 }
3304
3305 /***********************************************************************
3306  *
3307  *         InternetCombineUrlA
3308  *
3309  * Combine a base URL with a relative URL
3310  *
3311  * RETURNS
3312  *   TRUE on success
3313  *   FALSE on failure
3314  *
3315  */
3316
3317 BOOL WINAPI InternetCombineUrlA(LPCSTR lpszBaseUrl, LPCSTR lpszRelativeUrl,
3318                                 LPSTR lpszBuffer, LPDWORD lpdwBufferLength,
3319                                 DWORD dwFlags)
3320 {
3321     HRESULT hr=S_OK;
3322
3323     TRACE("(%s, %s, %p, %p, 0x%08lx)\n", debugstr_a(lpszBaseUrl), debugstr_a(lpszRelativeUrl), lpszBuffer, lpdwBufferLength, dwFlags);
3324
3325     /* Flip this bit to correspond to URL_ESCAPE_UNSAFE */
3326     dwFlags ^= ICU_NO_ENCODE;
3327     hr=UrlCombineA(lpszBaseUrl,lpszRelativeUrl,lpszBuffer,lpdwBufferLength,dwFlags);
3328
3329     return (hr==S_OK);
3330 }
3331
3332 /***********************************************************************
3333  *
3334  *         InternetCombineUrlW
3335  *
3336  * Combine a base URL with a relative URL
3337  *
3338  * RETURNS
3339  *   TRUE on success
3340  *   FALSE on failure
3341  *
3342  */
3343
3344 BOOL WINAPI InternetCombineUrlW(LPCWSTR lpszBaseUrl, LPCWSTR lpszRelativeUrl,
3345                                 LPWSTR lpszBuffer, LPDWORD lpdwBufferLength,
3346                                 DWORD dwFlags)
3347 {
3348     HRESULT hr=S_OK;
3349
3350     TRACE("(%s, %s, %p, %p, 0x%08lx)\n", debugstr_w(lpszBaseUrl), debugstr_w(lpszRelativeUrl), lpszBuffer, lpdwBufferLength, dwFlags);
3351
3352     /* Flip this bit to correspond to URL_ESCAPE_UNSAFE */
3353     dwFlags ^= ICU_NO_ENCODE;
3354     hr=UrlCombineW(lpszBaseUrl,lpszRelativeUrl,lpszBuffer,lpdwBufferLength,dwFlags);
3355
3356     return (hr==S_OK);
3357 }
3358
3359 /***********************************************************************
3360  *
3361  *         InternetCreateUrlA
3362  *
3363  * RETURNS
3364  *   TRUE on success
3365  *   FALSE on failure
3366  *
3367  */
3368 BOOL WINAPI InternetCreateUrlA(LPURL_COMPONENTSA lpUrlComponents, DWORD dwFlags,
3369                                LPSTR lpszUrl, LPDWORD lpdwUrlLength)
3370 {
3371     FIXME("\n");
3372     return FALSE;
3373 }
3374
3375 DWORD WINAPI InternetConfirmZoneCrossingA( HWND hWnd, LPSTR szUrlPrev, LPSTR szUrlNew, BOOL bPost )
3376 {
3377     FIXME("(%p, %s, %s, %x) stub\n", hWnd, debugstr_a(szUrlPrev), debugstr_a(szUrlNew), bPost);
3378     return ERROR_SUCCESS;
3379 }
3380
3381 DWORD WINAPI InternetConfirmZoneCrossingW( HWND hWnd, LPWSTR szUrlPrev, LPWSTR szUrlNew, BOOL bPost )
3382 {
3383     FIXME("(%p, %s, %s, %x) stub\n", hWnd, debugstr_w(szUrlPrev), debugstr_w(szUrlNew), bPost);
3384     return ERROR_SUCCESS;
3385 }
3386
3387 DWORD WINAPI InternetDialA( HWND hwndParent, LPSTR lpszConnectoid, DWORD dwFlags,
3388                             LPDWORD lpdwConnection, DWORD dwReserved )
3389 {
3390     FIXME("(%p, %p, 0x%08lx, %p, 0x%08lx) stub\n", hwndParent, lpszConnectoid, dwFlags,
3391           lpdwConnection, dwReserved);
3392     return ERROR_SUCCESS;
3393 }
3394
3395 DWORD WINAPI InternetDialW( HWND hwndParent, LPWSTR lpszConnectoid, DWORD dwFlags,
3396                             LPDWORD lpdwConnection, DWORD dwReserved )
3397 {
3398     FIXME("(%p, %p, 0x%08lx, %p, 0x%08lx) stub\n", hwndParent, lpszConnectoid, dwFlags,
3399           lpdwConnection, dwReserved);
3400     return ERROR_SUCCESS;
3401 }
3402
3403 BOOL WINAPI InternetGoOnlineA( LPSTR lpszURL, HWND hwndParent, DWORD dwReserved )
3404 {
3405     FIXME("(%s, %p, 0x%08lx) stub\n", debugstr_a(lpszURL), hwndParent, dwReserved);
3406     return TRUE;
3407 }
3408
3409 BOOL WINAPI InternetGoOnlineW( LPWSTR lpszURL, HWND hwndParent, DWORD dwReserved )
3410 {
3411     FIXME("(%s, %p, 0x%08lx) stub\n", debugstr_w(lpszURL), hwndParent, dwReserved);
3412     return TRUE;
3413 }
3414
3415 DWORD WINAPI InternetHangUp( DWORD dwConnection, DWORD dwReserved )
3416 {
3417     FIXME("(0x%08lx, 0x%08lx) stub\n", dwConnection, dwReserved);
3418     return ERROR_SUCCESS;
3419 }
3420
3421 BOOL WINAPI CreateMD5SSOHash( PWSTR pszChallengeInfo, PWSTR pwszRealm, PWSTR pwszTarget,
3422                               PBYTE pbHexHash )
3423 {
3424     FIXME("(%s, %s, %s, %p) stub\n", debugstr_w(pszChallengeInfo), debugstr_w(pwszRealm),
3425           debugstr_w(pwszTarget), pbHexHash);
3426     return FALSE;
3427 }
3428
3429 BOOL WINAPI InternetClearAllPerSiteCookieDecisions( VOID )
3430 {
3431     FIXME("stub\n");
3432     return TRUE;
3433 }
3434
3435 BOOL WINAPI InternetEnumPerSiteCookieDecisionA( LPSTR pszSiteName, unsigned long *pcSiteNameSize,
3436                                                 unsigned long *pdwDecision, unsigned long dwIndex )
3437 {
3438     FIXME("(%s, %p, %p, 0x%08lx) stub\n",
3439           debugstr_a(pszSiteName), pcSiteNameSize, pdwDecision, dwIndex);
3440     return FALSE;
3441 }
3442
3443 BOOL WINAPI InternetEnumPerSiteCookieDecisionW( LPWSTR pszSiteName, unsigned long *pcSiteNameSize,
3444                                                 unsigned long *pdwDecision, unsigned long dwIndex )
3445 {
3446     FIXME("(%s, %p, %p, 0x%08lx) stub\n",
3447           debugstr_w(pszSiteName), pcSiteNameSize, pdwDecision, dwIndex);
3448     return FALSE;
3449 }
3450
3451 BOOL WINAPI InternetGetCookieExA( LPCSTR pchURL, LPCSTR pchCookieName, LPSTR pchCookieData,
3452                                   LPDWORD pcchCookieData, DWORD dwFlags, LPVOID lpReserved)
3453 {
3454     FIXME("(%s, %s, %s, %p, 0x%08lx, %p) stub\n",
3455           debugstr_a(pchURL), debugstr_a(pchCookieName), debugstr_a(pchCookieData),
3456           pcchCookieData, dwFlags, lpReserved);
3457     return FALSE;
3458 }
3459
3460 BOOL WINAPI InternetGetCookieExW( LPCWSTR pchURL, LPCWSTR pchCookieName, LPWSTR pchCookieData,
3461                                   LPDWORD pcchCookieData, DWORD dwFlags, LPVOID lpReserved)
3462 {
3463     FIXME("(%s, %s, %s, %p, 0x%08lx, %p) stub\n",
3464           debugstr_w(pchURL), debugstr_w(pchCookieName), debugstr_w(pchCookieData),
3465           pcchCookieData, dwFlags, lpReserved);
3466     return FALSE;
3467 }
3468
3469 BOOL WINAPI InternetGetPerSiteCookieDecisionA( LPCSTR pwchHostName, unsigned long *pResult )
3470 {
3471     FIXME("(%s, %p) stub\n", debugstr_a(pwchHostName), pResult);
3472     return FALSE;
3473 }
3474
3475 BOOL WINAPI InternetGetPerSiteCookieDecisionW( LPCWSTR pwchHostName, unsigned long *pResult )
3476 {
3477     FIXME("(%s, %p) stub\n", debugstr_w(pwchHostName), pResult);
3478     return FALSE;
3479 }
3480
3481 BOOL WINAPI InternetSetPerSiteCookieDecisionA( LPCSTR pchHostName, DWORD dwDecision )
3482 {
3483     FIXME("(%s, 0x%08lx) stub\n", debugstr_a(pchHostName), dwDecision);
3484     return FALSE;
3485 }
3486
3487 BOOL WINAPI InternetSetPerSiteCookieDecisionW( LPCWSTR pchHostName, DWORD dwDecision )
3488 {
3489     FIXME("(%s, 0x%08lx) stub\n", debugstr_w(pchHostName), dwDecision);
3490     return FALSE;
3491 }
3492
3493 DWORD WINAPI InternetSetCookieExA( LPCSTR lpszURL, LPCSTR lpszCookieName, LPCSTR lpszCookieData,
3494                                    DWORD dwFlags, DWORD_PTR dwReserved)
3495 {
3496     FIXME("(%s, %s, %s, 0x%08lx, 0x%08lx) stub\n",
3497           debugstr_a(lpszURL), debugstr_a(lpszCookieName), debugstr_a(lpszCookieData),
3498           dwFlags, dwReserved);
3499     return TRUE;
3500 }
3501
3502 DWORD WINAPI InternetSetCookieExW( LPCWSTR lpszURL, LPCWSTR lpszCookieName, LPCWSTR lpszCookieData,
3503                                    DWORD dwFlags, DWORD_PTR dwReserved)
3504 {
3505     FIXME("(%s, %s, %s, 0x%08lx, 0x%08lx) stub\n",
3506           debugstr_w(lpszURL), debugstr_w(lpszCookieName), debugstr_w(lpszCookieData),
3507           dwFlags, dwReserved);
3508     return TRUE;
3509 }
3510
3511 BOOL WINAPI ResumeSuspendedDownload( HINTERNET hInternet, DWORD dwError )
3512 {
3513     FIXME("(%p, 0x%08lx) stub\n", hInternet, dwError);
3514     return FALSE;
3515 }
3516  
3517 /***********************************************************************
3518  *
3519  *         InternetCreateUrlW
3520  *
3521  * RETURNS
3522  *   TRUE on success
3523  *   FALSE on failure
3524  *
3525  */
3526 BOOL WINAPI InternetCreateUrlW(LPURL_COMPONENTSW lpUrlComponents, DWORD dwFlags,
3527                                LPWSTR lpszUrl, LPDWORD lpdwUrlLength)
3528 {
3529     FIXME("\n");
3530     return FALSE;
3531 }
3532
3533 /***********************************************************************
3534  *           dump_INTERNET_FLAGS
3535  *
3536  * Helper function to TRACE the internet flags.
3537  *
3538  * RETURNS
3539  *    None
3540  *
3541  */
3542 void dump_INTERNET_FLAGS(DWORD dwFlags) 
3543 {
3544 #define FE(x) { x, #x }
3545     static const wininet_flag_info flag[] = {
3546         FE(INTERNET_FLAG_RELOAD),
3547         FE(INTERNET_FLAG_RAW_DATA),
3548         FE(INTERNET_FLAG_EXISTING_CONNECT),
3549         FE(INTERNET_FLAG_ASYNC),
3550         FE(INTERNET_FLAG_PASSIVE),
3551         FE(INTERNET_FLAG_NO_CACHE_WRITE),
3552         FE(INTERNET_FLAG_MAKE_PERSISTENT),
3553         FE(INTERNET_FLAG_FROM_CACHE),
3554         FE(INTERNET_FLAG_SECURE),
3555         FE(INTERNET_FLAG_KEEP_CONNECTION),
3556         FE(INTERNET_FLAG_NO_AUTO_REDIRECT),
3557         FE(INTERNET_FLAG_READ_PREFETCH),
3558         FE(INTERNET_FLAG_NO_COOKIES),
3559         FE(INTERNET_FLAG_NO_AUTH),
3560         FE(INTERNET_FLAG_CACHE_IF_NET_FAIL),
3561         FE(INTERNET_FLAG_IGNORE_REDIRECT_TO_HTTP),
3562         FE(INTERNET_FLAG_IGNORE_REDIRECT_TO_HTTPS),
3563         FE(INTERNET_FLAG_IGNORE_CERT_DATE_INVALID),
3564         FE(INTERNET_FLAG_IGNORE_CERT_CN_INVALID),
3565         FE(INTERNET_FLAG_RESYNCHRONIZE),
3566         FE(INTERNET_FLAG_HYPERLINK),
3567         FE(INTERNET_FLAG_NO_UI),
3568         FE(INTERNET_FLAG_PRAGMA_NOCACHE),
3569         FE(INTERNET_FLAG_CACHE_ASYNC),
3570         FE(INTERNET_FLAG_FORMS_SUBMIT),
3571         FE(INTERNET_FLAG_NEED_FILE),
3572         FE(INTERNET_FLAG_TRANSFER_ASCII),
3573         FE(INTERNET_FLAG_TRANSFER_BINARY)
3574     };
3575 #undef FE
3576     int i;
3577     
3578     for (i = 0; i < (sizeof(flag) / sizeof(flag[0])); i++) {
3579         if (flag[i].val & dwFlags) {
3580             TRACE(" %s", flag[i].name);
3581             dwFlags &= ~flag[i].val;
3582         }
3583     }   
3584     if (dwFlags)
3585         TRACE(" Unknown flags (%08lx)\n", dwFlags);
3586     else
3587         TRACE("\n");
3588 }