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