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