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