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"
22 #include "wine/debug.h"
24 WINE_DEFAULT_DEBUG_CHANNEL(urlmon
);
26 typedef struct name_space
{
32 struct name_space
*next
;
35 typedef struct mime_filter
{
40 struct mime_filter
*next
;
43 static name_space
*name_space_list
= NULL
;
44 static mime_filter
*mime_filter_list
= NULL
;
46 static CRITICAL_SECTION session_cs
;
47 static CRITICAL_SECTION_DEBUG session_cs_dbg
=
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 const WCHAR internet_settings_keyW
[] =
56 {'S','O','F','T','W','A','R','E',
57 '\\','M','i','c','r','o','s','o','f','t',
58 '\\','W','i','n','d','o','w','s',
59 '\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n',
60 '\\','I','n','t','e','r','n','e','t',' ','S','e','t','t','i','n','g','s',0};
62 static name_space
*find_name_space(LPCWSTR protocol
)
66 for(iter
= name_space_list
; iter
; iter
= iter
->next
) {
67 if(!strcmpW(iter
->protocol
, protocol
))
74 static HRESULT
get_protocol_cf(LPCWSTR schema
, DWORD schema_len
, CLSID
*pclsid
, IClassFactory
**ret
)
78 DWORD res
, type
, size
;
83 static const WCHAR wszProtocolsKey
[] =
84 {'P','R','O','T','O','C','O','L','S','\\','H','a','n','d','l','e','r','\\'};
85 static const WCHAR wszCLSID
[] = {'C','L','S','I','D',0};
87 wszKey
= heap_alloc(sizeof(wszProtocolsKey
)+(schema_len
+1)*sizeof(WCHAR
));
88 memcpy(wszKey
, wszProtocolsKey
, sizeof(wszProtocolsKey
));
89 memcpy(wszKey
+ sizeof(wszProtocolsKey
)/sizeof(WCHAR
), schema
, (schema_len
+1)*sizeof(WCHAR
));
91 res
= RegOpenKeyW(HKEY_CLASSES_ROOT
, wszKey
, &hkey
);
93 if(res
!= ERROR_SUCCESS
) {
94 TRACE("Could not open protocol handler key\n");
98 size
= sizeof(str_clsid
);
99 res
= RegQueryValueExW(hkey
, wszCLSID
, NULL
, &type
, (LPBYTE
)str_clsid
, &size
);
101 if(res
!= ERROR_SUCCESS
|| type
!= REG_SZ
) {
102 WARN("Could not get protocol CLSID res=%d\n", res
);
106 hres
= CLSIDFromString(str_clsid
, &clsid
);
108 WARN("CLSIDFromString failed: %08x\n", hres
);
118 return CoGetClassObject(&clsid
, CLSCTX_INPROC_SERVER
, NULL
, &IID_IClassFactory
, (void**)ret
);
121 static HRESULT
register_namespace(IClassFactory
*cf
, REFIID clsid
, LPCWSTR protocol
, BOOL urlmon_protocol
)
123 name_space
*new_name_space
;
125 new_name_space
= heap_alloc(sizeof(name_space
));
128 IClassFactory_AddRef(cf
);
129 new_name_space
->cf
= cf
;
130 new_name_space
->clsid
= *clsid
;
131 new_name_space
->urlmon
= urlmon_protocol
;
132 new_name_space
->protocol
= heap_strdupW(protocol
);
134 EnterCriticalSection(&session_cs
);
136 new_name_space
->next
= name_space_list
;
137 name_space_list
= new_name_space
;
139 LeaveCriticalSection(&session_cs
);
144 static HRESULT
unregister_namespace(IClassFactory
*cf
, LPCWSTR protocol
)
146 name_space
*iter
, *last
= NULL
;
148 EnterCriticalSection(&session_cs
);
150 for(iter
= name_space_list
; iter
; iter
= iter
->next
) {
151 if(iter
->cf
== cf
&& !strcmpW(iter
->protocol
, protocol
))
158 last
->next
= iter
->next
;
160 name_space_list
= iter
->next
;
163 LeaveCriticalSection(&session_cs
);
167 IClassFactory_Release(iter
->cf
);
168 heap_free(iter
->protocol
);
176 void register_urlmon_namespace(IClassFactory
*cf
, REFIID clsid
, LPCWSTR protocol
, BOOL do_register
)
179 register_namespace(cf
, clsid
, protocol
, TRUE
);
181 unregister_namespace(cf
, protocol
);
184 BOOL
is_registered_protocol(LPCWSTR url
)
190 hres
= CoInternetParseUrl(url
, PARSE_SCHEMA
, 0, schema
, sizeof(schema
)/sizeof(schema
[0]),
195 return get_protocol_cf(schema
, schema_len
, NULL
, NULL
) == S_OK
;
198 IInternetProtocolInfo
*get_protocol_info(LPCWSTR url
)
200 IInternetProtocolInfo
*ret
= NULL
;
207 hres
= CoInternetParseUrl(url
, PARSE_SCHEMA
, 0, schema
, sizeof(schema
)/sizeof(schema
[0]),
209 if(FAILED(hres
) || !schema_len
)
212 EnterCriticalSection(&session_cs
);
214 ns
= find_name_space(schema
);
215 if(ns
&& !ns
->urlmon
) {
216 hres
= IClassFactory_QueryInterface(ns
->cf
, &IID_IInternetProtocolInfo
, (void**)&ret
);
218 hres
= IClassFactory_CreateInstance(ns
->cf
, NULL
, &IID_IInternetProtocolInfo
, (void**)&ret
);
221 LeaveCriticalSection(&session_cs
);
223 if(ns
&& SUCCEEDED(hres
))
226 hres
= get_protocol_cf(schema
, schema_len
, NULL
, &cf
);
230 hres
= IClassFactory_QueryInterface(cf
, &IID_IInternetProtocolInfo
, (void**)&ret
);
232 IClassFactory_CreateInstance(cf
, NULL
, &IID_IInternetProtocolInfo
, (void**)&ret
);
233 IClassFactory_Release(cf
);
238 HRESULT
get_protocol_handler(LPCWSTR url
, CLSID
*clsid
, BOOL
*urlmon_protocol
, IClassFactory
**ret
)
247 hres
= CoInternetParseUrl(url
, PARSE_SCHEMA
, 0, schema
, sizeof(schema
)/sizeof(schema
[0]),
249 if(FAILED(hres
) || !schema_len
)
250 return schema_len
? hres
: E_FAIL
;
252 EnterCriticalSection(&session_cs
);
254 ns
= find_name_space(schema
);
257 IClassFactory_AddRef(*ret
);
261 *urlmon_protocol
= ns
->urlmon
;
264 LeaveCriticalSection(&session_cs
);
270 *urlmon_protocol
= FALSE
;
271 return get_protocol_cf(schema
, schema_len
, clsid
, ret
);
274 IInternetProtocol
*get_mime_filter(LPCWSTR mime
)
276 IClassFactory
*cf
= NULL
;
277 IInternetProtocol
*ret
;
281 EnterCriticalSection(&session_cs
);
283 for(iter
= mime_filter_list
; iter
; iter
= iter
->next
) {
284 if(!strcmpW(iter
->mime
, mime
)) {
290 LeaveCriticalSection(&session_cs
);
295 hres
= IClassFactory_CreateInstance(cf
, NULL
, &IID_IInternetProtocol
, (void**)&ret
);
297 WARN("CreateInstance failed: %08x\n", hres
);
304 static HRESULT WINAPI
InternetSession_QueryInterface(IInternetSession
*iface
,
305 REFIID riid
, void **ppv
)
307 TRACE("(%s %p)\n", debugstr_guid(riid
), ppv
);
309 if(IsEqualGUID(&IID_IUnknown
, riid
) || IsEqualGUID(&IID_IInternetSession
, riid
)) {
311 IInternetSession_AddRef(iface
);
316 return E_NOINTERFACE
;
319 static ULONG WINAPI
InternetSession_AddRef(IInternetSession
*iface
)
326 static ULONG WINAPI
InternetSession_Release(IInternetSession
*iface
)
329 URLMON_UnlockModule();
333 static HRESULT WINAPI
InternetSession_RegisterNameSpace(IInternetSession
*iface
,
334 IClassFactory
*pCF
, REFCLSID rclsid
, LPCWSTR pwzProtocol
, ULONG cPatterns
,
335 const LPCWSTR
*ppwzPatterns
, DWORD dwReserved
)
337 TRACE("(%p %s %s %d %p %d)\n", pCF
, debugstr_guid(rclsid
), debugstr_w(pwzProtocol
),
338 cPatterns
, ppwzPatterns
, dwReserved
);
340 if(cPatterns
|| ppwzPatterns
)
341 FIXME("patterns not supported\n");
343 WARN("dwReserved = %d\n", dwReserved
);
345 if(!pCF
|| !pwzProtocol
)
348 return register_namespace(pCF
, rclsid
, pwzProtocol
, FALSE
);
351 static HRESULT WINAPI
InternetSession_UnregisterNameSpace(IInternetSession
*iface
,
352 IClassFactory
*pCF
, LPCWSTR pszProtocol
)
354 TRACE("(%p %s)\n", pCF
, debugstr_w(pszProtocol
));
356 if(!pCF
|| !pszProtocol
)
359 return unregister_namespace(pCF
, pszProtocol
);
362 static HRESULT WINAPI
InternetSession_RegisterMimeFilter(IInternetSession
*iface
,
363 IClassFactory
*pCF
, REFCLSID rclsid
, LPCWSTR pwzType
)
367 TRACE("(%p %s %s)\n", pCF
, debugstr_guid(rclsid
), debugstr_w(pwzType
));
369 filter
= heap_alloc(sizeof(mime_filter
));
371 IClassFactory_AddRef(pCF
);
373 filter
->clsid
= *rclsid
;
374 filter
->mime
= heap_strdupW(pwzType
);
376 EnterCriticalSection(&session_cs
);
378 filter
->next
= mime_filter_list
;
379 mime_filter_list
= filter
;
381 LeaveCriticalSection(&session_cs
);
386 static HRESULT WINAPI
InternetSession_UnregisterMimeFilter(IInternetSession
*iface
,
387 IClassFactory
*pCF
, LPCWSTR pwzType
)
389 mime_filter
*iter
, *prev
= NULL
;
391 TRACE("(%p %s)\n", pCF
, debugstr_w(pwzType
));
393 EnterCriticalSection(&session_cs
);
395 for(iter
= mime_filter_list
; iter
; iter
= iter
->next
) {
396 if(iter
->cf
== pCF
&& !strcmpW(iter
->mime
, pwzType
))
403 prev
->next
= iter
->next
;
405 mime_filter_list
= iter
->next
;
408 LeaveCriticalSection(&session_cs
);
411 IClassFactory_Release(iter
->cf
);
412 heap_free(iter
->mime
);
419 static HRESULT WINAPI
InternetSession_CreateBinding(IInternetSession
*iface
,
420 LPBC pBC
, LPCWSTR szUrl
, IUnknown
*pUnkOuter
, IUnknown
**ppUnk
,
421 IInternetProtocol
**ppOInetProt
, DWORD dwOption
)
423 TRACE("(%p %s %p %p %p %08x)\n", pBC
, debugstr_w(szUrl
), pUnkOuter
, ppUnk
,
424 ppOInetProt
, dwOption
);
426 if(pBC
|| pUnkOuter
|| ppUnk
|| dwOption
)
427 FIXME("Unsupported arguments\n");
429 return create_binding_protocol(szUrl
, FALSE
, ppOInetProt
);
432 static HRESULT WINAPI
InternetSession_SetSessionOption(IInternetSession
*iface
,
433 DWORD dwOption
, LPVOID pBuffer
, DWORD dwBufferLength
, DWORD dwReserved
)
435 FIXME("(%08x %p %d %d)\n", dwOption
, pBuffer
, dwBufferLength
, dwReserved
);
439 static const IInternetSessionVtbl InternetSessionVtbl
= {
440 InternetSession_QueryInterface
,
441 InternetSession_AddRef
,
442 InternetSession_Release
,
443 InternetSession_RegisterNameSpace
,
444 InternetSession_UnregisterNameSpace
,
445 InternetSession_RegisterMimeFilter
,
446 InternetSession_UnregisterMimeFilter
,
447 InternetSession_CreateBinding
,
448 InternetSession_SetSessionOption
451 static IInternetSession InternetSession
= { &InternetSessionVtbl
};
453 /***********************************************************************
454 * CoInternetGetSession (URLMON.@)
456 * Create a new internet session and return an IInternetSession interface
460 * dwSessionMode [I] Mode for the internet session
461 * ppIInternetSession [O] Destination for creates IInternetSession object
462 * dwReserved [I] Reserved, must be 0.
465 * Success: S_OK. ppIInternetSession contains the IInternetSession interface.
466 * Failure: E_INVALIDARG, if any argument is invalid, or
467 * E_OUTOFMEMORY if memory allocation fails.
469 HRESULT WINAPI
CoInternetGetSession(DWORD dwSessionMode
, IInternetSession
**ppIInternetSession
,
472 TRACE("(%d %p %d)\n", dwSessionMode
, ppIInternetSession
, dwReserved
);
475 ERR("dwSessionMode=%d\n", dwSessionMode
);
477 ERR("dwReserved=%d\n", dwReserved
);
479 IInternetSession_AddRef(&InternetSession
);
480 *ppIInternetSession
= &InternetSession
;
484 /**************************************************************************
485 * UrlMkGetSessionOption (URLMON.@)
487 static BOOL
get_url_encoding(HKEY root
, DWORD
*encoding
)
489 DWORD size
= sizeof(DWORD
), res
, type
;
492 static const WCHAR wszUrlEncoding
[] = {'U','r','l','E','n','c','o','d','i','n','g',0};
494 res
= RegOpenKeyW(root
, internet_settings_keyW
, &hkey
);
495 if(res
!= ERROR_SUCCESS
)
498 res
= RegQueryValueExW(hkey
, wszUrlEncoding
, NULL
, &type
, (LPBYTE
)encoding
, &size
);
501 return res
== ERROR_SUCCESS
;
504 static LPWSTR user_agent
;
506 static void ensure_useragent(void)
508 DWORD size
= sizeof(DWORD
), res
, type
;
511 static const WCHAR user_agentW
[] = {'U','s','e','r',' ','A','g','e','n','t',0};
516 res
= RegOpenKeyW(HKEY_CURRENT_USER
, internet_settings_keyW
, &hkey
);
517 if(res
!= ERROR_SUCCESS
)
520 res
= RegQueryValueExW(hkey
, user_agentW
, NULL
, &type
, NULL
, &size
);
521 if(res
== ERROR_SUCCESS
&& type
== REG_SZ
) {
522 user_agent
= heap_alloc(size
);
523 res
= RegQueryValueExW(hkey
, user_agentW
, NULL
, &type
, (LPBYTE
)user_agent
, &size
);
524 if(res
!= ERROR_SUCCESS
) {
525 heap_free(user_agent
);
529 WARN("Could not find User Agent value: %u\n", res
);
535 LPWSTR
get_useragent(void)
541 EnterCriticalSection(&session_cs
);
542 ret
= heap_strdupW(user_agent
);
543 LeaveCriticalSection(&session_cs
);
548 HRESULT WINAPI
UrlMkGetSessionOption(DWORD dwOption
, LPVOID pBuffer
, DWORD dwBufferLength
,
549 DWORD
* pdwBufferLength
, DWORD dwReserved
)
551 TRACE("(%x, %p, %d, %p)\n", dwOption
, pBuffer
, dwBufferLength
, pdwBufferLength
);
554 WARN("dwReserved = %d\n", dwReserved
);
557 case URLMON_OPTION_USERAGENT
: {
558 HRESULT hres
= E_OUTOFMEMORY
;
564 EnterCriticalSection(&session_cs
);
568 size
= WideCharToMultiByte(CP_ACP
, 0, user_agent
, -1, NULL
, 0, NULL
, NULL
);
569 *pdwBufferLength
= size
;
570 if(size
<= dwBufferLength
) {
572 WideCharToMultiByte(CP_ACP
, 0, user_agent
, -1, pBuffer
, size
, NULL
, NULL
);
578 LeaveCriticalSection(&session_cs
);
580 /* Tests prove that we have to return E_OUTOFMEMORY on success. */
583 case URLMON_OPTION_URL_ENCODING
: {
586 if(!pBuffer
|| dwBufferLength
< sizeof(DWORD
) || !pdwBufferLength
)
589 if(!get_url_encoding(HKEY_CURRENT_USER
, &encoding
))
590 get_url_encoding(HKEY_LOCAL_MACHINE
, &encoding
);
592 *pdwBufferLength
= sizeof(DWORD
);
593 *(DWORD
*)pBuffer
= encoding
? URL_ENCODING_DISABLE_UTF8
: URL_ENCODING_ENABLE_UTF8
;
597 FIXME("unsupported option %x\n", dwOption
);
603 /**************************************************************************
604 * UrlMkSetSessionOption (URLMON.@)
606 HRESULT WINAPI
UrlMkSetSessionOption(DWORD dwOption
, LPVOID pBuffer
, DWORD dwBufferLength
,
609 TRACE("(%x %p %x)\n", dwOption
, pBuffer
, dwBufferLength
);
612 case URLMON_OPTION_USERAGENT
: {
613 LPWSTR new_user_agent
;
617 if(!pBuffer
|| !dwBufferLength
)
620 for(len
=0; len
<dwBufferLength
&& buf
[len
]; len
++);
622 TRACE("Setting user agent %s\n", debugstr_an(buf
, len
));
624 size
= MultiByteToWideChar(CP_ACP
, 0, buf
, len
, NULL
, 0);
625 new_user_agent
= heap_alloc((size
+1)*sizeof(WCHAR
));
627 return E_OUTOFMEMORY
;
628 MultiByteToWideChar(CP_ACP
, 0, buf
, len
, new_user_agent
, size
);
629 new_user_agent
[size
] = 0;
631 EnterCriticalSection(&session_cs
);
633 heap_free(user_agent
);
634 user_agent
= new_user_agent
;
636 LeaveCriticalSection(&session_cs
);
640 FIXME("Unknown option %x\n", dwOption
);
647 /**************************************************************************
648 * ObtainUserAgentString (URLMON.@)
650 HRESULT WINAPI
ObtainUserAgentString(DWORD dwOption
, LPSTR pcszUAOut
, DWORD
*cbSize
)
653 HRESULT hres
= E_FAIL
;
655 TRACE("(%d %p %p)\n", dwOption
, pcszUAOut
, cbSize
);
657 if(!pcszUAOut
|| !cbSize
)
660 EnterCriticalSection(&session_cs
);
664 size
= WideCharToMultiByte(CP_ACP
, 0, user_agent
, -1, NULL
, 0, NULL
, NULL
);
666 if(size
<= *cbSize
) {
667 WideCharToMultiByte(CP_ACP
, 0, user_agent
, -1, pcszUAOut
, *cbSize
, NULL
, NULL
);
670 hres
= E_OUTOFMEMORY
;
676 LeaveCriticalSection(&session_cs
);
680 void free_session(void)
682 heap_free(user_agent
);