windowscodecs: Implement Commit for BMP encoder.
[wine] / dlls / urlmon / bindprot.c
1 /*
2  * Copyright 2007-2009 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 BindProtocol BindProtocol;
25
26 struct _task_header_t;
27
28 typedef void (*task_proc_t)(BindProtocol*,struct _task_header_t*);
29
30 typedef struct _task_header_t {
31     task_proc_t proc;
32     struct _task_header_t *next;
33 } task_header_t;
34
35 struct BindProtocol {
36     const IInternetProtocolVtbl      *lpIInternetProtocolVtbl;
37     const IInternetBindInfoVtbl      *lpInternetBindInfoVtbl;
38     const IInternetPriorityVtbl      *lpInternetPriorityVtbl;
39     const IServiceProviderVtbl       *lpServiceProviderVtbl;
40     const IInternetProtocolSinkVtbl  *lpIInternetProtocolSinkVtbl;
41
42     const IInternetProtocolVtbl *lpIInternetProtocolHandlerVtbl;
43
44     LONG ref;
45
46     IInternetProtocol *protocol;
47     IInternetProtocol *protocol_handler;
48     IInternetBindInfo *bind_info;
49     IInternetProtocolSink *protocol_sink;
50     IServiceProvider *service_provider;
51     IWinInetInfo *wininet_info;
52
53     LONG priority;
54
55     BOOL reported_result;
56     BOOL reported_mime;
57     BOOL from_urlmon;
58     DWORD pi;
59
60     DWORD apartment_thread;
61     HWND notif_hwnd;
62     DWORD continue_call;
63
64     CRITICAL_SECTION section;
65     task_header_t *task_queue_head, *task_queue_tail;
66
67     BYTE *buf;
68     DWORD buf_size;
69     LPWSTR mime;
70     LPWSTR url;
71     ProtocolProxy *filter_proxy;
72 };
73
74 #define BINDINFO(x)  ((IInternetBindInfo*) &(x)->lpInternetBindInfoVtbl)
75 #define PRIORITY(x)  ((IInternetPriority*) &(x)->lpInternetPriorityVtbl)
76 #define SERVPROV(x)  ((IServiceProvider*)  &(x)->lpServiceProviderVtbl)
77
78 #define PROTOCOLHANDLER(x)  ((IInternetProtocol*)  &(x)->lpIInternetProtocolHandlerVtbl)
79
80 #define BUFFER_SIZE     2048
81 #define MIME_TEST_SIZE  255
82
83 #define WM_MK_CONTINUE   (WM_USER+101)
84 #define WM_MK_RELEASE    (WM_USER+102)
85
86 static LRESULT WINAPI notif_wnd_proc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
87 {
88     switch(msg) {
89     case WM_MK_CONTINUE: {
90         BindProtocol *This = (BindProtocol*)lParam;
91         task_header_t *task;
92
93         while(1) {
94             EnterCriticalSection(&This->section);
95
96             task = This->task_queue_head;
97             if(task) {
98                 This->task_queue_head = task->next;
99                 if(!This->task_queue_head)
100                     This->task_queue_tail = NULL;
101             }
102
103             LeaveCriticalSection(&This->section);
104
105             if(!task)
106                 break;
107
108             This->continue_call++;
109             task->proc(This, task);
110             This->continue_call--;
111         }
112
113         IInternetProtocol_Release(PROTOCOL(This));
114         return 0;
115     }
116     case WM_MK_RELEASE: {
117         tls_data_t *data = get_tls_data();
118
119         if(!--data->notif_hwnd_cnt) {
120             DestroyWindow(hwnd);
121             data->notif_hwnd = NULL;
122         }
123     }
124     }
125
126     return DefWindowProcW(hwnd, msg, wParam, lParam);
127 }
128
129 HWND get_notif_hwnd(void)
130 {
131     static ATOM wnd_class = 0;
132     tls_data_t *tls_data;
133
134     static const WCHAR wszURLMonikerNotificationWindow[] =
135         {'U','R','L',' ','M','o','n','i','k','e','r',' ',
136          'N','o','t','i','f','i','c','a','t','i','o','n',' ','W','i','n','d','o','w',0};
137
138     tls_data = get_tls_data();
139     if(!tls_data)
140         return NULL;
141
142     if(tls_data->notif_hwnd_cnt) {
143         tls_data->notif_hwnd_cnt++;
144         return tls_data->notif_hwnd;
145     }
146
147     if(!wnd_class) {
148         static WNDCLASSEXW wndclass = {
149             sizeof(wndclass), 0,
150             notif_wnd_proc, 0, 0,
151             NULL, NULL, NULL, NULL, NULL,
152             wszURLMonikerNotificationWindow,
153             NULL
154         };
155
156         wndclass.hInstance = URLMON_hInstance;
157
158         wnd_class = RegisterClassExW(&wndclass);
159         if (!wnd_class && GetLastError() == ERROR_CLASS_ALREADY_EXISTS)
160             wnd_class = 1;
161     }
162
163     tls_data->notif_hwnd = CreateWindowExW(0, wszURLMonikerNotificationWindow,
164             wszURLMonikerNotificationWindow, 0, 0, 0, 0, 0, HWND_MESSAGE,
165             NULL, URLMON_hInstance, NULL);
166     if(tls_data->notif_hwnd)
167         tls_data->notif_hwnd_cnt++;
168
169     TRACE("hwnd = %p\n", tls_data->notif_hwnd);
170
171     return tls_data->notif_hwnd;
172 }
173
174 void release_notif_hwnd(HWND hwnd)
175 {
176     tls_data_t *data = get_tls_data();
177
178     if(!data)
179         return;
180
181     if(data->notif_hwnd != hwnd) {
182         PostMessageW(data->notif_hwnd, WM_MK_RELEASE, 0, 0);
183         return;
184     }
185
186     if(!--data->notif_hwnd_cnt) {
187         DestroyWindow(data->notif_hwnd);
188         data->notif_hwnd = NULL;
189     }
190 }
191
192 static void push_task(BindProtocol *This, task_header_t *task, task_proc_t proc)
193 {
194     BOOL do_post = FALSE;
195
196     task->proc = proc;
197     task->next = NULL;
198
199     EnterCriticalSection(&This->section);
200
201     if(This->task_queue_tail) {
202         This->task_queue_tail->next = task;
203         This->task_queue_tail = task;
204     }else {
205         This->task_queue_tail = This->task_queue_head = task;
206         do_post = TRUE;
207     }
208
209     LeaveCriticalSection(&This->section);
210
211     if(do_post) {
212         IInternetProtocol_AddRef(PROTOCOL(This));
213         PostMessageW(This->notif_hwnd, WM_MK_CONTINUE, 0, (LPARAM)This);
214     }
215 }
216
217 static inline BOOL do_direct_notif(BindProtocol *This)
218 {
219     return !(This->pi & PI_APARTMENTTHREADED) || (This->apartment_thread == GetCurrentThreadId() && !This->continue_call);
220 }
221
222 static HRESULT handle_mime_filter(BindProtocol *This, IInternetProtocol *mime_filter, LPCWSTR mime)
223 {
224     PROTOCOLFILTERDATA filter_data = { sizeof(PROTOCOLFILTERDATA), NULL, NULL, NULL, 0 };
225     IInternetProtocolSink *protocol_sink, *old_sink;
226     ProtocolProxy *filter_proxy;
227     HRESULT hres;
228
229     hres = IInternetProtocol_QueryInterface(mime_filter, &IID_IInternetProtocolSink, (void**)&protocol_sink);
230     if(FAILED(hres))
231         return hres;
232
233     hres = create_protocol_proxy(PROTOCOLHANDLER(This), This->protocol_sink, &filter_proxy);
234     if(FAILED(hres)) {
235         IInternetProtocolSink_Release(protocol_sink);
236         return hres;
237     }
238
239     old_sink = This->protocol_sink;
240     This->protocol_sink = protocol_sink;
241     This->filter_proxy = filter_proxy;
242
243     IInternetProtocol_AddRef(mime_filter);
244     This->protocol_handler = mime_filter;
245
246     filter_data.pProtocol = PROTOCOL(filter_proxy);
247     hres = IInternetProtocol_Start(mime_filter, mime, PROTSINK(filter_proxy), BINDINFO(This),
248             PI_FILTER_MODE|PI_FORCE_ASYNC, (HANDLE_PTR)&filter_data);
249     if(FAILED(hres)) {
250         IInternetProtocolSink_Release(old_sink);
251         return hres;
252     }
253
254     IInternetProtocolSink_ReportProgress(old_sink, BINDSTATUS_LOADINGMIMEHANDLER, NULL);
255     IInternetProtocolSink_Release(old_sink);
256
257     This->pi &= ~PI_MIMEVERIFICATION; /* FIXME: more tests */
258     return S_OK;
259 }
260
261 static void mime_available(BindProtocol *This, LPCWSTR mime, BOOL verified)
262 {
263     IInternetProtocol *mime_filter;
264     HRESULT hres;
265
266     heap_free(This->mime);
267     This->mime = NULL;
268
269     mime_filter = get_mime_filter(mime);
270     if(mime_filter) {
271         TRACE("Got mime filter for %s\n", debugstr_w(mime));
272
273         hres = handle_mime_filter(This, mime_filter, mime);
274         IInternetProtocol_Release(mime_filter);
275         if(FAILED(hres))
276             FIXME("MIME filter failed: %08x\n", hres);
277     }else {
278         This->mime = heap_strdupW(mime);
279
280         if(verified || !(This->pi & PI_MIMEVERIFICATION)) {
281             This->reported_mime = TRUE;
282
283             if(This->protocol_sink)
284                 IInternetProtocolSink_ReportProgress(This->protocol_sink, BINDSTATUS_MIMETYPEAVAILABLE, mime);
285         }
286     }
287 }
288
289 #define PROTOCOL_THIS(iface) DEFINE_THIS(BindProtocol, IInternetProtocol, iface)
290
291 static HRESULT WINAPI BindProtocol_QueryInterface(IInternetProtocol *iface, REFIID riid, void **ppv)
292 {
293     BindProtocol *This = PROTOCOL_THIS(iface);
294
295     *ppv = NULL;
296     if(IsEqualGUID(&IID_IUnknown, riid)) {
297         TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
298         *ppv = PROTOCOL(This);
299     }else if(IsEqualGUID(&IID_IInternetProtocolRoot, riid)) {
300         TRACE("(%p)->(IID_IInternetProtocolRoot %p)\n", This, ppv);
301         *ppv = PROTOCOL(This);
302     }else if(IsEqualGUID(&IID_IInternetProtocol, riid)) {
303         TRACE("(%p)->(IID_IInternetProtocol %p)\n", This, ppv);
304         *ppv = PROTOCOL(This);
305     }else if(IsEqualGUID(&IID_IInternetBindInfo, riid)) {
306         TRACE("(%p)->(IID_IInternetBindInfo %p)\n", This, ppv);
307         *ppv = BINDINFO(This);
308     }else if(IsEqualGUID(&IID_IInternetPriority, riid)) {
309         TRACE("(%p)->(IID_IInternetPriority %p)\n", This, ppv);
310         *ppv = PRIORITY(This);
311     }else if(IsEqualGUID(&IID_IAuthenticate, riid)) {
312         FIXME("(%p)->(IID_IAuthenticate %p)\n", This, ppv);
313     }else if(IsEqualGUID(&IID_IServiceProvider, riid)) {
314         TRACE("(%p)->(IID_IServiceProvider %p)\n", This, ppv);
315         *ppv = SERVPROV(This);
316     }else if(IsEqualGUID(&IID_IInternetProtocolSink, riid)) {
317         TRACE("(%p)->(IID_IInternetProtocolSink %p)\n", This, ppv);
318         *ppv = PROTSINK(This);
319     }
320
321     if(*ppv) {
322         IInternetProtocol_AddRef(iface);
323         return S_OK;
324     }
325
326     WARN("not supported interface %s\n", debugstr_guid(riid));
327     return E_NOINTERFACE;
328 }
329
330 static ULONG WINAPI BindProtocol_AddRef(IInternetProtocol *iface)
331 {
332     BindProtocol *This = PROTOCOL_THIS(iface);
333     LONG ref = InterlockedIncrement(&This->ref);
334     TRACE("(%p) ref=%d\n", This, ref);
335     return ref;
336 }
337
338 static ULONG WINAPI BindProtocol_Release(IInternetProtocol *iface)
339 {
340     BindProtocol *This = PROTOCOL_THIS(iface);
341     LONG ref = InterlockedDecrement(&This->ref);
342
343     TRACE("(%p) ref=%d\n", This, ref);
344
345     if(!ref) {
346         if(This->wininet_info)
347             IWinInetInfo_Release(This->wininet_info);
348         if(This->protocol)
349             IInternetProtocol_Release(This->protocol);
350         if(This->bind_info)
351             IInternetBindInfo_Release(This->bind_info);
352         if(This->protocol_handler && This->protocol_handler != PROTOCOLHANDLER(This))
353             IInternetProtocol_Release(This->protocol_handler);
354         if(This->filter_proxy)
355             IInternetProtocol_Release(PROTOCOL(This->filter_proxy));
356
357         set_binding_sink(PROTOCOL(This), NULL);
358
359         if(This->notif_hwnd)
360             release_notif_hwnd(This->notif_hwnd);
361         DeleteCriticalSection(&This->section);
362
363         heap_free(This->mime);
364         heap_free(This->url);
365         heap_free(This);
366
367         URLMON_UnlockModule();
368     }
369
370     return ref;
371 }
372
373 static HRESULT WINAPI BindProtocol_Start(IInternetProtocol *iface, LPCWSTR szUrl,
374         IInternetProtocolSink *pOIProtSink, IInternetBindInfo *pOIBindInfo,
375         DWORD grfPI, HANDLE_PTR dwReserved)
376 {
377     BindProtocol *This = PROTOCOL_THIS(iface);
378
379     TRACE("(%p)->(%s %p %p %08x %lx)\n", This, debugstr_w(szUrl), pOIProtSink,
380             pOIBindInfo, grfPI, dwReserved);
381
382     return IInternetProtocol_Start(This->protocol_handler, szUrl, pOIProtSink, pOIBindInfo, grfPI, dwReserved);
383 }
384
385 static HRESULT WINAPI BindProtocol_Continue(IInternetProtocol *iface, PROTOCOLDATA *pProtocolData)
386 {
387     BindProtocol *This = PROTOCOL_THIS(iface);
388
389     TRACE("(%p)->(%p)\n", This, pProtocolData);
390
391     return IInternetProtocol_Continue(This->protocol_handler, pProtocolData);
392 }
393
394 static HRESULT WINAPI BindProtocol_Abort(IInternetProtocol *iface, HRESULT hrReason,
395         DWORD dwOptions)
396 {
397     BindProtocol *This = PROTOCOL_THIS(iface);
398     FIXME("(%p)->(%08x %08x)\n", This, hrReason, dwOptions);
399     return E_NOTIMPL;
400 }
401
402 static HRESULT WINAPI BindProtocol_Terminate(IInternetProtocol *iface, DWORD dwOptions)
403 {
404     BindProtocol *This = PROTOCOL_THIS(iface);
405
406     TRACE("(%p)->(%08x)\n", This, dwOptions);
407
408     return IInternetProtocol_Terminate(This->protocol_handler, dwOptions);
409 }
410
411 static HRESULT WINAPI BindProtocol_Suspend(IInternetProtocol *iface)
412 {
413     BindProtocol *This = PROTOCOL_THIS(iface);
414     FIXME("(%p)\n", This);
415     return E_NOTIMPL;
416 }
417
418 static HRESULT WINAPI BindProtocol_Resume(IInternetProtocol *iface)
419 {
420     BindProtocol *This = PROTOCOL_THIS(iface);
421     FIXME("(%p)\n", This);
422     return E_NOTIMPL;
423 }
424
425 static HRESULT WINAPI BindProtocol_Read(IInternetProtocol *iface, void *pv,
426         ULONG cb, ULONG *pcbRead)
427 {
428     BindProtocol *This = PROTOCOL_THIS(iface);
429
430     TRACE("(%p)->(%p %u %p)\n", This, pv, cb, pcbRead);
431
432     if(pcbRead)
433         *pcbRead = 0;
434     return IInternetProtocol_Read(This->protocol_handler, pv, cb, pcbRead);
435 }
436
437 static HRESULT WINAPI BindProtocol_Seek(IInternetProtocol *iface, LARGE_INTEGER dlibMove,
438         DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition)
439 {
440     BindProtocol *This = PROTOCOL_THIS(iface);
441     FIXME("(%p)->(%d %d %p)\n", This, dlibMove.u.LowPart, dwOrigin, plibNewPosition);
442     return E_NOTIMPL;
443 }
444
445 static HRESULT WINAPI BindProtocol_LockRequest(IInternetProtocol *iface, DWORD dwOptions)
446 {
447     BindProtocol *This = PROTOCOL_THIS(iface);
448
449     TRACE("(%p)->(%08x)\n", This, dwOptions);
450
451     return IInternetProtocol_LockRequest(This->protocol_handler, dwOptions);
452 }
453
454 static HRESULT WINAPI BindProtocol_UnlockRequest(IInternetProtocol *iface)
455 {
456     BindProtocol *This = PROTOCOL_THIS(iface);
457
458     TRACE("(%p)\n", This);
459
460     return IInternetProtocol_UnlockRequest(This->protocol_handler);
461 }
462
463 void set_binding_sink(IInternetProtocol *bind_protocol, IInternetProtocolSink *sink)
464 {
465     BindProtocol *This = PROTOCOL_THIS(bind_protocol);
466     IInternetProtocolSink *prev_sink;
467     IServiceProvider *service_provider = NULL;
468
469     if(sink)
470         IInternetProtocolSink_AddRef(sink);
471     prev_sink = InterlockedExchangePointer((void**)&This->protocol_sink, sink);
472     if(prev_sink)
473         IInternetProtocolSink_Release(prev_sink);
474
475     if(sink)
476         IInternetProtocolSink_QueryInterface(sink, &IID_IServiceProvider, (void**)&service_provider);
477     service_provider = InterlockedExchangePointer((void**)&This->service_provider, service_provider);
478     if(service_provider)
479         IServiceProvider_Release(service_provider);
480 }
481
482 IWinInetInfo *get_wininet_info(IInternetProtocol *bind_protocol)
483 {
484     BindProtocol *This = PROTOCOL_THIS(bind_protocol);
485
486     return This->wininet_info;
487 }
488
489 #undef PROTOCOL_THIS
490
491 static const IInternetProtocolVtbl BindProtocolVtbl = {
492     BindProtocol_QueryInterface,
493     BindProtocol_AddRef,
494     BindProtocol_Release,
495     BindProtocol_Start,
496     BindProtocol_Continue,
497     BindProtocol_Abort,
498     BindProtocol_Terminate,
499     BindProtocol_Suspend,
500     BindProtocol_Resume,
501     BindProtocol_Read,
502     BindProtocol_Seek,
503     BindProtocol_LockRequest,
504     BindProtocol_UnlockRequest
505 };
506
507 #define PROTOCOLHANDLER_THIS(iface) DEFINE_THIS(BindProtocol, IInternetProtocolHandler, iface)
508
509 static HRESULT WINAPI ProtocolHandler_QueryInterface(IInternetProtocol *iface, REFIID riid, void **ppv)
510 {
511     ERR("should not be called\n");
512     return E_NOINTERFACE;
513 }
514
515 static ULONG WINAPI ProtocolHandler_AddRef(IInternetProtocol *iface)
516 {
517     BindProtocol *This = PROTOCOLHANDLER_THIS(iface);
518     return IInternetProtocol_AddRef(PROTOCOL(This));
519 }
520
521 static ULONG WINAPI ProtocolHandler_Release(IInternetProtocol *iface)
522 {
523     BindProtocol *This = PROTOCOLHANDLER_THIS(iface);
524     return IInternetProtocol_Release(PROTOCOL(This));
525 }
526
527 static HRESULT WINAPI ProtocolHandler_Start(IInternetProtocol *iface, LPCWSTR szUrl,
528         IInternetProtocolSink *pOIProtSink, IInternetBindInfo *pOIBindInfo,
529         DWORD grfPI, HANDLE_PTR dwReserved)
530 {
531     BindProtocol *This = PROTOCOLHANDLER_THIS(iface);
532     IInternetProtocol *protocol = NULL;
533     IInternetPriority *priority;
534     IServiceProvider *service_provider;
535     BOOL urlmon_protocol = FALSE;
536     CLSID clsid = IID_NULL;
537     LPOLESTR clsid_str;
538     HRESULT hres;
539
540     TRACE("(%p)->(%s %p %p %08x %lx)\n", This, debugstr_w(szUrl), pOIProtSink,
541             pOIBindInfo, grfPI, dwReserved);
542
543     if(!szUrl || !pOIProtSink || !pOIBindInfo)
544         return E_INVALIDARG;
545
546     This->pi = grfPI;
547     This->url = heap_strdupW(szUrl);
548
549     hres = IInternetProtocolSink_QueryInterface(pOIProtSink, &IID_IServiceProvider,
550                                                 (void**)&service_provider);
551     if(SUCCEEDED(hres)) {
552         /* FIXME: What's protocol CLSID here? */
553         IServiceProvider_QueryService(service_provider, &IID_IInternetProtocol,
554                                       &IID_IInternetProtocol, (void**)&protocol);
555         IServiceProvider_Release(service_provider);
556     }
557
558     if(!protocol) {
559         IClassFactory *cf;
560         IUnknown *unk;
561
562         hres = get_protocol_handler(szUrl, &clsid, &urlmon_protocol, &cf);
563         if(FAILED(hres))
564             return hres;
565
566         if(This->from_urlmon) {
567             hres = IClassFactory_CreateInstance(cf, NULL, &IID_IInternetProtocol, (void**)&protocol);
568             IClassFactory_Release(cf);
569             if(FAILED(hres))
570                 return hres;
571         }else {
572             hres = IClassFactory_CreateInstance(cf, (IUnknown*)BINDINFO(This),
573                     &IID_IUnknown, (void**)&unk);
574             IClassFactory_Release(cf);
575             if(FAILED(hres))
576                 return hres;
577
578             hres = IUnknown_QueryInterface(unk, &IID_IInternetProtocol, (void**)&protocol);
579             IUnknown_Release(unk);
580             if(FAILED(hres))
581                 return hres;
582         }
583     }
584
585     StringFromCLSID(&clsid, &clsid_str);
586     IInternetProtocolSink_ReportProgress(pOIProtSink, BINDSTATUS_PROTOCOLCLASSID, clsid_str);
587     CoTaskMemFree(clsid_str);
588
589     This->protocol = protocol;
590
591     if(urlmon_protocol)
592         IInternetProtocol_QueryInterface(protocol, &IID_IWinInetInfo, (void**)&This->wininet_info);
593
594     IInternetBindInfo_AddRef(pOIBindInfo);
595     This->bind_info = pOIBindInfo;
596
597     set_binding_sink(PROTOCOL(This), pOIProtSink);
598
599     hres = IInternetProtocol_QueryInterface(protocol, &IID_IInternetPriority, (void**)&priority);
600     if(SUCCEEDED(hres)) {
601         IInternetPriority_SetPriority(priority, This->priority);
602         IInternetPriority_Release(priority);
603     }
604
605     return IInternetProtocol_Start(protocol, szUrl, PROTSINK(This), BINDINFO(This), 0, 0);
606 }
607
608 static HRESULT WINAPI ProtocolHandler_Continue(IInternetProtocol *iface, PROTOCOLDATA *pProtocolData)
609 {
610     BindProtocol *This = PROTOCOLHANDLER_THIS(iface);
611     HRESULT hres;
612
613     TRACE("(%p)->(%p)\n", This, pProtocolData);
614
615     hres = IInternetProtocol_Continue(This->protocol, pProtocolData);
616
617     heap_free(pProtocolData);
618     return hres;
619 }
620
621 static HRESULT WINAPI ProtocolHandler_Abort(IInternetProtocol *iface, HRESULT hrReason,
622         DWORD dwOptions)
623 {
624     BindProtocol *This = PROTOCOLHANDLER_THIS(iface);
625     FIXME("(%p)->(%08x %08x)\n", This, hrReason, dwOptions);
626     return E_NOTIMPL;
627 }
628
629 static HRESULT WINAPI ProtocolHandler_Terminate(IInternetProtocol *iface, DWORD dwOptions)
630 {
631     BindProtocol *This = PROTOCOLHANDLER_THIS(iface);
632
633     TRACE("(%p)->(%08x)\n", This, dwOptions);
634
635     if(!This->reported_result)
636         return E_FAIL;
637
638     IInternetProtocol_Terminate(This->protocol, 0);
639
640     if(This->filter_proxy) {
641         IInternetProtocol_Release(PROTOCOL(This->filter_proxy));
642         This->filter_proxy = NULL;
643     }
644
645     set_binding_sink(PROTOCOL(This), NULL);
646
647     if(This->bind_info) {
648         IInternetBindInfo_Release(This->bind_info);
649         This->bind_info = NULL;
650     }
651
652     return S_OK;
653 }
654
655 static HRESULT WINAPI ProtocolHandler_Suspend(IInternetProtocol *iface)
656 {
657     BindProtocol *This = PROTOCOLHANDLER_THIS(iface);
658     FIXME("(%p)\n", This);
659     return E_NOTIMPL;
660 }
661
662 static HRESULT WINAPI ProtocolHandler_Resume(IInternetProtocol *iface)
663 {
664     BindProtocol *This = PROTOCOLHANDLER_THIS(iface);
665     FIXME("(%p)\n", This);
666     return E_NOTIMPL;
667 }
668
669 static HRESULT WINAPI ProtocolHandler_Read(IInternetProtocol *iface, void *pv,
670         ULONG cb, ULONG *pcbRead)
671 {
672     BindProtocol *This = PROTOCOLHANDLER_THIS(iface);
673     ULONG read = 0;
674     HRESULT hres = S_OK;
675
676     TRACE("(%p)->(%p %u %p)\n", This, pv, cb, pcbRead);
677
678     if(This->buf) {
679         read = min(cb, This->buf_size);
680         memcpy(pv, This->buf, read);
681
682         if(read == This->buf_size) {
683             heap_free(This->buf);
684             This->buf = NULL;
685         }else {
686             memmove(This->buf, This->buf+cb, This->buf_size-cb);
687         }
688
689         This->buf_size -= read;
690     }
691
692     if(read < cb) {
693         ULONG cread = 0;
694
695         hres = IInternetProtocol_Read(This->protocol, (BYTE*)pv+read, cb-read, &cread);
696         read += cread;
697     }
698
699     *pcbRead = read;
700     return hres;
701 }
702
703 static HRESULT WINAPI ProtocolHandler_Seek(IInternetProtocol *iface, LARGE_INTEGER dlibMove,
704         DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition)
705 {
706     BindProtocol *This = PROTOCOLHANDLER_THIS(iface);
707     FIXME("(%p)->(%d %d %p)\n", This, dlibMove.u.LowPart, dwOrigin, plibNewPosition);
708     return E_NOTIMPL;
709 }
710
711 static HRESULT WINAPI ProtocolHandler_LockRequest(IInternetProtocol *iface, DWORD dwOptions)
712 {
713     BindProtocol *This = PROTOCOLHANDLER_THIS(iface);
714
715     TRACE("(%p)->(%08x)\n", This, dwOptions);
716
717     return IInternetProtocol_LockRequest(This->protocol, dwOptions);
718 }
719
720 static HRESULT WINAPI ProtocolHandler_UnlockRequest(IInternetProtocol *iface)
721 {
722     BindProtocol *This = PROTOCOLHANDLER_THIS(iface);
723
724     TRACE("(%p)\n", This);
725
726     return IInternetProtocol_UnlockRequest(This->protocol);
727 }
728
729 #undef PROTOCOL_THIS
730
731 static const IInternetProtocolVtbl InternetProtocolHandlerVtbl = {
732     ProtocolHandler_QueryInterface,
733     ProtocolHandler_AddRef,
734     ProtocolHandler_Release,
735     ProtocolHandler_Start,
736     ProtocolHandler_Continue,
737     ProtocolHandler_Abort,
738     ProtocolHandler_Terminate,
739     ProtocolHandler_Suspend,
740     ProtocolHandler_Resume,
741     ProtocolHandler_Read,
742     ProtocolHandler_Seek,
743     ProtocolHandler_LockRequest,
744     ProtocolHandler_UnlockRequest
745 };
746
747 #define BINDINFO_THIS(iface) DEFINE_THIS(BindProtocol, InternetBindInfo, iface)
748
749 static HRESULT WINAPI BindInfo_QueryInterface(IInternetBindInfo *iface,
750         REFIID riid, void **ppv)
751 {
752     BindProtocol *This = BINDINFO_THIS(iface);
753     return IInternetProtocol_QueryInterface(PROTOCOL(This), riid, ppv);
754 }
755
756 static ULONG WINAPI BindInfo_AddRef(IInternetBindInfo *iface)
757 {
758     BindProtocol *This = BINDINFO_THIS(iface);
759     return IBinding_AddRef(PROTOCOL(This));
760 }
761
762 static ULONG WINAPI BindInfo_Release(IInternetBindInfo *iface)
763 {
764     BindProtocol *This = BINDINFO_THIS(iface);
765     return IBinding_Release(PROTOCOL(This));
766 }
767
768 static HRESULT WINAPI BindInfo_GetBindInfo(IInternetBindInfo *iface,
769         DWORD *grfBINDF, BINDINFO *pbindinfo)
770 {
771     BindProtocol *This = BINDINFO_THIS(iface);
772     HRESULT hres;
773
774     TRACE("(%p)->(%p %p)\n", This, grfBINDF, pbindinfo);
775
776     hres = IInternetBindInfo_GetBindInfo(This->bind_info, grfBINDF, pbindinfo);
777     if(FAILED(hres)) {
778         WARN("GetBindInfo failed: %08x\n", hres);
779         return hres;
780     }
781
782     *grfBINDF |= BINDF_FROMURLMON;
783     return hres;
784 }
785
786 static HRESULT WINAPI BindInfo_GetBindString(IInternetBindInfo *iface,
787         ULONG ulStringType, LPOLESTR *ppwzStr, ULONG cEl, ULONG *pcElFetched)
788 {
789     BindProtocol *This = BINDINFO_THIS(iface);
790
791     TRACE("(%p)->(%d %p %d %p)\n", This, ulStringType, ppwzStr, cEl, pcElFetched);
792
793     return IInternetBindInfo_GetBindString(This->bind_info, ulStringType, ppwzStr, cEl, pcElFetched);
794 }
795
796 #undef BINDFO_THIS
797
798 static const IInternetBindInfoVtbl InternetBindInfoVtbl = {
799     BindInfo_QueryInterface,
800     BindInfo_AddRef,
801     BindInfo_Release,
802     BindInfo_GetBindInfo,
803     BindInfo_GetBindString
804 };
805
806 #define PRIORITY_THIS(iface) DEFINE_THIS(BindProtocol, InternetPriority, iface)
807
808 static HRESULT WINAPI InternetPriority_QueryInterface(IInternetPriority *iface,
809         REFIID riid, void **ppv)
810 {
811     BindProtocol *This = PRIORITY_THIS(iface);
812     return IInternetProtocol_QueryInterface(PROTOCOL(This), riid, ppv);
813 }
814
815 static ULONG WINAPI InternetPriority_AddRef(IInternetPriority *iface)
816 {
817     BindProtocol *This = PRIORITY_THIS(iface);
818     return IInternetProtocol_AddRef(PROTOCOL(This));
819 }
820
821 static ULONG WINAPI InternetPriority_Release(IInternetPriority *iface)
822 {
823     BindProtocol *This = PRIORITY_THIS(iface);
824     return IInternetProtocol_Release(PROTOCOL(This));
825 }
826
827 static HRESULT WINAPI InternetPriority_SetPriority(IInternetPriority *iface, LONG nPriority)
828 {
829     BindProtocol *This = PRIORITY_THIS(iface);
830
831     TRACE("(%p)->(%d)\n", This, nPriority);
832
833     This->priority = nPriority;
834     return S_OK;
835 }
836
837 static HRESULT WINAPI InternetPriority_GetPriority(IInternetPriority *iface, LONG *pnPriority)
838 {
839     BindProtocol *This = PRIORITY_THIS(iface);
840
841     TRACE("(%p)->(%p)\n", This, pnPriority);
842
843     *pnPriority = This->priority;
844     return S_OK;
845 }
846
847 #undef PRIORITY_THIS
848
849 static const IInternetPriorityVtbl InternetPriorityVtbl = {
850     InternetPriority_QueryInterface,
851     InternetPriority_AddRef,
852     InternetPriority_Release,
853     InternetPriority_SetPriority,
854     InternetPriority_GetPriority
855
856 };
857
858 #define PROTSINK_THIS(iface) DEFINE_THIS(BindProtocol, IInternetProtocolSink, iface)
859
860 static HRESULT WINAPI BPInternetProtocolSink_QueryInterface(IInternetProtocolSink *iface,
861         REFIID riid, void **ppv)
862 {
863     BindProtocol *This = PROTSINK_THIS(iface);
864     return IInternetProtocol_QueryInterface(PROTOCOL(This), riid, ppv);
865 }
866
867 static ULONG WINAPI BPInternetProtocolSink_AddRef(IInternetProtocolSink *iface)
868 {
869     BindProtocol *This = PROTSINK_THIS(iface);
870     return IInternetProtocol_AddRef(PROTOCOL(This));
871 }
872
873 static ULONG WINAPI BPInternetProtocolSink_Release(IInternetProtocolSink *iface)
874 {
875     BindProtocol *This = PROTSINK_THIS(iface);
876     return IInternetProtocol_Release(PROTOCOL(This));
877 }
878
879 typedef struct {
880     task_header_t header;
881     PROTOCOLDATA *data;
882 } switch_task_t;
883
884 static void switch_proc(BindProtocol *bind, task_header_t *t)
885 {
886     switch_task_t *task = (switch_task_t*)t;
887
888     IInternetProtocol_Continue(bind->protocol_handler, task->data);
889
890     heap_free(task);
891 }
892
893 static HRESULT WINAPI BPInternetProtocolSink_Switch(IInternetProtocolSink *iface,
894         PROTOCOLDATA *pProtocolData)
895 {
896     BindProtocol *This = PROTSINK_THIS(iface);
897     PROTOCOLDATA *data;
898
899     TRACE("(%p)->(%p)\n", This, pProtocolData);
900
901     TRACE("flags %x state %x data %p cb %u\n", pProtocolData->grfFlags, pProtocolData->dwState,
902           pProtocolData->pData, pProtocolData->cbData);
903
904     data = heap_alloc(sizeof(PROTOCOLDATA));
905     if(!data)
906         return E_OUTOFMEMORY;
907     memcpy(data, pProtocolData, sizeof(PROTOCOLDATA));
908
909     if(!do_direct_notif(This)) {
910         switch_task_t *task;
911
912         task = heap_alloc(sizeof(switch_task_t));
913         if(!task)
914             return E_OUTOFMEMORY;
915
916         task->data = data;
917
918         push_task(This, &task->header, switch_proc);
919         return S_OK;
920     }
921
922     if(!This->protocol_sink) {
923         IInternetProtocol_Continue(This->protocol_handler, data);
924         return S_OK;
925     }
926
927     return IInternetProtocolSink_Switch(This->protocol_sink, data);
928 }
929
930 static void report_progress(BindProtocol *This, ULONG status_code, LPCWSTR status_text)
931 {
932     switch(status_code) {
933     case BINDSTATUS_FINDINGRESOURCE:
934     case BINDSTATUS_CONNECTING:
935     case BINDSTATUS_BEGINDOWNLOADDATA:
936     case BINDSTATUS_SENDINGREQUEST:
937     case BINDSTATUS_CACHEFILENAMEAVAILABLE:
938     case BINDSTATUS_DIRECTBIND:
939     case BINDSTATUS_ACCEPTRANGES:
940         if(This->protocol_sink)
941             IInternetProtocolSink_ReportProgress(This->protocol_sink, status_code, status_text);
942         break;
943
944     case BINDSTATUS_MIMETYPEAVAILABLE:
945         mime_available(This, status_text, FALSE);
946         break;
947
948     case BINDSTATUS_VERIFIEDMIMETYPEAVAILABLE:
949         mime_available(This, status_text, TRUE);
950         break;
951
952     default:
953         FIXME("unsupported ulStatusCode %u\n", status_code);
954     }
955 }
956
957 typedef struct {
958     task_header_t header;
959
960     ULONG status_code;
961     LPWSTR status_text;
962 } on_progress_task_t;
963
964 static void on_progress_proc(BindProtocol *This, task_header_t *t)
965 {
966     on_progress_task_t *task = (on_progress_task_t*)t;
967
968     report_progress(This, task->status_code, task->status_text);
969
970     heap_free(task->status_text);
971     heap_free(task);
972 }
973
974 static HRESULT WINAPI BPInternetProtocolSink_ReportProgress(IInternetProtocolSink *iface,
975         ULONG ulStatusCode, LPCWSTR szStatusText)
976 {
977     BindProtocol *This = PROTSINK_THIS(iface);
978
979     TRACE("(%p)->(%u %s)\n", This, ulStatusCode, debugstr_w(szStatusText));
980
981     if(do_direct_notif(This)) {
982         report_progress(This, ulStatusCode, szStatusText);
983     }else {
984         on_progress_task_t *task;
985
986         task = heap_alloc(sizeof(on_progress_task_t));
987
988         task->status_code = ulStatusCode;
989         task->status_text = heap_strdupW(szStatusText);
990
991         push_task(This, &task->header, on_progress_proc);
992     }
993
994     return S_OK;
995 }
996
997 static HRESULT report_data(BindProtocol *This, DWORD bscf, ULONG progress, ULONG progress_max)
998 {
999     if(!This->protocol_sink)
1000         return S_OK;
1001
1002     if((This->pi & PI_MIMEVERIFICATION) && !This->reported_mime) {
1003         DWORD read = 0;
1004         LPWSTR mime;
1005         HRESULT hres;
1006
1007         if(!This->buf) {
1008             This->buf = heap_alloc(BUFFER_SIZE);
1009             if(!This->buf)
1010                 return E_OUTOFMEMORY;
1011         }
1012
1013         do {
1014             read = 0;
1015             hres = IInternetProtocol_Read(This->protocol, This->buf+This->buf_size,
1016                     BUFFER_SIZE-This->buf_size, &read);
1017             if(FAILED(hres) && hres != E_PENDING)
1018                 return hres;
1019             This->buf_size += read;
1020         }while(This->buf_size < MIME_TEST_SIZE && hres == S_OK);
1021
1022         if(This->buf_size < MIME_TEST_SIZE && hres != S_FALSE)
1023             return S_OK;
1024
1025         hres = FindMimeFromData(NULL, This->url, This->buf, min(This->buf_size, MIME_TEST_SIZE),
1026                 This->mime, 0, &mime, 0);
1027         if(FAILED(hres))
1028             return hres;
1029
1030         mime_available(This, mime, TRUE);
1031         CoTaskMemFree(mime);
1032     }
1033
1034     return IInternetProtocolSink_ReportData(This->protocol_sink, bscf, progress, progress_max);
1035 }
1036
1037 typedef struct {
1038     task_header_t header;
1039     DWORD bscf;
1040     ULONG progress;
1041     ULONG progress_max;
1042 } report_data_task_t;
1043
1044 static void report_data_proc(BindProtocol *This, task_header_t *t)
1045 {
1046     report_data_task_t *task = (report_data_task_t*)t;
1047
1048     report_data(This, task->bscf, task->progress, task->progress_max);
1049     heap_free(task);
1050 }
1051
1052 static HRESULT WINAPI BPInternetProtocolSink_ReportData(IInternetProtocolSink *iface,
1053         DWORD grfBSCF, ULONG ulProgress, ULONG ulProgressMax)
1054 {
1055     BindProtocol *This = PROTSINK_THIS(iface);
1056
1057     TRACE("(%p)->(%d %u %u)\n", This, grfBSCF, ulProgress, ulProgressMax);
1058
1059     if(!This->protocol_sink)
1060         return S_OK;
1061
1062     if(!do_direct_notif(This)) {
1063         report_data_task_t *task;
1064
1065         task = heap_alloc(sizeof(report_data_task_t));
1066         if(!task)
1067             return E_OUTOFMEMORY;
1068
1069         task->bscf = grfBSCF;
1070         task->progress = ulProgress;
1071         task->progress_max = ulProgressMax;
1072
1073         push_task(This, &task->header, report_data_proc);
1074         return S_OK;
1075     }
1076
1077     return report_data(This, grfBSCF, ulProgress, ulProgressMax);
1078 }
1079
1080 typedef struct {
1081     task_header_t header;
1082
1083     HRESULT hres;
1084     DWORD err;
1085     LPWSTR str;
1086 } report_result_task_t;
1087
1088 static void report_result_proc(BindProtocol *This, task_header_t *t)
1089 {
1090     report_result_task_t *task = (report_result_task_t*)t;
1091
1092     if(This->protocol_sink)
1093         IInternetProtocolSink_ReportResult(This->protocol_sink, task->hres, task->err, task->str);
1094
1095     heap_free(task->str);
1096     heap_free(task);
1097 }
1098
1099 static HRESULT WINAPI BPInternetProtocolSink_ReportResult(IInternetProtocolSink *iface,
1100         HRESULT hrResult, DWORD dwError, LPCWSTR szResult)
1101 {
1102     BindProtocol *This = PROTSINK_THIS(iface);
1103
1104     TRACE("(%p)->(%08x %d %s)\n", This, hrResult, dwError, debugstr_w(szResult));
1105
1106     if(!This->protocol_sink)
1107         return E_FAIL;
1108
1109     This->reported_result = TRUE;
1110
1111     if(!do_direct_notif(This)) {
1112         report_result_task_t *task;
1113
1114         task = heap_alloc(sizeof(report_result_task_t));
1115         if(!task)
1116             return E_OUTOFMEMORY;
1117
1118         task->hres = hrResult;
1119         task->err = dwError;
1120         task->str = heap_strdupW(szResult);
1121
1122         push_task(This, &task->header, report_result_proc);
1123         return S_OK;
1124     }
1125
1126     return IInternetProtocolSink_ReportResult(This->protocol_sink, hrResult, dwError, szResult);
1127 }
1128
1129 #undef PROTSINK_THIS
1130
1131 static const IInternetProtocolSinkVtbl InternetProtocolSinkVtbl = {
1132     BPInternetProtocolSink_QueryInterface,
1133     BPInternetProtocolSink_AddRef,
1134     BPInternetProtocolSink_Release,
1135     BPInternetProtocolSink_Switch,
1136     BPInternetProtocolSink_ReportProgress,
1137     BPInternetProtocolSink_ReportData,
1138     BPInternetProtocolSink_ReportResult
1139 };
1140
1141 #define SERVPROV_THIS(iface) DEFINE_THIS(BindProtocol, ServiceProvider, iface)
1142
1143 static HRESULT WINAPI BPServiceProvider_QueryInterface(IServiceProvider *iface,
1144         REFIID riid, void **ppv)
1145 {
1146     BindProtocol *This = SERVPROV_THIS(iface);
1147     return IInternetProtocol_QueryInterface(PROTOCOL(This), riid, ppv);
1148 }
1149
1150 static ULONG WINAPI BPServiceProvider_AddRef(IServiceProvider *iface)
1151 {
1152     BindProtocol *This = SERVPROV_THIS(iface);
1153     return IInternetProtocol_AddRef(PROTOCOL(This));
1154 }
1155
1156 static ULONG WINAPI BPServiceProvider_Release(IServiceProvider *iface)
1157 {
1158     BindProtocol *This = SERVPROV_THIS(iface);
1159     return IInternetProtocol_Release(PROTOCOL(This));
1160 }
1161
1162 static HRESULT WINAPI BPServiceProvider_QueryService(IServiceProvider *iface,
1163         REFGUID guidService, REFIID riid, void **ppv)
1164 {
1165     BindProtocol *This = SERVPROV_THIS(iface);
1166
1167     TRACE("(%p)->(%s %s %p)\n", This, debugstr_guid(guidService), debugstr_guid(riid), ppv);
1168
1169     if(!This->service_provider)
1170         return E_NOINTERFACE;
1171
1172     return IServiceProvider_QueryService(This->service_provider, guidService, riid, ppv);
1173 }
1174
1175 #undef SERVPROV_THIS
1176
1177 static const IServiceProviderVtbl ServiceProviderVtbl = {
1178     BPServiceProvider_QueryInterface,
1179     BPServiceProvider_AddRef,
1180     BPServiceProvider_Release,
1181     BPServiceProvider_QueryService
1182 };
1183
1184 HRESULT create_binding_protocol(LPCWSTR url, BOOL from_urlmon, IInternetProtocol **protocol)
1185 {
1186     BindProtocol *ret = heap_alloc_zero(sizeof(BindProtocol));
1187
1188     ret->lpIInternetProtocolVtbl        = &BindProtocolVtbl;
1189     ret->lpInternetBindInfoVtbl         = &InternetBindInfoVtbl;
1190     ret->lpInternetPriorityVtbl         = &InternetPriorityVtbl;
1191     ret->lpServiceProviderVtbl          = &ServiceProviderVtbl;
1192     ret->lpIInternetProtocolSinkVtbl    = &InternetProtocolSinkVtbl;
1193     ret->lpIInternetProtocolHandlerVtbl = &InternetProtocolHandlerVtbl;
1194
1195     ret->ref = 1;
1196     ret->from_urlmon = from_urlmon;
1197     ret->apartment_thread = GetCurrentThreadId();
1198     ret->notif_hwnd = get_notif_hwnd();
1199     ret->protocol_handler = PROTOCOLHANDLER(ret);
1200     InitializeCriticalSection(&ret->section);
1201
1202     URLMON_LockModule();
1203
1204     *protocol = PROTOCOL(ret);
1205     return S_OK;
1206 }