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