wineoss: Use dedicated macros to call interface functions.
[wine.git] / dlls / urlmon / session.c
blob660fab54570c6fd1da8a1d2fb14951f42a281331
1 /*
2 * Copyright 2005-2006 Jacek Caban for CodeWeavers
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.
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.
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
19 #include "urlmon_main.h"
20 #include "winreg.h"
22 #include "wine/debug.h"
24 WINE_DEFAULT_DEBUG_CHANNEL(urlmon);
26 typedef struct {
27 LPWSTR protocol;
28 IClassFactory *cf;
29 CLSID clsid;
30 BOOL urlmon;
32 struct list entry;
33 } name_space;
35 typedef struct {
36 IClassFactory *cf;
37 CLSID clsid;
38 LPWSTR mime;
40 struct list entry;
41 } mime_filter;
43 static struct list name_space_list = LIST_INIT(name_space_list);
44 static struct list mime_filter_list = LIST_INIT(mime_filter_list);
46 static CRITICAL_SECTION session_cs;
47 static CRITICAL_SECTION_DEBUG session_cs_dbg =
49 0, 0, &session_cs,
50 { &session_cs_dbg.ProcessLocksList, &session_cs_dbg.ProcessLocksList },
51 0, 0, { (DWORD_PTR)(__FILE__ ": session") }
53 static CRITICAL_SECTION session_cs = { &session_cs_dbg, -1, 0, 0, 0, 0 };
55 static name_space *find_name_space(LPCWSTR protocol)
57 name_space *iter;
59 LIST_FOR_EACH_ENTRY(iter, &name_space_list, name_space, entry) {
60 if(!wcsicmp(iter->protocol, protocol))
61 return iter;
64 return NULL;
67 static HRESULT get_protocol_cf(LPCWSTR schema, DWORD schema_len, CLSID *pclsid, IClassFactory **ret)
69 WCHAR str_clsid[64];
70 HKEY hkey = NULL;
71 DWORD res, type, size;
72 CLSID clsid;
73 LPWSTR wszKey;
74 HRESULT hres;
76 static const WCHAR wszProtocolsKey[] =
77 {'P','R','O','T','O','C','O','L','S','\\','H','a','n','d','l','e','r','\\'};
79 wszKey = malloc(sizeof(wszProtocolsKey) + (schema_len + 1) * sizeof(WCHAR));
80 memcpy(wszKey, wszProtocolsKey, sizeof(wszProtocolsKey));
81 memcpy(wszKey + ARRAY_SIZE(wszProtocolsKey), schema, (schema_len+1)*sizeof(WCHAR));
83 res = RegOpenKeyW(HKEY_CLASSES_ROOT, wszKey, &hkey);
84 free(wszKey);
85 if(res != ERROR_SUCCESS) {
86 TRACE("Could not open protocol handler key\n");
87 return MK_E_SYNTAX;
90 size = sizeof(str_clsid);
91 res = RegQueryValueExW(hkey, L"CLSID", NULL, &type, (BYTE*)str_clsid, &size);
92 RegCloseKey(hkey);
93 if(res != ERROR_SUCCESS || type != REG_SZ) {
94 WARN("Could not get protocol CLSID res=%ld\n", res);
95 return MK_E_SYNTAX;
98 hres = CLSIDFromString(str_clsid, &clsid);
99 if(FAILED(hres)) {
100 WARN("CLSIDFromString failed: %08lx\n", hres);
101 return hres;
104 if(pclsid)
105 *pclsid = clsid;
107 if(!ret)
108 return S_OK;
110 hres = CoGetClassObject(&clsid, CLSCTX_INPROC_SERVER, NULL, &IID_IClassFactory, (void**)ret);
111 return SUCCEEDED(hres) ? S_OK : MK_E_SYNTAX;
114 HRESULT register_namespace(IClassFactory *cf, REFIID clsid, LPCWSTR protocol, BOOL urlmon_protocol)
116 name_space *new_name_space;
118 new_name_space = malloc(sizeof(name_space));
120 if(!urlmon_protocol)
121 IClassFactory_AddRef(cf);
122 new_name_space->cf = cf;
123 new_name_space->clsid = *clsid;
124 new_name_space->urlmon = urlmon_protocol;
125 new_name_space->protocol = wcsdup(protocol);
127 EnterCriticalSection(&session_cs);
129 list_add_head(&name_space_list, &new_name_space->entry);
131 LeaveCriticalSection(&session_cs);
133 return S_OK;
136 static HRESULT unregister_namespace(IClassFactory *cf, LPCWSTR protocol)
138 name_space *iter;
140 EnterCriticalSection(&session_cs);
142 LIST_FOR_EACH_ENTRY(iter, &name_space_list, name_space, entry) {
143 if(iter->cf == cf && !wcsicmp(iter->protocol, protocol)) {
144 list_remove(&iter->entry);
146 LeaveCriticalSection(&session_cs);
148 if(!iter->urlmon)
149 IClassFactory_Release(iter->cf);
150 free(iter->protocol);
151 free(iter);
152 return S_OK;
156 LeaveCriticalSection(&session_cs);
157 return S_OK;
160 BOOL is_registered_protocol(LPCWSTR url)
162 DWORD schema_len;
163 WCHAR schema[64];
164 HRESULT hres;
166 hres = CoInternetParseUrl(url, PARSE_SCHEMA, 0, schema, ARRAY_SIZE(schema), &schema_len, 0);
167 if(FAILED(hres))
168 return FALSE;
170 return get_protocol_cf(schema, schema_len, NULL, NULL) == S_OK;
173 IInternetProtocolInfo *get_protocol_info(LPCWSTR url)
175 IInternetProtocolInfo *ret = NULL;
176 IClassFactory *cf;
177 name_space *ns;
178 WCHAR schema[64];
179 DWORD schema_len;
180 HRESULT hres;
182 hres = CoInternetParseUrl(url, PARSE_SCHEMA, 0, schema, ARRAY_SIZE(schema), &schema_len, 0);
183 if(FAILED(hres) || !schema_len)
184 return NULL;
186 EnterCriticalSection(&session_cs);
188 ns = find_name_space(schema);
189 if(ns && !ns->urlmon) {
190 hres = IClassFactory_QueryInterface(ns->cf, &IID_IInternetProtocolInfo, (void**)&ret);
191 if(FAILED(hres))
192 hres = IClassFactory_CreateInstance(ns->cf, NULL, &IID_IInternetProtocolInfo, (void**)&ret);
195 LeaveCriticalSection(&session_cs);
197 if(ns && SUCCEEDED(hres))
198 return ret;
200 hres = get_protocol_cf(schema, schema_len, NULL, &cf);
201 if(FAILED(hres))
202 return NULL;
204 hres = IClassFactory_QueryInterface(cf, &IID_IInternetProtocolInfo, (void**)&ret);
205 if(FAILED(hres))
206 IClassFactory_CreateInstance(cf, NULL, &IID_IInternetProtocolInfo, (void**)&ret);
207 IClassFactory_Release(cf);
209 return ret;
212 HRESULT get_protocol_handler(IUri *uri, CLSID *clsid, IClassFactory **ret)
214 name_space *ns;
215 BSTR scheme;
216 HRESULT hres;
218 *ret = NULL;
220 /* FIXME: Avoid GetSchemeName call for known schemes */
221 hres = IUri_GetSchemeName(uri, &scheme);
222 if(FAILED(hres))
223 return hres;
225 EnterCriticalSection(&session_cs);
227 ns = find_name_space(scheme);
228 if(ns) {
229 *ret = ns->cf;
230 IClassFactory_AddRef(*ret);
231 if(clsid)
232 *clsid = ns->clsid;
235 LeaveCriticalSection(&session_cs);
237 hres = *ret ? S_OK : get_protocol_cf(scheme, SysStringLen(scheme), clsid, ret);
238 SysFreeString(scheme);
239 return hres;
242 IInternetProtocol *get_mime_filter(LPCWSTR mime)
244 IClassFactory *cf = NULL;
245 IInternetProtocol *ret;
246 mime_filter *iter;
247 HKEY hlist, hfilter;
248 WCHAR clsidw[64];
249 CLSID clsid;
250 DWORD res, type, size;
251 HRESULT hres;
253 EnterCriticalSection(&session_cs);
255 LIST_FOR_EACH_ENTRY(iter, &mime_filter_list, mime_filter, entry) {
256 if(!wcscmp(iter->mime, mime)) {
257 cf = iter->cf;
258 break;
262 LeaveCriticalSection(&session_cs);
264 if(cf) {
265 hres = IClassFactory_CreateInstance(cf, NULL, &IID_IInternetProtocol, (void**)&ret);
266 if(FAILED(hres)) {
267 WARN("CreateInstance failed: %08lx\n", hres);
268 return NULL;
271 return ret;
274 res = RegOpenKeyW(HKEY_CLASSES_ROOT, L"Protocols\\Filter", &hlist);
275 if(res != ERROR_SUCCESS) {
276 TRACE("Could not open MIME filters key\n");
277 return NULL;
280 res = RegOpenKeyW(hlist, mime, &hfilter);
281 CloseHandle(hlist);
282 if(res != ERROR_SUCCESS)
283 return NULL;
285 size = sizeof(clsidw);
286 res = RegQueryValueExW(hfilter, L"CLSID", NULL, &type, (BYTE*)clsidw, &size);
287 CloseHandle(hfilter);
288 if(res!=ERROR_SUCCESS || type!=REG_SZ) {
289 WARN("Could not get filter CLSID for %s\n", debugstr_w(mime));
290 return NULL;
293 hres = CLSIDFromString(clsidw, &clsid);
294 if(FAILED(hres)) {
295 WARN("CLSIDFromString failed for %s (%lx)\n", debugstr_w(mime), hres);
296 return NULL;
299 hres = CoCreateInstance(&clsid, NULL, CLSCTX_INPROC_SERVER, &IID_IInternetProtocol, (void**)&ret);
300 if(FAILED(hres)) {
301 WARN("CoCreateInstance failed: %08lx\n", hres);
302 return NULL;
305 return ret;
308 static HRESULT WINAPI InternetSession_QueryInterface(IInternetSession *iface,
309 REFIID riid, void **ppv)
311 TRACE("(%s %p)\n", debugstr_guid(riid), ppv);
313 if(IsEqualGUID(&IID_IUnknown, riid) || IsEqualGUID(&IID_IInternetSession, riid)) {
314 *ppv = iface;
315 IInternetSession_AddRef(iface);
316 return S_OK;
319 *ppv = NULL;
320 return E_NOINTERFACE;
323 static ULONG WINAPI InternetSession_AddRef(IInternetSession *iface)
325 TRACE("()\n");
326 URLMON_LockModule();
327 return 2;
330 static ULONG WINAPI InternetSession_Release(IInternetSession *iface)
332 TRACE("()\n");
333 URLMON_UnlockModule();
334 return 1;
337 static HRESULT WINAPI InternetSession_RegisterNameSpace(IInternetSession *iface,
338 IClassFactory *pCF, REFCLSID rclsid, LPCWSTR pwzProtocol, ULONG cPatterns,
339 const LPCWSTR *ppwzPatterns, DWORD dwReserved)
341 TRACE("(%p %s %s %ld %p %ld)\n", pCF, debugstr_guid(rclsid), debugstr_w(pwzProtocol),
342 cPatterns, ppwzPatterns, dwReserved);
344 if(cPatterns || ppwzPatterns)
345 FIXME("patterns not supported\n");
346 if(dwReserved)
347 WARN("dwReserved = %ld\n", dwReserved);
349 if(!pCF || !pwzProtocol)
350 return E_INVALIDARG;
352 return register_namespace(pCF, rclsid, pwzProtocol, FALSE);
355 static HRESULT WINAPI InternetSession_UnregisterNameSpace(IInternetSession *iface,
356 IClassFactory *pCF, LPCWSTR pszProtocol)
358 TRACE("(%p %s)\n", pCF, debugstr_w(pszProtocol));
360 if(!pCF || !pszProtocol)
361 return E_INVALIDARG;
363 return unregister_namespace(pCF, pszProtocol);
366 static HRESULT WINAPI InternetSession_RegisterMimeFilter(IInternetSession *iface,
367 IClassFactory *pCF, REFCLSID rclsid, LPCWSTR pwzType)
369 mime_filter *filter;
371 TRACE("(%p %s %s)\n", pCF, debugstr_guid(rclsid), debugstr_w(pwzType));
373 filter = malloc(sizeof(mime_filter));
375 IClassFactory_AddRef(pCF);
376 filter->cf = pCF;
377 filter->clsid = *rclsid;
378 filter->mime = wcsdup(pwzType);
380 EnterCriticalSection(&session_cs);
382 list_add_head(&mime_filter_list, &filter->entry);
384 LeaveCriticalSection(&session_cs);
386 return S_OK;
389 static HRESULT WINAPI InternetSession_UnregisterMimeFilter(IInternetSession *iface,
390 IClassFactory *pCF, LPCWSTR pwzType)
392 mime_filter *iter;
394 TRACE("(%p %s)\n", pCF, debugstr_w(pwzType));
396 EnterCriticalSection(&session_cs);
398 LIST_FOR_EACH_ENTRY(iter, &mime_filter_list, mime_filter, entry) {
399 if(iter->cf == pCF && !wcscmp(iter->mime, pwzType)) {
400 list_remove(&iter->entry);
402 LeaveCriticalSection(&session_cs);
404 IClassFactory_Release(iter->cf);
405 free(iter->mime);
406 free(iter);
407 return S_OK;
411 LeaveCriticalSection(&session_cs);
412 return S_OK;
415 static HRESULT WINAPI InternetSession_CreateBinding(IInternetSession *iface,
416 LPBC pBC, LPCWSTR szUrl, IUnknown *pUnkOuter, IUnknown **ppUnk,
417 IInternetProtocol **ppOInetProt, DWORD dwOption)
419 BindProtocol *protocol;
420 HRESULT hres;
422 TRACE("(%p %s %p %p %p %08lx)\n", pBC, debugstr_w(szUrl), pUnkOuter, ppUnk,
423 ppOInetProt, dwOption);
425 if(pBC || pUnkOuter || ppUnk || dwOption)
426 FIXME("Unsupported arguments\n");
428 hres = create_binding_protocol(&protocol);
429 if(FAILED(hres))
430 return hres;
432 *ppOInetProt = (IInternetProtocol*)&protocol->IInternetProtocolEx_iface;
433 return S_OK;
436 static HRESULT WINAPI InternetSession_SetSessionOption(IInternetSession *iface,
437 DWORD dwOption, LPVOID pBuffer, DWORD dwBufferLength, DWORD dwReserved)
439 FIXME("(%08lx %p %ld %ld)\n", dwOption, pBuffer, dwBufferLength, dwReserved);
440 return E_NOTIMPL;
443 static const IInternetSessionVtbl InternetSessionVtbl = {
444 InternetSession_QueryInterface,
445 InternetSession_AddRef,
446 InternetSession_Release,
447 InternetSession_RegisterNameSpace,
448 InternetSession_UnregisterNameSpace,
449 InternetSession_RegisterMimeFilter,
450 InternetSession_UnregisterMimeFilter,
451 InternetSession_CreateBinding,
452 InternetSession_SetSessionOption
455 static IInternetSession InternetSession = { &InternetSessionVtbl };
457 /***********************************************************************
458 * CoInternetGetSession (URLMON.@)
460 * Create a new internet session and return an IInternetSession interface
461 * representing it.
463 * PARAMS
464 * dwSessionMode [I] Mode for the internet session
465 * ppIInternetSession [O] Destination for creates IInternetSession object
466 * dwReserved [I] Reserved, must be 0.
468 * RETURNS
469 * Success: S_OK. ppIInternetSession contains the IInternetSession interface.
470 * Failure: E_INVALIDARG, if any argument is invalid, or
471 * E_OUTOFMEMORY if memory allocation fails.
473 HRESULT WINAPI CoInternetGetSession(DWORD dwSessionMode, IInternetSession **ppIInternetSession,
474 DWORD dwReserved)
476 TRACE("(%ld %p %ld)\n", dwSessionMode, ppIInternetSession, dwReserved);
478 if(dwSessionMode)
479 ERR("dwSessionMode=%ld\n", dwSessionMode);
480 if(dwReserved)
481 ERR("dwReserved=%ld\n", dwReserved);
483 IInternetSession_AddRef(&InternetSession);
484 *ppIInternetSession = &InternetSession;
485 return S_OK;
488 /**************************************************************************
489 * UrlMkGetSessionOption (URLMON.@)
491 static BOOL get_url_encoding(HKEY root, DWORD *encoding)
493 DWORD size = sizeof(DWORD), res, type;
494 HKEY hkey;
496 res = RegOpenKeyW(root, L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Internet Settings", &hkey);
497 if(res != ERROR_SUCCESS)
498 return FALSE;
500 res = RegQueryValueExW(hkey, L"UrlEncoding", NULL, &type, (BYTE*)encoding, &size);
501 RegCloseKey(hkey);
503 return res == ERROR_SUCCESS;
506 static LPWSTR user_agent;
507 static BOOL user_agent_set;
509 static size_t obtain_user_agent(unsigned int version, WCHAR *ret, size_t size)
511 BOOL is_wow, quirks = FALSE, use_current = FALSE;
512 OSVERSIONINFOW info = {sizeof(info)};
513 const WCHAR *os_type, *is_nt;
514 DWORD res;
515 size_t len = 0;
516 HKEY key;
518 if(version & UAS_EXACTLEGACY) {
519 version &= ~UAS_EXACTLEGACY;
520 if(version == 7)
521 quirks = TRUE;
522 else {
523 use_current = TRUE;
524 version = 7;
528 if(version > 11) {
529 FIXME("Unsupported version %u\n", version);
530 version = 11;
533 if(version < 7 || use_current) {
534 EnterCriticalSection(&session_cs);
535 if(user_agent) {
536 len = wcslen(user_agent) + 1;
537 memcpy(ret, user_agent, min(size, len) * sizeof(WCHAR));
539 LeaveCriticalSection(&session_cs);
540 if(len) return len;
543 if(version < 7)
544 version = 7;
546 swprintf(ret, size, L"Mozilla/%s (", version < 9 ? L"4.0" : L"5.0");
547 len = lstrlenW(ret);
548 if(version < 11) {
549 swprintf(ret + len, size - len, L"compatible; MSIE %u.0; ", version);
550 len += wcslen(ret + len);
553 GetVersionExW(&info);
554 is_nt = info.dwPlatformId == VER_PLATFORM_WIN32_NT ? L"NT " : L"";
556 if(sizeof(void*) == 8)
557 #ifdef __x86_64__
558 os_type = L"; Win64; x64";
559 #else
560 os_type = L"; Win64";
561 #endif
562 else if(IsWow64Process(GetCurrentProcess(), &is_wow) && is_wow)
563 os_type = L"; WOW64";
564 else
565 os_type = L"";
567 swprintf(ret + len, size - len, L"Windows %s%d.%d%s", is_nt, info.dwMajorVersion,
568 info.dwMinorVersion, os_type);
569 len = lstrlenW(ret);
571 if(!quirks) {
572 wcscpy(ret + len, L"; Trident/7.0");
573 len += ARRAY_SIZE(L"; Trident/7.0") - 1;
576 if(version < 9) {
577 res = RegOpenKeyW(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\"
578 "Internet Settings\\5.0\\User Agent\\Post Platform", &key);
579 if(res == ERROR_SUCCESS) {
580 DWORD value_len, idx;
582 for(idx = 0;; idx++) {
583 ret[len++] = ';';
584 ret[len++] = ' ';
586 value_len = size - len - 2;
587 res = RegEnumValueW(key, idx, ret + len, &value_len, NULL, NULL, NULL, NULL);
588 if(res != ERROR_SUCCESS)
589 break;
591 len += value_len;
594 RegCloseKey(key);
595 if(idx) len -= 2;
598 wcscpy(ret + len, version >= 11 ? L"; rv:11.0) like Gecko" : L")");
599 len += wcslen(ret + len) + 1;
601 TRACE("Using user agent %s\n", debugstr_w(ret));
602 return len;
605 static void ensure_user_agent(void)
607 EnterCriticalSection(&session_cs);
609 if(!user_agent) {
610 WCHAR buf[1024];
611 obtain_user_agent(0, buf, ARRAY_SIZE(buf));
612 user_agent = wcsdup(buf);
615 LeaveCriticalSection(&session_cs);
618 LPWSTR get_useragent(void)
620 LPWSTR ret;
622 ensure_user_agent();
624 EnterCriticalSection(&session_cs);
625 ret = wcsdup(user_agent);
626 LeaveCriticalSection(&session_cs);
628 return ret;
631 HRESULT WINAPI UrlMkGetSessionOption(DWORD dwOption, LPVOID pBuffer, DWORD dwBufferLength,
632 DWORD* pdwBufferLength, DWORD dwReserved)
634 TRACE("(%lx, %p, %ld, %p)\n", dwOption, pBuffer, dwBufferLength, pdwBufferLength);
636 if(dwReserved)
637 WARN("dwReserved = %ld\n", dwReserved);
639 switch(dwOption) {
640 case URLMON_OPTION_USERAGENT: {
641 HRESULT hres = E_OUTOFMEMORY;
642 DWORD size;
644 if(!pdwBufferLength)
645 return E_INVALIDARG;
647 EnterCriticalSection(&session_cs);
649 ensure_user_agent();
650 if(user_agent) {
651 size = WideCharToMultiByte(CP_ACP, 0, user_agent, -1, NULL, 0, NULL, NULL);
652 *pdwBufferLength = size;
653 if(size <= dwBufferLength) {
654 if(pBuffer)
655 WideCharToMultiByte(CP_ACP, 0, user_agent, -1, pBuffer, size, NULL, NULL);
656 else
657 hres = E_INVALIDARG;
661 LeaveCriticalSection(&session_cs);
663 /* Tests prove that we have to return E_OUTOFMEMORY on success. */
664 return hres;
666 case URLMON_OPTION_URL_ENCODING: {
667 DWORD encoding = 0;
669 if(!pBuffer || dwBufferLength < sizeof(DWORD) || !pdwBufferLength)
670 return E_INVALIDARG;
672 if(!get_url_encoding(HKEY_CURRENT_USER, &encoding))
673 get_url_encoding(HKEY_LOCAL_MACHINE, &encoding);
675 *pdwBufferLength = sizeof(DWORD);
676 *(DWORD*)pBuffer = encoding ? URL_ENCODING_DISABLE_UTF8 : URL_ENCODING_ENABLE_UTF8;
677 return S_OK;
679 default:
680 FIXME("unsupported option %lx\n", dwOption);
683 return E_INVALIDARG;
686 /**************************************************************************
687 * UrlMkSetSessionOption (URLMON.@)
689 HRESULT WINAPI UrlMkSetSessionOption(DWORD dwOption, LPVOID pBuffer, DWORD dwBufferLength,
690 DWORD Reserved)
692 TRACE("(%lx %p %lx)\n", dwOption, pBuffer, dwBufferLength);
694 switch(dwOption) {
695 case URLMON_OPTION_USERAGENT: {
696 LPWSTR new_user_agent;
697 char *buf = pBuffer;
698 DWORD len, size;
700 if(!pBuffer || !dwBufferLength)
701 return E_INVALIDARG;
703 for(len=0; len<dwBufferLength && buf[len]; len++);
705 TRACE("Setting user agent %s\n", debugstr_an(buf, len));
707 size = MultiByteToWideChar(CP_ACP, 0, buf, len, NULL, 0);
708 new_user_agent = malloc((size + 1) * sizeof(WCHAR));
709 if(!new_user_agent)
710 return E_OUTOFMEMORY;
711 MultiByteToWideChar(CP_ACP, 0, buf, len, new_user_agent, size);
712 new_user_agent[size] = 0;
714 EnterCriticalSection(&session_cs);
716 free(user_agent);
717 user_agent = new_user_agent;
718 user_agent_set = TRUE;
719 update_user_agent(user_agent);
721 LeaveCriticalSection(&session_cs);
722 break;
724 default:
725 FIXME("Unknown option %lx\n", dwOption);
726 return E_INVALIDARG;
729 return S_OK;
732 /**************************************************************************
733 * ObtainUserAgentString (URLMON.@)
735 HRESULT WINAPI ObtainUserAgentString(DWORD option, char *ret, DWORD *ret_size)
737 DWORD size, len;
738 WCHAR buf[1024];
739 HRESULT hres = S_OK;
741 TRACE("(%ld %p %p)\n", option, ret, ret_size);
743 if(!ret || !ret_size)
744 return E_INVALIDARG;
746 len = obtain_user_agent(option, buf, ARRAY_SIZE(buf));
747 size = WideCharToMultiByte(CP_ACP, 0, buf, len, NULL, 0, NULL, NULL);
748 if(size <= *ret_size)
749 WideCharToMultiByte(CP_ACP, 0, buf, len, ret, *ret_size+1, NULL, NULL);
750 else
751 hres = E_OUTOFMEMORY;
753 *ret_size = size;
754 return hres;
757 /***********************************************************************
758 * MapBrowserEmulationModeToUserAgent (URLMON.445)
759 * Undocumented, added in IE8
761 HRESULT WINAPI MapBrowserEmulationModeToUserAgent(const void *arg, WCHAR **ret)
763 DWORD size, version;
764 const WCHAR *ua;
765 WCHAR buf[1024];
767 TRACE("%p %p: semi-stub\n", arg, ret);
769 if(user_agent_set) {
770 /* Native ignores first arg if custom user agent has been set, doesn't crash even if NULL */
771 size = (wcslen(user_agent) + 1) * sizeof(WCHAR);
772 ua = user_agent;
773 }else {
774 *ret = NULL;
776 /* First arg seems to be a pointer to a structure of unknown size, and crashes
777 if it's too small (or filled with arbitrary values from the stack). For our
778 purposes, we only check first field which seems to be the requested version. */
779 version = *(DWORD*)arg;
780 if(version == 5)
781 version = 7;
782 if(version < 7 || version > 11)
783 return E_FAIL;
785 size = obtain_user_agent(version, buf, ARRAY_SIZE(buf)) * sizeof(WCHAR);
786 ua = buf;
789 if(!(*ret = CoTaskMemAlloc(size)))
790 return E_OUTOFMEMORY;
791 memcpy(*ret, ua, size);
792 return S_OK;
795 void free_session(void)
797 name_space *ns_iter, *ns_last;
798 mime_filter *mf_iter, *mf_last;
800 LIST_FOR_EACH_ENTRY_SAFE(ns_iter, ns_last, &name_space_list, name_space, entry) {
801 if(!ns_iter->urlmon)
802 IClassFactory_Release(ns_iter->cf);
803 free(ns_iter->protocol);
804 free(ns_iter);
807 LIST_FOR_EACH_ENTRY_SAFE(mf_iter, mf_last, &mime_filter_list, mime_filter, entry) {
808 IClassFactory_Release(mf_iter->cf);
809 free(mf_iter->mime);
810 free(mf_iter);
813 free(user_agent);