winex11: Set the fullscreen state of virtual desktops based on size.
[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
612     TRACE("(%p)->(%p)\n", This, pProtocolData);
613
614     return IInternetProtocol_Continue(This->protocol, pProtocolData);
615 }
616
617 static HRESULT WINAPI ProtocolHandler_Abort(IInternetProtocol *iface, HRESULT hrReason,
618         DWORD dwOptions)
619 {
620     BindProtocol *This = PROTOCOLHANDLER_THIS(iface);
621     FIXME("(%p)->(%08x %08x)\n", This, hrReason, dwOptions);
622     return E_NOTIMPL;
623 }
624
625 static HRESULT WINAPI ProtocolHandler_Terminate(IInternetProtocol *iface, DWORD dwOptions)
626 {
627     BindProtocol *This = PROTOCOLHANDLER_THIS(iface);
628
629     TRACE("(%p)->(%08x)\n", This, dwOptions);
630
631     if(!This->reported_result)
632         return E_FAIL;
633
634     IInternetProtocol_Terminate(This->protocol, 0);
635
636     if(This->filter_proxy) {
637         IInternetProtocol_Release(PROTOCOL(This->filter_proxy));
638         This->filter_proxy = NULL;
639     }
640
641     set_binding_sink(PROTOCOL(This), NULL);
642
643     if(This->bind_info) {
644         IInternetBindInfo_Release(This->bind_info);
645         This->bind_info = NULL;
646     }
647
648     return S_OK;
649 }
650
651 static HRESULT WINAPI ProtocolHandler_Suspend(IInternetProtocol *iface)
652 {
653     BindProtocol *This = PROTOCOLHANDLER_THIS(iface);
654     FIXME("(%p)\n", This);
655     return E_NOTIMPL;
656 }
657
658 static HRESULT WINAPI ProtocolHandler_Resume(IInternetProtocol *iface)
659 {
660     BindProtocol *This = PROTOCOLHANDLER_THIS(iface);
661     FIXME("(%p)\n", This);
662     return E_NOTIMPL;
663 }
664
665 static HRESULT WINAPI ProtocolHandler_Read(IInternetProtocol *iface, void *pv,
666         ULONG cb, ULONG *pcbRead)
667 {
668     BindProtocol *This = PROTOCOLHANDLER_THIS(iface);
669     ULONG read = 0;
670     HRESULT hres = S_OK;
671
672     TRACE("(%p)->(%p %u %p)\n", This, pv, cb, pcbRead);
673
674     if(This->buf) {
675         read = min(cb, This->buf_size);
676         memcpy(pv, This->buf, read);
677
678         if(read == This->buf_size) {
679             heap_free(This->buf);
680             This->buf = NULL;
681         }else {
682             memmove(This->buf, This->buf+cb, This->buf_size-cb);
683         }
684
685         This->buf_size -= read;
686     }
687
688     if(read < cb) {
689         ULONG cread = 0;
690
691         hres = IInternetProtocol_Read(This->protocol, (BYTE*)pv+read, cb-read, &cread);
692         read += cread;
693     }
694
695     *pcbRead = read;
696     return hres;
697 }
698
699 static HRESULT WINAPI ProtocolHandler_Seek(IInternetProtocol *iface, LARGE_INTEGER dlibMove,
700         DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition)
701 {
702     BindProtocol *This = PROTOCOLHANDLER_THIS(iface);
703     FIXME("(%p)->(%d %d %p)\n", This, dlibMove.u.LowPart, dwOrigin, plibNewPosition);
704     return E_NOTIMPL;
705 }
706
707 static HRESULT WINAPI ProtocolHandler_LockRequest(IInternetProtocol *iface, DWORD dwOptions)
708 {
709     BindProtocol *This = PROTOCOLHANDLER_THIS(iface);
710
711     TRACE("(%p)->(%08x)\n", This, dwOptions);
712
713     return IInternetProtocol_LockRequest(This->protocol, dwOptions);
714 }
715
716 static HRESULT WINAPI ProtocolHandler_UnlockRequest(IInternetProtocol *iface)
717 {
718     BindProtocol *This = PROTOCOLHANDLER_THIS(iface);
719
720     TRACE("(%p)\n", This);
721
722     return IInternetProtocol_UnlockRequest(This->protocol);
723 }
724
725 #undef PROTOCOL_THIS
726
727 static const IInternetProtocolVtbl InternetProtocolHandlerVtbl = {
728     ProtocolHandler_QueryInterface,
729     ProtocolHandler_AddRef,
730     ProtocolHandler_Release,
731     ProtocolHandler_Start,
732     ProtocolHandler_Continue,
733     ProtocolHandler_Abort,
734     ProtocolHandler_Terminate,
735     ProtocolHandler_Suspend,
736     ProtocolHandler_Resume,
737     ProtocolHandler_Read,
738     ProtocolHandler_Seek,
739     ProtocolHandler_LockRequest,
740     ProtocolHandler_UnlockRequest
741 };
742
743 #define BINDINFO_THIS(iface) DEFINE_THIS(BindProtocol, InternetBindInfo, iface)
744
745 static HRESULT WINAPI BindInfo_QueryInterface(IInternetBindInfo *iface,
746         REFIID riid, void **ppv)
747 {
748     BindProtocol *This = BINDINFO_THIS(iface);
749     return IInternetProtocol_QueryInterface(PROTOCOL(This), riid, ppv);
750 }
751
752 static ULONG WINAPI BindInfo_AddRef(IInternetBindInfo *iface)
753 {
754     BindProtocol *This = BINDINFO_THIS(iface);
755     return IBinding_AddRef(PROTOCOL(This));
756 }
757
758 static ULONG WINAPI BindInfo_Release(IInternetBindInfo *iface)
759 {
760     BindProtocol *This = BINDINFO_THIS(iface);
761     return IBinding_Release(PROTOCOL(This));
762 }
763
764 static HRESULT WINAPI BindInfo_GetBindInfo(IInternetBindInfo *iface,
765         DWORD *grfBINDF, BINDINFO *pbindinfo)
766 {
767     BindProtocol *This = BINDINFO_THIS(iface);
768     HRESULT hres;
769
770     TRACE("(%p)->(%p %p)\n", This, grfBINDF, pbindinfo);
771
772     hres = IInternetBindInfo_GetBindInfo(This->bind_info, grfBINDF, pbindinfo);
773     if(FAILED(hres)) {
774         WARN("GetBindInfo failed: %08x\n", hres);
775         return hres;
776     }
777
778     *grfBINDF |= BINDF_FROMURLMON;
779     return hres;
780 }
781
782 static HRESULT WINAPI BindInfo_GetBindString(IInternetBindInfo *iface,
783         ULONG ulStringType, LPOLESTR *ppwzStr, ULONG cEl, ULONG *pcElFetched)
784 {
785     BindProtocol *This = BINDINFO_THIS(iface);
786
787     TRACE("(%p)->(%d %p %d %p)\n", This, ulStringType, ppwzStr, cEl, pcElFetched);
788
789     return IInternetBindInfo_GetBindString(This->bind_info, ulStringType, ppwzStr, cEl, pcElFetched);
790 }
791
792 #undef BINDFO_THIS
793
794 static const IInternetBindInfoVtbl InternetBindInfoVtbl = {
795     BindInfo_QueryInterface,
796     BindInfo_AddRef,
797     BindInfo_Release,
798     BindInfo_GetBindInfo,
799     BindInfo_GetBindString
800 };
801
802 #define PRIORITY_THIS(iface) DEFINE_THIS(BindProtocol, InternetPriority, iface)
803
804 static HRESULT WINAPI InternetPriority_QueryInterface(IInternetPriority *iface,
805         REFIID riid, void **ppv)
806 {
807     BindProtocol *This = PRIORITY_THIS(iface);
808     return IInternetProtocol_QueryInterface(PROTOCOL(This), riid, ppv);
809 }
810
811 static ULONG WINAPI InternetPriority_AddRef(IInternetPriority *iface)
812 {
813     BindProtocol *This = PRIORITY_THIS(iface);
814     return IInternetProtocol_AddRef(PROTOCOL(This));
815 }
816
817 static ULONG WINAPI InternetPriority_Release(IInternetPriority *iface)
818 {
819     BindProtocol *This = PRIORITY_THIS(iface);
820     return IInternetProtocol_Release(PROTOCOL(This));
821 }
822
823 static HRESULT WINAPI InternetPriority_SetPriority(IInternetPriority *iface, LONG nPriority)
824 {
825     BindProtocol *This = PRIORITY_THIS(iface);
826
827     TRACE("(%p)->(%d)\n", This, nPriority);
828
829     This->priority = nPriority;
830     return S_OK;
831 }
832
833 static HRESULT WINAPI InternetPriority_GetPriority(IInternetPriority *iface, LONG *pnPriority)
834 {
835     BindProtocol *This = PRIORITY_THIS(iface);
836
837     TRACE("(%p)->(%p)\n", This, pnPriority);
838
839     *pnPriority = This->priority;
840     return S_OK;
841 }
842
843 #undef PRIORITY_THIS
844
845 static const IInternetPriorityVtbl InternetPriorityVtbl = {
846     InternetPriority_QueryInterface,
847     InternetPriority_AddRef,
848     InternetPriority_Release,
849     InternetPriority_SetPriority,
850     InternetPriority_GetPriority
851
852 };
853
854 #define PROTSINK_THIS(iface) DEFINE_THIS(BindProtocol, IInternetProtocolSink, iface)
855
856 static HRESULT WINAPI BPInternetProtocolSink_QueryInterface(IInternetProtocolSink *iface,
857         REFIID riid, void **ppv)
858 {
859     BindProtocol *This = PROTSINK_THIS(iface);
860     return IInternetProtocol_QueryInterface(PROTOCOL(This), riid, ppv);
861 }
862
863 static ULONG WINAPI BPInternetProtocolSink_AddRef(IInternetProtocolSink *iface)
864 {
865     BindProtocol *This = PROTSINK_THIS(iface);
866     return IInternetProtocol_AddRef(PROTOCOL(This));
867 }
868
869 static ULONG WINAPI BPInternetProtocolSink_Release(IInternetProtocolSink *iface)
870 {
871     BindProtocol *This = PROTSINK_THIS(iface);
872     return IInternetProtocol_Release(PROTOCOL(This));
873 }
874
875 typedef struct {
876     task_header_t header;
877     PROTOCOLDATA data;
878 } switch_task_t;
879
880 static void switch_proc(BindProtocol *bind, task_header_t *t)
881 {
882     switch_task_t *task = (switch_task_t*)t;
883
884     IInternetProtocol_Continue(bind->protocol_handler, &task->data);
885
886     heap_free(task);
887 }
888
889 static HRESULT WINAPI BPInternetProtocolSink_Switch(IInternetProtocolSink *iface,
890         PROTOCOLDATA *pProtocolData)
891 {
892     BindProtocol *This = PROTSINK_THIS(iface);
893
894     TRACE("(%p)->(%p)\n", This, pProtocolData);
895
896     TRACE("flags %x state %x data %p cb %u\n", pProtocolData->grfFlags, pProtocolData->dwState,
897           pProtocolData->pData, pProtocolData->cbData);
898
899     if(!do_direct_notif(This)) {
900         switch_task_t *task;
901
902         task = heap_alloc(sizeof(switch_task_t));
903         if(!task)
904             return E_OUTOFMEMORY;
905
906         task->data = *pProtocolData;
907
908         push_task(This, &task->header, switch_proc);
909         return S_OK;
910     }
911
912     if(!This->protocol_sink) {
913         IInternetProtocol_Continue(This->protocol_handler, pProtocolData);
914         return S_OK;
915     }
916
917     return IInternetProtocolSink_Switch(This->protocol_sink, pProtocolData);
918 }
919
920 static void report_progress(BindProtocol *This, ULONG status_code, LPCWSTR status_text)
921 {
922     switch(status_code) {
923     case BINDSTATUS_FINDINGRESOURCE:
924     case BINDSTATUS_CONNECTING:
925     case BINDSTATUS_BEGINDOWNLOADDATA:
926     case BINDSTATUS_SENDINGREQUEST:
927     case BINDSTATUS_CACHEFILENAMEAVAILABLE:
928     case BINDSTATUS_DIRECTBIND:
929     case BINDSTATUS_ACCEPTRANGES:
930         if(This->protocol_sink)
931             IInternetProtocolSink_ReportProgress(This->protocol_sink, status_code, status_text);
932         break;
933
934     case BINDSTATUS_MIMETYPEAVAILABLE:
935         mime_available(This, status_text, FALSE);
936         break;
937
938     case BINDSTATUS_VERIFIEDMIMETYPEAVAILABLE:
939         mime_available(This, status_text, TRUE);
940         break;
941
942     default:
943         FIXME("unsupported ulStatusCode %u\n", status_code);
944     }
945 }
946
947 typedef struct {
948     task_header_t header;
949
950     ULONG status_code;
951     LPWSTR status_text;
952 } on_progress_task_t;
953
954 static void on_progress_proc(BindProtocol *This, task_header_t *t)
955 {
956     on_progress_task_t *task = (on_progress_task_t*)t;
957
958     report_progress(This, task->status_code, task->status_text);
959
960     heap_free(task->status_text);
961     heap_free(task);
962 }
963
964 static HRESULT WINAPI BPInternetProtocolSink_ReportProgress(IInternetProtocolSink *iface,
965         ULONG ulStatusCode, LPCWSTR szStatusText)
966 {
967     BindProtocol *This = PROTSINK_THIS(iface);
968
969     TRACE("(%p)->(%u %s)\n", This, ulStatusCode, debugstr_w(szStatusText));
970
971     if(do_direct_notif(This)) {
972         report_progress(This, ulStatusCode, szStatusText);
973     }else {
974         on_progress_task_t *task;
975
976         task = heap_alloc(sizeof(on_progress_task_t));
977
978         task->status_code = ulStatusCode;
979         task->status_text = heap_strdupW(szStatusText);
980
981         push_task(This, &task->header, on_progress_proc);
982     }
983
984     return S_OK;
985 }
986
987 static HRESULT report_data(BindProtocol *This, DWORD bscf, ULONG progress, ULONG progress_max)
988 {
989     if(!This->protocol_sink)
990         return S_OK;
991
992     if((This->pi & PI_MIMEVERIFICATION) && !This->reported_mime) {
993         DWORD read = 0;
994         LPWSTR mime;
995         HRESULT hres;
996
997         if(!This->buf) {
998             This->buf = heap_alloc(BUFFER_SIZE);
999             if(!This->buf)
1000                 return E_OUTOFMEMORY;
1001         }
1002
1003         do {
1004             read = 0;
1005             hres = IInternetProtocol_Read(This->protocol, This->buf+This->buf_size,
1006                     BUFFER_SIZE-This->buf_size, &read);
1007             if(FAILED(hres) && hres != E_PENDING)
1008                 return hres;
1009             This->buf_size += read;
1010         }while(This->buf_size < MIME_TEST_SIZE && hres == S_OK);
1011
1012         if(This->buf_size < MIME_TEST_SIZE && hres != S_FALSE)
1013             return S_OK;
1014
1015         hres = FindMimeFromData(NULL, This->url, This->buf, min(This->buf_size, MIME_TEST_SIZE),
1016                 This->mime, 0, &mime, 0);
1017         if(FAILED(hres))
1018             return hres;
1019
1020         mime_available(This, mime, TRUE);
1021         CoTaskMemFree(mime);
1022     }
1023
1024     return IInternetProtocolSink_ReportData(This->protocol_sink, bscf, progress, progress_max);
1025 }
1026
1027 typedef struct {
1028     task_header_t header;
1029     DWORD bscf;
1030     ULONG progress;
1031     ULONG progress_max;
1032 } report_data_task_t;
1033
1034 static void report_data_proc(BindProtocol *This, task_header_t *t)
1035 {
1036     report_data_task_t *task = (report_data_task_t*)t;
1037
1038     report_data(This, task->bscf, task->progress, task->progress_max);
1039     heap_free(task);
1040 }
1041
1042 static HRESULT WINAPI BPInternetProtocolSink_ReportData(IInternetProtocolSink *iface,
1043         DWORD grfBSCF, ULONG ulProgress, ULONG ulProgressMax)
1044 {
1045     BindProtocol *This = PROTSINK_THIS(iface);
1046
1047     TRACE("(%p)->(%d %u %u)\n", This, grfBSCF, ulProgress, ulProgressMax);
1048
1049     if(!This->protocol_sink)
1050         return S_OK;
1051
1052     if(!do_direct_notif(This)) {
1053         report_data_task_t *task;
1054
1055         task = heap_alloc(sizeof(report_data_task_t));
1056         if(!task)
1057             return E_OUTOFMEMORY;
1058
1059         task->bscf = grfBSCF;
1060         task->progress = ulProgress;
1061         task->progress_max = ulProgressMax;
1062
1063         push_task(This, &task->header, report_data_proc);
1064         return S_OK;
1065     }
1066
1067     return report_data(This, grfBSCF, ulProgress, ulProgressMax);
1068 }
1069
1070 typedef struct {
1071     task_header_t header;
1072
1073     HRESULT hres;
1074     DWORD err;
1075     LPWSTR str;
1076 } report_result_task_t;
1077
1078 static void report_result_proc(BindProtocol *This, task_header_t *t)
1079 {
1080     report_result_task_t *task = (report_result_task_t*)t;
1081
1082     if(This->protocol_sink)
1083         IInternetProtocolSink_ReportResult(This->protocol_sink, task->hres, task->err, task->str);
1084
1085     heap_free(task->str);
1086     heap_free(task);
1087 }
1088
1089 static HRESULT WINAPI BPInternetProtocolSink_ReportResult(IInternetProtocolSink *iface,
1090         HRESULT hrResult, DWORD dwError, LPCWSTR szResult)
1091 {
1092     BindProtocol *This = PROTSINK_THIS(iface);
1093
1094     TRACE("(%p)->(%08x %d %s)\n", This, hrResult, dwError, debugstr_w(szResult));
1095
1096     if(!This->protocol_sink)
1097         return E_FAIL;
1098
1099     This->reported_result = TRUE;
1100
1101     if(!do_direct_notif(This)) {
1102         report_result_task_t *task;
1103
1104         task = heap_alloc(sizeof(report_result_task_t));
1105         if(!task)
1106             return E_OUTOFMEMORY;
1107
1108         task->hres = hrResult;
1109         task->err = dwError;
1110         task->str = heap_strdupW(szResult);
1111
1112         push_task(This, &task->header, report_result_proc);
1113         return S_OK;
1114     }
1115
1116     return IInternetProtocolSink_ReportResult(This->protocol_sink, hrResult, dwError, szResult);
1117 }
1118
1119 #undef PROTSINK_THIS
1120
1121 static const IInternetProtocolSinkVtbl InternetProtocolSinkVtbl = {
1122     BPInternetProtocolSink_QueryInterface,
1123     BPInternetProtocolSink_AddRef,
1124     BPInternetProtocolSink_Release,
1125     BPInternetProtocolSink_Switch,
1126     BPInternetProtocolSink_ReportProgress,
1127     BPInternetProtocolSink_ReportData,
1128     BPInternetProtocolSink_ReportResult
1129 };
1130
1131 #define SERVPROV_THIS(iface) DEFINE_THIS(BindProtocol, ServiceProvider, iface)
1132
1133 static HRESULT WINAPI BPServiceProvider_QueryInterface(IServiceProvider *iface,
1134         REFIID riid, void **ppv)
1135 {
1136     BindProtocol *This = SERVPROV_THIS(iface);
1137     return IInternetProtocol_QueryInterface(PROTOCOL(This), riid, ppv);
1138 }
1139
1140 static ULONG WINAPI BPServiceProvider_AddRef(IServiceProvider *iface)
1141 {
1142     BindProtocol *This = SERVPROV_THIS(iface);
1143     return IInternetProtocol_AddRef(PROTOCOL(This));
1144 }
1145
1146 static ULONG WINAPI BPServiceProvider_Release(IServiceProvider *iface)
1147 {
1148     BindProtocol *This = SERVPROV_THIS(iface);
1149     return IInternetProtocol_Release(PROTOCOL(This));
1150 }
1151
1152 static HRESULT WINAPI BPServiceProvider_QueryService(IServiceProvider *iface,
1153         REFGUID guidService, REFIID riid, void **ppv)
1154 {
1155     BindProtocol *This = SERVPROV_THIS(iface);
1156
1157     TRACE("(%p)->(%s %s %p)\n", This, debugstr_guid(guidService), debugstr_guid(riid), ppv);
1158
1159     if(!This->service_provider)
1160         return E_NOINTERFACE;
1161
1162     return IServiceProvider_QueryService(This->service_provider, guidService, riid, ppv);
1163 }
1164
1165 #undef SERVPROV_THIS
1166
1167 static const IServiceProviderVtbl ServiceProviderVtbl = {
1168     BPServiceProvider_QueryInterface,
1169     BPServiceProvider_AddRef,
1170     BPServiceProvider_Release,
1171     BPServiceProvider_QueryService
1172 };
1173
1174 HRESULT create_binding_protocol(LPCWSTR url, BOOL from_urlmon, IInternetProtocol **protocol)
1175 {
1176     BindProtocol *ret = heap_alloc_zero(sizeof(BindProtocol));
1177
1178     ret->lpIInternetProtocolVtbl        = &BindProtocolVtbl;
1179     ret->lpInternetBindInfoVtbl         = &InternetBindInfoVtbl;
1180     ret->lpInternetPriorityVtbl         = &InternetPriorityVtbl;
1181     ret->lpServiceProviderVtbl          = &ServiceProviderVtbl;
1182     ret->lpIInternetProtocolSinkVtbl    = &InternetProtocolSinkVtbl;
1183     ret->lpIInternetProtocolHandlerVtbl = &InternetProtocolHandlerVtbl;
1184
1185     ret->ref = 1;
1186     ret->from_urlmon = from_urlmon;
1187     ret->apartment_thread = GetCurrentThreadId();
1188     ret->notif_hwnd = get_notif_hwnd();
1189     ret->protocol_handler = PROTOCOLHANDLER(ret);
1190     InitializeCriticalSection(&ret->section);
1191
1192     URLMON_LockModule();
1193
1194     *protocol = PROTOCOL(ret);
1195     return S_OK;
1196 }