urlmon: Added BindProtocol::Continue implementation.
[wine] / dlls / urlmon / bindprot.c
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 "urlmon_main.h"
20 #include "wine/debug.h"
21
22 WINE_DEFAULT_DEBUG_CHANNEL(urlmon);
23
24 typedef struct {
25     const IInternetProtocolVtbl *lpInternetProtocolVtbl;
26     const IInternetBindInfoVtbl *lpInternetBindInfoVtbl;
27     const IInternetPriorityVtbl *lpInternetPriorityVtbl;
28     const IServiceProviderVtbl  *lpServiceProviderVtbl;
29     const IInternetProtocolSinkVtbl *lpInternetProtocolSinkVtbl;
30
31     LONG ref;
32
33     IInternetProtocol *protocol;
34     IInternetBindInfo *bind_info;
35     IInternetProtocolSink *protocol_sink;
36     IServiceProvider *service_provider;
37
38     LONG priority;
39 } BindProtocol;
40
41 #define PROTOCOL(x)  ((IInternetProtocol*) &(x)->lpInternetProtocolVtbl)
42 #define BINDINFO(x)  ((IInternetBindInfo*) &(x)->lpInternetBindInfoVtbl)
43 #define PRIORITY(x)  ((IInternetPriority*) &(x)->lpInternetPriorityVtbl)
44 #define SERVPROV(x)  ((IServiceProvider*)  &(x)->lpServiceProviderVtbl)
45 #define PROTSINK(x)  ((IInternetProtocolSink*) &(x)->lpInternetProtocolSinkVtbl)
46
47 #define PROTOCOL_THIS(iface) DEFINE_THIS(BindProtocol, InternetProtocol, iface)
48
49 static HRESULT WINAPI BindProtocol_QueryInterface(IInternetProtocol *iface, REFIID riid, void **ppv)
50 {
51     BindProtocol *This = PROTOCOL_THIS(iface);
52
53     *ppv = NULL;
54     if(IsEqualGUID(&IID_IUnknown, riid)) {
55         TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
56         *ppv = PROTOCOL(This);
57     }else if(IsEqualGUID(&IID_IInternetProtocolRoot, riid)) {
58         TRACE("(%p)->(IID_IInternetProtocolRoot %p)\n", This, ppv);
59         *ppv = PROTOCOL(This);
60     }else if(IsEqualGUID(&IID_IInternetProtocol, riid)) {
61         TRACE("(%p)->(IID_IInternetProtocol %p)\n", This, ppv);
62         *ppv = PROTOCOL(This);
63     }else if(IsEqualGUID(&IID_IInternetBindInfo, riid)) {
64         TRACE("(%p)->(IID_IInternetBindInfo %p)\n", This, ppv);
65         *ppv = BINDINFO(This);
66     }else if(IsEqualGUID(&IID_IInternetPriority, riid)) {
67         TRACE("(%p)->(IID_IInternetPriority %p)\n", This, ppv);
68         *ppv = PRIORITY(This);
69     }else if(IsEqualGUID(&IID_IAuthenticate, riid)) {
70         FIXME("(%p)->(IID_IAuthenticate %p)\n", This, ppv);
71     }else if(IsEqualGUID(&IID_IServiceProvider, riid)) {
72         TRACE("(%p)->(IID_IServiceProvider %p)\n", This, ppv);
73         *ppv = SERVPROV(This);
74     }else if(IsEqualGUID(&IID_IInternetProtocolSink, riid)) {
75         TRACE("(%p)->(IID_IInternetProtocolSink %p)\n", This, ppv);
76         *ppv = PROTSINK(This);
77     }
78
79     if(*ppv) {
80         IInternetProtocol_AddRef(iface);
81         return S_OK;
82     }
83
84     WARN("not supported interface %s\n", debugstr_guid(riid));
85     return E_NOINTERFACE;
86 }
87
88 static ULONG WINAPI BindProtocol_AddRef(IInternetProtocol *iface)
89 {
90     BindProtocol *This = PROTOCOL_THIS(iface);
91     LONG ref = InterlockedIncrement(&This->ref);
92     TRACE("(%p) ref=%d\n", This, ref);
93     return ref;
94 }
95
96 static ULONG WINAPI BindProtocol_Release(IInternetProtocol *iface)
97 {
98     BindProtocol *This = PROTOCOL_THIS(iface);
99     LONG ref = InterlockedDecrement(&This->ref);
100
101     TRACE("(%p) ref=%d\n", This, ref);
102
103     if(!ref) {
104         if(This->protocol)
105             IInternetProtocol_Release(This->protocol);
106         if(This->bind_info)
107             IInternetBindInfo_Release(This->bind_info);
108         if(This->protocol_sink)
109             IInternetProtocolSink_Release(This->protocol_sink);
110
111         heap_free(This);
112
113         URLMON_UnlockModule();
114     }
115
116     return ref;
117 }
118
119 static HRESULT WINAPI BindProtocol_Start(IInternetProtocol *iface, LPCWSTR szUrl,
120         IInternetProtocolSink *pOIProtSink, IInternetBindInfo *pOIBindInfo,
121         DWORD grfPI, DWORD dwReserved)
122 {
123     BindProtocol *This = PROTOCOL_THIS(iface);
124     IInternetProtocol *protocol = NULL;
125     IInternetPriority *priority;
126     IServiceProvider *service_provider;
127     CLSID clsid = IID_NULL;
128     LPOLESTR clsid_str;
129     HRESULT hres;
130
131     TRACE("(%p)->(%s %p %p %08x %d)\n", This, debugstr_w(szUrl), pOIProtSink,
132             pOIBindInfo, grfPI, dwReserved);
133
134     if(!szUrl || !pOIProtSink || !pOIBindInfo)
135         return E_INVALIDARG;
136
137     hres = IInternetProtocolSink_QueryInterface(pOIProtSink, &IID_IServiceProvider,
138                                                 (void**)&service_provider);
139     if(SUCCEEDED(hres)) {
140         /* FIXME: What's protocol CLSID here? */
141         IServiceProvider_QueryService(service_provider, &IID_IInternetProtocol,
142                                       &IID_IInternetProtocol, (void**)&protocol);
143         IServiceProvider_Release(service_provider);
144     }
145
146     if(!protocol) {
147         IClassFactory *cf;
148         IUnknown *unk;
149
150         hres = get_protocol_handler(szUrl, &clsid, &cf);
151         if(FAILED(hres))
152             return hres;
153
154         hres = IClassFactory_CreateInstance(cf, (IUnknown*)BINDINFO(This),
155                 &IID_IUnknown, (void**)&unk);
156         IClassFactory_Release(cf);
157         if(FAILED(hres))
158             return hres;
159
160         hres = IUnknown_QueryInterface(unk, &IID_IInternetProtocol, (void**)&protocol);
161         IUnknown_Release(unk);
162         if(FAILED(hres))
163             return hres;
164     }
165
166     StringFromCLSID(&clsid, &clsid_str);
167     IInternetProtocolSink_ReportProgress(pOIProtSink, BINDSTATUS_PROTOCOLCLASSID, clsid_str);
168     CoTaskMemFree(clsid_str);
169
170     This->protocol = protocol;
171
172     IInternetBindInfo_AddRef(pOIBindInfo);
173     This->bind_info = pOIBindInfo;
174
175     IInternetProtocolSink_AddRef(pOIProtSink);
176     This->protocol_sink = pOIProtSink;
177
178     IInternetProtocolSink_QueryInterface(pOIProtSink, &IID_IServiceProvider, (void**)&This->service_provider);
179
180     hres = IInternetProtocol_QueryInterface(protocol, &IID_IInternetPriority, (void**)&priority);
181     if(SUCCEEDED(hres)) {
182         IInternetPriority_SetPriority(priority, This->priority);
183         IInternetPriority_Release(priority);
184     }
185
186     return IInternetProtocol_Start(protocol, szUrl, PROTSINK(This), BINDINFO(This), 0, 0);
187 }
188
189 static HRESULT WINAPI BindProtocol_Continue(IInternetProtocol *iface, PROTOCOLDATA *pProtocolData)
190 {
191     BindProtocol *This = PROTOCOL_THIS(iface);
192
193     TRACE("(%p)->(%p)\n", This, pProtocolData);
194
195     return IInternetProtocol_Continue(This->protocol, pProtocolData);
196 }
197
198 static HRESULT WINAPI BindProtocol_Abort(IInternetProtocol *iface, HRESULT hrReason,
199         DWORD dwOptions)
200 {
201     BindProtocol *This = PROTOCOL_THIS(iface);
202     FIXME("(%p)->(%08x %08x)\n", This, hrReason, dwOptions);
203     return E_NOTIMPL;
204 }
205
206 static HRESULT WINAPI BindProtocol_Terminate(IInternetProtocol *iface, DWORD dwOptions)
207 {
208     BindProtocol *This = PROTOCOL_THIS(iface);
209
210     TRACE("(%p)->(%08x)\n", This, dwOptions);
211
212     IInternetProtocol_Terminate(This->protocol, 0);
213     return S_OK;
214 }
215
216 static HRESULT WINAPI BindProtocol_Suspend(IInternetProtocol *iface)
217 {
218     BindProtocol *This = PROTOCOL_THIS(iface);
219     FIXME("(%p)\n", This);
220     return E_NOTIMPL;
221 }
222
223 static HRESULT WINAPI BindProtocol_Resume(IInternetProtocol *iface)
224 {
225     BindProtocol *This = PROTOCOL_THIS(iface);
226     FIXME("(%p)\n", This);
227     return E_NOTIMPL;
228 }
229
230 static HRESULT WINAPI BindProtocol_Read(IInternetProtocol *iface, void *pv,
231         ULONG cb, ULONG *pcbRead)
232 {
233     BindProtocol *This = PROTOCOL_THIS(iface);
234     ULONG read = 0;
235     HRESULT hres;
236
237     TRACE("(%p)->(%p %u %p)\n", This, pv, cb, pcbRead);
238
239     hres = IInternetProtocol_Read(This->protocol, pv, cb, &read);
240
241     *pcbRead = read;
242     return hres;
243 }
244
245 static HRESULT WINAPI BindProtocol_Seek(IInternetProtocol *iface, LARGE_INTEGER dlibMove,
246         DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition)
247 {
248     BindProtocol *This = PROTOCOL_THIS(iface);
249     FIXME("(%p)->(%d %d %p)\n", This, dlibMove.u.LowPart, dwOrigin, plibNewPosition);
250     return E_NOTIMPL;
251 }
252
253 static HRESULT WINAPI BindProtocol_LockRequest(IInternetProtocol *iface, DWORD dwOptions)
254 {
255     BindProtocol *This = PROTOCOL_THIS(iface);
256     FIXME("(%p)->(%08x)\n", This, dwOptions);
257     return E_NOTIMPL;
258 }
259
260 static HRESULT WINAPI BindProtocol_UnlockRequest(IInternetProtocol *iface)
261 {
262     BindProtocol *This = PROTOCOL_THIS(iface);
263     FIXME("(%p)\n", This);
264     return E_NOTIMPL;
265 }
266
267 #undef PROTOCOL_THIS
268
269 static const IInternetProtocolVtbl BindProtocolVtbl = {
270     BindProtocol_QueryInterface,
271     BindProtocol_AddRef,
272     BindProtocol_Release,
273     BindProtocol_Start,
274     BindProtocol_Continue,
275     BindProtocol_Abort,
276     BindProtocol_Terminate,
277     BindProtocol_Suspend,
278     BindProtocol_Resume,
279     BindProtocol_Read,
280     BindProtocol_Seek,
281     BindProtocol_LockRequest,
282     BindProtocol_UnlockRequest
283 };
284
285 #define BINDINFO_THIS(iface) DEFINE_THIS(BindProtocol, InternetBindInfo, iface)
286
287 static HRESULT WINAPI BindInfo_QueryInterface(IInternetBindInfo *iface,
288         REFIID riid, void **ppv)
289 {
290     BindProtocol *This = BINDINFO_THIS(iface);
291     return IInternetProtocol_QueryInterface(PROTOCOL(This), riid, ppv);
292 }
293
294 static ULONG WINAPI BindInfo_AddRef(IInternetBindInfo *iface)
295 {
296     BindProtocol *This = BINDINFO_THIS(iface);
297     return IBinding_AddRef(PROTOCOL(This));
298 }
299
300 static ULONG WINAPI BindInfo_Release(IInternetBindInfo *iface)
301 {
302     BindProtocol *This = BINDINFO_THIS(iface);
303     return IBinding_Release(PROTOCOL(This));
304 }
305
306 static HRESULT WINAPI BindInfo_GetBindInfo(IInternetBindInfo *iface,
307         DWORD *grfBINDF, BINDINFO *pbindinfo)
308 {
309     BindProtocol *This = BINDINFO_THIS(iface);
310     HRESULT hres;
311
312     TRACE("(%p)->(%p %p)\n", This, grfBINDF, pbindinfo);
313
314     hres = IInternetBindInfo_GetBindInfo(This->bind_info, grfBINDF, pbindinfo);
315     if(FAILED(hres)) {
316         WARN("GetBindInfo failed: %08x\n", hres);
317         return hres;
318     }
319
320     *grfBINDF |= BINDF_FROMURLMON;
321     return hres;
322 }
323
324 static HRESULT WINAPI BindInfo_GetBindString(IInternetBindInfo *iface,
325         ULONG ulStringType, LPOLESTR *ppwzStr, ULONG cEl, ULONG *pcElFetched)
326 {
327     BindProtocol *This = BINDINFO_THIS(iface);
328
329     TRACE("(%p)->(%d %p %d %p)\n", This, ulStringType, ppwzStr, cEl, pcElFetched);
330
331     return IInternetBindInfo_GetBindString(This->bind_info, ulStringType, ppwzStr, cEl, pcElFetched);
332 }
333
334 #undef BINDFO_THIS
335
336 static const IInternetBindInfoVtbl InternetBindInfoVtbl = {
337     BindInfo_QueryInterface,
338     BindInfo_AddRef,
339     BindInfo_Release,
340     BindInfo_GetBindInfo,
341     BindInfo_GetBindString
342 };
343
344 #define PRIORITY_THIS(iface) DEFINE_THIS(BindProtocol, InternetPriority, iface)
345
346 static HRESULT WINAPI InternetPriority_QueryInterface(IInternetPriority *iface,
347         REFIID riid, void **ppv)
348 {
349     BindProtocol *This = PRIORITY_THIS(iface);
350     return IInternetProtocol_QueryInterface(PROTOCOL(This), riid, ppv);
351 }
352
353 static ULONG WINAPI InternetPriority_AddRef(IInternetPriority *iface)
354 {
355     BindProtocol *This = PRIORITY_THIS(iface);
356     return IInternetProtocol_AddRef(PROTOCOL(This));
357 }
358
359 static ULONG WINAPI InternetPriority_Release(IInternetPriority *iface)
360 {
361     BindProtocol *This = PRIORITY_THIS(iface);
362     return IInternetProtocol_Release(PROTOCOL(This));
363 }
364
365 static HRESULT WINAPI InternetPriority_SetPriority(IInternetPriority *iface, LONG nPriority)
366 {
367     BindProtocol *This = PRIORITY_THIS(iface);
368
369     TRACE("(%p)->(%d)\n", This, nPriority);
370
371     This->priority = nPriority;
372     return S_OK;
373 }
374
375 static HRESULT WINAPI InternetPriority_GetPriority(IInternetPriority *iface, LONG *pnPriority)
376 {
377     BindProtocol *This = PRIORITY_THIS(iface);
378
379     TRACE("(%p)->(%p)\n", This, pnPriority);
380
381     *pnPriority = This->priority;
382     return S_OK;
383 }
384
385 #undef PRIORITY_THIS
386
387 static const IInternetPriorityVtbl InternetPriorityVtbl = {
388     InternetPriority_QueryInterface,
389     InternetPriority_AddRef,
390     InternetPriority_Release,
391     InternetPriority_SetPriority,
392     InternetPriority_GetPriority
393
394 };
395
396 #define PROTSINK_THIS(iface) DEFINE_THIS(BindProtocol, InternetProtocolSink, iface)
397
398 static HRESULT WINAPI InternetProtocolSink_QueryInterface(IInternetProtocolSink *iface,
399         REFIID riid, void **ppv)
400 {
401     BindProtocol *This = PROTSINK_THIS(iface);
402     return IInternetProtocol_QueryInterface(PROTOCOL(This), riid, ppv);
403 }
404
405 static ULONG WINAPI InternetProtocolSink_AddRef(IInternetProtocolSink *iface)
406 {
407     BindProtocol *This = PROTSINK_THIS(iface);
408     return IInternetProtocol_AddRef(PROTOCOL(This));
409 }
410
411 static ULONG WINAPI InternetProtocolSink_Release(IInternetProtocolSink *iface)
412 {
413     BindProtocol *This = PROTSINK_THIS(iface);
414     return IInternetProtocol_Release(PROTOCOL(This));
415 }
416
417 static HRESULT WINAPI InternetProtocolSink_Switch(IInternetProtocolSink *iface,
418         PROTOCOLDATA *pProtocolData)
419 {
420     BindProtocol *This = PROTSINK_THIS(iface);
421
422     TRACE("(%p)->(%p)\n", This, pProtocolData);
423
424     return IInternetProtocolSink_Switch(This->protocol_sink, pProtocolData);
425 }
426
427 static HRESULT WINAPI InternetProtocolSink_ReportProgress(IInternetProtocolSink *iface,
428         ULONG ulStatusCode, LPCWSTR szStatusText)
429 {
430     BindProtocol *This = PROTSINK_THIS(iface);
431
432     TRACE("(%p)->(%u %s)\n", This, ulStatusCode, debugstr_w(szStatusText));
433
434     switch(ulStatusCode) {
435     case BINDSTATUS_SENDINGREQUEST:
436         return IInternetProtocolSink_ReportProgress(This->protocol_sink,
437                 ulStatusCode, NULL);
438     case BINDSTATUS_CACHEFILENAMEAVAILABLE:
439         return IInternetProtocolSink_ReportProgress(This->protocol_sink,
440                 ulStatusCode, szStatusText);
441     case BINDSTATUS_VERIFIEDMIMETYPEAVAILABLE:
442         return IInternetProtocolSink_ReportProgress(This->protocol_sink,
443                 BINDSTATUS_MIMETYPEAVAILABLE, szStatusText);
444     default:
445         FIXME("unsupported ulStatusCode %u\n", ulStatusCode);
446     }
447
448     return E_NOTIMPL;
449 }
450
451 static HRESULT WINAPI InternetProtocolSink_ReportData(IInternetProtocolSink *iface,
452         DWORD grfBSCF, ULONG ulProgress, ULONG ulProgressMax)
453 {
454     BindProtocol *This = PROTSINK_THIS(iface);
455
456     TRACE("(%p)->(%d %u %u)\n", This, grfBSCF, ulProgress, ulProgressMax);
457
458     return IInternetProtocolSink_ReportData(This->protocol_sink, grfBSCF, ulProgress, ulProgressMax);
459 }
460
461 static HRESULT WINAPI InternetProtocolSink_ReportResult(IInternetProtocolSink *iface,
462         HRESULT hrResult, DWORD dwError, LPCWSTR szResult)
463 {
464     BindProtocol *This = PROTSINK_THIS(iface);
465
466     TRACE("(%p)->(%08x %d %s)\n", This, hrResult, dwError, debugstr_w(szResult));
467
468     return IInternetProtocolSink_ReportResult(This->protocol_sink, hrResult, dwError, szResult);
469 }
470
471 #undef PROTSINK_THIS
472
473 static const IInternetProtocolSinkVtbl InternetProtocolSinkVtbl = {
474     InternetProtocolSink_QueryInterface,
475     InternetProtocolSink_AddRef,
476     InternetProtocolSink_Release,
477     InternetProtocolSink_Switch,
478     InternetProtocolSink_ReportProgress,
479     InternetProtocolSink_ReportData,
480     InternetProtocolSink_ReportResult
481 };
482
483 #define SERVPROV_THIS(iface) DEFINE_THIS(BindProtocol, ServiceProvider, iface)
484
485 static HRESULT WINAPI BPServiceProvider_QueryInterface(IServiceProvider *iface,
486         REFIID riid, void **ppv)
487 {
488     BindProtocol *This = SERVPROV_THIS(iface);
489     return IInternetProtocol_QueryInterface(PROTOCOL(This), riid, ppv);
490 }
491
492 static ULONG WINAPI BPServiceProvider_AddRef(IServiceProvider *iface)
493 {
494     BindProtocol *This = SERVPROV_THIS(iface);
495     return IInternetProtocol_AddRef(PROTOCOL(This));
496 }
497
498 static ULONG WINAPI BPServiceProvider_Release(IServiceProvider *iface)
499 {
500     BindProtocol *This = SERVPROV_THIS(iface);
501     return IInternetProtocol_Release(PROTOCOL(This));
502 }
503
504 static HRESULT WINAPI BPServiceProvider_QueryService(IServiceProvider *iface,
505         REFGUID guidService, REFIID riid, void **ppv)
506 {
507     BindProtocol *This = SERVPROV_THIS(iface);
508
509     TRACE("(%p)->(%s %s %p)\n", This, debugstr_guid(guidService), debugstr_guid(riid), ppv);
510
511     if(!This->service_provider)
512         return E_NOINTERFACE;
513
514     return IServiceProvider_QueryService(This->service_provider, guidService, riid, ppv);
515 }
516
517 #undef SERVPROV_THIS
518
519 static const IServiceProviderVtbl ServiceProviderVtbl = {
520     BPServiceProvider_QueryInterface,
521     BPServiceProvider_AddRef,
522     BPServiceProvider_Release,
523     BPServiceProvider_QueryService
524 };
525
526 HRESULT create_binding_protocol(LPCWSTR url, IInternetProtocol **protocol)
527 {
528     BindProtocol *ret = heap_alloc(sizeof(BindProtocol));
529
530     ret->lpInternetProtocolVtbl = &BindProtocolVtbl;
531     ret->lpInternetBindInfoVtbl = &InternetBindInfoVtbl;
532     ret->lpInternetPriorityVtbl = &InternetPriorityVtbl;
533     ret->lpServiceProviderVtbl  = &ServiceProviderVtbl;
534     ret->lpInternetProtocolSinkVtbl = &InternetProtocolSinkVtbl;
535
536     ret->ref = 1;
537     ret->protocol = NULL;
538     ret->bind_info = NULL;
539     ret->protocol_sink = NULL;
540     ret->service_provider = NULL;
541     ret->priority = 0;
542
543     URLMON_LockModule();
544
545     *protocol = PROTOCOL(ret);
546     return S_OK;
547 }