/* * 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); #define DEFINE_THIS(cls,ifc,iface) ((cls*)((BYTE*)(iface)-offsetof(cls,lp ## ifc ## Vtbl))) typedef struct { const IUnknownVtbl *lpIUnknownVtbl; const IAuthenticateVtbl *lpIAuthenticateVtbl; const IHttpNegotiateVtbl *lpIHttpNegotiateVtbl; const IExtensionServicesVtbl *lpIExtensionServicesVtbl; LONG ref; IUnknown *outer; HWND hwnd; LPWSTR username; LPWSTR password; LPWSTR headers; } ExtensionService; #define EXTSERVUNK(x) ((IUnknown*)&(x)->lpIUnknownVtbl) #define AUTHENTICATE(x) (&(x)->lpIAuthenticateVtbl) #define HTTPNEGOTIATE(x) (&(x)->lpIHttpNegotiateVtbl) #define EXTENSIONSERVICES(x) (&(x)->lpIExtensionServicesVtbl) #define EXTSERVUNK_THIS(iface) DEFINE_THIS(ExtensionService, IUnknown, iface) static HRESULT WINAPI ExtServUnk_QueryInterface(IUnknown *iface, REFIID riid, void **ppv) { ExtensionService *This = EXTSERVUNK_THIS(iface); *ppv = NULL; if(IsEqualGUID(&IID_IUnknown, riid)) { TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv); *ppv = EXTSERVUNK(This); }else if(IsEqualGUID(&IID_IAuthenticate, riid)) { TRACE("(%p)->(IID_IAuthenticate %p)\n", This, ppv); *ppv = AUTHENTICATE(This); }else if(IsEqualGUID(&IID_IHttpNegotiate, riid)) { TRACE("(%p)->(IID_IHttpNegotiate %p)\n", This, ppv); *ppv = HTTPNEGOTIATE(This); }else if(IsEqualGUID(&IID_IExtensionServices, riid)) { TRACE("(%p)->(IID_IExtensionServices %p)\n", This, ppv); *ppv = EXTENSIONSERVICES(This); } 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 = EXTSERVUNK_THIS(iface); LONG ref = InterlockedIncrement(&This->ref); TRACE("(%p) ref=%d\n", This, ref); return ref; } static ULONG WINAPI ExtServUnk_Release(IUnknown *iface) { ExtensionService *This = EXTSERVUNK_THIS(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; } #undef EXTSERVUNK_THIS static const IUnknownVtbl ExtServUnkVtbl = { ExtServUnk_QueryInterface, ExtServUnk_AddRef, ExtServUnk_Release }; #define AUTHENTICATE_THIS(iface) DEFINE_THIS(ExtensionService, IAuthenticate, iface) static HRESULT WINAPI Authenticate_QueryInterface(IAuthenticate *iface, REFIID riid, void **ppv) { ExtensionService *This = AUTHENTICATE_THIS(iface); return IUnknown_QueryInterface(This->outer, riid, ppv); } static ULONG WINAPI Authenticate_AddRef(IAuthenticate *iface) { ExtensionService *This = AUTHENTICATE_THIS(iface); return IUnknown_AddRef(This->outer); } static ULONG WINAPI Authenticate_Release(IAuthenticate *iface) { ExtensionService *This = AUTHENTICATE_THIS(iface); return IUnknown_Release(This->outer); } static HRESULT WINAPI Authenticate_Authenticate(IAuthenticate *iface, HWND *phwnd, LPWSTR *pszUsername, LPWSTR *pszPassword) { ExtensionService *This = AUTHENTICATE_THIS(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; } #undef AUTHENTICATE_THIS static const IAuthenticateVtbl AuthenticateVtbl = { Authenticate_QueryInterface, Authenticate_AddRef, Authenticate_Release, Authenticate_Authenticate }; #define HTTPNEGOTIATE_THIS(iface) DEFINE_THIS(ExtensionService, IHttpNegotiate, iface) static HRESULT WINAPI HttpNegotiate_QueryInterface(IHttpNegotiate *iface, REFIID riid, void **ppv) { ExtensionService *This = HTTPNEGOTIATE_THIS(iface); return IUnknown_QueryInterface(This->outer, riid, ppv); } static ULONG WINAPI HttpNegotiate_AddRef(IHttpNegotiate *iface) { ExtensionService *This = HTTPNEGOTIATE_THIS(iface); return IUnknown_AddRef(This->outer); } static ULONG WINAPI HttpNegotiate_Release(IHttpNegotiate *iface) { ExtensionService *This = HTTPNEGOTIATE_THIS(iface); return IUnknown_Release(This->outer); } static HRESULT WINAPI HttpNegotiate_BeginningTransaction(IHttpNegotiate *iface, LPCWSTR szURL, LPCWSTR szHeaders, DWORD dwReserved, LPWSTR *pszAdditionalHeaders) { ExtensionService *This = HTTPNEGOTIATE_THIS(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 = HTTPNEGOTIATE_THIS(iface); TRACE("(%p)->(%d %s %s %p)\n", This, dwResponseCode, debugstr_w(szResponseHeaders), debugstr_w(szRequestHeaders), pszAdditionalRequestHeaders); *pszAdditionalRequestHeaders = NULL; return S_OK; } #undef HTTPNEGOTIATE_THIS static const IHttpNegotiateVtbl HttpNegotiateVtbl = { HttpNegotiate_QueryInterface, HttpNegotiate_AddRef, HttpNegotiate_Release, HttpNegotiate_BeginningTransaction, HttpNegotiate_OnResponse }; #define EXTENSIONSERVICES_THIS(iface) DEFINE_THIS(ExtensionService, IExtensionServices, iface) static HRESULT WINAPI ExtServ_QueryInterface(IExtensionServices *iface, REFIID riid, void **ppv) { ExtensionService *This = EXTENSIONSERVICES_THIS(iface); return IUnknown_QueryInterface(This->outer, riid, ppv); } static ULONG WINAPI ExtServ_AddRef(IExtensionServices *iface) { ExtensionService *This = EXTENSIONSERVICES_THIS(iface); return IUnknown_AddRef(This->outer); } static ULONG WINAPI ExtServ_Release(IExtensionServices *iface) { ExtensionService *This = EXTENSIONSERVICES_THIS(iface); return IUnknown_Release(This->outer); } static HRESULT ExtServ_ImplSetAdditionalHeaders(ExtensionService* This, LPCWSTR pwzAdditionalHeaders) { int len = 0; 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 = EXTENSIONSERVICES_THIS(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 = EXTENSIONSERVICES_THIS(iface); TRACE("(%p)->(%p %s %s)\n", This, phwnd, debugstr_w(pwzUsername), debugstr_w(pwzPassword)); return ExtServ_ImplSetAuthenticateData(This, phwnd, pwzUsername, pwzPassword); } #undef EXTENSIONSERVICES_THIS 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->lpIUnknownVtbl = &ExtServUnkVtbl; ret->lpIAuthenticateVtbl = &AuthenticateVtbl; ret->lpIHttpNegotiateVtbl = &HttpNegotiateVtbl; ret->lpIExtensionServicesVtbl= &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 = EXTSERVUNK(ret); hres = IUnknown_QueryInterface(EXTSERVUNK(ret), riid, ppv); IUnknown_Release(EXTSERVUNK(ret)); }else if(IsEqualGUID(&IID_IUnknown, riid)) { ret->outer = punkOuter; *ppv = EXTSERVUNK(ret); }else { IUnknown_Release(EXTSERVUNK(ret)); hres = E_INVALIDARG; } return hres; }