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