urlmon: Implemented canonicalization of query strings.
[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 (!lpwhh)
2585         {
2586             SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
2587             return FALSE;
2588         }
2589         if (!lpBuffer || dwBufferLength != sizeof(DWORD_PTR))
2590         {
2591             SetLastError(ERROR_INVALID_PARAMETER);
2592             ret = FALSE;
2593         }
2594         else
2595             lpwhh->dwContext = *(DWORD_PTR *)lpBuffer;
2596         break;
2597     }
2598     case INTERNET_OPTION_SECURITY_FLAGS:
2599          FIXME("Option INTERNET_OPTION_SECURITY_FLAGS; STUB\n");
2600          break;
2601     case INTERNET_OPTION_DISABLE_AUTODIAL:
2602          FIXME("Option INTERNET_OPTION_DISABLE_AUTODIAL; STUB\n");
2603          break;
2604     case INTERNET_OPTION_HTTP_DECODING:
2605         FIXME("INTERNET_OPTION_HTTP_DECODING; STUB\n");
2606         SetLastError(ERROR_INTERNET_INVALID_OPTION);
2607         ret = FALSE;
2608         break;
2609     case INTERNET_OPTION_COOKIES_3RD_PARTY:
2610         FIXME("INTERNET_OPTION_COOKIES_3RD_PARTY; STUB\n");
2611         SetLastError(ERROR_INTERNET_INVALID_OPTION);
2612         ret = FALSE;
2613         break;
2614     case INTERNET_OPTION_SEND_UTF8_SERVERNAME_TO_PROXY:
2615         FIXME("INTERNET_OPTION_SEND_UTF8_SERVERNAME_TO_PROXY; STUB\n");
2616         SetLastError(ERROR_INTERNET_INVALID_OPTION);
2617         ret = FALSE;
2618         break;
2619     case INTERNET_OPTION_CODEPAGE_PATH:
2620         FIXME("INTERNET_OPTION_CODEPAGE_PATH; STUB\n");
2621         SetLastError(ERROR_INTERNET_INVALID_OPTION);
2622         ret = FALSE;
2623         break;
2624     case INTERNET_OPTION_CODEPAGE_EXTRA:
2625         FIXME("INTERNET_OPTION_CODEPAGE_EXTRA; STUB\n");
2626         SetLastError(ERROR_INTERNET_INVALID_OPTION);
2627         ret = FALSE;
2628         break;
2629     case INTERNET_OPTION_IDN:
2630         FIXME("INTERNET_OPTION_IDN; STUB\n");
2631         SetLastError(ERROR_INTERNET_INVALID_OPTION);
2632         ret = FALSE;
2633         break;
2634     case INTERNET_OPTION_POLICY:
2635         SetLastError(ERROR_INVALID_PARAMETER);
2636         ret = FALSE;
2637         break;
2638     case INTERNET_OPTION_PER_CONNECTION_OPTION: {
2639         INTERNET_PER_CONN_OPTION_LISTW *con = lpBuffer;
2640         LONG res;
2641         int i;
2642         proxyinfo_t pi;
2643
2644         INTERNET_LoadProxySettings(&pi);
2645
2646         for (i = 0; i < con->dwOptionCount; i++) {
2647             INTERNET_PER_CONN_OPTIONW *option = con->pOptions + i;
2648
2649             switch (option->dwOption) {
2650             case INTERNET_PER_CONN_PROXY_SERVER:
2651                 HeapFree(GetProcessHeap(), 0, pi.lpszProxyServer);
2652                 pi.lpszProxyServer = heap_strdupW(option->Value.pszValue);
2653                 break;
2654
2655             case INTERNET_PER_CONN_FLAGS:
2656                 if(option->Value.dwValue & PROXY_TYPE_PROXY)
2657                     pi.dwProxyEnabled = 1;
2658                 else
2659                 {
2660                     if(option->Value.dwValue != PROXY_TYPE_DIRECT)
2661                         FIXME("Unhandled flags: 0x%x\n", option->Value.dwValue);
2662                     pi.dwProxyEnabled = 0;
2663                 }
2664                 break;
2665
2666             case INTERNET_PER_CONN_AUTOCONFIG_URL:
2667             case INTERNET_PER_CONN_AUTODISCOVERY_FLAGS:
2668             case INTERNET_PER_CONN_AUTOCONFIG_SECONDARY_URL:
2669             case INTERNET_PER_CONN_AUTOCONFIG_RELOAD_DELAY_MINS:
2670             case INTERNET_PER_CONN_AUTOCONFIG_LAST_DETECT_TIME:
2671             case INTERNET_PER_CONN_AUTOCONFIG_LAST_DETECT_URL:
2672             case INTERNET_PER_CONN_PROXY_BYPASS:
2673                 FIXME("Unhandled dwOption %d\n", option->dwOption);
2674                 break;
2675
2676             default:
2677                 FIXME("Unknown dwOption %d\n", option->dwOption);
2678                 SetLastError(ERROR_INVALID_PARAMETER);
2679                 break;
2680             }
2681         }
2682
2683         if ((res = INTERNET_SaveProxySettings(&pi)))
2684             SetLastError(res);
2685
2686         FreeProxyInfo(&pi);
2687
2688         ret = (res == ERROR_SUCCESS);
2689         break;
2690         }
2691     default:
2692         FIXME("Option %d STUB\n",dwOption);
2693         SetLastError(ERROR_INTERNET_INVALID_OPTION);
2694         ret = FALSE;
2695         break;
2696     }
2697
2698     if(lpwhh)
2699         WININET_Release( lpwhh );
2700
2701     return ret;
2702 }
2703
2704
2705 /***********************************************************************
2706  *           InternetSetOptionA (WININET.@)
2707  *
2708  * Sets an options on the specified handle.
2709  *
2710  * RETURNS
2711  *    TRUE  on success
2712  *    FALSE on failure
2713  *
2714  */
2715 BOOL WINAPI InternetSetOptionA(HINTERNET hInternet, DWORD dwOption,
2716                            LPVOID lpBuffer, DWORD dwBufferLength)
2717 {
2718     LPVOID wbuffer;
2719     DWORD wlen;
2720     BOOL r;
2721
2722     switch( dwOption )
2723     {
2724     case INTERNET_OPTION_CALLBACK:
2725         {
2726         object_header_t *lpwh;
2727
2728         if (!(lpwh = WININET_GetObject(hInternet)))
2729         {
2730             INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
2731             return FALSE;
2732         }
2733         WININET_Release(lpwh);
2734         INTERNET_SetLastError(ERROR_INTERNET_OPTION_NOT_SETTABLE);
2735         return FALSE;
2736         }
2737     case INTERNET_OPTION_PROXY:
2738         {
2739         LPINTERNET_PROXY_INFOA pi = (LPINTERNET_PROXY_INFOA) lpBuffer;
2740         LPINTERNET_PROXY_INFOW piw;
2741         DWORD proxlen, prbylen;
2742         LPWSTR prox, prby;
2743
2744         proxlen = MultiByteToWideChar( CP_ACP, 0, pi->lpszProxy, -1, NULL, 0);
2745         prbylen= MultiByteToWideChar( CP_ACP, 0, pi->lpszProxyBypass, -1, NULL, 0);
2746         wlen = sizeof(*piw) + proxlen + prbylen;
2747         wbuffer = HeapAlloc( GetProcessHeap(), 0, wlen*sizeof(WCHAR) );
2748         piw = (LPINTERNET_PROXY_INFOW) wbuffer;
2749         piw->dwAccessType = pi->dwAccessType;
2750         prox = (LPWSTR) &piw[1];
2751         prby = &prox[proxlen+1];
2752         MultiByteToWideChar( CP_ACP, 0, pi->lpszProxy, -1, prox, proxlen);
2753         MultiByteToWideChar( CP_ACP, 0, pi->lpszProxyBypass, -1, prby, prbylen);
2754         piw->lpszProxy = prox;
2755         piw->lpszProxyBypass = prby;
2756         }
2757         break;
2758     case INTERNET_OPTION_USER_AGENT:
2759     case INTERNET_OPTION_USERNAME:
2760     case INTERNET_OPTION_PASSWORD:
2761         wlen = MultiByteToWideChar( CP_ACP, 0, lpBuffer, dwBufferLength,
2762                                    NULL, 0 );
2763         wbuffer = HeapAlloc( GetProcessHeap(), 0, wlen*sizeof(WCHAR) );
2764         MultiByteToWideChar( CP_ACP, 0, lpBuffer, dwBufferLength,
2765                                    wbuffer, wlen );
2766         break;
2767     case INTERNET_OPTION_PER_CONNECTION_OPTION: {
2768         int i;
2769         INTERNET_PER_CONN_OPTION_LISTW *listW;
2770         INTERNET_PER_CONN_OPTION_LISTA *listA = lpBuffer;
2771         wlen = sizeof(INTERNET_PER_CONN_OPTION_LISTW);
2772         wbuffer = HeapAlloc( GetProcessHeap(), 0, wlen );
2773         listW = wbuffer;
2774
2775         listW->dwSize = sizeof(INTERNET_PER_CONN_OPTION_LISTW);
2776         if (listA->pszConnection)
2777         {
2778             wlen = MultiByteToWideChar( CP_ACP, 0, listA->pszConnection, -1, NULL, 0 );
2779             listW->pszConnection = HeapAlloc( GetProcessHeap(), 0, wlen*sizeof(WCHAR) );
2780             MultiByteToWideChar( CP_ACP, 0, listA->pszConnection, -1, listW->pszConnection, wlen );
2781         }
2782         else
2783             listW->pszConnection = NULL;
2784         listW->dwOptionCount = listA->dwOptionCount;
2785         listW->dwOptionError = listA->dwOptionError;
2786         listW->pOptions = HeapAlloc( GetProcessHeap(), 0, sizeof(INTERNET_PER_CONN_OPTIONW) * listA->dwOptionCount );
2787
2788         for (i = 0; i < listA->dwOptionCount; ++i) {
2789             INTERNET_PER_CONN_OPTIONA *optA = listA->pOptions + i;
2790             INTERNET_PER_CONN_OPTIONW *optW = listW->pOptions + i;
2791
2792             optW->dwOption = optA->dwOption;
2793
2794             switch (optA->dwOption) {
2795             case INTERNET_PER_CONN_AUTOCONFIG_URL:
2796             case INTERNET_PER_CONN_PROXY_BYPASS:
2797             case INTERNET_PER_CONN_PROXY_SERVER:
2798             case INTERNET_PER_CONN_AUTOCONFIG_SECONDARY_URL:
2799             case INTERNET_PER_CONN_AUTOCONFIG_LAST_DETECT_URL:
2800                 if (optA->Value.pszValue)
2801                 {
2802                     wlen = MultiByteToWideChar( CP_ACP, 0, optA->Value.pszValue, -1, NULL, 0 );
2803                     optW->Value.pszValue = HeapAlloc( GetProcessHeap(), 0, wlen*sizeof(WCHAR) );
2804                     MultiByteToWideChar( CP_ACP, 0, optA->Value.pszValue, -1, optW->Value.pszValue, wlen );
2805                 }
2806                 else
2807                     optW->Value.pszValue = NULL;
2808                 break;
2809             case INTERNET_PER_CONN_AUTODISCOVERY_FLAGS:
2810             case INTERNET_PER_CONN_FLAGS:
2811             case INTERNET_PER_CONN_AUTOCONFIG_RELOAD_DELAY_MINS:
2812                 optW->Value.dwValue = optA->Value.dwValue;
2813                 break;
2814             case INTERNET_PER_CONN_AUTOCONFIG_LAST_DETECT_TIME:
2815                 optW->Value.ftValue = optA->Value.ftValue;
2816             default:
2817                 WARN("Unknown PER_CONN dwOption: %d, guessing at conversion to Wide\n", optA->dwOption);
2818                 optW->Value.dwValue = optA->Value.dwValue;
2819                 break;
2820             }
2821         }
2822         }
2823         break;
2824     default:
2825         wbuffer = lpBuffer;
2826         wlen = dwBufferLength;
2827     }
2828
2829     r = InternetSetOptionW(hInternet,dwOption, wbuffer, wlen);
2830
2831     if( lpBuffer != wbuffer )
2832     {
2833         if (dwOption == INTERNET_OPTION_PER_CONNECTION_OPTION)
2834         {
2835             INTERNET_PER_CONN_OPTION_LISTW *list = wbuffer;
2836             int i;
2837             for (i = 0; i < list->dwOptionCount; ++i) {
2838                 INTERNET_PER_CONN_OPTIONW *opt = list->pOptions + i;
2839                 switch (opt->dwOption) {
2840                 case INTERNET_PER_CONN_AUTOCONFIG_URL:
2841                 case INTERNET_PER_CONN_PROXY_BYPASS:
2842                 case INTERNET_PER_CONN_PROXY_SERVER:
2843                 case INTERNET_PER_CONN_AUTOCONFIG_SECONDARY_URL:
2844                 case INTERNET_PER_CONN_AUTOCONFIG_LAST_DETECT_URL:
2845                     HeapFree( GetProcessHeap(), 0, opt->Value.pszValue );
2846                     break;
2847                 default:
2848                     break;
2849                 }
2850             }
2851             HeapFree( GetProcessHeap(), 0, list->pOptions );
2852         }
2853         HeapFree( GetProcessHeap(), 0, wbuffer );
2854     }
2855
2856     return r;
2857 }
2858
2859
2860 /***********************************************************************
2861  *           InternetSetOptionExA (WININET.@)
2862  */
2863 BOOL WINAPI InternetSetOptionExA(HINTERNET hInternet, DWORD dwOption,
2864                            LPVOID lpBuffer, DWORD dwBufferLength, DWORD dwFlags)
2865 {
2866     FIXME("Flags %08x ignored\n", dwFlags);
2867     return InternetSetOptionA( hInternet, dwOption, lpBuffer, dwBufferLength );
2868 }
2869
2870 /***********************************************************************
2871  *           InternetSetOptionExW (WININET.@)
2872  */
2873 BOOL WINAPI InternetSetOptionExW(HINTERNET hInternet, DWORD dwOption,
2874                            LPVOID lpBuffer, DWORD dwBufferLength, DWORD dwFlags)
2875 {
2876     FIXME("Flags %08x ignored\n", dwFlags);
2877     if( dwFlags & ~ISO_VALID_FLAGS )
2878     {
2879         SetLastError( ERROR_INVALID_PARAMETER );
2880         return FALSE;
2881     }
2882     return InternetSetOptionW( hInternet, dwOption, lpBuffer, dwBufferLength );
2883 }
2884
2885 static const WCHAR WININET_wkday[7][4] =
2886     { { 'S','u','n', 0 }, { 'M','o','n', 0 }, { 'T','u','e', 0 }, { 'W','e','d', 0 },
2887       { 'T','h','u', 0 }, { 'F','r','i', 0 }, { 'S','a','t', 0 } };
2888 static const WCHAR WININET_month[12][4] =
2889     { { 'J','a','n', 0 }, { 'F','e','b', 0 }, { 'M','a','r', 0 }, { 'A','p','r', 0 },
2890       { 'M','a','y', 0 }, { 'J','u','n', 0 }, { 'J','u','l', 0 }, { 'A','u','g', 0 },
2891       { 'S','e','p', 0 }, { 'O','c','t', 0 }, { 'N','o','v', 0 }, { 'D','e','c', 0 } };
2892
2893 /***********************************************************************
2894  *           InternetTimeFromSystemTimeA (WININET.@)
2895  */
2896 BOOL WINAPI InternetTimeFromSystemTimeA( const SYSTEMTIME* time, DWORD format, LPSTR string, DWORD size )
2897 {
2898     BOOL ret;
2899     WCHAR stringW[INTERNET_RFC1123_BUFSIZE];
2900
2901     TRACE( "%p 0x%08x %p 0x%08x\n", time, format, string, size );
2902
2903     if (!time || !string || format != INTERNET_RFC1123_FORMAT)
2904     {
2905         SetLastError(ERROR_INVALID_PARAMETER);
2906         return FALSE;
2907     }
2908
2909     if (size < INTERNET_RFC1123_BUFSIZE * sizeof(*string))
2910     {
2911         SetLastError(ERROR_INSUFFICIENT_BUFFER);
2912         return FALSE;
2913     }
2914
2915     ret = InternetTimeFromSystemTimeW( time, format, stringW, sizeof(stringW) );
2916     if (ret) WideCharToMultiByte( CP_ACP, 0, stringW, -1, string, size, NULL, NULL );
2917
2918     return ret;
2919 }
2920
2921 /***********************************************************************
2922  *           InternetTimeFromSystemTimeW (WININET.@)
2923  */
2924 BOOL WINAPI InternetTimeFromSystemTimeW( const SYSTEMTIME* time, DWORD format, LPWSTR string, DWORD size )
2925 {
2926     static const WCHAR date[] =
2927         { '%','s',',',' ','%','0','2','d',' ','%','s',' ','%','4','d',' ','%','0',
2928           '2','d',':','%','0','2','d',':','%','0','2','d',' ','G','M','T', 0 };
2929
2930     TRACE( "%p 0x%08x %p 0x%08x\n", time, format, string, size );
2931
2932     if (!time || !string || format != INTERNET_RFC1123_FORMAT)
2933     {
2934         SetLastError(ERROR_INVALID_PARAMETER);
2935         return FALSE;
2936     }
2937
2938     if (size < INTERNET_RFC1123_BUFSIZE * sizeof(*string))
2939     {
2940         SetLastError(ERROR_INSUFFICIENT_BUFFER);
2941         return FALSE;
2942     }
2943
2944     sprintfW( string, date,
2945               WININET_wkday[time->wDayOfWeek],
2946               time->wDay,
2947               WININET_month[time->wMonth - 1],
2948               time->wYear,
2949               time->wHour,
2950               time->wMinute,
2951               time->wSecond );
2952
2953     return TRUE;
2954 }
2955
2956 /***********************************************************************
2957  *           InternetTimeToSystemTimeA (WININET.@)
2958  */
2959 BOOL WINAPI InternetTimeToSystemTimeA( LPCSTR string, SYSTEMTIME* time, DWORD reserved )
2960 {
2961     BOOL ret = FALSE;
2962     WCHAR *stringW;
2963
2964     TRACE( "%s %p 0x%08x\n", debugstr_a(string), time, reserved );
2965
2966     stringW = heap_strdupAtoW(string);
2967     if (stringW)
2968     {
2969         ret = InternetTimeToSystemTimeW( stringW, time, reserved );
2970         HeapFree( GetProcessHeap(), 0, stringW );
2971     }
2972     return ret;
2973 }
2974
2975 /***********************************************************************
2976  *           InternetTimeToSystemTimeW (WININET.@)
2977  */
2978 BOOL WINAPI InternetTimeToSystemTimeW( LPCWSTR string, SYSTEMTIME* time, DWORD reserved )
2979 {
2980     unsigned int i;
2981     const WCHAR *s = string;
2982     WCHAR       *end;
2983
2984     TRACE( "%s %p 0x%08x\n", debugstr_w(string), time, reserved );
2985
2986     if (!string || !time) return FALSE;
2987
2988     /* Windows does this too */
2989     GetSystemTime( time );
2990
2991     /*  Convert an RFC1123 time such as 'Fri, 07 Jan 2005 12:06:35 GMT' into
2992      *  a SYSTEMTIME structure.
2993      */
2994
2995     while (*s && !isalphaW( *s )) s++;
2996     if (s[0] == '\0' || s[1] == '\0' || s[2] == '\0') return TRUE;
2997     time->wDayOfWeek = 7;
2998
2999     for (i = 0; i < 7; i++)
3000     {
3001         if (toupperW( WININET_wkday[i][0] ) == toupperW( s[0] ) &&
3002             toupperW( WININET_wkday[i][1] ) == toupperW( s[1] ) &&
3003             toupperW( WININET_wkday[i][2] ) == toupperW( s[2] ) )
3004         {
3005             time->wDayOfWeek = i;
3006             break;
3007         }
3008     }
3009
3010     if (time->wDayOfWeek > 6) return TRUE;
3011     while (*s && !isdigitW( *s )) s++;
3012     time->wDay = strtolW( s, &end, 10 );
3013     s = end;
3014
3015     while (*s && !isalphaW( *s )) s++;
3016     if (s[0] == '\0' || s[1] == '\0' || s[2] == '\0') return TRUE;
3017     time->wMonth = 0;
3018
3019     for (i = 0; i < 12; i++)
3020     {
3021         if (toupperW( WININET_month[i][0]) == toupperW( s[0] ) &&
3022             toupperW( WININET_month[i][1]) == toupperW( s[1] ) &&
3023             toupperW( WININET_month[i][2]) == toupperW( s[2] ) )
3024         {
3025             time->wMonth = i + 1;
3026             break;
3027         }
3028     }
3029     if (time->wMonth == 0) return TRUE;
3030
3031     while (*s && !isdigitW( *s )) s++;
3032     if (*s == '\0') return TRUE;
3033     time->wYear = strtolW( s, &end, 10 );
3034     s = end;
3035
3036     while (*s && !isdigitW( *s )) s++;
3037     if (*s == '\0') return TRUE;
3038     time->wHour = strtolW( s, &end, 10 );
3039     s = end;
3040
3041     while (*s && !isdigitW( *s )) s++;
3042     if (*s == '\0') return TRUE;
3043     time->wMinute = strtolW( s, &end, 10 );
3044     s = end;
3045
3046     while (*s && !isdigitW( *s )) s++;
3047     if (*s == '\0') return TRUE;
3048     time->wSecond = strtolW( s, &end, 10 );
3049     s = end;
3050
3051     time->wMilliseconds = 0;
3052     return TRUE;
3053 }
3054
3055 /***********************************************************************
3056  *      InternetCheckConnectionW (WININET.@)
3057  *
3058  * Pings a requested host to check internet connection
3059  *
3060  * RETURNS
3061  *   TRUE on success and FALSE on failure. If a failure then
3062  *   ERROR_NOT_CONNECTED is placed into GetLastError
3063  *
3064  */
3065 BOOL WINAPI InternetCheckConnectionW( LPCWSTR lpszUrl, DWORD dwFlags, DWORD dwReserved )
3066 {
3067 /*
3068  * this is a kludge which runs the resident ping program and reads the output.
3069  *
3070  * Anyone have a better idea?
3071  */
3072
3073   BOOL   rc = FALSE;
3074   static const CHAR ping[] = "ping -c 1 ";
3075   static const CHAR redirect[] = " >/dev/null 2>/dev/null";
3076   CHAR *command = NULL;
3077   WCHAR hostW[1024];
3078   DWORD len;
3079   INTERNET_PORT port;
3080   int status = -1;
3081
3082   FIXME("\n");
3083
3084   /*
3085    * Crack or set the Address
3086    */
3087   if (lpszUrl == NULL)
3088   {
3089      /*
3090       * According to the doc we are supposed to use the ip for the next
3091       * server in the WnInet internal server database. I have
3092       * no idea what that is or how to get it.
3093       *
3094       * So someone needs to implement this.
3095       */
3096      FIXME("Unimplemented with URL of NULL\n");
3097      return TRUE;
3098   }
3099   else
3100   {
3101      URL_COMPONENTSW components;
3102
3103      ZeroMemory(&components,sizeof(URL_COMPONENTSW));
3104      components.lpszHostName = (LPWSTR)hostW;
3105      components.dwHostNameLength = 1024;
3106
3107      if (!InternetCrackUrlW(lpszUrl,0,0,&components))
3108        goto End;
3109
3110      TRACE("host name : %s\n",debugstr_w(components.lpszHostName));
3111      port = components.nPort;
3112      TRACE("port: %d\n", port);
3113   }
3114
3115   if (dwFlags & FLAG_ICC_FORCE_CONNECTION)
3116   {
3117       struct sockaddr_storage saddr;
3118       socklen_t sa_len = sizeof(saddr);
3119       int fd;
3120
3121       if (!GetAddress(hostW, port, (struct sockaddr *)&saddr, &sa_len))
3122           goto End;
3123       fd = socket(saddr.ss_family, SOCK_STREAM, 0);
3124       if (fd != -1)
3125       {
3126           if (connect(fd, (struct sockaddr *)&saddr, sa_len) == 0)
3127               rc = TRUE;
3128           close(fd);
3129       }
3130   }
3131   else
3132   {
3133       /*
3134        * Build our ping command
3135        */
3136       len = WideCharToMultiByte(CP_UNIXCP, 0, hostW, -1, NULL, 0, NULL, NULL);
3137       command = HeapAlloc( GetProcessHeap(), 0, strlen(ping)+len+strlen(redirect) );
3138       strcpy(command,ping);
3139       WideCharToMultiByte(CP_UNIXCP, 0, hostW, -1, command+strlen(ping), len, NULL, NULL);
3140       strcat(command,redirect);
3141
3142       TRACE("Ping command is : %s\n",command);
3143
3144       status = system(command);
3145
3146       TRACE("Ping returned a code of %i\n",status);
3147
3148       /* Ping return code of 0 indicates success */
3149       if (status == 0)
3150          rc = TRUE;
3151   }
3152
3153 End:
3154
3155   HeapFree( GetProcessHeap(), 0, command );
3156   if (rc == FALSE)
3157     INTERNET_SetLastError(ERROR_NOT_CONNECTED);
3158
3159   return rc;
3160 }
3161
3162
3163 /***********************************************************************
3164  *      InternetCheckConnectionA (WININET.@)
3165  *
3166  * Pings a requested host to check internet connection
3167  *
3168  * RETURNS
3169  *   TRUE on success and FALSE on failure. If a failure then
3170  *   ERROR_NOT_CONNECTED is placed into GetLastError
3171  *
3172  */
3173 BOOL WINAPI InternetCheckConnectionA(LPCSTR lpszUrl, DWORD dwFlags, DWORD dwReserved)
3174 {
3175     WCHAR *url = NULL;
3176     BOOL rc;
3177
3178     if(lpszUrl) {
3179         url = heap_strdupAtoW(lpszUrl);
3180         if(!url)
3181             return FALSE;
3182     }
3183
3184     rc = InternetCheckConnectionW(url, dwFlags, dwReserved);
3185
3186     HeapFree(GetProcessHeap(), 0, url);
3187     return rc;
3188 }
3189
3190
3191 /**********************************************************
3192  *      INTERNET_InternetOpenUrlW (internal)
3193  *
3194  * Opens an URL
3195  *
3196  * RETURNS
3197  *   handle of connection or NULL on failure
3198  */
3199 static HINTERNET INTERNET_InternetOpenUrlW(appinfo_t *hIC, LPCWSTR lpszUrl,
3200     LPCWSTR lpszHeaders, DWORD dwHeadersLength, DWORD dwFlags, DWORD_PTR dwContext)
3201 {
3202     URL_COMPONENTSW urlComponents;
3203     WCHAR protocol[32], hostName[MAXHOSTNAME], userName[1024];
3204     WCHAR password[1024], path[2048], extra[1024];
3205     HINTERNET client = NULL, client1 = NULL;
3206     DWORD res;
3207     
3208     TRACE("(%p, %s, %s, %08x, %08x, %08lx)\n", hIC, debugstr_w(lpszUrl), debugstr_w(lpszHeaders),
3209           dwHeadersLength, dwFlags, dwContext);
3210     
3211     urlComponents.dwStructSize = sizeof(URL_COMPONENTSW);
3212     urlComponents.lpszScheme = protocol;
3213     urlComponents.dwSchemeLength = 32;
3214     urlComponents.lpszHostName = hostName;
3215     urlComponents.dwHostNameLength = MAXHOSTNAME;
3216     urlComponents.lpszUserName = userName;
3217     urlComponents.dwUserNameLength = 1024;
3218     urlComponents.lpszPassword = password;
3219     urlComponents.dwPasswordLength = 1024;
3220     urlComponents.lpszUrlPath = path;
3221     urlComponents.dwUrlPathLength = 2048;
3222     urlComponents.lpszExtraInfo = extra;
3223     urlComponents.dwExtraInfoLength = 1024;
3224     if(!InternetCrackUrlW(lpszUrl, strlenW(lpszUrl), 0, &urlComponents))
3225         return NULL;
3226     switch(urlComponents.nScheme) {
3227     case INTERNET_SCHEME_FTP:
3228         if(urlComponents.nPort == 0)
3229             urlComponents.nPort = INTERNET_DEFAULT_FTP_PORT;
3230         client = FTP_Connect(hIC, hostName, urlComponents.nPort,
3231                              userName, password, dwFlags, dwContext, INET_OPENURL);
3232         if(client == NULL)
3233             break;
3234         client1 = FtpOpenFileW(client, path, GENERIC_READ, dwFlags, dwContext);
3235         if(client1 == NULL) {
3236             InternetCloseHandle(client);
3237             break;
3238         }
3239         break;
3240         
3241     case INTERNET_SCHEME_HTTP:
3242     case INTERNET_SCHEME_HTTPS: {
3243         static const WCHAR szStars[] = { '*','/','*', 0 };
3244         LPCWSTR accept[2] = { szStars, NULL };
3245         if(urlComponents.nPort == 0) {
3246             if(urlComponents.nScheme == INTERNET_SCHEME_HTTP)
3247                 urlComponents.nPort = INTERNET_DEFAULT_HTTP_PORT;
3248             else
3249                 urlComponents.nPort = INTERNET_DEFAULT_HTTPS_PORT;
3250         }
3251         if (urlComponents.nScheme == INTERNET_SCHEME_HTTPS) dwFlags |= INTERNET_FLAG_SECURE;
3252
3253         /* FIXME: should use pointers, not handles, as handles are not thread-safe */
3254         res = HTTP_Connect(hIC, hostName, urlComponents.nPort,
3255                            userName, password, dwFlags, dwContext, INET_OPENURL, &client);
3256         if(res != ERROR_SUCCESS) {
3257             INTERNET_SetLastError(res);
3258             break;
3259         }
3260
3261         if (urlComponents.dwExtraInfoLength) {
3262                 WCHAR *path_extra;
3263                 DWORD len = urlComponents.dwUrlPathLength + urlComponents.dwExtraInfoLength + 1;
3264
3265                 if (!(path_extra = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR))))
3266                 {
3267                         InternetCloseHandle(client);
3268                         break;
3269                 }
3270                 strcpyW(path_extra, urlComponents.lpszUrlPath);
3271                 strcatW(path_extra, urlComponents.lpszExtraInfo);
3272                 client1 = HttpOpenRequestW(client, NULL, path_extra, NULL, NULL, accept, dwFlags, dwContext);
3273                 HeapFree(GetProcessHeap(), 0, path_extra);
3274         }
3275         else
3276                 client1 = HttpOpenRequestW(client, NULL, path, NULL, NULL, accept, dwFlags, dwContext);
3277
3278         if(client1 == NULL) {
3279             InternetCloseHandle(client);
3280             break;
3281         }
3282         HttpAddRequestHeadersW(client1, lpszHeaders, dwHeadersLength, HTTP_ADDREQ_FLAG_ADD);
3283         if (!HttpSendRequestW(client1, NULL, 0, NULL, 0) &&
3284             GetLastError() != ERROR_IO_PENDING) {
3285             InternetCloseHandle(client1);
3286             client1 = NULL;
3287             break;
3288         }
3289     }
3290     case INTERNET_SCHEME_GOPHER:
3291         /* gopher doesn't seem to be implemented in wine, but it's supposed
3292          * to be supported by InternetOpenUrlA. */
3293     default:
3294         SetLastError(ERROR_INTERNET_UNRECOGNIZED_SCHEME);
3295         break;
3296     }
3297
3298     TRACE(" %p <--\n", client1);
3299     
3300     return client1;
3301 }
3302
3303 /**********************************************************
3304  *      InternetOpenUrlW (WININET.@)
3305  *
3306  * Opens an URL
3307  *
3308  * RETURNS
3309  *   handle of connection or NULL on failure
3310  */
3311 static void AsyncInternetOpenUrlProc(WORKREQUEST *workRequest)
3312 {
3313     struct WORKREQ_INTERNETOPENURLW const *req = &workRequest->u.InternetOpenUrlW;
3314     appinfo_t *hIC = (appinfo_t*) workRequest->hdr;
3315
3316     TRACE("%p\n", hIC);
3317
3318     INTERNET_InternetOpenUrlW(hIC, req->lpszUrl,
3319                               req->lpszHeaders, req->dwHeadersLength, req->dwFlags, req->dwContext);
3320     HeapFree(GetProcessHeap(), 0, req->lpszUrl);
3321     HeapFree(GetProcessHeap(), 0, req->lpszHeaders);
3322 }
3323
3324 HINTERNET WINAPI InternetOpenUrlW(HINTERNET hInternet, LPCWSTR lpszUrl,
3325     LPCWSTR lpszHeaders, DWORD dwHeadersLength, DWORD dwFlags, DWORD_PTR dwContext)
3326 {
3327     HINTERNET ret = NULL;
3328     appinfo_t *hIC = NULL;
3329
3330     if (TRACE_ON(wininet)) {
3331         TRACE("(%p, %s, %s, %08x, %08x, %08lx)\n", hInternet, debugstr_w(lpszUrl), debugstr_w(lpszHeaders),
3332               dwHeadersLength, dwFlags, dwContext);
3333         TRACE("  flags :");
3334         dump_INTERNET_FLAGS(dwFlags);
3335     }
3336
3337     if (!lpszUrl)
3338     {
3339         SetLastError(ERROR_INVALID_PARAMETER);
3340         goto lend;
3341     }
3342
3343     hIC = (appinfo_t*)WININET_GetObject( hInternet );
3344     if (NULL == hIC ||  hIC->hdr.htype != WH_HINIT) {
3345         SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
3346         goto lend;
3347     }
3348     
3349     if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC) {
3350         WORKREQUEST workRequest;
3351         struct WORKREQ_INTERNETOPENURLW *req;
3352
3353         workRequest.asyncproc = AsyncInternetOpenUrlProc;
3354         workRequest.hdr = WININET_AddRef( &hIC->hdr );
3355         req = &workRequest.u.InternetOpenUrlW;
3356         req->lpszUrl = heap_strdupW(lpszUrl);
3357         req->lpszHeaders = heap_strdupW(lpszHeaders);
3358         req->dwHeadersLength = dwHeadersLength;
3359         req->dwFlags = dwFlags;
3360         req->dwContext = dwContext;
3361         
3362         INTERNET_AsyncCall(&workRequest);
3363         /*
3364          * This is from windows.
3365          */
3366         SetLastError(ERROR_IO_PENDING);
3367     } else {
3368         ret = INTERNET_InternetOpenUrlW(hIC, lpszUrl, lpszHeaders, dwHeadersLength, dwFlags, dwContext);
3369     }
3370     
3371   lend:
3372     if( hIC )
3373         WININET_Release( &hIC->hdr );
3374     TRACE(" %p <--\n", ret);
3375     
3376     return ret;
3377 }
3378
3379 /**********************************************************
3380  *      InternetOpenUrlA (WININET.@)
3381  *
3382  * Opens an URL
3383  *
3384  * RETURNS
3385  *   handle of connection or NULL on failure
3386  */
3387 HINTERNET WINAPI InternetOpenUrlA(HINTERNET hInternet, LPCSTR lpszUrl,
3388     LPCSTR lpszHeaders, DWORD dwHeadersLength, DWORD dwFlags, DWORD_PTR dwContext)
3389 {
3390     HINTERNET rc = NULL;
3391     DWORD lenHeaders = 0;
3392     LPWSTR szUrl = NULL;
3393     LPWSTR szHeaders = NULL;
3394
3395     TRACE("\n");
3396
3397     if(lpszUrl) {
3398         szUrl = heap_strdupAtoW(lpszUrl);
3399         if(!szUrl)
3400             return NULL;
3401     }
3402
3403     if(lpszHeaders) {
3404         lenHeaders = MultiByteToWideChar(CP_ACP, 0, lpszHeaders, dwHeadersLength, NULL, 0 );
3405         szHeaders = HeapAlloc(GetProcessHeap(), 0, lenHeaders*sizeof(WCHAR));
3406         if(!szHeaders) {
3407             HeapFree(GetProcessHeap(), 0, szUrl);
3408             return NULL;
3409         }
3410         MultiByteToWideChar(CP_ACP, 0, lpszHeaders, dwHeadersLength, szHeaders, lenHeaders);
3411     }
3412     
3413     rc = InternetOpenUrlW(hInternet, szUrl, szHeaders,
3414         lenHeaders, dwFlags, dwContext);
3415
3416     HeapFree(GetProcessHeap(), 0, szUrl);
3417     HeapFree(GetProcessHeap(), 0, szHeaders);
3418
3419     return rc;
3420 }
3421
3422
3423 static LPWITHREADERROR INTERNET_AllocThreadError(void)
3424 {
3425     LPWITHREADERROR lpwite = HeapAlloc(GetProcessHeap(), 0, sizeof(*lpwite));
3426
3427     if (lpwite)
3428     {
3429         lpwite->dwError = 0;
3430         lpwite->response[0] = '\0';
3431     }
3432
3433     if (!TlsSetValue(g_dwTlsErrIndex, lpwite))
3434     {
3435         HeapFree(GetProcessHeap(), 0, lpwite);
3436         return NULL;
3437     }
3438
3439     return lpwite;
3440 }
3441
3442
3443 /***********************************************************************
3444  *           INTERNET_SetLastError (internal)
3445  *
3446  * Set last thread specific error
3447  *
3448  * RETURNS
3449  *
3450  */
3451 void INTERNET_SetLastError(DWORD dwError)
3452 {
3453     LPWITHREADERROR lpwite = TlsGetValue(g_dwTlsErrIndex);
3454
3455     if (!lpwite)
3456         lpwite = INTERNET_AllocThreadError();
3457
3458     SetLastError(dwError);
3459     if(lpwite)
3460         lpwite->dwError = dwError;
3461 }
3462
3463
3464 /***********************************************************************
3465  *           INTERNET_GetLastError (internal)
3466  *
3467  * Get last thread specific error
3468  *
3469  * RETURNS
3470  *
3471  */
3472 DWORD INTERNET_GetLastError(void)
3473 {
3474     LPWITHREADERROR lpwite = TlsGetValue(g_dwTlsErrIndex);
3475     if (!lpwite) return 0;
3476     /* TlsGetValue clears last error, so set it again here */
3477     SetLastError(lpwite->dwError);
3478     return lpwite->dwError;
3479 }
3480
3481
3482 /***********************************************************************
3483  *           INTERNET_WorkerThreadFunc (internal)
3484  *
3485  * Worker thread execution function
3486  *
3487  * RETURNS
3488  *
3489  */
3490 static DWORD CALLBACK INTERNET_WorkerThreadFunc(LPVOID lpvParam)
3491 {
3492     LPWORKREQUEST lpRequest = lpvParam;
3493     WORKREQUEST workRequest;
3494
3495     TRACE("\n");
3496
3497     workRequest = *lpRequest;
3498     HeapFree(GetProcessHeap(), 0, lpRequest);
3499
3500     workRequest.asyncproc(&workRequest);
3501     WININET_Release( workRequest.hdr );
3502
3503     if (g_dwTlsErrIndex != TLS_OUT_OF_INDEXES)
3504     {
3505         HeapFree(GetProcessHeap(), 0, TlsGetValue(g_dwTlsErrIndex));
3506         TlsSetValue(g_dwTlsErrIndex, NULL);
3507     }
3508     return TRUE;
3509 }
3510
3511
3512 /***********************************************************************
3513  *           INTERNET_AsyncCall (internal)
3514  *
3515  * Retrieves work request from queue
3516  *
3517  * RETURNS
3518  *
3519  */
3520 DWORD INTERNET_AsyncCall(LPWORKREQUEST lpWorkRequest)
3521 {
3522     BOOL bSuccess;
3523     LPWORKREQUEST lpNewRequest;
3524
3525     TRACE("\n");
3526
3527     lpNewRequest = HeapAlloc(GetProcessHeap(), 0, sizeof(WORKREQUEST));
3528     if (!lpNewRequest)
3529         return ERROR_OUTOFMEMORY;
3530
3531     *lpNewRequest = *lpWorkRequest;
3532
3533     bSuccess = QueueUserWorkItem(INTERNET_WorkerThreadFunc, lpNewRequest, WT_EXECUTELONGFUNCTION);
3534     if (!bSuccess)
3535     {
3536         HeapFree(GetProcessHeap(), 0, lpNewRequest);
3537         return ERROR_INTERNET_ASYNC_THREAD_FAILED;
3538     }
3539
3540     return ERROR_SUCCESS;
3541 }
3542
3543
3544 /***********************************************************************
3545  *          INTERNET_GetResponseBuffer  (internal)
3546  *
3547  * RETURNS
3548  *
3549  */
3550 LPSTR INTERNET_GetResponseBuffer(void)
3551 {
3552     LPWITHREADERROR lpwite = TlsGetValue(g_dwTlsErrIndex);
3553     if (!lpwite)
3554         lpwite = INTERNET_AllocThreadError();
3555     TRACE("\n");
3556     return lpwite->response;
3557 }
3558
3559 /***********************************************************************
3560  *           INTERNET_GetNextLine  (internal)
3561  *
3562  * Parse next line in directory string listing
3563  *
3564  * RETURNS
3565  *   Pointer to beginning of next line
3566  *   NULL on failure
3567  *
3568  */
3569
3570 LPSTR INTERNET_GetNextLine(INT nSocket, LPDWORD dwLen)
3571 {
3572     struct pollfd pfd;
3573     BOOL bSuccess = FALSE;
3574     INT nRecv = 0;
3575     LPSTR lpszBuffer = INTERNET_GetResponseBuffer();
3576
3577     TRACE("\n");
3578
3579     pfd.fd = nSocket;
3580     pfd.events = POLLIN;
3581
3582     while (nRecv < MAX_REPLY_LEN)
3583     {
3584         if (poll(&pfd,1, RESPONSE_TIMEOUT * 1000) > 0)
3585         {
3586             if (recv(nSocket, &lpszBuffer[nRecv], 1, 0) <= 0)
3587             {
3588                 INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS);
3589                 goto lend;
3590             }
3591
3592             if (lpszBuffer[nRecv] == '\n')
3593             {
3594                 bSuccess = TRUE;
3595                 break;
3596             }
3597             if (lpszBuffer[nRecv] != '\r')
3598                 nRecv++;
3599         }
3600         else
3601         {
3602             INTERNET_SetLastError(ERROR_INTERNET_TIMEOUT);
3603             goto lend;
3604         }
3605     }
3606
3607 lend:
3608     if (bSuccess)
3609     {
3610         lpszBuffer[nRecv] = '\0';
3611         *dwLen = nRecv - 1;
3612         TRACE(":%d %s\n", nRecv, lpszBuffer);
3613         return lpszBuffer;
3614     }
3615     else
3616     {
3617         return NULL;
3618     }
3619 }
3620
3621 /**********************************************************
3622  *      InternetQueryDataAvailable (WININET.@)
3623  *
3624  * Determines how much data is available to be read.
3625  *
3626  * RETURNS
3627  *   TRUE on success, FALSE if an error occurred. If
3628  *   INTERNET_FLAG_ASYNC was specified in InternetOpen, and
3629  *   no data is presently available, FALSE is returned with
3630  *   the last error ERROR_IO_PENDING; a callback with status
3631  *   INTERNET_STATUS_REQUEST_COMPLETE will be sent when more
3632  *   data is available.
3633  */
3634 BOOL WINAPI InternetQueryDataAvailable( HINTERNET hFile,
3635                                 LPDWORD lpdwNumberOfBytesAvailble,
3636                                 DWORD dwFlags, DWORD_PTR dwContext)
3637 {
3638     object_header_t *hdr;
3639     DWORD res;
3640
3641     TRACE("(%p %p %x %lx)\n", hFile, lpdwNumberOfBytesAvailble, dwFlags, dwContext);
3642
3643     hdr = WININET_GetObject( hFile );
3644     if (!hdr) {
3645         SetLastError(ERROR_INVALID_HANDLE);
3646         return FALSE;
3647     }
3648
3649     if(hdr->vtbl->QueryDataAvailable) {
3650         res = hdr->vtbl->QueryDataAvailable(hdr, lpdwNumberOfBytesAvailble, dwFlags, dwContext);
3651     }else {
3652         WARN("wrong handle\n");
3653         res = ERROR_INTERNET_INCORRECT_HANDLE_TYPE;
3654     }
3655
3656     WININET_Release(hdr);
3657
3658     if(res != ERROR_SUCCESS)
3659         SetLastError(res);
3660     return res == ERROR_SUCCESS;
3661 }
3662
3663
3664 /***********************************************************************
3665  *      InternetLockRequestFile (WININET.@)
3666  */
3667 BOOL WINAPI InternetLockRequestFile( HINTERNET hInternet, HANDLE
3668 *lphLockReqHandle)
3669 {
3670     FIXME("STUB\n");
3671     return FALSE;
3672 }
3673
3674 BOOL WINAPI InternetUnlockRequestFile( HANDLE hLockHandle)
3675 {
3676     FIXME("STUB\n");
3677     return FALSE;
3678 }
3679
3680
3681 /***********************************************************************
3682  *      InternetAutodial (WININET.@)
3683  *
3684  * On windows this function is supposed to dial the default internet
3685  * connection. We don't want to have Wine dial out to the internet so
3686  * we return TRUE by default. It might be nice to check if we are connected.
3687  *
3688  * RETURNS
3689  *   TRUE on success
3690  *   FALSE on failure
3691  *
3692  */
3693 BOOL WINAPI InternetAutodial(DWORD dwFlags, HWND hwndParent)
3694 {
3695     FIXME("STUB\n");
3696
3697     /* Tell that we are connected to the internet. */
3698     return TRUE;
3699 }
3700
3701 /***********************************************************************
3702  *      InternetAutodialHangup (WININET.@)
3703  *
3704  * Hangs up a connection made with InternetAutodial
3705  *
3706  * PARAM
3707  *    dwReserved
3708  * RETURNS
3709  *   TRUE on success
3710  *   FALSE on failure
3711  *
3712  */
3713 BOOL WINAPI InternetAutodialHangup(DWORD dwReserved)
3714 {
3715     FIXME("STUB\n");
3716
3717     /* we didn't dial, we don't disconnect */
3718     return TRUE;
3719 }
3720
3721 /***********************************************************************
3722  *      InternetCombineUrlA (WININET.@)
3723  *
3724  * Combine a base URL with a relative URL
3725  *
3726  * RETURNS
3727  *   TRUE on success
3728  *   FALSE on failure
3729  *
3730  */
3731
3732 BOOL WINAPI InternetCombineUrlA(LPCSTR lpszBaseUrl, LPCSTR lpszRelativeUrl,
3733                                 LPSTR lpszBuffer, LPDWORD lpdwBufferLength,
3734                                 DWORD dwFlags)
3735 {
3736     HRESULT hr=S_OK;
3737
3738     TRACE("(%s, %s, %p, %p, 0x%08x)\n", debugstr_a(lpszBaseUrl), debugstr_a(lpszRelativeUrl), lpszBuffer, lpdwBufferLength, dwFlags);
3739
3740     /* Flip this bit to correspond to URL_ESCAPE_UNSAFE */
3741     dwFlags ^= ICU_NO_ENCODE;
3742     hr=UrlCombineA(lpszBaseUrl,lpszRelativeUrl,lpszBuffer,lpdwBufferLength,dwFlags);
3743
3744     return (hr==S_OK);
3745 }
3746
3747 /***********************************************************************
3748  *      InternetCombineUrlW (WININET.@)
3749  *
3750  * Combine a base URL with a relative URL
3751  *
3752  * RETURNS
3753  *   TRUE on success
3754  *   FALSE on failure
3755  *
3756  */
3757
3758 BOOL WINAPI InternetCombineUrlW(LPCWSTR lpszBaseUrl, LPCWSTR lpszRelativeUrl,
3759                                 LPWSTR lpszBuffer, LPDWORD lpdwBufferLength,
3760                                 DWORD dwFlags)
3761 {
3762     HRESULT hr=S_OK;
3763
3764     TRACE("(%s, %s, %p, %p, 0x%08x)\n", debugstr_w(lpszBaseUrl), debugstr_w(lpszRelativeUrl), lpszBuffer, lpdwBufferLength, dwFlags);
3765
3766     /* Flip this bit to correspond to URL_ESCAPE_UNSAFE */
3767     dwFlags ^= ICU_NO_ENCODE;
3768     hr=UrlCombineW(lpszBaseUrl,lpszRelativeUrl,lpszBuffer,lpdwBufferLength,dwFlags);
3769
3770     return (hr==S_OK);
3771 }
3772
3773 /* max port num is 65535 => 5 digits */
3774 #define MAX_WORD_DIGITS 5
3775
3776 #define URL_GET_COMP_LENGTH(url, component) ((url)->dw##component##Length ? \
3777     (url)->dw##component##Length : strlenW((url)->lpsz##component))
3778 #define URL_GET_COMP_LENGTHA(url, component) ((url)->dw##component##Length ? \
3779     (url)->dw##component##Length : strlen((url)->lpsz##component))
3780
3781 static BOOL url_uses_default_port(INTERNET_SCHEME nScheme, INTERNET_PORT nPort)
3782 {
3783     if ((nScheme == INTERNET_SCHEME_HTTP) &&
3784         (nPort == INTERNET_DEFAULT_HTTP_PORT))
3785         return TRUE;
3786     if ((nScheme == INTERNET_SCHEME_HTTPS) &&
3787         (nPort == INTERNET_DEFAULT_HTTPS_PORT))
3788         return TRUE;
3789     if ((nScheme == INTERNET_SCHEME_FTP) &&
3790         (nPort == INTERNET_DEFAULT_FTP_PORT))
3791         return TRUE;
3792     if ((nScheme == INTERNET_SCHEME_GOPHER) &&
3793         (nPort == INTERNET_DEFAULT_GOPHER_PORT))
3794         return TRUE;
3795
3796     if (nPort == INTERNET_INVALID_PORT_NUMBER)
3797         return TRUE;
3798
3799     return FALSE;
3800 }
3801
3802 /* opaque urls do not fit into the standard url hierarchy and don't have
3803  * two following slashes */
3804 static inline BOOL scheme_is_opaque(INTERNET_SCHEME nScheme)
3805 {
3806     return (nScheme != INTERNET_SCHEME_FTP) &&
3807            (nScheme != INTERNET_SCHEME_GOPHER) &&
3808            (nScheme != INTERNET_SCHEME_HTTP) &&
3809            (nScheme != INTERNET_SCHEME_HTTPS) &&
3810            (nScheme != INTERNET_SCHEME_FILE);
3811 }
3812
3813 static LPCWSTR INTERNET_GetSchemeString(INTERNET_SCHEME scheme)
3814 {
3815     int index;
3816     if (scheme < INTERNET_SCHEME_FIRST)
3817         return NULL;
3818     index = scheme - INTERNET_SCHEME_FIRST;
3819     if (index >= sizeof(url_schemes)/sizeof(url_schemes[0]))
3820         return NULL;
3821     return (LPCWSTR)url_schemes[index];
3822 }
3823
3824 /* we can calculate using ansi strings because we're just
3825  * calculating string length, not size
3826  */
3827 static BOOL calc_url_length(LPURL_COMPONENTSW lpUrlComponents,
3828                             LPDWORD lpdwUrlLength)
3829 {
3830     INTERNET_SCHEME nScheme;
3831
3832     *lpdwUrlLength = 0;
3833
3834     if (lpUrlComponents->lpszScheme)
3835     {
3836         DWORD dwLen = URL_GET_COMP_LENGTH(lpUrlComponents, Scheme);
3837         *lpdwUrlLength += dwLen;
3838         nScheme = GetInternetSchemeW(lpUrlComponents->lpszScheme, dwLen);
3839     }
3840     else
3841     {
3842         LPCWSTR scheme;
3843
3844         nScheme = lpUrlComponents->nScheme;
3845
3846         if (nScheme == INTERNET_SCHEME_DEFAULT)
3847             nScheme = INTERNET_SCHEME_HTTP;
3848         scheme = INTERNET_GetSchemeString(nScheme);
3849         *lpdwUrlLength += strlenW(scheme);
3850     }
3851
3852     (*lpdwUrlLength)++; /* ':' */
3853     if (!scheme_is_opaque(nScheme) || lpUrlComponents->lpszHostName)
3854         *lpdwUrlLength += strlen("//");
3855
3856     if (lpUrlComponents->lpszUserName)
3857     {
3858         *lpdwUrlLength += URL_GET_COMP_LENGTH(lpUrlComponents, UserName);
3859         *lpdwUrlLength += strlen("@");
3860     }
3861     else
3862     {
3863         if (lpUrlComponents->lpszPassword)
3864         {
3865             INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
3866             return FALSE;
3867         }
3868     }
3869
3870     if (lpUrlComponents->lpszPassword)
3871     {
3872         *lpdwUrlLength += strlen(":");
3873         *lpdwUrlLength += URL_GET_COMP_LENGTH(lpUrlComponents, Password);
3874     }
3875
3876     if (lpUrlComponents->lpszHostName)
3877     {
3878         *lpdwUrlLength += URL_GET_COMP_LENGTH(lpUrlComponents, HostName);
3879
3880         if (!url_uses_default_port(nScheme, lpUrlComponents->nPort))
3881         {
3882             char szPort[MAX_WORD_DIGITS+1];
3883
3884             sprintf(szPort, "%d", lpUrlComponents->nPort);
3885             *lpdwUrlLength += strlen(szPort);
3886             *lpdwUrlLength += strlen(":");
3887         }
3888
3889         if (lpUrlComponents->lpszUrlPath && *lpUrlComponents->lpszUrlPath != '/')
3890             (*lpdwUrlLength)++; /* '/' */
3891     }
3892
3893     if (lpUrlComponents->lpszUrlPath)
3894         *lpdwUrlLength += URL_GET_COMP_LENGTH(lpUrlComponents, UrlPath);
3895
3896     if (lpUrlComponents->lpszExtraInfo)
3897         *lpdwUrlLength += URL_GET_COMP_LENGTH(lpUrlComponents, ExtraInfo);
3898
3899     return TRUE;
3900 }
3901
3902 static void convert_urlcomp_atow(LPURL_COMPONENTSA lpUrlComponents, LPURL_COMPONENTSW urlCompW)
3903 {
3904     INT len;
3905
3906     ZeroMemory(urlCompW, sizeof(URL_COMPONENTSW));
3907
3908     urlCompW->dwStructSize = sizeof(URL_COMPONENTSW);
3909     urlCompW->dwSchemeLength = lpUrlComponents->dwSchemeLength;
3910     urlCompW->nScheme = lpUrlComponents->nScheme;
3911     urlCompW->dwHostNameLength = lpUrlComponents->dwHostNameLength;
3912     urlCompW->nPort = lpUrlComponents->nPort;
3913     urlCompW->dwUserNameLength = lpUrlComponents->dwUserNameLength;
3914     urlCompW->dwPasswordLength = lpUrlComponents->dwPasswordLength;
3915     urlCompW->dwUrlPathLength = lpUrlComponents->dwUrlPathLength;
3916     urlCompW->dwExtraInfoLength = lpUrlComponents->dwExtraInfoLength;
3917
3918     if (lpUrlComponents->lpszScheme)
3919     {
3920         len = URL_GET_COMP_LENGTHA(lpUrlComponents, Scheme) + 1;
3921         urlCompW->lpszScheme = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
3922         MultiByteToWideChar(CP_ACP, 0, lpUrlComponents->lpszScheme,
3923                             -1, urlCompW->lpszScheme, len);
3924     }
3925
3926     if (lpUrlComponents->lpszHostName)
3927     {
3928         len = URL_GET_COMP_LENGTHA(lpUrlComponents, HostName) + 1;
3929         urlCompW->lpszHostName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
3930         MultiByteToWideChar(CP_ACP, 0, lpUrlComponents->lpszHostName,
3931                             -1, urlCompW->lpszHostName, len);
3932     }
3933
3934     if (lpUrlComponents->lpszUserName)
3935     {
3936         len = URL_GET_COMP_LENGTHA(lpUrlComponents, UserName) + 1;
3937         urlCompW->lpszUserName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
3938         MultiByteToWideChar(CP_ACP, 0, lpUrlComponents->lpszUserName,
3939                             -1, urlCompW->lpszUserName, len);
3940     }
3941
3942     if (lpUrlComponents->lpszPassword)
3943     {
3944         len = URL_GET_COMP_LENGTHA(lpUrlComponents, Password) + 1;
3945         urlCompW->lpszPassword = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
3946         MultiByteToWideChar(CP_ACP, 0, lpUrlComponents->lpszPassword,
3947                             -1, urlCompW->lpszPassword, len);
3948     }
3949
3950     if (lpUrlComponents->lpszUrlPath)
3951     {
3952         len = URL_GET_COMP_LENGTHA(lpUrlComponents, UrlPath) + 1;
3953         urlCompW->lpszUrlPath = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
3954         MultiByteToWideChar(CP_ACP, 0, lpUrlComponents->lpszUrlPath,
3955                             -1, urlCompW->lpszUrlPath, len);
3956     }
3957
3958     if (lpUrlComponents->lpszExtraInfo)
3959     {
3960         len = URL_GET_COMP_LENGTHA(lpUrlComponents, ExtraInfo) + 1;
3961         urlCompW->lpszExtraInfo = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
3962         MultiByteToWideChar(CP_ACP, 0, lpUrlComponents->lpszExtraInfo,
3963                             -1, urlCompW->lpszExtraInfo, len);
3964     }
3965 }
3966
3967 /***********************************************************************
3968  *      InternetCreateUrlA (WININET.@)
3969  *
3970  * See InternetCreateUrlW.
3971  */
3972 BOOL WINAPI InternetCreateUrlA(LPURL_COMPONENTSA lpUrlComponents, DWORD dwFlags,
3973                                LPSTR lpszUrl, LPDWORD lpdwUrlLength)
3974 {
3975     BOOL ret;
3976     LPWSTR urlW = NULL;
3977     URL_COMPONENTSW urlCompW;
3978
3979     TRACE("(%p,%d,%p,%p)\n", lpUrlComponents, dwFlags, lpszUrl, lpdwUrlLength);
3980
3981     if (!lpUrlComponents || lpUrlComponents->dwStructSize != sizeof(URL_COMPONENTSW) || !lpdwUrlLength)
3982     {
3983         SetLastError(ERROR_INVALID_PARAMETER);
3984         return FALSE;
3985     }
3986
3987     convert_urlcomp_atow(lpUrlComponents, &urlCompW);
3988
3989     if (lpszUrl)
3990         urlW = HeapAlloc(GetProcessHeap(), 0, *lpdwUrlLength * sizeof(WCHAR));
3991
3992     ret = InternetCreateUrlW(&urlCompW, dwFlags, urlW, lpdwUrlLength);
3993
3994     if (!ret && (GetLastError() == ERROR_INSUFFICIENT_BUFFER))
3995         *lpdwUrlLength /= sizeof(WCHAR);
3996
3997     /* on success, lpdwUrlLength points to the size of urlW in WCHARS
3998     * minus one, so add one to leave room for NULL terminator
3999     */
4000     if (ret)
4001         WideCharToMultiByte(CP_ACP, 0, urlW, -1, lpszUrl, *lpdwUrlLength + 1, NULL, NULL);
4002
4003     HeapFree(GetProcessHeap(), 0, urlCompW.lpszScheme);
4004     HeapFree(GetProcessHeap(), 0, urlCompW.lpszHostName);
4005     HeapFree(GetProcessHeap(), 0, urlCompW.lpszUserName);
4006     HeapFree(GetProcessHeap(), 0, urlCompW.lpszPassword);
4007     HeapFree(GetProcessHeap(), 0, urlCompW.lpszUrlPath);
4008     HeapFree(GetProcessHeap(), 0, urlCompW.lpszExtraInfo);
4009     HeapFree(GetProcessHeap(), 0, urlW);
4010
4011     return ret;
4012 }
4013
4014 /***********************************************************************
4015  *      InternetCreateUrlW (WININET.@)
4016  *
4017  * Creates a URL from its component parts.
4018  *
4019  * PARAMS
4020  *  lpUrlComponents [I] URL Components.
4021  *  dwFlags         [I] Flags. See notes.
4022  *  lpszUrl         [I] Buffer in which to store the created URL.
4023  *  lpdwUrlLength   [I/O] On input, the length of the buffer pointed to by
4024  *                        lpszUrl in characters. On output, the number of bytes
4025  *                        required to store the URL including terminator.
4026  *
4027  * NOTES
4028  *
4029  * The dwFlags parameter can be zero or more of the following:
4030  *|ICU_ESCAPE - Generates escape sequences for unsafe characters in the path and extra info of the URL.
4031  *
4032  * RETURNS
4033  *   TRUE on success
4034  *   FALSE on failure
4035  *
4036  */
4037 BOOL WINAPI InternetCreateUrlW(LPURL_COMPONENTSW lpUrlComponents, DWORD dwFlags,
4038                                LPWSTR lpszUrl, LPDWORD lpdwUrlLength)
4039 {
4040     DWORD dwLen;
4041     INTERNET_SCHEME nScheme;
4042
4043     static const WCHAR slashSlashW[] = {'/','/'};
4044     static const WCHAR percentD[] = {'%','d',0};
4045
4046     TRACE("(%p,%d,%p,%p)\n", lpUrlComponents, dwFlags, lpszUrl, lpdwUrlLength);
4047
4048     if (!lpUrlComponents || lpUrlComponents->dwStructSize != sizeof(URL_COMPONENTSW) || !lpdwUrlLength)
4049     {
4050         INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
4051         return FALSE;
4052     }
4053
4054     if (!calc_url_length(lpUrlComponents, &dwLen))
4055         return FALSE;
4056
4057     if (!lpszUrl || *lpdwUrlLength < dwLen)
4058     {
4059         *lpdwUrlLength = (dwLen + 1) * sizeof(WCHAR);
4060         INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
4061         return FALSE;
4062     }
4063
4064     *lpdwUrlLength = dwLen;
4065     lpszUrl[0] = 0x00;
4066
4067     dwLen = 0;
4068
4069     if (lpUrlComponents->lpszScheme)
4070     {
4071         dwLen = URL_GET_COMP_LENGTH(lpUrlComponents, Scheme);
4072         memcpy(lpszUrl, lpUrlComponents->lpszScheme, dwLen * sizeof(WCHAR));
4073         lpszUrl += dwLen;
4074
4075         nScheme = GetInternetSchemeW(lpUrlComponents->lpszScheme, dwLen);
4076     }
4077     else
4078     {
4079         LPCWSTR scheme;
4080         nScheme = lpUrlComponents->nScheme;
4081
4082         if (nScheme == INTERNET_SCHEME_DEFAULT)
4083             nScheme = INTERNET_SCHEME_HTTP;
4084
4085         scheme = INTERNET_GetSchemeString(nScheme);
4086         dwLen = strlenW(scheme);
4087         memcpy(lpszUrl, scheme, dwLen * sizeof(WCHAR));
4088         lpszUrl += dwLen;
4089     }
4090
4091     /* all schemes are followed by at least a colon */
4092     *lpszUrl = ':';
4093     lpszUrl++;
4094
4095     if (!scheme_is_opaque(nScheme) || lpUrlComponents->lpszHostName)
4096     {
4097         memcpy(lpszUrl, slashSlashW, sizeof(slashSlashW));
4098         lpszUrl += sizeof(slashSlashW)/sizeof(slashSlashW[0]);
4099     }
4100
4101     if (lpUrlComponents->lpszUserName)
4102     {
4103         dwLen = URL_GET_COMP_LENGTH(lpUrlComponents, UserName);
4104         memcpy(lpszUrl, lpUrlComponents->lpszUserName, dwLen * sizeof(WCHAR));
4105         lpszUrl += dwLen;
4106
4107         if (lpUrlComponents->lpszPassword)
4108         {
4109             *lpszUrl = ':';
4110             lpszUrl++;
4111
4112             dwLen = URL_GET_COMP_LENGTH(lpUrlComponents, Password);
4113             memcpy(lpszUrl, lpUrlComponents->lpszPassword, dwLen * sizeof(WCHAR));
4114             lpszUrl += dwLen;
4115         }
4116
4117         *lpszUrl = '@';
4118         lpszUrl++;
4119     }
4120
4121     if (lpUrlComponents->lpszHostName)
4122     {
4123         dwLen = URL_GET_COMP_LENGTH(lpUrlComponents, HostName);
4124         memcpy(lpszUrl, lpUrlComponents->lpszHostName, dwLen * sizeof(WCHAR));
4125         lpszUrl += dwLen;
4126
4127         if (!url_uses_default_port(nScheme, lpUrlComponents->nPort))
4128         {
4129             WCHAR szPort[MAX_WORD_DIGITS+1];
4130
4131             sprintfW(szPort, percentD, lpUrlComponents->nPort);
4132             *lpszUrl = ':';
4133             lpszUrl++;
4134             dwLen = strlenW(szPort);
4135             memcpy(lpszUrl, szPort, dwLen * sizeof(WCHAR));
4136             lpszUrl += dwLen;
4137         }
4138
4139         /* add slash between hostname and path if necessary */
4140         if (lpUrlComponents->lpszUrlPath && *lpUrlComponents->lpszUrlPath != '/')
4141         {
4142             *lpszUrl = '/';
4143             lpszUrl++;
4144         }
4145     }
4146
4147     if (lpUrlComponents->lpszUrlPath)
4148     {
4149         dwLen = URL_GET_COMP_LENGTH(lpUrlComponents, UrlPath);
4150         memcpy(lpszUrl, lpUrlComponents->lpszUrlPath, dwLen * sizeof(WCHAR));
4151         lpszUrl += dwLen;
4152     }
4153
4154     if (lpUrlComponents->lpszExtraInfo)
4155     {
4156         dwLen = URL_GET_COMP_LENGTH(lpUrlComponents, ExtraInfo);
4157         memcpy(lpszUrl, lpUrlComponents->lpszExtraInfo, dwLen * sizeof(WCHAR));
4158         lpszUrl += dwLen;
4159     }
4160
4161     *lpszUrl = '\0';
4162
4163     return TRUE;
4164 }
4165
4166 /***********************************************************************
4167  *      InternetConfirmZoneCrossingA (WININET.@)
4168  *
4169  */
4170 DWORD WINAPI InternetConfirmZoneCrossingA( HWND hWnd, LPSTR szUrlPrev, LPSTR szUrlNew, BOOL bPost )
4171 {
4172     FIXME("(%p, %s, %s, %x) stub\n", hWnd, debugstr_a(szUrlPrev), debugstr_a(szUrlNew), bPost);
4173     return ERROR_SUCCESS;
4174 }
4175
4176 /***********************************************************************
4177  *      InternetConfirmZoneCrossingW (WININET.@)
4178  *
4179  */
4180 DWORD WINAPI InternetConfirmZoneCrossingW( HWND hWnd, LPWSTR szUrlPrev, LPWSTR szUrlNew, BOOL bPost )
4181 {
4182     FIXME("(%p, %s, %s, %x) stub\n", hWnd, debugstr_w(szUrlPrev), debugstr_w(szUrlNew), bPost);
4183     return ERROR_SUCCESS;
4184 }
4185
4186 static DWORD zone_preference = 3;
4187
4188 /***********************************************************************
4189  *      PrivacySetZonePreferenceW (WININET.@)
4190  */
4191 DWORD WINAPI PrivacySetZonePreferenceW( DWORD zone, DWORD type, DWORD template, LPCWSTR preference )
4192 {
4193     FIXME( "%x %x %x %s: stub\n", zone, type, template, debugstr_w(preference) );
4194
4195     zone_preference = template;
4196     return 0;
4197 }
4198
4199 /***********************************************************************
4200  *      PrivacyGetZonePreferenceW (WININET.@)
4201  */
4202 DWORD WINAPI PrivacyGetZonePreferenceW( DWORD zone, DWORD type, LPDWORD template,
4203                                         LPWSTR preference, LPDWORD length )
4204 {
4205     FIXME( "%x %x %p %p %p: stub\n", zone, type, template, preference, length );
4206
4207     if (template) *template = zone_preference;
4208     return 0;
4209 }
4210
4211 DWORD WINAPI InternetDialA( HWND hwndParent, LPSTR lpszConnectoid, DWORD dwFlags,
4212                             DWORD_PTR* lpdwConnection, DWORD dwReserved )
4213 {
4214     FIXME("(%p, %p, 0x%08x, %p, 0x%08x) stub\n", hwndParent, lpszConnectoid, dwFlags,
4215           lpdwConnection, dwReserved);
4216     return ERROR_SUCCESS;
4217 }
4218
4219 DWORD WINAPI InternetDialW( HWND hwndParent, LPWSTR lpszConnectoid, DWORD dwFlags,
4220                             DWORD_PTR* lpdwConnection, DWORD dwReserved )
4221 {
4222     FIXME("(%p, %p, 0x%08x, %p, 0x%08x) stub\n", hwndParent, lpszConnectoid, dwFlags,
4223           lpdwConnection, dwReserved);
4224     return ERROR_SUCCESS;
4225 }
4226
4227 BOOL WINAPI InternetGoOnlineA( LPSTR lpszURL, HWND hwndParent, DWORD dwReserved )
4228 {
4229     FIXME("(%s, %p, 0x%08x) stub\n", debugstr_a(lpszURL), hwndParent, dwReserved);
4230     return TRUE;
4231 }
4232
4233 BOOL WINAPI InternetGoOnlineW( LPWSTR lpszURL, HWND hwndParent, DWORD dwReserved )
4234 {
4235     FIXME("(%s, %p, 0x%08x) stub\n", debugstr_w(lpszURL), hwndParent, dwReserved);
4236     return TRUE;
4237 }
4238
4239 DWORD WINAPI InternetHangUp( DWORD_PTR dwConnection, DWORD dwReserved )
4240 {
4241     FIXME("(0x%08lx, 0x%08x) stub\n", dwConnection, dwReserved);
4242     return ERROR_SUCCESS;
4243 }
4244
4245 BOOL WINAPI CreateMD5SSOHash( PWSTR pszChallengeInfo, PWSTR pwszRealm, PWSTR pwszTarget,
4246                               PBYTE pbHexHash )
4247 {
4248     FIXME("(%s, %s, %s, %p) stub\n", debugstr_w(pszChallengeInfo), debugstr_w(pwszRealm),
4249           debugstr_w(pwszTarget), pbHexHash);
4250     return FALSE;
4251 }
4252
4253 BOOL WINAPI ResumeSuspendedDownload( HINTERNET hInternet, DWORD dwError )
4254 {
4255     FIXME("(%p, 0x%08x) stub\n", hInternet, dwError);
4256     return FALSE;
4257 }
4258
4259 BOOL WINAPI InternetQueryFortezzaStatus(DWORD *a, DWORD_PTR b)
4260 {
4261     FIXME("(%p, %08lx) stub\n", a, b);
4262     return 0;
4263 }