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