wined3d: Introduce device_get_draw_rect() to calculate the effective viewport.
[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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
27  */
28
29 #include "config.h"
30 #include "wine/port.h"
31
32 #define MAXHOSTNAME 100 /* from http.c */
33
34 #if defined(__MINGW32__) || defined (_MSC_VER)
35 #include <ws2tcpip.h>
36 #endif
37
38 #include <string.h>
39 #include <stdarg.h>
40 #include <stdio.h>
41 #include <sys/types.h>
42 #ifdef HAVE_SYS_SOCKET_H
43 # include <sys/socket.h>
44 #endif
45 #ifdef HAVE_POLL_H
46 #include <poll.h>
47 #endif
48 #ifdef HAVE_SYS_POLL_H
49 # include <sys/poll.h>
50 #endif
51 #ifdef HAVE_SYS_TIME_H
52 # include <sys/time.h>
53 #endif
54 #include <stdlib.h>
55 #include <ctype.h>
56 #ifdef HAVE_UNISTD_H
57 # include <unistd.h>
58 #endif
59 #include <assert.h>
60
61 #include "windef.h"
62 #include "winbase.h"
63 #include "winreg.h"
64 #include "winuser.h"
65 #include "wininet.h"
66 #include "winineti.h"
67 #include "winnls.h"
68 #include "wine/debug.h"
69 #include "winerror.h"
70 #define NO_SHLWAPI_STREAM
71 #include "shlwapi.h"
72
73 #include "wine/exception.h"
74
75 #include "internet.h"
76 #include "resource.h"
77
78 #include "wine/unicode.h"
79
80 WINE_DEFAULT_DEBUG_CHANNEL(wininet);
81
82 #define RESPONSE_TIMEOUT        30
83
84 typedef struct
85 {
86     DWORD  dwError;
87     CHAR   response[MAX_REPLY_LEN];
88 } WITHREADERROR, *LPWITHREADERROR;
89
90 static DWORD g_dwTlsErrIndex = TLS_OUT_OF_INDEXES;
91 static HMODULE WININET_hModule;
92
93 #define HANDLE_CHUNK_SIZE 0x10
94
95 static CRITICAL_SECTION WININET_cs;
96 static CRITICAL_SECTION_DEBUG WININET_cs_debug = 
97 {
98     0, 0, &WININET_cs,
99     { &WININET_cs_debug.ProcessLocksList, &WININET_cs_debug.ProcessLocksList },
100       0, 0, { (DWORD_PTR)(__FILE__ ": WININET_cs") }
101 };
102 static CRITICAL_SECTION WININET_cs = { &WININET_cs_debug, -1, 0, 0, 0, 0 };
103
104 static object_header_t **WININET_Handles;
105 static UINT_PTR WININET_dwNextHandle;
106 static UINT_PTR WININET_dwMaxHandles;
107
108 typedef struct
109 {
110     DWORD dwProxyEnabled;
111     LPWSTR lpszProxyServer;
112     LPWSTR lpszProxyBypass;
113 } proxyinfo_t;
114
115 static const WCHAR szInternetSettings[] =
116     { 'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
117       'W','i','n','d','o','w','s','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
118       'I','n','t','e','r','n','e','t',' ','S','e','t','t','i','n','g','s',0 };
119 static const WCHAR szProxyServer[] = { 'P','r','o','x','y','S','e','r','v','e','r', 0 };
120 static const WCHAR szProxyEnable[] = { 'P','r','o','x','y','E','n','a','b','l','e', 0 };
121
122 HINTERNET WININET_AllocHandle( object_header_t *info )
123 {
124     object_header_t **p;
125     UINT_PTR handle = 0, num;
126
127     list_init( &info->children );
128
129     EnterCriticalSection( &WININET_cs );
130     if( !WININET_dwMaxHandles )
131     {
132         num = HANDLE_CHUNK_SIZE;
133         p = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, 
134                    sizeof (*WININET_Handles)* num);
135         if( !p )
136             goto end;
137         WININET_Handles = p;
138         WININET_dwMaxHandles = num;
139     }
140     if( WININET_dwMaxHandles == WININET_dwNextHandle )
141     {
142         num = WININET_dwMaxHandles + HANDLE_CHUNK_SIZE;
143         p = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
144                    WININET_Handles, sizeof (*WININET_Handles)* num);
145         if( !p )
146             goto end;
147         WININET_Handles = p;
148         WININET_dwMaxHandles = num;
149     }
150
151     handle = WININET_dwNextHandle;
152     if( WININET_Handles[handle] )
153         ERR("handle isn't free but should be\n");
154     WININET_Handles[handle] = WININET_AddRef( info );
155
156     while( WININET_Handles[WININET_dwNextHandle] && 
157            (WININET_dwNextHandle < WININET_dwMaxHandles ) )
158         WININET_dwNextHandle++;
159     
160 end:
161     LeaveCriticalSection( &WININET_cs );
162
163     return info->hInternet = (HINTERNET) (handle+1);
164 }
165
166 object_header_t *WININET_AddRef( object_header_t *info )
167 {
168     ULONG refs = InterlockedIncrement(&info->refs);
169     TRACE("%p -> refcount = %d\n", info, refs );
170     return info;
171 }
172
173 object_header_t *WININET_GetObject( HINTERNET hinternet )
174 {
175     object_header_t *info = NULL;
176     UINT_PTR handle = (UINT_PTR) hinternet;
177
178     EnterCriticalSection( &WININET_cs );
179
180     if( (handle > 0) && ( handle <= WININET_dwMaxHandles ) && 
181         WININET_Handles[handle-1] )
182         info = WININET_AddRef( WININET_Handles[handle-1] );
183
184     LeaveCriticalSection( &WININET_cs );
185
186     TRACE("handle %ld -> %p\n", handle, info);
187
188     return info;
189 }
190
191 BOOL WININET_Release( object_header_t *info )
192 {
193     ULONG refs = InterlockedDecrement(&info->refs);
194     TRACE( "object %p refcount = %d\n", info, refs );
195     if( !refs )
196     {
197         if ( info->vtbl->CloseConnection )
198         {
199             TRACE( "closing connection %p\n", info);
200             info->vtbl->CloseConnection( info );
201         }
202         /* Don't send a callback if this is a session handle created with InternetOpenUrl */
203         if ((info->htype != WH_HHTTPSESSION && info->htype != WH_HFTPSESSION)
204             || !(info->dwInternalFlags & INET_OPENURL))
205         {
206             INTERNET_SendCallback(info, info->dwContext,
207                                   INTERNET_STATUS_HANDLE_CLOSING, &info->hInternet,
208                                   sizeof(HINTERNET));
209         }
210         TRACE( "destroying object %p\n", info);
211         if ( info->htype != WH_HINIT )
212             list_remove( &info->entry );
213         info->vtbl->Destroy( info );
214     }
215     return TRUE;
216 }
217
218 BOOL WININET_FreeHandle( HINTERNET hinternet )
219 {
220     BOOL ret = FALSE;
221     UINT_PTR handle = (UINT_PTR) hinternet;
222     object_header_t *info = NULL, *child, *next;
223
224     EnterCriticalSection( &WININET_cs );
225
226     if( (handle > 0) && ( handle <= WININET_dwMaxHandles ) )
227     {
228         handle--;
229         if( WININET_Handles[handle] )
230         {
231             info = WININET_Handles[handle];
232             TRACE( "destroying handle %ld for object %p\n", handle+1, info);
233             WININET_Handles[handle] = NULL;
234             ret = TRUE;
235         }
236     }
237
238     LeaveCriticalSection( &WININET_cs );
239
240     /* As on native when the equivalent of WININET_Release is called, the handle
241      * is already invalid, but if a new handle is created at this time it does
242      * not yet get assigned the freed handle number */
243     if( info )
244     {
245         /* Free all children as native does */
246         LIST_FOR_EACH_ENTRY_SAFE( child, next, &info->children, object_header_t, entry )
247         {
248             TRACE( "freeing child handle %ld for parent handle %ld\n",
249                    (UINT_PTR)child->hInternet, handle+1);
250             WININET_FreeHandle( child->hInternet );
251         }
252         WININET_Release( info );
253     }
254
255     EnterCriticalSection( &WININET_cs );
256
257     if( WININET_dwNextHandle > handle && !WININET_Handles[handle] )
258         WININET_dwNextHandle = handle;
259
260     LeaveCriticalSection( &WININET_cs );
261
262     return ret;
263 }
264
265 /***********************************************************************
266  * DllMain [Internal] Initializes the internal 'WININET.DLL'.
267  *
268  * PARAMS
269  *     hinstDLL    [I] handle to the DLL's instance
270  *     fdwReason   [I]
271  *     lpvReserved [I] reserved, must be NULL
272  *
273  * RETURNS
274  *     Success: TRUE
275  *     Failure: FALSE
276  */
277
278 BOOL WINAPI DllMain (HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
279 {
280     TRACE("%p,%x,%p\n", hinstDLL, fdwReason, lpvReserved);
281
282     switch (fdwReason) {
283         case DLL_PROCESS_ATTACH:
284
285             g_dwTlsErrIndex = TlsAlloc();
286
287             if (g_dwTlsErrIndex == TLS_OUT_OF_INDEXES)
288                 return FALSE;
289
290             URLCacheContainers_CreateDefaults();
291
292             WININET_hModule = hinstDLL;
293
294         case DLL_THREAD_ATTACH:
295             break;
296
297         case DLL_THREAD_DETACH:
298             if (g_dwTlsErrIndex != TLS_OUT_OF_INDEXES)
299                         {
300                                 LPVOID lpwite = TlsGetValue(g_dwTlsErrIndex);
301                                 HeapFree(GetProcessHeap(), 0, lpwite);
302                         }
303             break;
304
305         case DLL_PROCESS_DETACH:
306
307             NETCON_unload();
308
309             URLCacheContainers_DeleteAll();
310
311             if (g_dwTlsErrIndex != TLS_OUT_OF_INDEXES)
312             {
313                 HeapFree(GetProcessHeap(), 0, TlsGetValue(g_dwTlsErrIndex));
314                 TlsFree(g_dwTlsErrIndex);
315             }
316             break;
317     }
318
319     return TRUE;
320 }
321
322 /***********************************************************************
323  *           INTERNET_SaveProxySettings
324  *
325  * Stores the proxy settings given by lpwai into the registry
326  *
327  * RETURNS
328  *     ERROR_SUCCESS if no error, or error code on fail
329  */
330 static LONG INTERNET_SaveProxySettings( proxyinfo_t *lpwpi )
331 {
332     HKEY key;
333     LONG ret;
334
335     if ((ret = RegOpenKeyW( HKEY_CURRENT_USER, szInternetSettings, &key )))
336         return ret;
337
338     if ((ret = RegSetValueExW( key, szProxyEnable, 0, REG_DWORD, (BYTE*)&lpwpi->dwProxyEnabled, sizeof(DWORD))))
339     {
340         RegCloseKey( key );
341         return ret;
342     }
343
344     if (lpwpi->lpszProxyServer)
345     {
346         if ((ret = RegSetValueExW( key, szProxyServer, 0, REG_SZ, (BYTE*)lpwpi->lpszProxyServer, sizeof(WCHAR) * (lstrlenW(lpwpi->lpszProxyServer) + 1))))
347         {
348             RegCloseKey( key );
349             return ret;
350         }
351     }
352     else
353     {
354         if ((ret = RegDeleteValueW( key, szProxyServer )))
355         {
356             RegCloseKey( key );
357             return ret;
358         }
359     }
360
361     RegCloseKey(key);
362     return ERROR_SUCCESS;
363 }
364
365 /***********************************************************************
366  *           INTERNET_FindProxyForProtocol
367  *
368  * Searches the proxy string for a proxy of the given protocol.
369  * Returns the found proxy, or the default proxy if none of the given
370  * protocol is found.
371  *
372  * PARAMETERS
373  *     szProxy       [In]     proxy string to search
374  *     proto         [In]     protocol to search for, e.g. "http"
375  *     foundProxy    [Out]    found proxy
376  *     foundProxyLen [In/Out] length of foundProxy buffer, in WCHARs
377  *
378  * RETURNS
379  *     TRUE if a proxy is found, FALSE if not.  If foundProxy is too short,
380  *     *foundProxyLen is set to the required size in WCHARs, including the
381  *     NULL terminator, and the last error is set to ERROR_INSUFFICIENT_BUFFER.
382  */
383 BOOL INTERNET_FindProxyForProtocol(LPCWSTR szProxy, LPCWSTR proto, WCHAR *foundProxy, DWORD *foundProxyLen)
384 {
385     LPCWSTR ptr;
386     BOOL ret = FALSE;
387
388     TRACE("(%s, %s)\n", debugstr_w(szProxy), debugstr_w(proto));
389
390     /* First, look for the specified protocol (proto=scheme://host:port) */
391     for (ptr = szProxy; !ret && ptr && *ptr; )
392     {
393         LPCWSTR end, equal;
394
395         if (!(end = strchrW(ptr, ' ')))
396             end = ptr + strlenW(ptr);
397         if ((equal = strchrW(ptr, '=')) && equal < end &&
398              equal - ptr == strlenW(proto) &&
399              !strncmpiW(proto, ptr, strlenW(proto)))
400         {
401             if (end - equal > *foundProxyLen)
402             {
403                 WARN("buffer too short for %s\n",
404                      debugstr_wn(equal + 1, end - equal - 1));
405                 *foundProxyLen = end - equal;
406                 SetLastError(ERROR_INSUFFICIENT_BUFFER);
407             }
408             else
409             {
410                 memcpy(foundProxy, equal + 1, (end - equal) * sizeof(WCHAR));
411                 foundProxy[end - equal] = 0;
412                 ret = TRUE;
413             }
414         }
415         if (*end == ' ')
416             ptr = end + 1;
417         else
418             ptr = end;
419     }
420     if (!ret)
421     {
422         /* It wasn't found: look for no protocol */
423         for (ptr = szProxy; !ret && ptr && *ptr; )
424         {
425             LPCWSTR end, equal;
426
427             if (!(end = strchrW(ptr, ' ')))
428                 end = ptr + strlenW(ptr);
429             if (!(equal = strchrW(ptr, '=')))
430             {
431                 if (end - ptr + 1 > *foundProxyLen)
432                 {
433                     WARN("buffer too short for %s\n",
434                          debugstr_wn(ptr, end - ptr));
435                     *foundProxyLen = end - ptr + 1;
436                     SetLastError(ERROR_INSUFFICIENT_BUFFER);
437                 }
438                 else
439                 {
440                     memcpy(foundProxy, ptr, (end - ptr) * sizeof(WCHAR));
441                     foundProxy[end - ptr] = 0;
442                     ret = TRUE;
443                 }
444             }
445             if (*end == ' ')
446                 ptr = end + 1;
447             else
448                 ptr = end;
449         }
450     }
451     if (ret)
452         TRACE("found proxy for %s: %s\n", debugstr_w(proto),
453               debugstr_w(foundProxy));
454     return ret;
455 }
456
457 /***********************************************************************
458  *           InternetInitializeAutoProxyDll   (WININET.@)
459  *
460  * Setup the internal proxy
461  *
462  * PARAMETERS
463  *     dwReserved
464  *
465  * RETURNS
466  *     FALSE on failure
467  *
468  */
469 BOOL WINAPI InternetInitializeAutoProxyDll(DWORD dwReserved)
470 {
471     FIXME("STUB\n");
472     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
473     return FALSE;
474 }
475
476 /***********************************************************************
477  *           DetectAutoProxyUrl   (WININET.@)
478  *
479  * Auto detect the proxy url
480  *
481  * RETURNS
482  *     FALSE on failure
483  *
484  */
485 BOOL WINAPI DetectAutoProxyUrl(LPSTR lpszAutoProxyUrl,
486         DWORD dwAutoProxyUrlLength, DWORD dwDetectFlags)
487 {
488     FIXME("STUB\n");
489     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
490     return FALSE;
491 }
492
493 static void FreeProxyInfo( proxyinfo_t *lpwpi )
494 {
495     HeapFree(GetProcessHeap(), 0, lpwpi->lpszProxyServer);
496     HeapFree(GetProcessHeap(), 0, lpwpi->lpszProxyBypass);
497 }
498
499 /***********************************************************************
500  *          INTERNET_LoadProxySettings
501  *
502  * Loads proxy information from the registry or environment into lpwpi.
503  *
504  * The caller should call FreeProxyInfo when done with lpwpi.
505  *
506  * FIXME:
507  * The proxy may be specified in the form 'http=proxy.my.org'
508  * Presumably that means there can be ftp=ftpproxy.my.org too.
509  */
510 static LONG INTERNET_LoadProxySettings( proxyinfo_t *lpwpi )
511 {
512     HKEY key;
513     DWORD type, len;
514     LPCSTR envproxy;
515     LONG ret;
516
517     if ((ret = RegOpenKeyW( HKEY_CURRENT_USER, szInternetSettings, &key )))
518         return ret;
519
520     len = sizeof(DWORD);
521     if (RegQueryValueExW( key, szProxyEnable, NULL, &type, (BYTE *)&lpwpi->dwProxyEnabled, &len ) || type != REG_DWORD)
522     {
523         lpwpi->dwProxyEnabled = 0;
524         if((ret = RegSetValueExW( key, szProxyEnable, 0, REG_DWORD, (BYTE *)&lpwpi->dwProxyEnabled, sizeof(DWORD) )))
525         {
526             RegCloseKey( key );
527             return ret;
528         }
529     }
530
531     if (!(envproxy = getenv( "http_proxy" )) || lpwpi->dwProxyEnabled)
532     {
533         TRACE("Proxy is enabled.\n");
534
535         /* figure out how much memory the proxy setting takes */
536         if (!RegQueryValueExW( key, szProxyServer, NULL, &type, NULL, &len ) && len && (type == REG_SZ))
537         {
538             LPWSTR szProxy, p;
539             static const WCHAR szHttp[] = {'h','t','t','p','=',0};
540
541             if (!(szProxy = HeapAlloc( GetProcessHeap(), 0, len )))
542             {
543                 RegCloseKey( key );
544                 return ERROR_OUTOFMEMORY;
545             }
546             RegQueryValueExW( key, szProxyServer, NULL, &type, (BYTE*)szProxy, &len );
547
548             /* find the http proxy, and strip away everything else */
549             p = strstrW( szProxy, szHttp );
550             if (p)
551             {
552                 p += lstrlenW( szHttp );
553                 lstrcpyW( szProxy, p );
554             }
555             p = strchrW( szProxy, ' ' );
556             if (p) *p = 0;
557
558             lpwpi->lpszProxyServer = szProxy;
559
560             TRACE("http proxy = %s\n", debugstr_w(lpwpi->lpszProxyServer));
561         }
562         else
563         {
564             TRACE("No proxy server settings in registry.\n");
565             lpwpi->lpszProxyServer = NULL;
566         }
567     }
568     else if (envproxy)
569     {
570         WCHAR *envproxyW;
571
572         len = MultiByteToWideChar( CP_UNIXCP, 0, envproxy, -1, NULL, 0 );
573         if (!(envproxyW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR))))
574             return ERROR_OUTOFMEMORY;
575         MultiByteToWideChar( CP_UNIXCP, 0, envproxy, -1, envproxyW, len );
576
577         lpwpi->dwProxyEnabled = 1;
578         lpwpi->lpszProxyServer = envproxyW;
579
580         TRACE("http proxy (from environment) = %s\n", debugstr_w(lpwpi->lpszProxyServer));
581     }
582     RegCloseKey( key );
583
584     lpwpi->lpszProxyBypass = NULL;
585
586     return ERROR_SUCCESS;
587 }
588
589 /***********************************************************************
590  *           INTERNET_ConfigureProxy
591  */
592 static BOOL INTERNET_ConfigureProxy( appinfo_t *lpwai )
593 {
594     proxyinfo_t wpi;
595
596     if (INTERNET_LoadProxySettings( &wpi ))
597         return FALSE;
598
599     if (wpi.dwProxyEnabled)
600     {
601         lpwai->dwAccessType = INTERNET_OPEN_TYPE_PROXY;
602         lpwai->lpszProxy = wpi.lpszProxyServer;
603         return TRUE;
604     }
605
606     lpwai->dwAccessType = INTERNET_OPEN_TYPE_DIRECT;
607     return FALSE;
608 }
609
610 /***********************************************************************
611  *           dump_INTERNET_FLAGS
612  *
613  * Helper function to TRACE the internet flags.
614  *
615  * RETURNS
616  *    None
617  *
618  */
619 static void dump_INTERNET_FLAGS(DWORD dwFlags) 
620 {
621 #define FE(x) { x, #x }
622     static const wininet_flag_info flag[] = {
623         FE(INTERNET_FLAG_RELOAD),
624         FE(INTERNET_FLAG_RAW_DATA),
625         FE(INTERNET_FLAG_EXISTING_CONNECT),
626         FE(INTERNET_FLAG_ASYNC),
627         FE(INTERNET_FLAG_PASSIVE),
628         FE(INTERNET_FLAG_NO_CACHE_WRITE),
629         FE(INTERNET_FLAG_MAKE_PERSISTENT),
630         FE(INTERNET_FLAG_FROM_CACHE),
631         FE(INTERNET_FLAG_SECURE),
632         FE(INTERNET_FLAG_KEEP_CONNECTION),
633         FE(INTERNET_FLAG_NO_AUTO_REDIRECT),
634         FE(INTERNET_FLAG_READ_PREFETCH),
635         FE(INTERNET_FLAG_NO_COOKIES),
636         FE(INTERNET_FLAG_NO_AUTH),
637         FE(INTERNET_FLAG_CACHE_IF_NET_FAIL),
638         FE(INTERNET_FLAG_IGNORE_REDIRECT_TO_HTTP),
639         FE(INTERNET_FLAG_IGNORE_REDIRECT_TO_HTTPS),
640         FE(INTERNET_FLAG_IGNORE_CERT_DATE_INVALID),
641         FE(INTERNET_FLAG_IGNORE_CERT_CN_INVALID),
642         FE(INTERNET_FLAG_RESYNCHRONIZE),
643         FE(INTERNET_FLAG_HYPERLINK),
644         FE(INTERNET_FLAG_NO_UI),
645         FE(INTERNET_FLAG_PRAGMA_NOCACHE),
646         FE(INTERNET_FLAG_CACHE_ASYNC),
647         FE(INTERNET_FLAG_FORMS_SUBMIT),
648         FE(INTERNET_FLAG_NEED_FILE),
649         FE(INTERNET_FLAG_TRANSFER_ASCII),
650         FE(INTERNET_FLAG_TRANSFER_BINARY)
651     };
652 #undef FE
653     unsigned int i;
654
655     for (i = 0; i < (sizeof(flag) / sizeof(flag[0])); i++) {
656         if (flag[i].val & dwFlags) {
657             TRACE(" %s", flag[i].name);
658             dwFlags &= ~flag[i].val;
659         }
660     }   
661     if (dwFlags)
662         TRACE(" Unknown flags (%08x)\n", dwFlags);
663     else
664         TRACE("\n");
665 }
666
667 /***********************************************************************
668  *           INTERNET_CloseHandle (internal)
669  *
670  * Close internet handle
671  *
672  */
673 static VOID APPINFO_Destroy(object_header_t *hdr)
674 {
675     appinfo_t *lpwai = (appinfo_t*)hdr;
676
677     TRACE("%p\n",lpwai);
678
679     HeapFree(GetProcessHeap(), 0, lpwai->lpszAgent);
680     HeapFree(GetProcessHeap(), 0, lpwai->lpszProxy);
681     HeapFree(GetProcessHeap(), 0, lpwai->lpszProxyBypass);
682     HeapFree(GetProcessHeap(), 0, lpwai->lpszProxyUsername);
683     HeapFree(GetProcessHeap(), 0, lpwai->lpszProxyPassword);
684     HeapFree(GetProcessHeap(), 0, lpwai);
685 }
686
687 static DWORD APPINFO_QueryOption(object_header_t *hdr, DWORD option, void *buffer, DWORD *size, BOOL unicode)
688 {
689     appinfo_t *ai = (appinfo_t*)hdr;
690
691     switch(option) {
692     case INTERNET_OPTION_HANDLE_TYPE:
693         TRACE("INTERNET_OPTION_HANDLE_TYPE\n");
694
695         if (*size < sizeof(ULONG))
696             return ERROR_INSUFFICIENT_BUFFER;
697
698         *size = sizeof(DWORD);
699         *(DWORD*)buffer = INTERNET_HANDLE_TYPE_INTERNET;
700         return ERROR_SUCCESS;
701
702     case INTERNET_OPTION_USER_AGENT: {
703         DWORD bufsize;
704
705         TRACE("INTERNET_OPTION_USER_AGENT\n");
706
707         bufsize = *size;
708
709         if (unicode) {
710             DWORD len = ai->lpszAgent ? strlenW(ai->lpszAgent) : 0;
711
712             *size = (len + 1) * sizeof(WCHAR);
713             if(!buffer || bufsize < *size)
714                 return ERROR_INSUFFICIENT_BUFFER;
715
716             if (ai->lpszAgent)
717                 strcpyW(buffer, ai->lpszAgent);
718             else
719                 *(WCHAR *)buffer = 0;
720             /* If the buffer is copied, the returned length doesn't include
721              * the NULL terminator.
722              */
723             *size = len * sizeof(WCHAR);
724         }else {
725             if (ai->lpszAgent)
726                 *size = WideCharToMultiByte(CP_ACP, 0, ai->lpszAgent, -1, NULL, 0, NULL, NULL);
727             else
728                 *size = 1;
729             if(!buffer || bufsize < *size)
730                 return ERROR_INSUFFICIENT_BUFFER;
731
732             if (ai->lpszAgent)
733                 WideCharToMultiByte(CP_ACP, 0, ai->lpszAgent, -1, buffer, *size, NULL, NULL);
734             else
735                 *(char *)buffer = 0;
736             /* If the buffer is copied, the returned length doesn't include
737              * the NULL terminator.
738              */
739             *size -= 1;
740         }
741
742         return ERROR_SUCCESS;
743     }
744
745     case INTERNET_OPTION_PROXY:
746         if (unicode) {
747             INTERNET_PROXY_INFOW *pi = (INTERNET_PROXY_INFOW *)buffer;
748             DWORD proxyBytesRequired = 0, proxyBypassBytesRequired = 0;
749             LPWSTR proxy, proxy_bypass;
750
751             if (ai->lpszProxy)
752                 proxyBytesRequired = (lstrlenW(ai->lpszProxy) + 1) * sizeof(WCHAR);
753             if (ai->lpszProxyBypass)
754                 proxyBypassBytesRequired = (lstrlenW(ai->lpszProxyBypass) + 1) * sizeof(WCHAR);
755             if (*size < sizeof(INTERNET_PROXY_INFOW) + proxyBytesRequired + proxyBypassBytesRequired)
756             {
757                 *size = sizeof(INTERNET_PROXY_INFOW) + proxyBytesRequired + proxyBypassBytesRequired;
758                 return ERROR_INSUFFICIENT_BUFFER;
759             }
760             proxy = (LPWSTR)((LPBYTE)buffer + sizeof(INTERNET_PROXY_INFOW));
761             proxy_bypass = (LPWSTR)((LPBYTE)buffer + sizeof(INTERNET_PROXY_INFOW) + proxyBytesRequired);
762
763             pi->dwAccessType = ai->dwAccessType;
764             pi->lpszProxy = NULL;
765             pi->lpszProxyBypass = NULL;
766             if (ai->lpszProxy) {
767                 lstrcpyW(proxy, ai->lpszProxy);
768                 pi->lpszProxy = proxy;
769             }
770
771             if (ai->lpszProxyBypass) {
772                 lstrcpyW(proxy_bypass, ai->lpszProxyBypass);
773                 pi->lpszProxyBypass = proxy_bypass;
774             }
775
776             *size = sizeof(INTERNET_PROXY_INFOW) + proxyBytesRequired + proxyBypassBytesRequired;
777             return ERROR_SUCCESS;
778         }else {
779             INTERNET_PROXY_INFOA *pi = (INTERNET_PROXY_INFOA *)buffer;
780             DWORD proxyBytesRequired = 0, proxyBypassBytesRequired = 0;
781             LPSTR proxy, proxy_bypass;
782
783             if (ai->lpszProxy)
784                 proxyBytesRequired = WideCharToMultiByte(CP_ACP, 0, ai->lpszProxy, -1, NULL, 0, NULL, NULL);
785             if (ai->lpszProxyBypass)
786                 proxyBypassBytesRequired = WideCharToMultiByte(CP_ACP, 0, ai->lpszProxyBypass, -1,
787                         NULL, 0, NULL, NULL);
788             if (*size < sizeof(INTERNET_PROXY_INFOA) + proxyBytesRequired + proxyBypassBytesRequired)
789             {
790                 *size = sizeof(INTERNET_PROXY_INFOA) + proxyBytesRequired + proxyBypassBytesRequired;
791                 return ERROR_INSUFFICIENT_BUFFER;
792             }
793             proxy = (LPSTR)((LPBYTE)buffer + sizeof(INTERNET_PROXY_INFOA));
794             proxy_bypass = (LPSTR)((LPBYTE)buffer + sizeof(INTERNET_PROXY_INFOA) + proxyBytesRequired);
795
796             pi->dwAccessType = ai->dwAccessType;
797             pi->lpszProxy = NULL;
798             pi->lpszProxyBypass = NULL;
799             if (ai->lpszProxy) {
800                 WideCharToMultiByte(CP_ACP, 0, ai->lpszProxy, -1, proxy, proxyBytesRequired, NULL, NULL);
801                 pi->lpszProxy = proxy;
802             }
803
804             if (ai->lpszProxyBypass) {
805                 WideCharToMultiByte(CP_ACP, 0, ai->lpszProxyBypass, -1, proxy_bypass,
806                         proxyBypassBytesRequired, NULL, NULL);
807                 pi->lpszProxyBypass = proxy_bypass;
808             }
809
810             *size = sizeof(INTERNET_PROXY_INFOA) + proxyBytesRequired + proxyBypassBytesRequired;
811             return ERROR_SUCCESS;
812         }
813     }
814
815     return INET_QueryOption(option, buffer, size, unicode);
816 }
817
818 static const object_vtbl_t APPINFOVtbl = {
819     APPINFO_Destroy,
820     NULL,
821     APPINFO_QueryOption,
822     NULL,
823     NULL,
824     NULL,
825     NULL,
826     NULL,
827     NULL
828 };
829
830
831 /***********************************************************************
832  *           InternetOpenW   (WININET.@)
833  *
834  * Per-application initialization of wininet
835  *
836  * RETURNS
837  *    HINTERNET on success
838  *    NULL on failure
839  *
840  */
841 HINTERNET WINAPI InternetOpenW(LPCWSTR lpszAgent, DWORD dwAccessType,
842     LPCWSTR lpszProxy, LPCWSTR lpszProxyBypass, DWORD dwFlags)
843 {
844     appinfo_t *lpwai = NULL;
845     HINTERNET handle = NULL;
846
847     if (TRACE_ON(wininet)) {
848 #define FE(x) { x, #x }
849         static const wininet_flag_info access_type[] = {
850             FE(INTERNET_OPEN_TYPE_PRECONFIG),
851             FE(INTERNET_OPEN_TYPE_DIRECT),
852             FE(INTERNET_OPEN_TYPE_PROXY),
853             FE(INTERNET_OPEN_TYPE_PRECONFIG_WITH_NO_AUTOPROXY)
854         };
855 #undef FE
856         DWORD i;
857         const char *access_type_str = "Unknown";
858         
859         TRACE("(%s, %i, %s, %s, %i)\n", debugstr_w(lpszAgent), dwAccessType,
860               debugstr_w(lpszProxy), debugstr_w(lpszProxyBypass), dwFlags);
861         for (i = 0; i < (sizeof(access_type) / sizeof(access_type[0])); i++) {
862             if (access_type[i].val == dwAccessType) {
863                 access_type_str = access_type[i].name;
864                 break;
865             }
866         }
867         TRACE("  access type : %s\n", access_type_str);
868         TRACE("  flags       :");
869         dump_INTERNET_FLAGS(dwFlags);
870     }
871
872     /* Clear any error information */
873     INTERNET_SetLastError(0);
874
875     lpwai = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(appinfo_t));
876     if (NULL == lpwai)
877     {
878         INTERNET_SetLastError(ERROR_OUTOFMEMORY);
879         goto lend;
880     }
881
882     lpwai->hdr.htype = WH_HINIT;
883     lpwai->hdr.vtbl = &APPINFOVtbl;
884     lpwai->hdr.dwFlags = dwFlags;
885     lpwai->hdr.refs = 1;
886     lpwai->dwAccessType = dwAccessType;
887     lpwai->lpszProxyUsername = NULL;
888     lpwai->lpszProxyPassword = NULL;
889
890     handle = WININET_AllocHandle( &lpwai->hdr );
891     if( !handle )
892     {
893         HeapFree( GetProcessHeap(), 0, lpwai );
894         INTERNET_SetLastError(ERROR_OUTOFMEMORY);
895         goto lend;
896     }
897
898     lpwai->lpszAgent = heap_strdupW(lpszAgent);
899     if(dwAccessType == INTERNET_OPEN_TYPE_PRECONFIG)
900         INTERNET_ConfigureProxy( lpwai );
901     else
902         lpwai->lpszProxy = heap_strdupW(lpszProxy);
903     lpwai->lpszProxyBypass = heap_strdupW(lpszProxyBypass);
904
905 lend:
906     if( lpwai )
907         WININET_Release( &lpwai->hdr );
908
909     TRACE("returning %p\n", lpwai);
910
911     return handle;
912 }
913
914
915 /***********************************************************************
916  *           InternetOpenA   (WININET.@)
917  *
918  * Per-application initialization of wininet
919  *
920  * RETURNS
921  *    HINTERNET on success
922  *    NULL on failure
923  *
924  */
925 HINTERNET WINAPI InternetOpenA(LPCSTR lpszAgent, DWORD dwAccessType,
926     LPCSTR lpszProxy, LPCSTR lpszProxyBypass, DWORD dwFlags)
927 {
928     WCHAR *szAgent, *szProxy, *szBypass;
929     HINTERNET rc;
930
931     TRACE("(%s, 0x%08x, %s, %s, 0x%08x)\n", debugstr_a(lpszAgent),
932        dwAccessType, debugstr_a(lpszProxy), debugstr_a(lpszProxyBypass), dwFlags);
933
934     szAgent = heap_strdupAtoW(lpszAgent);
935     szProxy = heap_strdupAtoW(lpszProxy);
936     szBypass = heap_strdupAtoW(lpszProxyBypass);
937
938     rc = InternetOpenW(szAgent, dwAccessType, szProxy, szBypass, dwFlags);
939
940     HeapFree(GetProcessHeap(), 0, szAgent);
941     HeapFree(GetProcessHeap(), 0, szProxy);
942     HeapFree(GetProcessHeap(), 0, szBypass);
943
944     return rc;
945 }
946
947 /***********************************************************************
948  *           InternetGetLastResponseInfoA (WININET.@)
949  *
950  * Return last wininet error description on the calling thread
951  *
952  * RETURNS
953  *    TRUE on success of writing to buffer
954  *    FALSE on failure
955  *
956  */
957 BOOL WINAPI InternetGetLastResponseInfoA(LPDWORD lpdwError,
958     LPSTR lpszBuffer, LPDWORD lpdwBufferLength)
959 {
960     LPWITHREADERROR lpwite = TlsGetValue(g_dwTlsErrIndex);
961
962     TRACE("\n");
963
964     if (lpwite)
965     {
966         *lpdwError = lpwite->dwError;
967         if (lpwite->dwError)
968         {
969             memcpy(lpszBuffer, lpwite->response, *lpdwBufferLength);
970             *lpdwBufferLength = strlen(lpszBuffer);
971         }
972         else
973             *lpdwBufferLength = 0;
974     }
975     else
976     {
977         *lpdwError = 0;
978         *lpdwBufferLength = 0;
979     }
980
981     return TRUE;
982 }
983
984 /***********************************************************************
985  *           InternetGetLastResponseInfoW (WININET.@)
986  *
987  * Return last wininet error description on the calling thread
988  *
989  * RETURNS
990  *    TRUE on success of writing to buffer
991  *    FALSE on failure
992  *
993  */
994 BOOL WINAPI InternetGetLastResponseInfoW(LPDWORD lpdwError,
995     LPWSTR lpszBuffer, LPDWORD lpdwBufferLength)
996 {
997     LPWITHREADERROR lpwite = TlsGetValue(g_dwTlsErrIndex);
998
999     TRACE("\n");
1000
1001     if (lpwite)
1002     {
1003         *lpdwError = lpwite->dwError;
1004         if (lpwite->dwError)
1005         {
1006             memcpy(lpszBuffer, lpwite->response, *lpdwBufferLength);
1007             *lpdwBufferLength = lstrlenW(lpszBuffer);
1008         }
1009         else
1010             *lpdwBufferLength = 0;
1011     }
1012     else
1013     {
1014         *lpdwError = 0;
1015         *lpdwBufferLength = 0;
1016     }
1017
1018     return TRUE;
1019 }
1020
1021 /***********************************************************************
1022  *           InternetGetConnectedState (WININET.@)
1023  *
1024  * Return connected state
1025  *
1026  * RETURNS
1027  *    TRUE if connected
1028  *    if lpdwStatus is not null, return the status (off line,
1029  *    modem, lan...) in it.
1030  *    FALSE if not connected
1031  */
1032 BOOL WINAPI InternetGetConnectedState(LPDWORD lpdwStatus, DWORD dwReserved)
1033 {
1034     TRACE("(%p, 0x%08x)\n", lpdwStatus, dwReserved);
1035
1036     if (lpdwStatus) {
1037         WARN("always returning LAN connection.\n");
1038         *lpdwStatus = INTERNET_CONNECTION_LAN;
1039     }
1040     return TRUE;
1041 }
1042
1043
1044 /***********************************************************************
1045  *           InternetGetConnectedStateExW (WININET.@)
1046  *
1047  * Return connected state
1048  *
1049  * PARAMS
1050  *
1051  * lpdwStatus         [O] Flags specifying the status of the internet connection.
1052  * lpszConnectionName [O] Pointer to buffer to receive the friendly name of the internet connection.
1053  * dwNameLen          [I] Size of the buffer, in characters.
1054  * dwReserved         [I] Reserved. Must be set to 0.
1055  *
1056  * RETURNS
1057  *    TRUE if connected
1058  *    if lpdwStatus is not null, return the status (off line,
1059  *    modem, lan...) in it.
1060  *    FALSE if not connected
1061  *
1062  * NOTES
1063  *   If the system has no available network connections, an empty string is
1064  *   stored in lpszConnectionName. If there is a LAN connection, a localized
1065  *   "LAN Connection" string is stored. Presumably, if only a dial-up
1066  *   connection is available then the name of the dial-up connection is
1067  *   returned. Why any application, other than the "Internet Settings" CPL,
1068  *   would want to use this function instead of the simpler InternetGetConnectedStateW
1069  *   function is beyond me.
1070  */
1071 BOOL WINAPI InternetGetConnectedStateExW(LPDWORD lpdwStatus, LPWSTR lpszConnectionName,
1072                                          DWORD dwNameLen, DWORD dwReserved)
1073 {
1074     TRACE("(%p, %p, %d, 0x%08x)\n", lpdwStatus, lpszConnectionName, dwNameLen, dwReserved);
1075
1076     /* Must be zero */
1077     if(dwReserved)
1078         return FALSE;
1079
1080     if (lpdwStatus) {
1081         WARN("always returning LAN connection.\n");
1082         *lpdwStatus = INTERNET_CONNECTION_LAN;
1083     }
1084     return LoadStringW(WININET_hModule, IDS_LANCONNECTION, lpszConnectionName, dwNameLen);
1085 }
1086
1087
1088 /***********************************************************************
1089  *           InternetGetConnectedStateExA (WININET.@)
1090  */
1091 BOOL WINAPI InternetGetConnectedStateExA(LPDWORD lpdwStatus, LPSTR lpszConnectionName,
1092                                          DWORD dwNameLen, DWORD dwReserved)
1093 {
1094     LPWSTR lpwszConnectionName = NULL;
1095     BOOL rc;
1096
1097     TRACE("(%p, %p, %d, 0x%08x)\n", lpdwStatus, lpszConnectionName, dwNameLen, dwReserved);
1098
1099     if (lpszConnectionName && dwNameLen > 0)
1100         lpwszConnectionName= HeapAlloc(GetProcessHeap(), 0, dwNameLen * sizeof(WCHAR));
1101
1102     rc = InternetGetConnectedStateExW(lpdwStatus,lpwszConnectionName, dwNameLen,
1103                                       dwReserved);
1104     if (rc && lpwszConnectionName)
1105     {
1106         WideCharToMultiByte(CP_ACP,0,lpwszConnectionName,-1,lpszConnectionName,
1107                             dwNameLen, NULL, NULL);
1108
1109         HeapFree(GetProcessHeap(),0,lpwszConnectionName);
1110     }
1111
1112     return rc;
1113 }
1114
1115
1116 /***********************************************************************
1117  *           InternetConnectW (WININET.@)
1118  *
1119  * Open a ftp, gopher or http session
1120  *
1121  * RETURNS
1122  *    HINTERNET a session handle on success
1123  *    NULL on failure
1124  *
1125  */
1126 HINTERNET WINAPI InternetConnectW(HINTERNET hInternet,
1127     LPCWSTR lpszServerName, INTERNET_PORT nServerPort,
1128     LPCWSTR lpszUserName, LPCWSTR lpszPassword,
1129     DWORD dwService, DWORD dwFlags, DWORD_PTR dwContext)
1130 {
1131     appinfo_t *hIC;
1132     HINTERNET rc = NULL;
1133     DWORD res = ERROR_SUCCESS;
1134
1135     TRACE("(%p, %s, %i, %s, %s, %i, %i, %lx)\n", hInternet, debugstr_w(lpszServerName),
1136           nServerPort, debugstr_w(lpszUserName), debugstr_w(lpszPassword),
1137           dwService, dwFlags, dwContext);
1138
1139     if (!lpszServerName)
1140     {
1141         SetLastError(ERROR_INVALID_PARAMETER);
1142         return NULL;
1143     }
1144
1145     hIC = (appinfo_t*)WININET_GetObject( hInternet );
1146     if ( (hIC == NULL) || (hIC->hdr.htype != WH_HINIT) )
1147     {
1148         res = ERROR_INVALID_HANDLE;
1149         goto lend;
1150     }
1151
1152     switch (dwService)
1153     {
1154         case INTERNET_SERVICE_FTP:
1155             rc = FTP_Connect(hIC, lpszServerName, nServerPort,
1156             lpszUserName, lpszPassword, dwFlags, dwContext, 0);
1157             if(!rc)
1158                 res = INTERNET_GetLastError();
1159             break;
1160
1161         case INTERNET_SERVICE_HTTP:
1162             res = HTTP_Connect(hIC, lpszServerName, nServerPort,
1163                     lpszUserName, lpszPassword, dwFlags, dwContext, 0, &rc);
1164             break;
1165
1166         case INTERNET_SERVICE_GOPHER:
1167         default:
1168             break;
1169     }
1170 lend:
1171     if( hIC )
1172         WININET_Release( &hIC->hdr );
1173
1174     TRACE("returning %p\n", rc);
1175     SetLastError(res);
1176     return rc;
1177 }
1178
1179
1180 /***********************************************************************
1181  *           InternetConnectA (WININET.@)
1182  *
1183  * Open a ftp, gopher or http session
1184  *
1185  * RETURNS
1186  *    HINTERNET a session handle on success
1187  *    NULL on failure
1188  *
1189  */
1190 HINTERNET WINAPI InternetConnectA(HINTERNET hInternet,
1191     LPCSTR lpszServerName, INTERNET_PORT nServerPort,
1192     LPCSTR lpszUserName, LPCSTR lpszPassword,
1193     DWORD dwService, DWORD dwFlags, DWORD_PTR dwContext)
1194 {
1195     HINTERNET rc = NULL;
1196     LPWSTR szServerName;
1197     LPWSTR szUserName;
1198     LPWSTR szPassword;
1199
1200     szServerName = heap_strdupAtoW(lpszServerName);
1201     szUserName = heap_strdupAtoW(lpszUserName);
1202     szPassword = heap_strdupAtoW(lpszPassword);
1203
1204     rc = InternetConnectW(hInternet, szServerName, nServerPort,
1205         szUserName, szPassword, dwService, dwFlags, dwContext);
1206
1207     HeapFree(GetProcessHeap(), 0, szServerName);
1208     HeapFree(GetProcessHeap(), 0, szUserName);
1209     HeapFree(GetProcessHeap(), 0, szPassword);
1210     return rc;
1211 }
1212
1213
1214 /***********************************************************************
1215  *           InternetFindNextFileA (WININET.@)
1216  *
1217  * Continues a file search from a previous call to FindFirstFile
1218  *
1219  * RETURNS
1220  *    TRUE on success
1221  *    FALSE on failure
1222  *
1223  */
1224 BOOL WINAPI InternetFindNextFileA(HINTERNET hFind, LPVOID lpvFindData)
1225 {
1226     BOOL ret;
1227     WIN32_FIND_DATAW fd;
1228     
1229     ret = InternetFindNextFileW(hFind, lpvFindData?&fd:NULL);
1230     if(lpvFindData)
1231         WININET_find_data_WtoA(&fd, (LPWIN32_FIND_DATAA)lpvFindData);
1232     return ret;
1233 }
1234
1235 /***********************************************************************
1236  *           InternetFindNextFileW (WININET.@)
1237  *
1238  * Continues a file search from a previous call to FindFirstFile
1239  *
1240  * RETURNS
1241  *    TRUE on success
1242  *    FALSE on failure
1243  *
1244  */
1245 BOOL WINAPI InternetFindNextFileW(HINTERNET hFind, LPVOID lpvFindData)
1246 {
1247     object_header_t *hdr;
1248     DWORD res;
1249
1250     TRACE("\n");
1251
1252     hdr = WININET_GetObject(hFind);
1253     if(!hdr) {
1254         WARN("Invalid handle\n");
1255         SetLastError(ERROR_INVALID_HANDLE);
1256         return FALSE;
1257     }
1258
1259     if(hdr->vtbl->FindNextFileW) {
1260         res = hdr->vtbl->FindNextFileW(hdr, lpvFindData);
1261     }else {
1262         WARN("Handle doesn't support NextFile\n");
1263         res = ERROR_INTERNET_INCORRECT_HANDLE_TYPE;
1264     }
1265
1266     WININET_Release(hdr);
1267
1268     if(res != ERROR_SUCCESS)
1269         SetLastError(res);
1270     return res == ERROR_SUCCESS;
1271 }
1272
1273 /***********************************************************************
1274  *           InternetCloseHandle (WININET.@)
1275  *
1276  * Generic close handle function
1277  *
1278  * RETURNS
1279  *    TRUE on success
1280  *    FALSE on failure
1281  *
1282  */
1283 BOOL WINAPI InternetCloseHandle(HINTERNET hInternet)
1284 {
1285     object_header_t *lpwh;
1286     
1287     TRACE("%p\n",hInternet);
1288
1289     lpwh = WININET_GetObject( hInternet );
1290     if (NULL == lpwh)
1291     {
1292         INTERNET_SetLastError(ERROR_INVALID_HANDLE);
1293         return FALSE;
1294     }
1295
1296     WININET_Release( lpwh );
1297     WININET_FreeHandle( hInternet );
1298
1299     return TRUE;
1300 }
1301
1302
1303 /***********************************************************************
1304  *           ConvertUrlComponentValue (Internal)
1305  *
1306  * Helper function for InternetCrackUrlA
1307  *
1308  */
1309 static void ConvertUrlComponentValue(LPSTR* lppszComponent, LPDWORD dwComponentLen,
1310                                      LPWSTR lpwszComponent, DWORD dwwComponentLen,
1311                                      LPCSTR lpszStart, LPCWSTR lpwszStart)
1312 {
1313     TRACE("%p %d %p %d %p %p\n", *lppszComponent, *dwComponentLen, lpwszComponent, dwwComponentLen, lpszStart, lpwszStart);
1314     if (*dwComponentLen != 0)
1315     {
1316         DWORD nASCIILength=WideCharToMultiByte(CP_ACP,0,lpwszComponent,dwwComponentLen,NULL,0,NULL,NULL);
1317         if (*lppszComponent == NULL)
1318         {
1319             if (lpwszComponent)
1320             {
1321                 int offset = WideCharToMultiByte(CP_ACP, 0, lpwszStart, lpwszComponent-lpwszStart, NULL, 0, NULL, NULL);
1322                 *lppszComponent = (LPSTR)lpszStart + offset;
1323             }
1324             else
1325                 *lppszComponent = NULL;
1326
1327             *dwComponentLen = nASCIILength;
1328         }
1329         else
1330         {
1331             DWORD ncpylen = min((*dwComponentLen)-1, nASCIILength);
1332             WideCharToMultiByte(CP_ACP,0,lpwszComponent,dwwComponentLen,*lppszComponent,ncpylen+1,NULL,NULL);
1333             (*lppszComponent)[ncpylen]=0;
1334             *dwComponentLen = ncpylen;
1335         }
1336     }
1337 }
1338
1339
1340 /***********************************************************************
1341  *           InternetCrackUrlA (WININET.@)
1342  *
1343  * See InternetCrackUrlW.
1344  */
1345 BOOL WINAPI InternetCrackUrlA(LPCSTR lpszUrl, DWORD dwUrlLength, DWORD dwFlags,
1346     LPURL_COMPONENTSA lpUrlComponents)
1347 {
1348   DWORD nLength;
1349   URL_COMPONENTSW UCW;
1350   BOOL ret = FALSE;
1351   WCHAR *lpwszUrl, *hostname = NULL, *username = NULL, *password = NULL, *path = NULL,
1352         *scheme = NULL, *extra = NULL;
1353
1354   TRACE("(%s %u %x %p)\n",
1355         lpszUrl ? debugstr_an(lpszUrl, dwUrlLength ? dwUrlLength : strlen(lpszUrl)) : "(null)",
1356         dwUrlLength, dwFlags, lpUrlComponents);
1357
1358   if (!lpszUrl || !*lpszUrl || !lpUrlComponents ||
1359           lpUrlComponents->dwStructSize != sizeof(URL_COMPONENTSA))
1360   {
1361       INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
1362       return FALSE;
1363   }
1364
1365   if(dwUrlLength<=0)
1366       dwUrlLength=-1;
1367   nLength=MultiByteToWideChar(CP_ACP,0,lpszUrl,dwUrlLength,NULL,0);
1368
1369   /* if dwUrlLength=-1 then nLength includes null but length to 
1370        InternetCrackUrlW should not include it                  */
1371   if (dwUrlLength == -1) nLength--;
1372
1373   lpwszUrl = HeapAlloc(GetProcessHeap(), 0, nLength * sizeof(WCHAR));
1374   MultiByteToWideChar(CP_ACP,0,lpszUrl,dwUrlLength,lpwszUrl,nLength);
1375
1376   memset(&UCW,0,sizeof(UCW));
1377   UCW.dwStructSize = sizeof(URL_COMPONENTSW);
1378   if (lpUrlComponents->dwHostNameLength)
1379   {
1380     UCW.dwHostNameLength = lpUrlComponents->dwHostNameLength;
1381     if (lpUrlComponents->lpszHostName)
1382     {
1383       hostname = HeapAlloc(GetProcessHeap(), 0, UCW.dwHostNameLength * sizeof(WCHAR));
1384       UCW.lpszHostName = hostname;
1385     }
1386   }
1387   if (lpUrlComponents->dwUserNameLength)
1388   {
1389     UCW.dwUserNameLength = lpUrlComponents->dwUserNameLength;
1390     if (lpUrlComponents->lpszUserName)
1391     {
1392       username = HeapAlloc(GetProcessHeap(), 0, UCW.dwUserNameLength * sizeof(WCHAR));
1393       UCW.lpszUserName = username;
1394     }
1395   }
1396   if (lpUrlComponents->dwPasswordLength)
1397   {
1398     UCW.dwPasswordLength = lpUrlComponents->dwPasswordLength;
1399     if (lpUrlComponents->lpszPassword)
1400     {
1401       password = HeapAlloc(GetProcessHeap(), 0, UCW.dwPasswordLength * sizeof(WCHAR));
1402       UCW.lpszPassword = password;
1403     }
1404   }
1405   if (lpUrlComponents->dwUrlPathLength)
1406   {
1407     UCW.dwUrlPathLength = lpUrlComponents->dwUrlPathLength;
1408     if (lpUrlComponents->lpszUrlPath)
1409     {
1410       path = HeapAlloc(GetProcessHeap(), 0, UCW.dwUrlPathLength * sizeof(WCHAR));
1411       UCW.lpszUrlPath = path;
1412     }
1413   }
1414   if (lpUrlComponents->dwSchemeLength)
1415   {
1416     UCW.dwSchemeLength = lpUrlComponents->dwSchemeLength;
1417     if (lpUrlComponents->lpszScheme)
1418     {
1419       scheme = HeapAlloc(GetProcessHeap(), 0, UCW.dwSchemeLength * sizeof(WCHAR));
1420       UCW.lpszScheme = scheme;
1421     }
1422   }
1423   if (lpUrlComponents->dwExtraInfoLength)
1424   {
1425     UCW.dwExtraInfoLength = lpUrlComponents->dwExtraInfoLength;
1426     if (lpUrlComponents->lpszExtraInfo)
1427     {
1428       extra = HeapAlloc(GetProcessHeap(), 0, UCW.dwExtraInfoLength * sizeof(WCHAR));
1429       UCW.lpszExtraInfo = extra;
1430     }
1431   }
1432   if ((ret = InternetCrackUrlW(lpwszUrl, nLength, dwFlags, &UCW)))
1433   {
1434     ConvertUrlComponentValue(&lpUrlComponents->lpszHostName, &lpUrlComponents->dwHostNameLength,
1435                              UCW.lpszHostName, UCW.dwHostNameLength, lpszUrl, lpwszUrl);
1436     ConvertUrlComponentValue(&lpUrlComponents->lpszUserName, &lpUrlComponents->dwUserNameLength,
1437                              UCW.lpszUserName, UCW.dwUserNameLength, lpszUrl, lpwszUrl);
1438     ConvertUrlComponentValue(&lpUrlComponents->lpszPassword, &lpUrlComponents->dwPasswordLength,
1439                              UCW.lpszPassword, UCW.dwPasswordLength, lpszUrl, lpwszUrl);
1440     ConvertUrlComponentValue(&lpUrlComponents->lpszUrlPath, &lpUrlComponents->dwUrlPathLength,
1441                              UCW.lpszUrlPath, UCW.dwUrlPathLength, lpszUrl, lpwszUrl);
1442     ConvertUrlComponentValue(&lpUrlComponents->lpszScheme, &lpUrlComponents->dwSchemeLength,
1443                              UCW.lpszScheme, UCW.dwSchemeLength, lpszUrl, lpwszUrl);
1444     ConvertUrlComponentValue(&lpUrlComponents->lpszExtraInfo, &lpUrlComponents->dwExtraInfoLength,
1445                              UCW.lpszExtraInfo, UCW.dwExtraInfoLength, lpszUrl, lpwszUrl);
1446
1447     lpUrlComponents->nScheme = UCW.nScheme;
1448     lpUrlComponents->nPort = UCW.nPort;
1449
1450     TRACE("%s: scheme(%s) host(%s) path(%s) extra(%s)\n", lpszUrl,
1451           debugstr_an(lpUrlComponents->lpszScheme, lpUrlComponents->dwSchemeLength),
1452           debugstr_an(lpUrlComponents->lpszHostName, lpUrlComponents->dwHostNameLength),
1453           debugstr_an(lpUrlComponents->lpszUrlPath, lpUrlComponents->dwUrlPathLength),
1454           debugstr_an(lpUrlComponents->lpszExtraInfo, lpUrlComponents->dwExtraInfoLength));
1455   }
1456   HeapFree(GetProcessHeap(), 0, lpwszUrl);
1457   HeapFree(GetProcessHeap(), 0, hostname);
1458   HeapFree(GetProcessHeap(), 0, username);
1459   HeapFree(GetProcessHeap(), 0, password);
1460   HeapFree(GetProcessHeap(), 0, path);
1461   HeapFree(GetProcessHeap(), 0, scheme);
1462   HeapFree(GetProcessHeap(), 0, extra);
1463   return ret;
1464 }
1465
1466 static const WCHAR url_schemes[][7] =
1467 {
1468     {'f','t','p',0},
1469     {'g','o','p','h','e','r',0},
1470     {'h','t','t','p',0},
1471     {'h','t','t','p','s',0},
1472     {'f','i','l','e',0},
1473     {'n','e','w','s',0},
1474     {'m','a','i','l','t','o',0},
1475     {'r','e','s',0},
1476 };
1477
1478 /***********************************************************************
1479  *           GetInternetSchemeW (internal)
1480  *
1481  * Get scheme of url
1482  *
1483  * RETURNS
1484  *    scheme on success
1485  *    INTERNET_SCHEME_UNKNOWN on failure
1486  *
1487  */
1488 static INTERNET_SCHEME GetInternetSchemeW(LPCWSTR lpszScheme, DWORD nMaxCmp)
1489 {
1490     int i;
1491
1492     TRACE("%s %d\n",debugstr_wn(lpszScheme, nMaxCmp), nMaxCmp);
1493
1494     if(lpszScheme==NULL)
1495         return INTERNET_SCHEME_UNKNOWN;
1496
1497     for (i = 0; i < sizeof(url_schemes)/sizeof(url_schemes[0]); i++)
1498         if (!strncmpW(lpszScheme, url_schemes[i], nMaxCmp))
1499             return INTERNET_SCHEME_FIRST + i;
1500
1501     return INTERNET_SCHEME_UNKNOWN;
1502 }
1503
1504 /***********************************************************************
1505  *           SetUrlComponentValueW (Internal)
1506  *
1507  * Helper function for InternetCrackUrlW
1508  *
1509  * PARAMS
1510  *     lppszComponent [O] Holds the returned string
1511  *     dwComponentLen [I] Holds the size of lppszComponent
1512  *                    [O] Holds the length of the string in lppszComponent without '\0'
1513  *     lpszStart      [I] Holds the string to copy from
1514  *     len            [I] Holds the length of lpszStart without '\0'
1515  *
1516  * RETURNS
1517  *    TRUE on success
1518  *    FALSE on failure
1519  *
1520  */
1521 static BOOL SetUrlComponentValueW(LPWSTR* lppszComponent, LPDWORD dwComponentLen, LPCWSTR lpszStart, DWORD len)
1522 {
1523     TRACE("%s (%d)\n", debugstr_wn(lpszStart,len), len);
1524
1525     if ( (*dwComponentLen == 0) && (*lppszComponent == NULL) )
1526         return FALSE;
1527
1528     if (*dwComponentLen != 0 || *lppszComponent == NULL)
1529     {
1530         if (*lppszComponent == NULL)
1531         {
1532             *lppszComponent = (LPWSTR)lpszStart;
1533             *dwComponentLen = len;
1534         }
1535         else
1536         {
1537             DWORD ncpylen = min((*dwComponentLen)-1, len);
1538             memcpy(*lppszComponent, lpszStart, ncpylen*sizeof(WCHAR));
1539             (*lppszComponent)[ncpylen] = '\0';
1540             *dwComponentLen = ncpylen;
1541         }
1542     }
1543
1544     return TRUE;
1545 }
1546
1547 /***********************************************************************
1548  *           InternetCrackUrlW   (WININET.@)
1549  *
1550  * Break up URL into its components
1551  *
1552  * RETURNS
1553  *    TRUE on success
1554  *    FALSE on failure
1555  */
1556 BOOL WINAPI InternetCrackUrlW(LPCWSTR lpszUrl_orig, DWORD dwUrlLength_orig, DWORD dwFlags,
1557                               LPURL_COMPONENTSW lpUC)
1558 {
1559   /*
1560    * RFC 1808
1561    * <protocol>:[//<net_loc>][/path][;<params>][?<query>][#<fragment>]
1562    *
1563    */
1564     LPCWSTR lpszParam    = NULL;
1565     BOOL  bIsAbsolute = FALSE;
1566     LPCWSTR lpszap, lpszUrl = lpszUrl_orig;
1567     LPCWSTR lpszcp = NULL;
1568     LPWSTR  lpszUrl_decode = NULL;
1569     DWORD dwUrlLength = dwUrlLength_orig;
1570
1571     TRACE("(%s %u %x %p)\n",
1572           lpszUrl ? debugstr_wn(lpszUrl, dwUrlLength ? dwUrlLength : strlenW(lpszUrl)) : "(null)",
1573           dwUrlLength, dwFlags, lpUC);
1574
1575     if (!lpszUrl_orig || !*lpszUrl_orig || !lpUC)
1576     {
1577         INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
1578         return FALSE;
1579     }
1580     if (!dwUrlLength) dwUrlLength = strlenW(lpszUrl);
1581
1582     if (dwFlags & ICU_DECODE)
1583     {
1584         WCHAR *url_tmp;
1585         DWORD len = dwUrlLength + 1;
1586
1587         if (!(url_tmp = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR))))
1588         {
1589             INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1590             return FALSE;
1591         }
1592         memcpy(url_tmp, lpszUrl_orig, dwUrlLength * sizeof(WCHAR));
1593         url_tmp[dwUrlLength] = 0;
1594         if (!(lpszUrl_decode = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR))))
1595         {
1596             HeapFree(GetProcessHeap(), 0, url_tmp);
1597             INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1598             return FALSE;
1599         }
1600         if (InternetCanonicalizeUrlW(url_tmp, lpszUrl_decode, &len, ICU_DECODE | ICU_NO_ENCODE))
1601         {
1602             dwUrlLength = len;
1603             lpszUrl = lpszUrl_decode;
1604         }
1605         HeapFree(GetProcessHeap(), 0, url_tmp);
1606     }
1607     lpszap = lpszUrl;
1608     
1609     /* Determine if the URI is absolute. */
1610     while (lpszap - lpszUrl < dwUrlLength)
1611     {
1612         if (isalnumW(*lpszap) || *lpszap == '+' || *lpszap == '.' || *lpszap == '-')
1613         {
1614             lpszap++;
1615             continue;
1616         }
1617         if ((*lpszap == ':') && (lpszap - lpszUrl >= 2))
1618         {
1619             bIsAbsolute = TRUE;
1620             lpszcp = lpszap;
1621         }
1622         else
1623         {
1624             lpszcp = lpszUrl; /* Relative url */
1625         }
1626
1627         break;
1628     }
1629
1630     lpUC->nScheme = INTERNET_SCHEME_UNKNOWN;
1631     lpUC->nPort = INTERNET_INVALID_PORT_NUMBER;
1632
1633     /* Parse <params> */
1634     lpszParam = memchrW(lpszap, ';', dwUrlLength - (lpszap - lpszUrl));
1635     if(!lpszParam)
1636         lpszParam = memchrW(lpszap, '?', dwUrlLength - (lpszap - lpszUrl));
1637     if(!lpszParam)
1638         lpszParam = memchrW(lpszap, '#', dwUrlLength - (lpszap - lpszUrl));
1639
1640     SetUrlComponentValueW(&lpUC->lpszExtraInfo, &lpUC->dwExtraInfoLength,
1641                           lpszParam, lpszParam ? dwUrlLength-(lpszParam-lpszUrl) : 0);
1642
1643     if (bIsAbsolute) /* Parse <protocol>:[//<net_loc>] */
1644     {
1645         LPCWSTR lpszNetLoc;
1646
1647         /* Get scheme first. */
1648         lpUC->nScheme = GetInternetSchemeW(lpszUrl, lpszcp - lpszUrl);
1649         SetUrlComponentValueW(&lpUC->lpszScheme, &lpUC->dwSchemeLength,
1650                                    lpszUrl, lpszcp - lpszUrl);
1651
1652         /* Eat ':' in protocol. */
1653         lpszcp++;
1654
1655         /* double slash indicates the net_loc portion is present */
1656         if ((lpszcp[0] == '/') && (lpszcp[1] == '/'))
1657         {
1658             lpszcp += 2;
1659
1660             lpszNetLoc = memchrW(lpszcp, '/', dwUrlLength - (lpszcp - lpszUrl));
1661             if (lpszParam)
1662             {
1663                 if (lpszNetLoc)
1664                     lpszNetLoc = min(lpszNetLoc, lpszParam);
1665                 else
1666                     lpszNetLoc = lpszParam;
1667             }
1668             else if (!lpszNetLoc)
1669                 lpszNetLoc = lpszcp + dwUrlLength-(lpszcp-lpszUrl);
1670
1671             /* Parse net-loc */
1672             if (lpszNetLoc)
1673             {
1674                 LPCWSTR lpszHost;
1675                 LPCWSTR lpszPort;
1676
1677                 /* [<user>[<:password>]@]<host>[:<port>] */
1678                 /* First find the user and password if they exist */
1679
1680                 lpszHost = memchrW(lpszcp, '@', dwUrlLength - (lpszcp - lpszUrl));
1681                 if (lpszHost == NULL || lpszHost > lpszNetLoc)
1682                 {
1683                     /* username and password not specified. */
1684                     SetUrlComponentValueW(&lpUC->lpszUserName, &lpUC->dwUserNameLength, NULL, 0);
1685                     SetUrlComponentValueW(&lpUC->lpszPassword, &lpUC->dwPasswordLength, NULL, 0);
1686                 }
1687                 else /* Parse out username and password */
1688                 {
1689                     LPCWSTR lpszUser = lpszcp;
1690                     LPCWSTR lpszPasswd = lpszHost;
1691
1692                     while (lpszcp < lpszHost)
1693                     {
1694                         if (*lpszcp == ':')
1695                             lpszPasswd = lpszcp;
1696
1697                         lpszcp++;
1698                     }
1699
1700                     SetUrlComponentValueW(&lpUC->lpszUserName, &lpUC->dwUserNameLength,
1701                                           lpszUser, lpszPasswd - lpszUser);
1702
1703                     if (lpszPasswd != lpszHost)
1704                         lpszPasswd++;
1705                     SetUrlComponentValueW(&lpUC->lpszPassword, &lpUC->dwPasswordLength,
1706                                           lpszPasswd == lpszHost ? NULL : lpszPasswd,
1707                                           lpszHost - lpszPasswd);
1708
1709                     lpszcp++; /* Advance to beginning of host */
1710                 }
1711
1712                 /* Parse <host><:port> */
1713
1714                 lpszHost = lpszcp;
1715                 lpszPort = lpszNetLoc;
1716
1717                 /* special case for res:// URLs: there is no port here, so the host is the
1718                    entire string up to the first '/' */
1719                 if(lpUC->nScheme==INTERNET_SCHEME_RES)
1720                 {
1721                     SetUrlComponentValueW(&lpUC->lpszHostName, &lpUC->dwHostNameLength,
1722                                           lpszHost, lpszPort - lpszHost);
1723                     lpszcp=lpszNetLoc;
1724                 }
1725                 else
1726                 {
1727                     while (lpszcp < lpszNetLoc)
1728                     {
1729                         if (*lpszcp == ':')
1730                             lpszPort = lpszcp;
1731
1732                         lpszcp++;
1733                     }
1734
1735                     /* If the scheme is "file" and the host is just one letter, it's not a host */
1736                     if(lpUC->nScheme==INTERNET_SCHEME_FILE && lpszPort <= lpszHost+1)
1737                     {
1738                         lpszcp=lpszHost;
1739                         SetUrlComponentValueW(&lpUC->lpszHostName, &lpUC->dwHostNameLength,
1740                                               NULL, 0);
1741                     }
1742                     else
1743                     {
1744                         SetUrlComponentValueW(&lpUC->lpszHostName, &lpUC->dwHostNameLength,
1745                                               lpszHost, lpszPort - lpszHost);
1746                         if (lpszPort != lpszNetLoc)
1747                             lpUC->nPort = atoiW(++lpszPort);
1748                         else switch (lpUC->nScheme)
1749                         {
1750                         case INTERNET_SCHEME_HTTP:
1751                             lpUC->nPort = INTERNET_DEFAULT_HTTP_PORT;
1752                             break;
1753                         case INTERNET_SCHEME_HTTPS:
1754                             lpUC->nPort = INTERNET_DEFAULT_HTTPS_PORT;
1755                             break;
1756                         case INTERNET_SCHEME_FTP:
1757                             lpUC->nPort = INTERNET_DEFAULT_FTP_PORT;
1758                             break;
1759                         case INTERNET_SCHEME_GOPHER:
1760                             lpUC->nPort = INTERNET_DEFAULT_GOPHER_PORT;
1761                             break;
1762                         default:
1763                             break;
1764                         }
1765                     }
1766                 }
1767             }
1768         }
1769         else
1770         {
1771             SetUrlComponentValueW(&lpUC->lpszUserName, &lpUC->dwUserNameLength, NULL, 0);
1772             SetUrlComponentValueW(&lpUC->lpszPassword, &lpUC->dwPasswordLength, NULL, 0);
1773             SetUrlComponentValueW(&lpUC->lpszHostName, &lpUC->dwHostNameLength, NULL, 0);
1774         }
1775     }
1776     else
1777     {
1778         SetUrlComponentValueW(&lpUC->lpszScheme, &lpUC->dwSchemeLength, NULL, 0);
1779         SetUrlComponentValueW(&lpUC->lpszUserName, &lpUC->dwUserNameLength, NULL, 0);
1780         SetUrlComponentValueW(&lpUC->lpszPassword, &lpUC->dwPasswordLength, NULL, 0);
1781         SetUrlComponentValueW(&lpUC->lpszHostName, &lpUC->dwHostNameLength, NULL, 0);
1782     }
1783
1784     /* Here lpszcp points to:
1785      *
1786      * <protocol>:[//<net_loc>][/path][;<params>][?<query>][#<fragment>]
1787      *                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1788      */
1789     if (lpszcp != 0 && lpszcp - lpszUrl < dwUrlLength && (!lpszParam || lpszcp <= lpszParam))
1790     {
1791         INT len;
1792
1793         /* Only truncate the parameter list if it's already been saved
1794          * in lpUC->lpszExtraInfo.
1795          */
1796         if (lpszParam && lpUC->dwExtraInfoLength && lpUC->lpszExtraInfo)
1797             len = lpszParam - lpszcp;
1798         else
1799         {
1800             /* Leave the parameter list in lpszUrlPath.  Strip off any trailing
1801              * newlines if necessary.
1802              */
1803             LPWSTR lpsznewline = memchrW(lpszcp, '\n', dwUrlLength - (lpszcp - lpszUrl));
1804             if (lpsznewline != NULL)
1805                 len = lpsznewline - lpszcp;
1806             else
1807                 len = dwUrlLength-(lpszcp-lpszUrl);
1808         }
1809         SetUrlComponentValueW(&lpUC->lpszUrlPath, &lpUC->dwUrlPathLength,
1810                                    lpszcp, len);
1811     }
1812     else
1813     {
1814         if (lpUC->lpszUrlPath && (lpUC->dwUrlPathLength > 0))
1815             lpUC->lpszUrlPath[0] = 0;
1816         lpUC->dwUrlPathLength = 0;
1817     }
1818
1819     TRACE("%s: scheme(%s) host(%s) path(%s) extra(%s)\n", debugstr_wn(lpszUrl,dwUrlLength),
1820              debugstr_wn(lpUC->lpszScheme,lpUC->dwSchemeLength),
1821              debugstr_wn(lpUC->lpszHostName,lpUC->dwHostNameLength),
1822              debugstr_wn(lpUC->lpszUrlPath,lpUC->dwUrlPathLength),
1823              debugstr_wn(lpUC->lpszExtraInfo,lpUC->dwExtraInfoLength));
1824
1825     HeapFree(GetProcessHeap(), 0, lpszUrl_decode );
1826     return TRUE;
1827 }
1828
1829 /***********************************************************************
1830  *           InternetAttemptConnect (WININET.@)
1831  *
1832  * Attempt to make a connection to the internet
1833  *
1834  * RETURNS
1835  *    ERROR_SUCCESS on success
1836  *    Error value   on failure
1837  *
1838  */
1839 DWORD WINAPI InternetAttemptConnect(DWORD dwReserved)
1840 {
1841     FIXME("Stub\n");
1842     return ERROR_SUCCESS;
1843 }
1844
1845
1846 /***********************************************************************
1847  *           InternetCanonicalizeUrlA (WININET.@)
1848  *
1849  * Escape unsafe characters and spaces
1850  *
1851  * RETURNS
1852  *    TRUE on success
1853  *    FALSE on failure
1854  *
1855  */
1856 BOOL WINAPI InternetCanonicalizeUrlA(LPCSTR lpszUrl, LPSTR lpszBuffer,
1857         LPDWORD lpdwBufferLength, DWORD dwFlags)
1858 {
1859     HRESULT hr;
1860     DWORD dwURLFlags = URL_WININET_COMPATIBILITY | URL_ESCAPE_UNSAFE;
1861
1862     TRACE("(%s, %p, %p, 0x%08x) bufferlength: %d\n", debugstr_a(lpszUrl), lpszBuffer,
1863         lpdwBufferLength, lpdwBufferLength ? *lpdwBufferLength : -1, dwFlags);
1864
1865     if(dwFlags & ICU_DECODE)
1866     {
1867         dwURLFlags |= URL_UNESCAPE;
1868         dwFlags &= ~ICU_DECODE;
1869     }
1870
1871     if(dwFlags & ICU_ESCAPE)
1872     {
1873         dwURLFlags |= URL_UNESCAPE;
1874         dwFlags &= ~ICU_ESCAPE;
1875     }
1876
1877     if(dwFlags & ICU_BROWSER_MODE)
1878     {
1879         dwURLFlags |= URL_BROWSER_MODE;
1880         dwFlags &= ~ICU_BROWSER_MODE;
1881     }
1882
1883     if(dwFlags & ICU_NO_ENCODE)
1884     {
1885         /* Flip this bit to correspond to URL_ESCAPE_UNSAFE */
1886         dwURLFlags ^= URL_ESCAPE_UNSAFE;
1887         dwFlags &= ~ICU_NO_ENCODE;
1888     }
1889
1890     if (dwFlags) FIXME("Unhandled flags 0x%08x\n", dwFlags);
1891
1892     hr = UrlCanonicalizeA(lpszUrl, lpszBuffer, lpdwBufferLength, dwURLFlags);
1893     if (hr == E_POINTER) SetLastError(ERROR_INSUFFICIENT_BUFFER);
1894     if (hr == E_INVALIDARG) SetLastError(ERROR_INVALID_PARAMETER);
1895
1896     return (hr == S_OK) ? TRUE : FALSE;
1897 }
1898
1899 /***********************************************************************
1900  *           InternetCanonicalizeUrlW (WININET.@)
1901  *
1902  * Escape unsafe characters and spaces
1903  *
1904  * RETURNS
1905  *    TRUE on success
1906  *    FALSE on failure
1907  *
1908  */
1909 BOOL WINAPI InternetCanonicalizeUrlW(LPCWSTR lpszUrl, LPWSTR lpszBuffer,
1910     LPDWORD lpdwBufferLength, DWORD dwFlags)
1911 {
1912     HRESULT hr;
1913     DWORD dwURLFlags = URL_WININET_COMPATIBILITY | URL_ESCAPE_UNSAFE;
1914
1915     TRACE("(%s, %p, %p, 0x%08x) bufferlength: %d\n", debugstr_w(lpszUrl), lpszBuffer,
1916           lpdwBufferLength, dwFlags, lpdwBufferLength ? *lpdwBufferLength : -1);
1917
1918     if(dwFlags & ICU_DECODE)
1919     {
1920         dwURLFlags |= URL_UNESCAPE;
1921         dwFlags &= ~ICU_DECODE;
1922     }
1923
1924     if(dwFlags & ICU_ESCAPE)
1925     {
1926         dwURLFlags |= URL_UNESCAPE;
1927         dwFlags &= ~ICU_ESCAPE;
1928     }
1929
1930     if(dwFlags & ICU_BROWSER_MODE)
1931     {
1932         dwURLFlags |= URL_BROWSER_MODE;
1933         dwFlags &= ~ICU_BROWSER_MODE;
1934     }
1935
1936     if(dwFlags & ICU_NO_ENCODE)
1937     {
1938         /* Flip this bit to correspond to URL_ESCAPE_UNSAFE */
1939         dwURLFlags ^= URL_ESCAPE_UNSAFE;
1940         dwFlags &= ~ICU_NO_ENCODE;
1941     }
1942
1943     if (dwFlags) FIXME("Unhandled flags 0x%08x\n", dwFlags);
1944
1945     hr = UrlCanonicalizeW(lpszUrl, lpszBuffer, lpdwBufferLength, dwURLFlags);
1946     if (hr == E_POINTER) SetLastError(ERROR_INSUFFICIENT_BUFFER);
1947     if (hr == E_INVALIDARG) SetLastError(ERROR_INVALID_PARAMETER);
1948
1949     return (hr == S_OK) ? TRUE : FALSE;
1950 }
1951
1952 /* #################################################### */
1953
1954 static INTERNET_STATUS_CALLBACK set_status_callback(
1955     object_header_t *lpwh, INTERNET_STATUS_CALLBACK callback, BOOL unicode)
1956 {
1957     INTERNET_STATUS_CALLBACK ret;
1958
1959     if (unicode) lpwh->dwInternalFlags |= INET_CALLBACKW;
1960     else lpwh->dwInternalFlags &= ~INET_CALLBACKW;
1961
1962     ret = lpwh->lpfnStatusCB;
1963     lpwh->lpfnStatusCB = callback;
1964
1965     return ret;
1966 }
1967
1968 /***********************************************************************
1969  *           InternetSetStatusCallbackA (WININET.@)
1970  *
1971  * Sets up a callback function which is called as progress is made
1972  * during an operation.
1973  *
1974  * RETURNS
1975  *    Previous callback or NULL         on success
1976  *    INTERNET_INVALID_STATUS_CALLBACK  on failure
1977  *
1978  */
1979 INTERNET_STATUS_CALLBACK WINAPI InternetSetStatusCallbackA(
1980         HINTERNET hInternet ,INTERNET_STATUS_CALLBACK lpfnIntCB)
1981 {
1982     INTERNET_STATUS_CALLBACK retVal;
1983     object_header_t *lpwh;
1984
1985     TRACE("%p\n", hInternet);
1986
1987     if (!(lpwh = WININET_GetObject(hInternet)))
1988         return INTERNET_INVALID_STATUS_CALLBACK;
1989
1990     retVal = set_status_callback(lpwh, lpfnIntCB, FALSE);
1991
1992     WININET_Release( lpwh );
1993     return retVal;
1994 }
1995
1996 /***********************************************************************
1997  *           InternetSetStatusCallbackW (WININET.@)
1998  *
1999  * Sets up a callback function which is called as progress is made
2000  * during an operation.
2001  *
2002  * RETURNS
2003  *    Previous callback or NULL         on success
2004  *    INTERNET_INVALID_STATUS_CALLBACK  on failure
2005  *
2006  */
2007 INTERNET_STATUS_CALLBACK WINAPI InternetSetStatusCallbackW(
2008         HINTERNET hInternet ,INTERNET_STATUS_CALLBACK lpfnIntCB)
2009 {
2010     INTERNET_STATUS_CALLBACK retVal;
2011     object_header_t *lpwh;
2012
2013     TRACE("%p\n", hInternet);
2014
2015     if (!(lpwh = WININET_GetObject(hInternet)))
2016         return INTERNET_INVALID_STATUS_CALLBACK;
2017
2018     retVal = set_status_callback(lpwh, lpfnIntCB, TRUE);
2019
2020     WININET_Release( lpwh );
2021     return retVal;
2022 }
2023
2024 /***********************************************************************
2025  *           InternetSetFilePointer (WININET.@)
2026  */
2027 DWORD WINAPI InternetSetFilePointer(HINTERNET hFile, LONG lDistanceToMove,
2028     PVOID pReserved, DWORD dwMoveContext, DWORD_PTR dwContext)
2029 {
2030     FIXME("stub\n");
2031     return FALSE;
2032 }
2033
2034 /***********************************************************************
2035  *           InternetWriteFile (WININET.@)
2036  *
2037  * Write data to an open internet file
2038  *
2039  * RETURNS
2040  *    TRUE  on success
2041  *    FALSE on failure
2042  *
2043  */
2044 BOOL WINAPI InternetWriteFile(HINTERNET hFile, LPCVOID lpBuffer,
2045         DWORD dwNumOfBytesToWrite, LPDWORD lpdwNumOfBytesWritten)
2046 {
2047     object_header_t *lpwh;
2048     BOOL res;
2049
2050     TRACE("(%p %p %d %p)\n", hFile, lpBuffer, dwNumOfBytesToWrite, lpdwNumOfBytesWritten);
2051
2052     lpwh = WININET_GetObject( hFile );
2053     if (!lpwh) {
2054         WARN("Invalid handle\n");
2055         SetLastError(ERROR_INVALID_HANDLE);
2056         return FALSE;
2057     }
2058
2059     if(lpwh->vtbl->WriteFile) {
2060         res = lpwh->vtbl->WriteFile(lpwh, lpBuffer, dwNumOfBytesToWrite, lpdwNumOfBytesWritten);
2061     }else {
2062         WARN("No Writefile method.\n");
2063         res = ERROR_INVALID_HANDLE;
2064     }
2065
2066     WININET_Release( lpwh );
2067
2068     if(res != ERROR_SUCCESS)
2069         SetLastError(res);
2070     return res == ERROR_SUCCESS;
2071 }
2072
2073
2074 /***********************************************************************
2075  *           InternetReadFile (WININET.@)
2076  *
2077  * Read data from an open internet file
2078  *
2079  * RETURNS
2080  *    TRUE  on success
2081  *    FALSE on failure
2082  *
2083  */
2084 BOOL WINAPI InternetReadFile(HINTERNET hFile, LPVOID lpBuffer,
2085         DWORD dwNumOfBytesToRead, LPDWORD pdwNumOfBytesRead)
2086 {
2087     object_header_t *hdr;
2088     DWORD res = ERROR_INTERNET_INCORRECT_HANDLE_TYPE;
2089
2090     TRACE("%p %p %d %p\n", hFile, lpBuffer, dwNumOfBytesToRead, pdwNumOfBytesRead);
2091
2092     hdr = WININET_GetObject(hFile);
2093     if (!hdr) {
2094         INTERNET_SetLastError(ERROR_INVALID_HANDLE);
2095         return FALSE;
2096     }
2097
2098     if(hdr->vtbl->ReadFile)
2099         res = hdr->vtbl->ReadFile(hdr, lpBuffer, dwNumOfBytesToRead, pdwNumOfBytesRead);
2100
2101     WININET_Release(hdr);
2102
2103     TRACE("-- %s (%u) (bytes read: %d)\n", res == ERROR_SUCCESS ? "TRUE": "FALSE", res,
2104           pdwNumOfBytesRead ? *pdwNumOfBytesRead : -1);
2105
2106     if(res != ERROR_SUCCESS)
2107         SetLastError(res);
2108     return res == ERROR_SUCCESS;
2109 }
2110
2111 /***********************************************************************
2112  *           InternetReadFileExA (WININET.@)
2113  *
2114  * Read data from an open internet file
2115  *
2116  * PARAMS
2117  *  hFile         [I] Handle returned by InternetOpenUrl or HttpOpenRequest.
2118  *  lpBuffersOut  [I/O] Buffer.
2119  *  dwFlags       [I] Flags. See notes.
2120  *  dwContext     [I] Context for callbacks.
2121  *
2122  * RETURNS
2123  *    TRUE  on success
2124  *    FALSE on failure
2125  *
2126  * NOTES
2127  *  The parameter dwFlags include zero or more of the following flags:
2128  *|IRF_ASYNC - Makes the call asynchronous.
2129  *|IRF_SYNC - Makes the call synchronous.
2130  *|IRF_USE_CONTEXT - Forces dwContext to be used.
2131  *|IRF_NO_WAIT - Don't block if the data is not available, just return what is available.
2132  *
2133  * However, in testing IRF_USE_CONTEXT seems to have no effect - dwContext isn't used.
2134  *
2135  * SEE
2136  *  InternetOpenUrlA(), HttpOpenRequestA()
2137  */
2138 BOOL WINAPI InternetReadFileExA(HINTERNET hFile, LPINTERNET_BUFFERSA lpBuffersOut,
2139         DWORD dwFlags, DWORD_PTR dwContext)
2140 {
2141     object_header_t *hdr;
2142     DWORD res = ERROR_INTERNET_INCORRECT_HANDLE_TYPE;
2143
2144     TRACE("(%p %p 0x%x 0x%lx)\n", hFile, lpBuffersOut, dwFlags, dwContext);
2145
2146     hdr = WININET_GetObject(hFile);
2147     if (!hdr) {
2148         INTERNET_SetLastError(ERROR_INVALID_HANDLE);
2149         return FALSE;
2150     }
2151
2152     if(hdr->vtbl->ReadFileExA)
2153         res = hdr->vtbl->ReadFileExA(hdr, lpBuffersOut, dwFlags, dwContext);
2154
2155     WININET_Release(hdr);
2156
2157     TRACE("-- %s (%u, bytes read: %d)\n", res == ERROR_SUCCESS ? "TRUE": "FALSE",
2158           res, lpBuffersOut->dwBufferLength);
2159
2160     if(res != ERROR_SUCCESS)
2161         SetLastError(res);
2162     return res == ERROR_SUCCESS;
2163 }
2164
2165 /***********************************************************************
2166  *           InternetReadFileExW (WININET.@)
2167  * SEE
2168  *  InternetReadFileExA()
2169  */
2170 BOOL WINAPI InternetReadFileExW(HINTERNET hFile, LPINTERNET_BUFFERSW lpBuffer,
2171         DWORD dwFlags, DWORD_PTR dwContext)
2172 {
2173     object_header_t *hdr;
2174     DWORD res = ERROR_INTERNET_INCORRECT_HANDLE_TYPE;
2175
2176     TRACE("(%p %p 0x%x 0x%lx)\n", hFile, lpBuffer, dwFlags, dwContext);
2177
2178     hdr = WININET_GetObject(hFile);
2179     if (!hdr) {
2180         INTERNET_SetLastError(ERROR_INVALID_HANDLE);
2181         return FALSE;
2182     }
2183
2184     if(hdr->vtbl->ReadFileExW)
2185         res = hdr->vtbl->ReadFileExW(hdr, lpBuffer, dwFlags, dwContext);
2186
2187     WININET_Release(hdr);
2188
2189     TRACE("-- %s (%u, bytes read: %d)\n", res == ERROR_SUCCESS ? "TRUE": "FALSE",
2190           res, lpBuffer->dwBufferLength);
2191
2192     if(res != ERROR_SUCCESS)
2193         SetLastError(res);
2194     return res == ERROR_SUCCESS;
2195 }
2196
2197 DWORD INET_QueryOption(DWORD option, void *buffer, DWORD *size, BOOL unicode)
2198 {
2199     static BOOL warn = TRUE;
2200
2201     switch(option) {
2202     case INTERNET_OPTION_REQUEST_FLAGS:
2203         TRACE("INTERNET_OPTION_REQUEST_FLAGS\n");
2204
2205         if (*size < sizeof(ULONG))
2206             return ERROR_INSUFFICIENT_BUFFER;
2207
2208         *(ULONG*)buffer = 4;
2209         *size = sizeof(ULONG);
2210
2211         return ERROR_SUCCESS;
2212
2213     case INTERNET_OPTION_HTTP_VERSION:
2214         if (*size < sizeof(HTTP_VERSION_INFO))
2215             return ERROR_INSUFFICIENT_BUFFER;
2216
2217         /*
2218          * Presently hardcoded to 1.1
2219          */
2220         ((HTTP_VERSION_INFO*)buffer)->dwMajorVersion = 1;
2221         ((HTTP_VERSION_INFO*)buffer)->dwMinorVersion = 1;
2222         *size = sizeof(HTTP_VERSION_INFO);
2223
2224         return ERROR_SUCCESS;
2225
2226     case INTERNET_OPTION_CONNECTED_STATE:
2227         if (warn) {
2228             FIXME("INTERNET_OPTION_CONNECTED_STATE: semi-stub\n");
2229             warn = FALSE;
2230         }
2231         if (*size < sizeof(ULONG))
2232             return ERROR_INSUFFICIENT_BUFFER;
2233
2234         *(ULONG*)buffer = INTERNET_STATE_CONNECTED;
2235         *size = sizeof(ULONG);
2236
2237         return ERROR_SUCCESS;
2238
2239     case INTERNET_OPTION_PROXY: {
2240         appinfo_t ai;
2241         BOOL ret;
2242
2243         TRACE("Getting global proxy info\n");
2244         memset(&ai, 0, sizeof(appinfo_t));
2245         INTERNET_ConfigureProxy(&ai);
2246
2247         ret = APPINFO_QueryOption(&ai.hdr, INTERNET_OPTION_PROXY, buffer, size, unicode); /* FIXME */
2248         APPINFO_Destroy(&ai.hdr);
2249         return ret;
2250     }
2251
2252     case INTERNET_OPTION_MAX_CONNS_PER_SERVER:
2253         TRACE("INTERNET_OPTION_MAX_CONNS_PER_SERVER\n");
2254
2255         if (*size < sizeof(ULONG))
2256             return ERROR_INSUFFICIENT_BUFFER;
2257
2258         *(ULONG*)buffer = 2;
2259         *size = sizeof(ULONG);
2260
2261         return ERROR_SUCCESS;
2262
2263     case INTERNET_OPTION_MAX_CONNS_PER_1_0_SERVER:
2264             TRACE("INTERNET_OPTION_MAX_CONNS_1_0_SERVER\n");
2265
2266             if (*size < sizeof(ULONG))
2267                 return ERROR_INSUFFICIENT_BUFFER;
2268
2269             *(ULONG*)size = 4;
2270             *size = sizeof(ULONG);
2271
2272             return ERROR_SUCCESS;
2273
2274     case INTERNET_OPTION_SECURITY_FLAGS:
2275         FIXME("INTERNET_OPTION_SECURITY_FLAGS: Stub\n");
2276         return ERROR_SUCCESS;
2277
2278     case INTERNET_OPTION_VERSION: {
2279         static const INTERNET_VERSION_INFO info = { 1, 2 };
2280
2281         TRACE("INTERNET_OPTION_VERSION\n");
2282
2283         if (*size < sizeof(INTERNET_VERSION_INFO))
2284             return ERROR_INSUFFICIENT_BUFFER;
2285
2286         memcpy(buffer, &info, sizeof(info));
2287         *size = sizeof(info);
2288
2289         return ERROR_SUCCESS;
2290     }
2291
2292     case INTERNET_OPTION_PER_CONNECTION_OPTION: {
2293         INTERNET_PER_CONN_OPTION_LISTW *con = buffer;
2294         INTERNET_PER_CONN_OPTION_LISTA *conA = buffer;
2295         DWORD res = ERROR_SUCCESS, i;
2296         proxyinfo_t pi;
2297         LONG ret;
2298
2299         TRACE("Getting global proxy info\n");
2300         if((ret = INTERNET_LoadProxySettings(&pi)))
2301             return ret;
2302
2303         FIXME("INTERNET_OPTION_PER_CONNECTION_OPTION stub\n");
2304
2305         if (*size < sizeof(INTERNET_PER_CONN_OPTION_LISTW)) {
2306             FreeProxyInfo(&pi);
2307             return ERROR_INSUFFICIENT_BUFFER;
2308         }
2309
2310         for (i = 0; i < con->dwOptionCount; i++) {
2311             INTERNET_PER_CONN_OPTIONW *option = con->pOptions + i;
2312             INTERNET_PER_CONN_OPTIONA *optionA = conA->pOptions + i;
2313
2314             switch (option->dwOption) {
2315             case INTERNET_PER_CONN_FLAGS:
2316                 if(pi.dwProxyEnabled)
2317                     option->Value.dwValue = PROXY_TYPE_PROXY;
2318                 else
2319                     option->Value.dwValue = PROXY_TYPE_DIRECT;
2320                 break;
2321
2322             case INTERNET_PER_CONN_PROXY_SERVER:
2323                 if (unicode)
2324                     option->Value.pszValue = heap_strdupW(pi.lpszProxyServer);
2325                 else
2326                     optionA->Value.pszValue = heap_strdupWtoA(pi.lpszProxyServer);
2327                 break;
2328
2329             case INTERNET_PER_CONN_PROXY_BYPASS:
2330                 if (unicode)
2331                     option->Value.pszValue = heap_strdupW(pi.lpszProxyBypass);
2332                 else
2333                     optionA->Value.pszValue = heap_strdupWtoA(pi.lpszProxyBypass);
2334                 break;
2335
2336             case INTERNET_PER_CONN_AUTOCONFIG_URL:
2337             case INTERNET_PER_CONN_AUTODISCOVERY_FLAGS:
2338             case INTERNET_PER_CONN_AUTOCONFIG_SECONDARY_URL:
2339             case INTERNET_PER_CONN_AUTOCONFIG_RELOAD_DELAY_MINS:
2340             case INTERNET_PER_CONN_AUTOCONFIG_LAST_DETECT_TIME:
2341             case INTERNET_PER_CONN_AUTOCONFIG_LAST_DETECT_URL:
2342                 FIXME("Unhandled dwOption %d\n", option->dwOption);
2343                 memset(&option->Value, 0, sizeof(option->Value));
2344                 break;
2345
2346             default:
2347                 FIXME("Unknown dwOption %d\n", option->dwOption);
2348                 res = ERROR_INVALID_PARAMETER;
2349                 break;
2350             }
2351         }
2352         FreeProxyInfo(&pi);
2353
2354         return res;
2355     }
2356     case INTERNET_OPTION_USER_AGENT:
2357         return ERROR_INTERNET_INCORRECT_HANDLE_TYPE;
2358     case INTERNET_OPTION_POLICY:
2359         return ERROR_INVALID_PARAMETER;
2360     }
2361
2362     FIXME("Stub for %d\n", option);
2363     return ERROR_INTERNET_INCORRECT_HANDLE_TYPE;
2364 }
2365
2366 /***********************************************************************
2367  *           InternetQueryOptionW (WININET.@)
2368  *
2369  * Queries an options on the specified handle
2370  *
2371  * RETURNS
2372  *    TRUE  on success
2373  *    FALSE on failure
2374  *
2375  */
2376 BOOL WINAPI InternetQueryOptionW(HINTERNET hInternet, DWORD dwOption,
2377                                  LPVOID lpBuffer, LPDWORD lpdwBufferLength)
2378 {
2379     object_header_t *hdr;
2380     DWORD res = ERROR_INVALID_HANDLE;
2381
2382     TRACE("%p %d %p %p\n", hInternet, dwOption, lpBuffer, lpdwBufferLength);
2383
2384     if(hInternet) {
2385         hdr = WININET_GetObject(hInternet);
2386         if (hdr) {
2387             res = hdr->vtbl->QueryOption(hdr, dwOption, lpBuffer, lpdwBufferLength, TRUE);
2388             WININET_Release(hdr);
2389         }
2390     }else {
2391         res = INET_QueryOption(dwOption, lpBuffer, lpdwBufferLength, TRUE);
2392     }
2393
2394     if(res != ERROR_SUCCESS)
2395         SetLastError(res);
2396     return res == ERROR_SUCCESS;
2397 }
2398
2399 /***********************************************************************
2400  *           InternetQueryOptionA (WININET.@)
2401  *
2402  * Queries an options on the specified handle
2403  *
2404  * RETURNS
2405  *    TRUE  on success
2406  *    FALSE on failure
2407  *
2408  */
2409 BOOL WINAPI InternetQueryOptionA(HINTERNET hInternet, DWORD dwOption,
2410                                  LPVOID lpBuffer, LPDWORD lpdwBufferLength)
2411 {
2412     object_header_t *hdr;
2413     DWORD res = ERROR_INVALID_HANDLE;
2414
2415     TRACE("%p %d %p %p\n", hInternet, dwOption, lpBuffer, lpdwBufferLength);
2416
2417     if(hInternet) {
2418         hdr = WININET_GetObject(hInternet);
2419         if (hdr) {
2420             res = hdr->vtbl->QueryOption(hdr, dwOption, lpBuffer, lpdwBufferLength, FALSE);
2421             WININET_Release(hdr);
2422         }
2423     }else {
2424         res = INET_QueryOption(dwOption, lpBuffer, lpdwBufferLength, FALSE);
2425     }
2426
2427     if(res != ERROR_SUCCESS)
2428         SetLastError(res);
2429     return res == ERROR_SUCCESS;
2430 }
2431
2432
2433 /***********************************************************************
2434  *           InternetSetOptionW (WININET.@)
2435  *
2436  * Sets an options on the specified handle
2437  *
2438  * RETURNS
2439  *    TRUE  on success
2440  *    FALSE on failure
2441  *
2442  */
2443 BOOL WINAPI InternetSetOptionW(HINTERNET hInternet, DWORD dwOption,
2444                            LPVOID lpBuffer, DWORD dwBufferLength)
2445 {
2446     object_header_t *lpwhh;
2447     BOOL ret = TRUE;
2448
2449     TRACE("(%p %d %p %d)\n", hInternet, dwOption, lpBuffer, dwBufferLength);
2450
2451     lpwhh = (object_header_t*) WININET_GetObject( hInternet );
2452     if(lpwhh && lpwhh->vtbl->SetOption) {
2453         DWORD res;
2454
2455         res = lpwhh->vtbl->SetOption(lpwhh, dwOption, lpBuffer, dwBufferLength);
2456         if(res != ERROR_INTERNET_INVALID_OPTION) {
2457             WININET_Release( lpwhh );
2458
2459             if(res != ERROR_SUCCESS)
2460                 SetLastError(res);
2461
2462             return res == ERROR_SUCCESS;
2463         }
2464     }
2465
2466     switch (dwOption)
2467     {
2468     case INTERNET_OPTION_CALLBACK:
2469       {
2470         if (!lpwhh)
2471         {
2472             SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
2473             return FALSE;
2474         }
2475         WININET_Release(lpwhh);
2476         SetLastError(ERROR_INTERNET_OPTION_NOT_SETTABLE);
2477         return FALSE;
2478       }
2479     case INTERNET_OPTION_HTTP_VERSION:
2480       {
2481         HTTP_VERSION_INFO* pVersion=(HTTP_VERSION_INFO*)lpBuffer;
2482         FIXME("Option INTERNET_OPTION_HTTP_VERSION(%d,%d): STUB\n",pVersion->dwMajorVersion,pVersion->dwMinorVersion);
2483       }
2484       break;
2485     case INTERNET_OPTION_ERROR_MASK:
2486       {
2487         ULONG flags = *(ULONG *)lpBuffer;
2488         FIXME("Option INTERNET_OPTION_ERROR_MASK(%d): STUB\n", flags);
2489       }
2490       break;
2491     case INTERNET_OPTION_CODEPAGE:
2492       {
2493         ULONG codepage = *(ULONG *)lpBuffer;
2494         FIXME("Option INTERNET_OPTION_CODEPAGE (%d): STUB\n", codepage);
2495       }
2496       break;
2497     case INTERNET_OPTION_REQUEST_PRIORITY:
2498       {
2499         ULONG priority = *(ULONG *)lpBuffer;
2500         FIXME("Option INTERNET_OPTION_REQUEST_PRIORITY (%d): STUB\n", priority);
2501       }
2502       break;
2503     case INTERNET_OPTION_CONNECT_TIMEOUT:
2504       {
2505         ULONG connecttimeout = *(ULONG *)lpBuffer;
2506         FIXME("Option INTERNET_OPTION_CONNECT_TIMEOUT (%d): STUB\n", connecttimeout);
2507       }
2508       break;
2509     case INTERNET_OPTION_DATA_RECEIVE_TIMEOUT:
2510       {
2511         ULONG receivetimeout = *(ULONG *)lpBuffer;
2512         FIXME("Option INTERNET_OPTION_DATA_RECEIVE_TIMEOUT (%d): STUB\n", receivetimeout);
2513       }
2514       break;
2515     case INTERNET_OPTION_MAX_CONNS_PER_SERVER:
2516       {
2517         ULONG conns = *(ULONG *)lpBuffer;
2518         FIXME("Option INTERNET_OPTION_MAX_CONNS_PER_SERVER (%d): STUB\n", conns);
2519       }
2520       break;
2521     case INTERNET_OPTION_MAX_CONNS_PER_1_0_SERVER:
2522       {
2523         ULONG conns = *(ULONG *)lpBuffer;
2524         FIXME("Option INTERNET_OPTION_MAX_CONNS_PER_1_0_SERVER (%d): STUB\n", conns);
2525       }
2526       break;
2527     case INTERNET_OPTION_RESET_URLCACHE_SESSION:
2528         FIXME("Option INTERNET_OPTION_RESET_URLCACHE_SESSION: STUB\n");
2529         break;
2530     case INTERNET_OPTION_END_BROWSER_SESSION:
2531         FIXME("Option INTERNET_OPTION_END_BROWSER_SESSION: STUB\n");
2532         break;
2533     case INTERNET_OPTION_CONNECTED_STATE:
2534         FIXME("Option INTERNET_OPTION_CONNECTED_STATE: STUB\n");
2535         break;
2536     case INTERNET_OPTION_DISABLE_PASSPORT_AUTH:
2537         TRACE("Option INTERNET_OPTION_DISABLE_PASSPORT_AUTH: harmless stub, since not enabled\n");
2538         break;
2539     case INTERNET_OPTION_SEND_TIMEOUT:
2540     case INTERNET_OPTION_RECEIVE_TIMEOUT:
2541     {
2542         ULONG timeout = *(ULONG *)lpBuffer;
2543         FIXME("INTERNET_OPTION_SEND/RECEIVE_TIMEOUT %d\n", timeout);
2544         break;
2545     }
2546     case INTERNET_OPTION_CONNECT_RETRIES:
2547     {
2548         ULONG retries = *(ULONG *)lpBuffer;
2549         FIXME("INTERNET_OPTION_CONNECT_RETRIES %d\n", retries);
2550         break;
2551     }
2552     case INTERNET_OPTION_CONTEXT_VALUE:
2553          FIXME("Option INTERNET_OPTION_CONTEXT_VALUE; STUB\n");
2554          break;
2555     case INTERNET_OPTION_SECURITY_FLAGS:
2556          FIXME("Option INTERNET_OPTION_SECURITY_FLAGS; STUB\n");
2557          break;
2558     case INTERNET_OPTION_DISABLE_AUTODIAL:
2559          FIXME("Option INTERNET_OPTION_DISABLE_AUTODIAL; STUB\n");
2560          break;
2561     case INTERNET_OPTION_HTTP_DECODING:
2562         FIXME("INTERNET_OPTION_HTTP_DECODING; STUB\n");
2563         SetLastError(ERROR_INTERNET_INVALID_OPTION);
2564         ret = FALSE;
2565         break;
2566     case INTERNET_OPTION_COOKIES_3RD_PARTY:
2567         FIXME("INTERNET_OPTION_COOKIES_3RD_PARTY; STUB\n");
2568         SetLastError(ERROR_INTERNET_INVALID_OPTION);
2569         ret = FALSE;
2570         break;
2571     case INTERNET_OPTION_SEND_UTF8_SERVERNAME_TO_PROXY:
2572         FIXME("INTERNET_OPTION_SEND_UTF8_SERVERNAME_TO_PROXY; STUB\n");
2573         SetLastError(ERROR_INTERNET_INVALID_OPTION);
2574         ret = FALSE;
2575         break;
2576     case INTERNET_OPTION_CODEPAGE_PATH:
2577         FIXME("INTERNET_OPTION_CODEPAGE_PATH; STUB\n");
2578         SetLastError(ERROR_INTERNET_INVALID_OPTION);
2579         ret = FALSE;
2580         break;
2581     case INTERNET_OPTION_CODEPAGE_EXTRA:
2582         FIXME("INTERNET_OPTION_CODEPAGE_EXTRA; STUB\n");
2583         SetLastError(ERROR_INTERNET_INVALID_OPTION);
2584         ret = FALSE;
2585         break;
2586     case INTERNET_OPTION_IDN:
2587         FIXME("INTERNET_OPTION_IDN; STUB\n");
2588         SetLastError(ERROR_INTERNET_INVALID_OPTION);
2589         ret = FALSE;
2590         break;
2591     case INTERNET_OPTION_POLICY:
2592         SetLastError(ERROR_INVALID_PARAMETER);
2593         ret = FALSE;
2594         break;
2595     case INTERNET_OPTION_PER_CONNECTION_OPTION: {
2596         INTERNET_PER_CONN_OPTION_LISTW *con = lpBuffer;
2597         LONG res;
2598         int i;
2599         proxyinfo_t pi;
2600
2601         INTERNET_LoadProxySettings(&pi);
2602
2603         for (i = 0; i < con->dwOptionCount; i++) {
2604             INTERNET_PER_CONN_OPTIONW *option = con->pOptions + i;
2605
2606             switch (option->dwOption) {
2607             case INTERNET_PER_CONN_PROXY_SERVER:
2608                 HeapFree(GetProcessHeap(), 0, pi.lpszProxyServer);
2609                 pi.lpszProxyServer = heap_strdupW(option->Value.pszValue);
2610                 break;
2611
2612             case INTERNET_PER_CONN_FLAGS:
2613                 if(option->Value.dwValue & PROXY_TYPE_PROXY)
2614                     pi.dwProxyEnabled = 1;
2615                 else
2616                 {
2617                     if(option->Value.dwValue != PROXY_TYPE_DIRECT)
2618                         FIXME("Unhandled flags: 0x%x\n", option->Value.dwValue);
2619                     pi.dwProxyEnabled = 0;
2620                 }
2621                 break;
2622
2623             case INTERNET_PER_CONN_AUTOCONFIG_URL:
2624             case INTERNET_PER_CONN_AUTODISCOVERY_FLAGS:
2625             case INTERNET_PER_CONN_AUTOCONFIG_SECONDARY_URL:
2626             case INTERNET_PER_CONN_AUTOCONFIG_RELOAD_DELAY_MINS:
2627             case INTERNET_PER_CONN_AUTOCONFIG_LAST_DETECT_TIME:
2628             case INTERNET_PER_CONN_AUTOCONFIG_LAST_DETECT_URL:
2629             case INTERNET_PER_CONN_PROXY_BYPASS:
2630                 FIXME("Unhandled dwOption %d\n", option->dwOption);
2631                 break;
2632
2633             default:
2634                 FIXME("Unknown dwOption %d\n", option->dwOption);
2635                 SetLastError(ERROR_INVALID_PARAMETER);
2636                 break;
2637             }
2638         }
2639
2640         if ((res = INTERNET_SaveProxySettings(&pi)))
2641             SetLastError(res);
2642
2643         FreeProxyInfo(&pi);
2644
2645         ret = (res == ERROR_SUCCESS);
2646         break;
2647         }
2648     default:
2649         FIXME("Option %d STUB\n",dwOption);
2650         SetLastError(ERROR_INTERNET_INVALID_OPTION);
2651         ret = FALSE;
2652         break;
2653     }
2654
2655     if(lpwhh)
2656         WININET_Release( lpwhh );
2657
2658     return ret;
2659 }
2660
2661
2662 /***********************************************************************
2663  *           InternetSetOptionA (WININET.@)
2664  *
2665  * Sets an options on the specified handle.
2666  *
2667  * RETURNS
2668  *    TRUE  on success
2669  *    FALSE on failure
2670  *
2671  */
2672 BOOL WINAPI InternetSetOptionA(HINTERNET hInternet, DWORD dwOption,
2673                            LPVOID lpBuffer, DWORD dwBufferLength)
2674 {
2675     LPVOID wbuffer;
2676     DWORD wlen;
2677     BOOL r;
2678
2679     switch( dwOption )
2680     {
2681     case INTERNET_OPTION_CALLBACK:
2682         {
2683         object_header_t *lpwh;
2684
2685         if (!(lpwh = WININET_GetObject(hInternet)))
2686         {
2687             INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
2688             return FALSE;
2689         }
2690         WININET_Release(lpwh);
2691         INTERNET_SetLastError(ERROR_INTERNET_OPTION_NOT_SETTABLE);
2692         return FALSE;
2693         }
2694     case INTERNET_OPTION_PROXY:
2695         {
2696         LPINTERNET_PROXY_INFOA pi = (LPINTERNET_PROXY_INFOA) lpBuffer;
2697         LPINTERNET_PROXY_INFOW piw;
2698         DWORD proxlen, prbylen;
2699         LPWSTR prox, prby;
2700
2701         proxlen = MultiByteToWideChar( CP_ACP, 0, pi->lpszProxy, -1, NULL, 0);
2702         prbylen= MultiByteToWideChar( CP_ACP, 0, pi->lpszProxyBypass, -1, NULL, 0);
2703         wlen = sizeof(*piw) + proxlen + prbylen;
2704         wbuffer = HeapAlloc( GetProcessHeap(), 0, wlen*sizeof(WCHAR) );
2705         piw = (LPINTERNET_PROXY_INFOW) wbuffer;
2706         piw->dwAccessType = pi->dwAccessType;
2707         prox = (LPWSTR) &piw[1];
2708         prby = &prox[proxlen+1];
2709         MultiByteToWideChar( CP_ACP, 0, pi->lpszProxy, -1, prox, proxlen);
2710         MultiByteToWideChar( CP_ACP, 0, pi->lpszProxyBypass, -1, prby, prbylen);
2711         piw->lpszProxy = prox;
2712         piw->lpszProxyBypass = prby;
2713         }
2714         break;
2715     case INTERNET_OPTION_USER_AGENT:
2716     case INTERNET_OPTION_USERNAME:
2717     case INTERNET_OPTION_PASSWORD:
2718         wlen = MultiByteToWideChar( CP_ACP, 0, lpBuffer, dwBufferLength,
2719                                    NULL, 0 );
2720         wbuffer = HeapAlloc( GetProcessHeap(), 0, wlen*sizeof(WCHAR) );
2721         MultiByteToWideChar( CP_ACP, 0, lpBuffer, dwBufferLength,
2722                                    wbuffer, wlen );
2723         break;
2724     case INTERNET_OPTION_PER_CONNECTION_OPTION: {
2725         int i;
2726         INTERNET_PER_CONN_OPTION_LISTW *listW;
2727         INTERNET_PER_CONN_OPTION_LISTA *listA = lpBuffer;
2728         wlen = sizeof(INTERNET_PER_CONN_OPTION_LISTW);
2729         wbuffer = HeapAlloc( GetProcessHeap(), 0, wlen );
2730         listW = wbuffer;
2731
2732         listW->dwSize = sizeof(INTERNET_PER_CONN_OPTION_LISTW);
2733         if (listA->pszConnection)
2734         {
2735             wlen = MultiByteToWideChar( CP_ACP, 0, listA->pszConnection, -1, NULL, 0 );
2736             listW->pszConnection = HeapAlloc( GetProcessHeap(), 0, wlen*sizeof(WCHAR) );
2737             MultiByteToWideChar( CP_ACP, 0, listA->pszConnection, -1, listW->pszConnection, wlen );
2738         }
2739         else
2740             listW->pszConnection = NULL;
2741         listW->dwOptionCount = listA->dwOptionCount;
2742         listW->dwOptionError = listA->dwOptionError;
2743         listW->pOptions = HeapAlloc( GetProcessHeap(), 0, sizeof(INTERNET_PER_CONN_OPTIONW) * listA->dwOptionCount );
2744
2745         for (i = 0; i < listA->dwOptionCount; ++i) {
2746             INTERNET_PER_CONN_OPTIONA *optA = listA->pOptions + i;
2747             INTERNET_PER_CONN_OPTIONW *optW = listW->pOptions + i;
2748
2749             optW->dwOption = optA->dwOption;
2750
2751             switch (optA->dwOption) {
2752             case INTERNET_PER_CONN_AUTOCONFIG_URL:
2753             case INTERNET_PER_CONN_PROXY_BYPASS:
2754             case INTERNET_PER_CONN_PROXY_SERVER:
2755             case INTERNET_PER_CONN_AUTOCONFIG_SECONDARY_URL:
2756             case INTERNET_PER_CONN_AUTOCONFIG_LAST_DETECT_URL:
2757                 if (optA->Value.pszValue)
2758                 {
2759                     wlen = MultiByteToWideChar( CP_ACP, 0, optA->Value.pszValue, -1, NULL, 0 );
2760                     optW->Value.pszValue = HeapAlloc( GetProcessHeap(), 0, wlen*sizeof(WCHAR) );
2761                     MultiByteToWideChar( CP_ACP, 0, optA->Value.pszValue, -1, optW->Value.pszValue, wlen );
2762                 }
2763                 else
2764                     optW->Value.pszValue = NULL;
2765                 break;
2766             case INTERNET_PER_CONN_AUTODISCOVERY_FLAGS:
2767             case INTERNET_PER_CONN_FLAGS:
2768             case INTERNET_PER_CONN_AUTOCONFIG_RELOAD_DELAY_MINS:
2769                 optW->Value.dwValue = optA->Value.dwValue;
2770                 break;
2771             case INTERNET_PER_CONN_AUTOCONFIG_LAST_DETECT_TIME:
2772                 optW->Value.ftValue = optA->Value.ftValue;
2773             default:
2774                 WARN("Unknown PER_CONN dwOption: %d, guessing at conversion to Wide\n", optA->dwOption);
2775                 optW->Value.dwValue = optA->Value.dwValue;
2776                 break;
2777             }
2778         }
2779         }
2780         break;
2781     default:
2782         wbuffer = lpBuffer;
2783         wlen = dwBufferLength;
2784     }
2785
2786     r = InternetSetOptionW(hInternet,dwOption, wbuffer, wlen);
2787
2788     if( lpBuffer != wbuffer )
2789     {
2790         if (dwOption == INTERNET_OPTION_PER_CONNECTION_OPTION)
2791         {
2792             INTERNET_PER_CONN_OPTION_LISTW *list = wbuffer;
2793             int i;
2794             for (i = 0; i < list->dwOptionCount; ++i) {
2795                 INTERNET_PER_CONN_OPTIONW *opt = list->pOptions + i;
2796                 switch (opt->dwOption) {
2797                 case INTERNET_PER_CONN_AUTOCONFIG_URL:
2798                 case INTERNET_PER_CONN_PROXY_BYPASS:
2799                 case INTERNET_PER_CONN_PROXY_SERVER:
2800                 case INTERNET_PER_CONN_AUTOCONFIG_SECONDARY_URL:
2801                 case INTERNET_PER_CONN_AUTOCONFIG_LAST_DETECT_URL:
2802                     HeapFree( GetProcessHeap(), 0, opt->Value.pszValue );
2803                     break;
2804                 default:
2805                     break;
2806                 }
2807             }
2808             HeapFree( GetProcessHeap(), 0, list->pOptions );
2809         }
2810         HeapFree( GetProcessHeap(), 0, wbuffer );
2811     }
2812
2813     return r;
2814 }
2815
2816
2817 /***********************************************************************
2818  *           InternetSetOptionExA (WININET.@)
2819  */
2820 BOOL WINAPI InternetSetOptionExA(HINTERNET hInternet, DWORD dwOption,
2821                            LPVOID lpBuffer, DWORD dwBufferLength, DWORD dwFlags)
2822 {
2823     FIXME("Flags %08x ignored\n", dwFlags);
2824     return InternetSetOptionA( hInternet, dwOption, lpBuffer, dwBufferLength );
2825 }
2826
2827 /***********************************************************************
2828  *           InternetSetOptionExW (WININET.@)
2829  */
2830 BOOL WINAPI InternetSetOptionExW(HINTERNET hInternet, DWORD dwOption,
2831                            LPVOID lpBuffer, DWORD dwBufferLength, DWORD dwFlags)
2832 {
2833     FIXME("Flags %08x ignored\n", dwFlags);
2834     if( dwFlags & ~ISO_VALID_FLAGS )
2835     {
2836         SetLastError( ERROR_INVALID_PARAMETER );
2837         return FALSE;
2838     }
2839     return InternetSetOptionW( hInternet, dwOption, lpBuffer, dwBufferLength );
2840 }
2841
2842 static const WCHAR WININET_wkday[7][4] =
2843     { { 'S','u','n', 0 }, { 'M','o','n', 0 }, { 'T','u','e', 0 }, { 'W','e','d', 0 },
2844       { 'T','h','u', 0 }, { 'F','r','i', 0 }, { 'S','a','t', 0 } };
2845 static const WCHAR WININET_month[12][4] =
2846     { { 'J','a','n', 0 }, { 'F','e','b', 0 }, { 'M','a','r', 0 }, { 'A','p','r', 0 },
2847       { 'M','a','y', 0 }, { 'J','u','n', 0 }, { 'J','u','l', 0 }, { 'A','u','g', 0 },
2848       { 'S','e','p', 0 }, { 'O','c','t', 0 }, { 'N','o','v', 0 }, { 'D','e','c', 0 } };
2849
2850 /***********************************************************************
2851  *           InternetTimeFromSystemTimeA (WININET.@)
2852  */
2853 BOOL WINAPI InternetTimeFromSystemTimeA( const SYSTEMTIME* time, DWORD format, LPSTR string, DWORD size )
2854 {
2855     BOOL ret;
2856     WCHAR stringW[INTERNET_RFC1123_BUFSIZE];
2857
2858     TRACE( "%p 0x%08x %p 0x%08x\n", time, format, string, size );
2859
2860     if (!time || !string || format != INTERNET_RFC1123_FORMAT)
2861     {
2862         SetLastError(ERROR_INVALID_PARAMETER);
2863         return FALSE;
2864     }
2865
2866     if (size < INTERNET_RFC1123_BUFSIZE * sizeof(*string))
2867     {
2868         SetLastError(ERROR_INSUFFICIENT_BUFFER);
2869         return FALSE;
2870     }
2871
2872     ret = InternetTimeFromSystemTimeW( time, format, stringW, sizeof(stringW) );
2873     if (ret) WideCharToMultiByte( CP_ACP, 0, stringW, -1, string, size, NULL, NULL );
2874
2875     return ret;
2876 }
2877
2878 /***********************************************************************
2879  *           InternetTimeFromSystemTimeW (WININET.@)
2880  */
2881 BOOL WINAPI InternetTimeFromSystemTimeW( const SYSTEMTIME* time, DWORD format, LPWSTR string, DWORD size )
2882 {
2883     static const WCHAR date[] =
2884         { '%','s',',',' ','%','0','2','d',' ','%','s',' ','%','4','d',' ','%','0',
2885           '2','d',':','%','0','2','d',':','%','0','2','d',' ','G','M','T', 0 };
2886
2887     TRACE( "%p 0x%08x %p 0x%08x\n", time, format, string, size );
2888
2889     if (!time || !string || format != INTERNET_RFC1123_FORMAT)
2890     {
2891         SetLastError(ERROR_INVALID_PARAMETER);
2892         return FALSE;
2893     }
2894
2895     if (size < INTERNET_RFC1123_BUFSIZE * sizeof(*string))
2896     {
2897         SetLastError(ERROR_INSUFFICIENT_BUFFER);
2898         return FALSE;
2899     }
2900
2901     sprintfW( string, date,
2902               WININET_wkday[time->wDayOfWeek],
2903               time->wDay,
2904               WININET_month[time->wMonth - 1],
2905               time->wYear,
2906               time->wHour,
2907               time->wMinute,
2908               time->wSecond );
2909
2910     return TRUE;
2911 }
2912
2913 /***********************************************************************
2914  *           InternetTimeToSystemTimeA (WININET.@)
2915  */
2916 BOOL WINAPI InternetTimeToSystemTimeA( LPCSTR string, SYSTEMTIME* time, DWORD reserved )
2917 {
2918     BOOL ret = FALSE;
2919     WCHAR *stringW;
2920
2921     TRACE( "%s %p 0x%08x\n", debugstr_a(string), time, reserved );
2922
2923     stringW = heap_strdupAtoW(string);
2924     if (stringW)
2925     {
2926         ret = InternetTimeToSystemTimeW( stringW, time, reserved );
2927         HeapFree( GetProcessHeap(), 0, stringW );
2928     }
2929     return ret;
2930 }
2931
2932 /***********************************************************************
2933  *           InternetTimeToSystemTimeW (WININET.@)
2934  */
2935 BOOL WINAPI InternetTimeToSystemTimeW( LPCWSTR string, SYSTEMTIME* time, DWORD reserved )
2936 {
2937     unsigned int i;
2938     const WCHAR *s = string;
2939     WCHAR       *end;
2940
2941     TRACE( "%s %p 0x%08x\n", debugstr_w(string), time, reserved );
2942
2943     if (!string || !time) return FALSE;
2944
2945     /* Windows does this too */
2946     GetSystemTime( time );
2947
2948     /*  Convert an RFC1123 time such as 'Fri, 07 Jan 2005 12:06:35 GMT' into
2949      *  a SYSTEMTIME structure.
2950      */
2951
2952     while (*s && !isalphaW( *s )) s++;
2953     if (s[0] == '\0' || s[1] == '\0' || s[2] == '\0') return TRUE;
2954     time->wDayOfWeek = 7;
2955
2956     for (i = 0; i < 7; i++)
2957     {
2958         if (toupperW( WININET_wkday[i][0] ) == toupperW( s[0] ) &&
2959             toupperW( WININET_wkday[i][1] ) == toupperW( s[1] ) &&
2960             toupperW( WININET_wkday[i][2] ) == toupperW( s[2] ) )
2961         {
2962             time->wDayOfWeek = i;
2963             break;
2964         }
2965     }
2966
2967     if (time->wDayOfWeek > 6) return TRUE;
2968     while (*s && !isdigitW( *s )) s++;
2969     time->wDay = strtolW( s, &end, 10 );
2970     s = end;
2971
2972     while (*s && !isalphaW( *s )) s++;
2973     if (s[0] == '\0' || s[1] == '\0' || s[2] == '\0') return TRUE;
2974     time->wMonth = 0;
2975
2976     for (i = 0; i < 12; i++)
2977     {
2978         if (toupperW( WININET_month[i][0]) == toupperW( s[0] ) &&
2979             toupperW( WININET_month[i][1]) == toupperW( s[1] ) &&
2980             toupperW( WININET_month[i][2]) == toupperW( s[2] ) )
2981         {
2982             time->wMonth = i + 1;
2983             break;
2984         }
2985     }
2986     if (time->wMonth == 0) return TRUE;
2987
2988     while (*s && !isdigitW( *s )) s++;
2989     if (*s == '\0') return TRUE;
2990     time->wYear = strtolW( s, &end, 10 );
2991     s = end;
2992
2993     while (*s && !isdigitW( *s )) s++;
2994     if (*s == '\0') return TRUE;
2995     time->wHour = strtolW( s, &end, 10 );
2996     s = end;
2997
2998     while (*s && !isdigitW( *s )) s++;
2999     if (*s == '\0') return TRUE;
3000     time->wMinute = strtolW( s, &end, 10 );
3001     s = end;
3002
3003     while (*s && !isdigitW( *s )) s++;
3004     if (*s == '\0') return TRUE;
3005     time->wSecond = strtolW( s, &end, 10 );
3006     s = end;
3007
3008     time->wMilliseconds = 0;
3009     return TRUE;
3010 }
3011
3012 /***********************************************************************
3013  *      InternetCheckConnectionW (WININET.@)
3014  *
3015  * Pings a requested host to check internet connection
3016  *
3017  * RETURNS
3018  *   TRUE on success and FALSE on failure. If a failure then
3019  *   ERROR_NOT_CONNECTED is placed into GetLastError
3020  *
3021  */
3022 BOOL WINAPI InternetCheckConnectionW( LPCWSTR lpszUrl, DWORD dwFlags, DWORD dwReserved )
3023 {
3024 /*
3025  * this is a kludge which runs the resident ping program and reads the output.
3026  *
3027  * Anyone have a better idea?
3028  */
3029
3030   BOOL   rc = FALSE;
3031   static const CHAR ping[] = "ping -c 1 ";
3032   static const CHAR redirect[] = " >/dev/null 2>/dev/null";
3033   CHAR *command = NULL;
3034   WCHAR hostW[1024];
3035   DWORD len;
3036   INTERNET_PORT port;
3037   int status = -1;
3038
3039   FIXME("\n");
3040
3041   /*
3042    * Crack or set the Address
3043    */
3044   if (lpszUrl == NULL)
3045   {
3046      /*
3047       * According to the doc we are supposed to use the ip for the next
3048       * server in the WnInet internal server database. I have
3049       * no idea what that is or how to get it.
3050       *
3051       * So someone needs to implement this.
3052       */
3053      FIXME("Unimplemented with URL of NULL\n");
3054      return TRUE;
3055   }
3056   else
3057   {
3058      URL_COMPONENTSW components;
3059
3060      ZeroMemory(&components,sizeof(URL_COMPONENTSW));
3061      components.lpszHostName = (LPWSTR)hostW;
3062      components.dwHostNameLength = 1024;
3063
3064      if (!InternetCrackUrlW(lpszUrl,0,0,&components))
3065        goto End;
3066
3067      TRACE("host name : %s\n",debugstr_w(components.lpszHostName));
3068      port = components.nPort;
3069      TRACE("port: %d\n", port);
3070   }
3071
3072   if (dwFlags & FLAG_ICC_FORCE_CONNECTION)
3073   {
3074       struct sockaddr_storage saddr;
3075       socklen_t sa_len = sizeof(saddr);
3076       int fd;
3077
3078       if (!GetAddress(hostW, port, (struct sockaddr *)&saddr, &sa_len))
3079           goto End;
3080       fd = socket(saddr.ss_family, SOCK_STREAM, 0);
3081       if (fd != -1)
3082       {
3083           if (connect(fd, (struct sockaddr *)&saddr, sa_len) == 0)
3084               rc = TRUE;
3085           close(fd);
3086       }
3087   }
3088   else
3089   {
3090       /*
3091        * Build our ping command
3092        */
3093       len = WideCharToMultiByte(CP_UNIXCP, 0, hostW, -1, NULL, 0, NULL, NULL);
3094       command = HeapAlloc( GetProcessHeap(), 0, strlen(ping)+len+strlen(redirect) );
3095       strcpy(command,ping);
3096       WideCharToMultiByte(CP_UNIXCP, 0, hostW, -1, command+strlen(ping), len, NULL, NULL);
3097       strcat(command,redirect);
3098
3099       TRACE("Ping command is : %s\n",command);
3100
3101       status = system(command);
3102
3103       TRACE("Ping returned a code of %i\n",status);
3104
3105       /* Ping return code of 0 indicates success */
3106       if (status == 0)
3107          rc = TRUE;
3108   }
3109
3110 End:
3111
3112   HeapFree( GetProcessHeap(), 0, command );
3113   if (rc == FALSE)
3114     INTERNET_SetLastError(ERROR_NOT_CONNECTED);
3115
3116   return rc;
3117 }
3118
3119
3120 /***********************************************************************
3121  *      InternetCheckConnectionA (WININET.@)
3122  *
3123  * Pings a requested host to check internet connection
3124  *
3125  * RETURNS
3126  *   TRUE on success and FALSE on failure. If a failure then
3127  *   ERROR_NOT_CONNECTED is placed into GetLastError
3128  *
3129  */
3130 BOOL WINAPI InternetCheckConnectionA(LPCSTR lpszUrl, DWORD dwFlags, DWORD dwReserved)
3131 {
3132     WCHAR *url = NULL;
3133     BOOL rc;
3134
3135     if(lpszUrl) {
3136         url = heap_strdupAtoW(lpszUrl);
3137         if(!url)
3138             return FALSE;
3139     }
3140
3141     rc = InternetCheckConnectionW(url, dwFlags, dwReserved);
3142
3143     HeapFree(GetProcessHeap(), 0, url);
3144     return rc;
3145 }
3146
3147
3148 /**********************************************************
3149  *      INTERNET_InternetOpenUrlW (internal)
3150  *
3151  * Opens an URL
3152  *
3153  * RETURNS
3154  *   handle of connection or NULL on failure
3155  */
3156 static HINTERNET INTERNET_InternetOpenUrlW(appinfo_t *hIC, LPCWSTR lpszUrl,
3157     LPCWSTR lpszHeaders, DWORD dwHeadersLength, DWORD dwFlags, DWORD_PTR dwContext)
3158 {
3159     URL_COMPONENTSW urlComponents;
3160     WCHAR protocol[32], hostName[MAXHOSTNAME], userName[1024];
3161     WCHAR password[1024], path[2048], extra[1024];
3162     HINTERNET client = NULL, client1 = NULL;
3163     DWORD res;
3164     
3165     TRACE("(%p, %s, %s, %08x, %08x, %08lx)\n", hIC, debugstr_w(lpszUrl), debugstr_w(lpszHeaders),
3166           dwHeadersLength, dwFlags, dwContext);
3167     
3168     urlComponents.dwStructSize = sizeof(URL_COMPONENTSW);
3169     urlComponents.lpszScheme = protocol;
3170     urlComponents.dwSchemeLength = 32;
3171     urlComponents.lpszHostName = hostName;
3172     urlComponents.dwHostNameLength = MAXHOSTNAME;
3173     urlComponents.lpszUserName = userName;
3174     urlComponents.dwUserNameLength = 1024;
3175     urlComponents.lpszPassword = password;
3176     urlComponents.dwPasswordLength = 1024;
3177     urlComponents.lpszUrlPath = path;
3178     urlComponents.dwUrlPathLength = 2048;
3179     urlComponents.lpszExtraInfo = extra;
3180     urlComponents.dwExtraInfoLength = 1024;
3181     if(!InternetCrackUrlW(lpszUrl, strlenW(lpszUrl), 0, &urlComponents))
3182         return NULL;
3183     switch(urlComponents.nScheme) {
3184     case INTERNET_SCHEME_FTP:
3185         if(urlComponents.nPort == 0)
3186             urlComponents.nPort = INTERNET_DEFAULT_FTP_PORT;
3187         client = FTP_Connect(hIC, hostName, urlComponents.nPort,
3188                              userName, password, dwFlags, dwContext, INET_OPENURL);
3189         if(client == NULL)
3190             break;
3191         client1 = FtpOpenFileW(client, path, GENERIC_READ, dwFlags, dwContext);
3192         if(client1 == NULL) {
3193             InternetCloseHandle(client);
3194             break;
3195         }
3196         break;
3197         
3198     case INTERNET_SCHEME_HTTP:
3199     case INTERNET_SCHEME_HTTPS: {
3200         static const WCHAR szStars[] = { '*','/','*', 0 };
3201         LPCWSTR accept[2] = { szStars, NULL };
3202         if(urlComponents.nPort == 0) {
3203             if(urlComponents.nScheme == INTERNET_SCHEME_HTTP)
3204                 urlComponents.nPort = INTERNET_DEFAULT_HTTP_PORT;
3205             else
3206                 urlComponents.nPort = INTERNET_DEFAULT_HTTPS_PORT;
3207         }
3208         if (urlComponents.nScheme == INTERNET_SCHEME_HTTPS) dwFlags |= INTERNET_FLAG_SECURE;
3209
3210         /* FIXME: should use pointers, not handles, as handles are not thread-safe */
3211         res = HTTP_Connect(hIC, hostName, urlComponents.nPort,
3212                            userName, password, dwFlags, dwContext, INET_OPENURL, &client);
3213         if(res != ERROR_SUCCESS) {
3214             INTERNET_SetLastError(res);
3215             break;
3216         }
3217
3218         if (urlComponents.dwExtraInfoLength) {
3219                 WCHAR *path_extra;
3220                 DWORD len = urlComponents.dwUrlPathLength + urlComponents.dwExtraInfoLength + 1;
3221
3222                 if (!(path_extra = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR))))
3223                 {
3224                         InternetCloseHandle(client);
3225                         break;
3226                 }
3227                 strcpyW(path_extra, urlComponents.lpszUrlPath);
3228                 strcatW(path_extra, urlComponents.lpszExtraInfo);
3229                 client1 = HttpOpenRequestW(client, NULL, path_extra, NULL, NULL, accept, dwFlags, dwContext);
3230                 HeapFree(GetProcessHeap(), 0, path_extra);
3231         }
3232         else
3233                 client1 = HttpOpenRequestW(client, NULL, path, NULL, NULL, accept, dwFlags, dwContext);
3234
3235         if(client1 == NULL) {
3236             InternetCloseHandle(client);
3237             break;
3238         }
3239         HttpAddRequestHeadersW(client1, lpszHeaders, dwHeadersLength, HTTP_ADDREQ_FLAG_ADD);
3240         if (!HttpSendRequestW(client1, NULL, 0, NULL, 0) &&
3241             GetLastError() != ERROR_IO_PENDING) {
3242             InternetCloseHandle(client1);
3243             client1 = NULL;
3244             break;
3245         }
3246     }
3247     case INTERNET_SCHEME_GOPHER:
3248         /* gopher doesn't seem to be implemented in wine, but it's supposed
3249          * to be supported by InternetOpenUrlA. */
3250     default:
3251         SetLastError(ERROR_INTERNET_UNRECOGNIZED_SCHEME);
3252         break;
3253     }
3254
3255     TRACE(" %p <--\n", client1);
3256     
3257     return client1;
3258 }
3259
3260 /**********************************************************
3261  *      InternetOpenUrlW (WININET.@)
3262  *
3263  * Opens an URL
3264  *
3265  * RETURNS
3266  *   handle of connection or NULL on failure
3267  */
3268 static void AsyncInternetOpenUrlProc(WORKREQUEST *workRequest)
3269 {
3270     struct WORKREQ_INTERNETOPENURLW const *req = &workRequest->u.InternetOpenUrlW;
3271     appinfo_t *hIC = (appinfo_t*) workRequest->hdr;
3272
3273     TRACE("%p\n", hIC);
3274
3275     INTERNET_InternetOpenUrlW(hIC, req->lpszUrl,
3276                               req->lpszHeaders, req->dwHeadersLength, req->dwFlags, req->dwContext);
3277     HeapFree(GetProcessHeap(), 0, req->lpszUrl);
3278     HeapFree(GetProcessHeap(), 0, req->lpszHeaders);
3279 }
3280
3281 HINTERNET WINAPI InternetOpenUrlW(HINTERNET hInternet, LPCWSTR lpszUrl,
3282     LPCWSTR lpszHeaders, DWORD dwHeadersLength, DWORD dwFlags, DWORD_PTR dwContext)
3283 {
3284     HINTERNET ret = NULL;
3285     appinfo_t *hIC = NULL;
3286
3287     if (TRACE_ON(wininet)) {
3288         TRACE("(%p, %s, %s, %08x, %08x, %08lx)\n", hInternet, debugstr_w(lpszUrl), debugstr_w(lpszHeaders),
3289               dwHeadersLength, dwFlags, dwContext);
3290         TRACE("  flags :");
3291         dump_INTERNET_FLAGS(dwFlags);
3292     }
3293
3294     if (!lpszUrl)
3295     {
3296         SetLastError(ERROR_INVALID_PARAMETER);
3297         goto lend;
3298     }
3299
3300     hIC = (appinfo_t*)WININET_GetObject( hInternet );
3301     if (NULL == hIC ||  hIC->hdr.htype != WH_HINIT) {
3302         SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
3303         goto lend;
3304     }
3305     
3306     if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC) {
3307         WORKREQUEST workRequest;
3308         struct WORKREQ_INTERNETOPENURLW *req;
3309
3310         workRequest.asyncproc = AsyncInternetOpenUrlProc;
3311         workRequest.hdr = WININET_AddRef( &hIC->hdr );
3312         req = &workRequest.u.InternetOpenUrlW;
3313         req->lpszUrl = heap_strdupW(lpszUrl);
3314         req->lpszHeaders = heap_strdupW(lpszHeaders);
3315         req->dwHeadersLength = dwHeadersLength;
3316         req->dwFlags = dwFlags;
3317         req->dwContext = dwContext;
3318         
3319         INTERNET_AsyncCall(&workRequest);
3320         /*
3321          * This is from windows.
3322          */
3323         SetLastError(ERROR_IO_PENDING);
3324     } else {
3325         ret = INTERNET_InternetOpenUrlW(hIC, lpszUrl, lpszHeaders, dwHeadersLength, dwFlags, dwContext);
3326     }
3327     
3328   lend:
3329     if( hIC )
3330         WININET_Release( &hIC->hdr );
3331     TRACE(" %p <--\n", ret);
3332     
3333     return ret;
3334 }
3335
3336 /**********************************************************
3337  *      InternetOpenUrlA (WININET.@)
3338  *
3339  * Opens an URL
3340  *
3341  * RETURNS
3342  *   handle of connection or NULL on failure
3343  */
3344 HINTERNET WINAPI InternetOpenUrlA(HINTERNET hInternet, LPCSTR lpszUrl,
3345     LPCSTR lpszHeaders, DWORD dwHeadersLength, DWORD dwFlags, DWORD_PTR dwContext)
3346 {
3347     HINTERNET rc = NULL;
3348     DWORD lenHeaders = 0;
3349     LPWSTR szUrl = NULL;
3350     LPWSTR szHeaders = NULL;
3351
3352     TRACE("\n");
3353
3354     if(lpszUrl) {
3355         szUrl = heap_strdupAtoW(lpszUrl);
3356         if(!szUrl)
3357             return NULL;
3358     }
3359
3360     if(lpszHeaders) {
3361         lenHeaders = MultiByteToWideChar(CP_ACP, 0, lpszHeaders, dwHeadersLength, NULL, 0 );
3362         szHeaders = HeapAlloc(GetProcessHeap(), 0, lenHeaders*sizeof(WCHAR));
3363         if(!szHeaders) {
3364             HeapFree(GetProcessHeap(), 0, szUrl);
3365             return NULL;
3366         }
3367         MultiByteToWideChar(CP_ACP, 0, lpszHeaders, dwHeadersLength, szHeaders, lenHeaders);
3368     }
3369     
3370     rc = InternetOpenUrlW(hInternet, szUrl, szHeaders,
3371         lenHeaders, dwFlags, dwContext);
3372
3373     HeapFree(GetProcessHeap(), 0, szUrl);
3374     HeapFree(GetProcessHeap(), 0, szHeaders);
3375
3376     return rc;
3377 }
3378
3379
3380 static LPWITHREADERROR INTERNET_AllocThreadError(void)
3381 {
3382     LPWITHREADERROR lpwite = HeapAlloc(GetProcessHeap(), 0, sizeof(*lpwite));
3383
3384     if (lpwite)
3385     {
3386         lpwite->dwError = 0;
3387         lpwite->response[0] = '\0';
3388     }
3389
3390     if (!TlsSetValue(g_dwTlsErrIndex, lpwite))
3391     {
3392         HeapFree(GetProcessHeap(), 0, lpwite);
3393         return NULL;
3394     }
3395
3396     return lpwite;
3397 }
3398
3399
3400 /***********************************************************************
3401  *           INTERNET_SetLastError (internal)
3402  *
3403  * Set last thread specific error
3404  *
3405  * RETURNS
3406  *
3407  */
3408 void INTERNET_SetLastError(DWORD dwError)
3409 {
3410     LPWITHREADERROR lpwite = TlsGetValue(g_dwTlsErrIndex);
3411
3412     if (!lpwite)
3413         lpwite = INTERNET_AllocThreadError();
3414
3415     SetLastError(dwError);
3416     if(lpwite)
3417         lpwite->dwError = dwError;
3418 }
3419
3420
3421 /***********************************************************************
3422  *           INTERNET_GetLastError (internal)
3423  *
3424  * Get last thread specific error
3425  *
3426  * RETURNS
3427  *
3428  */
3429 DWORD INTERNET_GetLastError(void)
3430 {
3431     LPWITHREADERROR lpwite = TlsGetValue(g_dwTlsErrIndex);
3432     if (!lpwite) return 0;
3433     /* TlsGetValue clears last error, so set it again here */
3434     SetLastError(lpwite->dwError);
3435     return lpwite->dwError;
3436 }
3437
3438
3439 /***********************************************************************
3440  *           INTERNET_WorkerThreadFunc (internal)
3441  *
3442  * Worker thread execution function
3443  *
3444  * RETURNS
3445  *
3446  */
3447 static DWORD CALLBACK INTERNET_WorkerThreadFunc(LPVOID lpvParam)
3448 {
3449     LPWORKREQUEST lpRequest = lpvParam;
3450     WORKREQUEST workRequest;
3451
3452     TRACE("\n");
3453
3454     workRequest = *lpRequest;
3455     HeapFree(GetProcessHeap(), 0, lpRequest);
3456
3457     workRequest.asyncproc(&workRequest);
3458     WININET_Release( workRequest.hdr );
3459
3460     if (g_dwTlsErrIndex != TLS_OUT_OF_INDEXES)
3461     {
3462         HeapFree(GetProcessHeap(), 0, TlsGetValue(g_dwTlsErrIndex));
3463         TlsSetValue(g_dwTlsErrIndex, NULL);
3464     }
3465     return TRUE;
3466 }
3467
3468
3469 /***********************************************************************
3470  *           INTERNET_AsyncCall (internal)
3471  *
3472  * Retrieves work request from queue
3473  *
3474  * RETURNS
3475  *
3476  */
3477 DWORD INTERNET_AsyncCall(LPWORKREQUEST lpWorkRequest)
3478 {
3479     BOOL bSuccess;
3480     LPWORKREQUEST lpNewRequest;
3481
3482     TRACE("\n");
3483
3484     lpNewRequest = HeapAlloc(GetProcessHeap(), 0, sizeof(WORKREQUEST));
3485     if (!lpNewRequest)
3486         return ERROR_OUTOFMEMORY;
3487
3488     *lpNewRequest = *lpWorkRequest;
3489
3490     bSuccess = QueueUserWorkItem(INTERNET_WorkerThreadFunc, lpNewRequest, WT_EXECUTELONGFUNCTION);
3491     if (!bSuccess)
3492     {
3493         HeapFree(GetProcessHeap(), 0, lpNewRequest);
3494         return ERROR_INTERNET_ASYNC_THREAD_FAILED;
3495     }
3496
3497     return ERROR_SUCCESS;
3498 }
3499
3500
3501 /***********************************************************************
3502  *          INTERNET_GetResponseBuffer  (internal)
3503  *
3504  * RETURNS
3505  *
3506  */
3507 LPSTR INTERNET_GetResponseBuffer(void)
3508 {
3509     LPWITHREADERROR lpwite = TlsGetValue(g_dwTlsErrIndex);
3510     if (!lpwite)
3511         lpwite = INTERNET_AllocThreadError();
3512     TRACE("\n");
3513     return lpwite->response;
3514 }
3515
3516 /***********************************************************************
3517  *           INTERNET_GetNextLine  (internal)
3518  *
3519  * Parse next line in directory string listing
3520  *
3521  * RETURNS
3522  *   Pointer to beginning of next line
3523  *   NULL on failure
3524  *
3525  */
3526
3527 LPSTR INTERNET_GetNextLine(INT nSocket, LPDWORD dwLen)
3528 {
3529     struct pollfd pfd;
3530     BOOL bSuccess = FALSE;
3531     INT nRecv = 0;
3532     LPSTR lpszBuffer = INTERNET_GetResponseBuffer();
3533
3534     TRACE("\n");
3535
3536     pfd.fd = nSocket;
3537     pfd.events = POLLIN;
3538
3539     while (nRecv < MAX_REPLY_LEN)
3540     {
3541         if (poll(&pfd,1, RESPONSE_TIMEOUT * 1000) > 0)
3542         {
3543             if (recv(nSocket, &lpszBuffer[nRecv], 1, 0) <= 0)
3544             {
3545                 INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS);
3546                 goto lend;
3547             }
3548
3549             if (lpszBuffer[nRecv] == '\n')
3550             {
3551                 bSuccess = TRUE;
3552                 break;
3553             }
3554             if (lpszBuffer[nRecv] != '\r')
3555                 nRecv++;
3556         }
3557         else
3558         {
3559             INTERNET_SetLastError(ERROR_INTERNET_TIMEOUT);
3560             goto lend;
3561         }
3562     }
3563
3564 lend:
3565     if (bSuccess)
3566     {
3567         lpszBuffer[nRecv] = '\0';
3568         *dwLen = nRecv - 1;
3569         TRACE(":%d %s\n", nRecv, lpszBuffer);
3570         return lpszBuffer;
3571     }
3572     else
3573     {
3574         return NULL;
3575     }
3576 }
3577
3578 /**********************************************************
3579  *      InternetQueryDataAvailable (WININET.@)
3580  *
3581  * Determines how much data is available to be read.
3582  *
3583  * RETURNS
3584  *   TRUE on success, FALSE if an error occurred. If
3585  *   INTERNET_FLAG_ASYNC was specified in InternetOpen, and
3586  *   no data is presently available, FALSE is returned with
3587  *   the last error ERROR_IO_PENDING; a callback with status
3588  *   INTERNET_STATUS_REQUEST_COMPLETE will be sent when more
3589  *   data is available.
3590  */
3591 BOOL WINAPI InternetQueryDataAvailable( HINTERNET hFile,
3592                                 LPDWORD lpdwNumberOfBytesAvailble,
3593                                 DWORD dwFlags, DWORD_PTR dwContext)
3594 {
3595     object_header_t *hdr;
3596     DWORD res;
3597
3598     TRACE("(%p %p %x %lx)\n", hFile, lpdwNumberOfBytesAvailble, dwFlags, dwContext);
3599
3600     hdr = WININET_GetObject( hFile );
3601     if (!hdr) {
3602         SetLastError(ERROR_INVALID_HANDLE);
3603         return FALSE;
3604     }
3605
3606     if(hdr->vtbl->QueryDataAvailable) {
3607         res = hdr->vtbl->QueryDataAvailable(hdr, lpdwNumberOfBytesAvailble, dwFlags, dwContext);
3608     }else {
3609         WARN("wrong handle\n");
3610         res = ERROR_INTERNET_INCORRECT_HANDLE_TYPE;
3611     }
3612
3613     WININET_Release(hdr);
3614
3615     if(res != ERROR_SUCCESS)
3616         SetLastError(res);
3617     return res == ERROR_SUCCESS;
3618 }
3619
3620
3621 /***********************************************************************
3622  *      InternetLockRequestFile (WININET.@)
3623  */
3624 BOOL WINAPI InternetLockRequestFile( HINTERNET hInternet, HANDLE
3625 *lphLockReqHandle)
3626 {
3627     FIXME("STUB\n");
3628     return FALSE;
3629 }
3630
3631 BOOL WINAPI InternetUnlockRequestFile( HANDLE hLockHandle)
3632 {
3633     FIXME("STUB\n");
3634     return FALSE;
3635 }
3636
3637
3638 /***********************************************************************
3639  *      InternetAutodial (WININET.@)
3640  *
3641  * On windows this function is supposed to dial the default internet
3642  * connection. We don't want to have Wine dial out to the internet so
3643  * we return TRUE by default. It might be nice to check if we are connected.
3644  *
3645  * RETURNS
3646  *   TRUE on success
3647  *   FALSE on failure
3648  *
3649  */
3650 BOOL WINAPI InternetAutodial(DWORD dwFlags, HWND hwndParent)
3651 {
3652     FIXME("STUB\n");
3653
3654     /* Tell that we are connected to the internet. */
3655     return TRUE;
3656 }
3657
3658 /***********************************************************************
3659  *      InternetAutodialHangup (WININET.@)
3660  *
3661  * Hangs up a connection made with InternetAutodial
3662  *
3663  * PARAM
3664  *    dwReserved
3665  * RETURNS
3666  *   TRUE on success
3667  *   FALSE on failure
3668  *
3669  */
3670 BOOL WINAPI InternetAutodialHangup(DWORD dwReserved)
3671 {
3672     FIXME("STUB\n");
3673
3674     /* we didn't dial, we don't disconnect */
3675     return TRUE;
3676 }
3677
3678 /***********************************************************************
3679  *      InternetCombineUrlA (WININET.@)
3680  *
3681  * Combine a base URL with a relative URL
3682  *
3683  * RETURNS
3684  *   TRUE on success
3685  *   FALSE on failure
3686  *
3687  */
3688
3689 BOOL WINAPI InternetCombineUrlA(LPCSTR lpszBaseUrl, LPCSTR lpszRelativeUrl,
3690                                 LPSTR lpszBuffer, LPDWORD lpdwBufferLength,
3691                                 DWORD dwFlags)
3692 {
3693     HRESULT hr=S_OK;
3694
3695     TRACE("(%s, %s, %p, %p, 0x%08x)\n", debugstr_a(lpszBaseUrl), debugstr_a(lpszRelativeUrl), lpszBuffer, lpdwBufferLength, dwFlags);
3696
3697     /* Flip this bit to correspond to URL_ESCAPE_UNSAFE */
3698     dwFlags ^= ICU_NO_ENCODE;
3699     hr=UrlCombineA(lpszBaseUrl,lpszRelativeUrl,lpszBuffer,lpdwBufferLength,dwFlags);
3700
3701     return (hr==S_OK);
3702 }
3703
3704 /***********************************************************************
3705  *      InternetCombineUrlW (WININET.@)
3706  *
3707  * Combine a base URL with a relative URL
3708  *
3709  * RETURNS
3710  *   TRUE on success
3711  *   FALSE on failure
3712  *
3713  */
3714
3715 BOOL WINAPI InternetCombineUrlW(LPCWSTR lpszBaseUrl, LPCWSTR lpszRelativeUrl,
3716                                 LPWSTR lpszBuffer, LPDWORD lpdwBufferLength,
3717                                 DWORD dwFlags)
3718 {
3719     HRESULT hr=S_OK;
3720
3721     TRACE("(%s, %s, %p, %p, 0x%08x)\n", debugstr_w(lpszBaseUrl), debugstr_w(lpszRelativeUrl), lpszBuffer, lpdwBufferLength, dwFlags);
3722
3723     /* Flip this bit to correspond to URL_ESCAPE_UNSAFE */
3724     dwFlags ^= ICU_NO_ENCODE;
3725     hr=UrlCombineW(lpszBaseUrl,lpszRelativeUrl,lpszBuffer,lpdwBufferLength,dwFlags);
3726
3727     return (hr==S_OK);
3728 }
3729
3730 /* max port num is 65535 => 5 digits */
3731 #define MAX_WORD_DIGITS 5
3732
3733 #define URL_GET_COMP_LENGTH(url, component) ((url)->dw##component##Length ? \
3734     (url)->dw##component##Length : strlenW((url)->lpsz##component))
3735 #define URL_GET_COMP_LENGTHA(url, component) ((url)->dw##component##Length ? \
3736     (url)->dw##component##Length : strlen((url)->lpsz##component))
3737
3738 static BOOL url_uses_default_port(INTERNET_SCHEME nScheme, INTERNET_PORT nPort)
3739 {
3740     if ((nScheme == INTERNET_SCHEME_HTTP) &&
3741         (nPort == INTERNET_DEFAULT_HTTP_PORT))
3742         return TRUE;
3743     if ((nScheme == INTERNET_SCHEME_HTTPS) &&
3744         (nPort == INTERNET_DEFAULT_HTTPS_PORT))
3745         return TRUE;
3746     if ((nScheme == INTERNET_SCHEME_FTP) &&
3747         (nPort == INTERNET_DEFAULT_FTP_PORT))
3748         return TRUE;
3749     if ((nScheme == INTERNET_SCHEME_GOPHER) &&
3750         (nPort == INTERNET_DEFAULT_GOPHER_PORT))
3751         return TRUE;
3752
3753     if (nPort == INTERNET_INVALID_PORT_NUMBER)
3754         return TRUE;
3755
3756     return FALSE;
3757 }
3758
3759 /* opaque urls do not fit into the standard url hierarchy and don't have
3760  * two following slashes */
3761 static inline BOOL scheme_is_opaque(INTERNET_SCHEME nScheme)
3762 {
3763     return (nScheme != INTERNET_SCHEME_FTP) &&
3764            (nScheme != INTERNET_SCHEME_GOPHER) &&
3765            (nScheme != INTERNET_SCHEME_HTTP) &&
3766            (nScheme != INTERNET_SCHEME_HTTPS) &&
3767            (nScheme != INTERNET_SCHEME_FILE);
3768 }
3769
3770 static LPCWSTR INTERNET_GetSchemeString(INTERNET_SCHEME scheme)
3771 {
3772     int index;
3773     if (scheme < INTERNET_SCHEME_FIRST)
3774         return NULL;
3775     index = scheme - INTERNET_SCHEME_FIRST;
3776     if (index >= sizeof(url_schemes)/sizeof(url_schemes[0]))
3777         return NULL;
3778     return (LPCWSTR)url_schemes[index];
3779 }
3780
3781 /* we can calculate using ansi strings because we're just
3782  * calculating string length, not size
3783  */
3784 static BOOL calc_url_length(LPURL_COMPONENTSW lpUrlComponents,
3785                             LPDWORD lpdwUrlLength)
3786 {
3787     INTERNET_SCHEME nScheme;
3788
3789     *lpdwUrlLength = 0;
3790
3791     if (lpUrlComponents->lpszScheme)
3792     {
3793         DWORD dwLen = URL_GET_COMP_LENGTH(lpUrlComponents, Scheme);
3794         *lpdwUrlLength += dwLen;
3795         nScheme = GetInternetSchemeW(lpUrlComponents->lpszScheme, dwLen);
3796     }
3797     else
3798     {
3799         LPCWSTR scheme;
3800
3801         nScheme = lpUrlComponents->nScheme;
3802
3803         if (nScheme == INTERNET_SCHEME_DEFAULT)
3804             nScheme = INTERNET_SCHEME_HTTP;
3805         scheme = INTERNET_GetSchemeString(nScheme);
3806         *lpdwUrlLength += strlenW(scheme);
3807     }
3808
3809     (*lpdwUrlLength)++; /* ':' */
3810     if (!scheme_is_opaque(nScheme) || lpUrlComponents->lpszHostName)
3811         *lpdwUrlLength += strlen("//");
3812
3813     if (lpUrlComponents->lpszUserName)
3814     {
3815         *lpdwUrlLength += URL_GET_COMP_LENGTH(lpUrlComponents, UserName);
3816         *lpdwUrlLength += strlen("@");
3817     }
3818     else
3819     {
3820         if (lpUrlComponents->lpszPassword)
3821         {
3822             INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
3823             return FALSE;
3824         }
3825     }
3826
3827     if (lpUrlComponents->lpszPassword)
3828     {
3829         *lpdwUrlLength += strlen(":");
3830         *lpdwUrlLength += URL_GET_COMP_LENGTH(lpUrlComponents, Password);
3831     }
3832
3833     if (lpUrlComponents->lpszHostName)
3834     {
3835         *lpdwUrlLength += URL_GET_COMP_LENGTH(lpUrlComponents, HostName);
3836
3837         if (!url_uses_default_port(nScheme, lpUrlComponents->nPort))
3838         {
3839             char szPort[MAX_WORD_DIGITS+1];
3840
3841             sprintf(szPort, "%d", lpUrlComponents->nPort);
3842             *lpdwUrlLength += strlen(szPort);
3843             *lpdwUrlLength += strlen(":");
3844         }
3845
3846         if (lpUrlComponents->lpszUrlPath && *lpUrlComponents->lpszUrlPath != '/')
3847             (*lpdwUrlLength)++; /* '/' */
3848     }
3849
3850     if (lpUrlComponents->lpszUrlPath)
3851         *lpdwUrlLength += URL_GET_COMP_LENGTH(lpUrlComponents, UrlPath);
3852
3853     if (lpUrlComponents->lpszExtraInfo)
3854         *lpdwUrlLength += URL_GET_COMP_LENGTH(lpUrlComponents, ExtraInfo);
3855
3856     return TRUE;
3857 }
3858
3859 static void convert_urlcomp_atow(LPURL_COMPONENTSA lpUrlComponents, LPURL_COMPONENTSW urlCompW)
3860 {
3861     INT len;
3862
3863     ZeroMemory(urlCompW, sizeof(URL_COMPONENTSW));
3864
3865     urlCompW->dwStructSize = sizeof(URL_COMPONENTSW);
3866     urlCompW->dwSchemeLength = lpUrlComponents->dwSchemeLength;
3867     urlCompW->nScheme = lpUrlComponents->nScheme;
3868     urlCompW->dwHostNameLength = lpUrlComponents->dwHostNameLength;
3869     urlCompW->nPort = lpUrlComponents->nPort;
3870     urlCompW->dwUserNameLength = lpUrlComponents->dwUserNameLength;
3871     urlCompW->dwPasswordLength = lpUrlComponents->dwPasswordLength;
3872     urlCompW->dwUrlPathLength = lpUrlComponents->dwUrlPathLength;
3873     urlCompW->dwExtraInfoLength = lpUrlComponents->dwExtraInfoLength;
3874
3875     if (lpUrlComponents->lpszScheme)
3876     {
3877         len = URL_GET_COMP_LENGTHA(lpUrlComponents, Scheme) + 1;
3878         urlCompW->lpszScheme = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
3879         MultiByteToWideChar(CP_ACP, 0, lpUrlComponents->lpszScheme,
3880                             -1, urlCompW->lpszScheme, len);
3881     }
3882
3883     if (lpUrlComponents->lpszHostName)
3884     {
3885         len = URL_GET_COMP_LENGTHA(lpUrlComponents, HostName) + 1;
3886         urlCompW->lpszHostName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
3887         MultiByteToWideChar(CP_ACP, 0, lpUrlComponents->lpszHostName,
3888                             -1, urlCompW->lpszHostName, len);
3889     }
3890
3891     if (lpUrlComponents->lpszUserName)
3892     {
3893         len = URL_GET_COMP_LENGTHA(lpUrlComponents, UserName) + 1;
3894         urlCompW->lpszUserName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
3895         MultiByteToWideChar(CP_ACP, 0, lpUrlComponents->lpszUserName,
3896                             -1, urlCompW->lpszUserName, len);
3897     }
3898
3899     if (lpUrlComponents->lpszPassword)
3900     {
3901         len = URL_GET_COMP_LENGTHA(lpUrlComponents, Password) + 1;
3902         urlCompW->lpszPassword = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
3903         MultiByteToWideChar(CP_ACP, 0, lpUrlComponents->lpszPassword,
3904                             -1, urlCompW->lpszPassword, len);
3905     }
3906
3907     if (lpUrlComponents->lpszUrlPath)
3908     {
3909         len = URL_GET_COMP_LENGTHA(lpUrlComponents, UrlPath) + 1;
3910         urlCompW->lpszUrlPath = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
3911         MultiByteToWideChar(CP_ACP, 0, lpUrlComponents->lpszUrlPath,
3912                             -1, urlCompW->lpszUrlPath, len);
3913     }
3914
3915     if (lpUrlComponents->lpszExtraInfo)
3916     {
3917         len = URL_GET_COMP_LENGTHA(lpUrlComponents, ExtraInfo) + 1;
3918         urlCompW->lpszExtraInfo = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
3919         MultiByteToWideChar(CP_ACP, 0, lpUrlComponents->lpszExtraInfo,
3920                             -1, urlCompW->lpszExtraInfo, len);
3921     }
3922 }
3923
3924 /***********************************************************************
3925  *      InternetCreateUrlA (WININET.@)
3926  *
3927  * See InternetCreateUrlW.
3928  */
3929 BOOL WINAPI InternetCreateUrlA(LPURL_COMPONENTSA lpUrlComponents, DWORD dwFlags,
3930                                LPSTR lpszUrl, LPDWORD lpdwUrlLength)
3931 {
3932     BOOL ret;
3933     LPWSTR urlW = NULL;
3934     URL_COMPONENTSW urlCompW;
3935
3936     TRACE("(%p,%d,%p,%p)\n", lpUrlComponents, dwFlags, lpszUrl, lpdwUrlLength);
3937
3938     if (!lpUrlComponents || lpUrlComponents->dwStructSize != sizeof(URL_COMPONENTSW) || !lpdwUrlLength)
3939     {
3940         SetLastError(ERROR_INVALID_PARAMETER);
3941         return FALSE;
3942     }
3943
3944     convert_urlcomp_atow(lpUrlComponents, &urlCompW);
3945
3946     if (lpszUrl)
3947         urlW = HeapAlloc(GetProcessHeap(), 0, *lpdwUrlLength * sizeof(WCHAR));
3948
3949     ret = InternetCreateUrlW(&urlCompW, dwFlags, urlW, lpdwUrlLength);
3950
3951     if (!ret && (GetLastError() == ERROR_INSUFFICIENT_BUFFER))
3952         *lpdwUrlLength /= sizeof(WCHAR);
3953
3954     /* on success, lpdwUrlLength points to the size of urlW in WCHARS
3955     * minus one, so add one to leave room for NULL terminator
3956     */
3957     if (ret)
3958         WideCharToMultiByte(CP_ACP, 0, urlW, -1, lpszUrl, *lpdwUrlLength + 1, NULL, NULL);
3959
3960     HeapFree(GetProcessHeap(), 0, urlCompW.lpszScheme);
3961     HeapFree(GetProcessHeap(), 0, urlCompW.lpszHostName);
3962     HeapFree(GetProcessHeap(), 0, urlCompW.lpszUserName);
3963     HeapFree(GetProcessHeap(), 0, urlCompW.lpszPassword);
3964     HeapFree(GetProcessHeap(), 0, urlCompW.lpszUrlPath);
3965     HeapFree(GetProcessHeap(), 0, urlCompW.lpszExtraInfo);
3966     HeapFree(GetProcessHeap(), 0, urlW);
3967
3968     return ret;
3969 }
3970
3971 /***********************************************************************
3972  *      InternetCreateUrlW (WININET.@)
3973  *
3974  * Creates a URL from its component parts.
3975  *
3976  * PARAMS
3977  *  lpUrlComponents [I] URL Components.
3978  *  dwFlags         [I] Flags. See notes.
3979  *  lpszUrl         [I] Buffer in which to store the created URL.
3980  *  lpdwUrlLength   [I/O] On input, the length of the buffer pointed to by
3981  *                        lpszUrl in characters. On output, the number of bytes
3982  *                        required to store the URL including terminator.
3983  *
3984  * NOTES
3985  *
3986  * The dwFlags parameter can be zero or more of the following:
3987  *|ICU_ESCAPE - Generates escape sequences for unsafe characters in the path and extra info of the URL.
3988  *
3989  * RETURNS
3990  *   TRUE on success
3991  *   FALSE on failure
3992  *
3993  */
3994 BOOL WINAPI InternetCreateUrlW(LPURL_COMPONENTSW lpUrlComponents, DWORD dwFlags,
3995                                LPWSTR lpszUrl, LPDWORD lpdwUrlLength)
3996 {
3997     DWORD dwLen;
3998     INTERNET_SCHEME nScheme;
3999
4000     static const WCHAR slashSlashW[] = {'/','/'};
4001     static const WCHAR percentD[] = {'%','d',0};
4002
4003     TRACE("(%p,%d,%p,%p)\n", lpUrlComponents, dwFlags, lpszUrl, lpdwUrlLength);
4004
4005     if (!lpUrlComponents || lpUrlComponents->dwStructSize != sizeof(URL_COMPONENTSW) || !lpdwUrlLength)
4006     {
4007         INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
4008         return FALSE;
4009     }
4010
4011     if (!calc_url_length(lpUrlComponents, &dwLen))
4012         return FALSE;
4013
4014     if (!lpszUrl || *lpdwUrlLength < dwLen)
4015     {
4016         *lpdwUrlLength = (dwLen + 1) * sizeof(WCHAR);
4017         INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
4018         return FALSE;
4019     }
4020
4021     *lpdwUrlLength = dwLen;
4022     lpszUrl[0] = 0x00;
4023
4024     dwLen = 0;
4025
4026     if (lpUrlComponents->lpszScheme)
4027     {
4028         dwLen = URL_GET_COMP_LENGTH(lpUrlComponents, Scheme);
4029         memcpy(lpszUrl, lpUrlComponents->lpszScheme, dwLen * sizeof(WCHAR));
4030         lpszUrl += dwLen;
4031
4032         nScheme = GetInternetSchemeW(lpUrlComponents->lpszScheme, dwLen);
4033     }
4034     else
4035     {
4036         LPCWSTR scheme;
4037         nScheme = lpUrlComponents->nScheme;
4038
4039         if (nScheme == INTERNET_SCHEME_DEFAULT)
4040             nScheme = INTERNET_SCHEME_HTTP;
4041
4042         scheme = INTERNET_GetSchemeString(nScheme);
4043         dwLen = strlenW(scheme);
4044         memcpy(lpszUrl, scheme, dwLen * sizeof(WCHAR));
4045         lpszUrl += dwLen;
4046     }
4047
4048     /* all schemes are followed by at least a colon */
4049     *lpszUrl = ':';
4050     lpszUrl++;
4051
4052     if (!scheme_is_opaque(nScheme) || lpUrlComponents->lpszHostName)
4053     {
4054         memcpy(lpszUrl, slashSlashW, sizeof(slashSlashW));
4055         lpszUrl += sizeof(slashSlashW)/sizeof(slashSlashW[0]);
4056     }
4057
4058     if (lpUrlComponents->lpszUserName)
4059     {
4060         dwLen = URL_GET_COMP_LENGTH(lpUrlComponents, UserName);
4061         memcpy(lpszUrl, lpUrlComponents->lpszUserName, dwLen * sizeof(WCHAR));
4062         lpszUrl += dwLen;
4063
4064         if (lpUrlComponents->lpszPassword)
4065         {
4066             *lpszUrl = ':';
4067             lpszUrl++;
4068
4069             dwLen = URL_GET_COMP_LENGTH(lpUrlComponents, Password);
4070             memcpy(lpszUrl, lpUrlComponents->lpszPassword, dwLen * sizeof(WCHAR));
4071             lpszUrl += dwLen;
4072         }
4073
4074         *lpszUrl = '@';
4075         lpszUrl++;
4076     }
4077
4078     if (lpUrlComponents->lpszHostName)
4079     {
4080         dwLen = URL_GET_COMP_LENGTH(lpUrlComponents, HostName);
4081         memcpy(lpszUrl, lpUrlComponents->lpszHostName, dwLen * sizeof(WCHAR));
4082         lpszUrl += dwLen;
4083
4084         if (!url_uses_default_port(nScheme, lpUrlComponents->nPort))
4085         {
4086             WCHAR szPort[MAX_WORD_DIGITS+1];
4087
4088             sprintfW(szPort, percentD, lpUrlComponents->nPort);
4089             *lpszUrl = ':';
4090             lpszUrl++;
4091             dwLen = strlenW(szPort);
4092             memcpy(lpszUrl, szPort, dwLen * sizeof(WCHAR));
4093             lpszUrl += dwLen;
4094         }
4095
4096         /* add slash between hostname and path if necessary */
4097         if (lpUrlComponents->lpszUrlPath && *lpUrlComponents->lpszUrlPath != '/')
4098         {
4099             *lpszUrl = '/';
4100             lpszUrl++;
4101         }
4102     }
4103
4104     if (lpUrlComponents->lpszUrlPath)
4105     {
4106         dwLen = URL_GET_COMP_LENGTH(lpUrlComponents, UrlPath);
4107         memcpy(lpszUrl, lpUrlComponents->lpszUrlPath, dwLen * sizeof(WCHAR));
4108         lpszUrl += dwLen;
4109     }
4110
4111     if (lpUrlComponents->lpszExtraInfo)
4112     {
4113         dwLen = URL_GET_COMP_LENGTH(lpUrlComponents, ExtraInfo);
4114         memcpy(lpszUrl, lpUrlComponents->lpszExtraInfo, dwLen * sizeof(WCHAR));
4115         lpszUrl += dwLen;
4116     }
4117
4118     *lpszUrl = '\0';
4119
4120     return TRUE;
4121 }
4122
4123 /***********************************************************************
4124  *      InternetConfirmZoneCrossingA (WININET.@)
4125  *
4126  */
4127 DWORD WINAPI InternetConfirmZoneCrossingA( HWND hWnd, LPSTR szUrlPrev, LPSTR szUrlNew, BOOL bPost )
4128 {
4129     FIXME("(%p, %s, %s, %x) stub\n", hWnd, debugstr_a(szUrlPrev), debugstr_a(szUrlNew), bPost);
4130     return ERROR_SUCCESS;
4131 }
4132
4133 /***********************************************************************
4134  *      InternetConfirmZoneCrossingW (WININET.@)
4135  *
4136  */
4137 DWORD WINAPI InternetConfirmZoneCrossingW( HWND hWnd, LPWSTR szUrlPrev, LPWSTR szUrlNew, BOOL bPost )
4138 {
4139     FIXME("(%p, %s, %s, %x) stub\n", hWnd, debugstr_w(szUrlPrev), debugstr_w(szUrlNew), bPost);
4140     return ERROR_SUCCESS;
4141 }
4142
4143 static DWORD zone_preference = 3;
4144
4145 /***********************************************************************
4146  *      PrivacySetZonePreferenceW (WININET.@)
4147  */
4148 DWORD WINAPI PrivacySetZonePreferenceW( DWORD zone, DWORD type, DWORD template, LPCWSTR preference )
4149 {
4150     FIXME( "%x %x %x %s: stub\n", zone, type, template, debugstr_w(preference) );
4151
4152     zone_preference = template;
4153     return 0;
4154 }
4155
4156 /***********************************************************************
4157  *      PrivacyGetZonePreferenceW (WININET.@)
4158  */
4159 DWORD WINAPI PrivacyGetZonePreferenceW( DWORD zone, DWORD type, LPDWORD template,
4160                                         LPWSTR preference, LPDWORD length )
4161 {
4162     FIXME( "%x %x %p %p %p: stub\n", zone, type, template, preference, length );
4163
4164     if (template) *template = zone_preference;
4165     return 0;
4166 }
4167
4168 DWORD WINAPI InternetDialA( HWND hwndParent, LPSTR lpszConnectoid, DWORD dwFlags,
4169                             DWORD_PTR* lpdwConnection, DWORD dwReserved )
4170 {
4171     FIXME("(%p, %p, 0x%08x, %p, 0x%08x) stub\n", hwndParent, lpszConnectoid, dwFlags,
4172           lpdwConnection, dwReserved);
4173     return ERROR_SUCCESS;
4174 }
4175
4176 DWORD WINAPI InternetDialW( HWND hwndParent, LPWSTR lpszConnectoid, DWORD dwFlags,
4177                             DWORD_PTR* lpdwConnection, DWORD dwReserved )
4178 {
4179     FIXME("(%p, %p, 0x%08x, %p, 0x%08x) stub\n", hwndParent, lpszConnectoid, dwFlags,
4180           lpdwConnection, dwReserved);
4181     return ERROR_SUCCESS;
4182 }
4183
4184 BOOL WINAPI InternetGoOnlineA( LPSTR lpszURL, HWND hwndParent, DWORD dwReserved )
4185 {
4186     FIXME("(%s, %p, 0x%08x) stub\n", debugstr_a(lpszURL), hwndParent, dwReserved);
4187     return TRUE;
4188 }
4189
4190 BOOL WINAPI InternetGoOnlineW( LPWSTR lpszURL, HWND hwndParent, DWORD dwReserved )
4191 {
4192     FIXME("(%s, %p, 0x%08x) stub\n", debugstr_w(lpszURL), hwndParent, dwReserved);
4193     return TRUE;
4194 }
4195
4196 DWORD WINAPI InternetHangUp( DWORD_PTR dwConnection, DWORD dwReserved )
4197 {
4198     FIXME("(0x%08lx, 0x%08x) stub\n", dwConnection, dwReserved);
4199     return ERROR_SUCCESS;
4200 }
4201
4202 BOOL WINAPI CreateMD5SSOHash( PWSTR pszChallengeInfo, PWSTR pwszRealm, PWSTR pwszTarget,
4203                               PBYTE pbHexHash )
4204 {
4205     FIXME("(%s, %s, %s, %p) stub\n", debugstr_w(pszChallengeInfo), debugstr_w(pwszRealm),
4206           debugstr_w(pwszTarget), pbHexHash);
4207     return FALSE;
4208 }
4209
4210 BOOL WINAPI ResumeSuspendedDownload( HINTERNET hInternet, DWORD dwError )
4211 {
4212     FIXME("(%p, 0x%08x) stub\n", hInternet, dwError);
4213     return FALSE;
4214 }
4215
4216 BOOL WINAPI InternetQueryFortezzaStatus(DWORD *a, DWORD_PTR b)
4217 {
4218     FIXME("(%p, %08lx) stub\n", a, b);
4219     return 0;
4220 }