urlmon: Added more BindProtocol::ReportProgress 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
257     TRACE("(%p)->(%08x)\n", This, dwOptions);
258
259     return IInternetProtocol_LockRequest(This->protocol, dwOptions);
260 }
261
262 static HRESULT WINAPI BindProtocol_UnlockRequest(IInternetProtocol *iface)
263 {
264     BindProtocol *This = PROTOCOL_THIS(iface);
265
266     TRACE("(%p)\n", This);
267
268     return IInternetProtocol_UnlockRequest(This->protocol);
269 }
270
271 #undef PROTOCOL_THIS
272
273 static const IInternetProtocolVtbl BindProtocolVtbl = {
274     BindProtocol_QueryInterface,
275     BindProtocol_AddRef,
276     BindProtocol_Release,
277     BindProtocol_Start,
278     BindProtocol_Continue,
279     BindProtocol_Abort,
280     BindProtocol_Terminate,
281     BindProtocol_Suspend,
282     BindProtocol_Resume,
283     BindProtocol_Read,
284     BindProtocol_Seek,
285     BindProtocol_LockRequest,
286     BindProtocol_UnlockRequest
287 };
288
289 #define BINDINFO_THIS(iface) DEFINE_THIS(BindProtocol, InternetBindInfo, iface)
290
291 static HRESULT WINAPI BindInfo_QueryInterface(IInternetBindInfo *iface,
292         REFIID riid, void **ppv)
293 {
294     BindProtocol *This = BINDINFO_THIS(iface);
295     return IInternetProtocol_QueryInterface(PROTOCOL(This), riid, ppv);
296 }
297
298 static ULONG WINAPI BindInfo_AddRef(IInternetBindInfo *iface)
299 {
300     BindProtocol *This = BINDINFO_THIS(iface);
301     return IBinding_AddRef(PROTOCOL(This));
302 }
303
304 static ULONG WINAPI BindInfo_Release(IInternetBindInfo *iface)
305 {
306     BindProtocol *This = BINDINFO_THIS(iface);
307     return IBinding_Release(PROTOCOL(This));
308 }
309
310 static HRESULT WINAPI BindInfo_GetBindInfo(IInternetBindInfo *iface,
311         DWORD *grfBINDF, BINDINFO *pbindinfo)
312 {
313     BindProtocol *This = BINDINFO_THIS(iface);
314     HRESULT hres;
315
316     TRACE("(%p)->(%p %p)\n", This, grfBINDF, pbindinfo);
317
318     hres = IInternetBindInfo_GetBindInfo(This->bind_info, grfBINDF, pbindinfo);
319     if(FAILED(hres)) {
320         WARN("GetBindInfo failed: %08x\n", hres);
321         return hres;
322     }
323
324     *grfBINDF |= BINDF_FROMURLMON;
325     return hres;
326 }
327
328 static HRESULT WINAPI BindInfo_GetBindString(IInternetBindInfo *iface,
329         ULONG ulStringType, LPOLESTR *ppwzStr, ULONG cEl, ULONG *pcElFetched)
330 {
331     BindProtocol *This = BINDINFO_THIS(iface);
332
333     TRACE("(%p)->(%d %p %d %p)\n", This, ulStringType, ppwzStr, cEl, pcElFetched);
334
335     return IInternetBindInfo_GetBindString(This->bind_info, ulStringType, ppwzStr, cEl, pcElFetched);
336 }
337
338 #undef BINDFO_THIS
339
340 static const IInternetBindInfoVtbl InternetBindInfoVtbl = {
341     BindInfo_QueryInterface,
342     BindInfo_AddRef,
343     BindInfo_Release,
344     BindInfo_GetBindInfo,
345     BindInfo_GetBindString
346 };
347
348 #define PRIORITY_THIS(iface) DEFINE_THIS(BindProtocol, InternetPriority, iface)
349
350 static HRESULT WINAPI InternetPriority_QueryInterface(IInternetPriority *iface,
351         REFIID riid, void **ppv)
352 {
353     BindProtocol *This = PRIORITY_THIS(iface);
354     return IInternetProtocol_QueryInterface(PROTOCOL(This), riid, ppv);
355 }
356
357 static ULONG WINAPI InternetPriority_AddRef(IInternetPriority *iface)
358 {
359     BindProtocol *This = PRIORITY_THIS(iface);
360     return IInternetProtocol_AddRef(PROTOCOL(This));
361 }
362
363 static ULONG WINAPI InternetPriority_Release(IInternetPriority *iface)
364 {
365     BindProtocol *This = PRIORITY_THIS(iface);
366     return IInternetProtocol_Release(PROTOCOL(This));
367 }
368
369 static HRESULT WINAPI InternetPriority_SetPriority(IInternetPriority *iface, LONG nPriority)
370 {
371     BindProtocol *This = PRIORITY_THIS(iface);
372
373     TRACE("(%p)->(%d)\n", This, nPriority);
374
375     This->priority = nPriority;
376     return S_OK;
377 }
378
379 static HRESULT WINAPI InternetPriority_GetPriority(IInternetPriority *iface, LONG *pnPriority)
380 {
381     BindProtocol *This = PRIORITY_THIS(iface);
382
383     TRACE("(%p)->(%p)\n", This, pnPriority);
384
385     *pnPriority = This->priority;
386     return S_OK;
387 }
388
389 #undef PRIORITY_THIS
390
391 static const IInternetPriorityVtbl InternetPriorityVtbl = {
392     InternetPriority_QueryInterface,
393     InternetPriority_AddRef,
394     InternetPriority_Release,
395     InternetPriority_SetPriority,
396     InternetPriority_GetPriority
397
398 };
399
400 #define PROTSINK_THIS(iface) DEFINE_THIS(BindProtocol, InternetProtocolSink, iface)
401
402 static HRESULT WINAPI InternetProtocolSink_QueryInterface(IInternetProtocolSink *iface,
403         REFIID riid, void **ppv)
404 {
405     BindProtocol *This = PROTSINK_THIS(iface);
406     return IInternetProtocol_QueryInterface(PROTOCOL(This), riid, ppv);
407 }
408
409 static ULONG WINAPI InternetProtocolSink_AddRef(IInternetProtocolSink *iface)
410 {
411     BindProtocol *This = PROTSINK_THIS(iface);
412     return IInternetProtocol_AddRef(PROTOCOL(This));
413 }
414
415 static ULONG WINAPI InternetProtocolSink_Release(IInternetProtocolSink *iface)
416 {
417     BindProtocol *This = PROTSINK_THIS(iface);
418     return IInternetProtocol_Release(PROTOCOL(This));
419 }
420
421 static HRESULT WINAPI InternetProtocolSink_Switch(IInternetProtocolSink *iface,
422         PROTOCOLDATA *pProtocolData)
423 {
424     BindProtocol *This = PROTSINK_THIS(iface);
425
426     TRACE("(%p)->(%p)\n", This, pProtocolData);
427
428     return IInternetProtocolSink_Switch(This->protocol_sink, pProtocolData);
429 }
430
431 static HRESULT WINAPI InternetProtocolSink_ReportProgress(IInternetProtocolSink *iface,
432         ULONG ulStatusCode, LPCWSTR szStatusText)
433 {
434     BindProtocol *This = PROTSINK_THIS(iface);
435
436     TRACE("(%p)->(%u %s)\n", This, ulStatusCode, debugstr_w(szStatusText));
437
438     switch(ulStatusCode) {
439     case BINDSTATUS_FINDINGRESOURCE:
440     case BINDSTATUS_CONNECTING:
441     case BINDSTATUS_SENDINGREQUEST:
442     case BINDSTATUS_CACHEFILENAMEAVAILABLE:
443         return IInternetProtocolSink_ReportProgress(This->protocol_sink,
444                 ulStatusCode, szStatusText);
445     case BINDSTATUS_VERIFIEDMIMETYPEAVAILABLE:
446     case BINDSTATUS_MIMETYPEAVAILABLE:
447         return IInternetProtocolSink_ReportProgress(This->protocol_sink,
448                 BINDSTATUS_MIMETYPEAVAILABLE, szStatusText);
449     default:
450         FIXME("unsupported ulStatusCode %u\n", ulStatusCode);
451     }
452
453     return E_NOTIMPL;
454 }
455
456 static HRESULT WINAPI InternetProtocolSink_ReportData(IInternetProtocolSink *iface,
457         DWORD grfBSCF, ULONG ulProgress, ULONG ulProgressMax)
458 {
459     BindProtocol *This = PROTSINK_THIS(iface);
460
461     TRACE("(%p)->(%d %u %u)\n", This, grfBSCF, ulProgress, ulProgressMax);
462
463     return IInternetProtocolSink_ReportData(This->protocol_sink, grfBSCF, ulProgress, ulProgressMax);
464 }
465
466 static HRESULT WINAPI InternetProtocolSink_ReportResult(IInternetProtocolSink *iface,
467         HRESULT hrResult, DWORD dwError, LPCWSTR szResult)
468 {
469     BindProtocol *This = PROTSINK_THIS(iface);
470
471     TRACE("(%p)->(%08x %d %s)\n", This, hrResult, dwError, debugstr_w(szResult));
472
473     return IInternetProtocolSink_ReportResult(This->protocol_sink, hrResult, dwError, szResult);
474 }
475
476 #undef PROTSINK_THIS
477
478 static const IInternetProtocolSinkVtbl InternetProtocolSinkVtbl = {
479     InternetProtocolSink_QueryInterface,
480     InternetProtocolSink_AddRef,
481     InternetProtocolSink_Release,
482     InternetProtocolSink_Switch,
483     InternetProtocolSink_ReportProgress,
484     InternetProtocolSink_ReportData,
485     InternetProtocolSink_ReportResult
486 };
487
488 #define SERVPROV_THIS(iface) DEFINE_THIS(BindProtocol, ServiceProvider, iface)
489
490 static HRESULT WINAPI BPServiceProvider_QueryInterface(IServiceProvider *iface,
491         REFIID riid, void **ppv)
492 {
493     BindProtocol *This = SERVPROV_THIS(iface);
494     return IInternetProtocol_QueryInterface(PROTOCOL(This), riid, ppv);
495 }
496
497 static ULONG WINAPI BPServiceProvider_AddRef(IServiceProvider *iface)
498 {
499     BindProtocol *This = SERVPROV_THIS(iface);
500     return IInternetProtocol_AddRef(PROTOCOL(This));
501 }
502
503 static ULONG WINAPI BPServiceProvider_Release(IServiceProvider *iface)
504 {
505     BindProtocol *This = SERVPROV_THIS(iface);
506     return IInternetProtocol_Release(PROTOCOL(This));
507 }
508
509 static HRESULT WINAPI BPServiceProvider_QueryService(IServiceProvider *iface,
510         REFGUID guidService, REFIID riid, void **ppv)
511 {
512     BindProtocol *This = SERVPROV_THIS(iface);
513
514     TRACE("(%p)->(%s %s %p)\n", This, debugstr_guid(guidService), debugstr_guid(riid), ppv);
515
516     if(!This->service_provider)
517         return E_NOINTERFACE;
518
519     return IServiceProvider_QueryService(This->service_provider, guidService, riid, ppv);
520 }
521
522 #undef SERVPROV_THIS
523
524 static const IServiceProviderVtbl ServiceProviderVtbl = {
525     BPServiceProvider_QueryInterface,
526     BPServiceProvider_AddRef,
527     BPServiceProvider_Release,
528     BPServiceProvider_QueryService
529 };
530
531 HRESULT create_binding_protocol(LPCWSTR url, IInternetProtocol **protocol)
532 {
533     BindProtocol *ret = heap_alloc(sizeof(BindProtocol));
534
535     ret->lpInternetProtocolVtbl = &BindProtocolVtbl;
536     ret->lpInternetBindInfoVtbl = &InternetBindInfoVtbl;
537     ret->lpInternetPriorityVtbl = &InternetPriorityVtbl;
538     ret->lpServiceProviderVtbl  = &ServiceProviderVtbl;
539     ret->lpInternetProtocolSinkVtbl = &InternetProtocolSinkVtbl;
540
541     ret->ref = 1;
542     ret->protocol = NULL;
543     ret->bind_info = NULL;
544     ret->protocol_sink = NULL;
545     ret->service_provider = NULL;
546     ret->priority = 0;
547
548     URLMON_LockModule();
549
550     *protocol = PROTOCOL(ret);
551     return S_OK;
552 }