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