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