| /* | |
| * Copyright 2007 Jacek Caban for CodeWeavers | |
| * | |
| * This library is free software; you can redistribute it and/or | |
| * modify it under the terms of the GNU Lesser General Public | |
| * License as published by the Free Software Foundation; either | |
| * version 2.1 of the License, or (at your option) any later version. | |
| * | |
| * This library is distributed in the hope that it will be useful, | |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
| * Lesser General Public License for more details. | |
| * | |
| * You should have received a copy of the GNU Lesser General Public | |
| * License along with this library; if not, write to the Free Software | |
| * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA | |
| */ | |
| #include "hlink_private.h" | |
| #include "wine/debug.h" | |
| #include "wine/unicode.h" | |
| WINE_DEFAULT_DEBUG_CHANNEL(hlink); | |
| typedef struct { | |
| IUnknown IUnknown_inner; | |
| IAuthenticate IAuthenticate_iface; | |
| IHttpNegotiate IHttpNegotiate_iface; | |
| IExtensionServices IExtensionServices_iface; | |
| IUnknown *outer_unk; | |
| LONG ref; | |
| HWND hwnd; | |
| LPWSTR username; | |
| LPWSTR password; | |
| LPWSTR headers; | |
| } ExtensionService; | |
| static inline ExtensionService *impl_from_IUnknown(IUnknown *iface) | |
| { | |
| return CONTAINING_RECORD(iface, ExtensionService, IUnknown_inner); | |
| } | |
| static HRESULT WINAPI ExtServUnk_QueryInterface(IUnknown *iface, REFIID riid, void **ppv) | |
| { | |
| ExtensionService *This = impl_from_IUnknown(iface); | |
| *ppv = NULL; | |
| if(IsEqualGUID(&IID_IUnknown, riid)) { | |
| TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv); | |
| *ppv = &This->IUnknown_inner; | |
| }else if(IsEqualGUID(&IID_IAuthenticate, riid)) { | |
| TRACE("(%p)->(IID_IAuthenticate %p)\n", This, ppv); | |
| *ppv = &This->IAuthenticate_iface; | |
| }else if(IsEqualGUID(&IID_IHttpNegotiate, riid)) { | |
| TRACE("(%p)->(IID_IHttpNegotiate %p)\n", This, ppv); | |
| *ppv = &This->IHttpNegotiate_iface; | |
| }else if(IsEqualGUID(&IID_IExtensionServices, riid)) { | |
| TRACE("(%p)->(IID_IExtensionServices %p)\n", This, ppv); | |
| *ppv = &This->IExtensionServices_iface; | |
| } | |
| if(*ppv) { | |
| IUnknown_AddRef((IUnknown*)*ppv); | |
| return S_OK; | |
| } | |
| FIXME("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv); | |
| return E_NOINTERFACE; | |
| } | |
| static ULONG WINAPI ExtServUnk_AddRef(IUnknown *iface) | |
| { | |
| ExtensionService *This = impl_from_IUnknown(iface); | |
| LONG ref = InterlockedIncrement(&This->ref); | |
| TRACE("(%p) ref=%d\n", This, ref); | |
| return ref; | |
| } | |
| static ULONG WINAPI ExtServUnk_Release(IUnknown *iface) | |
| { | |
| ExtensionService *This = impl_from_IUnknown(iface); | |
| LONG ref = InterlockedDecrement(&This->ref); | |
| TRACE("(%p) ref=%d\n", This, ref); | |
| if(!ref) { | |
| heap_free(This->username); | |
| heap_free(This->password); | |
| heap_free(This->headers); | |
| heap_free(This); | |
| } | |
| return ref; | |
| } | |
| static const IUnknownVtbl ExtServUnkVtbl = { | |
| ExtServUnk_QueryInterface, | |
| ExtServUnk_AddRef, | |
| ExtServUnk_Release | |
| }; | |
| static inline ExtensionService *impl_from_IAuthenticate(IAuthenticate *iface) | |
| { | |
| return CONTAINING_RECORD(iface, ExtensionService, IAuthenticate_iface); | |
| } | |
| static HRESULT WINAPI Authenticate_QueryInterface(IAuthenticate *iface, REFIID riid, void **ppv) | |
| { | |
| ExtensionService *This = impl_from_IAuthenticate(iface); | |
| return IUnknown_QueryInterface(This->outer_unk, riid, ppv); | |
| } | |
| static ULONG WINAPI Authenticate_AddRef(IAuthenticate *iface) | |
| { | |
| ExtensionService *This = impl_from_IAuthenticate(iface); | |
| return IUnknown_AddRef(This->outer_unk); | |
| } | |
| static ULONG WINAPI Authenticate_Release(IAuthenticate *iface) | |
| { | |
| ExtensionService *This = impl_from_IAuthenticate(iface); | |
| return IUnknown_Release(This->outer_unk); | |
| } | |
| static HRESULT WINAPI Authenticate_Authenticate(IAuthenticate *iface, | |
| HWND *phwnd, LPWSTR *pszUsername, LPWSTR *pszPassword) | |
| { | |
| ExtensionService *This = impl_from_IAuthenticate(iface); | |
| TRACE("(%p)->(%p %p %p)\n", This, phwnd, pszUsername, pszPassword); | |
| if(!phwnd || !pszUsername || !pszPassword) | |
| return E_INVALIDARG; | |
| *phwnd = This->hwnd; | |
| *pszUsername = hlink_co_strdupW(This->username); | |
| *pszPassword = hlink_co_strdupW(This->password); | |
| return S_OK; | |
| } | |
| static const IAuthenticateVtbl AuthenticateVtbl = { | |
| Authenticate_QueryInterface, | |
| Authenticate_AddRef, | |
| Authenticate_Release, | |
| Authenticate_Authenticate | |
| }; | |
| static inline ExtensionService *impl_from_IHttpNegotiate(IHttpNegotiate *iface) | |
| { | |
| return CONTAINING_RECORD(iface, ExtensionService, IHttpNegotiate_iface); | |
| } | |
| static HRESULT WINAPI HttpNegotiate_QueryInterface(IHttpNegotiate *iface, REFIID riid, void **ppv) | |
| { | |
| ExtensionService *This = impl_from_IHttpNegotiate(iface); | |
| return IUnknown_QueryInterface(This->outer_unk, riid, ppv); | |
| } | |
| static ULONG WINAPI HttpNegotiate_AddRef(IHttpNegotiate *iface) | |
| { | |
| ExtensionService *This = impl_from_IHttpNegotiate(iface); | |
| return IUnknown_AddRef(This->outer_unk); | |
| } | |
| static ULONG WINAPI HttpNegotiate_Release(IHttpNegotiate *iface) | |
| { | |
| ExtensionService *This = impl_from_IHttpNegotiate(iface); | |
| return IUnknown_Release(This->outer_unk); | |
| } | |
| static HRESULT WINAPI HttpNegotiate_BeginningTransaction(IHttpNegotiate *iface, | |
| LPCWSTR szURL, LPCWSTR szHeaders, DWORD dwReserved, LPWSTR *pszAdditionalHeaders) | |
| { | |
| ExtensionService *This = impl_from_IHttpNegotiate(iface); | |
| TRACE("(%p)->(%s %s %x %p)\n", This, debugstr_w(szURL), debugstr_w(szHeaders), dwReserved, | |
| pszAdditionalHeaders); | |
| if(!pszAdditionalHeaders) | |
| return E_INVALIDARG; | |
| *pszAdditionalHeaders = hlink_co_strdupW(This->headers); | |
| return S_OK; | |
| } | |
| static HRESULT WINAPI HttpNegotiate_OnResponse(IHttpNegotiate *iface, DWORD dwResponseCode, | |
| LPCWSTR szResponseHeaders, LPCWSTR szRequestHeaders, LPWSTR *pszAdditionalRequestHeaders) | |
| { | |
| ExtensionService *This = impl_from_IHttpNegotiate(iface); | |
| TRACE("(%p)->(%d %s %s %p)\n", This, dwResponseCode, debugstr_w(szResponseHeaders), | |
| debugstr_w(szRequestHeaders), pszAdditionalRequestHeaders); | |
| *pszAdditionalRequestHeaders = NULL; | |
| return S_OK; | |
| } | |
| static const IHttpNegotiateVtbl HttpNegotiateVtbl = { | |
| HttpNegotiate_QueryInterface, | |
| HttpNegotiate_AddRef, | |
| HttpNegotiate_Release, | |
| HttpNegotiate_BeginningTransaction, | |
| HttpNegotiate_OnResponse | |
| }; | |
| static inline ExtensionService *impl_from_IExtensionServices(IExtensionServices *iface) | |
| { | |
| return CONTAINING_RECORD(iface, ExtensionService, IExtensionServices_iface); | |
| } | |
| static HRESULT WINAPI ExtServ_QueryInterface(IExtensionServices *iface, REFIID riid, void **ppv) | |
| { | |
| ExtensionService *This = impl_from_IExtensionServices(iface); | |
| return IUnknown_QueryInterface(This->outer_unk, riid, ppv); | |
| } | |
| static ULONG WINAPI ExtServ_AddRef(IExtensionServices *iface) | |
| { | |
| ExtensionService *This = impl_from_IExtensionServices(iface); | |
| return IUnknown_AddRef(This->outer_unk); | |
| } | |
| static ULONG WINAPI ExtServ_Release(IExtensionServices *iface) | |
| { | |
| ExtensionService *This = impl_from_IExtensionServices(iface); | |
| return IUnknown_Release(This->outer_unk); | |
| } | |
| static HRESULT ExtServ_ImplSetAdditionalHeaders(ExtensionService* This, LPCWSTR pwzAdditionalHeaders) | |
| { | |
| int len; | |
| heap_free(This->headers); | |
| This->headers = NULL; | |
| if (!pwzAdditionalHeaders) | |
| return S_OK; | |
| len = strlenW(pwzAdditionalHeaders); | |
| if(len && pwzAdditionalHeaders[len-1] != '\n' && pwzAdditionalHeaders[len-1] != '\r') { | |
| static const WCHAR endlW[] = {'\r','\n',0}; | |
| This->headers = heap_alloc(len*sizeof(WCHAR) + sizeof(endlW)); | |
| memcpy(This->headers, pwzAdditionalHeaders, len*sizeof(WCHAR)); | |
| memcpy(This->headers+len, endlW, sizeof(endlW)); | |
| }else { | |
| This->headers = hlink_strdupW(pwzAdditionalHeaders); | |
| } | |
| return S_OK; | |
| } | |
| static HRESULT WINAPI ExtServ_SetAdditionalHeaders(IExtensionServices* iface, LPCWSTR pwzAdditionalHeaders) | |
| { | |
| ExtensionService *This = impl_from_IExtensionServices(iface); | |
| TRACE("(%p)->(%s)\n", This, debugstr_w(pwzAdditionalHeaders)); | |
| return ExtServ_ImplSetAdditionalHeaders(This,pwzAdditionalHeaders); | |
| } | |
| static HRESULT ExtServ_ImplSetAuthenticateData(ExtensionService* This, HWND phwnd, LPCWSTR pwzUsername, LPCWSTR pwzPassword) | |
| { | |
| heap_free(This->username); | |
| heap_free(This->password); | |
| This->hwnd = phwnd; | |
| This->username = hlink_strdupW(pwzUsername); | |
| This->password = hlink_strdupW(pwzPassword); | |
| return S_OK; | |
| } | |
| static HRESULT WINAPI ExtServ_SetAuthenticateData(IExtensionServices* iface, HWND phwnd, LPCWSTR pwzUsername, LPCWSTR pwzPassword) | |
| { | |
| ExtensionService *This = impl_from_IExtensionServices(iface); | |
| TRACE("(%p)->(%p %s %s)\n", This, phwnd, debugstr_w(pwzUsername), debugstr_w(pwzPassword)); | |
| return ExtServ_ImplSetAuthenticateData(This, phwnd, pwzUsername, pwzPassword); | |
| } | |
| static const IExtensionServicesVtbl ExtServVtbl = { | |
| ExtServ_QueryInterface, | |
| ExtServ_AddRef, | |
| ExtServ_Release, | |
| ExtServ_SetAdditionalHeaders, | |
| ExtServ_SetAuthenticateData | |
| }; | |
| /*********************************************************************** | |
| * HlinkCreateExtensionServices (HLINK.@) | |
| */ | |
| HRESULT WINAPI HlinkCreateExtensionServices(LPCWSTR pwzAdditionalHeaders, | |
| HWND phwnd, LPCWSTR pszUsername, LPCWSTR pszPassword, | |
| IUnknown *punkOuter, REFIID riid, void** ppv) | |
| { | |
| ExtensionService *ret; | |
| HRESULT hres = S_OK; | |
| TRACE("%s %p %s %s %p %s %p\n",debugstr_w(pwzAdditionalHeaders), | |
| phwnd, debugstr_w(pszUsername), debugstr_w(pszPassword), | |
| punkOuter, debugstr_guid(riid), ppv); | |
| ret = heap_alloc(sizeof(*ret)); | |
| ret->IUnknown_inner.lpVtbl = &ExtServUnkVtbl; | |
| ret->IAuthenticate_iface.lpVtbl = &AuthenticateVtbl; | |
| ret->IHttpNegotiate_iface.lpVtbl = &HttpNegotiateVtbl; | |
| ret->IExtensionServices_iface.lpVtbl = &ExtServVtbl; | |
| ret->ref = 1; | |
| ret->headers = NULL; | |
| ret->hwnd = NULL; | |
| ret->username = NULL; | |
| ret->password = NULL; | |
| ExtServ_ImplSetAuthenticateData(ret, phwnd, pszUsername, pszPassword); | |
| ExtServ_ImplSetAdditionalHeaders(ret, pwzAdditionalHeaders); | |
| if(!punkOuter) { | |
| ret->outer_unk = &ret->IUnknown_inner; | |
| hres = IUnknown_QueryInterface(&ret->IUnknown_inner, riid, ppv); | |
| IUnknown_Release(&ret->IUnknown_inner); | |
| }else if(IsEqualGUID(&IID_IUnknown, riid)) { | |
| ret->outer_unk = punkOuter; | |
| *ppv = &ret->IUnknown_inner; | |
| }else { | |
| IUnknown_Release(&ret->IUnknown_inner); | |
| hres = E_INVALIDARG; | |
| } | |
| return hres; | |
| } |