urlmon: Includes clean up.
[wine] / dlls / 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 #include "winreg.h"
21
22 #include "wine/debug.h"
23
24 WINE_DEFAULT_DEBUG_CHANNEL(urlmon);
25
26 typedef struct name_space {
27     LPWSTR protocol;
28     IClassFactory *cf;
29     CLSID clsid;
30
31     struct name_space *next;
32 } name_space;
33
34 static name_space *name_space_list = NULL;
35
36 static name_space *find_name_space(LPCWSTR protocol)
37 {
38     name_space *iter;
39
40     for(iter = name_space_list; iter; iter = iter->next) {
41         if(!strcmpW(iter->protocol, protocol))
42             return iter;
43     }
44
45     return NULL;
46 }
47
48 static HRESULT get_protocol_cf(LPCWSTR schema, DWORD schema_len, CLSID *pclsid, IClassFactory **ret)
49 {
50     WCHAR str_clsid[64];
51     HKEY hkey = NULL;
52     DWORD res, type, size;
53     CLSID clsid;
54     LPWSTR wszKey;
55     HRESULT hres;
56
57     static const WCHAR wszProtocolsKey[] =
58         {'P','R','O','T','O','C','O','L','S','\\','H','a','n','d','l','e','r','\\'};
59     static const WCHAR wszCLSID[] = {'C','L','S','I','D',0};
60
61     wszKey = heap_alloc(sizeof(wszProtocolsKey)+(schema_len+1)*sizeof(WCHAR));
62     memcpy(wszKey, wszProtocolsKey, sizeof(wszProtocolsKey));
63     memcpy(wszKey + sizeof(wszProtocolsKey)/sizeof(WCHAR), schema, (schema_len+1)*sizeof(WCHAR));
64
65     res = RegOpenKeyW(HKEY_CLASSES_ROOT, wszKey, &hkey);
66     heap_free(wszKey);
67     if(res != ERROR_SUCCESS) {
68         TRACE("Could not open protocol handler key\n");
69         return E_FAIL;
70     }
71     
72     size = sizeof(str_clsid);
73     res = RegQueryValueExW(hkey, wszCLSID, NULL, &type, (LPBYTE)str_clsid, &size);
74     RegCloseKey(hkey);
75     if(res != ERROR_SUCCESS || type != REG_SZ) {
76         WARN("Could not get protocol CLSID res=%d\n", res);
77         return E_FAIL;
78     }
79
80     hres = CLSIDFromString(str_clsid, &clsid);
81     if(FAILED(hres)) {
82         WARN("CLSIDFromString failed: %08x\n", hres);
83         return hres;
84     }
85
86     if(pclsid)
87         *pclsid = clsid;
88
89     return CoGetClassObject(&clsid, CLSCTX_INPROC_SERVER, NULL, &IID_IClassFactory, (void**)ret);
90 }
91
92 IInternetProtocolInfo *get_protocol_info(LPCWSTR url)
93 {
94     IInternetProtocolInfo *ret = NULL;
95     IClassFactory *cf;
96     name_space *ns;
97     WCHAR schema[64];
98     DWORD schema_len;
99     HRESULT hres;
100
101     hres = CoInternetParseUrl(url, PARSE_SCHEMA, 0, schema, sizeof(schema)/sizeof(schema[0]),
102             &schema_len, 0);
103     if(FAILED(hres) || !schema_len)
104         return NULL;
105
106     ns = find_name_space(schema);
107     if(ns) {
108         hres = IClassFactory_QueryInterface(ns->cf, &IID_IInternetProtocolInfo, (void**)&ret);
109         if(SUCCEEDED(hres))
110             return ret;
111
112         hres = IClassFactory_CreateInstance(ns->cf, NULL, &IID_IInternetProtocolInfo, (void**)&ret);
113         if(SUCCEEDED(hres))
114             return ret;
115     }
116
117     hres = get_protocol_cf(schema, schema_len, NULL, &cf);
118     if(FAILED(hres))
119         return NULL;
120
121     hres = IClassFactory_QueryInterface(cf, &IID_IInternetProtocolInfo, (void**)&ret);
122     if(FAILED(hres))
123         IClassFactory_CreateInstance(cf, NULL, &IID_IInternetProtocolInfo, (void**)&ret);
124     IClassFactory_Release(cf);
125
126     return ret;
127 }
128
129 HRESULT get_protocol_handler(LPCWSTR url, CLSID *clsid, IClassFactory **ret)
130 {
131     name_space *ns;
132     WCHAR schema[64];
133     DWORD schema_len;
134     HRESULT hres;
135
136     hres = CoInternetParseUrl(url, PARSE_SCHEMA, 0, schema, sizeof(schema)/sizeof(schema[0]),
137             &schema_len, 0);
138     if(FAILED(hres) || !schema_len)
139         return schema_len ? hres : E_FAIL;
140
141     ns = find_name_space(schema);
142     if(ns) {
143         *ret = ns->cf;
144         IClassFactory_AddRef(*ret);
145         if(clsid)
146             *clsid = ns->clsid;
147         return S_OK;
148     }
149
150     return get_protocol_cf(schema, schema_len, clsid, ret);
151 }
152
153 static HRESULT WINAPI InternetSession_QueryInterface(IInternetSession *iface,
154         REFIID riid, void **ppv)
155 {
156     TRACE("(%s %p)\n", debugstr_guid(riid), ppv);
157
158     if(IsEqualGUID(&IID_IUnknown, riid) || IsEqualGUID(&IID_IInternetSession, riid)) {
159         *ppv = iface;
160         IInternetSession_AddRef(iface);
161         return S_OK;
162     }
163
164     *ppv = NULL;
165     return E_NOINTERFACE;
166 }
167
168 static ULONG WINAPI InternetSession_AddRef(IInternetSession *iface)
169 {
170     TRACE("()\n");
171     URLMON_LockModule();
172     return 2;
173 }
174
175 static ULONG WINAPI InternetSession_Release(IInternetSession *iface)
176 {
177     TRACE("()\n");
178     URLMON_UnlockModule();
179     return 1;
180 }
181
182 static HRESULT WINAPI InternetSession_RegisterNameSpace(IInternetSession *iface,
183         IClassFactory *pCF, REFCLSID rclsid, LPCWSTR pwzProtocol, ULONG cPatterns,
184         const LPCWSTR *ppwzPatterns, DWORD dwReserved)
185 {
186     name_space *new_name_space;
187     int size;
188
189     TRACE("(%p %s %s %d %p %d)\n", pCF, debugstr_guid(rclsid), debugstr_w(pwzProtocol),
190           cPatterns, ppwzPatterns, dwReserved);
191
192     if(cPatterns || ppwzPatterns)
193         FIXME("patterns not supported\n");
194     if(dwReserved)
195         WARN("dwReserved = %d\n", dwReserved);
196
197     if(!pCF || !pwzProtocol)
198         return E_INVALIDARG;
199
200     new_name_space = heap_alloc(sizeof(name_space));
201
202     size = (strlenW(pwzProtocol)+1)*sizeof(WCHAR);
203     new_name_space->protocol = heap_alloc(size);
204     memcpy(new_name_space->protocol, pwzProtocol, size);
205
206     IClassFactory_AddRef(pCF);
207     new_name_space->cf = pCF;
208     new_name_space->clsid = *rclsid;
209
210     new_name_space->next = name_space_list;
211     name_space_list = new_name_space;
212     return S_OK;
213 }
214
215 static HRESULT WINAPI InternetSession_UnregisterNameSpace(IInternetSession *iface,
216         IClassFactory *pCF, LPCWSTR pszProtocol)
217 {
218     name_space *iter, *last = NULL;
219
220     TRACE("(%p %s)\n", pCF, debugstr_w(pszProtocol));
221
222     if(!pCF || !pszProtocol)
223         return E_INVALIDARG;
224
225     for(iter = name_space_list; iter; iter = iter->next) {
226         if(iter->cf == pCF && !strcmpW(iter->protocol, pszProtocol))
227             break;
228         last = iter;
229     }
230
231     if(!iter)
232         return S_OK;
233
234     if(last)
235         last->next = iter->next;
236     else
237         name_space_list = iter->next;
238
239     IClassFactory_Release(iter->cf);
240     heap_free(iter->protocol);
241     heap_free(iter);
242
243     return S_OK;
244 }
245
246 static HRESULT WINAPI InternetSession_RegisterMimeFilter(IInternetSession *iface,
247         IClassFactory *pCF, REFCLSID rclsid, LPCWSTR pwzType)
248 {
249     FIXME("(%p %s %s)\n", pCF, debugstr_guid(rclsid), debugstr_w(pwzType));
250     return E_NOTIMPL;
251 }
252
253 static HRESULT WINAPI InternetSession_UnregisterMimeFilter(IInternetSession *iface,
254         IClassFactory *pCF, LPCWSTR pwzType)
255 {
256     FIXME("(%p %s)\n", pCF, debugstr_w(pwzType));
257     return E_NOTIMPL;
258 }
259
260 static HRESULT WINAPI InternetSession_CreateBinding(IInternetSession *iface,
261         LPBC pBC, LPCWSTR szUrl, IUnknown *pUnkOuter, IUnknown **ppUnk,
262         IInternetProtocol **ppOInetProt, DWORD dwOption)
263 {
264     TRACE("(%p %s %p %p %p %08x)\n", pBC, debugstr_w(szUrl), pUnkOuter, ppUnk,
265             ppOInetProt, dwOption);
266
267     if(pBC || pUnkOuter || ppUnk || dwOption)
268         FIXME("Unsupported arguments\n");
269
270     return create_binding_protocol(szUrl, ppOInetProt);
271 }
272
273 static HRESULT WINAPI InternetSession_SetSessionOption(IInternetSession *iface,
274         DWORD dwOption, LPVOID pBuffer, DWORD dwBufferLength, DWORD dwReserved)
275 {
276     FIXME("(%08x %p %d %d)\n", dwOption, pBuffer, dwBufferLength, dwReserved);
277     return E_NOTIMPL;
278 }
279
280 static const IInternetSessionVtbl InternetSessionVtbl = {
281     InternetSession_QueryInterface,
282     InternetSession_AddRef,
283     InternetSession_Release,
284     InternetSession_RegisterNameSpace,
285     InternetSession_UnregisterNameSpace,
286     InternetSession_RegisterMimeFilter,
287     InternetSession_UnregisterMimeFilter,
288     InternetSession_CreateBinding,
289     InternetSession_SetSessionOption
290 };
291
292 static IInternetSession InternetSession = { &InternetSessionVtbl };
293
294 /***********************************************************************
295  *           CoInternetGetSession (URLMON.@)
296  *
297  * Create a new internet session and return an IInternetSession interface
298  * representing it.
299  *
300  * PARAMS
301  *    dwSessionMode      [I] Mode for the internet session
302  *    ppIInternetSession [O] Destination for creates IInternetSession object
303  *    dwReserved         [I] Reserved, must be 0.
304  *
305  * RETURNS
306  *    Success: S_OK. ppIInternetSession contains the IInternetSession interface.
307  *    Failure: E_INVALIDARG, if any argument is invalid, or
308  *             E_OUTOFMEMORY if memory allocation fails.
309  */
310 HRESULT WINAPI CoInternetGetSession(DWORD dwSessionMode, IInternetSession **ppIInternetSession,
311         DWORD dwReserved)
312 {
313     TRACE("(%d %p %d)\n", dwSessionMode, ppIInternetSession, dwReserved);
314
315     if(dwSessionMode)
316         ERR("dwSessionMode=%d\n", dwSessionMode);
317     if(dwReserved)
318         ERR("dwReserved=%d\n", dwReserved);
319
320     IInternetSession_AddRef(&InternetSession);
321     *ppIInternetSession = &InternetSession;
322     return S_OK;
323 }
324
325 /**************************************************************************
326  *                 UrlMkGetSessionOption (URLMON.@)
327  */
328 static BOOL get_url_encoding(HKEY root, DWORD *encoding)
329 {
330     DWORD size = sizeof(DWORD), res, type;
331     HKEY hkey;
332
333     static const WCHAR wszKeyName[] = 
334         {'S','O','F','T','W','A','R','E',
335          '\\','M','i','c','r','o','s','o','f','t',
336          '\\','W','i','n','d','o','w','s',
337          '\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n',
338          '\\','I','n','t','e','r','n','e','t',' ','S','e','t','t','i','n','g','s',0};
339     static const WCHAR wszUrlEncoding[] = {'U','r','l','E','n','c','o','d','i','n','g',0};
340
341     res = RegOpenKeyW(root, wszKeyName, &hkey);
342     if(res != ERROR_SUCCESS)
343         return FALSE;
344
345     res = RegQueryValueExW(hkey, wszUrlEncoding, NULL, &type, (LPBYTE)encoding, &size);
346     RegCloseKey(hkey);
347
348     return res == ERROR_SUCCESS;
349 }
350
351 HRESULT WINAPI UrlMkGetSessionOption(DWORD dwOption, LPVOID pBuffer, DWORD dwBufferLength,
352                                      DWORD* pdwBufferLength, DWORD dwReserved)
353 {
354     TRACE("(%x, %p, %d, %p)\n", dwOption, pBuffer, dwBufferLength, pdwBufferLength);
355
356     if(dwReserved)
357         WARN("dwReserved = %d\n", dwReserved);
358
359     switch(dwOption) {
360     case URLMON_OPTION_URL_ENCODING: {
361         DWORD encoding = 0;
362
363         if(!pBuffer || dwBufferLength < sizeof(DWORD) || !pdwBufferLength)
364             return E_INVALIDARG;
365
366         if(!get_url_encoding(HKEY_CURRENT_USER, &encoding))
367             get_url_encoding(HKEY_LOCAL_MACHINE, &encoding);
368
369         *pdwBufferLength = sizeof(DWORD);
370         *(DWORD*)pBuffer = encoding ? URL_ENCODING_DISABLE_UTF8 : URL_ENCODING_ENABLE_UTF8;
371         return S_OK;
372     }
373     default:
374         FIXME("unsupported option %x\n", dwOption);
375     }
376
377     return E_INVALIDARG;
378 }