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