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