1 /*
2 * Copyright 2007 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 "hlink_private.h"
20
21 #include "wine/debug.h"
22
23 WINE_DEFAULT_DEBUG_CHANNEL(hlink);
24
25 typedef struct {
26 IUnknown IUnknown_inner;
27 IAuthenticate IAuthenticate_iface;
28 IHttpNegotiate IHttpNegotiate_iface;
29 IExtensionServices IExtensionServices_iface;
30
31 IUnknown *outer_unk;
32 LONG ref;
33
34 HWND hwnd;
35 LPWSTR username;
36 LPWSTR password;
37 LPWSTR headers;
38 } ExtensionService;
39
impl_from_IUnknown(IUnknown * iface)40 static inline ExtensionService *impl_from_IUnknown(IUnknown *iface)
41 {
42 return CONTAINING_RECORD(iface, ExtensionService, IUnknown_inner);
43 }
44
ExtServUnk_QueryInterface(IUnknown * iface,REFIID riid,void ** ppv)45 static HRESULT WINAPI ExtServUnk_QueryInterface(IUnknown *iface, REFIID riid, void **ppv)
46 {
47 ExtensionService *This = impl_from_IUnknown(iface);
48
49 *ppv = NULL;
50
51 if(IsEqualGUID(&IID_IUnknown, riid)) {
52 TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
53 *ppv = &This->IUnknown_inner;
54 }else if(IsEqualGUID(&IID_IAuthenticate, riid)) {
55 TRACE("(%p)->(IID_IAuthenticate %p)\n", This, ppv);
56 *ppv = &This->IAuthenticate_iface;
57 }else if(IsEqualGUID(&IID_IHttpNegotiate, riid)) {
58 TRACE("(%p)->(IID_IHttpNegotiate %p)\n", This, ppv);
59 *ppv = &This->IHttpNegotiate_iface;
60 }else if(IsEqualGUID(&IID_IExtensionServices, riid)) {
61 TRACE("(%p)->(IID_IExtensionServices %p)\n", This, ppv);
62 *ppv = &This->IExtensionServices_iface;
63 }
64
65 if(*ppv) {
66 IUnknown_AddRef((IUnknown*)*ppv);
67 return S_OK;
68 }
69
70 FIXME("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
71 return E_NOINTERFACE;
72 }
73
ExtServUnk_AddRef(IUnknown * iface)74 static ULONG WINAPI ExtServUnk_AddRef(IUnknown *iface)
75 {
76 ExtensionService *This = impl_from_IUnknown(iface);
77 LONG ref = InterlockedIncrement(&This->ref);
78
79 TRACE("(%p) ref=%d\n", This, ref);
80
81 return ref;
82 }
83
ExtServUnk_Release(IUnknown * iface)84 static ULONG WINAPI ExtServUnk_Release(IUnknown *iface)
85 {
86 ExtensionService *This = impl_from_IUnknown(iface);
87 LONG ref = InterlockedDecrement(&This->ref);
88
89 TRACE("(%p) ref=%d\n", This, ref);
90
91 if(!ref) {
92 heap_free(This->username);
93 heap_free(This->password);
94 heap_free(This->headers);
95 heap_free(This);
96 }
97
98 return ref;
99 }
100
101 static const IUnknownVtbl ExtServUnkVtbl = {
102 ExtServUnk_QueryInterface,
103 ExtServUnk_AddRef,
104 ExtServUnk_Release
105 };
106
impl_from_IAuthenticate(IAuthenticate * iface)107 static inline ExtensionService *impl_from_IAuthenticate(IAuthenticate *iface)
108 {
109 return CONTAINING_RECORD(iface, ExtensionService, IAuthenticate_iface);
110 }
111
Authenticate_QueryInterface(IAuthenticate * iface,REFIID riid,void ** ppv)112 static HRESULT WINAPI Authenticate_QueryInterface(IAuthenticate *iface, REFIID riid, void **ppv)
113 {
114 ExtensionService *This = impl_from_IAuthenticate(iface);
115 return IUnknown_QueryInterface(This->outer_unk, riid, ppv);
116 }
117
Authenticate_AddRef(IAuthenticate * iface)118 static ULONG WINAPI Authenticate_AddRef(IAuthenticate *iface)
119 {
120 ExtensionService *This = impl_from_IAuthenticate(iface);
121 return IUnknown_AddRef(This->outer_unk);
122 }
123
Authenticate_Release(IAuthenticate * iface)124 static ULONG WINAPI Authenticate_Release(IAuthenticate *iface)
125 {
126 ExtensionService *This = impl_from_IAuthenticate(iface);
127 return IUnknown_Release(This->outer_unk);
128 }
129
Authenticate_Authenticate(IAuthenticate * iface,HWND * phwnd,LPWSTR * pszUsername,LPWSTR * pszPassword)130 static HRESULT WINAPI Authenticate_Authenticate(IAuthenticate *iface,
131 HWND *phwnd, LPWSTR *pszUsername, LPWSTR *pszPassword)
132 {
133 ExtensionService *This = impl_from_IAuthenticate(iface);
134
135 TRACE("(%p)->(%p %p %p)\n", This, phwnd, pszUsername, pszPassword);
136
137 if(!phwnd || !pszUsername || !pszPassword)
138 return E_INVALIDARG;
139
140 *phwnd = This->hwnd;
141 *pszUsername = hlink_co_strdupW(This->username);
142 *pszPassword = hlink_co_strdupW(This->password);
143
144 return S_OK;
145 }
146
147 static const IAuthenticateVtbl AuthenticateVtbl = {
148 Authenticate_QueryInterface,
149 Authenticate_AddRef,
150 Authenticate_Release,
151 Authenticate_Authenticate
152 };
153
impl_from_IHttpNegotiate(IHttpNegotiate * iface)154 static inline ExtensionService *impl_from_IHttpNegotiate(IHttpNegotiate *iface)
155 {
156 return CONTAINING_RECORD(iface, ExtensionService, IHttpNegotiate_iface);
157 }
158
HttpNegotiate_QueryInterface(IHttpNegotiate * iface,REFIID riid,void ** ppv)159 static HRESULT WINAPI HttpNegotiate_QueryInterface(IHttpNegotiate *iface, REFIID riid, void **ppv)
160 {
161 ExtensionService *This = impl_from_IHttpNegotiate(iface);
162 return IUnknown_QueryInterface(This->outer_unk, riid, ppv);
163 }
164
HttpNegotiate_AddRef(IHttpNegotiate * iface)165 static ULONG WINAPI HttpNegotiate_AddRef(IHttpNegotiate *iface)
166 {
167 ExtensionService *This = impl_from_IHttpNegotiate(iface);
168 return IUnknown_AddRef(This->outer_unk);
169 }
170
HttpNegotiate_Release(IHttpNegotiate * iface)171 static ULONG WINAPI HttpNegotiate_Release(IHttpNegotiate *iface)
172 {
173 ExtensionService *This = impl_from_IHttpNegotiate(iface);
174 return IUnknown_Release(This->outer_unk);
175 }
176
HttpNegotiate_BeginningTransaction(IHttpNegotiate * iface,LPCWSTR szURL,LPCWSTR szHeaders,DWORD dwReserved,LPWSTR * pszAdditionalHeaders)177 static HRESULT WINAPI HttpNegotiate_BeginningTransaction(IHttpNegotiate *iface,
178 LPCWSTR szURL, LPCWSTR szHeaders, DWORD dwReserved, LPWSTR *pszAdditionalHeaders)
179 {
180 ExtensionService *This = impl_from_IHttpNegotiate(iface);
181
182 TRACE("(%p)->(%s %s %x %p)\n", This, debugstr_w(szURL), debugstr_w(szHeaders), dwReserved,
183 pszAdditionalHeaders);
184
185 if(!pszAdditionalHeaders)
186 return E_INVALIDARG;
187
188 *pszAdditionalHeaders = hlink_co_strdupW(This->headers);
189 return S_OK;
190 }
191
HttpNegotiate_OnResponse(IHttpNegotiate * iface,DWORD dwResponseCode,LPCWSTR szResponseHeaders,LPCWSTR szRequestHeaders,LPWSTR * pszAdditionalRequestHeaders)192 static HRESULT WINAPI HttpNegotiate_OnResponse(IHttpNegotiate *iface, DWORD dwResponseCode,
193 LPCWSTR szResponseHeaders, LPCWSTR szRequestHeaders, LPWSTR *pszAdditionalRequestHeaders)
194 {
195 ExtensionService *This = impl_from_IHttpNegotiate(iface);
196
197 TRACE("(%p)->(%d %s %s %p)\n", This, dwResponseCode, debugstr_w(szResponseHeaders),
198 debugstr_w(szRequestHeaders), pszAdditionalRequestHeaders);
199
200 *pszAdditionalRequestHeaders = NULL;
201 return S_OK;
202 }
203
204 static const IHttpNegotiateVtbl HttpNegotiateVtbl = {
205 HttpNegotiate_QueryInterface,
206 HttpNegotiate_AddRef,
207 HttpNegotiate_Release,
208 HttpNegotiate_BeginningTransaction,
209 HttpNegotiate_OnResponse
210 };
211
impl_from_IExtensionServices(IExtensionServices * iface)212 static inline ExtensionService *impl_from_IExtensionServices(IExtensionServices *iface)
213 {
214 return CONTAINING_RECORD(iface, ExtensionService, IExtensionServices_iface);
215 }
216
ExtServ_QueryInterface(IExtensionServices * iface,REFIID riid,void ** ppv)217 static HRESULT WINAPI ExtServ_QueryInterface(IExtensionServices *iface, REFIID riid, void **ppv)
218 {
219 ExtensionService *This = impl_from_IExtensionServices(iface);
220 return IUnknown_QueryInterface(This->outer_unk, riid, ppv);
221 }
222
ExtServ_AddRef(IExtensionServices * iface)223 static ULONG WINAPI ExtServ_AddRef(IExtensionServices *iface)
224 {
225 ExtensionService *This = impl_from_IExtensionServices(iface);
226 return IUnknown_AddRef(This->outer_unk);
227 }
228
ExtServ_Release(IExtensionServices * iface)229 static ULONG WINAPI ExtServ_Release(IExtensionServices *iface)
230 {
231 ExtensionService *This = impl_from_IExtensionServices(iface);
232 return IUnknown_Release(This->outer_unk);
233 }
234
ExtServ_ImplSetAdditionalHeaders(ExtensionService * This,LPCWSTR pwzAdditionalHeaders)235 static HRESULT ExtServ_ImplSetAdditionalHeaders(ExtensionService* This, LPCWSTR pwzAdditionalHeaders)
236 {
237 int len;
238
239 heap_free(This->headers);
240 This->headers = NULL;
241
242 if (!pwzAdditionalHeaders)
243 return S_OK;
244
245 len = lstrlenW(pwzAdditionalHeaders);
246
247 if(len && pwzAdditionalHeaders[len-1] != '\n' && pwzAdditionalHeaders[len-1] != '\r') {
248 static const WCHAR endlW[] = {'\r','\n',0};
249 This->headers = heap_alloc(len*sizeof(WCHAR) + sizeof(endlW));
250 memcpy(This->headers, pwzAdditionalHeaders, len*sizeof(WCHAR));
251 memcpy(This->headers+len, endlW, sizeof(endlW));
252 }else {
253 This->headers = hlink_strdupW(pwzAdditionalHeaders);
254 }
255
256 return S_OK;
257 }
258
ExtServ_SetAdditionalHeaders(IExtensionServices * iface,LPCWSTR pwzAdditionalHeaders)259 static HRESULT WINAPI ExtServ_SetAdditionalHeaders(IExtensionServices* iface, LPCWSTR pwzAdditionalHeaders)
260 {
261 ExtensionService *This = impl_from_IExtensionServices(iface);
262
263 TRACE("(%p)->(%s)\n", This, debugstr_w(pwzAdditionalHeaders));
264
265 return ExtServ_ImplSetAdditionalHeaders(This,pwzAdditionalHeaders);
266 }
267
ExtServ_ImplSetAuthenticateData(ExtensionService * This,HWND phwnd,LPCWSTR pwzUsername,LPCWSTR pwzPassword)268 static HRESULT ExtServ_ImplSetAuthenticateData(ExtensionService* This, HWND phwnd, LPCWSTR pwzUsername, LPCWSTR pwzPassword)
269 {
270 heap_free(This->username);
271 heap_free(This->password);
272
273 This->hwnd = phwnd;
274 This->username = hlink_strdupW(pwzUsername);
275 This->password = hlink_strdupW(pwzPassword);
276
277 return S_OK;
278 }
279
ExtServ_SetAuthenticateData(IExtensionServices * iface,HWND phwnd,LPCWSTR pwzUsername,LPCWSTR pwzPassword)280 static HRESULT WINAPI ExtServ_SetAuthenticateData(IExtensionServices* iface, HWND phwnd, LPCWSTR pwzUsername, LPCWSTR pwzPassword)
281 {
282 ExtensionService *This = impl_from_IExtensionServices(iface);
283
284 TRACE("(%p)->(%p %s %s)\n", This, phwnd, debugstr_w(pwzUsername), debugstr_w(pwzPassword));
285
286 return ExtServ_ImplSetAuthenticateData(This, phwnd, pwzUsername, pwzPassword);
287 }
288
289 static const IExtensionServicesVtbl ExtServVtbl = {
290 ExtServ_QueryInterface,
291 ExtServ_AddRef,
292 ExtServ_Release,
293 ExtServ_SetAdditionalHeaders,
294 ExtServ_SetAuthenticateData
295 };
296
297 /***********************************************************************
298 * HlinkCreateExtensionServices (HLINK.@)
299 */
HlinkCreateExtensionServices(LPCWSTR pwzAdditionalHeaders,HWND phwnd,LPCWSTR pszUsername,LPCWSTR pszPassword,IUnknown * punkOuter,REFIID riid,void ** ppv)300 HRESULT WINAPI HlinkCreateExtensionServices(LPCWSTR pwzAdditionalHeaders,
301 HWND phwnd, LPCWSTR pszUsername, LPCWSTR pszPassword,
302 IUnknown *punkOuter, REFIID riid, void** ppv)
303 {
304 ExtensionService *ret;
305 HRESULT hres = S_OK;
306
307 TRACE("%s %p %s %s %p %s %p\n",debugstr_w(pwzAdditionalHeaders),
308 phwnd, debugstr_w(pszUsername), debugstr_w(pszPassword),
309 punkOuter, debugstr_guid(riid), ppv);
310
311 ret = heap_alloc(sizeof(*ret));
312
313 ret->IUnknown_inner.lpVtbl = &ExtServUnkVtbl;
314 ret->IAuthenticate_iface.lpVtbl = &AuthenticateVtbl;
315 ret->IHttpNegotiate_iface.lpVtbl = &HttpNegotiateVtbl;
316 ret->IExtensionServices_iface.lpVtbl = &ExtServVtbl;
317 ret->ref = 1;
318 ret->headers = NULL;
319 ret->hwnd = NULL;
320 ret->username = NULL;
321 ret->password = NULL;
322
323 ExtServ_ImplSetAuthenticateData(ret, phwnd, pszUsername, pszPassword);
324 ExtServ_ImplSetAdditionalHeaders(ret, pwzAdditionalHeaders);
325
326 if(!punkOuter) {
327 ret->outer_unk = &ret->IUnknown_inner;
328 hres = IUnknown_QueryInterface(&ret->IUnknown_inner, riid, ppv);
329 IUnknown_Release(&ret->IUnknown_inner);
330 }else if(IsEqualGUID(&IID_IUnknown, riid)) {
331 ret->outer_unk = punkOuter;
332 *ppv = &ret->IUnknown_inner;
333 }else {
334 IUnknown_Release(&ret->IUnknown_inner);
335 hres = E_INVALIDARG;
336 }
337
338 return hres;
339 }
340