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