1 /* 2 * Copyright 2005-2006 Jacek Caban for CodeWeavers 3 * 4 * This library is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU Lesser General Public 6 * License as published by the Free Software Foundation; either 7 * version 2.1 of the License, or (at your option) any later version. 8 * 9 * This library is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 * Lesser General Public License for more details. 13 * 14 * You should have received a copy of the GNU Lesser General Public 15 * License along with this library; if not, write to the Free Software 16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 17 */ 18 19 #include "urlmon_main.h" 20 #include "winreg.h" 21 22 #include "wine/debug.h" 23 24 WINE_DEFAULT_DEBUG_CHANNEL(urlmon); 25 26 typedef struct { 27 LPWSTR protocol; 28 IClassFactory *cf; 29 CLSID clsid; 30 BOOL urlmon; 31 32 struct list entry; 33 } name_space; 34 35 typedef struct { 36 IClassFactory *cf; 37 CLSID clsid; 38 LPWSTR mime; 39 40 struct list entry; 41 } mime_filter; 42 43 static struct list name_space_list = LIST_INIT(name_space_list); 44 static struct list mime_filter_list = LIST_INIT(mime_filter_list); 45 46 static CRITICAL_SECTION session_cs; 47 static CRITICAL_SECTION_DEBUG session_cs_dbg = 48 { 49 0, 0, &session_cs, 50 { &session_cs_dbg.ProcessLocksList, &session_cs_dbg.ProcessLocksList }, 51 0, 0, { (DWORD_PTR)(__FILE__ ": session") } 52 }; 53 static CRITICAL_SECTION session_cs = { &session_cs_dbg, -1, 0, 0, 0, 0 }; 54 55 static const WCHAR internet_settings_keyW[] = 56 {'S','O','F','T','W','A','R','E', 57 '\\','M','i','c','r','o','s','o','f','t', 58 '\\','W','i','n','d','o','w','s', 59 '\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n', 60 '\\','I','n','t','e','r','n','e','t',' ','S','e','t','t','i','n','g','s',0}; 61 62 static name_space *find_name_space(LPCWSTR protocol) 63 { 64 name_space *iter; 65 66 LIST_FOR_EACH_ENTRY(iter, &name_space_list, name_space, entry) { 67 if(!wcsicmp(iter->protocol, protocol)) 68 return iter; 69 } 70 71 return NULL; 72 } 73 74 static HRESULT get_protocol_cf(LPCWSTR schema, DWORD schema_len, CLSID *pclsid, IClassFactory **ret) 75 { 76 WCHAR str_clsid[64]; 77 HKEY hkey = NULL; 78 DWORD res, type, size; 79 CLSID clsid; 80 LPWSTR wszKey; 81 HRESULT hres; 82 83 static const WCHAR wszProtocolsKey[] = 84 {'P','R','O','T','O','C','O','L','S','\\','H','a','n','d','l','e','r','\\'}; 85 static const WCHAR wszCLSID[] = {'C','L','S','I','D',0}; 86 87 wszKey = heap_alloc(sizeof(wszProtocolsKey)+(schema_len+1)*sizeof(WCHAR)); 88 memcpy(wszKey, wszProtocolsKey, sizeof(wszProtocolsKey)); 89 memcpy(wszKey + ARRAY_SIZE(wszProtocolsKey), schema, (schema_len+1)*sizeof(WCHAR)); 90 91 res = RegOpenKeyW(HKEY_CLASSES_ROOT, wszKey, &hkey); 92 heap_free(wszKey); 93 if(res != ERROR_SUCCESS) { 94 TRACE("Could not open protocol handler key\n"); 95 return MK_E_SYNTAX; 96 } 97 98 size = sizeof(str_clsid); 99 res = RegQueryValueExW(hkey, wszCLSID, NULL, &type, (LPBYTE)str_clsid, &size); 100 RegCloseKey(hkey); 101 if(res != ERROR_SUCCESS || type != REG_SZ) { 102 WARN("Could not get protocol CLSID res=%d\n", res); 103 return MK_E_SYNTAX; 104 } 105 106 hres = CLSIDFromString(str_clsid, &clsid); 107 if(FAILED(hres)) { 108 WARN("CLSIDFromString failed: %08x\n", hres); 109 return hres; 110 } 111 112 if(pclsid) 113 *pclsid = clsid; 114 115 if(!ret) 116 return S_OK; 117 118 hres = CoGetClassObject(&clsid, CLSCTX_INPROC_SERVER, NULL, &IID_IClassFactory, (void**)ret); 119 return SUCCEEDED(hres) ? S_OK : MK_E_SYNTAX; 120 } 121 122 HRESULT register_namespace(IClassFactory *cf, REFIID clsid, LPCWSTR protocol, BOOL urlmon_protocol) 123 { 124 name_space *new_name_space; 125 126 new_name_space = heap_alloc(sizeof(name_space)); 127 128 if(!urlmon_protocol) 129 IClassFactory_AddRef(cf); 130 new_name_space->cf = cf; 131 new_name_space->clsid = *clsid; 132 new_name_space->urlmon = urlmon_protocol; 133 new_name_space->protocol = heap_strdupW(protocol); 134 135 EnterCriticalSection(&session_cs); 136 137 list_add_head(&name_space_list, &new_name_space->entry); 138 139 LeaveCriticalSection(&session_cs); 140 141 return S_OK; 142 } 143 144 static HRESULT unregister_namespace(IClassFactory *cf, LPCWSTR protocol) 145 { 146 name_space *iter; 147 148 EnterCriticalSection(&session_cs); 149 150 LIST_FOR_EACH_ENTRY(iter, &name_space_list, name_space, entry) { 151 if(iter->cf == cf && !wcsicmp(iter->protocol, protocol)) { 152 list_remove(&iter->entry); 153 154 LeaveCriticalSection(&session_cs); 155 156 if(!iter->urlmon) 157 IClassFactory_Release(iter->cf); 158 heap_free(iter->protocol); 159 heap_free(iter); 160 return S_OK; 161 } 162 } 163 164 LeaveCriticalSection(&session_cs); 165 return S_OK; 166 } 167 168 BOOL is_registered_protocol(LPCWSTR url) 169 { 170 DWORD schema_len; 171 WCHAR schema[64]; 172 HRESULT hres; 173 174 hres = CoInternetParseUrl(url, PARSE_SCHEMA, 0, schema, ARRAY_SIZE(schema), &schema_len, 0); 175 if(FAILED(hres)) 176 return FALSE; 177 178 return get_protocol_cf(schema, schema_len, NULL, NULL) == S_OK; 179 } 180 181 IInternetProtocolInfo *get_protocol_info(LPCWSTR url) 182 { 183 IInternetProtocolInfo *ret = NULL; 184 IClassFactory *cf; 185 name_space *ns; 186 WCHAR schema[64]; 187 DWORD schema_len; 188 HRESULT hres; 189 190 hres = CoInternetParseUrl(url, PARSE_SCHEMA, 0, schema, ARRAY_SIZE(schema), &schema_len, 0); 191 if(FAILED(hres) || !schema_len) 192 return NULL; 193 194 EnterCriticalSection(&session_cs); 195 196 ns = find_name_space(schema); 197 if(ns && !ns->urlmon) { 198 hres = IClassFactory_QueryInterface(ns->cf, &IID_IInternetProtocolInfo, (void**)&ret); 199 if(FAILED(hres)) 200 hres = IClassFactory_CreateInstance(ns->cf, NULL, &IID_IInternetProtocolInfo, (void**)&ret); 201 } 202 203 LeaveCriticalSection(&session_cs); 204 205 if(ns && SUCCEEDED(hres)) 206 return ret; 207 208 hres = get_protocol_cf(schema, schema_len, NULL, &cf); 209 if(FAILED(hres)) 210 return NULL; 211 212 hres = IClassFactory_QueryInterface(cf, &IID_IInternetProtocolInfo, (void**)&ret); 213 if(FAILED(hres)) 214 IClassFactory_CreateInstance(cf, NULL, &IID_IInternetProtocolInfo, (void**)&ret); 215 IClassFactory_Release(cf); 216 217 return ret; 218 } 219 220 HRESULT get_protocol_handler(IUri *uri, CLSID *clsid, IClassFactory **ret) 221 { 222 name_space *ns; 223 BSTR scheme; 224 HRESULT hres; 225 226 *ret = NULL; 227 228 /* FIXME: Avoid GetSchemeName call for known schemes */ 229 hres = IUri_GetSchemeName(uri, &scheme); 230 if(FAILED(hres)) 231 return hres; 232 233 EnterCriticalSection(&session_cs); 234 235 ns = find_name_space(scheme); 236 if(ns) { 237 *ret = ns->cf; 238 IClassFactory_AddRef(*ret); 239 if(clsid) 240 *clsid = ns->clsid; 241 } 242 243 LeaveCriticalSection(&session_cs); 244 245 hres = *ret ? S_OK : get_protocol_cf(scheme, SysStringLen(scheme), clsid, ret); 246 SysFreeString(scheme); 247 return hres; 248 } 249 250 IInternetProtocol *get_mime_filter(LPCWSTR mime) 251 { 252 static const WCHAR filtersW[] = {'P','r','o','t','o','c','o','l','s', 253 '\\','F','i','l','t','e','r',0 }; 254 static const WCHAR CLSIDW[] = {'C','L','S','I','D',0}; 255 256 IClassFactory *cf = NULL; 257 IInternetProtocol *ret; 258 mime_filter *iter; 259 HKEY hlist, hfilter; 260 WCHAR clsidw[64]; 261 CLSID clsid; 262 DWORD res, type, size; 263 HRESULT hres; 264 265 EnterCriticalSection(&session_cs); 266 267 LIST_FOR_EACH_ENTRY(iter, &mime_filter_list, mime_filter, entry) { 268 if(!wcscmp(iter->mime, mime)) { 269 cf = iter->cf; 270 break; 271 } 272 } 273 274 LeaveCriticalSection(&session_cs); 275 276 if(cf) { 277 hres = IClassFactory_CreateInstance(cf, NULL, &IID_IInternetProtocol, (void**)&ret); 278 if(FAILED(hres)) { 279 WARN("CreateInstance failed: %08x\n", hres); 280 return NULL; 281 } 282 283 return ret; 284 } 285 286 res = RegOpenKeyW(HKEY_CLASSES_ROOT, filtersW, &hlist); 287 if(res != ERROR_SUCCESS) { 288 TRACE("Could not open MIME filters key\n"); 289 return NULL; 290 } 291 292 res = RegOpenKeyW(hlist, mime, &hfilter); 293 CloseHandle(hlist); 294 if(res != ERROR_SUCCESS) 295 return NULL; 296 297 size = sizeof(clsidw); 298 res = RegQueryValueExW(hfilter, CLSIDW, NULL, &type, (LPBYTE)clsidw, &size); 299 CloseHandle(hfilter); 300 if(res!=ERROR_SUCCESS || type!=REG_SZ) { 301 WARN("Could not get filter CLSID for %s\n", debugstr_w(mime)); 302 return NULL; 303 } 304 305 hres = CLSIDFromString(clsidw, &clsid); 306 if(FAILED(hres)) { 307 WARN("CLSIDFromString failed for %s (%x)\n", debugstr_w(mime), hres); 308 return NULL; 309 } 310 311 hres = CoCreateInstance(&clsid, NULL, CLSCTX_INPROC_SERVER, &IID_IInternetProtocol, (void**)&ret); 312 if(FAILED(hres)) { 313 WARN("CoCreateInstance failed: %08x\n", hres); 314 return NULL; 315 } 316 317 return ret; 318 } 319 320 static HRESULT WINAPI InternetSession_QueryInterface(IInternetSession *iface, 321 REFIID riid, void **ppv) 322 { 323 TRACE("(%s %p)\n", debugstr_guid(riid), ppv); 324 325 if(IsEqualGUID(&IID_IUnknown, riid) || IsEqualGUID(&IID_IInternetSession, riid)) { 326 *ppv = iface; 327 IInternetSession_AddRef(iface); 328 return S_OK; 329 } 330 331 *ppv = NULL; 332 return E_NOINTERFACE; 333 } 334 335 static ULONG WINAPI InternetSession_AddRef(IInternetSession *iface) 336 { 337 TRACE("()\n"); 338 URLMON_LockModule(); 339 return 2; 340 } 341 342 static ULONG WINAPI InternetSession_Release(IInternetSession *iface) 343 { 344 TRACE("()\n"); 345 URLMON_UnlockModule(); 346 return 1; 347 } 348 349 static HRESULT WINAPI InternetSession_RegisterNameSpace(IInternetSession *iface, 350 IClassFactory *pCF, REFCLSID rclsid, LPCWSTR pwzProtocol, ULONG cPatterns, 351 const LPCWSTR *ppwzPatterns, DWORD dwReserved) 352 { 353 TRACE("(%p %s %s %d %p %d)\n", pCF, debugstr_guid(rclsid), debugstr_w(pwzProtocol), 354 cPatterns, ppwzPatterns, dwReserved); 355 356 if(cPatterns || ppwzPatterns) 357 FIXME("patterns not supported\n"); 358 if(dwReserved) 359 WARN("dwReserved = %d\n", dwReserved); 360 361 if(!pCF || !pwzProtocol) 362 return E_INVALIDARG; 363 364 return register_namespace(pCF, rclsid, pwzProtocol, FALSE); 365 } 366 367 static HRESULT WINAPI InternetSession_UnregisterNameSpace(IInternetSession *iface, 368 IClassFactory *pCF, LPCWSTR pszProtocol) 369 { 370 TRACE("(%p %s)\n", pCF, debugstr_w(pszProtocol)); 371 372 if(!pCF || !pszProtocol) 373 return E_INVALIDARG; 374 375 return unregister_namespace(pCF, pszProtocol); 376 } 377 378 static HRESULT WINAPI InternetSession_RegisterMimeFilter(IInternetSession *iface, 379 IClassFactory *pCF, REFCLSID rclsid, LPCWSTR pwzType) 380 { 381 mime_filter *filter; 382 383 TRACE("(%p %s %s)\n", pCF, debugstr_guid(rclsid), debugstr_w(pwzType)); 384 385 filter = heap_alloc(sizeof(mime_filter)); 386 387 IClassFactory_AddRef(pCF); 388 filter->cf = pCF; 389 filter->clsid = *rclsid; 390 filter->mime = heap_strdupW(pwzType); 391 392 EnterCriticalSection(&session_cs); 393 394 list_add_head(&mime_filter_list, &filter->entry); 395 396 LeaveCriticalSection(&session_cs); 397 398 return S_OK; 399 } 400 401 static HRESULT WINAPI InternetSession_UnregisterMimeFilter(IInternetSession *iface, 402 IClassFactory *pCF, LPCWSTR pwzType) 403 { 404 mime_filter *iter; 405 406 TRACE("(%p %s)\n", pCF, debugstr_w(pwzType)); 407 408 EnterCriticalSection(&session_cs); 409 410 LIST_FOR_EACH_ENTRY(iter, &mime_filter_list, mime_filter, entry) { 411 if(iter->cf == pCF && !wcscmp(iter->mime, pwzType)) { 412 list_remove(&iter->entry); 413 414 LeaveCriticalSection(&session_cs); 415 416 IClassFactory_Release(iter->cf); 417 heap_free(iter->mime); 418 heap_free(iter); 419 return S_OK; 420 } 421 } 422 423 LeaveCriticalSection(&session_cs); 424 return S_OK; 425 } 426 427 static HRESULT WINAPI InternetSession_CreateBinding(IInternetSession *iface, 428 LPBC pBC, LPCWSTR szUrl, IUnknown *pUnkOuter, IUnknown **ppUnk, 429 IInternetProtocol **ppOInetProt, DWORD dwOption) 430 { 431 BindProtocol *protocol; 432 HRESULT hres; 433 434 TRACE("(%p %s %p %p %p %08x)\n", pBC, debugstr_w(szUrl), pUnkOuter, ppUnk, 435 ppOInetProt, dwOption); 436 437 if(pBC || pUnkOuter || ppUnk || dwOption) 438 FIXME("Unsupported arguments\n"); 439 440 hres = create_binding_protocol(&protocol); 441 if(FAILED(hres)) 442 return hres; 443 444 *ppOInetProt = (IInternetProtocol*)&protocol->IInternetProtocolEx_iface; 445 return S_OK; 446 } 447 448 static HRESULT WINAPI InternetSession_SetSessionOption(IInternetSession *iface, 449 DWORD dwOption, LPVOID pBuffer, DWORD dwBufferLength, DWORD dwReserved) 450 { 451 FIXME("(%08x %p %d %d)\n", dwOption, pBuffer, dwBufferLength, dwReserved); 452 return E_NOTIMPL; 453 } 454 455 static const IInternetSessionVtbl InternetSessionVtbl = { 456 InternetSession_QueryInterface, 457 InternetSession_AddRef, 458 InternetSession_Release, 459 InternetSession_RegisterNameSpace, 460 InternetSession_UnregisterNameSpace, 461 InternetSession_RegisterMimeFilter, 462 InternetSession_UnregisterMimeFilter, 463 InternetSession_CreateBinding, 464 InternetSession_SetSessionOption 465 }; 466 467 static IInternetSession InternetSession = { &InternetSessionVtbl }; 468 469 /*********************************************************************** 470 * CoInternetGetSession (URLMON.@) 471 * 472 * Create a new internet session and return an IInternetSession interface 473 * representing it. 474 * 475 * PARAMS 476 * dwSessionMode [I] Mode for the internet session 477 * ppIInternetSession [O] Destination for creates IInternetSession object 478 * dwReserved [I] Reserved, must be 0. 479 * 480 * RETURNS 481 * Success: S_OK. ppIInternetSession contains the IInternetSession interface. 482 * Failure: E_INVALIDARG, if any argument is invalid, or 483 * E_OUTOFMEMORY if memory allocation fails. 484 */ 485 HRESULT WINAPI CoInternetGetSession(DWORD dwSessionMode, IInternetSession **ppIInternetSession, 486 DWORD dwReserved) 487 { 488 TRACE("(%d %p %d)\n", dwSessionMode, ppIInternetSession, dwReserved); 489 490 if(dwSessionMode) 491 ERR("dwSessionMode=%d\n", dwSessionMode); 492 if(dwReserved) 493 ERR("dwReserved=%d\n", dwReserved); 494 495 IInternetSession_AddRef(&InternetSession); 496 *ppIInternetSession = &InternetSession; 497 return S_OK; 498 } 499 500 /************************************************************************** 501 * UrlMkGetSessionOption (URLMON.@) 502 */ 503 static BOOL get_url_encoding(HKEY root, DWORD *encoding) 504 { 505 DWORD size = sizeof(DWORD), res, type; 506 HKEY hkey; 507 508 static const WCHAR wszUrlEncoding[] = {'U','r','l','E','n','c','o','d','i','n','g',0}; 509 510 res = RegOpenKeyW(root, internet_settings_keyW, &hkey); 511 if(res != ERROR_SUCCESS) 512 return FALSE; 513 514 res = RegQueryValueExW(hkey, wszUrlEncoding, NULL, &type, (LPBYTE)encoding, &size); 515 RegCloseKey(hkey); 516 517 return res == ERROR_SUCCESS; 518 } 519 520 static LPWSTR user_agent; 521 522 static void ensure_useragent(void) 523 { 524 OSVERSIONINFOW info = {sizeof(info)}; 525 const WCHAR *os_type, *is_nt; 526 WCHAR buf[512], *ret, *tmp; 527 DWORD res, idx=0; 528 size_t len, size; 529 BOOL is_wow; 530 HKEY key; 531 532 static const WCHAR formatW[] = 533 {'M','o','z','i','l','l','a','/','4','.','0', 534 ' ','(','c','o','m','p','a','t','i','b','l','e',';', 535 ' ','M','S','I','E',' ','8','.','0',';', 536 ' ','W','i','n','d','o','w','s',' ','%','s','%','d','.','%','d',';', 537 ' ','%','s','T','r','i','d','e','n','t','/','5','.','0',0}; 538 static const WCHAR post_platform_keyW[] = 539 {'S','O','F','T','W','A','R','E', 540 '\\','M','i','c','r','o','s','o','f','t', 541 '\\','W','i','n','d','o','w','s', 542 '\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n', 543 '\\','I','n','t','e','r','n','e','t',' ','S','e','t','t','i','n','g','s', 544 '\\','5','.','0','\\','U','s','e','r',' ','A','g','e','n','t', 545 '\\','P','o','s','t',' ','P','l','a','t','f','o','r','m',0}; 546 static const WCHAR ntW[] = {'N','T',' ',0}; 547 static const WCHAR win64W[] = {'W','i','n','6','4',';',' ','x','6','4',';',' ',0}; 548 static const WCHAR wow64W[] = {'W','O','W','6','4',';',' ',0}; 549 static const WCHAR emptyW[] = {0}; 550 551 if(user_agent) 552 return; 553 554 GetVersionExW(&info); 555 is_nt = info.dwPlatformId == VER_PLATFORM_WIN32_NT ? ntW : emptyW; 556 557 if(sizeof(void*) == 8) 558 os_type = win64W; 559 else if(IsWow64Process(GetCurrentProcess(), &is_wow) && is_wow) 560 os_type = wow64W; 561 else 562 os_type = emptyW; 563 564 swprintf(buf, formatW, is_nt, info.dwMajorVersion, info.dwMinorVersion, os_type); 565 len = lstrlenW(buf); 566 567 size = len+40; 568 ret = heap_alloc(size * sizeof(WCHAR)); 569 if(!ret) 570 return; 571 572 memcpy(ret, buf, len*sizeof(WCHAR)); 573 574 res = RegOpenKeyW(HKEY_LOCAL_MACHINE, post_platform_keyW, &key); 575 if(res == ERROR_SUCCESS) { 576 DWORD value_len; 577 578 while(1) { 579 value_len = ARRAY_SIZE(buf); 580 res = RegEnumValueW(key, idx, buf, &value_len, NULL, NULL, NULL, NULL); 581 if(res != ERROR_SUCCESS) 582 break; 583 idx++; 584 585 if(len + value_len + 2 /* strlen("; ") */ + 1 /* trailing ')' */ >= size) { 586 tmp = heap_realloc(ret, (size*2+value_len)*sizeof(WCHAR)); 587 if(!tmp) 588 break; 589 ret = tmp; 590 size = size*2+value_len; 591 } 592 593 ret[len++] = ';'; 594 ret[len++] = ' '; 595 memcpy(ret+len, buf, value_len*sizeof(WCHAR)); 596 len += value_len; 597 } 598 599 RegCloseKey(key); 600 } 601 602 ret[len++] = ')'; 603 ret[len++] = 0; 604 605 user_agent = ret; 606 TRACE("Using user agent %s\n", debugstr_w(user_agent)); 607 } 608 609 LPWSTR get_useragent(void) 610 { 611 LPWSTR ret; 612 613 ensure_useragent(); 614 615 EnterCriticalSection(&session_cs); 616 ret = heap_strdupW(user_agent); 617 LeaveCriticalSection(&session_cs); 618 619 return ret; 620 } 621 622 HRESULT WINAPI UrlMkGetSessionOption(DWORD dwOption, LPVOID pBuffer, DWORD dwBufferLength, 623 DWORD* pdwBufferLength, DWORD dwReserved) 624 { 625 TRACE("(%x, %p, %d, %p)\n", dwOption, pBuffer, dwBufferLength, pdwBufferLength); 626 627 if(dwReserved) 628 WARN("dwReserved = %d\n", dwReserved); 629 630 switch(dwOption) { 631 case URLMON_OPTION_USERAGENT: { 632 HRESULT hres = E_OUTOFMEMORY; 633 DWORD size; 634 635 if(!pdwBufferLength) 636 return E_INVALIDARG; 637 638 EnterCriticalSection(&session_cs); 639 640 ensure_useragent(); 641 if(user_agent) { 642 size = WideCharToMultiByte(CP_ACP, 0, user_agent, -1, NULL, 0, NULL, NULL); 643 *pdwBufferLength = size; 644 if(size <= dwBufferLength) { 645 if(pBuffer) 646 WideCharToMultiByte(CP_ACP, 0, user_agent, -1, pBuffer, size, NULL, NULL); 647 else 648 hres = E_INVALIDARG; 649 } 650 } 651 652 LeaveCriticalSection(&session_cs); 653 654 /* Tests prove that we have to return E_OUTOFMEMORY on success. */ 655 return hres; 656 } 657 case URLMON_OPTION_URL_ENCODING: { 658 DWORD encoding = 0; 659 660 if(!pBuffer || dwBufferLength < sizeof(DWORD) || !pdwBufferLength) 661 return E_INVALIDARG; 662 663 if(!get_url_encoding(HKEY_CURRENT_USER, &encoding)) 664 get_url_encoding(HKEY_LOCAL_MACHINE, &encoding); 665 666 *pdwBufferLength = sizeof(DWORD); 667 *(DWORD*)pBuffer = encoding ? URL_ENCODING_DISABLE_UTF8 : URL_ENCODING_ENABLE_UTF8; 668 return S_OK; 669 } 670 default: 671 FIXME("unsupported option %x\n", dwOption); 672 } 673 674 return E_INVALIDARG; 675 } 676 677 /************************************************************************** 678 * UrlMkSetSessionOption (URLMON.@) 679 */ 680 HRESULT WINAPI UrlMkSetSessionOption(DWORD dwOption, LPVOID pBuffer, DWORD dwBufferLength, 681 DWORD Reserved) 682 { 683 TRACE("(%x %p %x)\n", dwOption, pBuffer, dwBufferLength); 684 685 switch(dwOption) { 686 case URLMON_OPTION_USERAGENT: { 687 LPWSTR new_user_agent; 688 char *buf = pBuffer; 689 DWORD len, size; 690 691 if(!pBuffer || !dwBufferLength) 692 return E_INVALIDARG; 693 694 for(len=0; len<dwBufferLength && buf[len]; len++); 695 696 TRACE("Setting user agent %s\n", debugstr_an(buf, len)); 697 698 size = MultiByteToWideChar(CP_ACP, 0, buf, len, NULL, 0); 699 new_user_agent = heap_alloc((size+1)*sizeof(WCHAR)); 700 if(!new_user_agent) 701 return E_OUTOFMEMORY; 702 MultiByteToWideChar(CP_ACP, 0, buf, len, new_user_agent, size); 703 new_user_agent[size] = 0; 704 705 EnterCriticalSection(&session_cs); 706 707 heap_free(user_agent); 708 user_agent = new_user_agent; 709 update_user_agent(user_agent); 710 711 LeaveCriticalSection(&session_cs); 712 break; 713 } 714 default: 715 FIXME("Unknown option %x\n", dwOption); 716 return E_INVALIDARG; 717 } 718 719 return S_OK; 720 } 721 722 /************************************************************************** 723 * ObtainUserAgentString (URLMON.@) 724 */ 725 HRESULT WINAPI ObtainUserAgentString(DWORD dwOption, LPSTR pcszUAOut, DWORD *cbSize) 726 { 727 DWORD size; 728 HRESULT hres = E_FAIL; 729 730 TRACE("(%d %p %p)\n", dwOption, pcszUAOut, cbSize); 731 732 if(!pcszUAOut || !cbSize) 733 return E_INVALIDARG; 734 735 EnterCriticalSection(&session_cs); 736 737 ensure_useragent(); 738 if(user_agent) { 739 size = WideCharToMultiByte(CP_ACP, 0, user_agent, -1, NULL, 0, NULL, NULL); 740 741 if(size <= *cbSize) { 742 WideCharToMultiByte(CP_ACP, 0, user_agent, -1, pcszUAOut, *cbSize, NULL, NULL); 743 hres = S_OK; 744 }else { 745 hres = E_OUTOFMEMORY; 746 } 747 748 *cbSize = size; 749 } 750 751 LeaveCriticalSection(&session_cs); 752 return hres; 753 } 754 755 void free_session(void) 756 { 757 name_space *ns_iter, *ns_last; 758 mime_filter *mf_iter, *mf_last; 759 760 LIST_FOR_EACH_ENTRY_SAFE(ns_iter, ns_last, &name_space_list, name_space, entry) { 761 if(!ns_iter->urlmon) 762 IClassFactory_Release(ns_iter->cf); 763 heap_free(ns_iter->protocol); 764 heap_free(ns_iter); 765 } 766 767 LIST_FOR_EACH_ENTRY_SAFE(mf_iter, mf_last, &mime_filter_list, mime_filter, entry) { 768 IClassFactory_Release(mf_iter->cf); 769 heap_free(mf_iter->mime); 770 heap_free(mf_iter); 771 } 772 773 heap_free(user_agent); 774 } 775