urlmon: Added application/pdf mime filter.
[wine] / dlls / urlmon / binding.c
1 /*
2  * Copyright 2005 Jacek Caban
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 <stdarg.h>
20
21 #define COBJMACROS
22 #define NONAMELESSUNION
23 #define NONAMELESSSTRUCT
24
25 #include "windef.h"
26 #include "winbase.h"
27 #include "winuser.h"
28 #include "ole2.h"
29 #include "urlmon.h"
30 #include "urlmon_main.h"
31
32 #include "wine/debug.h"
33 #include "wine/unicode.h"
34
35 WINE_DEFAULT_DEBUG_CHANNEL(urlmon);
36
37 typedef struct Binding Binding;
38
39 enum task_enum {
40     TASK_ON_PROGRESS,
41     TASK_SWITCH,
42     TASK_DATA_AVAILABLE
43 };
44
45 typedef struct {
46     Binding *binding;
47     ULONG progress;
48     ULONG progress_max;
49     ULONG status_code;
50     LPWSTR status_text;
51 } on_progress_data;
52
53 typedef struct _task_t {
54     enum task_enum task;
55     struct _task_t *next;
56     union {
57         on_progress_data on_progress;
58         PROTOCOLDATA *protocol_data;
59         DWORD bscf;
60     } data;
61 } task_t;
62
63 typedef struct {
64     const IStreamVtbl *lpStreamVtbl;
65
66     LONG ref;
67
68     IInternetProtocol *protocol;
69
70     BYTE buf[1024*8];
71     DWORD buf_size;
72     BOOL init_buf;
73 } ProtocolStream;
74
75 struct Binding {
76     const IBindingVtbl               *lpBindingVtbl;
77     const IInternetProtocolSinkVtbl  *lpInternetProtocolSinkVtbl;
78     const IInternetBindInfoVtbl      *lpInternetBindInfoVtbl;
79     const IServiceProviderVtbl       *lpServiceProviderVtbl;
80
81     LONG ref;
82
83     IBindStatusCallback *callback;
84     IInternetProtocol *protocol;
85     IServiceProvider *service_provider;
86     ProtocolStream *stream;
87
88     BINDINFO bindinfo;
89     DWORD bindf;
90     LPWSTR mime;
91     LPWSTR url;
92     BOOL verified_mime;
93     DWORD continue_call;
94
95     DWORD apartment_thread;
96     HWND notif_hwnd;
97
98     STGMEDIUM stgmed;
99
100     task_t *task_queue_head, *task_queue_tail;
101     CRITICAL_SECTION section;
102 };
103
104 #define BINDING(x)   ((IBinding*)               &(x)->lpBindingVtbl)
105 #define PROTSINK(x)  ((IInternetProtocolSink*)  &(x)->lpInternetProtocolSinkVtbl)
106 #define BINDINF(x)   ((IInternetBindInfo*)      &(x)->lpInternetBindInfoVtbl)
107 #define SERVPROV(x)  ((IServiceProvider*)       &(x)->lpServiceProviderVtbl)
108
109 #define STREAM(x) ((IStream*) &(x)->lpStreamVtbl)
110
111 #define WM_MK_CONTINUE   (WM_USER+101)
112
113 static void push_task(Binding *binding, task_t *task)
114 {
115     task->next = NULL;
116
117      EnterCriticalSection(&binding->section);
118
119     if(binding->task_queue_tail)
120         binding->task_queue_tail->next = task;
121     else
122         binding->task_queue_tail = binding->task_queue_head = task;
123
124     LeaveCriticalSection(&binding->section);
125 }
126
127 static task_t *pop_task(Binding *binding)
128 {
129     task_t *ret;
130
131      EnterCriticalSection(&binding->section);
132
133      ret = binding->task_queue_head;
134      if(ret) {
135          binding->task_queue_head = ret->next;
136          if(!binding->task_queue_head)
137              binding->task_queue_tail = NULL;
138      }
139
140      LeaveCriticalSection(&binding->section);
141
142      return ret;
143 }
144
145 static void fill_stream_buffer(ProtocolStream *This)
146 {
147     DWORD read = 0;
148     HRESULT hres;
149
150     if(sizeof(This->buf) == This->buf_size)
151         return;
152
153     hres = IInternetProtocol_Read(This->protocol, This->buf+This->buf_size,
154                                   sizeof(This->buf)-This->buf_size, &read);
155     if(SUCCEEDED(hres)) {
156         This->buf_size += read;
157         This->init_buf = TRUE;
158     }
159 }
160
161 static void on_data_available(Binding *binding, DWORD bscf)
162 {
163     FORMATETC formatetc = {0, NULL, 1, -1, TYMED_ISTREAM};
164
165     if(GetCurrentThreadId() != binding->apartment_thread)
166         FIXME("called from worked hread\n");
167
168     if(binding->continue_call) {
169         task_t *task = HeapAlloc(GetProcessHeap(), 0, sizeof(task_t));
170         task->task = TASK_DATA_AVAILABLE;
171         task->data.bscf = bscf;
172
173         push_task(binding, task);
174
175         return;
176     }
177
178     fill_stream_buffer(binding->stream);
179
180     IBindStatusCallback_OnDataAvailable(binding->callback, bscf, binding->stream->buf_size,
181             &formatetc, &binding->stgmed);
182 }
183
184
185 static void do_task(Binding *binding, task_t *task)
186 {
187     switch(task->task) {
188     case TASK_ON_PROGRESS: {
189         on_progress_data *data = &task->data.on_progress;
190
191         IBindStatusCallback_OnProgress(binding->callback, data->progress,
192                 data->progress_max, data->status_code, data->status_text);
193
194         HeapFree(GetProcessHeap(), 0, data->status_text);
195         HeapFree(GetProcessHeap(), 0, data);
196
197         break;
198     }
199     case TASK_SWITCH:
200         binding->continue_call++;
201         IInternetProtocol_Continue(binding->protocol, task->data.protocol_data);
202         binding->continue_call--;
203
204         break;
205     case TASK_DATA_AVAILABLE:
206         on_data_available(binding, task->data.bscf);
207     }
208 }
209
210 static void do_tasks(Binding *This)
211 {
212     task_t *task;
213
214     while((task = pop_task(This)))
215         do_task(This, task);
216 }
217
218 static LRESULT WINAPI notif_wnd_proc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
219 {
220     if(msg == WM_MK_CONTINUE) {
221         Binding *binding = (Binding*)lParam;
222
223         do_tasks(binding);
224
225         IBinding_Release(BINDING(binding));
226         return 0;
227     }
228
229     return DefWindowProcW(hwnd, msg, wParam, lParam);
230 }
231
232 static HWND get_notif_hwnd(void)
233 {
234     static ATOM wnd_class = 0;
235     HWND hwnd;
236
237     static const WCHAR wszURLMonikerNotificationWindow[] =
238         {'U','R','L',' ','M','o','n','i','k','e','r',' ',
239          'N','o','t','i','f','i','c','a','t','i','o','n',' ','W','i','n','d','o','w',0};
240
241     if(!wnd_class) {
242         static WNDCLASSEXW wndclass = {
243             sizeof(wndclass), 0,
244             notif_wnd_proc, 0, 0,
245             NULL, NULL, NULL, NULL, NULL,
246             wszURLMonikerNotificationWindow,
247             NULL        
248         };
249
250         wndclass.hInstance = URLMON_hInstance;
251
252         wnd_class = RegisterClassExW(&wndclass);
253         if (!wnd_class && GetLastError() == ERROR_CLASS_ALREADY_EXISTS)
254             wnd_class = 1;
255     }
256
257     hwnd = CreateWindowExW(0, wszURLMonikerNotificationWindow,
258                            wszURLMonikerNotificationWindow, 0, 0, 0, 0, 0, HWND_MESSAGE,
259                            NULL, URLMON_hInstance, NULL);
260
261     TRACE("hwnd = %p\n", hwnd);
262
263     return hwnd;
264 }
265
266 static void on_progress(Binding *This, ULONG progress, ULONG progress_max,
267                         ULONG status_code, LPCWSTR status_text)
268 {
269     task_t *task;
270
271     if(GetCurrentThreadId() == This->apartment_thread && !This->continue_call) {
272         IBindStatusCallback_OnProgress(This->callback, progress, progress_max,
273                                        status_code, status_text);
274         return;
275     }
276
277     task = HeapAlloc(GetProcessHeap(), 0, sizeof(task_t));
278
279     task->task = TASK_ON_PROGRESS;
280     task->data.on_progress.progress = progress;
281     task->data.on_progress.progress_max = progress_max;
282     task->data.on_progress.status_code = status_code;
283
284     if(status_text) {
285         DWORD size = (strlenW(status_text)+1)*sizeof(WCHAR);
286
287         task->data.on_progress.status_text = HeapAlloc(GetProcessHeap(), 0, size);
288         memcpy(task->data.on_progress.status_text, status_text, size);
289     }else {
290         task->data.on_progress.status_text = NULL;
291     }
292
293     push_task(This, task);
294
295     if(GetCurrentThreadId() != This->apartment_thread) {
296         IBinding_AddRef(BINDING(This));
297         PostMessageW(This->notif_hwnd, WM_MK_CONTINUE, 0, (LPARAM)This);
298     }
299 }
300
301 static void dump_BINDINFO(BINDINFO *bi)
302 {
303     static const char * const BINDINFOF_str[] = {
304         "#0",
305         "BINDINFOF_URLENCODESTGMEDDATA",
306         "BINDINFOF_URLENCODEDEXTRAINFO"
307     };
308
309     static const char * const BINDVERB_str[] = {
310         "BINDVERB_GET",
311         "BINDVERB_POST",
312         "BINDVERB_PUT",
313         "BINDVERB_CUSTOM"
314     };
315
316     TRACE("\n"
317             "BINDINFO = {\n"
318             "    %d, %s,\n"
319             "    {%d, %p, %p},\n"
320             "    %s,\n"
321             "    %s,\n"
322             "    %s,\n"
323             "    %d, %08x, %d, %d\n"
324             "    {%d %p %x},\n"
325             "    %s\n"
326             "    %p, %d\n"
327             "}\n",
328
329             bi->cbSize, debugstr_w(bi->szExtraInfo),
330             bi->stgmedData.tymed, bi->stgmedData.u.hGlobal, bi->stgmedData.pUnkForRelease,
331             bi->grfBindInfoF > BINDINFOF_URLENCODEDEXTRAINFO
332                 ? "unknown" : BINDINFOF_str[bi->grfBindInfoF],
333             bi->dwBindVerb > BINDVERB_CUSTOM
334                 ? "unknown" : BINDVERB_str[bi->dwBindVerb],
335             debugstr_w(bi->szCustomVerb),
336             bi->cbstgmedData, bi->dwOptions, bi->dwOptionsFlags, bi->dwCodePage,
337             bi->securityAttributes.nLength,
338             bi->securityAttributes.lpSecurityDescriptor,
339             bi->securityAttributes.bInheritHandle,
340             debugstr_guid(&bi->iid),
341             bi->pUnk, bi->dwReserved
342             );
343 }
344
345 static HRESULT WINAPI HttpNegotiate_QueryInterface(IHttpNegotiate2 *iface,
346                                                    REFIID riid, void **ppv)
347 {
348     *ppv = NULL;
349
350     if(IsEqualGUID(&IID_IUnknown, riid)) {
351         TRACE("(IID_IUnknown %p)\n", ppv);
352         *ppv = iface;
353     }else if(IsEqualGUID(&IID_IHttpNegotiate, riid)) {
354         TRACE("(IID_IHttpNegotiate %p)\n", ppv);
355         *ppv = iface;
356     }else if(IsEqualGUID(&IID_IHttpNegotiate2, riid)) {
357         TRACE("(IID_IHttpNegotiate2 %p)\n", ppv);
358         *ppv = iface;
359     }
360
361     if(*ppv) {
362         IHttpNegotiate2_AddRef(iface);
363         return S_OK;
364     }
365
366     WARN("Unsupported interface %s\n", debugstr_guid(riid));
367     return E_NOINTERFACE;
368 }
369
370 static ULONG WINAPI HttpNegotiate_AddRef(IHttpNegotiate2 *iface)
371 {
372     URLMON_LockModule();
373     return 2;
374 }
375
376 static ULONG WINAPI HttpNegotiate_Release(IHttpNegotiate2 *iface)
377 {
378     URLMON_UnlockModule();
379     return 1;
380 }
381
382 static HRESULT WINAPI HttpNegotiate_BeginningTransaction(IHttpNegotiate2 *iface,
383         LPCWSTR szURL, LPCWSTR szHeaders, DWORD dwReserved, LPWSTR *pszAdditionalHeaders)
384 {
385     TRACE("(%s %s %d %p)\n", debugstr_w(szURL), debugstr_w(szHeaders), dwReserved,
386           pszAdditionalHeaders);
387
388     *pszAdditionalHeaders = NULL;
389     return S_OK;
390 }
391
392 static HRESULT WINAPI HttpNegotiate_OnResponse(IHttpNegotiate2 *iface, DWORD dwResponseCode,
393         LPCWSTR szResponseHeaders, LPCWSTR szRequestHeaders,
394         LPWSTR *pszAdditionalRequestHeaders)
395 {
396     TRACE("(%d %s %s %p)\n", dwResponseCode, debugstr_w(szResponseHeaders),
397           debugstr_w(szRequestHeaders), pszAdditionalRequestHeaders);
398
399     if(pszAdditionalRequestHeaders)
400         *pszAdditionalRequestHeaders = NULL;
401     return S_OK;
402 }
403
404 static HRESULT WINAPI HttpNegotiate_GetRootSecurityId(IHttpNegotiate2 *iface,
405         BYTE *pbSecurityId, DWORD *pcbSecurityId, DWORD_PTR dwReserved)
406 {
407     TRACE("(%p %p %ld)\n", pbSecurityId, pcbSecurityId, dwReserved);
408
409     /* That's all we have to do here */
410     return E_FAIL;
411 }
412
413 static const IHttpNegotiate2Vtbl HttpNegotiate2Vtbl = {
414     HttpNegotiate_QueryInterface,
415     HttpNegotiate_AddRef,
416     HttpNegotiate_Release,
417     HttpNegotiate_BeginningTransaction,
418     HttpNegotiate_OnResponse,
419     HttpNegotiate_GetRootSecurityId
420 };
421
422 static IHttpNegotiate2 HttpNegotiate = { &HttpNegotiate2Vtbl };
423
424 #define STREAM_THIS(iface) DEFINE_THIS(ProtocolStream, Stream, iface)
425
426 static HRESULT WINAPI ProtocolStream_QueryInterface(IStream *iface,
427                                                           REFIID riid, void **ppv)
428 {
429     ProtocolStream *This = STREAM_THIS(iface);
430
431     *ppv = NULL;
432
433     if(IsEqualGUID(&IID_IUnknown, riid)) {
434         TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
435         *ppv = STREAM(This);
436     }else if(IsEqualGUID(&IID_ISequentialStream, riid)) {
437         TRACE("(%p)->(IID_ISequentialStream %p)\n", This, ppv);
438         *ppv = STREAM(This);
439     }else if(IsEqualGUID(&IID_IStream, riid)) {
440         TRACE("(%p)->(IID_IStream %p)\n", This, ppv);
441         *ppv = STREAM(This);
442     }
443
444     if(*ppv) {
445         IStream_AddRef(STREAM(This));
446         return S_OK;
447     }
448
449     WARN("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
450     return E_NOINTERFACE;
451 }
452
453 static ULONG WINAPI ProtocolStream_AddRef(IStream *iface)
454 {
455     ProtocolStream *This = STREAM_THIS(iface);
456     LONG ref = InterlockedIncrement(&This->ref);
457
458     TRACE("(%p) ref=%d\n", This, ref);
459
460     return ref;
461 }
462
463 static ULONG WINAPI ProtocolStream_Release(IStream *iface)
464 {
465     ProtocolStream *This = STREAM_THIS(iface);
466     LONG ref = InterlockedDecrement(&This->ref);
467
468     TRACE("(%p) ref=%d\n", This, ref);
469
470     if(!ref) {
471         IInternetProtocol_Release(This->protocol);
472         HeapFree(GetProcessHeap(), 0, This);
473
474         URLMON_UnlockModule();
475     }
476
477     return ref;
478 }
479
480 static HRESULT WINAPI ProtocolStream_Read(IStream *iface, void *pv,
481                                          ULONG cb, ULONG *pcbRead)
482 {
483     ProtocolStream *This = STREAM_THIS(iface);
484     DWORD read = 0, pread = 0;
485     HRESULT hres;
486
487     TRACE("(%p)->(%p %d %p)\n", This, pv, cb, pcbRead);
488
489     if(This->buf_size) {
490         read = cb;
491
492         if(read > This->buf_size)
493             read = This->buf_size;
494
495         memcpy(pv, This->buf, read);
496
497         if(read < This->buf_size)
498             memmove(This->buf, This->buf+read, This->buf_size-read);
499         This->buf_size -= read;
500     }
501
502     if(read == cb) {
503         *pcbRead = read;
504         return S_OK;
505     }
506
507     hres = IInternetProtocol_Read(This->protocol, (PBYTE)pv+read, cb-read, &pread);
508     *pcbRead = read + pread;
509
510     if(hres == E_PENDING)
511         return E_PENDING;
512     else if(FAILED(hres))
513         FIXME("Read failed: %08x\n", hres);
514
515     return read || pread ? S_OK : S_FALSE;
516 }
517
518 static HRESULT WINAPI ProtocolStream_Write(IStream *iface, const void *pv,
519                                           ULONG cb, ULONG *pcbWritten)
520 {
521     ProtocolStream *This = STREAM_THIS(iface);
522
523     TRACE("(%p)->(%p %d %p)\n", This, pv, cb, pcbWritten);
524
525     return STG_E_ACCESSDENIED;
526 }
527
528 static HRESULT WINAPI ProtocolStream_Seek(IStream *iface, LARGE_INTEGER dlibMove,
529                                          DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition)
530 {
531     ProtocolStream *This = STREAM_THIS(iface);
532     FIXME("(%p)->(%d %08x %p)\n", This, dlibMove.u.LowPart, dwOrigin, plibNewPosition);
533     return E_NOTIMPL;
534 }
535
536 static HRESULT WINAPI ProtocolStream_SetSize(IStream *iface, ULARGE_INTEGER libNewSize)
537 {
538     ProtocolStream *This = STREAM_THIS(iface);
539     FIXME("(%p)->(%d)\n", This, libNewSize.u.LowPart);
540     return E_NOTIMPL;
541 }
542
543 static HRESULT WINAPI ProtocolStream_CopyTo(IStream *iface, IStream *pstm,
544         ULARGE_INTEGER cb, ULARGE_INTEGER *pcbRead, ULARGE_INTEGER *pcbWritten)
545 {
546     ProtocolStream *This = STREAM_THIS(iface);
547     FIXME("(%p)->(%p %d %p %p)\n", This, pstm, cb.u.LowPart, pcbRead, pcbWritten);
548     return E_NOTIMPL;
549 }
550
551 static HRESULT WINAPI ProtocolStream_Commit(IStream *iface, DWORD grfCommitFlags)
552 {
553     ProtocolStream *This = STREAM_THIS(iface);
554
555     TRACE("(%p)->(%08x)\n", This, grfCommitFlags);
556
557     return E_NOTIMPL;
558 }
559
560 static HRESULT WINAPI ProtocolStream_Revert(IStream *iface)
561 {
562     ProtocolStream *This = STREAM_THIS(iface);
563
564     TRACE("(%p)\n", This);
565
566     return E_NOTIMPL;
567 }
568
569 static HRESULT WINAPI ProtocolStream_LockRegion(IStream *iface, ULARGE_INTEGER libOffset,
570                                                ULARGE_INTEGER cb, DWORD dwLockType)
571 {
572     ProtocolStream *This = STREAM_THIS(iface);
573     FIXME("(%p)->(%d %d %d)\n", This, libOffset.u.LowPart, cb.u.LowPart, dwLockType);
574     return E_NOTIMPL;
575 }
576
577 static HRESULT WINAPI ProtocolStream_UnlockRegion(IStream *iface,
578         ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType)
579 {
580     ProtocolStream *This = STREAM_THIS(iface);
581     FIXME("(%p)->(%d %d %d)\n", This, libOffset.u.LowPart, cb.u.LowPart, dwLockType);
582     return E_NOTIMPL;
583 }
584
585 static HRESULT WINAPI ProtocolStream_Stat(IStream *iface, STATSTG *pstatstg,
586                                          DWORD dwStatFlag)
587 {
588     ProtocolStream *This = STREAM_THIS(iface);
589     FIXME("(%p)->(%p %08x)\n", This, pstatstg, dwStatFlag);
590     return E_NOTIMPL;
591 }
592
593 static HRESULT WINAPI ProtocolStream_Clone(IStream *iface, IStream **ppstm)
594 {
595     ProtocolStream *This = STREAM_THIS(iface);
596     FIXME("(%p)->(%p)\n", This, ppstm);
597     return E_NOTIMPL;
598 }
599
600 #undef STREAM_THIS
601
602 static const IStreamVtbl ProtocolStreamVtbl = {
603     ProtocolStream_QueryInterface,
604     ProtocolStream_AddRef,
605     ProtocolStream_Release,
606     ProtocolStream_Read,
607     ProtocolStream_Write,
608     ProtocolStream_Seek,
609     ProtocolStream_SetSize,
610     ProtocolStream_CopyTo,
611     ProtocolStream_Commit,
612     ProtocolStream_Revert,
613     ProtocolStream_LockRegion,
614     ProtocolStream_UnlockRegion,
615     ProtocolStream_Stat,
616     ProtocolStream_Clone
617 };
618
619 #define BINDING_THIS(iface) DEFINE_THIS(Binding, Binding, iface)
620
621 static ProtocolStream *create_stream(IInternetProtocol *protocol)
622 {
623     ProtocolStream *ret = HeapAlloc(GetProcessHeap(), 0, sizeof(ProtocolStream));
624
625     ret->lpStreamVtbl = &ProtocolStreamVtbl;
626     ret->ref = 1;
627     ret->buf_size = 0;
628     ret->init_buf = FALSE;
629
630     IInternetProtocol_AddRef(protocol);
631     ret->protocol = protocol;
632
633     URLMON_LockModule();
634
635     return ret;
636 }
637
638 static HRESULT WINAPI Binding_QueryInterface(IBinding *iface, REFIID riid, void **ppv)
639 {
640     Binding *This = BINDING_THIS(iface);
641
642     *ppv = NULL;
643
644     if(IsEqualGUID(&IID_IUnknown, riid)) {
645         TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
646         *ppv = BINDING(This);
647     }else if(IsEqualGUID(&IID_IBinding, riid)) {
648         TRACE("(%p)->(IID_IBinding %p)\n", This, ppv);
649         *ppv = BINDING(This);
650     }else if(IsEqualGUID(&IID_IInternetProtocolSink, riid)) {
651         TRACE("(%p)->(IID_IInternetProtocolSink %p)\n", This, ppv);
652         *ppv = PROTSINK(This);
653     }else if(IsEqualGUID(&IID_IInternetBindInfo, riid)) {
654         TRACE("(%p)->(IID_IInternetBindInfo %p)\n", This, ppv);
655         *ppv = BINDINF(This);
656     }else if(IsEqualGUID(&IID_IServiceProvider, riid)) {
657         TRACE("(%p)->(IID_IServiceProvider %p)\n", This, ppv);
658         *ppv = SERVPROV(This);
659     }
660
661     if(*ppv) {
662         IBinding_AddRef(BINDING(This));
663         return S_OK;
664     }
665
666     WARN("Unsupported interface %s\n", debugstr_guid(riid));
667     return E_NOINTERFACE;
668 }
669
670 static ULONG WINAPI Binding_AddRef(IBinding *iface)
671 {
672     Binding *This = BINDING_THIS(iface);
673     LONG ref = InterlockedIncrement(&This->ref);
674
675     TRACE("(%p) ref=%d\n", This, ref);
676
677     return ref;
678 }
679
680 static ULONG WINAPI Binding_Release(IBinding *iface)
681 {
682     Binding *This = BINDING_THIS(iface);
683     LONG ref = InterlockedDecrement(&This->ref);
684
685     TRACE("(%p) ref=%d\n", This, ref);
686
687     if(!ref) {
688         if (This->notif_hwnd)
689             DestroyWindow( This->notif_hwnd );
690         if(This->callback)
691             IBindStatusCallback_Release(This->callback);
692         if(This->protocol)
693             IInternetProtocol_Release(This->protocol);
694         if(This->service_provider)
695             IServiceProvider_Release(This->service_provider);
696         if(This->stream)
697             IStream_Release(STREAM(This->stream));
698
699         ReleaseBindInfo(&This->bindinfo);
700         DeleteCriticalSection(&This->section);
701         HeapFree(GetProcessHeap(), 0, This->mime);
702         HeapFree(GetProcessHeap(), 0, This->url);
703
704         HeapFree(GetProcessHeap(), 0, This);
705
706         URLMON_UnlockModule();
707     }
708
709     return ref;
710 }
711
712 static HRESULT WINAPI Binding_Abort(IBinding *iface)
713 {
714     Binding *This = BINDING_THIS(iface);
715     FIXME("(%p)\n", This);
716     return E_NOTIMPL;
717 }
718
719 static HRESULT WINAPI Binding_Suspend(IBinding *iface)
720 {
721     Binding *This = BINDING_THIS(iface);
722     FIXME("(%p)\n", This);
723     return E_NOTIMPL;
724 }
725
726 static HRESULT WINAPI Binding_Resume(IBinding *iface)
727 {
728     Binding *This = BINDING_THIS(iface);
729     FIXME("(%p)\n", This);
730     return E_NOTIMPL;
731 }
732
733 static HRESULT WINAPI Binding_SetPriority(IBinding *iface, LONG nPriority)
734 {
735     Binding *This = BINDING_THIS(iface);
736     FIXME("(%p)->(%d)\n", This, nPriority);
737     return E_NOTIMPL;
738 }
739
740 static HRESULT WINAPI Binding_GetPriority(IBinding *iface, LONG *pnPriority)
741 {
742     Binding *This = BINDING_THIS(iface);
743     FIXME("(%p)->(%p)\n", This, pnPriority);
744     return E_NOTIMPL;
745 }
746
747 static HRESULT WINAPI Binding_GetBindResult(IBinding *iface, CLSID *pclsidProtocol,
748         DWORD *pdwResult, LPOLESTR *pszResult, DWORD *pdwReserved)
749 {
750     Binding *This = BINDING_THIS(iface);
751     FIXME("(%p)->(%p %p %p %p)\n", This, pclsidProtocol, pdwResult, pszResult, pdwReserved);
752     return E_NOTIMPL;
753 }
754
755 #undef BINDING_THIS
756
757 static const IBindingVtbl BindingVtbl = {
758     Binding_QueryInterface,
759     Binding_AddRef,
760     Binding_Release,
761     Binding_Abort,
762     Binding_Suspend,
763     Binding_Resume,
764     Binding_SetPriority,
765     Binding_GetPriority,
766     Binding_GetBindResult
767 };
768
769 #define PROTSINK_THIS(iface) DEFINE_THIS(Binding, InternetProtocolSink, iface)
770
771 static HRESULT WINAPI InternetProtocolSink_QueryInterface(IInternetProtocolSink *iface,
772         REFIID riid, void **ppv)
773 {
774     Binding *This = PROTSINK_THIS(iface);
775     return IBinding_QueryInterface(BINDING(This), riid, ppv);
776 }
777
778 static ULONG WINAPI InternetProtocolSink_AddRef(IInternetProtocolSink *iface)
779 {
780     Binding *This = PROTSINK_THIS(iface);
781     return IBinding_AddRef(BINDING(This));
782 }
783
784 static ULONG WINAPI InternetProtocolSink_Release(IInternetProtocolSink *iface)
785 {
786     Binding *This = PROTSINK_THIS(iface);
787     return IBinding_Release(BINDING(This));
788 }
789
790 static HRESULT WINAPI InternetProtocolSink_Switch(IInternetProtocolSink *iface,
791         PROTOCOLDATA *pProtocolData)
792 {
793     Binding *This = PROTSINK_THIS(iface);
794     task_t *task;
795
796     TRACE("(%p)->(%p)\n", This, pProtocolData);
797
798     task = HeapAlloc(GetProcessHeap(), 0, sizeof(task_t));
799     task->task = TASK_SWITCH;
800     task->data.protocol_data = pProtocolData;
801
802     push_task(This, task);
803
804     IBinding_AddRef(BINDING(This));
805     PostMessageW(This->notif_hwnd, WM_MK_CONTINUE, 0, (LPARAM)This);
806
807     return S_OK;
808 }
809
810 static HRESULT WINAPI InternetProtocolSink_ReportProgress(IInternetProtocolSink *iface,
811         ULONG ulStatusCode, LPCWSTR szStatusText)
812 {
813     Binding *This = PROTSINK_THIS(iface);
814
815     TRACE("(%p)->(%u %s)\n", This, ulStatusCode, debugstr_w(szStatusText));
816
817     switch(ulStatusCode) {
818     case BINDSTATUS_FINDINGRESOURCE:
819         on_progress(This, 0, 0, BINDSTATUS_FINDINGRESOURCE, szStatusText);
820         break;
821     case BINDSTATUS_CONNECTING:
822         on_progress(This, 0, 0, BINDSTATUS_CONNECTING, szStatusText);
823         break;
824     case BINDSTATUS_MIMETYPEAVAILABLE: {
825         int len = strlenW(szStatusText)+1;
826         This->mime = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR));
827         memcpy(This->mime, szStatusText, len*sizeof(WCHAR));
828         break;
829     }
830     case BINDSTATUS_SENDINGREQUEST:
831         on_progress(This, 0, 0, BINDSTATUS_SENDINGREQUEST, szStatusText);
832         break;
833     case BINDSTATUS_VERIFIEDMIMETYPEAVAILABLE:
834         This->verified_mime = TRUE;
835         on_progress(This, 0, 0, BINDSTATUS_MIMETYPEAVAILABLE, szStatusText);
836         break;
837     case BINDSTATUS_CACHEFILENAMEAVAILABLE:
838         break;
839     default:
840         FIXME("Unhandled status code %d\n", ulStatusCode);
841         return E_NOTIMPL;
842     };
843
844     return S_OK;
845 }
846
847 static HRESULT WINAPI InternetProtocolSink_ReportData(IInternetProtocolSink *iface,
848         DWORD grfBSCF, ULONG ulProgress, ULONG ulProgressMax)
849 {
850     Binding *This = PROTSINK_THIS(iface);
851
852     TRACE("(%p)->(%d %u %u)\n", This, grfBSCF, ulProgress, ulProgressMax);
853
854     if(!This->verified_mime) {
855         LPWSTR mime;
856
857         This->verified_mime = TRUE;
858
859         fill_stream_buffer(This->stream);
860
861         FindMimeFromData(NULL, This->url, This->stream->buf,
862                          min(This->stream->buf_size, 255), This->mime, 0, &mime, 0);
863
864         on_progress(This, ulProgress, ulProgressMax, BINDSTATUS_MIMETYPEAVAILABLE, mime);
865     }
866
867     if(grfBSCF & BSCF_FIRSTDATANOTIFICATION) {
868         on_progress(This, ulProgress, ulProgressMax, BINDSTATUS_BEGINDOWNLOADDATA, This->url);
869     }
870
871     if(grfBSCF & BSCF_LASTDATANOTIFICATION)
872         on_progress(This, ulProgress, ulProgressMax, BINDSTATUS_ENDDOWNLOADDATA, This->url);
873
874     if(grfBSCF & BSCF_FIRSTDATANOTIFICATION)
875         IInternetProtocol_LockRequest(This->protocol, 0);
876
877     on_data_available(This, grfBSCF);
878
879     if(grfBSCF & BSCF_LASTDATANOTIFICATION)
880         IBindStatusCallback_OnStopBinding(This->callback, S_OK, NULL);
881
882     return S_OK;
883 }
884
885 static HRESULT WINAPI InternetProtocolSink_ReportResult(IInternetProtocolSink *iface,
886         HRESULT hrResult, DWORD dwError, LPCWSTR szResult)
887 {
888     Binding *This = PROTSINK_THIS(iface);
889
890     TRACE("(%p)->(%08x %d %s)\n", This, hrResult, dwError, debugstr_w(szResult));
891
892     IInternetProtocol_Terminate(This->protocol, 0);
893     return S_OK;
894 }
895
896 #undef PROTSINK_THIS
897
898 static const IInternetProtocolSinkVtbl InternetProtocolSinkVtbl = {
899     InternetProtocolSink_QueryInterface,
900     InternetProtocolSink_AddRef,
901     InternetProtocolSink_Release,
902     InternetProtocolSink_Switch,
903     InternetProtocolSink_ReportProgress,
904     InternetProtocolSink_ReportData,
905     InternetProtocolSink_ReportResult
906 };
907
908 #define BINDINF_THIS(iface) DEFINE_THIS(Binding, InternetBindInfo, iface)
909
910 static HRESULT WINAPI InternetBindInfo_QueryInterface(IInternetBindInfo *iface,
911         REFIID riid, void **ppv)
912 {
913     Binding *This = BINDINF_THIS(iface);
914     return IBinding_QueryInterface(BINDING(This), riid, ppv);
915 }
916
917 static ULONG WINAPI InternetBindInfo_AddRef(IInternetBindInfo *iface)
918 {
919     Binding *This = BINDINF_THIS(iface);
920     return IBinding_AddRef(BINDING(This));
921 }
922
923 static ULONG WINAPI InternetBindInfo_Release(IInternetBindInfo *iface)
924 {
925     Binding *This = BINDINF_THIS(iface);
926     return IBinding_Release(BINDING(This));
927 }
928
929 static HRESULT WINAPI InternetBindInfo_GetBindInfo(IInternetBindInfo *iface,
930         DWORD *grfBINDF, BINDINFO *pbindinfo)
931 {
932     Binding *This = BINDINF_THIS(iface);
933
934     TRACE("(%p)->(%p %p)\n", This, grfBINDF, pbindinfo);
935
936     *grfBINDF = This->bindf;
937
938     memcpy(pbindinfo, &This->bindinfo, sizeof(BINDINFO));
939
940     if(pbindinfo->szExtraInfo || pbindinfo->szCustomVerb)
941         FIXME("copy strings\n");
942
943     if(pbindinfo->pUnk)
944         IUnknown_AddRef(pbindinfo->pUnk);
945
946     return S_OK;
947 }
948
949 static HRESULT WINAPI InternetBindInfo_GetBindString(IInternetBindInfo *iface,
950         ULONG ulStringType, LPOLESTR *ppwzStr, ULONG cEl, ULONG *pcElFetched)
951 {
952     Binding *This = BINDINF_THIS(iface);
953
954     TRACE("(%p)->(%d %p %d %p)\n", This, ulStringType, ppwzStr, cEl, pcElFetched);
955
956     switch(ulStringType) {
957     case BINDSTRING_ACCEPT_MIMES: {
958         static const WCHAR wszMimes[] = {'*','/','*',0};
959
960         if(!ppwzStr || !pcElFetched)
961             return E_INVALIDARG;
962
963         ppwzStr[0] = CoTaskMemAlloc(sizeof(wszMimes));
964         memcpy(ppwzStr[0], wszMimes, sizeof(wszMimes));
965         *pcElFetched = 1;
966         return S_OK;
967     }
968     case BINDSTRING_USER_AGENT: {
969         IInternetBindInfo *bindinfo = NULL;
970         HRESULT hres;
971
972         hres = IBindStatusCallback_QueryInterface(This->callback, &IID_IInternetBindInfo,
973                                                   (void**)&bindinfo);
974         if(FAILED(hres))
975             return hres;
976
977         hres = IInternetBindInfo_GetBindString(bindinfo, ulStringType, ppwzStr,
978                                                cEl, pcElFetched);
979         IInternetBindInfo_Release(bindinfo);
980
981         return hres;
982     }
983     }
984
985     FIXME("not supported string type %d\n", ulStringType);
986     return E_NOTIMPL;
987 }
988
989 #undef BINDF_THIS
990
991 static const IInternetBindInfoVtbl InternetBindInfoVtbl = {
992     InternetBindInfo_QueryInterface,
993     InternetBindInfo_AddRef,
994     InternetBindInfo_Release,
995     InternetBindInfo_GetBindInfo,
996     InternetBindInfo_GetBindString
997 };
998
999 #define SERVPROV_THIS(iface) DEFINE_THIS(Binding, ServiceProvider, iface)
1000
1001 static HRESULT WINAPI ServiceProvider_QueryInterface(IServiceProvider *iface,
1002         REFIID riid, void **ppv)
1003 {
1004     Binding *This = SERVPROV_THIS(iface);
1005     return IBinding_QueryInterface(BINDING(This), riid, ppv);
1006 }
1007
1008 static ULONG WINAPI ServiceProvider_AddRef(IServiceProvider *iface)
1009 {
1010     Binding *This = SERVPROV_THIS(iface);
1011     return IBinding_AddRef(BINDING(This));
1012 }
1013
1014 static ULONG WINAPI ServiceProvider_Release(IServiceProvider *iface)
1015 {
1016     Binding *This = SERVPROV_THIS(iface);
1017     return IBinding_Release(BINDING(This));
1018 }
1019
1020 static HRESULT WINAPI ServiceProvider_QueryService(IServiceProvider *iface,
1021         REFGUID guidService, REFIID riid, void **ppv)
1022 {
1023     Binding *This = SERVPROV_THIS(iface);
1024     HRESULT hres;
1025
1026     TRACE("(%p)->(%s %s %p)\n", This, debugstr_guid(guidService), debugstr_guid(riid), ppv);
1027
1028     if(This->service_provider) {
1029         hres = IServiceProvider_QueryService(This->service_provider, guidService,
1030                                              riid, ppv);
1031         if(SUCCEEDED(hres))
1032             return hres;
1033     }
1034
1035     if(IsEqualGUID(&IID_IHttpNegotiate, guidService)
1036        || IsEqualGUID(&IID_IHttpNegotiate2, guidService))
1037         return IHttpNegotiate2_QueryInterface(&HttpNegotiate, riid, ppv);
1038
1039     WARN("unknown service %s\n", debugstr_guid(guidService));
1040     return E_NOTIMPL;
1041 }
1042
1043 #undef SERVPROV_THIS
1044
1045 static const IServiceProviderVtbl ServiceProviderVtbl = {
1046     ServiceProvider_QueryInterface,
1047     ServiceProvider_AddRef,
1048     ServiceProvider_Release,
1049     ServiceProvider_QueryService
1050 };
1051
1052 static HRESULT get_callback(IBindCtx *pbc, IBindStatusCallback **callback)
1053 {
1054     HRESULT hres;
1055
1056     static WCHAR wszBSCBHolder[] = { '_','B','S','C','B','_','H','o','l','d','e','r','_',0 };
1057
1058     hres = IBindCtx_GetObjectParam(pbc, wszBSCBHolder, (IUnknown**)callback);
1059     if(FAILED(hres))
1060         return MK_E_SYNTAX;
1061
1062     return S_OK;
1063 }
1064
1065 static HRESULT get_protocol(Binding *This, LPCWSTR url)
1066 {
1067     IClassFactory *cf = NULL;
1068     HRESULT hres;
1069
1070     hres = IBindStatusCallback_QueryInterface(This->callback, &IID_IInternetProtocol,
1071             (void**)&This->protocol);
1072     if(SUCCEEDED(hres))
1073         return S_OK;
1074
1075     if(This->service_provider) {
1076         hres = IServiceProvider_QueryService(This->service_provider, &IID_IInternetProtocol,
1077                 &IID_IInternetProtocol, (void**)&This->protocol);
1078         if(SUCCEEDED(hres))
1079             return S_OK;
1080     }
1081
1082     hres = get_protocol_handler(url, &cf);
1083     if(FAILED(hres))
1084         return hres;
1085
1086     hres = IClassFactory_CreateInstance(cf, NULL, &IID_IInternetProtocol, (void**)&This->protocol);
1087     IClassFactory_Release(cf);
1088
1089     return hres;
1090 }
1091
1092 static HRESULT Binding_Create(LPCWSTR url, IBindCtx *pbc, REFIID riid, Binding **binding)
1093 {
1094     Binding *ret;
1095     int len;
1096     HRESULT hres;
1097
1098     static const WCHAR wszFile[] = {'f','i','l','e',':'};
1099
1100     if(!IsEqualGUID(&IID_IStream, riid)) {
1101         FIXME("Unsupported riid %s\n", debugstr_guid(riid));
1102         return E_NOTIMPL;
1103     }
1104
1105     URLMON_LockModule();
1106
1107     ret = HeapAlloc(GetProcessHeap(), 0, sizeof(Binding));
1108
1109     ret->lpBindingVtbl              = &BindingVtbl;
1110     ret->lpInternetProtocolSinkVtbl = &InternetProtocolSinkVtbl;
1111     ret->lpInternetBindInfoVtbl     = &InternetBindInfoVtbl;
1112     ret->lpServiceProviderVtbl      = &ServiceProviderVtbl;
1113
1114     ret->ref = 1;
1115
1116     ret->callback = NULL;
1117     ret->protocol = NULL;
1118     ret->service_provider = NULL;
1119     ret->stream = NULL;
1120     ret->mime = NULL;
1121     ret->url = NULL;
1122     ret->apartment_thread = GetCurrentThreadId();
1123     ret->notif_hwnd = get_notif_hwnd();
1124     ret->verified_mime = FALSE;
1125     ret->continue_call = 0;
1126     ret->task_queue_head = ret->task_queue_tail = NULL;
1127
1128     memset(&ret->bindinfo, 0, sizeof(BINDINFO));
1129     ret->bindinfo.cbSize = sizeof(BINDINFO);
1130     ret->bindf = 0;
1131
1132     InitializeCriticalSection(&ret->section);
1133
1134     hres = get_callback(pbc, &ret->callback);
1135     if(FAILED(hres)) {
1136         WARN("Could not get IBindStatusCallback\n");
1137         IBinding_Release(BINDING(ret));
1138         return hres;
1139     }
1140
1141     IBindStatusCallback_QueryInterface(ret->callback, &IID_IServiceProvider,
1142                                        (void**)&ret->service_provider);
1143
1144     hres = get_protocol(ret, url);
1145     if(FAILED(hres)) {
1146         WARN("Could not get protocol handler\n");
1147         IBinding_Release(BINDING(ret));
1148         return hres;
1149     }
1150
1151     hres = IBindStatusCallback_GetBindInfo(ret->callback, &ret->bindf, &ret->bindinfo);
1152     if(FAILED(hres)) {
1153         WARN("GetBindInfo failed: %08x\n", hres);
1154         IBinding_Release(BINDING(ret));
1155         return hres;
1156     }
1157
1158     dump_BINDINFO(&ret->bindinfo);
1159
1160     ret->bindf |= BINDF_FROMURLMON;
1161
1162     len = strlenW(url)+1;
1163
1164     if(len < sizeof(wszFile)/sizeof(WCHAR) || memcmp(wszFile, url, sizeof(wszFile)))
1165         ret->bindf |= BINDF_NEEDFILE;
1166
1167     ret->url = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR));
1168     memcpy(ret->url, url, len*sizeof(WCHAR));
1169
1170     ret->stream = create_stream(ret->protocol);
1171     ret->stgmed.tymed = TYMED_ISTREAM;
1172     ret->stgmed.u.pstm = STREAM(ret->stream);
1173     ret->stgmed.pUnkForRelease = (IUnknown*)BINDING(ret); /* NOTE: Windows uses other IUnknown */
1174
1175     *binding = ret;
1176     return S_OK;
1177 }
1178
1179 HRESULT start_binding(LPCWSTR url, IBindCtx *pbc, REFIID riid, void **ppv)
1180 {
1181     Binding *binding = NULL;
1182     HRESULT hres;
1183
1184     *ppv = NULL;
1185
1186     hres = Binding_Create(url, pbc, riid, &binding);
1187     if(FAILED(hres))
1188         return hres;
1189
1190     hres = IBindStatusCallback_OnStartBinding(binding->callback, 0, BINDING(binding));
1191     if(FAILED(hres)) {
1192         WARN("OnStartBinding failed: %08x\n", hres);
1193         IBindStatusCallback_OnStopBinding(binding->callback, 0x800c0008, NULL);
1194         IBinding_Release(BINDING(binding));
1195         return hres;
1196     }
1197
1198     hres = IInternetProtocol_Start(binding->protocol, url, PROTSINK(binding),
1199              BINDINF(binding), 0, 0);
1200
1201     if(FAILED(hres)) {
1202         WARN("Start failed: %08x\n", hres);
1203
1204         IInternetProtocol_Terminate(binding->protocol, 0);
1205         IBindStatusCallback_OnStopBinding(binding->callback, S_OK, NULL);
1206         IBinding_Release(BINDING(binding));
1207
1208         return hres;
1209     }
1210
1211     if(binding->stream->init_buf) {
1212         IInternetProtocol_UnlockRequest(binding->protocol);
1213
1214         IStream_AddRef(STREAM(binding->stream));
1215         *ppv = binding->stream;
1216
1217         hres = S_OK;
1218     }else {
1219         hres = MK_S_ASYNCHRONOUS;
1220     }
1221
1222     IBinding_Release(BINDING(binding));
1223
1224     return hres;
1225 }