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