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