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