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