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(!strcmpiW(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 + sizeof(wszProtocolsKey)/sizeof(WCHAR), 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 && !strcmpiW(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, sizeof(schema)/sizeof(schema[0]), 175 &schema_len, 0); 176 if(FAILED(hres)) 177 return FALSE; 178 179 return get_protocol_cf(schema, schema_len, NULL, NULL) == S_OK; 180 } 181 182 IInternetProtocolInfo *get_protocol_info(LPCWSTR url) 183 { 184 IInternetProtocolInfo *ret = NULL; 185 IClassFactory *cf; 186 name_space *ns; 187 WCHAR schema[64]; 188 DWORD schema_len; 189 HRESULT hres; 190 191 hres = CoInternetParseUrl(url, PARSE_SCHEMA, 0, schema, sizeof(schema)/sizeof(schema[0]), 192 &schema_len, 0); 193 if(FAILED(hres) || !schema_len) 194 return NULL; 195 196 EnterCriticalSection(&session_cs); 197 198 ns = find_name_space(schema); 199 if(ns && !ns->urlmon) { 200 hres = IClassFactory_QueryInterface(ns->cf, &IID_IInternetProtocolInfo, (void**)&ret); 201 if(FAILED(hres)) 202 hres = IClassFactory_CreateInstance(ns->cf, NULL, &IID_IInternetProtocolInfo, (void**)&ret); 203 } 204 205 LeaveCriticalSection(&session_cs); 206 207 if(ns && SUCCEEDED(hres)) 208 return ret; 209 210 hres = get_protocol_cf(schema, schema_len, NULL, &cf); 211 if(FAILED(hres)) 212 return NULL; 213 214 hres = IClassFactory_QueryInterface(cf, &IID_IInternetProtocolInfo, (void**)&ret); 215 if(FAILED(hres)) 216 IClassFactory_CreateInstance(cf, NULL, &IID_IInternetProtocolInfo, (void**)&ret); 217 IClassFactory_Release(cf); 218 219 return ret; 220 } 221 222 HRESULT get_protocol_handler(IUri *uri, CLSID *clsid, IClassFactory **ret) 223 { 224 name_space *ns; 225 BSTR scheme; 226 HRESULT hres; 227 228 *ret = NULL; 229 230 /* FIXME: Avoid GetSchemeName call for known schemes */ 231 hres = IUri_GetSchemeName(uri, &scheme); 232 if(FAILED(hres)) 233 return hres; 234 235 EnterCriticalSection(&session_cs); 236 237 ns = find_name_space(scheme); 238 if(ns) { 239 *ret = ns->cf; 240 IClassFactory_AddRef(*ret); 241 if(clsid) 242 *clsid = ns->clsid; 243 } 244 245 LeaveCriticalSection(&session_cs); 246 247 hres = *ret ? S_OK : get_protocol_cf(scheme, SysStringLen(scheme), clsid, ret); 248 SysFreeString(scheme); 249 return hres; 250 } 251 252 IInternetProtocol *get_mime_filter(LPCWSTR mime) 253 { 254 static const WCHAR filtersW[] = {'P','r','o','t','o','c','o','l','s', 255 '\\','F','i','l','t','e','r',0 }; 256 static const WCHAR CLSIDW[] = {'C','L','S','I','D',0}; 257 258 IClassFactory *cf = NULL; 259 IInternetProtocol *ret; 260 mime_filter *iter; 261 HKEY hlist, hfilter; 262 WCHAR clsidw[64]; 263 CLSID clsid; 264 DWORD res, type, size; 265 HRESULT hres; 266 267 EnterCriticalSection(&session_cs); 268 269 LIST_FOR_EACH_ENTRY(iter, &mime_filter_list, mime_filter, entry) { 270 if(!strcmpW(iter->mime, mime)) { 271 cf = iter->cf; 272 break; 273 } 274 } 275 276 LeaveCriticalSection(&session_cs); 277 278 if(cf) { 279 hres = IClassFactory_CreateInstance(cf, NULL, &IID_IInternetProtocol, (void**)&ret); 280 if(FAILED(hres)) { 281 WARN("CreateInstance failed: %08x\n", hres); 282 return NULL; 283 } 284 285 return ret; 286 } 287 288 res = RegOpenKeyW(HKEY_CLASSES_ROOT, filtersW, &hlist); 289 if(res != ERROR_SUCCESS) { 290 TRACE("Could not open MIME filters key\n"); 291 return NULL; 292 } 293 294 res = RegOpenKeyW(hlist, mime, &hfilter); 295 CloseHandle(hlist); 296 if(res != ERROR_SUCCESS) 297 return NULL; 298 299 size = sizeof(clsidw); 300 res = RegQueryValueExW(hfilter, CLSIDW, NULL, &type, (LPBYTE)clsidw, &size); 301 CloseHandle(hfilter); 302 if(res!=ERROR_SUCCESS || type!=REG_SZ) { 303 WARN("Could not get filter CLSID for %s\n", debugstr_w(mime)); 304 return NULL; 305 } 306 307 hres = CLSIDFromString(clsidw, &clsid); 308 if(FAILED(hres)) { 309 WARN("CLSIDFromString failed for %s (%x)\n", debugstr_w(mime), hres); 310 return NULL; 311 } 312 313 hres = CoCreateInstance(&clsid, NULL, CLSCTX_INPROC_SERVER, &IID_IInternetProtocol, (void**)&ret); 314 if(FAILED(hres)) { 315 WARN("CoCreateInstance failed: %08x\n", hres); 316 return NULL; 317 } 318 319 return ret; 320 } 321 322 static HRESULT WINAPI InternetSession_QueryInterface(IInternetSession *iface, 323 REFIID riid, void **ppv) 324 { 325 TRACE("(%s %p)\n", debugstr_guid(riid), ppv); 326 327 if(IsEqualGUID(&IID_IUnknown, riid) || IsEqualGUID(&IID_IInternetSession, riid)) { 328 *ppv = iface; 329 IInternetSession_AddRef(iface); 330 return S_OK; 331 } 332 333 *ppv = NULL; 334 return E_NOINTERFACE; 335 } 336 337 static ULONG WINAPI InternetSession_AddRef(IInternetSession *iface) 338 { 339 TRACE("()\n"); 340 URLMON_LockModule(); 341 return 2; 342 } 343 344 static ULONG WINAPI InternetSession_Release(IInternetSession *iface) 345 { 346 TRACE("()\n"); 347 URLMON_UnlockModule(); 348 return 1; 349 } 350 351 static HRESULT WINAPI InternetSession_RegisterNameSpace(IInternetSession *iface, 352 IClassFactory *pCF, REFCLSID rclsid, LPCWSTR pwzProtocol, ULONG cPatterns, 353 const LPCWSTR *ppwzPatterns, DWORD dwReserved) 354 { 355 TRACE("(%p %s %s %d %p %d)\n", pCF, debugstr_guid(rclsid), debugstr_w(pwzProtocol), 356 cPatterns, ppwzPatterns, dwReserved); 357 358 if(cPatterns || ppwzPatterns) 359 FIXME("patterns not supported\n"); 360 if(dwReserved) 361 WARN("dwReserved = %d\n", dwReserved); 362 363 if(!pCF || !pwzProtocol) 364 return E_INVALIDARG; 365 366 return register_namespace(pCF, rclsid, pwzProtocol, FALSE); 367 } 368 369 static HRESULT WINAPI InternetSession_UnregisterNameSpace(IInternetSession *iface, 370 IClassFactory *pCF, LPCWSTR pszProtocol) 371 { 372 TRACE("(%p %s)\n", pCF, debugstr_w(pszProtocol)); 373 374 if(!pCF || !pszProtocol) 375 return E_INVALIDARG; 376 377 return unregister_namespace(pCF, pszProtocol); 378 } 379 380 static HRESULT WINAPI InternetSession_RegisterMimeFilter(IInternetSession *iface, 381 IClassFactory *pCF, REFCLSID rclsid, LPCWSTR pwzType) 382 { 383 mime_filter *filter; 384 385 TRACE("(%p %s %s)\n", pCF, debugstr_guid(rclsid), debugstr_w(pwzType)); 386 387 filter = heap_alloc(sizeof(mime_filter)); 388 389 IClassFactory_AddRef(pCF); 390 filter->cf = pCF; 391 filter->clsid = *rclsid; 392 filter->mime = heap_strdupW(pwzType); 393 394 EnterCriticalSection(&session_cs); 395 396 list_add_head(&mime_filter_list, &filter->entry); 397 398 LeaveCriticalSection(&session_cs); 399 400 return S_OK; 401 } 402 403 static HRESULT WINAPI InternetSession_UnregisterMimeFilter(IInternetSession *iface, 404 IClassFactory *pCF, LPCWSTR pwzType) 405 { 406 mime_filter *iter; 407 408 TRACE("(%p %s)\n", pCF, debugstr_w(pwzType)); 409 410 EnterCriticalSection(&session_cs); 411 412 LIST_FOR_EACH_ENTRY(iter, &mime_filter_list, mime_filter, entry) { 413 if(iter->cf == pCF && !strcmpW(iter->mime, pwzType)) { 414 list_remove(&iter->entry); 415 416 LeaveCriticalSection(&session_cs); 417 418 IClassFactory_Release(iter->cf); 419 heap_free(iter->mime); 420 heap_free(iter); 421 return S_OK; 422 } 423 } 424 425 LeaveCriticalSection(&session_cs); 426 return S_OK; 427 } 428 429 static HRESULT WINAPI InternetSession_CreateBinding(IInternetSession *iface, 430 LPBC pBC, LPCWSTR szUrl, IUnknown *pUnkOuter, IUnknown **ppUnk, 431 IInternetProtocol **ppOInetProt, DWORD dwOption) 432 { 433 BindProtocol *protocol; 434 HRESULT hres; 435 436 TRACE("(%p %s %p %p %p %08x)\n", pBC, debugstr_w(szUrl), pUnkOuter, ppUnk, 437 ppOInetProt, dwOption); 438 439 if(pBC || pUnkOuter || ppUnk || dwOption) 440 FIXME("Unsupported arguments\n"); 441 442 hres = create_binding_protocol(&protocol); 443 if(FAILED(hres)) 444 return hres; 445 446 *ppOInetProt = (IInternetProtocol*)&protocol->IInternetProtocolEx_iface; 447 return S_OK; 448 } 449 450 static HRESULT WINAPI InternetSession_SetSessionOption(IInternetSession *iface, 451 DWORD dwOption, LPVOID pBuffer, DWORD dwBufferLength, DWORD dwReserved) 452 { 453 FIXME("(%08x %p %d %d)\n", dwOption, pBuffer, dwBufferLength, dwReserved); 454 return E_NOTIMPL; 455 } 456 457 static const IInternetSessionVtbl InternetSessionVtbl = { 458 InternetSession_QueryInterface, 459 InternetSession_AddRef, 460 InternetSession_Release, 461 InternetSession_RegisterNameSpace, 462 InternetSession_UnregisterNameSpace, 463 InternetSession_RegisterMimeFilter, 464 InternetSession_UnregisterMimeFilter, 465 InternetSession_CreateBinding, 466 InternetSession_SetSessionOption 467 }; 468 469 static IInternetSession InternetSession = { &InternetSessionVtbl }; 470 471 /*********************************************************************** 472 * CoInternetGetSession (URLMON.@) 473 * 474 * Create a new internet session and return an IInternetSession interface 475 * representing it. 476 * 477 * PARAMS 478 * dwSessionMode [I] Mode for the internet session 479 * ppIInternetSession [O] Destination for creates IInternetSession object 480 * dwReserved [I] Reserved, must be 0. 481 * 482 * RETURNS 483 * Success: S_OK. ppIInternetSession contains the IInternetSession interface. 484 * Failure: E_INVALIDARG, if any argument is invalid, or 485 * E_OUTOFMEMORY if memory allocation fails. 486 */ 487 HRESULT WINAPI CoInternetGetSession(DWORD dwSessionMode, IInternetSession **ppIInternetSession, 488 DWORD dwReserved) 489 { 490 TRACE("(%d %p %d)\n", dwSessionMode, ppIInternetSession, dwReserved); 491 492 if(dwSessionMode) 493 ERR("dwSessionMode=%d\n", dwSessionMode); 494 if(dwReserved) 495 ERR("dwReserved=%d\n", dwReserved); 496 497 IInternetSession_AddRef(&InternetSession); 498 *ppIInternetSession = &InternetSession; 499 return S_OK; 500 } 501 502 /************************************************************************** 503 * UrlMkGetSessionOption (URLMON.@) 504 */ 505 static BOOL get_url_encoding(HKEY root, DWORD *encoding) 506 { 507 DWORD size = sizeof(DWORD), res, type; 508 HKEY hkey; 509 510 static const WCHAR wszUrlEncoding[] = {'U','r','l','E','n','c','o','d','i','n','g',0}; 511 512 res = RegOpenKeyW(root, internet_settings_keyW, &hkey); 513 if(res != ERROR_SUCCESS) 514 return FALSE; 515 516 res = RegQueryValueExW(hkey, wszUrlEncoding, NULL, &type, (LPBYTE)encoding, &size); 517 RegCloseKey(hkey); 518 519 return res == ERROR_SUCCESS; 520 } 521 522 static LPWSTR user_agent; 523 524 static void ensure_useragent(void) 525 { 526 OSVERSIONINFOW info = {sizeof(info)}; 527 const WCHAR *os_type, *is_nt; 528 WCHAR buf[512], *ret, *tmp; 529 DWORD res, idx=0; 530 size_t len, size; 531 BOOL is_wow; 532 HKEY key; 533 534 static const WCHAR formatW[] = 535 {'M','o','z','i','l','l','a','/','4','.','0', 536 ' ','(','c','o','m','p','a','t','i','b','l','e',';', 537 ' ','M','S','I','E',' ','8','.','0',';', 538 ' ','W','i','n','d','o','w','s',' ','%','s','%','d','.','%','d',';', 539 ' ','%','s','T','r','i','d','e','n','t','/','5','.','0',0}; 540 static const WCHAR post_platform_keyW[] = 541 {'S','O','F','T','W','A','R','E', 542 '\\','M','i','c','r','o','s','o','f','t', 543 '\\','W','i','n','d','o','w','s', 544 '\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n', 545 '\\','I','n','t','e','r','n','e','t',' ','S','e','t','t','i','n','g','s', 546 '\\','5','.','0','\\','U','s','e','r',' ','A','g','e','n','t', 547 '\\','P','o','s','t',' ','P','l','a','t','f','o','r','m',0}; 548 static const WCHAR ntW[] = {'N','T',' ',0}; 549 static const WCHAR win64W[] = {'W','i','n','6','4',';',' ','x','6','4',';',' ',0}; 550 static const WCHAR wow64W[] = {'W','O','W','6','4',';',' ',0}; 551 static const WCHAR emptyW[] = {0}; 552 553 if(user_agent) 554 return; 555 556 GetVersionExW(&info); 557 is_nt = info.dwPlatformId == VER_PLATFORM_WIN32_NT ? ntW : emptyW; 558 559 if(sizeof(void*) == 8) 560 os_type = win64W; 561 else if(IsWow64Process(GetCurrentProcess(), &is_wow) && is_wow) 562 os_type = wow64W; 563 else 564 os_type = emptyW; 565 566 sprintfW(buf, formatW, is_nt, info.dwMajorVersion, info.dwMinorVersion, os_type); 567 len = strlenW(buf); 568 569 size = len+40; 570 ret = heap_alloc(size * sizeof(WCHAR)); 571 if(!ret) 572 return; 573 574 memcpy(ret, buf, len*sizeof(WCHAR)); 575 576 res = RegOpenKeyW(HKEY_LOCAL_MACHINE, post_platform_keyW, &key); 577 if(res == ERROR_SUCCESS) { 578 DWORD value_len; 579 580 while(1) { 581 value_len = sizeof(buf)/sizeof(WCHAR); 582 res = RegEnumValueW(key, idx, buf, &value_len, NULL, NULL, NULL, NULL); 583 if(res != ERROR_SUCCESS) 584 break; 585 idx++; 586 587 if(len + value_len + 2 /* strlen("; ") */ + 1 /* trailing ')' */ >= size) { 588 tmp = heap_realloc(ret, (size*2+value_len)*sizeof(WCHAR)); 589 if(!tmp) 590 break; 591 ret = tmp; 592 size = size*2+value_len; 593 } 594 595 ret[len++] = ';'; 596 ret[len++] = ' '; 597 memcpy(ret+len, buf, value_len*sizeof(WCHAR)); 598 len += value_len; 599 } 600 601 RegCloseKey(key); 602 } 603 604 ret[len++] = ')'; 605 ret[len++] = 0; 606 607 user_agent = ret; 608 TRACE("Using user agent %s\n", debugstr_w(user_agent)); 609 } 610 611 LPWSTR get_useragent(void) 612 { 613 LPWSTR ret; 614 615 ensure_useragent(); 616 617 EnterCriticalSection(&session_cs); 618 ret = heap_strdupW(user_agent); 619 LeaveCriticalSection(&session_cs); 620 621 return ret; 622 } 623 624 HRESULT WINAPI UrlMkGetSessionOption(DWORD dwOption, LPVOID pBuffer, DWORD dwBufferLength, 625 DWORD* pdwBufferLength, DWORD dwReserved) 626 { 627 TRACE("(%x, %p, %d, %p)\n", dwOption, pBuffer, dwBufferLength, pdwBufferLength); 628 629 if(dwReserved) 630 WARN("dwReserved = %d\n", dwReserved); 631 632 switch(dwOption) { 633 case URLMON_OPTION_USERAGENT: { 634 HRESULT hres = E_OUTOFMEMORY; 635 DWORD size; 636 637 if(!pdwBufferLength) 638 return E_INVALIDARG; 639 640 EnterCriticalSection(&session_cs); 641 642 ensure_useragent(); 643 if(user_agent) { 644 size = WideCharToMultiByte(CP_ACP, 0, user_agent, -1, NULL, 0, NULL, NULL); 645 *pdwBufferLength = size; 646 if(size <= dwBufferLength) { 647 if(pBuffer) 648 WideCharToMultiByte(CP_ACP, 0, user_agent, -1, pBuffer, size, NULL, NULL); 649 else 650 hres = E_INVALIDARG; 651 } 652 } 653 654 LeaveCriticalSection(&session_cs); 655 656 /* Tests prove that we have to return E_OUTOFMEMORY on success. */ 657 return hres; 658 } 659 case URLMON_OPTION_URL_ENCODING: { 660 DWORD encoding = 0; 661 662 if(!pBuffer || dwBufferLength < sizeof(DWORD) || !pdwBufferLength) 663 return E_INVALIDARG; 664 665 if(!get_url_encoding(HKEY_CURRENT_USER, &encoding)) 666 get_url_encoding(HKEY_LOCAL_MACHINE, &encoding); 667 668 *pdwBufferLength = sizeof(DWORD); 669 *(DWORD*)pBuffer = encoding ? URL_ENCODING_DISABLE_UTF8 : URL_ENCODING_ENABLE_UTF8; 670 return S_OK; 671 } 672 default: 673 FIXME("unsupported option %x\n", dwOption); 674 } 675 676 return E_INVALIDARG; 677 } 678 679 /************************************************************************** 680 * UrlMkSetSessionOption (URLMON.@) 681 */ 682 HRESULT WINAPI UrlMkSetSessionOption(DWORD dwOption, LPVOID pBuffer, DWORD dwBufferLength, 683 DWORD Reserved) 684 { 685 TRACE("(%x %p %x)\n", dwOption, pBuffer, dwBufferLength); 686 687 switch(dwOption) { 688 case URLMON_OPTION_USERAGENT: { 689 LPWSTR new_user_agent; 690 char *buf = pBuffer; 691 DWORD len, size; 692 693 if(!pBuffer || !dwBufferLength) 694 return E_INVALIDARG; 695 696 for(len=0; len<dwBufferLength && buf[len]; len++); 697 698 TRACE("Setting user agent %s\n", debugstr_an(buf, len)); 699 700 size = MultiByteToWideChar(CP_ACP, 0, buf, len, NULL, 0); 701 new_user_agent = heap_alloc((size+1)*sizeof(WCHAR)); 702 if(!new_user_agent) 703 return E_OUTOFMEMORY; 704 MultiByteToWideChar(CP_ACP, 0, buf, len, new_user_agent, size); 705 new_user_agent[size] = 0; 706 707 EnterCriticalSection(&session_cs); 708 709 heap_free(user_agent); 710 user_agent = new_user_agent; 711 update_user_agent(user_agent); 712 713 LeaveCriticalSection(&session_cs); 714 break; 715 } 716 default: 717 FIXME("Unknown option %x\n", dwOption); 718 return E_INVALIDARG; 719 } 720 721 return S_OK; 722 } 723 724 /************************************************************************** 725 * ObtainUserAgentString (URLMON.@) 726 */ 727 HRESULT WINAPI ObtainUserAgentString(DWORD dwOption, LPSTR pcszUAOut, DWORD *cbSize) 728 { 729 DWORD size; 730 HRESULT hres = E_FAIL; 731 732 TRACE("(%d %p %p)\n", dwOption, pcszUAOut, cbSize); 733 734 if(!pcszUAOut || !cbSize) 735 return E_INVALIDARG; 736 737 EnterCriticalSection(&session_cs); 738 739 ensure_useragent(); 740 if(user_agent) { 741 size = WideCharToMultiByte(CP_ACP, 0, user_agent, -1, NULL, 0, NULL, NULL); 742 743 if(size <= *cbSize) { 744 WideCharToMultiByte(CP_ACP, 0, user_agent, -1, pcszUAOut, *cbSize, NULL, NULL); 745 hres = S_OK; 746 }else { 747 hres = E_OUTOFMEMORY; 748 } 749 750 *cbSize = size; 751 } 752 753 LeaveCriticalSection(&session_cs); 754 return hres; 755 } 756 757 void free_session(void) 758 { 759 name_space *ns_iter, *ns_last; 760 mime_filter *mf_iter, *mf_last; 761 762 LIST_FOR_EACH_ENTRY_SAFE(ns_iter, ns_last, &name_space_list, name_space, entry) { 763 if(!ns_iter->urlmon) 764 IClassFactory_Release(ns_iter->cf); 765 heap_free(ns_iter->protocol); 766 heap_free(ns_iter); 767 } 768 769 LIST_FOR_EACH_ENTRY_SAFE(mf_iter, mf_last, &mime_filter_list, mime_filter, entry) { 770 IClassFactory_Release(mf_iter->cf); 771 heap_free(mf_iter->mime); 772 heap_free(mf_iter); 773 } 774 775 heap_free(user_agent); 776 } 777