[WININET] Sync with Wine Staging 1.9.16. CORE-11866
[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 FIXME("INTERNET_OPTION_PER_CONNECTION_OPTION stub\n");
2392
2393 if (*size < sizeof(INTERNET_PER_CONN_OPTION_LISTW)) {
2394 FreeProxyInfo(&pi);
2395 return ERROR_INSUFFICIENT_BUFFER;
2396 }
2397
2398 url = get_proxy_autoconfig_url();
2399
2400 for (i = 0; i < con->dwOptionCount; i++) {
2401 INTERNET_PER_CONN_OPTIONW *optionW = con->pOptions + i;
2402 INTERNET_PER_CONN_OPTIONA *optionA = conA->pOptions + i;
2403
2404 switch (optionW->dwOption) {
2405 case INTERNET_PER_CONN_FLAGS:
2406 if(pi.proxyEnabled)
2407 optionW->Value.dwValue = PROXY_TYPE_PROXY;
2408 else
2409 optionW->Value.dwValue = PROXY_TYPE_DIRECT;
2410 if (url)
2411 /* native includes PROXY_TYPE_DIRECT even if PROXY_TYPE_PROXY is set */
2412 optionW->Value.dwValue |= PROXY_TYPE_DIRECT|PROXY_TYPE_AUTO_PROXY_URL;
2413 break;
2414
2415 case INTERNET_PER_CONN_PROXY_SERVER:
2416 if (unicode)
2417 optionW->Value.pszValue = heap_strdupW(pi.proxy);
2418 else
2419 optionA->Value.pszValue = heap_strdupWtoA(pi.proxy);
2420 break;
2421
2422 case INTERNET_PER_CONN_PROXY_BYPASS:
2423 if (unicode)
2424 optionW->Value.pszValue = heap_strdupW(pi.proxyBypass);
2425 else
2426 optionA->Value.pszValue = heap_strdupWtoA(pi.proxyBypass);
2427 break;
2428
2429 case INTERNET_PER_CONN_AUTOCONFIG_URL:
2430 if (!url)
2431 optionW->Value.pszValue = NULL;
2432 else if (unicode)
2433 optionW->Value.pszValue = heap_strdupW(url);
2434 else
2435 optionA->Value.pszValue = heap_strdupWtoA(url);
2436 break;
2437
2438 case INTERNET_PER_CONN_AUTODISCOVERY_FLAGS:
2439 optionW->Value.dwValue = AUTO_PROXY_FLAG_ALWAYS_DETECT;
2440 break;
2441
2442 case INTERNET_PER_CONN_AUTOCONFIG_SECONDARY_URL:
2443 case INTERNET_PER_CONN_AUTOCONFIG_RELOAD_DELAY_MINS:
2444 case INTERNET_PER_CONN_AUTOCONFIG_LAST_DETECT_TIME:
2445 case INTERNET_PER_CONN_AUTOCONFIG_LAST_DETECT_URL:
2446 FIXME("Unhandled dwOption %d\n", optionW->dwOption);
2447 memset(&optionW->Value, 0, sizeof(optionW->Value));
2448 break;
2449
2450 default:
2451 FIXME("Unknown dwOption %d\n", optionW->dwOption);
2452 res = ERROR_INVALID_PARAMETER;
2453 break;
2454 }
2455 }
2456 heap_free(url);
2457 FreeProxyInfo(&pi);
2458
2459 return res;
2460 }
2461 case INTERNET_OPTION_REQUEST_FLAGS:
2462 case INTERNET_OPTION_USER_AGENT:
2463 *size = 0;
2464 return ERROR_INTERNET_INCORRECT_HANDLE_TYPE;
2465 case INTERNET_OPTION_POLICY:
2466 return ERROR_INVALID_PARAMETER;
2467 case INTERNET_OPTION_CONNECT_TIMEOUT:
2468 TRACE("INTERNET_OPTION_CONNECT_TIMEOUT\n");
2469
2470 if (*size < sizeof(ULONG))
2471 return ERROR_INSUFFICIENT_BUFFER;
2472
2473 *(ULONG*)buffer = connect_timeout;
2474 *size = sizeof(ULONG);
2475
2476 return ERROR_SUCCESS;
2477 }
2478
2479 FIXME("Stub for %d\n", option);
2480 return ERROR_INTERNET_INCORRECT_HANDLE_TYPE;
2481 }
2482
2483 DWORD INET_QueryOption(object_header_t *hdr, DWORD option, void *buffer, DWORD *size, BOOL unicode)
2484 {
2485 switch(option) {
2486 case INTERNET_OPTION_CONTEXT_VALUE:
2487 if (!size)
2488 return ERROR_INVALID_PARAMETER;
2489
2490 if (*size < sizeof(DWORD_PTR)) {
2491 *size = sizeof(DWORD_PTR);
2492 return ERROR_INSUFFICIENT_BUFFER;
2493 }
2494 if (!buffer)
2495 return ERROR_INVALID_PARAMETER;
2496
2497 *(DWORD_PTR *)buffer = hdr->dwContext;
2498 *size = sizeof(DWORD_PTR);
2499 return ERROR_SUCCESS;
2500
2501 case INTERNET_OPTION_REQUEST_FLAGS:
2502 WARN("INTERNET_OPTION_REQUEST_FLAGS\n");
2503 *size = sizeof(DWORD);
2504 return ERROR_INTERNET_INCORRECT_HANDLE_TYPE;
2505
2506 case INTERNET_OPTION_MAX_CONNS_PER_SERVER:
2507 case INTERNET_OPTION_MAX_CONNS_PER_1_0_SERVER:
2508 WARN("Called on global option %u\n", option);
2509 return ERROR_INTERNET_INVALID_OPERATION;
2510 }
2511
2512 /* FIXME: we shouldn't call it here */
2513 return query_global_option(option, buffer, size, unicode);
2514 }
2515
2516 /***********************************************************************
2517 * InternetQueryOptionW (WININET.@)
2518 *
2519 * Queries an options on the specified handle
2520 *
2521 * RETURNS
2522 * TRUE on success
2523 * FALSE on failure
2524 *
2525 */
2526 BOOL WINAPI InternetQueryOptionW(HINTERNET hInternet, DWORD dwOption,
2527 LPVOID lpBuffer, LPDWORD lpdwBufferLength)
2528 {
2529 object_header_t *hdr;
2530 DWORD res = ERROR_INVALID_HANDLE;
2531
2532 TRACE("%p %d %p %p\n", hInternet, dwOption, lpBuffer, lpdwBufferLength);
2533
2534 if(hInternet) {
2535 hdr = get_handle_object(hInternet);
2536 if (hdr) {
2537 res = hdr->vtbl->QueryOption(hdr, dwOption, lpBuffer, lpdwBufferLength, TRUE);
2538 WININET_Release(hdr);
2539 }
2540 }else {
2541 res = query_global_option(dwOption, lpBuffer, lpdwBufferLength, TRUE);
2542 }
2543
2544 if(res != ERROR_SUCCESS)
2545 SetLastError(res);
2546 return res == ERROR_SUCCESS;
2547 }
2548
2549 /***********************************************************************
2550 * InternetQueryOptionA (WININET.@)
2551 *
2552 * Queries an options on the specified handle
2553 *
2554 * RETURNS
2555 * TRUE on success
2556 * FALSE on failure
2557 *
2558 */
2559 BOOL WINAPI InternetQueryOptionA(HINTERNET hInternet, DWORD dwOption,
2560 LPVOID lpBuffer, LPDWORD lpdwBufferLength)
2561 {
2562 object_header_t *hdr;
2563 DWORD res = ERROR_INVALID_HANDLE;
2564
2565 TRACE("%p %d %p %p\n", hInternet, dwOption, lpBuffer, lpdwBufferLength);
2566
2567 if(hInternet) {
2568 hdr = get_handle_object(hInternet);
2569 if (hdr) {
2570 res = hdr->vtbl->QueryOption(hdr, dwOption, lpBuffer, lpdwBufferLength, FALSE);
2571 WININET_Release(hdr);
2572 }
2573 }else {
2574 res = query_global_option(dwOption, lpBuffer, lpdwBufferLength, FALSE);
2575 }
2576
2577 if(res != ERROR_SUCCESS)
2578 SetLastError(res);
2579 return res == ERROR_SUCCESS;
2580 }
2581
2582 DWORD INET_SetOption(object_header_t *hdr, DWORD option, void *buf, DWORD size)
2583 {
2584 switch(option) {
2585 case INTERNET_OPTION_CALLBACK:
2586 WARN("Not settable option %u\n", option);
2587 return ERROR_INTERNET_OPTION_NOT_SETTABLE;
2588 case INTERNET_OPTION_MAX_CONNS_PER_SERVER:
2589 case INTERNET_OPTION_MAX_CONNS_PER_1_0_SERVER:
2590 WARN("Called on global option %u\n", option);
2591 return ERROR_INTERNET_INVALID_OPERATION;
2592 }
2593
2594 return ERROR_INTERNET_INVALID_OPTION;
2595 }
2596
2597 static DWORD set_global_option(DWORD option, void *buf, DWORD size)
2598 {
2599 switch(option) {
2600 case INTERNET_OPTION_CALLBACK:
2601 WARN("Not global option %u\n", option);
2602 return ERROR_INTERNET_INCORRECT_HANDLE_TYPE;
2603
2604 case INTERNET_OPTION_MAX_CONNS_PER_SERVER:
2605 TRACE("INTERNET_OPTION_MAX_CONNS_PER_SERVER\n");
2606
2607 if(size != sizeof(max_conns))
2608 return ERROR_INTERNET_BAD_OPTION_LENGTH;
2609 if(!*(ULONG*)buf)
2610 return ERROR_BAD_ARGUMENTS;
2611
2612 max_conns = *(ULONG*)buf;
2613 return ERROR_SUCCESS;
2614
2615 case INTERNET_OPTION_MAX_CONNS_PER_1_0_SERVER:
2616 TRACE("INTERNET_OPTION_MAX_CONNS_PER_1_0_SERVER\n");
2617
2618 if(size != sizeof(max_1_0_conns))
2619 return ERROR_INTERNET_BAD_OPTION_LENGTH;
2620 if(!*(ULONG*)buf)
2621 return ERROR_BAD_ARGUMENTS;
2622
2623 max_1_0_conns = *(ULONG*)buf;
2624 return ERROR_SUCCESS;
2625
2626 case INTERNET_OPTION_CONNECT_TIMEOUT:
2627 TRACE("INTERNET_OPTION_CONNECT_TIMEOUT\n");
2628
2629 if(size != sizeof(connect_timeout))
2630 return ERROR_INTERNET_BAD_OPTION_LENGTH;
2631 if(!*(ULONG*)buf)
2632 return ERROR_BAD_ARGUMENTS;
2633
2634 connect_timeout = *(ULONG*)buf;
2635 return ERROR_SUCCESS;
2636
2637 case INTERNET_OPTION_SETTINGS_CHANGED:
2638 FIXME("INTERNETOPTION_SETTINGS_CHANGED semi-stub\n");
2639 collect_connections(COLLECT_CONNECTIONS);
2640 return ERROR_SUCCESS;
2641
2642 case INTERNET_OPTION_SUPPRESS_BEHAVIOR:
2643 FIXME("INTERNET_OPTION_SUPPRESS_BEHAVIOR stub\n");
2644
2645 if(size != sizeof(ULONG))
2646 return ERROR_INTERNET_BAD_OPTION_LENGTH;
2647
2648 FIXME("%08x\n", *(ULONG*)buf);
2649 return ERROR_SUCCESS;
2650 }
2651
2652 return ERROR_INTERNET_INVALID_OPTION;
2653 }
2654
2655 /***********************************************************************
2656 * InternetSetOptionW (WININET.@)
2657 *
2658 * Sets an options on the specified handle
2659 *
2660 * RETURNS
2661 * TRUE on success
2662 * FALSE on failure
2663 *
2664 */
2665 BOOL WINAPI InternetSetOptionW(HINTERNET hInternet, DWORD dwOption,
2666 LPVOID lpBuffer, DWORD dwBufferLength)
2667 {
2668 object_header_t *lpwhh;
2669 BOOL ret = TRUE;
2670 DWORD res;
2671
2672 TRACE("(%p %d %p %d)\n", hInternet, dwOption, lpBuffer, dwBufferLength);
2673
2674 lpwhh = (object_header_t*) get_handle_object( hInternet );
2675 if(lpwhh)
2676 res = lpwhh->vtbl->SetOption(lpwhh, dwOption, lpBuffer, dwBufferLength);
2677 else
2678 res = set_global_option(dwOption, lpBuffer, dwBufferLength);
2679
2680 if(res != ERROR_INTERNET_INVALID_OPTION) {
2681 if(lpwhh)
2682 WININET_Release(lpwhh);
2683
2684 if(res != ERROR_SUCCESS)
2685 SetLastError(res);
2686
2687 return res == ERROR_SUCCESS;
2688 }
2689
2690 switch (dwOption)
2691 {
2692 case INTERNET_OPTION_HTTP_VERSION:
2693 {
2694 HTTP_VERSION_INFO* pVersion=(HTTP_VERSION_INFO*)lpBuffer;
2695 FIXME("Option INTERNET_OPTION_HTTP_VERSION(%d,%d): STUB\n",pVersion->dwMajorVersion,pVersion->dwMinorVersion);
2696 }
2697 break;
2698 case INTERNET_OPTION_ERROR_MASK:
2699 {
2700 if(!lpwhh) {
2701 SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
2702 return FALSE;
2703 } else if(*(ULONG*)lpBuffer & (~(INTERNET_ERROR_MASK_INSERT_CDROM|
2704 INTERNET_ERROR_MASK_COMBINED_SEC_CERT|
2705 INTERNET_ERROR_MASK_LOGIN_FAILURE_DISPLAY_ENTITY_BODY))) {
2706 SetLastError(ERROR_INVALID_PARAMETER);
2707 ret = FALSE;
2708 } else if(dwBufferLength != sizeof(ULONG)) {
2709 SetLastError(ERROR_INTERNET_BAD_OPTION_LENGTH);
2710 ret = FALSE;
2711 } else
2712 TRACE("INTERNET_OPTION_ERROR_MASK: %x\n", *(ULONG*)lpBuffer);
2713 lpwhh->ErrorMask = *(ULONG*)lpBuffer;
2714 }
2715 break;
2716 case INTERNET_OPTION_PROXY:
2717 {
2718 INTERNET_PROXY_INFOW *info = lpBuffer;
2719
2720 if (!lpBuffer || dwBufferLength < sizeof(INTERNET_PROXY_INFOW))
2721 {
2722 SetLastError(ERROR_INVALID_PARAMETER);
2723 return FALSE;
2724 }
2725 if (!hInternet)
2726 {
2727 EnterCriticalSection( &WININET_cs );
2728 free_global_proxy();
2729 global_proxy = heap_alloc( sizeof(proxyinfo_t) );
2730 if (global_proxy)
2731 {
2732 if (info->dwAccessType == INTERNET_OPEN_TYPE_PROXY)
2733 {
2734 global_proxy->proxyEnabled = 1;
2735 global_proxy->proxy = heap_strdupW( info->lpszProxy );
2736 global_proxy->proxyBypass = heap_strdupW( info->lpszProxyBypass );
2737 }
2738 else
2739 {
2740 global_proxy->proxyEnabled = 0;
2741 global_proxy->proxy = global_proxy->proxyBypass = NULL;
2742 }
2743 }
2744 LeaveCriticalSection( &WININET_cs );
2745 }
2746 else
2747 {
2748 /* In general, each type of object should handle
2749 * INTERNET_OPTION_PROXY directly. This FIXME ensures it doesn't
2750 * get silently dropped.
2751 */
2752 FIXME("INTERNET_OPTION_PROXY unimplemented\n");
2753 SetLastError(ERROR_INTERNET_INVALID_OPTION);
2754 ret = FALSE;
2755 }
2756 break;
2757 }
2758 case INTERNET_OPTION_CODEPAGE:
2759 {
2760 ULONG codepage = *(ULONG *)lpBuffer;
2761 FIXME("Option INTERNET_OPTION_CODEPAGE (%d): STUB\n", codepage);
2762 }
2763 break;
2764 case INTERNET_OPTION_REQUEST_PRIORITY:
2765 {
2766 ULONG priority = *(ULONG *)lpBuffer;
2767 FIXME("Option INTERNET_OPTION_REQUEST_PRIORITY (%d): STUB\n", priority);
2768 }
2769 break;
2770 case INTERNET_OPTION_CONNECT_TIMEOUT:
2771 {
2772 ULONG connecttimeout = *(ULONG *)lpBuffer;
2773 FIXME("Option INTERNET_OPTION_CONNECT_TIMEOUT (%d): STUB\n", connecttimeout);
2774 }
2775 break;
2776 case INTERNET_OPTION_DATA_RECEIVE_TIMEOUT:
2777 {
2778 ULONG receivetimeout = *(ULONG *)lpBuffer;
2779 FIXME("Option INTERNET_OPTION_DATA_RECEIVE_TIMEOUT (%d): STUB\n", receivetimeout);
2780 }
2781 break;
2782 case INTERNET_OPTION_RESET_URLCACHE_SESSION:
2783 FIXME("Option INTERNET_OPTION_RESET_URLCACHE_SESSION: STUB\n");
2784 break;
2785 case INTERNET_OPTION_END_BROWSER_SESSION:
2786 FIXME("Option INTERNET_OPTION_END_BROWSER_SESSION: semi-stub\n");
2787 free_cookie();
2788 break;
2789 case INTERNET_OPTION_CONNECTED_STATE:
2790 FIXME("Option INTERNET_OPTION_CONNECTED_STATE: STUB\n");
2791 break;
2792 case INTERNET_OPTION_DISABLE_PASSPORT_AUTH:
2793 TRACE("Option INTERNET_OPTION_DISABLE_PASSPORT_AUTH: harmless stub, since not enabled\n");
2794 break;
2795 case INTERNET_OPTION_SEND_TIMEOUT:
2796 case INTERNET_OPTION_RECEIVE_TIMEOUT:
2797 case INTERNET_OPTION_DATA_SEND_TIMEOUT:
2798 {
2799 ULONG timeout = *(ULONG *)lpBuffer;
2800 FIXME("INTERNET_OPTION_SEND/RECEIVE_TIMEOUT/DATA_SEND_TIMEOUT %d\n", timeout);
2801 break;
2802 }
2803 case INTERNET_OPTION_CONNECT_RETRIES:
2804 {
2805 ULONG retries = *(ULONG *)lpBuffer;
2806 FIXME("INTERNET_OPTION_CONNECT_RETRIES %d\n", retries);
2807 break;
2808 }
2809 case INTERNET_OPTION_CONTEXT_VALUE:
2810 {
2811 if (!lpwhh)
2812 {
2813 SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
2814 return FALSE;
2815 }
2816 if (!lpBuffer || dwBufferLength != sizeof(DWORD_PTR))
2817 {
2818 SetLastError(ERROR_INVALID_PARAMETER);
2819 ret = FALSE;
2820 }
2821 else
2822 lpwhh->dwContext = *(DWORD_PTR *)lpBuffer;
2823 break;
2824 }
2825 case INTERNET_OPTION_SECURITY_FLAGS:
2826 FIXME("Option INTERNET_OPTION_SECURITY_FLAGS; STUB\n");
2827 break;
2828 case INTERNET_OPTION_DISABLE_AUTODIAL:
2829 FIXME("Option INTERNET_OPTION_DISABLE_AUTODIAL; STUB\n");
2830 break;
2831 case INTERNET_OPTION_HTTP_DECODING:
2832 FIXME("INTERNET_OPTION_HTTP_DECODING; STUB\n");
2833 SetLastError(ERROR_INTERNET_INVALID_OPTION);
2834 ret = FALSE;
2835 break;
2836 case INTERNET_OPTION_COOKIES_3RD_PARTY:
2837 FIXME("INTERNET_OPTION_COOKIES_3RD_PARTY; STUB\n");
2838 SetLastError(ERROR_INTERNET_INVALID_OPTION);
2839 ret = FALSE;
2840 break;
2841 case INTERNET_OPTION_SEND_UTF8_SERVERNAME_TO_PROXY:
2842 FIXME("INTERNET_OPTION_SEND_UTF8_SERVERNAME_TO_PROXY; STUB\n");
2843 SetLastError(ERROR_INTERNET_INVALID_OPTION);
2844 ret = FALSE;
2845 break;
2846 case INTERNET_OPTION_CODEPAGE_PATH:
2847 FIXME("INTERNET_OPTION_CODEPAGE_PATH; STUB\n");
2848 SetLastError(ERROR_INTERNET_INVALID_OPTION);
2849 ret = FALSE;
2850 break;
2851 case INTERNET_OPTION_CODEPAGE_EXTRA:
2852 FIXME("INTERNET_OPTION_CODEPAGE_EXTRA; STUB\n");
2853 SetLastError(ERROR_INTERNET_INVALID_OPTION);
2854 ret = FALSE;
2855 break;
2856 case INTERNET_OPTION_IDN:
2857 FIXME("INTERNET_OPTION_IDN; STUB\n");
2858 SetLastError(ERROR_INTERNET_INVALID_OPTION);
2859 ret = FALSE;
2860 break;
2861 case INTERNET_OPTION_POLICY:
2862 SetLastError(ERROR_INVALID_PARAMETER);
2863 ret = FALSE;
2864 break;
2865 case INTERNET_OPTION_PER_CONNECTION_OPTION: {
2866 INTERNET_PER_CONN_OPTION_LISTW *con = lpBuffer;
2867 LONG res;
2868 unsigned int i;
2869 proxyinfo_t pi;
2870
2871 if (INTERNET_LoadProxySettings(&pi)) return FALSE;
2872
2873 for (i = 0; i < con->dwOptionCount; i++) {
2874 INTERNET_PER_CONN_OPTIONW *option = con->pOptions + i;
2875
2876 switch (option->dwOption) {
2877 case INTERNET_PER_CONN_PROXY_SERVER:
2878 heap_free(pi.proxy);
2879 pi.proxy = heap_strdupW(option->Value.pszValue);
2880 break;
2881
2882 case INTERNET_PER_CONN_FLAGS:
2883 if(option->Value.dwValue & PROXY_TYPE_PROXY)
2884 pi.proxyEnabled = 1;
2885 else
2886 {
2887 if(option->Value.dwValue != PROXY_TYPE_DIRECT)
2888 FIXME("Unhandled flags: 0x%x\n", option->Value.dwValue);
2889 pi.proxyEnabled = 0;
2890 }
2891 break;
2892
2893 case INTERNET_PER_CONN_PROXY_BYPASS:
2894 heap_free(pi.proxyBypass);
2895 pi.proxyBypass = heap_strdupW(option->Value.pszValue);
2896 break;
2897
2898 case INTERNET_PER_CONN_AUTOCONFIG_URL:
2899 case INTERNET_PER_CONN_AUTODISCOVERY_FLAGS:
2900 case INTERNET_PER_CONN_AUTOCONFIG_SECONDARY_URL:
2901 case INTERNET_PER_CONN_AUTOCONFIG_RELOAD_DELAY_MINS:
2902 case INTERNET_PER_CONN_AUTOCONFIG_LAST_DETECT_TIME:
2903 case INTERNET_PER_CONN_AUTOCONFIG_LAST_DETECT_URL:
2904 FIXME("Unhandled dwOption %d\n", option->dwOption);
2905 break;
2906
2907 default:
2908 FIXME("Unknown dwOption %d\n", option->dwOption);
2909 SetLastError(ERROR_INVALID_PARAMETER);
2910 break;
2911 }
2912 }
2913
2914 if ((res = INTERNET_SaveProxySettings(&pi)))
2915 SetLastError(res);
2916
2917 FreeProxyInfo(&pi);
2918
2919 ret = (res == ERROR_SUCCESS);
2920 break;
2921 }
2922 case INTERNET_OPTION_SETTINGS_CHANGED:
2923 FIXME("INTERNET_OPTION_SETTINGS_CHANGED; STUB\n");
2924 break;
2925 case INTERNET_OPTION_REFRESH:
2926 FIXME("INTERNET_OPTION_REFRESH; STUB\n");
2927 break;
2928 default:
2929 FIXME("Option %d STUB\n",dwOption);
2930 SetLastError(ERROR_INTERNET_INVALID_OPTION);
2931 ret = FALSE;
2932 break;
2933 }
2934
2935 if(lpwhh)
2936 WININET_Release( lpwhh );
2937
2938 return ret;
2939 }
2940
2941
2942 /***********************************************************************
2943 * InternetSetOptionA (WININET.@)
2944 *
2945 * Sets an options on the specified handle.
2946 *
2947 * RETURNS
2948 * TRUE on success
2949 * FALSE on failure
2950 *
2951 */
2952 BOOL WINAPI InternetSetOptionA(HINTERNET hInternet, DWORD dwOption,
2953 LPVOID lpBuffer, DWORD dwBufferLength)
2954 {
2955 LPVOID wbuffer;
2956 DWORD wlen;
2957 BOOL r;
2958
2959 switch( dwOption )
2960 {
2961 case INTERNET_OPTION_PROXY:
2962 {
2963 LPINTERNET_PROXY_INFOA pi = (LPINTERNET_PROXY_INFOA) lpBuffer;
2964 LPINTERNET_PROXY_INFOW piw;
2965 DWORD proxlen, prbylen;
2966 LPWSTR prox, prby;
2967
2968 proxlen = MultiByteToWideChar( CP_ACP, 0, pi->lpszProxy, -1, NULL, 0);
2969 prbylen= MultiByteToWideChar( CP_ACP, 0, pi->lpszProxyBypass, -1, NULL, 0);
2970 wlen = sizeof(*piw) + proxlen + prbylen;
2971 wbuffer = heap_alloc(wlen*sizeof(WCHAR) );
2972 piw = (LPINTERNET_PROXY_INFOW) wbuffer;
2973 piw->dwAccessType = pi->dwAccessType;
2974 prox = (LPWSTR) &piw[1];
2975 prby = &prox[proxlen+1];
2976 MultiByteToWideChar( CP_ACP, 0, pi->lpszProxy, -1, prox, proxlen);
2977 MultiByteToWideChar( CP_ACP, 0, pi->lpszProxyBypass, -1, prby, prbylen);
2978 piw->lpszProxy = prox;
2979 piw->lpszProxyBypass = prby;
2980 }
2981 break;
2982 case INTERNET_OPTION_USER_AGENT:
2983 case INTERNET_OPTION_USERNAME:
2984 case INTERNET_OPTION_PASSWORD:
2985 case INTERNET_OPTION_PROXY_USERNAME:
2986 case INTERNET_OPTION_PROXY_PASSWORD:
2987 wlen = MultiByteToWideChar( CP_ACP, 0, lpBuffer, -1, NULL, 0 );
2988 if (!(wbuffer = heap_alloc( wlen * sizeof(WCHAR) ))) return ERROR_OUTOFMEMORY;
2989 MultiByteToWideChar( CP_ACP, 0, lpBuffer, -1, wbuffer, wlen );
2990 break;
2991 case INTERNET_OPTION_PER_CONNECTION_OPTION: {
2992 unsigned int i;
2993 INTERNET_PER_CONN_OPTION_LISTW *listW;
2994 INTERNET_PER_CONN_OPTION_LISTA *listA = lpBuffer;
2995 wlen = sizeof(INTERNET_PER_CONN_OPTION_LISTW);
2996 wbuffer = heap_alloc(wlen);
2997 listW = wbuffer;
2998
2999 listW->dwSize = sizeof(INTERNET_PER_CONN_OPTION_LISTW);
3000 if (listA->pszConnection)
3001 {
3002 wlen = MultiByteToWideChar( CP_ACP, 0, listA->pszConnection, -1, NULL, 0 );
3003 listW->pszConnection = heap_alloc(wlen*sizeof(WCHAR));
3004 MultiByteToWideChar( CP_ACP, 0, listA->pszConnection, -1, listW->pszConnection, wlen );
3005 }
3006 else
3007 listW->pszConnection = NULL;
3008 listW->dwOptionCount = listA->dwOptionCount;
3009 listW->dwOptionError = listA->dwOptionError;
3010 listW->pOptions = heap_alloc(sizeof(INTERNET_PER_CONN_OPTIONW) * listA->dwOptionCount);
3011
3012 for (i = 0; i < listA->dwOptionCount; ++i) {
3013 INTERNET_PER_CONN_OPTIONA *optA = listA->pOptions + i;
3014 INTERNET_PER_CONN_OPTIONW *optW = listW->pOptions + i;
3015
3016 optW->dwOption = optA->dwOption;
3017
3018 switch (optA->dwOption) {
3019 case INTERNET_PER_CONN_AUTOCONFIG_URL:
3020 case INTERNET_PER_CONN_PROXY_BYPASS:
3021 case INTERNET_PER_CONN_PROXY_SERVER:
3022 case INTERNET_PER_CONN_AUTOCONFIG_SECONDARY_URL:
3023 case INTERNET_PER_CONN_AUTOCONFIG_LAST_DETECT_URL:
3024 if (optA->Value.pszValue)
3025 {
3026 wlen = MultiByteToWideChar( CP_ACP, 0, optA->Value.pszValue, -1, NULL, 0 );
3027 optW->Value.pszValue = heap_alloc(wlen*sizeof(WCHAR));
3028 MultiByteToWideChar( CP_ACP, 0, optA->Value.pszValue, -1, optW->Value.pszValue, wlen );
3029 }
3030 else
3031 optW->Value.pszValue = NULL;
3032 break;
3033 case INTERNET_PER_CONN_AUTODISCOVERY_FLAGS:
3034 case INTERNET_PER_CONN_FLAGS:
3035 case INTERNET_PER_CONN_AUTOCONFIG_RELOAD_DELAY_MINS:
3036 optW->Value.dwValue = optA->Value.dwValue;
3037 break;
3038 case INTERNET_PER_CONN_AUTOCONFIG_LAST_DETECT_TIME:
3039 optW->Value.ftValue = optA->Value.ftValue;
3040 break;
3041 default:
3042 WARN("Unknown PER_CONN dwOption: %d, guessing at conversion to Wide\n", optA->dwOption);
3043 optW->Value.dwValue = optA->Value.dwValue;
3044 break;
3045 }
3046 }
3047 }
3048 break;
3049 default:
3050 wbuffer = lpBuffer;
3051 wlen = dwBufferLength;
3052 }
3053
3054 r = InternetSetOptionW(hInternet,dwOption, wbuffer, wlen);
3055
3056 if( lpBuffer != wbuffer )
3057 {
3058 if (dwOption == INTERNET_OPTION_PER_CONNECTION_OPTION)
3059 {
3060 INTERNET_PER_CONN_OPTION_LISTW *list = wbuffer;
3061 unsigned int i;
3062 for (i = 0; i < list->dwOptionCount; ++i) {
3063 INTERNET_PER_CONN_OPTIONW *opt = list->pOptions + i;
3064 switch (opt->dwOption) {
3065 case INTERNET_PER_CONN_AUTOCONFIG_URL:
3066 case INTERNET_PER_CONN_PROXY_BYPASS:
3067 case INTERNET_PER_CONN_PROXY_SERVER:
3068 case INTERNET_PER_CONN_AUTOCONFIG_SECONDARY_URL:
3069 case INTERNET_PER_CONN_AUTOCONFIG_LAST_DETECT_URL:
3070 heap_free( opt->Value.pszValue );
3071 break;
3072 default:
3073 break;
3074 }
3075 }
3076 heap_free( list->pOptions );
3077 }
3078 heap_free( wbuffer );
3079 }
3080
3081 return r;
3082 }
3083
3084
3085 /***********************************************************************
3086 * InternetSetOptionExA (WININET.@)
3087 */
3088 BOOL WINAPI InternetSetOptionExA(HINTERNET hInternet, DWORD dwOption,
3089 LPVOID lpBuffer, DWORD dwBufferLength, DWORD dwFlags)
3090 {
3091 FIXME("Flags %08x ignored\n", dwFlags);
3092 return InternetSetOptionA( hInternet, dwOption, lpBuffer, dwBufferLength );
3093 }
3094
3095 /***********************************************************************
3096 * InternetSetOptionExW (WININET.@)
3097 */
3098 BOOL WINAPI InternetSetOptionExW(HINTERNET hInternet, DWORD dwOption,
3099 LPVOID lpBuffer, DWORD dwBufferLength, DWORD dwFlags)
3100 {
3101 FIXME("Flags %08x ignored\n", dwFlags);
3102 if( dwFlags & ~ISO_VALID_FLAGS )
3103 {
3104 SetLastError( ERROR_INVALID_PARAMETER );
3105 return FALSE;
3106 }
3107 return InternetSetOptionW( hInternet, dwOption, lpBuffer, dwBufferLength );
3108 }
3109
3110 static const WCHAR WININET_wkday[7][4] =
3111 { { 'S','u','n', 0 }, { 'M','o','n', 0 }, { 'T','u','e', 0 }, { 'W','e','d', 0 },
3112 { 'T','h','u', 0 }, { 'F','r','i', 0 }, { 'S','a','t', 0 } };
3113 static const WCHAR WININET_month[12][4] =
3114 { { 'J','a','n', 0 }, { 'F','e','b', 0 }, { 'M','a','r', 0 }, { 'A','p','r', 0 },
3115 { 'M','a','y', 0 }, { 'J','u','n', 0 }, { 'J','u','l', 0 }, { 'A','u','g', 0 },
3116 { 'S','e','p', 0 }, { 'O','c','t', 0 }, { 'N','o','v', 0 }, { 'D','e','c', 0 } };
3117
3118 /***********************************************************************
3119 * InternetTimeFromSystemTimeA (WININET.@)
3120 */
3121 BOOL WINAPI InternetTimeFromSystemTimeA( const SYSTEMTIME* time, DWORD format, LPSTR string, DWORD size )
3122 {
3123 BOOL ret;
3124 WCHAR stringW[INTERNET_RFC1123_BUFSIZE];
3125
3126 TRACE( "%p 0x%08x %p 0x%08x\n", time, format, string, size );
3127
3128 if (!time || !string || format != INTERNET_RFC1123_FORMAT)
3129 {
3130 SetLastError(ERROR_INVALID_PARAMETER);
3131 return FALSE;
3132 }
3133
3134 if (size < INTERNET_RFC1123_BUFSIZE * sizeof(*string))
3135 {
3136 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3137 return FALSE;
3138 }
3139
3140 ret = InternetTimeFromSystemTimeW( time, format, stringW, sizeof(stringW) );
3141 if (ret) WideCharToMultiByte( CP_ACP, 0, stringW, -1, string, size, NULL, NULL );
3142
3143 return ret;
3144 }
3145
3146 /***********************************************************************
3147 * InternetTimeFromSystemTimeW (WININET.@)
3148 */
3149 BOOL WINAPI InternetTimeFromSystemTimeW( const SYSTEMTIME* time, DWORD format, LPWSTR string, DWORD size )
3150 {
3151 static const WCHAR date[] =
3152 { '%','s',',',' ','%','0','2','d',' ','%','s',' ','%','4','d',' ','%','0',
3153 '2','d',':','%','0','2','d',':','%','0','2','d',' ','G','M','T', 0 };
3154
3155 TRACE( "%p 0x%08x %p 0x%08x\n", time, format, string, size );
3156
3157 if (!time || !string || format != INTERNET_RFC1123_FORMAT)
3158 {
3159 SetLastError(ERROR_INVALID_PARAMETER);
3160 return FALSE;
3161 }
3162
3163 if (size < INTERNET_RFC1123_BUFSIZE * sizeof(*string))
3164 {
3165 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3166 return FALSE;
3167 }
3168
3169 sprintfW( string, date,
3170 WININET_wkday[time->wDayOfWeek],
3171 time->wDay,
3172 WININET_month[time->wMonth - 1],
3173 time->wYear,
3174 time->wHour,
3175 time->wMinute,
3176 time->wSecond );
3177
3178 return TRUE;
3179 }
3180
3181 /***********************************************************************
3182 * InternetTimeToSystemTimeA (WININET.@)
3183 */
3184 BOOL WINAPI InternetTimeToSystemTimeA( LPCSTR string, SYSTEMTIME* time, DWORD reserved )
3185 {
3186 BOOL ret = FALSE;
3187 WCHAR *stringW;
3188
3189 TRACE( "%s %p 0x%08x\n", debugstr_a(string), time, reserved );
3190
3191 stringW = heap_strdupAtoW(string);
3192 if (stringW)
3193 {
3194 ret = InternetTimeToSystemTimeW( stringW, time, reserved );
3195 heap_free( stringW );
3196 }
3197 return ret;
3198 }
3199
3200 /***********************************************************************
3201 * InternetTimeToSystemTimeW (WININET.@)
3202 */
3203 BOOL WINAPI InternetTimeToSystemTimeW( LPCWSTR string, SYSTEMTIME* time, DWORD reserved )
3204 {
3205 unsigned int i;
3206 const WCHAR *s = string;
3207 WCHAR *end;
3208
3209 TRACE( "%s %p 0x%08x\n", debugstr_w(string), time, reserved );
3210
3211 if (!string || !time) return FALSE;
3212
3213 /* Windows does this too */
3214 GetSystemTime( time );
3215
3216 /* Convert an RFC1123 time such as 'Fri, 07 Jan 2005 12:06:35 GMT' into
3217 * a SYSTEMTIME structure.
3218 */
3219
3220 while (*s && !isalphaW( *s )) s++;
3221 if (s[0] == '\0' || s[1] == '\0' || s[2] == '\0') return TRUE;
3222 time->wDayOfWeek = 7;
3223
3224 for (i = 0; i < 7; i++)
3225 {
3226 if (toupperW( WININET_wkday[i][0] ) == toupperW( s[0] ) &&
3227 toupperW( WININET_wkday[i][1] ) == toupperW( s[1] ) &&
3228 toupperW( WININET_wkday[i][2] ) == toupperW( s[2] ) )
3229 {
3230 time->wDayOfWeek = i;
3231 break;
3232 }
3233 }
3234
3235 if (time->wDayOfWeek > 6) return TRUE;
3236 while (*s && !isdigitW( *s )) s++;
3237 time->wDay = strtolW( s, &end, 10 );
3238 s = end;
3239
3240 while (*s && !isalphaW( *s )) s++;
3241 if (s[0] == '\0' || s[1] == '\0' || s[2] == '\0') return TRUE;
3242 time->wMonth = 0;
3243
3244 for (i = 0; i < 12; i++)
3245 {
3246 if (toupperW( WININET_month[i][0]) == toupperW( s[0] ) &&
3247 toupperW( WININET_month[i][1]) == toupperW( s[1] ) &&
3248 toupperW( WININET_month[i][2]) == toupperW( s[2] ) )
3249 {
3250 time->wMonth = i + 1;
3251 break;
3252 }
3253 }
3254 if (time->wMonth == 0) return TRUE;
3255
3256 while (*s && !isdigitW( *s )) s++;
3257 if (*s == '\0') return TRUE;
3258 time->wYear = strtolW( s, &end, 10 );
3259 s = end;
3260
3261 while (*s && !isdigitW( *s )) s++;
3262 if (*s == '\0') return TRUE;
3263 time->wHour = strtolW( s, &end, 10 );
3264 s = end;
3265
3266 while (*s && !isdigitW( *s )) s++;
3267 if (*s == '\0') return TRUE;
3268 time->wMinute = strtolW( s, &end, 10 );
3269 s = end;
3270
3271 while (*s && !isdigitW( *s )) s++;
3272 if (*s == '\0') return TRUE;
3273 time->wSecond = strtolW( s, &end, 10 );
3274 s = end;
3275
3276 time->wMilliseconds = 0;
3277 return TRUE;
3278 }
3279
3280 /***********************************************************************
3281 * InternetCheckConnectionW (WININET.@)
3282 *
3283 * Pings a requested host to check internet connection
3284 *
3285 * RETURNS
3286 * TRUE on success and FALSE on failure. If a failure then
3287 * ERROR_NOT_CONNECTED is placed into GetLastError
3288 *
3289 */
3290 BOOL WINAPI InternetCheckConnectionW( LPCWSTR lpszUrl, DWORD dwFlags, DWORD dwReserved )
3291 {
3292 /*
3293 * this is a kludge which runs the resident ping program and reads the output.
3294 *
3295 * Anyone have a better idea?
3296 */
3297
3298 BOOL rc = FALSE;
3299 static const CHAR ping[] = "ping -c 1 ";
3300 static const CHAR redirect[] = " >/dev/null 2>/dev/null";
3301 WCHAR *host;
3302 DWORD len, host_len;
3303 INTERNET_PORT port;
3304 int status = -1;
3305
3306 FIXME("(%s %x %x)\n", debugstr_w(lpszUrl), dwFlags, dwReserved);
3307
3308 /*
3309 * Crack or set the Address
3310 */
3311 if (lpszUrl == NULL)
3312 {
3313 /*
3314 * According to the doc we are supposed to use the ip for the next
3315 * server in the WnInet internal server database. I have
3316 * no idea what that is or how to get it.
3317 *
3318 * So someone needs to implement this.
3319 */
3320 FIXME("Unimplemented with URL of NULL\n");
3321 return TRUE;
3322 }
3323 else
3324 {
3325 URL_COMPONENTSW components = {sizeof(components)};
3326
3327 components.dwHostNameLength = 1;
3328
3329 if (!InternetCrackUrlW(lpszUrl,0,0,&components))
3330 goto End;
3331
3332 host = components.lpszHostName;
3333 host_len = components.dwHostNameLength;
3334 port = components.nPort;
3335 TRACE("host name: %s port: %d\n",debugstr_wn(host, host_len), port);
3336 }
3337
3338 if (dwFlags & FLAG_ICC_FORCE_CONNECTION)
3339 {
3340 struct sockaddr_storage saddr;
3341 int sa_len = sizeof(saddr);
3342 WCHAR *host_z;
3343 int fd;
3344 BOOL b;
3345
3346 host_z = heap_strndupW(host, host_len);
3347 if (!host_z)
3348 return FALSE;
3349
3350 b = GetAddress(host_z, port, (struct sockaddr *)&saddr, &sa_len, NULL);
3351 heap_free(host_z);
3352 if(!b)
3353 goto End;
3354 init_winsock();
3355 fd = socket(saddr.ss_family, SOCK_STREAM, 0);
3356 if (fd != -1)
3357 {
3358 if (connect(fd, (struct sockaddr *)&saddr, sa_len) == 0)
3359 rc = TRUE;
3360 closesocket(fd);
3361 }
3362 }
3363 else
3364 {
3365 /*
3366 * Build our ping command
3367 */
3368 char *command;
3369
3370 len = WideCharToMultiByte(CP_UNIXCP, 0, host, host_len, NULL, 0, NULL, NULL);
3371 command = heap_alloc(strlen(ping)+len+strlen(redirect)+1);
3372 strcpy(command, ping);
3373 WideCharToMultiByte(CP_UNIXCP, 0, host, host_len, command+sizeof(ping)-1, len, NULL, NULL);
3374 strcpy(command+sizeof(ping)-1+len, redirect);
3375
3376 TRACE("Ping command is : %s\n",command);
3377
3378 status = system(command);
3379 heap_free( command );
3380
3381 TRACE("Ping returned a code of %i\n",status);
3382
3383 /* Ping return code of 0 indicates success */
3384 if (status == 0)
3385 rc = TRUE;
3386 }
3387
3388 End:
3389 if (rc == FALSE)
3390 INTERNET_SetLastError(ERROR_NOT_CONNECTED);
3391
3392 return rc;
3393 }
3394
3395
3396 /***********************************************************************
3397 * InternetCheckConnectionA (WININET.@)
3398 *
3399 * Pings a requested host to check internet connection
3400 *
3401 * RETURNS
3402 * TRUE on success and FALSE on failure. If a failure then
3403 * ERROR_NOT_CONNECTED is placed into GetLastError
3404 *
3405 */
3406 BOOL WINAPI InternetCheckConnectionA(LPCSTR lpszUrl, DWORD dwFlags, DWORD dwReserved)
3407 {
3408 WCHAR *url = NULL;
3409 BOOL rc;
3410
3411 if(lpszUrl) {
3412 url = heap_strdupAtoW(lpszUrl);
3413 if(!url)
3414 return FALSE;
3415 }
3416
3417 rc = InternetCheckConnectionW(url, dwFlags, dwReserved);
3418
3419 heap_free(url);
3420 return rc;
3421 }
3422
3423
3424 /**********************************************************
3425 * INTERNET_InternetOpenUrlW (internal)
3426 *
3427 * Opens an URL
3428 *
3429 * RETURNS
3430 * handle of connection or NULL on failure
3431 */
3432 static HINTERNET INTERNET_InternetOpenUrlW(appinfo_t *hIC, LPCWSTR lpszUrl,
3433 LPCWSTR lpszHeaders, DWORD dwHeadersLength, DWORD dwFlags, DWORD_PTR dwContext)
3434 {
3435 URL_COMPONENTSW urlComponents = { sizeof(urlComponents) };
3436 WCHAR *host, *user = NULL, *pass = NULL, *path;
3437 HINTERNET client = NULL, client1 = NULL;
3438 DWORD res;
3439
3440 TRACE("(%p, %s, %s, %08x, %08x, %08lx)\n", hIC, debugstr_w(lpszUrl), debugstr_w(lpszHeaders),
3441 dwHeadersLength, dwFlags, dwContext);
3442
3443 urlComponents.dwHostNameLength = 1;
3444 urlComponents.dwUserNameLength = 1;
3445 urlComponents.dwPasswordLength = 1;
3446 urlComponents.dwUrlPathLength = 1;
3447 urlComponents.dwExtraInfoLength = 1;
3448 if(!InternetCrackUrlW(lpszUrl, strlenW(lpszUrl), 0, &urlComponents))
3449 return NULL;
3450
3451 if(urlComponents.nScheme == INTERNET_SCHEME_HTTP && urlComponents.dwExtraInfoLength) {
3452 assert(urlComponents.lpszUrlPath + urlComponents.dwUrlPathLength == urlComponents.lpszExtraInfo);
3453 urlComponents.dwUrlPathLength += urlComponents.dwExtraInfoLength;
3454 }
3455
3456 host = heap_strndupW(urlComponents.lpszHostName, urlComponents.dwHostNameLength);
3457 path = heap_strndupW(urlComponents.lpszUrlPath, urlComponents.dwUrlPathLength);
3458 if(urlComponents.dwUserNameLength)
3459 user = heap_strndupW(urlComponents.lpszUserName, urlComponents.dwUserNameLength);
3460 if(urlComponents.dwPasswordLength)
3461 pass = heap_strndupW(urlComponents.lpszPassword, urlComponents.dwPasswordLength);
3462
3463 switch(urlComponents.nScheme) {
3464 case INTERNET_SCHEME_FTP:
3465 client = FTP_Connect(hIC, host, urlComponents.nPort,
3466 user, pass, dwFlags, dwContext, INET_OPENURL);
3467 if(client == NULL)
3468 break;
3469 client1 = FtpOpenFileW(client, path, GENERIC_READ, dwFlags, dwContext);
3470 if(client1 == NULL) {
3471 InternetCloseHandle(client);
3472 break;
3473 }
3474 break;
3475
3476 case INTERNET_SCHEME_HTTP:
3477 case INTERNET_SCHEME_HTTPS: {
3478 static const WCHAR szStars[] = { '*','/','*', 0 };
3479 LPCWSTR accept[2] = { szStars, NULL };
3480
3481 if (urlComponents.nScheme == INTERNET_SCHEME_HTTPS) dwFlags |= INTERNET_FLAG_SECURE;
3482
3483 /* FIXME: should use pointers, not handles, as handles are not thread-safe */
3484 res = HTTP_Connect(hIC, host, urlComponents.nPort,
3485 user, pass, dwFlags, dwContext, INET_OPENURL, &client);
3486 if(res != ERROR_SUCCESS) {
3487 INTERNET_SetLastError(res);
3488 break;
3489 }
3490
3491 client1 = HttpOpenRequestW(client, NULL, path, NULL, NULL, accept, dwFlags, dwContext);
3492 if(client1 == NULL) {
3493 InternetCloseHandle(client);
3494 break;
3495 }
3496 HttpAddRequestHeadersW(client1, lpszHeaders, dwHeadersLength, HTTP_ADDREQ_FLAG_ADD);
3497 if (!HttpSendRequestW(client1, NULL, 0, NULL, 0) &&
3498 GetLastError() != ERROR_IO_PENDING) {
3499 InternetCloseHandle(client1);
3500 client1 = NULL;
3501 break;
3502 }
3503 }
3504 case INTERNET_SCHEME_GOPHER:
3505 /* gopher doesn't seem to be implemented in wine, but it's supposed
3506 * to be supported by InternetOpenUrlA. */
3507 default:
3508 SetLastError(ERROR_INTERNET_UNRECOGNIZED_SCHEME);
3509 break;
3510 }
3511
3512 TRACE(" %p <--\n", client1);
3513
3514 heap_free(host);
3515 heap_free(path);
3516 heap_free(user);
3517 heap_free(pass);
3518 return client1;
3519 }
3520
3521 /**********************************************************
3522 * InternetOpenUrlW (WININET.@)
3523 *
3524 * Opens an URL
3525 *
3526 * RETURNS
3527 * handle of connection or NULL on failure
3528 */
3529 typedef struct {
3530 task_header_t hdr;
3531 WCHAR *url;
3532 WCHAR *headers;
3533 DWORD headers_len;
3534 DWORD flags;
3535 DWORD_PTR context;
3536 } open_url_task_t;
3537
3538 static void AsyncInternetOpenUrlProc(task_header_t *hdr)
3539 {
3540 open_url_task_t *task = (open_url_task_t*)hdr;
3541
3542 TRACE("%p\n", task->hdr.hdr);
3543
3544 INTERNET_InternetOpenUrlW((appinfo_t*)task->hdr.hdr, task->url, task->headers,
3545 task->headers_len, task->flags, task->context);
3546 heap_free(task->url);
3547 heap_free(task->headers);
3548 }
3549
3550 HINTERNET WINAPI InternetOpenUrlW(HINTERNET hInternet, LPCWSTR lpszUrl,
3551 LPCWSTR lpszHeaders, DWORD dwHeadersLength, DWORD dwFlags, DWORD_PTR dwContext)
3552 {
3553 HINTERNET ret = NULL;
3554 appinfo_t *hIC = NULL;
3555
3556 if (TRACE_ON(wininet)) {
3557 TRACE("(%p, %s, %s, %08x, %08x, %08lx)\n", hInternet, debugstr_w(lpszUrl), debugstr_w(lpszHeaders),
3558 dwHeadersLength, dwFlags, dwContext);
3559 TRACE(" flags :");
3560 dump_INTERNET_FLAGS(dwFlags);
3561 }
3562
3563 if (!lpszUrl)
3564 {
3565 SetLastError(ERROR_INVALID_PARAMETER);
3566 goto lend;
3567 }
3568
3569 hIC = (appinfo_t*)get_handle_object( hInternet );
3570 if (NULL == hIC || hIC->hdr.htype != WH_HINIT) {
3571 SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
3572 goto lend;
3573 }
3574
3575 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC) {
3576 open_url_task_t *task;
3577
3578 task = alloc_async_task(&hIC->hdr, AsyncInternetOpenUrlProc, sizeof(*task));
3579 task->url = heap_strdupW(lpszUrl);
3580 task->headers = heap_strdupW(lpszHeaders);
3581 task->headers_len = dwHeadersLength;
3582 task->flags = dwFlags;
3583 task->context = dwContext;
3584
3585 INTERNET_AsyncCall(&task->hdr);
3586 SetLastError(ERROR_IO_PENDING);
3587 } else {
3588 ret = INTERNET_InternetOpenUrlW(hIC, lpszUrl, lpszHeaders, dwHeadersLength, dwFlags, dwContext);
3589 }
3590
3591 lend:
3592 if( hIC )
3593 WININET_Release( &hIC->hdr );
3594 TRACE(" %p <--\n", ret);
3595
3596 return ret;
3597 }
3598
3599 /**********************************************************
3600 * InternetOpenUrlA (WININET.@)
3601 *
3602 * Opens an URL
3603 *
3604 * RETURNS
3605 * handle of connection or NULL on failure
3606 */
3607 HINTERNET WINAPI InternetOpenUrlA(HINTERNET hInternet, LPCSTR lpszUrl,
3608 LPCSTR lpszHeaders, DWORD dwHeadersLength, DWORD dwFlags, DWORD_PTR dwContext)
3609 {
3610 HINTERNET rc = NULL;
3611 LPWSTR szUrl = NULL;
3612 WCHAR *headers = NULL;
3613
3614 TRACE("\n");
3615
3616 if(lpszUrl) {
3617 szUrl = heap_strdupAtoW(lpszUrl);
3618 if(!szUrl)
3619 return NULL;
3620 }
3621
3622 if(lpszHeaders) {
3623 headers = heap_strndupAtoW(lpszHeaders, dwHeadersLength, &dwHeadersLength);
3624 if(!headers) {
3625 heap_free(szUrl);
3626 return NULL;
3627 }
3628 }
3629
3630 rc = InternetOpenUrlW(hInternet, szUrl, headers, dwHeadersLength, dwFlags, dwContext);
3631
3632 heap_free(szUrl);
3633 heap_free(headers);
3634 return rc;
3635 }
3636
3637
3638 static LPWITHREADERROR INTERNET_AllocThreadError(void)
3639 {
3640 LPWITHREADERROR lpwite = heap_alloc(sizeof(*lpwite));
3641
3642 if (lpwite)
3643 {
3644 lpwite->dwError = 0;
3645 lpwite->response[0] = '\0';
3646 }
3647
3648 if (!TlsSetValue(g_dwTlsErrIndex, lpwite))
3649 {
3650 heap_free(lpwite);
3651 return NULL;
3652 }
3653 return lpwite;
3654 }
3655
3656
3657 /***********************************************************************
3658 * INTERNET_SetLastError (internal)
3659 *
3660 * Set last thread specific error
3661 *
3662 * RETURNS
3663 *
3664 */
3665 void INTERNET_SetLastError(DWORD dwError)
3666 {
3667 LPWITHREADERROR lpwite = TlsGetValue(g_dwTlsErrIndex);
3668
3669 if (!lpwite)
3670 lpwite = INTERNET_AllocThreadError();
3671
3672 SetLastError(dwError);
3673 if(lpwite)
3674 lpwite->dwError = dwError;
3675 }
3676
3677
3678 /***********************************************************************
3679 * INTERNET_GetLastError (internal)
3680 *
3681 * Get last thread specific error
3682 *
3683 * RETURNS
3684 *
3685 */
3686 DWORD INTERNET_GetLastError(void)
3687 {
3688 LPWITHREADERROR lpwite = TlsGetValue(g_dwTlsErrIndex);
3689 if (!lpwite) return 0;
3690 /* TlsGetValue clears last error, so set it again here */
3691 SetLastError(lpwite->dwError);
3692 return lpwite->dwError;
3693 }
3694
3695
3696 /***********************************************************************
3697 * INTERNET_WorkerThreadFunc (internal)
3698 *
3699 * Worker thread execution function
3700 *
3701 * RETURNS
3702 *
3703 */
3704 static DWORD CALLBACK INTERNET_WorkerThreadFunc(LPVOID lpvParam)
3705 {
3706 task_header_t *task = lpvParam;
3707
3708 TRACE("\n");
3709
3710 task->proc(task);
3711 WININET_Release(task->hdr);
3712 heap_free(task);
3713
3714 if (g_dwTlsErrIndex != TLS_OUT_OF_INDEXES)
3715 {
3716 heap_free(TlsGetValue(g_dwTlsErrIndex));
3717 TlsSetValue(g_dwTlsErrIndex, NULL);
3718 }
3719 return TRUE;
3720 }
3721
3722 void *alloc_async_task(object_header_t *hdr, async_task_proc_t proc, size_t size)
3723 {
3724 task_header_t *task;
3725
3726 task = heap_alloc(size);
3727 if(!task)
3728 return NULL;
3729
3730 task->hdr = WININET_AddRef(hdr);
3731 task->proc = proc;
3732 return task;
3733 }
3734
3735 /***********************************************************************
3736 * INTERNET_AsyncCall (internal)
3737 *
3738 * Retrieves work request from queue
3739 *
3740 * RETURNS
3741 *
3742 */
3743 DWORD INTERNET_AsyncCall(task_header_t *task)
3744 {
3745 BOOL bSuccess;
3746
3747 TRACE("\n");
3748
3749 bSuccess = QueueUserWorkItem(INTERNET_WorkerThreadFunc, task, WT_EXECUTELONGFUNCTION);
3750 if (!bSuccess)
3751 {
3752 heap_free(task);
3753 return ERROR_INTERNET_ASYNC_THREAD_FAILED;
3754 }
3755 return ERROR_SUCCESS;
3756 }
3757
3758
3759 /***********************************************************************
3760 * INTERNET_GetResponseBuffer (internal)
3761 *
3762 * RETURNS
3763 *
3764 */
3765 LPSTR INTERNET_GetResponseBuffer(void)
3766 {
3767 LPWITHREADERROR lpwite = TlsGetValue(g_dwTlsErrIndex);
3768 if (!lpwite)
3769 lpwite = INTERNET_AllocThreadError();
3770 TRACE("\n");
3771 return lpwite->response;
3772 }
3773
3774 /**********************************************************
3775 * InternetQueryDataAvailable (WININET.@)
3776 *
3777 * Determines how much data is available to be read.
3778 *
3779 * RETURNS
3780 * TRUE on success, FALSE if an error occurred. If
3781 * INTERNET_FLAG_ASYNC was specified in InternetOpen, and
3782 * no data is presently available, FALSE is returned with
3783 * the last error ERROR_IO_PENDING; a callback with status
3784 * INTERNET_STATUS_REQUEST_COMPLETE will be sent when more
3785 * data is available.
3786 */
3787 BOOL WINAPI InternetQueryDataAvailable( HINTERNET hFile,
3788 LPDWORD lpdwNumberOfBytesAvailable,
3789 DWORD dwFlags, DWORD_PTR dwContext)
3790 {
3791 object_header_t *hdr;
3792 DWORD res;
3793
3794 TRACE("(%p %p %x %lx)\n", hFile, lpdwNumberOfBytesAvailable, dwFlags, dwContext);
3795
3796 hdr = get_handle_object( hFile );
3797 if (!hdr) {
3798 SetLastError(ERROR_INVALID_HANDLE);
3799 return FALSE;
3800 }
3801
3802 if(hdr->vtbl->QueryDataAvailable) {
3803 res = hdr->vtbl->QueryDataAvailable(hdr, lpdwNumberOfBytesAvailable, dwFlags, dwContext);
3804 }else {
3805 WARN("wrong handle\n");
3806 res = ERROR_INTERNET_INCORRECT_HANDLE_TYPE;
3807 }
3808
3809 WININET_Release(hdr);
3810
3811 if(res != ERROR_SUCCESS)
3812 SetLastError(res);
3813 return res == ERROR_SUCCESS;
3814 }
3815
3816 DWORD create_req_file(const WCHAR *file_name, req_file_t **ret)
3817 {
3818 req_file_t *req_file;
3819
3820 req_file = heap_alloc_zero(sizeof(*req_file));
3821 if(!req_file)
3822 return ERROR_NOT_ENOUGH_MEMORY;
3823
3824 req_file->ref = 1;
3825
3826 req_file->file_name = heap_strdupW(file_name);
3827 if(!req_file->file_name) {
3828 heap_free(req_file);
3829 return ERROR_NOT_ENOUGH_MEMORY;
3830 }
3831
3832 req_file->file_handle = CreateFileW(req_file->file_name, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE,
3833 NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
3834 if(req_file->file_handle == INVALID_HANDLE_VALUE) {
3835 req_file_release(req_file);
3836 return GetLastError();
3837 }
3838
3839 *ret = req_file;
3840 return ERROR_SUCCESS;
3841 }
3842
3843 void req_file_release(req_file_t *req_file)
3844 {
3845 if(InterlockedDecrement(&req_file->ref))
3846 return;
3847
3848 if(!req_file->is_committed)
3849 DeleteFileW(req_file->file_name);
3850 if(req_file->file_handle && req_file->file_handle != INVALID_HANDLE_VALUE)
3851 CloseHandle(req_file->file_handle);
3852 heap_free(req_file->file_name);
3853 heap_free(req_file->url);
3854 heap_free(req_file);
3855 }
3856
3857 /***********************************************************************
3858 * InternetLockRequestFile (WININET.@)
3859 */
3860 BOOL WINAPI InternetLockRequestFile(HINTERNET hInternet, HANDLE *lphLockReqHandle)
3861 {
3862 req_file_t *req_file = NULL;
3863 object_header_t *hdr;
3864 DWORD res;
3865
3866 TRACE("(%p %p)\n", hInternet, lphLockReqHandle);
3867
3868 hdr = get_handle_object(hInternet);
3869 if (!hdr) {
3870 SetLastError(ERROR_INVALID_HANDLE);
3871 return FALSE;
3872 }
3873
3874 if(hdr->vtbl->LockRequestFile) {
3875 res = hdr->vtbl->LockRequestFile(hdr, &req_file);
3876 }else {
3877 WARN("wrong handle\n");
3878 res = ERROR_INTERNET_INCORRECT_HANDLE_TYPE;
3879 }
3880
3881 WININET_Release(hdr);
3882
3883 *lphLockReqHandle = req_file;
3884 if(res != ERROR_SUCCESS)
3885 SetLastError(res);
3886 return res == ERROR_SUCCESS;
3887 }
3888
3889 BOOL WINAPI InternetUnlockRequestFile(HANDLE hLockHandle)
3890 {
3891 TRACE("(%p)\n", hLockHandle);
3892
3893 req_file_release(hLockHandle);
3894 return TRUE;
3895 }
3896
3897
3898 /***********************************************************************
3899 * InternetAutodial (WININET.@)
3900 *
3901 * On windows this function is supposed to dial the default internet
3902 * connection. We don't want to have Wine dial out to the internet so
3903 * we return TRUE by default. It might be nice to check if we are connected.
3904 *
3905 * RETURNS
3906 * TRUE on success
3907 * FALSE on failure
3908 *
3909 */
3910 BOOL WINAPI InternetAutodial(DWORD dwFlags, HWND hwndParent)
3911 {
3912 FIXME("STUB\n");
3913
3914 /* Tell that we are connected to the internet. */
3915 return TRUE;
3916 }
3917
3918 /***********************************************************************
3919 * InternetAutodialHangup (WININET.@)
3920 *
3921 * Hangs up a connection made with InternetAutodial
3922 *
3923 * PARAM
3924 * dwReserved
3925 * RETURNS
3926 * TRUE on success
3927 * FALSE on failure
3928 *
3929 */
3930 BOOL WINAPI InternetAutodialHangup(DWORD dwReserved)
3931 {
3932 FIXME("STUB\n");
3933
3934 /* we didn't dial, we don't disconnect */
3935 return TRUE;
3936 }
3937
3938 /***********************************************************************
3939 * InternetCombineUrlA (WININET.@)
3940 *
3941 * Combine a base URL with a relative URL
3942 *
3943 * RETURNS
3944 * TRUE on success
3945 * FALSE on failure
3946 *
3947 */
3948
3949 BOOL WINAPI InternetCombineUrlA(LPCSTR lpszBaseUrl, LPCSTR lpszRelativeUrl,
3950 LPSTR lpszBuffer, LPDWORD lpdwBufferLength,
3951 DWORD dwFlags)
3952 {
3953 HRESULT hr=S_OK;
3954
3955 TRACE("(%s, %s, %p, %p, 0x%08x)\n", debugstr_a(lpszBaseUrl), debugstr_a(lpszRelativeUrl), lpszBuffer, lpdwBufferLength, dwFlags);
3956
3957 /* Flip this bit to correspond to URL_ESCAPE_UNSAFE */
3958 dwFlags ^= ICU_NO_ENCODE;
3959 hr=UrlCombineA(lpszBaseUrl,lpszRelativeUrl,lpszBuffer,lpdwBufferLength,dwFlags);
3960
3961 return (hr==S_OK);
3962 }
3963
3964 /***********************************************************************
3965 * InternetCombineUrlW (WININET.@)
3966 *
3967 * Combine a base URL with a relative URL
3968 *
3969 * RETURNS
3970 * TRUE on success
3971 * FALSE on failure
3972 *
3973 */
3974
3975 BOOL WINAPI InternetCombineUrlW(LPCWSTR lpszBaseUrl, LPCWSTR lpszRelativeUrl,
3976 LPWSTR lpszBuffer, LPDWORD lpdwBufferLength,
3977 DWORD dwFlags)
3978 {
3979 HRESULT hr=S_OK;
3980
3981 TRACE("(%s, %s, %p, %p, 0x%08x)\n", debugstr_w(lpszBaseUrl), debugstr_w(lpszRelativeUrl), lpszBuffer, lpdwBufferLength, dwFlags);
3982
3983 /* Flip this bit to correspond to URL_ESCAPE_UNSAFE */
3984 dwFlags ^= ICU_NO_ENCODE;
3985 hr=UrlCombineW(lpszBaseUrl,lpszRelativeUrl,lpszBuffer,lpdwBufferLength,dwFlags);
3986
3987 return (hr==S_OK);
3988 }
3989
3990 /* max port num is 65535 => 5 digits */
3991 #define MAX_WORD_DIGITS 5
3992
3993 #define URL_GET_COMP_LENGTH(url, component) ((url)->dw##component##Length ? \
3994 (url)->dw##component##Length : strlenW((url)->lpsz##component))
3995 #define URL_GET_COMP_LENGTHA(url, component) ((url)->dw##component##Length ? \
3996 (url)->dw##component##Length : strlen((url)->lpsz##component))
3997
3998 static BOOL url_uses_default_port(INTERNET_SCHEME nScheme, INTERNET_PORT nPort)
3999 {
4000 if ((nScheme == INTERNET_SCHEME_HTTP) &&
4001 (nPort == INTERNET_DEFAULT_HTTP_PORT))
4002 return TRUE;
4003 if ((nScheme == INTERNET_SCHEME_HTTPS) &&
4004 (nPort == INTERNET_DEFAULT_HTTPS_PORT))
4005 return TRUE;
4006 if ((nScheme == INTERNET_SCHEME_FTP) &&
4007 (nPort == INTERNET_DEFAULT_FTP_PORT))
4008 return TRUE;
4009 if ((nScheme == INTERNET_SCHEME_GOPHER) &&
4010 (nPort == INTERNET_DEFAULT_GOPHER_PORT))
4011 return TRUE;
4012
4013 if (nPort == INTERNET_INVALID_PORT_NUMBER)
4014 return TRUE;
4015
4016 return FALSE;
4017 }
4018
4019 /* opaque urls do not fit into the standard url hierarchy and don't have
4020 * two following slashes */
4021 static inline BOOL scheme_is_opaque(INTERNET_SCHEME nScheme)
4022 {
4023 return (nScheme != INTERNET_SCHEME_FTP) &&
4024 (nScheme != INTERNET_SCHEME_GOPHER) &&
4025 (nScheme != INTERNET_SCHEME_HTTP) &&
4026 (nScheme != INTERNET_SCHEME_HTTPS) &&
4027 (nScheme != INTERNET_SCHEME_FILE);
4028 }
4029
4030 static LPCWSTR INTERNET_GetSchemeString(INTERNET_SCHEME scheme)
4031 {
4032 int index;
4033 if (scheme < INTERNET_SCHEME_FIRST)
4034 return NULL;
4035 index = scheme - INTERNET_SCHEME_FIRST;
4036 if (index >= sizeof(url_schemes)/sizeof(url_schemes[0]))
4037 return NULL;
4038 return (LPCWSTR)url_schemes[index];
4039 }
4040
4041 /* we can calculate using ansi strings because we're just
4042 * calculating string length, not size
4043 */
4044 static BOOL calc_url_length(LPURL_COMPONENTSW lpUrlComponents,
4045 LPDWORD lpdwUrlLength)
4046 {
4047 INTERNET_SCHEME nScheme;
4048
4049 *lpdwUrlLength = 0;
4050
4051 if (lpUrlComponents->lpszScheme)
4052 {
4053 DWORD dwLen = URL_GET_COMP_LENGTH(lpUrlComponents, Scheme);
4054 *lpdwUrlLength += dwLen;
4055 nScheme = GetInternetSchemeW(lpUrlComponents->lpszScheme, dwLen);
4056 }
4057 else
4058 {
4059 LPCWSTR scheme;
4060
4061 nScheme = lpUrlComponents->nScheme;
4062
4063 if (nScheme == INTERNET_SCHEME_DEFAULT)
4064 nScheme = INTERNET_SCHEME_HTTP;
4065 scheme = INTERNET_GetSchemeString(nScheme);
4066 *lpdwUrlLength += strlenW(scheme);
4067 }
4068
4069 (*lpdwUrlLength)++; /* ':' */
4070 if (!scheme_is_opaque(nScheme) || lpUrlComponents->lpszHostName)
4071 *lpdwUrlLength += strlen("//");
4072
4073 if (lpUrlComponents->lpszUserName)
4074 {
4075 *lpdwUrlLength += URL_GET_COMP_LENGTH(lpUrlComponents, UserName);
4076 *lpdwUrlLength += strlen("@");
4077 }
4078 else
4079 {
4080 if (lpUrlComponents->lpszPassword)
4081 {
4082 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
4083 return FALSE;
4084 }
4085 }
4086
4087 if (lpUrlComponents->lpszPassword)
4088 {
4089 *lpdwUrlLength += strlen(":");
4090 *lpdwUrlLength += URL_GET_COMP_LENGTH(lpUrlComponents, Password);
4091 }
4092
4093 if (lpUrlComponents->lpszHostName)
4094 {
4095 *lpdwUrlLength += URL_GET_COMP_LENGTH(lpUrlComponents, HostName);
4096
4097 if (!url_uses_default_port(nScheme, lpUrlComponents->nPort))
4098 {
4099 char szPort[MAX_WORD_DIGITS+1];
4100
4101 sprintf(szPort, "%d", lpUrlComponents->nPort);
4102 *lpdwUrlLength += strlen(szPort);
4103 *lpdwUrlLength += strlen(":");
4104 }
4105
4106 if (lpUrlComponents->lpszUrlPath && *lpUrlComponents->lpszUrlPath != '/')
4107 (*lpdwUrlLength)++; /* '/' */
4108 }
4109
4110 if (lpUrlComponents->lpszUrlPath)
4111 *lpdwUrlLength += URL_GET_COMP_LENGTH(lpUrlComponents, UrlPath);
4112
4113 if (lpUrlComponents->lpszExtraInfo)
4114 *lpdwUrlLength += URL_GET_COMP_LENGTH(lpUrlComponents, ExtraInfo);
4115
4116 return TRUE;
4117 }
4118
4119 static void convert_urlcomp_atow(LPURL_COMPONENTSA lpUrlComponents, LPURL_COMPONENTSW urlCompW)
4120 {
4121 INT len;
4122
4123 ZeroMemory(urlCompW, sizeof(URL_COMPONENTSW));
4124
4125 urlCompW->dwStructSize = sizeof(URL_COMPONENTSW);
4126 urlCompW->dwSchemeLength = lpUrlComponents->dwSchemeLength;
4127 urlCompW->nScheme = lpUrlComponents->nScheme;
4128 urlCompW->dwHostNameLength = lpUrlComponents->dwHostNameLength;
4129 urlCompW->nPort = lpUrlComponents->nPort;
4130 urlCompW->dwUserNameLength = lpUrlComponents->dwUserNameLength;
4131 urlCompW->dwPasswordLength = lpUrlComponents->dwPasswordLength;
4132 urlCompW->dwUrlPathLength = lpUrlComponents->dwUrlPathLength;
4133 urlCompW->dwExtraInfoLength = lpUrlComponents->dwExtraInfoLength;
4134
4135 if (lpUrlComponents->lpszScheme)
4136 {
4137 len = URL_GET_COMP_LENGTHA(lpUrlComponents, Scheme) + 1;
4138 urlCompW->lpszScheme = heap_alloc(len * sizeof(WCHAR));
4139 MultiByteToWideChar(CP_ACP, 0, lpUrlComponents->lpszScheme,
4140 -1, urlCompW->lpszScheme, len);
4141 }
4142
4143 if (lpUrlComponents->lpszHostName)
4144 {
4145 len = URL_GET_COMP_LENGTHA(lpUrlComponents, HostName) + 1;
4146 urlCompW->lpszHostName = heap_alloc(len * sizeof(WCHAR));
4147 MultiByteToWideChar(CP_ACP, 0, lpUrlComponents->lpszHostName,
4148 -1, urlCompW->lpszHostName, len);
4149 }
4150
4151 if (lpUrlComponents->lpszUserName)
4152 {
4153 len = URL_GET_COMP_LENGTHA(lpUrlComponents, UserName) + 1;
4154 urlCompW->lpszUserName = heap_alloc(len * sizeof(WCHAR));
4155 MultiByteToWideChar(CP_ACP, 0, lpUrlComponents->lpszUserName,
4156 -1, urlCompW->lpszUserName, len);
4157 }
4158
4159 if (lpUrlComponents->lpszPassword)
4160 {
4161 len = URL_GET_COMP_LENGTHA(lpUrlComponents, Password) + 1;
4162 urlCompW->lpszPassword = heap_alloc(len * sizeof(WCHAR));
4163 MultiByteToWideChar(CP_ACP, 0, lpUrlComponents->lpszPassword,
4164 -1, urlCompW->lpszPassword, len);
4165 }
4166
4167 if (lpUrlComponents->lpszUrlPath)
4168 {
4169 len = URL_GET_COMP_LENGTHA(lpUrlComponents, UrlPath) + 1;
4170 urlCompW->lpszUrlPath = heap_alloc(len * sizeof(WCHAR));
4171 MultiByteToWideChar(CP_ACP, 0, lpUrlComponents->lpszUrlPath,
4172 -1, urlCompW->lpszUrlPath, len);
4173 }
4174
4175 if (lpUrlComponents->lpszExtraInfo)
4176 {
4177 len = URL_GET_COMP_LENGTHA(lpUrlComponents, ExtraInfo) + 1;
4178 urlCompW->lpszExtraInfo = heap_alloc(len * sizeof(WCHAR));
4179 MultiByteToWideChar(CP_ACP, 0, lpUrlComponents->lpszExtraInfo,
4180 -1, urlCompW->lpszExtraInfo, len);
4181 }
4182 }
4183
4184 /***********************************************************************
4185 * InternetCreateUrlA (WININET.@)
4186 *
4187 * See InternetCreateUrlW.
4188 */
4189 BOOL WINAPI InternetCreateUrlA(LPURL_COMPONENTSA lpUrlComponents, DWORD dwFlags,
4190 LPSTR lpszUrl, LPDWORD lpdwUrlLength)
4191 {
4192 BOOL ret;
4193 LPWSTR urlW = NULL;
4194 URL_COMPONENTSW urlCompW;
4195
4196 TRACE("(%p,%d,%p,%p)\n", lpUrlComponents, dwFlags, lpszUrl, lpdwUrlLength);
4197
4198 if (!lpUrlComponents || lpUrlComponents->dwStructSize != sizeof(URL_COMPONENTSW) || !lpdwUrlLength)
4199 {
4200 SetLastError(ERROR_INVALID_PARAMETER);
4201 return FALSE;
4202 }
4203
4204 convert_urlcomp_atow(lpUrlComponents, &urlCompW);
4205
4206 if (lpszUrl)
4207 urlW = heap_alloc(*lpdwUrlLength * sizeof(WCHAR));
4208
4209 ret = InternetCreateUrlW(&urlCompW, dwFlags, urlW, lpdwUrlLength);
4210
4211 if (!ret && (GetLastError() == ERROR_INSUFFICIENT_BUFFER))
4212 *lpdwUrlLength /= sizeof(WCHAR);
4213
4214 /* on success, lpdwUrlLength points to the size of urlW in WCHARS
4215 * minus one, so add one to leave room for NULL terminator
4216 */
4217 if (ret)
4218 WideCharToMultiByte(CP_ACP, 0, urlW, -1, lpszUrl, *lpdwUrlLength + 1, NULL, NULL);
4219
4220 heap_free(urlCompW.lpszScheme);
4221 heap_free(urlCompW.lpszHostName);
4222 heap_free(urlCompW.lpszUserName);
4223 heap_free(urlCompW.lpszPassword);
4224 heap_free(urlCompW.lpszUrlPath);
4225 heap_free(urlCompW.lpszExtraInfo);
4226 heap_free(urlW);
4227 return ret;
4228 }
4229
4230 /***********************************************************************
4231 * InternetCreateUrlW (WININET.@)
4232 *
4233 * Creates a URL from its component parts.
4234 *
4235 * PARAMS
4236 * lpUrlComponents [I] URL Components.
4237 * dwFlags [I] Flags. See notes.
4238 * lpszUrl [I] Buffer in which to store the created URL.
4239 * lpdwUrlLength [I/O] On input, the length of the buffer pointed to by
4240 * lpszUrl in characters. On output, the number of bytes
4241 * required to store the URL including terminator.
4242 *
4243 * NOTES
4244 *
4245 * The dwFlags parameter can be zero or more of the following:
4246 *|ICU_ESCAPE - Generates escape sequences for unsafe characters in the path and extra info of the URL.
4247 *
4248 * RETURNS
4249 * TRUE on success
4250 * FALSE on failure
4251 *
4252 */
4253 BOOL WINAPI InternetCreateUrlW(LPURL_COMPONENTSW lpUrlComponents, DWORD dwFlags,
4254 LPWSTR lpszUrl, LPDWORD lpdwUrlLength)
4255 {
4256 DWORD dwLen;
4257 INTERNET_SCHEME nScheme;
4258
4259 static const WCHAR slashSlashW[] = {'/','/'};
4260 static const WCHAR fmtW[] = {'%','u',0};
4261
4262 TRACE("(%p,%d,%p,%p)\n", lpUrlComponents, dwFlags, lpszUrl, lpdwUrlLength);
4263
4264 if (!lpUrlComponents || lpUrlComponents->dwStructSize != sizeof(URL_COMPONENTSW) || !lpdwUrlLength)
4265 {
4266 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
4267 return FALSE;
4268 }
4269
4270 if (!calc_url_length(lpUrlComponents, &dwLen))
4271 return FALSE;
4272
4273 if (!lpszUrl || *lpdwUrlLength < dwLen)
4274 {
4275 *lpdwUrlLength = (dwLen + 1) * sizeof(WCHAR);
4276 INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
4277 return FALSE;
4278 }
4279
4280 *lpdwUrlLength = dwLen;
4281 lpszUrl[0] = 0x00;
4282
4283 dwLen = 0;
4284
4285 if (lpUrlComponents->lpszScheme)
4286 {
4287 dwLen = URL_GET_COMP_LENGTH(lpUrlComponents, Scheme);
4288 memcpy(lpszUrl, lpUrlComponents->lpszScheme, dwLen * sizeof(WCHAR));
4289 lpszUrl += dwLen;
4290
4291 nScheme = GetInternetSchemeW(lpUrlComponents->lpszScheme, dwLen);
4292 }
4293 else
4294 {
4295 LPCWSTR scheme;
4296 nScheme = lpUrlComponents->nScheme;
4297
4298 if (nScheme == INTERNET_SCHEME_DEFAULT)
4299 nScheme = INTERNET_SCHEME_HTTP;
4300
4301 scheme = INTERNET_GetSchemeString(nScheme);
4302 dwLen = strlenW(scheme);
4303 memcpy(lpszUrl, scheme, dwLen * sizeof(WCHAR));
4304 lpszUrl += dwLen;
4305 }
4306
4307 /* all schemes are followed by at least a colon */
4308 *lpszUrl = ':';
4309 lpszUrl++;
4310
4311 if (!scheme_is_opaque(nScheme) || lpUrlComponents->lpszHostName)
4312 {
4313 memcpy(lpszUrl, slashSlashW, sizeof(slashSlashW));
4314 lpszUrl += sizeof(slashSlashW)/sizeof(slashSlashW[0]);
4315 }
4316
4317 if (lpUrlComponents->lpszUserName)
4318 {
4319 dwLen = URL_GET_COMP_LENGTH(lpUrlComponents, UserName);
4320 memcpy(lpszUrl, lpUrlComponents->lpszUserName, dwLen * sizeof(WCHAR));
4321 lpszUrl += dwLen;
4322
4323 if (lpUrlComponents->lpszPassword)
4324 {
4325 *lpszUrl = ':';
4326 lpszUrl++;
4327
4328 dwLen = URL_GET_COMP_LENGTH(lpUrlComponents, Password);
4329 memcpy(lpszUrl, lpUrlComponents->lpszPassword, dwLen * sizeof(WCHAR));
4330 lpszUrl += dwLen;
4331 }
4332
4333 *lpszUrl = '@';
4334 lpszUrl++;
4335 }
4336
4337 if (lpUrlComponents->lpszHostName)
4338 {
4339 dwLen = URL_GET_COMP_LENGTH(lpUrlComponents, HostName);
4340 memcpy(lpszUrl, lpUrlComponents->lpszHostName, dwLen * sizeof(WCHAR));
4341 lpszUrl += dwLen;
4342
4343 if (!url_uses_default_port(nScheme, lpUrlComponents->nPort))
4344 {
4345 WCHAR szPort[MAX_WORD_DIGITS+1];
4346
4347 sprintfW(szPort, fmtW, lpUrlComponents->nPort);
4348 *lpszUrl = ':';
4349 lpszUrl++;
4350 dwLen = strlenW(szPort);
4351 memcpy(lpszUrl, szPort, dwLen * sizeof(WCHAR));
4352 lpszUrl += dwLen;
4353 }
4354
4355 /* add slash between hostname and path if necessary */
4356 if (lpUrlComponents->lpszUrlPath && *lpUrlComponents->lpszUrlPath != '/')
4357 {
4358 *lpszUrl = '/';
4359 lpszUrl++;
4360 }
4361 }
4362
4363 if (lpUrlComponents->lpszUrlPath)
4364 {
4365 dwLen = URL_GET_COMP_LENGTH(lpUrlComponents, UrlPath);
4366 memcpy(lpszUrl, lpUrlComponents->lpszUrlPath, dwLen * sizeof(WCHAR));
4367 lpszUrl += dwLen;
4368 }
4369
4370 if (lpUrlComponents->lpszExtraInfo)
4371 {
4372 dwLen = URL_GET_COMP_LENGTH(lpUrlComponents, ExtraInfo);
4373 memcpy(lpszUrl, lpUrlComponents->lpszExtraInfo, dwLen * sizeof(WCHAR));
4374 lpszUrl += dwLen;
4375 }
4376
4377 *lpszUrl = '\0';
4378
4379 return TRUE;
4380 }
4381
4382 /***********************************************************************
4383 * InternetConfirmZoneCrossingA (WININET.@)
4384 *
4385 */
4386 DWORD WINAPI InternetConfirmZoneCrossingA( HWND hWnd, LPSTR szUrlPrev, LPSTR szUrlNew, BOOL bPost )
4387 {
4388 FIXME("(%p, %s, %s, %x) stub\n", hWnd, debugstr_a(szUrlPrev), debugstr_a(szUrlNew), bPost);
4389 return ERROR_SUCCESS;
4390 }
4391
4392 /***********************************************************************
4393 * InternetConfirmZoneCrossingW (WININET.@)
4394 *
4395 */
4396 DWORD WINAPI InternetConfirmZoneCrossingW( HWND hWnd, LPWSTR szUrlPrev, LPWSTR szUrlNew, BOOL bPost )
4397 {
4398 FIXME("(%p, %s, %s, %x) stub\n", hWnd, debugstr_w(szUrlPrev), debugstr_w(szUrlNew), bPost);
4399 return ERROR_SUCCESS;
4400 }
4401
4402 static DWORD zone_preference = 3;
4403
4404 /***********************************************************************
4405 * PrivacySetZonePreferenceW (WININET.@)
4406 */
4407 DWORD WINAPI PrivacySetZonePreferenceW( DWORD zone, DWORD type, DWORD template, LPCWSTR preference )
4408 {
4409 FIXME( "%x %x %x %s: stub\n", zone, type, template, debugstr_w(preference) );
4410
4411 zone_preference = template;
4412 return 0;
4413 }
4414
4415 /***********************************************************************
4416 * PrivacyGetZonePreferenceW (WININET.@)
4417 */
4418 DWORD WINAPI PrivacyGetZonePreferenceW( DWORD zone, DWORD type, LPDWORD template,
4419 LPWSTR preference, LPDWORD length )
4420 {
4421 FIXME( "%x %x %p %p %p: stub\n", zone, type, template, preference, length );
4422
4423 if (template) *template = zone_preference;
4424 return 0;
4425 }
4426
4427 /***********************************************************************
4428 * InternetGetSecurityInfoByURLA (WININET.@)
4429 */
4430 BOOL WINAPI InternetGetSecurityInfoByURLA(LPSTR lpszURL, PCCERT_CHAIN_CONTEXT *ppCertChain, DWORD *pdwSecureFlags)
4431 {
4432 WCHAR *url;
4433 BOOL res;
4434
4435 TRACE("(%s %p %p)\n", debugstr_a(lpszURL), ppCertChain, pdwSecureFlags);
4436
4437 url = heap_strdupAtoW(lpszURL);
4438 if(!url)
4439 return FALSE;
4440
4441 res = InternetGetSecurityInfoByURLW(url, ppCertChain, pdwSecureFlags);
4442 heap_free(url);
4443 return res;
4444 }
4445
4446 /***********************************************************************
4447 * InternetGetSecurityInfoByURLW (WININET.@)
4448 */
4449 BOOL WINAPI InternetGetSecurityInfoByURLW(LPCWSTR lpszURL, PCCERT_CHAIN_CONTEXT *ppCertChain, DWORD *pdwSecureFlags)
4450 {
4451 URL_COMPONENTSW url = {sizeof(url)};
4452 server_t *server;
4453 BOOL res;
4454
4455 TRACE("(%s %p %p)\n", debugstr_w(lpszURL), ppCertChain, pdwSecureFlags);
4456
4457 url.dwHostNameLength = 1;
4458 res = InternetCrackUrlW(lpszURL, 0, 0, &url);
4459 if(!res || url.nScheme != INTERNET_SCHEME_HTTPS) {
4460 SetLastError(ERROR_INTERNET_ITEM_NOT_FOUND);
4461 return FALSE;
4462 }
4463
4464 server = get_server(substr(url.lpszHostName, url.dwHostNameLength), url.nPort, TRUE, FALSE);
4465 if(!server) {
4466 SetLastError(ERROR_INTERNET_ITEM_NOT_FOUND);
4467 return FALSE;
4468 }
4469
4470 if(server->cert_chain) {
4471 const CERT_CHAIN_CONTEXT *chain_dup;
4472
4473 chain_dup = CertDuplicateCertificateChain(server->cert_chain);
4474 if(chain_dup) {
4475 *ppCertChain = chain_dup;
4476 *pdwSecureFlags = server->security_flags & _SECURITY_ERROR_FLAGS_MASK;
4477 }else {
4478 res = FALSE;
4479 }
4480 }else {
4481 SetLastError(ERROR_INTERNET_ITEM_NOT_FOUND);
4482 res = FALSE;
4483 }
4484
4485 server_release(server);
4486 return res;
4487 }
4488
4489 DWORD WINAPI InternetDialA( HWND hwndParent, LPSTR lpszConnectoid, DWORD dwFlags,
4490 DWORD_PTR* lpdwConnection, DWORD dwReserved )
4491 {
4492 FIXME("(%p, %p, 0x%08x, %p, 0x%08x) stub\n", hwndParent, lpszConnectoid, dwFlags,
4493 lpdwConnection, dwReserved);
4494 return ERROR_SUCCESS;
4495 }
4496
4497 DWORD WINAPI InternetDialW( HWND hwndParent, LPWSTR lpszConnectoid, DWORD dwFlags,
4498 DWORD_PTR* lpdwConnection, DWORD dwReserved )
4499 {
4500 FIXME("(%p, %p, 0x%08x, %p, 0x%08x) stub\n", hwndParent, lpszConnectoid, dwFlags,
4501 lpdwConnection, dwReserved);
4502 return ERROR_SUCCESS;
4503 }
4504
4505 BOOL WINAPI InternetGoOnlineA( LPSTR lpszURL, HWND hwndParent, DWORD dwReserved )
4506 {
4507 FIXME("(%s, %p, 0x%08x) stub\n", debugstr_a(lpszURL), hwndParent, dwReserved);
4508 return TRUE;
4509 }
4510
4511 BOOL WINAPI InternetGoOnlineW( LPWSTR lpszURL, HWND hwndParent, DWORD dwReserved )
4512 {
4513 FIXME("(%s, %p, 0x%08x) stub\n", debugstr_w(lpszURL), hwndParent, dwReserved);
4514 return TRUE;
4515 }
4516
4517 DWORD WINAPI InternetHangUp( DWORD_PTR dwConnection, DWORD dwReserved )
4518 {
4519 FIXME("(0x%08lx, 0x%08x) stub\n", dwConnection, dwReserved);
4520 return ERROR_SUCCESS;
4521 }
4522
4523 BOOL WINAPI CreateMD5SSOHash( PWSTR pszChallengeInfo, PWSTR pwszRealm, PWSTR pwszTarget,
4524 PBYTE pbHexHash )
4525 {
4526 FIXME("(%s, %s, %s, %p) stub\n", debugstr_w(pszChallengeInfo), debugstr_w(pwszRealm),
4527 debugstr_w(pwszTarget), pbHexHash);
4528 return FALSE;
4529 }
4530
4531 BOOL WINAPI ResumeSuspendedDownload( HINTERNET hInternet, DWORD dwError )
4532 {
4533 FIXME("(%p, 0x%08x) stub\n", hInternet, dwError);
4534 return FALSE;
4535 }
4536
4537 BOOL WINAPI InternetQueryFortezzaStatus(DWORD *a, DWORD_PTR b)
4538 {
4539 FIXME("(%p, %08lx) stub\n", a, b);
4540 return FALSE;
4541 }
4542
4543 DWORD WINAPI ShowClientAuthCerts(HWND parent)
4544 {
4545 FIXME("%p: stub\n", parent);
4546 return 0;
4547 }