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