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