wined3d: Use a lookup table in select_card_ati_binary().
[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 + 1) * sizeof(WCHAR));
1374   MultiByteToWideChar(CP_ACP,0,lpszUrl,dwUrlLength,lpwszUrl,nLength + 1);
1375   lpwszUrl[nLength] = '\0';
1376
1377   memset(&UCW,0,sizeof(UCW));
1378   UCW.dwStructSize = sizeof(URL_COMPONENTSW);
1379   if (lpUrlComponents->dwHostNameLength)
1380   {
1381     UCW.dwHostNameLength = lpUrlComponents->dwHostNameLength;
1382     if (lpUrlComponents->lpszHostName)
1383     {
1384       hostname = HeapAlloc(GetProcessHeap(), 0, UCW.dwHostNameLength * sizeof(WCHAR));
1385       UCW.lpszHostName = hostname;
1386     }
1387   }
1388   if (lpUrlComponents->dwUserNameLength)
1389   {
1390     UCW.dwUserNameLength = lpUrlComponents->dwUserNameLength;
1391     if (lpUrlComponents->lpszUserName)
1392     {
1393       username = HeapAlloc(GetProcessHeap(), 0, UCW.dwUserNameLength * sizeof(WCHAR));
1394       UCW.lpszUserName = username;
1395     }
1396   }
1397   if (lpUrlComponents->dwPasswordLength)
1398   {
1399     UCW.dwPasswordLength = lpUrlComponents->dwPasswordLength;
1400     if (lpUrlComponents->lpszPassword)
1401     {
1402       password = HeapAlloc(GetProcessHeap(), 0, UCW.dwPasswordLength * sizeof(WCHAR));
1403       UCW.lpszPassword = password;
1404     }
1405   }
1406   if (lpUrlComponents->dwUrlPathLength)
1407   {
1408     UCW.dwUrlPathLength = lpUrlComponents->dwUrlPathLength;
1409     if (lpUrlComponents->lpszUrlPath)
1410     {
1411       path = HeapAlloc(GetProcessHeap(), 0, UCW.dwUrlPathLength * sizeof(WCHAR));
1412       UCW.lpszUrlPath = path;
1413     }
1414   }
1415   if (lpUrlComponents->dwSchemeLength)
1416   {
1417     UCW.dwSchemeLength = lpUrlComponents->dwSchemeLength;
1418     if (lpUrlComponents->lpszScheme)
1419     {
1420       scheme = HeapAlloc(GetProcessHeap(), 0, UCW.dwSchemeLength * sizeof(WCHAR));
1421       UCW.lpszScheme = scheme;
1422     }
1423   }
1424   if (lpUrlComponents->dwExtraInfoLength)
1425   {
1426     UCW.dwExtraInfoLength = lpUrlComponents->dwExtraInfoLength;
1427     if (lpUrlComponents->lpszExtraInfo)
1428     {
1429       extra = HeapAlloc(GetProcessHeap(), 0, UCW.dwExtraInfoLength * sizeof(WCHAR));
1430       UCW.lpszExtraInfo = extra;
1431     }
1432   }
1433   if ((ret = InternetCrackUrlW(lpwszUrl, nLength, dwFlags, &UCW)))
1434   {
1435     ConvertUrlComponentValue(&lpUrlComponents->lpszHostName, &lpUrlComponents->dwHostNameLength,
1436                              UCW.lpszHostName, UCW.dwHostNameLength, lpszUrl, lpwszUrl);
1437     ConvertUrlComponentValue(&lpUrlComponents->lpszUserName, &lpUrlComponents->dwUserNameLength,
1438                              UCW.lpszUserName, UCW.dwUserNameLength, lpszUrl, lpwszUrl);
1439     ConvertUrlComponentValue(&lpUrlComponents->lpszPassword, &lpUrlComponents->dwPasswordLength,
1440                              UCW.lpszPassword, UCW.dwPasswordLength, lpszUrl, lpwszUrl);
1441     ConvertUrlComponentValue(&lpUrlComponents->lpszUrlPath, &lpUrlComponents->dwUrlPathLength,
1442                              UCW.lpszUrlPath, UCW.dwUrlPathLength, lpszUrl, lpwszUrl);
1443     ConvertUrlComponentValue(&lpUrlComponents->lpszScheme, &lpUrlComponents->dwSchemeLength,
1444                              UCW.lpszScheme, UCW.dwSchemeLength, lpszUrl, lpwszUrl);
1445     ConvertUrlComponentValue(&lpUrlComponents->lpszExtraInfo, &lpUrlComponents->dwExtraInfoLength,
1446                              UCW.lpszExtraInfo, UCW.dwExtraInfoLength, lpszUrl, lpwszUrl);
1447
1448     lpUrlComponents->nScheme = UCW.nScheme;
1449     lpUrlComponents->nPort = UCW.nPort;
1450
1451     TRACE("%s: scheme(%s) host(%s) path(%s) extra(%s)\n", debugstr_a(lpszUrl),
1452           debugstr_an(lpUrlComponents->lpszScheme, lpUrlComponents->dwSchemeLength),
1453           debugstr_an(lpUrlComponents->lpszHostName, lpUrlComponents->dwHostNameLength),
1454           debugstr_an(lpUrlComponents->lpszUrlPath, lpUrlComponents->dwUrlPathLength),
1455           debugstr_an(lpUrlComponents->lpszExtraInfo, lpUrlComponents->dwExtraInfoLength));
1456   }
1457   HeapFree(GetProcessHeap(), 0, lpwszUrl);
1458   HeapFree(GetProcessHeap(), 0, hostname);
1459   HeapFree(GetProcessHeap(), 0, username);
1460   HeapFree(GetProcessHeap(), 0, password);
1461   HeapFree(GetProcessHeap(), 0, path);
1462   HeapFree(GetProcessHeap(), 0, scheme);
1463   HeapFree(GetProcessHeap(), 0, extra);
1464   return ret;
1465 }
1466
1467 static const WCHAR url_schemes[][7] =
1468 {
1469     {'f','t','p',0},
1470     {'g','o','p','h','e','r',0},
1471     {'h','t','t','p',0},
1472     {'h','t','t','p','s',0},
1473     {'f','i','l','e',0},
1474     {'n','e','w','s',0},
1475     {'m','a','i','l','t','o',0},
1476     {'r','e','s',0},
1477 };
1478
1479 /***********************************************************************
1480  *           GetInternetSchemeW (internal)
1481  *
1482  * Get scheme of url
1483  *
1484  * RETURNS
1485  *    scheme on success
1486  *    INTERNET_SCHEME_UNKNOWN on failure
1487  *
1488  */
1489 static INTERNET_SCHEME GetInternetSchemeW(LPCWSTR lpszScheme, DWORD nMaxCmp)
1490 {
1491     int i;
1492
1493     TRACE("%s %d\n",debugstr_wn(lpszScheme, nMaxCmp), nMaxCmp);
1494
1495     if(lpszScheme==NULL)
1496         return INTERNET_SCHEME_UNKNOWN;
1497
1498     for (i = 0; i < sizeof(url_schemes)/sizeof(url_schemes[0]); i++)
1499         if (!strncmpW(lpszScheme, url_schemes[i], nMaxCmp))
1500             return INTERNET_SCHEME_FIRST + i;
1501
1502     return INTERNET_SCHEME_UNKNOWN;
1503 }
1504
1505 /***********************************************************************
1506  *           SetUrlComponentValueW (Internal)
1507  *
1508  * Helper function for InternetCrackUrlW
1509  *
1510  * PARAMS
1511  *     lppszComponent [O] Holds the returned string
1512  *     dwComponentLen [I] Holds the size of lppszComponent
1513  *                    [O] Holds the length of the string in lppszComponent without '\0'
1514  *     lpszStart      [I] Holds the string to copy from
1515  *     len            [I] Holds the length of lpszStart without '\0'
1516  *
1517  * RETURNS
1518  *    TRUE on success
1519  *    FALSE on failure
1520  *
1521  */
1522 static BOOL SetUrlComponentValueW(LPWSTR* lppszComponent, LPDWORD dwComponentLen, LPCWSTR lpszStart, DWORD len)
1523 {
1524     TRACE("%s (%d)\n", debugstr_wn(lpszStart,len), len);
1525
1526     if ( (*dwComponentLen == 0) && (*lppszComponent == NULL) )
1527         return FALSE;
1528
1529     if (*dwComponentLen != 0 || *lppszComponent == NULL)
1530     {
1531         if (*lppszComponent == NULL)
1532         {
1533             *lppszComponent = (LPWSTR)lpszStart;
1534             *dwComponentLen = len;
1535         }
1536         else
1537         {
1538             DWORD ncpylen = min((*dwComponentLen)-1, len);
1539             memcpy(*lppszComponent, lpszStart, ncpylen*sizeof(WCHAR));
1540             (*lppszComponent)[ncpylen] = '\0';
1541             *dwComponentLen = ncpylen;
1542         }
1543     }
1544
1545     return TRUE;
1546 }
1547
1548 /***********************************************************************
1549  *           InternetCrackUrlW   (WININET.@)
1550  *
1551  * Break up URL into its components
1552  *
1553  * RETURNS
1554  *    TRUE on success
1555  *    FALSE on failure
1556  */
1557 BOOL WINAPI InternetCrackUrlW(LPCWSTR lpszUrl_orig, DWORD dwUrlLength_orig, DWORD dwFlags,
1558                               LPURL_COMPONENTSW lpUC)
1559 {
1560   /*
1561    * RFC 1808
1562    * <protocol>:[//<net_loc>][/path][;<params>][?<query>][#<fragment>]
1563    *
1564    */
1565     LPCWSTR lpszParam    = NULL;
1566     BOOL  bIsAbsolute = FALSE;
1567     LPCWSTR lpszap, lpszUrl = lpszUrl_orig;
1568     LPCWSTR lpszcp = NULL;
1569     LPWSTR  lpszUrl_decode = NULL;
1570     DWORD dwUrlLength = dwUrlLength_orig;
1571
1572     TRACE("(%s %u %x %p)\n",
1573           lpszUrl ? debugstr_wn(lpszUrl, dwUrlLength ? dwUrlLength : strlenW(lpszUrl)) : "(null)",
1574           dwUrlLength, dwFlags, lpUC);
1575
1576     if (!lpszUrl_orig || !*lpszUrl_orig || !lpUC)
1577     {
1578         INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
1579         return FALSE;
1580     }
1581     if (!dwUrlLength) dwUrlLength = strlenW(lpszUrl);
1582
1583     if (dwFlags & ICU_DECODE)
1584     {
1585         WCHAR *url_tmp;
1586         DWORD len = dwUrlLength + 1;
1587
1588         if (!(url_tmp = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR))))
1589         {
1590             INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1591             return FALSE;
1592         }
1593         memcpy(url_tmp, lpszUrl_orig, dwUrlLength * sizeof(WCHAR));
1594         url_tmp[dwUrlLength] = 0;
1595         if (!(lpszUrl_decode = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR))))
1596         {
1597             HeapFree(GetProcessHeap(), 0, url_tmp);
1598             INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1599             return FALSE;
1600         }
1601         if (InternetCanonicalizeUrlW(url_tmp, lpszUrl_decode, &len, ICU_DECODE | ICU_NO_ENCODE))
1602         {
1603             dwUrlLength = len;
1604             lpszUrl = lpszUrl_decode;
1605         }
1606         HeapFree(GetProcessHeap(), 0, url_tmp);
1607     }
1608     lpszap = lpszUrl;
1609     
1610     /* Determine if the URI is absolute. */
1611     while (lpszap - lpszUrl < dwUrlLength)
1612     {
1613         if (isalnumW(*lpszap) || *lpszap == '+' || *lpszap == '.' || *lpszap == '-')
1614         {
1615             lpszap++;
1616             continue;
1617         }
1618         if ((*lpszap == ':') && (lpszap - lpszUrl >= 2))
1619         {
1620             bIsAbsolute = TRUE;
1621             lpszcp = lpszap;
1622         }
1623         else
1624         {
1625             lpszcp = lpszUrl; /* Relative url */
1626         }
1627
1628         break;
1629     }
1630
1631     lpUC->nScheme = INTERNET_SCHEME_UNKNOWN;
1632     lpUC->nPort = INTERNET_INVALID_PORT_NUMBER;
1633
1634     /* Parse <params> */
1635     lpszParam = memchrW(lpszap, ';', dwUrlLength - (lpszap - lpszUrl));
1636     if(!lpszParam)
1637         lpszParam = memchrW(lpszap, '?', dwUrlLength - (lpszap - lpszUrl));
1638     if(!lpszParam)
1639         lpszParam = memchrW(lpszap, '#', dwUrlLength - (lpszap - lpszUrl));
1640
1641     SetUrlComponentValueW(&lpUC->lpszExtraInfo, &lpUC->dwExtraInfoLength,
1642                           lpszParam, lpszParam ? dwUrlLength-(lpszParam-lpszUrl) : 0);
1643
1644     if (bIsAbsolute) /* Parse <protocol>:[//<net_loc>] */
1645     {
1646         LPCWSTR lpszNetLoc;
1647
1648         /* Get scheme first. */
1649         lpUC->nScheme = GetInternetSchemeW(lpszUrl, lpszcp - lpszUrl);
1650         SetUrlComponentValueW(&lpUC->lpszScheme, &lpUC->dwSchemeLength,
1651                                    lpszUrl, lpszcp - lpszUrl);
1652
1653         /* Eat ':' in protocol. */
1654         lpszcp++;
1655
1656         /* double slash indicates the net_loc portion is present */
1657         if ((lpszcp[0] == '/') && (lpszcp[1] == '/'))
1658         {
1659             lpszcp += 2;
1660
1661             lpszNetLoc = memchrW(lpszcp, '/', dwUrlLength - (lpszcp - lpszUrl));
1662             if (lpszParam)
1663             {
1664                 if (lpszNetLoc)
1665                     lpszNetLoc = min(lpszNetLoc, lpszParam);
1666                 else
1667                     lpszNetLoc = lpszParam;
1668             }
1669             else if (!lpszNetLoc)
1670                 lpszNetLoc = lpszcp + dwUrlLength-(lpszcp-lpszUrl);
1671
1672             /* Parse net-loc */
1673             if (lpszNetLoc)
1674             {
1675                 LPCWSTR lpszHost;
1676                 LPCWSTR lpszPort;
1677
1678                 /* [<user>[<:password>]@]<host>[:<port>] */
1679                 /* First find the user and password if they exist */
1680
1681                 lpszHost = memchrW(lpszcp, '@', dwUrlLength - (lpszcp - lpszUrl));
1682                 if (lpszHost == NULL || lpszHost > lpszNetLoc)
1683                 {
1684                     /* username and password not specified. */
1685                     SetUrlComponentValueW(&lpUC->lpszUserName, &lpUC->dwUserNameLength, NULL, 0);
1686                     SetUrlComponentValueW(&lpUC->lpszPassword, &lpUC->dwPasswordLength, NULL, 0);
1687                 }
1688                 else /* Parse out username and password */
1689                 {
1690                     LPCWSTR lpszUser = lpszcp;
1691                     LPCWSTR lpszPasswd = lpszHost;
1692
1693                     while (lpszcp < lpszHost)
1694                     {
1695                         if (*lpszcp == ':')
1696                             lpszPasswd = lpszcp;
1697
1698                         lpszcp++;
1699                     }
1700
1701                     SetUrlComponentValueW(&lpUC->lpszUserName, &lpUC->dwUserNameLength,
1702                                           lpszUser, lpszPasswd - lpszUser);
1703
1704                     if (lpszPasswd != lpszHost)
1705                         lpszPasswd++;
1706                     SetUrlComponentValueW(&lpUC->lpszPassword, &lpUC->dwPasswordLength,
1707                                           lpszPasswd == lpszHost ? NULL : lpszPasswd,
1708                                           lpszHost - lpszPasswd);
1709
1710                     lpszcp++; /* Advance to beginning of host */
1711                 }
1712
1713                 /* Parse <host><:port> */
1714
1715                 lpszHost = lpszcp;
1716                 lpszPort = lpszNetLoc;
1717
1718                 /* special case for res:// URLs: there is no port here, so the host is the
1719                    entire string up to the first '/' */
1720                 if(lpUC->nScheme==INTERNET_SCHEME_RES)
1721                 {
1722                     SetUrlComponentValueW(&lpUC->lpszHostName, &lpUC->dwHostNameLength,
1723                                           lpszHost, lpszPort - lpszHost);
1724                     lpszcp=lpszNetLoc;
1725                 }
1726                 else
1727                 {
1728                     while (lpszcp < lpszNetLoc)
1729                     {
1730                         if (*lpszcp == ':')
1731                             lpszPort = lpszcp;
1732
1733                         lpszcp++;
1734                     }
1735
1736                     /* If the scheme is "file" and the host is just one letter, it's not a host */
1737                     if(lpUC->nScheme==INTERNET_SCHEME_FILE && lpszPort <= lpszHost+1)
1738                     {
1739                         lpszcp=lpszHost;
1740                         SetUrlComponentValueW(&lpUC->lpszHostName, &lpUC->dwHostNameLength,
1741                                               NULL, 0);
1742                     }
1743                     else
1744                     {
1745                         SetUrlComponentValueW(&lpUC->lpszHostName, &lpUC->dwHostNameLength,
1746                                               lpszHost, lpszPort - lpszHost);
1747                         if (lpszPort != lpszNetLoc)
1748                             lpUC->nPort = atoiW(++lpszPort);
1749                         else switch (lpUC->nScheme)
1750                         {
1751                         case INTERNET_SCHEME_HTTP:
1752                             lpUC->nPort = INTERNET_DEFAULT_HTTP_PORT;
1753                             break;
1754                         case INTERNET_SCHEME_HTTPS:
1755                             lpUC->nPort = INTERNET_DEFAULT_HTTPS_PORT;
1756                             break;
1757                         case INTERNET_SCHEME_FTP:
1758                             lpUC->nPort = INTERNET_DEFAULT_FTP_PORT;
1759                             break;
1760                         case INTERNET_SCHEME_GOPHER:
1761                             lpUC->nPort = INTERNET_DEFAULT_GOPHER_PORT;
1762                             break;
1763                         default:
1764                             break;
1765                         }
1766                     }
1767                 }
1768             }
1769         }
1770         else
1771         {
1772             SetUrlComponentValueW(&lpUC->lpszUserName, &lpUC->dwUserNameLength, NULL, 0);
1773             SetUrlComponentValueW(&lpUC->lpszPassword, &lpUC->dwPasswordLength, NULL, 0);
1774             SetUrlComponentValueW(&lpUC->lpszHostName, &lpUC->dwHostNameLength, NULL, 0);
1775         }
1776     }
1777     else
1778     {
1779         SetUrlComponentValueW(&lpUC->lpszScheme, &lpUC->dwSchemeLength, NULL, 0);
1780         SetUrlComponentValueW(&lpUC->lpszUserName, &lpUC->dwUserNameLength, NULL, 0);
1781         SetUrlComponentValueW(&lpUC->lpszPassword, &lpUC->dwPasswordLength, NULL, 0);
1782         SetUrlComponentValueW(&lpUC->lpszHostName, &lpUC->dwHostNameLength, NULL, 0);
1783     }
1784
1785     /* Here lpszcp points to:
1786      *
1787      * <protocol>:[//<net_loc>][/path][;<params>][?<query>][#<fragment>]
1788      *                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1789      */
1790     if (lpszcp != 0 && lpszcp - lpszUrl < dwUrlLength && (!lpszParam || lpszcp <= lpszParam))
1791     {
1792         DWORD len;
1793
1794         /* Only truncate the parameter list if it's already been saved
1795          * in lpUC->lpszExtraInfo.
1796          */
1797         if (lpszParam && lpUC->dwExtraInfoLength && lpUC->lpszExtraInfo)
1798             len = lpszParam - lpszcp;
1799         else
1800         {
1801             /* Leave the parameter list in lpszUrlPath.  Strip off any trailing
1802              * newlines if necessary.
1803              */
1804             LPWSTR lpsznewline = memchrW(lpszcp, '\n', dwUrlLength - (lpszcp - lpszUrl));
1805             if (lpsznewline != NULL)
1806                 len = lpsznewline - lpszcp;
1807             else
1808                 len = dwUrlLength-(lpszcp-lpszUrl);
1809         }
1810         if (lpUC->dwUrlPathLength && lpUC->lpszUrlPath &&
1811                 lpUC->nScheme == INTERNET_SCHEME_FILE)
1812         {
1813             WCHAR tmppath[MAX_PATH];
1814             if (*lpszcp == '/')
1815             {
1816                 len = MAX_PATH;
1817                 PathCreateFromUrlW(lpszUrl_orig, tmppath, &len, 0);
1818             }
1819             else
1820             {
1821                 WCHAR *iter;
1822                 memcpy(tmppath, lpszcp, len * sizeof(WCHAR));
1823                 tmppath[len] = '\0';
1824
1825                 iter = tmppath;
1826                 while (*iter) {
1827                     if (*iter == '/')
1828                         *iter = '\\';
1829                     ++iter;
1830                 }
1831             }
1832             /* if ends in \. or \.. append a backslash */
1833             if (tmppath[len - 1] == '.' &&
1834                     (tmppath[len - 2] == '\\' ||
1835                      (tmppath[len - 2] == '.' && tmppath[len - 3] == '\\')))
1836             {
1837                 if (len < MAX_PATH - 1)
1838                 {
1839                     tmppath[len] = '\\';
1840                     tmppath[len+1] = '\0';
1841                     ++len;
1842                 }
1843             }
1844             SetUrlComponentValueW(&lpUC->lpszUrlPath, &lpUC->dwUrlPathLength,
1845                                        tmppath, len);
1846         }
1847         else
1848             SetUrlComponentValueW(&lpUC->lpszUrlPath, &lpUC->dwUrlPathLength,
1849                                        lpszcp, len);
1850     }
1851     else
1852     {
1853         if (lpUC->lpszUrlPath && (lpUC->dwUrlPathLength > 0))
1854             lpUC->lpszUrlPath[0] = 0;
1855         lpUC->dwUrlPathLength = 0;
1856     }
1857
1858     TRACE("%s: scheme(%s) host(%s) path(%s) extra(%s)\n", debugstr_wn(lpszUrl,dwUrlLength),
1859              debugstr_wn(lpUC->lpszScheme,lpUC->dwSchemeLength),
1860              debugstr_wn(lpUC->lpszHostName,lpUC->dwHostNameLength),
1861              debugstr_wn(lpUC->lpszUrlPath,lpUC->dwUrlPathLength),
1862              debugstr_wn(lpUC->lpszExtraInfo,lpUC->dwExtraInfoLength));
1863
1864     HeapFree(GetProcessHeap(), 0, lpszUrl_decode );
1865     return TRUE;
1866 }
1867
1868 /***********************************************************************
1869  *           InternetAttemptConnect (WININET.@)
1870  *
1871  * Attempt to make a connection to the internet
1872  *
1873  * RETURNS
1874  *    ERROR_SUCCESS on success
1875  *    Error value   on failure
1876  *
1877  */
1878 DWORD WINAPI InternetAttemptConnect(DWORD dwReserved)
1879 {
1880     FIXME("Stub\n");
1881     return ERROR_SUCCESS;
1882 }
1883
1884
1885 /***********************************************************************
1886  *           InternetCanonicalizeUrlA (WININET.@)
1887  *
1888  * Escape unsafe characters and spaces
1889  *
1890  * RETURNS
1891  *    TRUE on success
1892  *    FALSE on failure
1893  *
1894  */
1895 BOOL WINAPI InternetCanonicalizeUrlA(LPCSTR lpszUrl, LPSTR lpszBuffer,
1896         LPDWORD lpdwBufferLength, DWORD dwFlags)
1897 {
1898     HRESULT hr;
1899     DWORD dwURLFlags = URL_WININET_COMPATIBILITY | URL_ESCAPE_UNSAFE;
1900
1901     TRACE("(%s, %p, %p, 0x%08x) bufferlength: %d\n", debugstr_a(lpszUrl), lpszBuffer,
1902         lpdwBufferLength, dwFlags, lpdwBufferLength ? *lpdwBufferLength : -1);
1903
1904     if(dwFlags & ICU_DECODE)
1905     {
1906         dwURLFlags |= URL_UNESCAPE;
1907         dwFlags &= ~ICU_DECODE;
1908     }
1909
1910     if(dwFlags & ICU_ESCAPE)
1911     {
1912         dwURLFlags |= URL_UNESCAPE;
1913         dwFlags &= ~ICU_ESCAPE;
1914     }
1915
1916     if(dwFlags & ICU_BROWSER_MODE)
1917     {
1918         dwURLFlags |= URL_BROWSER_MODE;
1919         dwFlags &= ~ICU_BROWSER_MODE;
1920     }
1921
1922     if(dwFlags & ICU_NO_ENCODE)
1923     {
1924         /* Flip this bit to correspond to URL_ESCAPE_UNSAFE */
1925         dwURLFlags ^= URL_ESCAPE_UNSAFE;
1926         dwFlags &= ~ICU_NO_ENCODE;
1927     }
1928
1929     if (dwFlags) FIXME("Unhandled flags 0x%08x\n", dwFlags);
1930
1931     hr = UrlCanonicalizeA(lpszUrl, lpszBuffer, lpdwBufferLength, dwURLFlags);
1932     if (hr == E_POINTER) SetLastError(ERROR_INSUFFICIENT_BUFFER);
1933     if (hr == E_INVALIDARG) SetLastError(ERROR_INVALID_PARAMETER);
1934
1935     return (hr == S_OK) ? TRUE : FALSE;
1936 }
1937
1938 /***********************************************************************
1939  *           InternetCanonicalizeUrlW (WININET.@)
1940  *
1941  * Escape unsafe characters and spaces
1942  *
1943  * RETURNS
1944  *    TRUE on success
1945  *    FALSE on failure
1946  *
1947  */
1948 BOOL WINAPI InternetCanonicalizeUrlW(LPCWSTR lpszUrl, LPWSTR lpszBuffer,
1949     LPDWORD lpdwBufferLength, DWORD dwFlags)
1950 {
1951     HRESULT hr;
1952     DWORD dwURLFlags = URL_WININET_COMPATIBILITY | URL_ESCAPE_UNSAFE;
1953
1954     TRACE("(%s, %p, %p, 0x%08x) bufferlength: %d\n", debugstr_w(lpszUrl), lpszBuffer,
1955           lpdwBufferLength, dwFlags, lpdwBufferLength ? *lpdwBufferLength : -1);
1956
1957     if(dwFlags & ICU_DECODE)
1958     {
1959         dwURLFlags |= URL_UNESCAPE;
1960         dwFlags &= ~ICU_DECODE;
1961     }
1962
1963     if(dwFlags & ICU_ESCAPE)
1964     {
1965         dwURLFlags |= URL_UNESCAPE;
1966         dwFlags &= ~ICU_ESCAPE;
1967     }
1968
1969     if(dwFlags & ICU_BROWSER_MODE)
1970     {
1971         dwURLFlags |= URL_BROWSER_MODE;
1972         dwFlags &= ~ICU_BROWSER_MODE;
1973     }
1974
1975     if(dwFlags & ICU_NO_ENCODE)
1976     {
1977         /* Flip this bit to correspond to URL_ESCAPE_UNSAFE */
1978         dwURLFlags ^= URL_ESCAPE_UNSAFE;
1979         dwFlags &= ~ICU_NO_ENCODE;
1980     }
1981
1982     if (dwFlags) FIXME("Unhandled flags 0x%08x\n", dwFlags);
1983
1984     hr = UrlCanonicalizeW(lpszUrl, lpszBuffer, lpdwBufferLength, dwURLFlags);
1985     if (hr == E_POINTER) SetLastError(ERROR_INSUFFICIENT_BUFFER);
1986     if (hr == E_INVALIDARG) SetLastError(ERROR_INVALID_PARAMETER);
1987
1988     return (hr == S_OK) ? TRUE : FALSE;
1989 }
1990
1991 /* #################################################### */
1992
1993 static INTERNET_STATUS_CALLBACK set_status_callback(
1994     object_header_t *lpwh, INTERNET_STATUS_CALLBACK callback, BOOL unicode)
1995 {
1996     INTERNET_STATUS_CALLBACK ret;
1997
1998     if (unicode) lpwh->dwInternalFlags |= INET_CALLBACKW;
1999     else lpwh->dwInternalFlags &= ~INET_CALLBACKW;
2000
2001     ret = lpwh->lpfnStatusCB;
2002     lpwh->lpfnStatusCB = callback;
2003
2004     return ret;
2005 }
2006
2007 /***********************************************************************
2008  *           InternetSetStatusCallbackA (WININET.@)
2009  *
2010  * Sets up a callback function which is called as progress is made
2011  * during an operation.
2012  *
2013  * RETURNS
2014  *    Previous callback or NULL         on success
2015  *    INTERNET_INVALID_STATUS_CALLBACK  on failure
2016  *
2017  */
2018 INTERNET_STATUS_CALLBACK WINAPI InternetSetStatusCallbackA(
2019         HINTERNET hInternet ,INTERNET_STATUS_CALLBACK lpfnIntCB)
2020 {
2021     INTERNET_STATUS_CALLBACK retVal;
2022     object_header_t *lpwh;
2023
2024     TRACE("%p\n", hInternet);
2025
2026     if (!(lpwh = WININET_GetObject(hInternet)))
2027         return INTERNET_INVALID_STATUS_CALLBACK;
2028
2029     retVal = set_status_callback(lpwh, lpfnIntCB, FALSE);
2030
2031     WININET_Release( lpwh );
2032     return retVal;
2033 }
2034
2035 /***********************************************************************
2036  *           InternetSetStatusCallbackW (WININET.@)
2037  *
2038  * Sets up a callback function which is called as progress is made
2039  * during an operation.
2040  *
2041  * RETURNS
2042  *    Previous callback or NULL         on success
2043  *    INTERNET_INVALID_STATUS_CALLBACK  on failure
2044  *
2045  */
2046 INTERNET_STATUS_CALLBACK WINAPI InternetSetStatusCallbackW(
2047         HINTERNET hInternet ,INTERNET_STATUS_CALLBACK lpfnIntCB)
2048 {
2049     INTERNET_STATUS_CALLBACK retVal;
2050     object_header_t *lpwh;
2051
2052     TRACE("%p\n", hInternet);
2053
2054     if (!(lpwh = WININET_GetObject(hInternet)))
2055         return INTERNET_INVALID_STATUS_CALLBACK;
2056
2057     retVal = set_status_callback(lpwh, lpfnIntCB, TRUE);
2058
2059     WININET_Release( lpwh );
2060     return retVal;
2061 }
2062
2063 /***********************************************************************
2064  *           InternetSetFilePointer (WININET.@)
2065  */
2066 DWORD WINAPI InternetSetFilePointer(HINTERNET hFile, LONG lDistanceToMove,
2067     PVOID pReserved, DWORD dwMoveContext, DWORD_PTR dwContext)
2068 {
2069     FIXME("stub\n");
2070     return FALSE;
2071 }
2072
2073 /***********************************************************************
2074  *           InternetWriteFile (WININET.@)
2075  *
2076  * Write data to an open internet file
2077  *
2078  * RETURNS
2079  *    TRUE  on success
2080  *    FALSE on failure
2081  *
2082  */
2083 BOOL WINAPI InternetWriteFile(HINTERNET hFile, LPCVOID lpBuffer,
2084         DWORD dwNumOfBytesToWrite, LPDWORD lpdwNumOfBytesWritten)
2085 {
2086     object_header_t *lpwh;
2087     BOOL res;
2088
2089     TRACE("(%p %p %d %p)\n", hFile, lpBuffer, dwNumOfBytesToWrite, lpdwNumOfBytesWritten);
2090
2091     lpwh = WININET_GetObject( hFile );
2092     if (!lpwh) {
2093         WARN("Invalid handle\n");
2094         SetLastError(ERROR_INVALID_HANDLE);
2095         return FALSE;
2096     }
2097
2098     if(lpwh->vtbl->WriteFile) {
2099         res = lpwh->vtbl->WriteFile(lpwh, lpBuffer, dwNumOfBytesToWrite, lpdwNumOfBytesWritten);
2100     }else {
2101         WARN("No Writefile method.\n");
2102         res = ERROR_INVALID_HANDLE;
2103     }
2104
2105     WININET_Release( lpwh );
2106
2107     if(res != ERROR_SUCCESS)
2108         SetLastError(res);
2109     return res == ERROR_SUCCESS;
2110 }
2111
2112
2113 /***********************************************************************
2114  *           InternetReadFile (WININET.@)
2115  *
2116  * Read data from an open internet file
2117  *
2118  * RETURNS
2119  *    TRUE  on success
2120  *    FALSE on failure
2121  *
2122  */
2123 BOOL WINAPI InternetReadFile(HINTERNET hFile, LPVOID lpBuffer,
2124         DWORD dwNumOfBytesToRead, LPDWORD pdwNumOfBytesRead)
2125 {
2126     object_header_t *hdr;
2127     DWORD res = ERROR_INTERNET_INCORRECT_HANDLE_TYPE;
2128
2129     TRACE("%p %p %d %p\n", hFile, lpBuffer, dwNumOfBytesToRead, pdwNumOfBytesRead);
2130
2131     hdr = WININET_GetObject(hFile);
2132     if (!hdr) {
2133         INTERNET_SetLastError(ERROR_INVALID_HANDLE);
2134         return FALSE;
2135     }
2136
2137     if(hdr->vtbl->ReadFile)
2138         res = hdr->vtbl->ReadFile(hdr, lpBuffer, dwNumOfBytesToRead, pdwNumOfBytesRead);
2139
2140     WININET_Release(hdr);
2141
2142     TRACE("-- %s (%u) (bytes read: %d)\n", res == ERROR_SUCCESS ? "TRUE": "FALSE", res,
2143           pdwNumOfBytesRead ? *pdwNumOfBytesRead : -1);
2144
2145     if(res != ERROR_SUCCESS)
2146         SetLastError(res);
2147     return res == ERROR_SUCCESS;
2148 }
2149
2150 /***********************************************************************
2151  *           InternetReadFileExA (WININET.@)
2152  *
2153  * Read data from an open internet file
2154  *
2155  * PARAMS
2156  *  hFile         [I] Handle returned by InternetOpenUrl or HttpOpenRequest.
2157  *  lpBuffersOut  [I/O] Buffer.
2158  *  dwFlags       [I] Flags. See notes.
2159  *  dwContext     [I] Context for callbacks.
2160  *
2161  * RETURNS
2162  *    TRUE  on success
2163  *    FALSE on failure
2164  *
2165  * NOTES
2166  *  The parameter dwFlags include zero or more of the following flags:
2167  *|IRF_ASYNC - Makes the call asynchronous.
2168  *|IRF_SYNC - Makes the call synchronous.
2169  *|IRF_USE_CONTEXT - Forces dwContext to be used.
2170  *|IRF_NO_WAIT - Don't block if the data is not available, just return what is available.
2171  *
2172  * However, in testing IRF_USE_CONTEXT seems to have no effect - dwContext isn't used.
2173  *
2174  * SEE
2175  *  InternetOpenUrlA(), HttpOpenRequestA()
2176  */
2177 BOOL WINAPI InternetReadFileExA(HINTERNET hFile, LPINTERNET_BUFFERSA lpBuffersOut,
2178         DWORD dwFlags, DWORD_PTR dwContext)
2179 {
2180     object_header_t *hdr;
2181     DWORD res = ERROR_INTERNET_INCORRECT_HANDLE_TYPE;
2182
2183     TRACE("(%p %p 0x%x 0x%lx)\n", hFile, lpBuffersOut, dwFlags, dwContext);
2184
2185     hdr = WININET_GetObject(hFile);
2186     if (!hdr) {
2187         INTERNET_SetLastError(ERROR_INVALID_HANDLE);
2188         return FALSE;
2189     }
2190
2191     if(hdr->vtbl->ReadFileExA)
2192         res = hdr->vtbl->ReadFileExA(hdr, lpBuffersOut, dwFlags, dwContext);
2193
2194     WININET_Release(hdr);
2195
2196     TRACE("-- %s (%u, bytes read: %d)\n", res == ERROR_SUCCESS ? "TRUE": "FALSE",
2197           res, lpBuffersOut->dwBufferLength);
2198
2199     if(res != ERROR_SUCCESS)
2200         SetLastError(res);
2201     return res == ERROR_SUCCESS;
2202 }
2203
2204 /***********************************************************************
2205  *           InternetReadFileExW (WININET.@)
2206  * SEE
2207  *  InternetReadFileExA()
2208  */
2209 BOOL WINAPI InternetReadFileExW(HINTERNET hFile, LPINTERNET_BUFFERSW lpBuffer,
2210         DWORD dwFlags, DWORD_PTR dwContext)
2211 {
2212     object_header_t *hdr;
2213     DWORD res = ERROR_INTERNET_INCORRECT_HANDLE_TYPE;
2214
2215     TRACE("(%p %p 0x%x 0x%lx)\n", hFile, lpBuffer, dwFlags, dwContext);
2216
2217     hdr = WININET_GetObject(hFile);
2218     if (!hdr) {
2219         INTERNET_SetLastError(ERROR_INVALID_HANDLE);
2220         return FALSE;
2221     }
2222
2223     if(hdr->vtbl->ReadFileExW)
2224         res = hdr->vtbl->ReadFileExW(hdr, lpBuffer, dwFlags, dwContext);
2225
2226     WININET_Release(hdr);
2227
2228     TRACE("-- %s (%u, bytes read: %d)\n", res == ERROR_SUCCESS ? "TRUE": "FALSE",
2229           res, lpBuffer->dwBufferLength);
2230
2231     if(res != ERROR_SUCCESS)
2232         SetLastError(res);
2233     return res == ERROR_SUCCESS;
2234 }
2235
2236 DWORD INET_QueryOption(object_header_t *hdr, DWORD option, void *buffer, DWORD *size, BOOL unicode)
2237 {
2238     static BOOL warn = TRUE;
2239
2240     switch(option) {
2241     case INTERNET_OPTION_REQUEST_FLAGS:
2242         TRACE("INTERNET_OPTION_REQUEST_FLAGS\n");
2243
2244         if (*size < sizeof(ULONG))
2245             return ERROR_INSUFFICIENT_BUFFER;
2246
2247         *(ULONG*)buffer = 4;
2248         *size = sizeof(ULONG);
2249
2250         return ERROR_SUCCESS;
2251
2252     case INTERNET_OPTION_HTTP_VERSION:
2253         if (*size < sizeof(HTTP_VERSION_INFO))
2254             return ERROR_INSUFFICIENT_BUFFER;
2255
2256         /*
2257          * Presently hardcoded to 1.1
2258          */
2259         ((HTTP_VERSION_INFO*)buffer)->dwMajorVersion = 1;
2260         ((HTTP_VERSION_INFO*)buffer)->dwMinorVersion = 1;
2261         *size = sizeof(HTTP_VERSION_INFO);
2262
2263         return ERROR_SUCCESS;
2264
2265     case INTERNET_OPTION_CONNECTED_STATE:
2266         if (warn) {
2267             FIXME("INTERNET_OPTION_CONNECTED_STATE: semi-stub\n");
2268             warn = FALSE;
2269         }
2270         if (*size < sizeof(ULONG))
2271             return ERROR_INSUFFICIENT_BUFFER;
2272
2273         *(ULONG*)buffer = INTERNET_STATE_CONNECTED;
2274         *size = sizeof(ULONG);
2275
2276         return ERROR_SUCCESS;
2277
2278     case INTERNET_OPTION_PROXY: {
2279         appinfo_t ai;
2280         BOOL ret;
2281
2282         TRACE("Getting global proxy info\n");
2283         memset(&ai, 0, sizeof(appinfo_t));
2284         INTERNET_ConfigureProxy(&ai);
2285
2286         ret = APPINFO_QueryOption(&ai.hdr, INTERNET_OPTION_PROXY, buffer, size, unicode); /* FIXME */
2287         APPINFO_Destroy(&ai.hdr);
2288         return ret;
2289     }
2290
2291     case INTERNET_OPTION_MAX_CONNS_PER_SERVER:
2292         TRACE("INTERNET_OPTION_MAX_CONNS_PER_SERVER\n");
2293
2294         if (*size < sizeof(ULONG))
2295             return ERROR_INSUFFICIENT_BUFFER;
2296
2297         *(ULONG*)buffer = 2;
2298         *size = sizeof(ULONG);
2299
2300         return ERROR_SUCCESS;
2301
2302     case INTERNET_OPTION_MAX_CONNS_PER_1_0_SERVER:
2303             TRACE("INTERNET_OPTION_MAX_CONNS_1_0_SERVER\n");
2304
2305             if (*size < sizeof(ULONG))
2306                 return ERROR_INSUFFICIENT_BUFFER;
2307
2308             *(ULONG*)size = 4;
2309             *size = sizeof(ULONG);
2310
2311             return ERROR_SUCCESS;
2312
2313     case INTERNET_OPTION_SECURITY_FLAGS:
2314         FIXME("INTERNET_OPTION_SECURITY_FLAGS: Stub\n");
2315         return ERROR_SUCCESS;
2316
2317     case INTERNET_OPTION_VERSION: {
2318         static const INTERNET_VERSION_INFO info = { 1, 2 };
2319
2320         TRACE("INTERNET_OPTION_VERSION\n");
2321
2322         if (*size < sizeof(INTERNET_VERSION_INFO))
2323             return ERROR_INSUFFICIENT_BUFFER;
2324
2325         memcpy(buffer, &info, sizeof(info));
2326         *size = sizeof(info);
2327
2328         return ERROR_SUCCESS;
2329     }
2330
2331     case INTERNET_OPTION_PER_CONNECTION_OPTION: {
2332         INTERNET_PER_CONN_OPTION_LISTW *con = buffer;
2333         INTERNET_PER_CONN_OPTION_LISTA *conA = buffer;
2334         DWORD res = ERROR_SUCCESS, i;
2335         proxyinfo_t pi;
2336         LONG ret;
2337
2338         TRACE("Getting global proxy info\n");
2339         if((ret = INTERNET_LoadProxySettings(&pi)))
2340             return ret;
2341
2342         FIXME("INTERNET_OPTION_PER_CONNECTION_OPTION stub\n");
2343
2344         if (*size < sizeof(INTERNET_PER_CONN_OPTION_LISTW)) {
2345             FreeProxyInfo(&pi);
2346             return ERROR_INSUFFICIENT_BUFFER;
2347         }
2348
2349         for (i = 0; i < con->dwOptionCount; i++) {
2350             INTERNET_PER_CONN_OPTIONW *option = con->pOptions + i;
2351             INTERNET_PER_CONN_OPTIONA *optionA = conA->pOptions + i;
2352
2353             switch (option->dwOption) {
2354             case INTERNET_PER_CONN_FLAGS:
2355                 if(pi.dwProxyEnabled)
2356                     option->Value.dwValue = PROXY_TYPE_PROXY;
2357                 else
2358                     option->Value.dwValue = PROXY_TYPE_DIRECT;
2359                 break;
2360
2361             case INTERNET_PER_CONN_PROXY_SERVER:
2362                 if (unicode)
2363                     option->Value.pszValue = heap_strdupW(pi.lpszProxyServer);
2364                 else
2365                     optionA->Value.pszValue = heap_strdupWtoA(pi.lpszProxyServer);
2366                 break;
2367
2368             case INTERNET_PER_CONN_PROXY_BYPASS:
2369                 if (unicode)
2370                     option->Value.pszValue = heap_strdupW(pi.lpszProxyBypass);
2371                 else
2372                     optionA->Value.pszValue = heap_strdupWtoA(pi.lpszProxyBypass);
2373                 break;
2374
2375             case INTERNET_PER_CONN_AUTOCONFIG_URL:
2376             case INTERNET_PER_CONN_AUTODISCOVERY_FLAGS:
2377             case INTERNET_PER_CONN_AUTOCONFIG_SECONDARY_URL:
2378             case INTERNET_PER_CONN_AUTOCONFIG_RELOAD_DELAY_MINS:
2379             case INTERNET_PER_CONN_AUTOCONFIG_LAST_DETECT_TIME:
2380             case INTERNET_PER_CONN_AUTOCONFIG_LAST_DETECT_URL:
2381                 FIXME("Unhandled dwOption %d\n", option->dwOption);
2382                 memset(&option->Value, 0, sizeof(option->Value));
2383                 break;
2384
2385             default:
2386                 FIXME("Unknown dwOption %d\n", option->dwOption);
2387                 res = ERROR_INVALID_PARAMETER;
2388                 break;
2389             }
2390         }
2391         FreeProxyInfo(&pi);
2392
2393         return res;
2394     }
2395     case INTERNET_OPTION_USER_AGENT:
2396         return ERROR_INTERNET_INCORRECT_HANDLE_TYPE;
2397     case INTERNET_OPTION_POLICY:
2398         return ERROR_INVALID_PARAMETER;
2399     case INTERNET_OPTION_CONTEXT_VALUE:
2400     {
2401         if (!hdr)
2402             return ERROR_INTERNET_INCORRECT_HANDLE_TYPE;
2403         if (!size)
2404             return ERROR_INVALID_PARAMETER;
2405
2406         if (*size < sizeof(DWORD_PTR))
2407         {
2408             *size = sizeof(DWORD_PTR);
2409             return ERROR_INSUFFICIENT_BUFFER;
2410         }
2411         if (!buffer)
2412             return ERROR_INVALID_PARAMETER;
2413
2414         *(DWORD_PTR *)buffer = hdr->dwContext;
2415         *size = sizeof(DWORD_PTR);
2416         return ERROR_SUCCESS;
2417     }
2418     }
2419
2420     FIXME("Stub for %d\n", option);
2421     return ERROR_INTERNET_INCORRECT_HANDLE_TYPE;
2422 }
2423
2424 /***********************************************************************
2425  *           InternetQueryOptionW (WININET.@)
2426  *
2427  * Queries an options on the specified handle
2428  *
2429  * RETURNS
2430  *    TRUE  on success
2431  *    FALSE on failure
2432  *
2433  */
2434 BOOL WINAPI InternetQueryOptionW(HINTERNET hInternet, DWORD dwOption,
2435                                  LPVOID lpBuffer, LPDWORD lpdwBufferLength)
2436 {
2437     object_header_t *hdr;
2438     DWORD res = ERROR_INVALID_HANDLE;
2439
2440     TRACE("%p %d %p %p\n", hInternet, dwOption, lpBuffer, lpdwBufferLength);
2441
2442     if(hInternet) {
2443         hdr = WININET_GetObject(hInternet);
2444         if (hdr) {
2445             res = hdr->vtbl->QueryOption(hdr, dwOption, lpBuffer, lpdwBufferLength, TRUE);
2446             WININET_Release(hdr);
2447         }
2448     }else {
2449         res = INET_QueryOption(NULL, dwOption, lpBuffer, lpdwBufferLength, TRUE);
2450     }
2451
2452     if(res != ERROR_SUCCESS)
2453         SetLastError(res);
2454     return res == ERROR_SUCCESS;
2455 }
2456
2457 /***********************************************************************
2458  *           InternetQueryOptionA (WININET.@)
2459  *
2460  * Queries an options on the specified handle
2461  *
2462  * RETURNS
2463  *    TRUE  on success
2464  *    FALSE on failure
2465  *
2466  */
2467 BOOL WINAPI InternetQueryOptionA(HINTERNET hInternet, DWORD dwOption,
2468                                  LPVOID lpBuffer, LPDWORD lpdwBufferLength)
2469 {
2470     object_header_t *hdr;
2471     DWORD res = ERROR_INVALID_HANDLE;
2472
2473     TRACE("%p %d %p %p\n", hInternet, dwOption, lpBuffer, lpdwBufferLength);
2474
2475     if(hInternet) {
2476         hdr = WININET_GetObject(hInternet);
2477         if (hdr) {
2478             res = hdr->vtbl->QueryOption(hdr, dwOption, lpBuffer, lpdwBufferLength, FALSE);
2479             WININET_Release(hdr);
2480         }
2481     }else {
2482         res = INET_QueryOption(NULL, dwOption, lpBuffer, lpdwBufferLength, FALSE);
2483     }
2484
2485     if(res != ERROR_SUCCESS)
2486         SetLastError(res);
2487     return res == ERROR_SUCCESS;
2488 }
2489
2490
2491 /***********************************************************************
2492  *           InternetSetOptionW (WININET.@)
2493  *
2494  * Sets an options on the specified handle
2495  *
2496  * RETURNS
2497  *    TRUE  on success
2498  *    FALSE on failure
2499  *
2500  */
2501 BOOL WINAPI InternetSetOptionW(HINTERNET hInternet, DWORD dwOption,
2502                            LPVOID lpBuffer, DWORD dwBufferLength)
2503 {
2504     object_header_t *lpwhh;
2505     BOOL ret = TRUE;
2506
2507     TRACE("(%p %d %p %d)\n", hInternet, dwOption, lpBuffer, dwBufferLength);
2508
2509     lpwhh = (object_header_t*) WININET_GetObject( hInternet );
2510     if(lpwhh && lpwhh->vtbl->SetOption) {
2511         DWORD res;
2512
2513         res = lpwhh->vtbl->SetOption(lpwhh, dwOption, lpBuffer, dwBufferLength);
2514         if(res != ERROR_INTERNET_INVALID_OPTION) {
2515             WININET_Release( lpwhh );
2516
2517             if(res != ERROR_SUCCESS)
2518                 SetLastError(res);
2519
2520             return res == ERROR_SUCCESS;
2521         }
2522     }
2523
2524     switch (dwOption)
2525     {
2526     case INTERNET_OPTION_CALLBACK:
2527       {
2528         if (!lpwhh)
2529         {
2530             SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
2531             return FALSE;
2532         }
2533         WININET_Release(lpwhh);
2534         SetLastError(ERROR_INTERNET_OPTION_NOT_SETTABLE);
2535         return FALSE;
2536       }
2537     case INTERNET_OPTION_HTTP_VERSION:
2538       {
2539         HTTP_VERSION_INFO* pVersion=(HTTP_VERSION_INFO*)lpBuffer;
2540         FIXME("Option INTERNET_OPTION_HTTP_VERSION(%d,%d): STUB\n",pVersion->dwMajorVersion,pVersion->dwMinorVersion);
2541       }
2542       break;
2543     case INTERNET_OPTION_ERROR_MASK:
2544       {
2545         if(!lpwhh) {
2546             SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
2547             return FALSE;
2548         } else if(*(ULONG*)lpBuffer & (~(INTERNET_ERROR_MASK_INSERT_CDROM|
2549                         INTERNET_ERROR_MASK_COMBINED_SEC_CERT|
2550                         INTERNET_ERROR_MASK_LOGIN_FAILURE_DISPLAY_ENTITY_BODY))) {
2551             SetLastError(ERROR_INVALID_PARAMETER);
2552             ret = FALSE;
2553         } else if(dwBufferLength != sizeof(ULONG)) {
2554             SetLastError(ERROR_INTERNET_BAD_OPTION_LENGTH);
2555             ret = FALSE;
2556         } else
2557             lpwhh->ErrorMask = *(ULONG*)lpBuffer;
2558       }
2559       break;
2560     case INTERNET_OPTION_CODEPAGE:
2561       {
2562         ULONG codepage = *(ULONG *)lpBuffer;
2563         FIXME("Option INTERNET_OPTION_CODEPAGE (%d): STUB\n", codepage);
2564       }
2565       break;
2566     case INTERNET_OPTION_REQUEST_PRIORITY:
2567       {
2568         ULONG priority = *(ULONG *)lpBuffer;
2569         FIXME("Option INTERNET_OPTION_REQUEST_PRIORITY (%d): STUB\n", priority);
2570       }
2571       break;
2572     case INTERNET_OPTION_CONNECT_TIMEOUT:
2573       {
2574         ULONG connecttimeout = *(ULONG *)lpBuffer;
2575         FIXME("Option INTERNET_OPTION_CONNECT_TIMEOUT (%d): STUB\n", connecttimeout);
2576       }
2577       break;
2578     case INTERNET_OPTION_DATA_RECEIVE_TIMEOUT:
2579       {
2580         ULONG receivetimeout = *(ULONG *)lpBuffer;
2581         FIXME("Option INTERNET_OPTION_DATA_RECEIVE_TIMEOUT (%d): STUB\n", receivetimeout);
2582       }
2583       break;
2584     case INTERNET_OPTION_MAX_CONNS_PER_SERVER:
2585       {
2586         ULONG conns = *(ULONG *)lpBuffer;
2587         FIXME("Option INTERNET_OPTION_MAX_CONNS_PER_SERVER (%d): STUB\n", conns);
2588       }
2589       break;
2590     case INTERNET_OPTION_MAX_CONNS_PER_1_0_SERVER:
2591       {
2592         ULONG conns = *(ULONG *)lpBuffer;
2593         FIXME("Option INTERNET_OPTION_MAX_CONNS_PER_1_0_SERVER (%d): STUB\n", conns);
2594       }
2595       break;
2596     case INTERNET_OPTION_RESET_URLCACHE_SESSION:
2597         FIXME("Option INTERNET_OPTION_RESET_URLCACHE_SESSION: STUB\n");
2598         break;
2599     case INTERNET_OPTION_END_BROWSER_SESSION:
2600         FIXME("Option INTERNET_OPTION_END_BROWSER_SESSION: STUB\n");
2601         break;
2602     case INTERNET_OPTION_CONNECTED_STATE:
2603         FIXME("Option INTERNET_OPTION_CONNECTED_STATE: STUB\n");
2604         break;
2605     case INTERNET_OPTION_DISABLE_PASSPORT_AUTH:
2606         TRACE("Option INTERNET_OPTION_DISABLE_PASSPORT_AUTH: harmless stub, since not enabled\n");
2607         break;
2608     case INTERNET_OPTION_SEND_TIMEOUT:
2609     case INTERNET_OPTION_RECEIVE_TIMEOUT:
2610     {
2611         ULONG timeout = *(ULONG *)lpBuffer;
2612         FIXME("INTERNET_OPTION_SEND/RECEIVE_TIMEOUT %d\n", timeout);
2613         break;
2614     }
2615     case INTERNET_OPTION_CONNECT_RETRIES:
2616     {
2617         ULONG retries = *(ULONG *)lpBuffer;
2618         FIXME("INTERNET_OPTION_CONNECT_RETRIES %d\n", retries);
2619         break;
2620     }
2621     case INTERNET_OPTION_CONTEXT_VALUE:
2622     {
2623         if (!lpwhh)
2624         {
2625             SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
2626             return FALSE;
2627         }
2628         if (!lpBuffer || dwBufferLength != sizeof(DWORD_PTR))
2629         {
2630             SetLastError(ERROR_INVALID_PARAMETER);
2631             ret = FALSE;
2632         }
2633         else
2634             lpwhh->dwContext = *(DWORD_PTR *)lpBuffer;
2635         break;
2636     }
2637     case INTERNET_OPTION_SECURITY_FLAGS:
2638          FIXME("Option INTERNET_OPTION_SECURITY_FLAGS; STUB\n");
2639          break;
2640     case INTERNET_OPTION_DISABLE_AUTODIAL:
2641          FIXME("Option INTERNET_OPTION_DISABLE_AUTODIAL; STUB\n");
2642          break;
2643     case INTERNET_OPTION_HTTP_DECODING:
2644         FIXME("INTERNET_OPTION_HTTP_DECODING; STUB\n");
2645         SetLastError(ERROR_INTERNET_INVALID_OPTION);
2646         ret = FALSE;
2647         break;
2648     case INTERNET_OPTION_COOKIES_3RD_PARTY:
2649         FIXME("INTERNET_OPTION_COOKIES_3RD_PARTY; STUB\n");
2650         SetLastError(ERROR_INTERNET_INVALID_OPTION);
2651         ret = FALSE;
2652         break;
2653     case INTERNET_OPTION_SEND_UTF8_SERVERNAME_TO_PROXY:
2654         FIXME("INTERNET_OPTION_SEND_UTF8_SERVERNAME_TO_PROXY; STUB\n");
2655         SetLastError(ERROR_INTERNET_INVALID_OPTION);
2656         ret = FALSE;
2657         break;
2658     case INTERNET_OPTION_CODEPAGE_PATH:
2659         FIXME("INTERNET_OPTION_CODEPAGE_PATH; STUB\n");
2660         SetLastError(ERROR_INTERNET_INVALID_OPTION);
2661         ret = FALSE;
2662         break;
2663     case INTERNET_OPTION_CODEPAGE_EXTRA:
2664         FIXME("INTERNET_OPTION_CODEPAGE_EXTRA; STUB\n");
2665         SetLastError(ERROR_INTERNET_INVALID_OPTION);
2666         ret = FALSE;
2667         break;
2668     case INTERNET_OPTION_IDN:
2669         FIXME("INTERNET_OPTION_IDN; STUB\n");
2670         SetLastError(ERROR_INTERNET_INVALID_OPTION);
2671         ret = FALSE;
2672         break;
2673     case INTERNET_OPTION_POLICY:
2674         SetLastError(ERROR_INVALID_PARAMETER);
2675         ret = FALSE;
2676         break;
2677     case INTERNET_OPTION_PER_CONNECTION_OPTION: {
2678         INTERNET_PER_CONN_OPTION_LISTW *con = lpBuffer;
2679         LONG res;
2680         int i;
2681         proxyinfo_t pi;
2682
2683         INTERNET_LoadProxySettings(&pi);
2684
2685         for (i = 0; i < con->dwOptionCount; i++) {
2686             INTERNET_PER_CONN_OPTIONW *option = con->pOptions + i;
2687
2688             switch (option->dwOption) {
2689             case INTERNET_PER_CONN_PROXY_SERVER:
2690                 HeapFree(GetProcessHeap(), 0, pi.lpszProxyServer);
2691                 pi.lpszProxyServer = heap_strdupW(option->Value.pszValue);
2692                 break;
2693
2694             case INTERNET_PER_CONN_FLAGS:
2695                 if(option->Value.dwValue & PROXY_TYPE_PROXY)
2696                     pi.dwProxyEnabled = 1;
2697                 else
2698                 {
2699                     if(option->Value.dwValue != PROXY_TYPE_DIRECT)
2700                         FIXME("Unhandled flags: 0x%x\n", option->Value.dwValue);
2701                     pi.dwProxyEnabled = 0;
2702                 }
2703                 break;
2704
2705             case INTERNET_PER_CONN_AUTOCONFIG_URL:
2706             case INTERNET_PER_CONN_AUTODISCOVERY_FLAGS:
2707             case INTERNET_PER_CONN_AUTOCONFIG_SECONDARY_URL:
2708             case INTERNET_PER_CONN_AUTOCONFIG_RELOAD_DELAY_MINS:
2709             case INTERNET_PER_CONN_AUTOCONFIG_LAST_DETECT_TIME:
2710             case INTERNET_PER_CONN_AUTOCONFIG_LAST_DETECT_URL:
2711             case INTERNET_PER_CONN_PROXY_BYPASS:
2712                 FIXME("Unhandled dwOption %d\n", option->dwOption);
2713                 break;
2714
2715             default:
2716                 FIXME("Unknown dwOption %d\n", option->dwOption);
2717                 SetLastError(ERROR_INVALID_PARAMETER);
2718                 break;
2719             }
2720         }
2721
2722         if ((res = INTERNET_SaveProxySettings(&pi)))
2723             SetLastError(res);
2724
2725         FreeProxyInfo(&pi);
2726
2727         ret = (res == ERROR_SUCCESS);
2728         break;
2729         }
2730     default:
2731         FIXME("Option %d STUB\n",dwOption);
2732         SetLastError(ERROR_INTERNET_INVALID_OPTION);
2733         ret = FALSE;
2734         break;
2735     }
2736
2737     if(lpwhh)
2738         WININET_Release( lpwhh );
2739
2740     return ret;
2741 }
2742
2743
2744 /***********************************************************************
2745  *           InternetSetOptionA (WININET.@)
2746  *
2747  * Sets an options on the specified handle.
2748  *
2749  * RETURNS
2750  *    TRUE  on success
2751  *    FALSE on failure
2752  *
2753  */
2754 BOOL WINAPI InternetSetOptionA(HINTERNET hInternet, DWORD dwOption,
2755                            LPVOID lpBuffer, DWORD dwBufferLength)
2756 {
2757     LPVOID wbuffer;
2758     DWORD wlen;
2759     BOOL r;
2760
2761     switch( dwOption )
2762     {
2763     case INTERNET_OPTION_CALLBACK:
2764         {
2765         object_header_t *lpwh;
2766
2767         if (!(lpwh = WININET_GetObject(hInternet)))
2768         {
2769             INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
2770             return FALSE;
2771         }
2772         WININET_Release(lpwh);
2773         INTERNET_SetLastError(ERROR_INTERNET_OPTION_NOT_SETTABLE);
2774         return FALSE;
2775         }
2776     case INTERNET_OPTION_PROXY:
2777         {
2778         LPINTERNET_PROXY_INFOA pi = (LPINTERNET_PROXY_INFOA) lpBuffer;
2779         LPINTERNET_PROXY_INFOW piw;
2780         DWORD proxlen, prbylen;
2781         LPWSTR prox, prby;
2782
2783         proxlen = MultiByteToWideChar( CP_ACP, 0, pi->lpszProxy, -1, NULL, 0);
2784         prbylen= MultiByteToWideChar( CP_ACP, 0, pi->lpszProxyBypass, -1, NULL, 0);
2785         wlen = sizeof(*piw) + proxlen + prbylen;
2786         wbuffer = HeapAlloc( GetProcessHeap(), 0, wlen*sizeof(WCHAR) );
2787         piw = (LPINTERNET_PROXY_INFOW) wbuffer;
2788         piw->dwAccessType = pi->dwAccessType;
2789         prox = (LPWSTR) &piw[1];
2790         prby = &prox[proxlen+1];
2791         MultiByteToWideChar( CP_ACP, 0, pi->lpszProxy, -1, prox, proxlen);
2792         MultiByteToWideChar( CP_ACP, 0, pi->lpszProxyBypass, -1, prby, prbylen);
2793         piw->lpszProxy = prox;
2794         piw->lpszProxyBypass = prby;
2795         }
2796         break;
2797     case INTERNET_OPTION_USER_AGENT:
2798     case INTERNET_OPTION_USERNAME:
2799     case INTERNET_OPTION_PASSWORD:
2800         wlen = MultiByteToWideChar( CP_ACP, 0, lpBuffer, dwBufferLength,
2801                                    NULL, 0 );
2802         wbuffer = HeapAlloc( GetProcessHeap(), 0, wlen*sizeof(WCHAR) );
2803         MultiByteToWideChar( CP_ACP, 0, lpBuffer, dwBufferLength,
2804                                    wbuffer, wlen );
2805         break;
2806     case INTERNET_OPTION_PER_CONNECTION_OPTION: {
2807         int i;
2808         INTERNET_PER_CONN_OPTION_LISTW *listW;
2809         INTERNET_PER_CONN_OPTION_LISTA *listA = lpBuffer;
2810         wlen = sizeof(INTERNET_PER_CONN_OPTION_LISTW);
2811         wbuffer = HeapAlloc( GetProcessHeap(), 0, wlen );
2812         listW = wbuffer;
2813
2814         listW->dwSize = sizeof(INTERNET_PER_CONN_OPTION_LISTW);
2815         if (listA->pszConnection)
2816         {
2817             wlen = MultiByteToWideChar( CP_ACP, 0, listA->pszConnection, -1, NULL, 0 );
2818             listW->pszConnection = HeapAlloc( GetProcessHeap(), 0, wlen*sizeof(WCHAR) );
2819             MultiByteToWideChar( CP_ACP, 0, listA->pszConnection, -1, listW->pszConnection, wlen );
2820         }
2821         else
2822             listW->pszConnection = NULL;
2823         listW->dwOptionCount = listA->dwOptionCount;
2824         listW->dwOptionError = listA->dwOptionError;
2825         listW->pOptions = HeapAlloc( GetProcessHeap(), 0, sizeof(INTERNET_PER_CONN_OPTIONW) * listA->dwOptionCount );
2826
2827         for (i = 0; i < listA->dwOptionCount; ++i) {
2828             INTERNET_PER_CONN_OPTIONA *optA = listA->pOptions + i;
2829             INTERNET_PER_CONN_OPTIONW *optW = listW->pOptions + i;
2830
2831             optW->dwOption = optA->dwOption;
2832
2833             switch (optA->dwOption) {
2834             case INTERNET_PER_CONN_AUTOCONFIG_URL:
2835             case INTERNET_PER_CONN_PROXY_BYPASS:
2836             case INTERNET_PER_CONN_PROXY_SERVER:
2837             case INTERNET_PER_CONN_AUTOCONFIG_SECONDARY_URL:
2838             case INTERNET_PER_CONN_AUTOCONFIG_LAST_DETECT_URL:
2839                 if (optA->Value.pszValue)
2840                 {
2841                     wlen = MultiByteToWideChar( CP_ACP, 0, optA->Value.pszValue, -1, NULL, 0 );
2842                     optW->Value.pszValue = HeapAlloc( GetProcessHeap(), 0, wlen*sizeof(WCHAR) );
2843                     MultiByteToWideChar( CP_ACP, 0, optA->Value.pszValue, -1, optW->Value.pszValue, wlen );
2844                 }
2845                 else
2846                     optW->Value.pszValue = NULL;
2847                 break;
2848             case INTERNET_PER_CONN_AUTODISCOVERY_FLAGS:
2849             case INTERNET_PER_CONN_FLAGS:
2850             case INTERNET_PER_CONN_AUTOCONFIG_RELOAD_DELAY_MINS:
2851                 optW->Value.dwValue = optA->Value.dwValue;
2852                 break;
2853             case INTERNET_PER_CONN_AUTOCONFIG_LAST_DETECT_TIME:
2854                 optW->Value.ftValue = optA->Value.ftValue;
2855             default:
2856                 WARN("Unknown PER_CONN dwOption: %d, guessing at conversion to Wide\n", optA->dwOption);
2857                 optW->Value.dwValue = optA->Value.dwValue;
2858                 break;
2859             }
2860         }
2861         }
2862         break;
2863     default:
2864         wbuffer = lpBuffer;
2865         wlen = dwBufferLength;
2866     }
2867
2868     r = InternetSetOptionW(hInternet,dwOption, wbuffer, wlen);
2869
2870     if( lpBuffer != wbuffer )
2871     {
2872         if (dwOption == INTERNET_OPTION_PER_CONNECTION_OPTION)
2873         {
2874             INTERNET_PER_CONN_OPTION_LISTW *list = wbuffer;
2875             int i;
2876             for (i = 0; i < list->dwOptionCount; ++i) {
2877                 INTERNET_PER_CONN_OPTIONW *opt = list->pOptions + i;
2878                 switch (opt->dwOption) {
2879                 case INTERNET_PER_CONN_AUTOCONFIG_URL:
2880                 case INTERNET_PER_CONN_PROXY_BYPASS:
2881                 case INTERNET_PER_CONN_PROXY_SERVER:
2882                 case INTERNET_PER_CONN_AUTOCONFIG_SECONDARY_URL:
2883                 case INTERNET_PER_CONN_AUTOCONFIG_LAST_DETECT_URL:
2884                     HeapFree( GetProcessHeap(), 0, opt->Value.pszValue );
2885                     break;
2886                 default:
2887                     break;
2888                 }
2889             }
2890             HeapFree( GetProcessHeap(), 0, list->pOptions );
2891         }
2892         HeapFree( GetProcessHeap(), 0, wbuffer );
2893     }
2894
2895     return r;
2896 }
2897
2898
2899 /***********************************************************************
2900  *           InternetSetOptionExA (WININET.@)
2901  */
2902 BOOL WINAPI InternetSetOptionExA(HINTERNET hInternet, DWORD dwOption,
2903                            LPVOID lpBuffer, DWORD dwBufferLength, DWORD dwFlags)
2904 {
2905     FIXME("Flags %08x ignored\n", dwFlags);
2906     return InternetSetOptionA( hInternet, dwOption, lpBuffer, dwBufferLength );
2907 }
2908
2909 /***********************************************************************
2910  *           InternetSetOptionExW (WININET.@)
2911  */
2912 BOOL WINAPI InternetSetOptionExW(HINTERNET hInternet, DWORD dwOption,
2913                            LPVOID lpBuffer, DWORD dwBufferLength, DWORD dwFlags)
2914 {
2915     FIXME("Flags %08x ignored\n", dwFlags);
2916     if( dwFlags & ~ISO_VALID_FLAGS )
2917     {
2918         SetLastError( ERROR_INVALID_PARAMETER );
2919         return FALSE;
2920     }
2921     return InternetSetOptionW( hInternet, dwOption, lpBuffer, dwBufferLength );
2922 }
2923
2924 static const WCHAR WININET_wkday[7][4] =
2925     { { 'S','u','n', 0 }, { 'M','o','n', 0 }, { 'T','u','e', 0 }, { 'W','e','d', 0 },
2926       { 'T','h','u', 0 }, { 'F','r','i', 0 }, { 'S','a','t', 0 } };
2927 static const WCHAR WININET_month[12][4] =
2928     { { 'J','a','n', 0 }, { 'F','e','b', 0 }, { 'M','a','r', 0 }, { 'A','p','r', 0 },
2929       { 'M','a','y', 0 }, { 'J','u','n', 0 }, { 'J','u','l', 0 }, { 'A','u','g', 0 },
2930       { 'S','e','p', 0 }, { 'O','c','t', 0 }, { 'N','o','v', 0 }, { 'D','e','c', 0 } };
2931
2932 /***********************************************************************
2933  *           InternetTimeFromSystemTimeA (WININET.@)
2934  */
2935 BOOL WINAPI InternetTimeFromSystemTimeA( const SYSTEMTIME* time, DWORD format, LPSTR string, DWORD size )
2936 {
2937     BOOL ret;
2938     WCHAR stringW[INTERNET_RFC1123_BUFSIZE];
2939
2940     TRACE( "%p 0x%08x %p 0x%08x\n", time, format, string, size );
2941
2942     if (!time || !string || format != INTERNET_RFC1123_FORMAT)
2943     {
2944         SetLastError(ERROR_INVALID_PARAMETER);
2945         return FALSE;
2946     }
2947
2948     if (size < INTERNET_RFC1123_BUFSIZE * sizeof(*string))
2949     {
2950         SetLastError(ERROR_INSUFFICIENT_BUFFER);
2951         return FALSE;
2952     }
2953
2954     ret = InternetTimeFromSystemTimeW( time, format, stringW, sizeof(stringW) );
2955     if (ret) WideCharToMultiByte( CP_ACP, 0, stringW, -1, string, size, NULL, NULL );
2956
2957     return ret;
2958 }
2959
2960 /***********************************************************************
2961  *           InternetTimeFromSystemTimeW (WININET.@)
2962  */
2963 BOOL WINAPI InternetTimeFromSystemTimeW( const SYSTEMTIME* time, DWORD format, LPWSTR string, DWORD size )
2964 {
2965     static const WCHAR date[] =
2966         { '%','s',',',' ','%','0','2','d',' ','%','s',' ','%','4','d',' ','%','0',
2967           '2','d',':','%','0','2','d',':','%','0','2','d',' ','G','M','T', 0 };
2968
2969     TRACE( "%p 0x%08x %p 0x%08x\n", time, format, string, size );
2970
2971     if (!time || !string || format != INTERNET_RFC1123_FORMAT)
2972     {
2973         SetLastError(ERROR_INVALID_PARAMETER);
2974         return FALSE;
2975     }
2976
2977     if (size < INTERNET_RFC1123_BUFSIZE * sizeof(*string))
2978     {
2979         SetLastError(ERROR_INSUFFICIENT_BUFFER);
2980         return FALSE;
2981     }
2982
2983     sprintfW( string, date,
2984               WININET_wkday[time->wDayOfWeek],
2985               time->wDay,
2986               WININET_month[time->wMonth - 1],
2987               time->wYear,
2988               time->wHour,
2989               time->wMinute,
2990               time->wSecond );
2991
2992     return TRUE;
2993 }
2994
2995 /***********************************************************************
2996  *           InternetTimeToSystemTimeA (WININET.@)
2997  */
2998 BOOL WINAPI InternetTimeToSystemTimeA( LPCSTR string, SYSTEMTIME* time, DWORD reserved )
2999 {
3000     BOOL ret = FALSE;
3001     WCHAR *stringW;
3002
3003     TRACE( "%s %p 0x%08x\n", debugstr_a(string), time, reserved );
3004
3005     stringW = heap_strdupAtoW(string);
3006     if (stringW)
3007     {
3008         ret = InternetTimeToSystemTimeW( stringW, time, reserved );
3009         HeapFree( GetProcessHeap(), 0, stringW );
3010     }
3011     return ret;
3012 }
3013
3014 /***********************************************************************
3015  *           InternetTimeToSystemTimeW (WININET.@)
3016  */
3017 BOOL WINAPI InternetTimeToSystemTimeW( LPCWSTR string, SYSTEMTIME* time, DWORD reserved )
3018 {
3019     unsigned int i;
3020     const WCHAR *s = string;
3021     WCHAR       *end;
3022
3023     TRACE( "%s %p 0x%08x\n", debugstr_w(string), time, reserved );
3024
3025     if (!string || !time) return FALSE;
3026
3027     /* Windows does this too */
3028     GetSystemTime( time );
3029
3030     /*  Convert an RFC1123 time such as 'Fri, 07 Jan 2005 12:06:35 GMT' into
3031      *  a SYSTEMTIME structure.
3032      */
3033
3034     while (*s && !isalphaW( *s )) s++;
3035     if (s[0] == '\0' || s[1] == '\0' || s[2] == '\0') return TRUE;
3036     time->wDayOfWeek = 7;
3037
3038     for (i = 0; i < 7; i++)
3039     {
3040         if (toupperW( WININET_wkday[i][0] ) == toupperW( s[0] ) &&
3041             toupperW( WININET_wkday[i][1] ) == toupperW( s[1] ) &&
3042             toupperW( WININET_wkday[i][2] ) == toupperW( s[2] ) )
3043         {
3044             time->wDayOfWeek = i;
3045             break;
3046         }
3047     }
3048
3049     if (time->wDayOfWeek > 6) return TRUE;
3050     while (*s && !isdigitW( *s )) s++;
3051     time->wDay = strtolW( s, &end, 10 );
3052     s = end;
3053
3054     while (*s && !isalphaW( *s )) s++;
3055     if (s[0] == '\0' || s[1] == '\0' || s[2] == '\0') return TRUE;
3056     time->wMonth = 0;
3057
3058     for (i = 0; i < 12; i++)
3059     {
3060         if (toupperW( WININET_month[i][0]) == toupperW( s[0] ) &&
3061             toupperW( WININET_month[i][1]) == toupperW( s[1] ) &&
3062             toupperW( WININET_month[i][2]) == toupperW( s[2] ) )
3063         {
3064             time->wMonth = i + 1;
3065             break;
3066         }
3067     }
3068     if (time->wMonth == 0) return TRUE;
3069
3070     while (*s && !isdigitW( *s )) s++;
3071     if (*s == '\0') return TRUE;
3072     time->wYear = strtolW( s, &end, 10 );
3073     s = end;
3074
3075     while (*s && !isdigitW( *s )) s++;
3076     if (*s == '\0') return TRUE;
3077     time->wHour = strtolW( s, &end, 10 );
3078     s = end;
3079
3080     while (*s && !isdigitW( *s )) s++;
3081     if (*s == '\0') return TRUE;
3082     time->wMinute = strtolW( s, &end, 10 );
3083     s = end;
3084
3085     while (*s && !isdigitW( *s )) s++;
3086     if (*s == '\0') return TRUE;
3087     time->wSecond = strtolW( s, &end, 10 );
3088     s = end;
3089
3090     time->wMilliseconds = 0;
3091     return TRUE;
3092 }
3093
3094 /***********************************************************************
3095  *      InternetCheckConnectionW (WININET.@)
3096  *
3097  * Pings a requested host to check internet connection
3098  *
3099  * RETURNS
3100  *   TRUE on success and FALSE on failure. If a failure then
3101  *   ERROR_NOT_CONNECTED is placed into GetLastError
3102  *
3103  */
3104 BOOL WINAPI InternetCheckConnectionW( LPCWSTR lpszUrl, DWORD dwFlags, DWORD dwReserved )
3105 {
3106 /*
3107  * this is a kludge which runs the resident ping program and reads the output.
3108  *
3109  * Anyone have a better idea?
3110  */
3111
3112   BOOL   rc = FALSE;
3113   static const CHAR ping[] = "ping -c 1 ";
3114   static const CHAR redirect[] = " >/dev/null 2>/dev/null";
3115   CHAR *command = NULL;
3116   WCHAR hostW[1024];
3117   DWORD len;
3118   INTERNET_PORT port;
3119   int status = -1;
3120
3121   FIXME("\n");
3122
3123   /*
3124    * Crack or set the Address
3125    */
3126   if (lpszUrl == NULL)
3127   {
3128      /*
3129       * According to the doc we are supposed to use the ip for the next
3130       * server in the WnInet internal server database. I have
3131       * no idea what that is or how to get it.
3132       *
3133       * So someone needs to implement this.
3134       */
3135      FIXME("Unimplemented with URL of NULL\n");
3136      return TRUE;
3137   }
3138   else
3139   {
3140      URL_COMPONENTSW components;
3141
3142      ZeroMemory(&components,sizeof(URL_COMPONENTSW));
3143      components.lpszHostName = (LPWSTR)hostW;
3144      components.dwHostNameLength = 1024;
3145
3146      if (!InternetCrackUrlW(lpszUrl,0,0,&components))
3147        goto End;
3148
3149      TRACE("host name : %s\n",debugstr_w(components.lpszHostName));
3150      port = components.nPort;
3151      TRACE("port: %d\n", port);
3152   }
3153
3154   if (dwFlags & FLAG_ICC_FORCE_CONNECTION)
3155   {
3156       struct sockaddr_storage saddr;
3157       socklen_t sa_len = sizeof(saddr);
3158       int fd;
3159
3160       if (!GetAddress(hostW, port, (struct sockaddr *)&saddr, &sa_len))
3161           goto End;
3162       fd = socket(saddr.ss_family, SOCK_STREAM, 0);
3163       if (fd != -1)
3164       {
3165           if (connect(fd, (struct sockaddr *)&saddr, sa_len) == 0)
3166               rc = TRUE;
3167           close(fd);
3168       }
3169   }
3170   else
3171   {
3172       /*
3173        * Build our ping command
3174        */
3175       len = WideCharToMultiByte(CP_UNIXCP, 0, hostW, -1, NULL, 0, NULL, NULL);
3176       command = HeapAlloc( GetProcessHeap(), 0, strlen(ping)+len+strlen(redirect) );
3177       strcpy(command,ping);
3178       WideCharToMultiByte(CP_UNIXCP, 0, hostW, -1, command+strlen(ping), len, NULL, NULL);
3179       strcat(command,redirect);
3180
3181       TRACE("Ping command is : %s\n",command);
3182
3183       status = system(command);
3184
3185       TRACE("Ping returned a code of %i\n",status);
3186
3187       /* Ping return code of 0 indicates success */
3188       if (status == 0)
3189          rc = TRUE;
3190   }
3191
3192 End:
3193
3194   HeapFree( GetProcessHeap(), 0, command );
3195   if (rc == FALSE)
3196     INTERNET_SetLastError(ERROR_NOT_CONNECTED);
3197
3198   return rc;
3199 }
3200
3201
3202 /***********************************************************************
3203  *      InternetCheckConnectionA (WININET.@)
3204  *
3205  * Pings a requested host to check internet connection
3206  *
3207  * RETURNS
3208  *   TRUE on success and FALSE on failure. If a failure then
3209  *   ERROR_NOT_CONNECTED is placed into GetLastError
3210  *
3211  */
3212 BOOL WINAPI InternetCheckConnectionA(LPCSTR lpszUrl, DWORD dwFlags, DWORD dwReserved)
3213 {
3214     WCHAR *url = NULL;
3215     BOOL rc;
3216
3217     if(lpszUrl) {
3218         url = heap_strdupAtoW(lpszUrl);
3219         if(!url)
3220             return FALSE;
3221     }
3222
3223     rc = InternetCheckConnectionW(url, dwFlags, dwReserved);
3224
3225     HeapFree(GetProcessHeap(), 0, url);
3226     return rc;
3227 }
3228
3229
3230 /**********************************************************
3231  *      INTERNET_InternetOpenUrlW (internal)
3232  *
3233  * Opens an URL
3234  *
3235  * RETURNS
3236  *   handle of connection or NULL on failure
3237  */
3238 static HINTERNET INTERNET_InternetOpenUrlW(appinfo_t *hIC, LPCWSTR lpszUrl,
3239     LPCWSTR lpszHeaders, DWORD dwHeadersLength, DWORD dwFlags, DWORD_PTR dwContext)
3240 {
3241     URL_COMPONENTSW urlComponents;
3242     WCHAR protocol[32], hostName[MAXHOSTNAME], userName[1024];
3243     WCHAR password[1024], path[2048], extra[1024];
3244     HINTERNET client = NULL, client1 = NULL;
3245     DWORD res;
3246     
3247     TRACE("(%p, %s, %s, %08x, %08x, %08lx)\n", hIC, debugstr_w(lpszUrl), debugstr_w(lpszHeaders),
3248           dwHeadersLength, dwFlags, dwContext);
3249     
3250     urlComponents.dwStructSize = sizeof(URL_COMPONENTSW);
3251     urlComponents.lpszScheme = protocol;
3252     urlComponents.dwSchemeLength = 32;
3253     urlComponents.lpszHostName = hostName;
3254     urlComponents.dwHostNameLength = MAXHOSTNAME;
3255     urlComponents.lpszUserName = userName;
3256     urlComponents.dwUserNameLength = 1024;
3257     urlComponents.lpszPassword = password;
3258     urlComponents.dwPasswordLength = 1024;
3259     urlComponents.lpszUrlPath = path;
3260     urlComponents.dwUrlPathLength = 2048;
3261     urlComponents.lpszExtraInfo = extra;
3262     urlComponents.dwExtraInfoLength = 1024;
3263     if(!InternetCrackUrlW(lpszUrl, strlenW(lpszUrl), 0, &urlComponents))
3264         return NULL;
3265     switch(urlComponents.nScheme) {
3266     case INTERNET_SCHEME_FTP:
3267         if(urlComponents.nPort == 0)
3268             urlComponents.nPort = INTERNET_DEFAULT_FTP_PORT;
3269         client = FTP_Connect(hIC, hostName, urlComponents.nPort,
3270                              userName, password, dwFlags, dwContext, INET_OPENURL);
3271         if(client == NULL)
3272             break;
3273         client1 = FtpOpenFileW(client, path, GENERIC_READ, dwFlags, dwContext);
3274         if(client1 == NULL) {
3275             InternetCloseHandle(client);
3276             break;
3277         }
3278         break;
3279         
3280     case INTERNET_SCHEME_HTTP:
3281     case INTERNET_SCHEME_HTTPS: {
3282         static const WCHAR szStars[] = { '*','/','*', 0 };
3283         LPCWSTR accept[2] = { szStars, NULL };
3284         if(urlComponents.nPort == 0) {
3285             if(urlComponents.nScheme == INTERNET_SCHEME_HTTP)
3286                 urlComponents.nPort = INTERNET_DEFAULT_HTTP_PORT;
3287             else
3288                 urlComponents.nPort = INTERNET_DEFAULT_HTTPS_PORT;
3289         }
3290         if (urlComponents.nScheme == INTERNET_SCHEME_HTTPS) dwFlags |= INTERNET_FLAG_SECURE;
3291
3292         /* FIXME: should use pointers, not handles, as handles are not thread-safe */
3293         res = HTTP_Connect(hIC, hostName, urlComponents.nPort,
3294                            userName, password, dwFlags, dwContext, INET_OPENURL, &client);
3295         if(res != ERROR_SUCCESS) {
3296             INTERNET_SetLastError(res);
3297             break;
3298         }
3299
3300         if (urlComponents.dwExtraInfoLength) {
3301                 WCHAR *path_extra;
3302                 DWORD len = urlComponents.dwUrlPathLength + urlComponents.dwExtraInfoLength + 1;
3303
3304                 if (!(path_extra = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR))))
3305                 {
3306                         InternetCloseHandle(client);
3307                         break;
3308                 }
3309                 strcpyW(path_extra, urlComponents.lpszUrlPath);
3310                 strcatW(path_extra, urlComponents.lpszExtraInfo);
3311                 client1 = HttpOpenRequestW(client, NULL, path_extra, NULL, NULL, accept, dwFlags, dwContext);
3312                 HeapFree(GetProcessHeap(), 0, path_extra);
3313         }
3314         else
3315                 client1 = HttpOpenRequestW(client, NULL, path, NULL, NULL, accept, dwFlags, dwContext);
3316
3317         if(client1 == NULL) {
3318             InternetCloseHandle(client);
3319             break;
3320         }
3321         HttpAddRequestHeadersW(client1, lpszHeaders, dwHeadersLength, HTTP_ADDREQ_FLAG_ADD);
3322         if (!HttpSendRequestW(client1, NULL, 0, NULL, 0) &&
3323             GetLastError() != ERROR_IO_PENDING) {
3324             InternetCloseHandle(client1);
3325             client1 = NULL;
3326             break;
3327         }
3328     }
3329     case INTERNET_SCHEME_GOPHER:
3330         /* gopher doesn't seem to be implemented in wine, but it's supposed
3331          * to be supported by InternetOpenUrlA. */
3332     default:
3333         SetLastError(ERROR_INTERNET_UNRECOGNIZED_SCHEME);
3334         break;
3335     }
3336
3337     TRACE(" %p <--\n", client1);
3338     
3339     return client1;
3340 }
3341
3342 /**********************************************************
3343  *      InternetOpenUrlW (WININET.@)
3344  *
3345  * Opens an URL
3346  *
3347  * RETURNS
3348  *   handle of connection or NULL on failure
3349  */
3350 static void AsyncInternetOpenUrlProc(WORKREQUEST *workRequest)
3351 {
3352     struct WORKREQ_INTERNETOPENURLW const *req = &workRequest->u.InternetOpenUrlW;
3353     appinfo_t *hIC = (appinfo_t*) workRequest->hdr;
3354
3355     TRACE("%p\n", hIC);
3356
3357     INTERNET_InternetOpenUrlW(hIC, req->lpszUrl,
3358                               req->lpszHeaders, req->dwHeadersLength, req->dwFlags, req->dwContext);
3359     HeapFree(GetProcessHeap(), 0, req->lpszUrl);
3360     HeapFree(GetProcessHeap(), 0, req->lpszHeaders);
3361 }
3362
3363 HINTERNET WINAPI InternetOpenUrlW(HINTERNET hInternet, LPCWSTR lpszUrl,
3364     LPCWSTR lpszHeaders, DWORD dwHeadersLength, DWORD dwFlags, DWORD_PTR dwContext)
3365 {
3366     HINTERNET ret = NULL;
3367     appinfo_t *hIC = NULL;
3368
3369     if (TRACE_ON(wininet)) {
3370         TRACE("(%p, %s, %s, %08x, %08x, %08lx)\n", hInternet, debugstr_w(lpszUrl), debugstr_w(lpszHeaders),
3371               dwHeadersLength, dwFlags, dwContext);
3372         TRACE("  flags :");
3373         dump_INTERNET_FLAGS(dwFlags);
3374     }
3375
3376     if (!lpszUrl)
3377     {
3378         SetLastError(ERROR_INVALID_PARAMETER);
3379         goto lend;
3380     }
3381
3382     hIC = (appinfo_t*)WININET_GetObject( hInternet );
3383     if (NULL == hIC ||  hIC->hdr.htype != WH_HINIT) {
3384         SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
3385         goto lend;
3386     }
3387     
3388     if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC) {
3389         WORKREQUEST workRequest;
3390         struct WORKREQ_INTERNETOPENURLW *req;
3391
3392         workRequest.asyncproc = AsyncInternetOpenUrlProc;
3393         workRequest.hdr = WININET_AddRef( &hIC->hdr );
3394         req = &workRequest.u.InternetOpenUrlW;
3395         req->lpszUrl = heap_strdupW(lpszUrl);
3396         req->lpszHeaders = heap_strdupW(lpszHeaders);
3397         req->dwHeadersLength = dwHeadersLength;
3398         req->dwFlags = dwFlags;
3399         req->dwContext = dwContext;
3400         
3401         INTERNET_AsyncCall(&workRequest);
3402         /*
3403          * This is from windows.
3404          */
3405         SetLastError(ERROR_IO_PENDING);
3406     } else {
3407         ret = INTERNET_InternetOpenUrlW(hIC, lpszUrl, lpszHeaders, dwHeadersLength, dwFlags, dwContext);
3408     }
3409     
3410   lend:
3411     if( hIC )
3412         WININET_Release( &hIC->hdr );
3413     TRACE(" %p <--\n", ret);
3414     
3415     return ret;
3416 }
3417
3418 /**********************************************************
3419  *      InternetOpenUrlA (WININET.@)
3420  *
3421  * Opens an URL
3422  *
3423  * RETURNS
3424  *   handle of connection or NULL on failure
3425  */
3426 HINTERNET WINAPI InternetOpenUrlA(HINTERNET hInternet, LPCSTR lpszUrl,
3427     LPCSTR lpszHeaders, DWORD dwHeadersLength, DWORD dwFlags, DWORD_PTR dwContext)
3428 {
3429     HINTERNET rc = NULL;
3430     DWORD lenHeaders = 0;
3431     LPWSTR szUrl = NULL;
3432     LPWSTR szHeaders = NULL;
3433
3434     TRACE("\n");
3435
3436     if(lpszUrl) {
3437         szUrl = heap_strdupAtoW(lpszUrl);
3438         if(!szUrl)
3439             return NULL;
3440     }
3441
3442     if(lpszHeaders) {
3443         lenHeaders = MultiByteToWideChar(CP_ACP, 0, lpszHeaders, dwHeadersLength, NULL, 0 );
3444         szHeaders = HeapAlloc(GetProcessHeap(), 0, lenHeaders*sizeof(WCHAR));
3445         if(!szHeaders) {
3446             HeapFree(GetProcessHeap(), 0, szUrl);
3447             return NULL;
3448         }
3449         MultiByteToWideChar(CP_ACP, 0, lpszHeaders, dwHeadersLength, szHeaders, lenHeaders);
3450     }
3451     
3452     rc = InternetOpenUrlW(hInternet, szUrl, szHeaders,
3453         lenHeaders, dwFlags, dwContext);
3454
3455     HeapFree(GetProcessHeap(), 0, szUrl);
3456     HeapFree(GetProcessHeap(), 0, szHeaders);
3457
3458     return rc;
3459 }
3460
3461
3462 static LPWITHREADERROR INTERNET_AllocThreadError(void)
3463 {
3464     LPWITHREADERROR lpwite = HeapAlloc(GetProcessHeap(), 0, sizeof(*lpwite));
3465
3466     if (lpwite)
3467     {
3468         lpwite->dwError = 0;
3469         lpwite->response[0] = '\0';
3470     }
3471
3472     if (!TlsSetValue(g_dwTlsErrIndex, lpwite))
3473     {
3474         HeapFree(GetProcessHeap(), 0, lpwite);
3475         return NULL;
3476     }
3477
3478     return lpwite;
3479 }
3480
3481
3482 /***********************************************************************
3483  *           INTERNET_SetLastError (internal)
3484  *
3485  * Set last thread specific error
3486  *
3487  * RETURNS
3488  *
3489  */
3490 void INTERNET_SetLastError(DWORD dwError)
3491 {
3492     LPWITHREADERROR lpwite = TlsGetValue(g_dwTlsErrIndex);
3493
3494     if (!lpwite)
3495         lpwite = INTERNET_AllocThreadError();
3496
3497     SetLastError(dwError);
3498     if(lpwite)
3499         lpwite->dwError = dwError;
3500 }
3501
3502
3503 /***********************************************************************
3504  *           INTERNET_GetLastError (internal)
3505  *
3506  * Get last thread specific error
3507  *
3508  * RETURNS
3509  *
3510  */
3511 DWORD INTERNET_GetLastError(void)
3512 {
3513     LPWITHREADERROR lpwite = TlsGetValue(g_dwTlsErrIndex);
3514     if (!lpwite) return 0;
3515     /* TlsGetValue clears last error, so set it again here */
3516     SetLastError(lpwite->dwError);
3517     return lpwite->dwError;
3518 }
3519
3520
3521 /***********************************************************************
3522  *           INTERNET_WorkerThreadFunc (internal)
3523  *
3524  * Worker thread execution function
3525  *
3526  * RETURNS
3527  *
3528  */
3529 static DWORD CALLBACK INTERNET_WorkerThreadFunc(LPVOID lpvParam)
3530 {
3531     LPWORKREQUEST lpRequest = lpvParam;
3532     WORKREQUEST workRequest;
3533
3534     TRACE("\n");
3535
3536     workRequest = *lpRequest;
3537     HeapFree(GetProcessHeap(), 0, lpRequest);
3538
3539     workRequest.asyncproc(&workRequest);
3540     WININET_Release( workRequest.hdr );
3541
3542     if (g_dwTlsErrIndex != TLS_OUT_OF_INDEXES)
3543     {
3544         HeapFree(GetProcessHeap(), 0, TlsGetValue(g_dwTlsErrIndex));
3545         TlsSetValue(g_dwTlsErrIndex, NULL);
3546     }
3547     return TRUE;
3548 }
3549
3550
3551 /***********************************************************************
3552  *           INTERNET_AsyncCall (internal)
3553  *
3554  * Retrieves work request from queue
3555  *
3556  * RETURNS
3557  *
3558  */
3559 DWORD INTERNET_AsyncCall(LPWORKREQUEST lpWorkRequest)
3560 {
3561     BOOL bSuccess;
3562     LPWORKREQUEST lpNewRequest;
3563
3564     TRACE("\n");
3565
3566     lpNewRequest = HeapAlloc(GetProcessHeap(), 0, sizeof(WORKREQUEST));
3567     if (!lpNewRequest)
3568         return ERROR_OUTOFMEMORY;
3569
3570     *lpNewRequest = *lpWorkRequest;
3571
3572     bSuccess = QueueUserWorkItem(INTERNET_WorkerThreadFunc, lpNewRequest, WT_EXECUTELONGFUNCTION);
3573     if (!bSuccess)
3574     {
3575         HeapFree(GetProcessHeap(), 0, lpNewRequest);
3576         return ERROR_INTERNET_ASYNC_THREAD_FAILED;
3577     }
3578
3579     return ERROR_SUCCESS;
3580 }
3581
3582
3583 /***********************************************************************
3584  *          INTERNET_GetResponseBuffer  (internal)
3585  *
3586  * RETURNS
3587  *
3588  */
3589 LPSTR INTERNET_GetResponseBuffer(void)
3590 {
3591     LPWITHREADERROR lpwite = TlsGetValue(g_dwTlsErrIndex);
3592     if (!lpwite)
3593         lpwite = INTERNET_AllocThreadError();
3594     TRACE("\n");
3595     return lpwite->response;
3596 }
3597
3598 /***********************************************************************
3599  *           INTERNET_GetNextLine  (internal)
3600  *
3601  * Parse next line in directory string listing
3602  *
3603  * RETURNS
3604  *   Pointer to beginning of next line
3605  *   NULL on failure
3606  *
3607  */
3608
3609 LPSTR INTERNET_GetNextLine(INT nSocket, LPDWORD dwLen)
3610 {
3611     struct pollfd pfd;
3612     BOOL bSuccess = FALSE;
3613     INT nRecv = 0;
3614     LPSTR lpszBuffer = INTERNET_GetResponseBuffer();
3615
3616     TRACE("\n");
3617
3618     pfd.fd = nSocket;
3619     pfd.events = POLLIN;
3620
3621     while (nRecv < MAX_REPLY_LEN)
3622     {
3623         if (poll(&pfd,1, RESPONSE_TIMEOUT * 1000) > 0)
3624         {
3625             if (recv(nSocket, &lpszBuffer[nRecv], 1, 0) <= 0)
3626             {
3627                 INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS);
3628                 goto lend;
3629             }
3630
3631             if (lpszBuffer[nRecv] == '\n')
3632             {
3633                 bSuccess = TRUE;
3634                 break;
3635             }
3636             if (lpszBuffer[nRecv] != '\r')
3637                 nRecv++;
3638         }
3639         else
3640         {
3641             INTERNET_SetLastError(ERROR_INTERNET_TIMEOUT);
3642             goto lend;
3643         }
3644     }
3645
3646 lend:
3647     if (bSuccess)
3648     {
3649         lpszBuffer[nRecv] = '\0';
3650         *dwLen = nRecv - 1;
3651         TRACE(":%d %s\n", nRecv, lpszBuffer);
3652         return lpszBuffer;
3653     }
3654     else
3655     {
3656         return NULL;
3657     }
3658 }
3659
3660 /**********************************************************
3661  *      InternetQueryDataAvailable (WININET.@)
3662  *
3663  * Determines how much data is available to be read.
3664  *
3665  * RETURNS
3666  *   TRUE on success, FALSE if an error occurred. If
3667  *   INTERNET_FLAG_ASYNC was specified in InternetOpen, and
3668  *   no data is presently available, FALSE is returned with
3669  *   the last error ERROR_IO_PENDING; a callback with status
3670  *   INTERNET_STATUS_REQUEST_COMPLETE will be sent when more
3671  *   data is available.
3672  */
3673 BOOL WINAPI InternetQueryDataAvailable( HINTERNET hFile,
3674                                 LPDWORD lpdwNumberOfBytesAvailble,
3675                                 DWORD dwFlags, DWORD_PTR dwContext)
3676 {
3677     object_header_t *hdr;
3678     DWORD res;
3679
3680     TRACE("(%p %p %x %lx)\n", hFile, lpdwNumberOfBytesAvailble, dwFlags, dwContext);
3681
3682     hdr = WININET_GetObject( hFile );
3683     if (!hdr) {
3684         SetLastError(ERROR_INVALID_HANDLE);
3685         return FALSE;
3686     }
3687
3688     if(hdr->vtbl->QueryDataAvailable) {
3689         res = hdr->vtbl->QueryDataAvailable(hdr, lpdwNumberOfBytesAvailble, dwFlags, dwContext);
3690     }else {
3691         WARN("wrong handle\n");
3692         res = ERROR_INTERNET_INCORRECT_HANDLE_TYPE;
3693     }
3694
3695     WININET_Release(hdr);
3696
3697     if(res != ERROR_SUCCESS)
3698         SetLastError(res);
3699     return res == ERROR_SUCCESS;
3700 }
3701
3702
3703 /***********************************************************************
3704  *      InternetLockRequestFile (WININET.@)
3705  */
3706 BOOL WINAPI InternetLockRequestFile( HINTERNET hInternet, HANDLE
3707 *lphLockReqHandle)
3708 {
3709     FIXME("STUB\n");
3710     return FALSE;
3711 }
3712
3713 BOOL WINAPI InternetUnlockRequestFile( HANDLE hLockHandle)
3714 {
3715     FIXME("STUB\n");
3716     return FALSE;
3717 }
3718
3719
3720 /***********************************************************************
3721  *      InternetAutodial (WININET.@)
3722  *
3723  * On windows this function is supposed to dial the default internet
3724  * connection. We don't want to have Wine dial out to the internet so
3725  * we return TRUE by default. It might be nice to check if we are connected.
3726  *
3727  * RETURNS
3728  *   TRUE on success
3729  *   FALSE on failure
3730  *
3731  */
3732 BOOL WINAPI InternetAutodial(DWORD dwFlags, HWND hwndParent)
3733 {
3734     FIXME("STUB\n");
3735
3736     /* Tell that we are connected to the internet. */
3737     return TRUE;
3738 }
3739
3740 /***********************************************************************
3741  *      InternetAutodialHangup (WININET.@)
3742  *
3743  * Hangs up a connection made with InternetAutodial
3744  *
3745  * PARAM
3746  *    dwReserved
3747  * RETURNS
3748  *   TRUE on success
3749  *   FALSE on failure
3750  *
3751  */
3752 BOOL WINAPI InternetAutodialHangup(DWORD dwReserved)
3753 {
3754     FIXME("STUB\n");
3755
3756     /* we didn't dial, we don't disconnect */
3757     return TRUE;
3758 }
3759
3760 /***********************************************************************
3761  *      InternetCombineUrlA (WININET.@)
3762  *
3763  * Combine a base URL with a relative URL
3764  *
3765  * RETURNS
3766  *   TRUE on success
3767  *   FALSE on failure
3768  *
3769  */
3770
3771 BOOL WINAPI InternetCombineUrlA(LPCSTR lpszBaseUrl, LPCSTR lpszRelativeUrl,
3772                                 LPSTR lpszBuffer, LPDWORD lpdwBufferLength,
3773                                 DWORD dwFlags)
3774 {
3775     HRESULT hr=S_OK;
3776
3777     TRACE("(%s, %s, %p, %p, 0x%08x)\n", debugstr_a(lpszBaseUrl), debugstr_a(lpszRelativeUrl), lpszBuffer, lpdwBufferLength, dwFlags);
3778
3779     /* Flip this bit to correspond to URL_ESCAPE_UNSAFE */
3780     dwFlags ^= ICU_NO_ENCODE;
3781     hr=UrlCombineA(lpszBaseUrl,lpszRelativeUrl,lpszBuffer,lpdwBufferLength,dwFlags);
3782
3783     return (hr==S_OK);
3784 }
3785
3786 /***********************************************************************
3787  *      InternetCombineUrlW (WININET.@)
3788  *
3789  * Combine a base URL with a relative URL
3790  *
3791  * RETURNS
3792  *   TRUE on success
3793  *   FALSE on failure
3794  *
3795  */
3796
3797 BOOL WINAPI InternetCombineUrlW(LPCWSTR lpszBaseUrl, LPCWSTR lpszRelativeUrl,
3798                                 LPWSTR lpszBuffer, LPDWORD lpdwBufferLength,
3799                                 DWORD dwFlags)
3800 {
3801     HRESULT hr=S_OK;
3802
3803     TRACE("(%s, %s, %p, %p, 0x%08x)\n", debugstr_w(lpszBaseUrl), debugstr_w(lpszRelativeUrl), lpszBuffer, lpdwBufferLength, dwFlags);
3804
3805     /* Flip this bit to correspond to URL_ESCAPE_UNSAFE */
3806     dwFlags ^= ICU_NO_ENCODE;
3807     hr=UrlCombineW(lpszBaseUrl,lpszRelativeUrl,lpszBuffer,lpdwBufferLength,dwFlags);
3808
3809     return (hr==S_OK);
3810 }
3811
3812 /* max port num is 65535 => 5 digits */
3813 #define MAX_WORD_DIGITS 5
3814
3815 #define URL_GET_COMP_LENGTH(url, component) ((url)->dw##component##Length ? \
3816     (url)->dw##component##Length : strlenW((url)->lpsz##component))
3817 #define URL_GET_COMP_LENGTHA(url, component) ((url)->dw##component##Length ? \
3818     (url)->dw##component##Length : strlen((url)->lpsz##component))
3819
3820 static BOOL url_uses_default_port(INTERNET_SCHEME nScheme, INTERNET_PORT nPort)
3821 {
3822     if ((nScheme == INTERNET_SCHEME_HTTP) &&
3823         (nPort == INTERNET_DEFAULT_HTTP_PORT))
3824         return TRUE;
3825     if ((nScheme == INTERNET_SCHEME_HTTPS) &&
3826         (nPort == INTERNET_DEFAULT_HTTPS_PORT))
3827         return TRUE;
3828     if ((nScheme == INTERNET_SCHEME_FTP) &&
3829         (nPort == INTERNET_DEFAULT_FTP_PORT))
3830         return TRUE;
3831     if ((nScheme == INTERNET_SCHEME_GOPHER) &&
3832         (nPort == INTERNET_DEFAULT_GOPHER_PORT))
3833         return TRUE;
3834
3835     if (nPort == INTERNET_INVALID_PORT_NUMBER)
3836         return TRUE;
3837
3838     return FALSE;
3839 }
3840
3841 /* opaque urls do not fit into the standard url hierarchy and don't have
3842  * two following slashes */
3843 static inline BOOL scheme_is_opaque(INTERNET_SCHEME nScheme)
3844 {
3845     return (nScheme != INTERNET_SCHEME_FTP) &&
3846            (nScheme != INTERNET_SCHEME_GOPHER) &&
3847            (nScheme != INTERNET_SCHEME_HTTP) &&
3848            (nScheme != INTERNET_SCHEME_HTTPS) &&
3849            (nScheme != INTERNET_SCHEME_FILE);
3850 }
3851
3852 static LPCWSTR INTERNET_GetSchemeString(INTERNET_SCHEME scheme)
3853 {
3854     int index;
3855     if (scheme < INTERNET_SCHEME_FIRST)
3856         return NULL;
3857     index = scheme - INTERNET_SCHEME_FIRST;
3858     if (index >= sizeof(url_schemes)/sizeof(url_schemes[0]))
3859         return NULL;
3860     return (LPCWSTR)url_schemes[index];
3861 }
3862
3863 /* we can calculate using ansi strings because we're just
3864  * calculating string length, not size
3865  */
3866 static BOOL calc_url_length(LPURL_COMPONENTSW lpUrlComponents,
3867                             LPDWORD lpdwUrlLength)
3868 {
3869     INTERNET_SCHEME nScheme;
3870
3871     *lpdwUrlLength = 0;
3872
3873     if (lpUrlComponents->lpszScheme)
3874     {
3875         DWORD dwLen = URL_GET_COMP_LENGTH(lpUrlComponents, Scheme);
3876         *lpdwUrlLength += dwLen;
3877         nScheme = GetInternetSchemeW(lpUrlComponents->lpszScheme, dwLen);
3878     }
3879     else
3880     {
3881         LPCWSTR scheme;
3882
3883         nScheme = lpUrlComponents->nScheme;
3884
3885         if (nScheme == INTERNET_SCHEME_DEFAULT)
3886             nScheme = INTERNET_SCHEME_HTTP;
3887         scheme = INTERNET_GetSchemeString(nScheme);
3888         *lpdwUrlLength += strlenW(scheme);
3889     }
3890
3891     (*lpdwUrlLength)++; /* ':' */
3892     if (!scheme_is_opaque(nScheme) || lpUrlComponents->lpszHostName)
3893         *lpdwUrlLength += strlen("//");
3894
3895     if (lpUrlComponents->lpszUserName)
3896     {
3897         *lpdwUrlLength += URL_GET_COMP_LENGTH(lpUrlComponents, UserName);
3898         *lpdwUrlLength += strlen("@");
3899     }
3900     else
3901     {
3902         if (lpUrlComponents->lpszPassword)
3903         {
3904             INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
3905             return FALSE;
3906         }
3907     }
3908
3909     if (lpUrlComponents->lpszPassword)
3910     {
3911         *lpdwUrlLength += strlen(":");
3912         *lpdwUrlLength += URL_GET_COMP_LENGTH(lpUrlComponents, Password);
3913     }
3914
3915     if (lpUrlComponents->lpszHostName)
3916     {
3917         *lpdwUrlLength += URL_GET_COMP_LENGTH(lpUrlComponents, HostName);
3918
3919         if (!url_uses_default_port(nScheme, lpUrlComponents->nPort))
3920         {
3921             char szPort[MAX_WORD_DIGITS+1];
3922
3923             sprintf(szPort, "%d", lpUrlComponents->nPort);
3924             *lpdwUrlLength += strlen(szPort);
3925             *lpdwUrlLength += strlen(":");
3926         }
3927
3928         if (lpUrlComponents->lpszUrlPath && *lpUrlComponents->lpszUrlPath != '/')
3929             (*lpdwUrlLength)++; /* '/' */
3930     }
3931
3932     if (lpUrlComponents->lpszUrlPath)
3933         *lpdwUrlLength += URL_GET_COMP_LENGTH(lpUrlComponents, UrlPath);
3934
3935     if (lpUrlComponents->lpszExtraInfo)
3936         *lpdwUrlLength += URL_GET_COMP_LENGTH(lpUrlComponents, ExtraInfo);
3937
3938     return TRUE;
3939 }
3940
3941 static void convert_urlcomp_atow(LPURL_COMPONENTSA lpUrlComponents, LPURL_COMPONENTSW urlCompW)
3942 {
3943     INT len;
3944
3945     ZeroMemory(urlCompW, sizeof(URL_COMPONENTSW));
3946
3947     urlCompW->dwStructSize = sizeof(URL_COMPONENTSW);
3948     urlCompW->dwSchemeLength = lpUrlComponents->dwSchemeLength;
3949     urlCompW->nScheme = lpUrlComponents->nScheme;
3950     urlCompW->dwHostNameLength = lpUrlComponents->dwHostNameLength;
3951     urlCompW->nPort = lpUrlComponents->nPort;
3952     urlCompW->dwUserNameLength = lpUrlComponents->dwUserNameLength;
3953     urlCompW->dwPasswordLength = lpUrlComponents->dwPasswordLength;
3954     urlCompW->dwUrlPathLength = lpUrlComponents->dwUrlPathLength;
3955     urlCompW->dwExtraInfoLength = lpUrlComponents->dwExtraInfoLength;
3956
3957     if (lpUrlComponents->lpszScheme)
3958     {
3959         len = URL_GET_COMP_LENGTHA(lpUrlComponents, Scheme) + 1;
3960         urlCompW->lpszScheme = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
3961         MultiByteToWideChar(CP_ACP, 0, lpUrlComponents->lpszScheme,
3962                             -1, urlCompW->lpszScheme, len);
3963     }
3964
3965     if (lpUrlComponents->lpszHostName)
3966     {
3967         len = URL_GET_COMP_LENGTHA(lpUrlComponents, HostName) + 1;
3968         urlCompW->lpszHostName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
3969         MultiByteToWideChar(CP_ACP, 0, lpUrlComponents->lpszHostName,
3970                             -1, urlCompW->lpszHostName, len);
3971     }
3972
3973     if (lpUrlComponents->lpszUserName)
3974     {
3975         len = URL_GET_COMP_LENGTHA(lpUrlComponents, UserName) + 1;
3976         urlCompW->lpszUserName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
3977         MultiByteToWideChar(CP_ACP, 0, lpUrlComponents->lpszUserName,
3978                             -1, urlCompW->lpszUserName, len);
3979     }
3980
3981     if (lpUrlComponents->lpszPassword)
3982     {
3983         len = URL_GET_COMP_LENGTHA(lpUrlComponents, Password) + 1;
3984         urlCompW->lpszPassword = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
3985         MultiByteToWideChar(CP_ACP, 0, lpUrlComponents->lpszPassword,
3986                             -1, urlCompW->lpszPassword, len);
3987     }
3988
3989     if (lpUrlComponents->lpszUrlPath)
3990     {
3991         len = URL_GET_COMP_LENGTHA(lpUrlComponents, UrlPath) + 1;
3992         urlCompW->lpszUrlPath = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
3993         MultiByteToWideChar(CP_ACP, 0, lpUrlComponents->lpszUrlPath,
3994                             -1, urlCompW->lpszUrlPath, len);
3995     }
3996
3997     if (lpUrlComponents->lpszExtraInfo)
3998     {
3999         len = URL_GET_COMP_LENGTHA(lpUrlComponents, ExtraInfo) + 1;
4000         urlCompW->lpszExtraInfo = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
4001         MultiByteToWideChar(CP_ACP, 0, lpUrlComponents->lpszExtraInfo,
4002                             -1, urlCompW->lpszExtraInfo, len);
4003     }
4004 }
4005
4006 /***********************************************************************
4007  *      InternetCreateUrlA (WININET.@)
4008  *
4009  * See InternetCreateUrlW.
4010  */
4011 BOOL WINAPI InternetCreateUrlA(LPURL_COMPONENTSA lpUrlComponents, DWORD dwFlags,
4012                                LPSTR lpszUrl, LPDWORD lpdwUrlLength)
4013 {
4014     BOOL ret;
4015     LPWSTR urlW = NULL;
4016     URL_COMPONENTSW urlCompW;
4017
4018     TRACE("(%p,%d,%p,%p)\n", lpUrlComponents, dwFlags, lpszUrl, lpdwUrlLength);
4019
4020     if (!lpUrlComponents || lpUrlComponents->dwStructSize != sizeof(URL_COMPONENTSW) || !lpdwUrlLength)
4021     {
4022         SetLastError(ERROR_INVALID_PARAMETER);
4023         return FALSE;
4024     }
4025
4026     convert_urlcomp_atow(lpUrlComponents, &urlCompW);
4027
4028     if (lpszUrl)
4029         urlW = HeapAlloc(GetProcessHeap(), 0, *lpdwUrlLength * sizeof(WCHAR));
4030
4031     ret = InternetCreateUrlW(&urlCompW, dwFlags, urlW, lpdwUrlLength);
4032
4033     if (!ret && (GetLastError() == ERROR_INSUFFICIENT_BUFFER))
4034         *lpdwUrlLength /= sizeof(WCHAR);
4035
4036     /* on success, lpdwUrlLength points to the size of urlW in WCHARS
4037     * minus one, so add one to leave room for NULL terminator
4038     */
4039     if (ret)
4040         WideCharToMultiByte(CP_ACP, 0, urlW, -1, lpszUrl, *lpdwUrlLength + 1, NULL, NULL);
4041
4042     HeapFree(GetProcessHeap(), 0, urlCompW.lpszScheme);
4043     HeapFree(GetProcessHeap(), 0, urlCompW.lpszHostName);
4044     HeapFree(GetProcessHeap(), 0, urlCompW.lpszUserName);
4045     HeapFree(GetProcessHeap(), 0, urlCompW.lpszPassword);
4046     HeapFree(GetProcessHeap(), 0, urlCompW.lpszUrlPath);
4047     HeapFree(GetProcessHeap(), 0, urlCompW.lpszExtraInfo);
4048     HeapFree(GetProcessHeap(), 0, urlW);
4049
4050     return ret;
4051 }
4052
4053 /***********************************************************************
4054  *      InternetCreateUrlW (WININET.@)
4055  *
4056  * Creates a URL from its component parts.
4057  *
4058  * PARAMS
4059  *  lpUrlComponents [I] URL Components.
4060  *  dwFlags         [I] Flags. See notes.
4061  *  lpszUrl         [I] Buffer in which to store the created URL.
4062  *  lpdwUrlLength   [I/O] On input, the length of the buffer pointed to by
4063  *                        lpszUrl in characters. On output, the number of bytes
4064  *                        required to store the URL including terminator.
4065  *
4066  * NOTES
4067  *
4068  * The dwFlags parameter can be zero or more of the following:
4069  *|ICU_ESCAPE - Generates escape sequences for unsafe characters in the path and extra info of the URL.
4070  *
4071  * RETURNS
4072  *   TRUE on success
4073  *   FALSE on failure
4074  *
4075  */
4076 BOOL WINAPI InternetCreateUrlW(LPURL_COMPONENTSW lpUrlComponents, DWORD dwFlags,
4077                                LPWSTR lpszUrl, LPDWORD lpdwUrlLength)
4078 {
4079     DWORD dwLen;
4080     INTERNET_SCHEME nScheme;
4081
4082     static const WCHAR slashSlashW[] = {'/','/'};
4083     static const WCHAR percentD[] = {'%','d',0};
4084
4085     TRACE("(%p,%d,%p,%p)\n", lpUrlComponents, dwFlags, lpszUrl, lpdwUrlLength);
4086
4087     if (!lpUrlComponents || lpUrlComponents->dwStructSize != sizeof(URL_COMPONENTSW) || !lpdwUrlLength)
4088     {
4089         INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
4090         return FALSE;
4091     }
4092
4093     if (!calc_url_length(lpUrlComponents, &dwLen))
4094         return FALSE;
4095
4096     if (!lpszUrl || *lpdwUrlLength < dwLen)
4097     {
4098         *lpdwUrlLength = (dwLen + 1) * sizeof(WCHAR);
4099         INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
4100         return FALSE;
4101     }
4102
4103     *lpdwUrlLength = dwLen;
4104     lpszUrl[0] = 0x00;
4105
4106     dwLen = 0;
4107
4108     if (lpUrlComponents->lpszScheme)
4109     {
4110         dwLen = URL_GET_COMP_LENGTH(lpUrlComponents, Scheme);
4111         memcpy(lpszUrl, lpUrlComponents->lpszScheme, dwLen * sizeof(WCHAR));
4112         lpszUrl += dwLen;
4113
4114         nScheme = GetInternetSchemeW(lpUrlComponents->lpszScheme, dwLen);
4115     }
4116     else
4117     {
4118         LPCWSTR scheme;
4119         nScheme = lpUrlComponents->nScheme;
4120
4121         if (nScheme == INTERNET_SCHEME_DEFAULT)
4122             nScheme = INTERNET_SCHEME_HTTP;
4123
4124         scheme = INTERNET_GetSchemeString(nScheme);
4125         dwLen = strlenW(scheme);
4126         memcpy(lpszUrl, scheme, dwLen * sizeof(WCHAR));
4127         lpszUrl += dwLen;
4128     }
4129
4130     /* all schemes are followed by at least a colon */
4131     *lpszUrl = ':';
4132     lpszUrl++;
4133
4134     if (!scheme_is_opaque(nScheme) || lpUrlComponents->lpszHostName)
4135     {
4136         memcpy(lpszUrl, slashSlashW, sizeof(slashSlashW));
4137         lpszUrl += sizeof(slashSlashW)/sizeof(slashSlashW[0]);
4138     }
4139
4140     if (lpUrlComponents->lpszUserName)
4141     {
4142         dwLen = URL_GET_COMP_LENGTH(lpUrlComponents, UserName);
4143         memcpy(lpszUrl, lpUrlComponents->lpszUserName, dwLen * sizeof(WCHAR));
4144         lpszUrl += dwLen;
4145
4146         if (lpUrlComponents->lpszPassword)
4147         {
4148             *lpszUrl = ':';
4149             lpszUrl++;
4150
4151             dwLen = URL_GET_COMP_LENGTH(lpUrlComponents, Password);
4152             memcpy(lpszUrl, lpUrlComponents->lpszPassword, dwLen * sizeof(WCHAR));
4153             lpszUrl += dwLen;
4154         }
4155
4156         *lpszUrl = '@';
4157         lpszUrl++;
4158     }
4159
4160     if (lpUrlComponents->lpszHostName)
4161     {
4162         dwLen = URL_GET_COMP_LENGTH(lpUrlComponents, HostName);
4163         memcpy(lpszUrl, lpUrlComponents->lpszHostName, dwLen * sizeof(WCHAR));
4164         lpszUrl += dwLen;
4165
4166         if (!url_uses_default_port(nScheme, lpUrlComponents->nPort))
4167         {
4168             WCHAR szPort[MAX_WORD_DIGITS+1];
4169
4170             sprintfW(szPort, percentD, lpUrlComponents->nPort);
4171             *lpszUrl = ':';
4172             lpszUrl++;
4173             dwLen = strlenW(szPort);
4174             memcpy(lpszUrl, szPort, dwLen * sizeof(WCHAR));
4175             lpszUrl += dwLen;
4176         }
4177
4178         /* add slash between hostname and path if necessary */
4179         if (lpUrlComponents->lpszUrlPath && *lpUrlComponents->lpszUrlPath != '/')
4180         {
4181             *lpszUrl = '/';
4182             lpszUrl++;
4183         }
4184     }
4185
4186     if (lpUrlComponents->lpszUrlPath)
4187     {
4188         dwLen = URL_GET_COMP_LENGTH(lpUrlComponents, UrlPath);
4189         memcpy(lpszUrl, lpUrlComponents->lpszUrlPath, dwLen * sizeof(WCHAR));
4190         lpszUrl += dwLen;
4191     }
4192
4193     if (lpUrlComponents->lpszExtraInfo)
4194     {
4195         dwLen = URL_GET_COMP_LENGTH(lpUrlComponents, ExtraInfo);
4196         memcpy(lpszUrl, lpUrlComponents->lpszExtraInfo, dwLen * sizeof(WCHAR));
4197         lpszUrl += dwLen;
4198     }
4199
4200     *lpszUrl = '\0';
4201
4202     return TRUE;
4203 }
4204
4205 /***********************************************************************
4206  *      InternetConfirmZoneCrossingA (WININET.@)
4207  *
4208  */
4209 DWORD WINAPI InternetConfirmZoneCrossingA( HWND hWnd, LPSTR szUrlPrev, LPSTR szUrlNew, BOOL bPost )
4210 {
4211     FIXME("(%p, %s, %s, %x) stub\n", hWnd, debugstr_a(szUrlPrev), debugstr_a(szUrlNew), bPost);
4212     return ERROR_SUCCESS;
4213 }
4214
4215 /***********************************************************************
4216  *      InternetConfirmZoneCrossingW (WININET.@)
4217  *
4218  */
4219 DWORD WINAPI InternetConfirmZoneCrossingW( HWND hWnd, LPWSTR szUrlPrev, LPWSTR szUrlNew, BOOL bPost )
4220 {
4221     FIXME("(%p, %s, %s, %x) stub\n", hWnd, debugstr_w(szUrlPrev), debugstr_w(szUrlNew), bPost);
4222     return ERROR_SUCCESS;
4223 }
4224
4225 static DWORD zone_preference = 3;
4226
4227 /***********************************************************************
4228  *      PrivacySetZonePreferenceW (WININET.@)
4229  */
4230 DWORD WINAPI PrivacySetZonePreferenceW( DWORD zone, DWORD type, DWORD template, LPCWSTR preference )
4231 {
4232     FIXME( "%x %x %x %s: stub\n", zone, type, template, debugstr_w(preference) );
4233
4234     zone_preference = template;
4235     return 0;
4236 }
4237
4238 /***********************************************************************
4239  *      PrivacyGetZonePreferenceW (WININET.@)
4240  */
4241 DWORD WINAPI PrivacyGetZonePreferenceW( DWORD zone, DWORD type, LPDWORD template,
4242                                         LPWSTR preference, LPDWORD length )
4243 {
4244     FIXME( "%x %x %p %p %p: stub\n", zone, type, template, preference, length );
4245
4246     if (template) *template = zone_preference;
4247     return 0;
4248 }
4249
4250 DWORD WINAPI InternetDialA( HWND hwndParent, LPSTR lpszConnectoid, DWORD dwFlags,
4251                             DWORD_PTR* lpdwConnection, DWORD dwReserved )
4252 {
4253     FIXME("(%p, %p, 0x%08x, %p, 0x%08x) stub\n", hwndParent, lpszConnectoid, dwFlags,
4254           lpdwConnection, dwReserved);
4255     return ERROR_SUCCESS;
4256 }
4257
4258 DWORD WINAPI InternetDialW( HWND hwndParent, LPWSTR lpszConnectoid, DWORD dwFlags,
4259                             DWORD_PTR* lpdwConnection, DWORD dwReserved )
4260 {
4261     FIXME("(%p, %p, 0x%08x, %p, 0x%08x) stub\n", hwndParent, lpszConnectoid, dwFlags,
4262           lpdwConnection, dwReserved);
4263     return ERROR_SUCCESS;
4264 }
4265
4266 BOOL WINAPI InternetGoOnlineA( LPSTR lpszURL, HWND hwndParent, DWORD dwReserved )
4267 {
4268     FIXME("(%s, %p, 0x%08x) stub\n", debugstr_a(lpszURL), hwndParent, dwReserved);
4269     return TRUE;
4270 }
4271
4272 BOOL WINAPI InternetGoOnlineW( LPWSTR lpszURL, HWND hwndParent, DWORD dwReserved )
4273 {
4274     FIXME("(%s, %p, 0x%08x) stub\n", debugstr_w(lpszURL), hwndParent, dwReserved);
4275     return TRUE;
4276 }
4277
4278 DWORD WINAPI InternetHangUp( DWORD_PTR dwConnection, DWORD dwReserved )
4279 {
4280     FIXME("(0x%08lx, 0x%08x) stub\n", dwConnection, dwReserved);
4281     return ERROR_SUCCESS;
4282 }
4283
4284 BOOL WINAPI CreateMD5SSOHash( PWSTR pszChallengeInfo, PWSTR pwszRealm, PWSTR pwszTarget,
4285                               PBYTE pbHexHash )
4286 {
4287     FIXME("(%s, %s, %s, %p) stub\n", debugstr_w(pszChallengeInfo), debugstr_w(pwszRealm),
4288           debugstr_w(pwszTarget), pbHexHash);
4289     return FALSE;
4290 }
4291
4292 BOOL WINAPI ResumeSuspendedDownload( HINTERNET hInternet, DWORD dwError )
4293 {
4294     FIXME("(%p, 0x%08x) stub\n", hInternet, dwError);
4295     return FALSE;
4296 }
4297
4298 BOOL WINAPI InternetQueryFortezzaStatus(DWORD *a, DWORD_PTR b)
4299 {
4300     FIXME("(%p, %08lx) stub\n", a, b);
4301     return 0;
4302 }