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