urlmon: Pass FORMATETC to OnDataAvailable.
[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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  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 ProtocolStream ProtocolStream;
38
39 typedef struct {
40     const IBindingVtbl               *lpBindingVtbl;
41     const IInternetProtocolSinkVtbl  *lpInternetProtocolSinkVtbl;
42     const IInternetBindInfoVtbl      *lpInternetBindInfoVtbl;
43     const IServiceProviderVtbl       *lpServiceProviderVtbl;
44
45     LONG ref;
46
47     IBindStatusCallback *callback;
48     IInternetProtocol *protocol;
49     IServiceProvider *service_provider;
50     ProtocolStream *stream;
51
52     BINDINFO bindinfo;
53     DWORD bindf;
54     LPWSTR mime;
55     LPWSTR url;
56 } Binding;
57
58 struct ProtocolStream {
59     const IStreamVtbl *lpStreamVtbl;
60
61     LONG ref;
62
63     IInternetProtocol *protocol;
64
65     BYTE buf[1024*8];
66     DWORD buf_size;
67 };
68
69 #define BINDING(x)   ((IBinding*)               &(x)->lpBindingVtbl)
70 #define PROTSINK(x)  ((IInternetProtocolSink*)  &(x)->lpInternetProtocolSinkVtbl)
71 #define BINDINF(x)   ((IInternetBindInfo*)      &(x)->lpInternetBindInfoVtbl)
72 #define SERVPROV(x)  ((IServiceProvider*)       &(x)->lpServiceProviderVtbl)
73
74 #define STREAM(x) ((IStream*) &(x)->lpStreamVtbl)
75
76 static HRESULT WINAPI HttpNegotiate_QueryInterface(IHttpNegotiate2 *iface,
77                                                    REFIID riid, void **ppv)
78 {
79     *ppv = NULL;
80
81     if(IsEqualGUID(&IID_IUnknown, riid)) {
82         TRACE("(IID_IUnknown %p)\n", ppv);
83         *ppv = iface;
84     }else if(IsEqualGUID(&IID_IHttpNegotiate, riid)) {
85         TRACE("(IID_IHttpNegotiate %p)\n", ppv);
86         *ppv = iface;
87     }else if(IsEqualGUID(&IID_IHttpNegotiate2, riid)) {
88         TRACE("(IID_IHttpNegotiate2 %p)\n", ppv);
89         *ppv = iface;
90     }
91
92     if(*ppv) {
93         IHttpNegotiate2_AddRef(iface);
94         return S_OK;
95     }
96
97     WARN("Unsupported interface %s\n", debugstr_guid(riid));
98     return E_NOINTERFACE;
99 }
100
101 static ULONG WINAPI HttpNegotiate_AddRef(IHttpNegotiate2 *iface)
102 {
103     URLMON_LockModule();
104     return 2;
105 }
106
107 static ULONG WINAPI HttpNegotiate_Release(IHttpNegotiate2 *iface)
108 {
109     URLMON_UnlockModule();
110     return 1;
111 }
112
113 static HRESULT WINAPI HttpNegotiate_BeginningTransaction(IHttpNegotiate2 *iface,
114         LPCWSTR szURL, LPCWSTR szHeaders, DWORD dwReserved, LPWSTR *pszAdditionalHeaders)
115 {
116     FIXME("(%s %s %ld %p)\n", debugstr_w(szURL), debugstr_w(szHeaders), dwReserved,
117           pszAdditionalHeaders);
118     return E_NOTIMPL;
119 }
120
121 static HRESULT WINAPI HttpNegotiate_OnResponse(IHttpNegotiate2 *iface, DWORD dwResponseCode,
122         LPCWSTR szResponseHeaders, LPCWSTR szRequestHeaders,
123         LPWSTR *pszAdditionalRequestHeaders)
124 {
125     FIXME("(%ld %s %s %p)\n", dwResponseCode, debugstr_w(szResponseHeaders),
126           debugstr_w(szRequestHeaders), pszAdditionalRequestHeaders);
127     return E_NOTIMPL;
128 }
129
130 static HRESULT WINAPI HttpNegotiate_GetRootSecurityId(IHttpNegotiate2 *iface,
131         BYTE *pbSecurityId, DWORD *pcbSecurityId, DWORD_PTR dwReserved)
132 {
133     FIXME("(%p %p %ld)\n", pbSecurityId, pcbSecurityId, dwReserved);
134     return E_NOTIMPL;
135 }
136
137 static const IHttpNegotiate2Vtbl HttpNegotiate2Vtbl = {
138     HttpNegotiate_QueryInterface,
139     HttpNegotiate_AddRef,
140     HttpNegotiate_Release,
141     HttpNegotiate_BeginningTransaction,
142     HttpNegotiate_OnResponse,
143     HttpNegotiate_GetRootSecurityId
144 };
145
146 static IHttpNegotiate2 HttpNegotiate = { &HttpNegotiate2Vtbl };
147
148 #define STREAM_THIS(iface) DEFINE_THIS(ProtocolStream, Stream, iface)
149
150 static HRESULT WINAPI ProtocolStream_QueryInterface(IStream *iface,
151                                                           REFIID riid, void **ppv)
152 {
153     ProtocolStream *This = STREAM_THIS(iface);
154
155     *ppv = NULL;
156
157     if(IsEqualGUID(&IID_IUnknown, riid)) {
158         TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
159         *ppv = STREAM(This);
160     }else if(IsEqualGUID(&IID_ISequentialStream, riid)) {
161         TRACE("(%p)->(IID_ISequentialStream %p)\n", This, ppv);
162         *ppv = STREAM(This);
163     }else if(IsEqualGUID(&IID_IStream, riid)) {
164         TRACE("(%p)->(IID_IStream %p)\n", This, ppv);
165         *ppv = STREAM(This);
166     }
167
168     if(*ppv) {
169         IStream_AddRef(STREAM(This));
170         return S_OK;
171     }
172
173     WARN("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
174     return E_NOINTERFACE;
175 }
176
177 static ULONG WINAPI ProtocolStream_AddRef(IStream *iface)
178 {
179     ProtocolStream *This = STREAM_THIS(iface);
180     LONG ref = InterlockedIncrement(&This->ref);
181
182     TRACE("(%p) ref=%ld\n", This, ref);
183
184     return ref;
185 }
186
187 static ULONG WINAPI ProtocolStream_Release(IStream *iface)
188 {
189     ProtocolStream *This = STREAM_THIS(iface);
190     LONG ref = InterlockedDecrement(&This->ref);
191
192     TRACE("(%p) ref=%ld\n", This, ref);
193
194     if(!ref) {
195         IInternetProtocol_Release(This->protocol);
196         HeapFree(GetProcessHeap(), 0, This);
197     }
198
199     return ref;
200 }
201
202 static HRESULT WINAPI ProtocolStream_Read(IStream *iface, void *pv,
203                                          ULONG cb, ULONG *pcbRead)
204 {
205     ProtocolStream *This = STREAM_THIS(iface);
206     DWORD read = 0, pread = 0;
207
208     TRACE("(%p)->(%p %ld %p)\n", This, pv, cb, pcbRead);
209
210     if(This->buf_size) {
211         read = cb;
212
213         if(read > This->buf_size)
214             read = This->buf_size;
215
216         memcpy(pv, This->buf, read);
217
218         if(read < This->buf_size)
219             memmove(This->buf, This->buf+read, This->buf_size-read);
220         This->buf_size -= read;
221     }
222
223     if(read == cb) {
224         *pcbRead = read;
225         return S_OK;
226     }
227
228     IInternetProtocol_Read(This->protocol, (PBYTE)pv+read, cb-read, &pread);
229     *pcbRead = read + pread;
230
231     return read || pread ? S_OK : S_FALSE;
232 }
233
234 static HRESULT WINAPI ProtocolStream_Write(IStream *iface, const void *pv,
235                                           ULONG cb, ULONG *pcbWritten)
236 {
237     ProtocolStream *This = STREAM_THIS(iface);
238
239     TRACE("(%p)->(%p %ld %p)\n", This, pv, cb, pcbWritten);
240
241     return STG_E_ACCESSDENIED;
242 }
243
244 static HRESULT WINAPI ProtocolStream_Seek(IStream *iface, LARGE_INTEGER dlibMove,
245                                          DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition)
246 {
247     ProtocolStream *This = STREAM_THIS(iface);
248     FIXME("(%p)->(%ld %08lx %p)\n", This, dlibMove.u.LowPart, dwOrigin, plibNewPosition);
249     return E_NOTIMPL;
250 }
251
252 static HRESULT WINAPI ProtocolStream_SetSize(IStream *iface, ULARGE_INTEGER libNewSize)
253 {
254     ProtocolStream *This = STREAM_THIS(iface);
255     FIXME("(%p)->(%ld)\n", This, libNewSize.u.LowPart);
256     return E_NOTIMPL;
257 }
258
259 static HRESULT WINAPI ProtocolStream_CopyTo(IStream *iface, IStream *pstm,
260         ULARGE_INTEGER cb, ULARGE_INTEGER *pcbRead, ULARGE_INTEGER *pcbWritten)
261 {
262     ProtocolStream *This = STREAM_THIS(iface);
263     FIXME("(%p)->(%p %ld %p %p)\n", This, pstm, cb.u.LowPart, pcbRead, pcbWritten);
264     return E_NOTIMPL;
265 }
266
267 static HRESULT WINAPI ProtocolStream_Commit(IStream *iface, DWORD grfCommitFlags)
268 {
269     ProtocolStream *This = STREAM_THIS(iface);
270
271     TRACE("(%p)->(%08lx)\n", This, grfCommitFlags);
272
273     return E_NOTIMPL;
274 }
275
276 static HRESULT WINAPI ProtocolStream_Revert(IStream *iface)
277 {
278     ProtocolStream *This = STREAM_THIS(iface);
279
280     TRACE("(%p)\n", This);
281
282     return E_NOTIMPL;
283 }
284
285 static HRESULT WINAPI ProtocolStream_LockRegion(IStream *iface, ULARGE_INTEGER libOffset,
286                                                ULARGE_INTEGER cb, DWORD dwLockType)
287 {
288     ProtocolStream *This = STREAM_THIS(iface);
289     FIXME("(%p)->(%ld %ld %ld)\n", This, libOffset.u.LowPart, cb.u.LowPart, dwLockType);
290     return E_NOTIMPL;
291 }
292
293 static HRESULT WINAPI ProtocolStream_UnlockRegion(IStream *iface,
294         ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType)
295 {
296     ProtocolStream *This = STREAM_THIS(iface);
297     FIXME("(%p)->(%ld %ld %ld)\n", This, libOffset.u.LowPart, cb.u.LowPart, dwLockType);
298     return E_NOTIMPL;
299 }
300
301 static HRESULT WINAPI ProtocolStream_Stat(IStream *iface, STATSTG *pstatstg,
302                                          DWORD dwStatFlag)
303 {
304     ProtocolStream *This = STREAM_THIS(iface);
305     FIXME("(%p)->(%p %08lx)\n", This, pstatstg, dwStatFlag);
306     return E_NOTIMPL;
307 }
308
309 static HRESULT WINAPI ProtocolStream_Clone(IStream *iface, IStream **ppstm)
310 {
311     ProtocolStream *This = STREAM_THIS(iface);
312     FIXME("(%p)->(%p)\n", This, ppstm);
313     return E_NOTIMPL;
314 }
315
316 #undef STREAM_THIS
317
318 static const IStreamVtbl ProtocolStreamVtbl = {
319     ProtocolStream_QueryInterface,
320     ProtocolStream_AddRef,
321     ProtocolStream_Release,
322     ProtocolStream_Read,
323     ProtocolStream_Write,
324     ProtocolStream_Seek,
325     ProtocolStream_SetSize,
326     ProtocolStream_CopyTo,
327     ProtocolStream_Commit,
328     ProtocolStream_Revert,
329     ProtocolStream_LockRegion,
330     ProtocolStream_UnlockRegion,
331     ProtocolStream_Stat,
332     ProtocolStream_Clone
333 };
334
335 #define BINDING_THIS(iface) DEFINE_THIS(Binding, Binding, iface)
336
337 static ProtocolStream *create_stream(IInternetProtocol *protocol)
338 {
339     ProtocolStream *ret = HeapAlloc(GetProcessHeap(), 0, sizeof(ProtocolStream));
340
341     ret->lpStreamVtbl = &ProtocolStreamVtbl;
342     ret->ref = 1;
343     ret->buf_size = 0;
344
345     IInternetProtocol_AddRef(protocol);
346     ret->protocol = protocol;
347
348     return ret;
349 }
350
351 static void fill_stream_buffer(ProtocolStream *This)
352 {
353     DWORD read = 0;
354
355     IInternetProtocol_Read(This->protocol, This->buf+This->buf_size,
356                            sizeof(This->buf)-This->buf_size, &read);
357     This->buf_size += read;
358 }
359
360 static HRESULT WINAPI Binding_QueryInterface(IBinding *iface, REFIID riid, void **ppv)
361 {
362     Binding *This = BINDING_THIS(iface);
363
364     *ppv = NULL;
365
366     if(IsEqualGUID(&IID_IUnknown, riid)) {
367         TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
368         *ppv = BINDING(This);
369     }else if(IsEqualGUID(&IID_IBinding, riid)) {
370         TRACE("(%p)->(IID_IBinding %p)\n", This, ppv);
371         *ppv = BINDING(This);
372     }else if(IsEqualGUID(&IID_IInternetProtocolSink, riid)) {
373         TRACE("(%p)->(IID_IInternetProtocolSink %p)\n", This, ppv);
374         *ppv = PROTSINK(This);
375     }else if(IsEqualGUID(&IID_IInternetBindInfo, riid)) {
376         TRACE("(%p)->(IID_IInternetBindInfo %p)\n", This, ppv);
377         *ppv = BINDINF(This);
378     }else if(IsEqualGUID(&IID_IServiceProvider, riid)) {
379         TRACE("(%p)->(IID_IServiceProvider %p)\n", This, ppv);
380         *ppv = SERVPROV(This);
381     }
382
383     if(*ppv)
384         return S_OK;
385
386     WARN("Unsupported interface %s\n", debugstr_guid(riid));
387     return E_NOINTERFACE;
388 }
389
390 static ULONG WINAPI Binding_AddRef(IBinding *iface)
391 {
392     Binding *This = BINDING_THIS(iface);
393     LONG ref = InterlockedIncrement(&This->ref);
394
395     TRACE("(%p) ref=%ld\n", This, ref);
396
397     return ref;
398 }
399
400 static ULONG WINAPI Binding_Release(IBinding *iface)
401 {
402     Binding *This = BINDING_THIS(iface);
403     LONG ref = InterlockedDecrement(&This->ref);
404
405     TRACE("(%p) ref=%ld\n", This, ref);
406
407     if(!ref) {
408         if(This->callback)
409             IBindStatusCallback_Release(This->callback);
410         if(This->protocol)
411             IInternetProtocol_Release(This->protocol);
412         if(This->service_provider)
413             IServiceProvider_Release(This->service_provider);
414         if(This->stream)
415             IStream_Release(STREAM(This->stream));
416
417         ReleaseBindInfo(&This->bindinfo);
418         HeapFree(GetProcessHeap(), 0, This->mime);
419         HeapFree(GetProcessHeap(), 0, This->url);
420
421         HeapFree(GetProcessHeap(), 0, This);
422     }
423
424     return ref;
425 }
426
427 static HRESULT WINAPI Binding_Abort(IBinding *iface)
428 {
429     Binding *This = BINDING_THIS(iface);
430     FIXME("(%p)\n", This);
431     return E_NOTIMPL;
432 }
433
434 static HRESULT WINAPI Binding_Suspend(IBinding *iface)
435 {
436     Binding *This = BINDING_THIS(iface);
437     FIXME("(%p)\n", This);
438     return E_NOTIMPL;
439 }
440
441 static HRESULT WINAPI Binding_Resume(IBinding *iface)
442 {
443     Binding *This = BINDING_THIS(iface);
444     FIXME("(%p)\n", This);
445     return E_NOTIMPL;
446 }
447
448 static HRESULT WINAPI Binding_SetPriority(IBinding *iface, LONG nPriority)
449 {
450     Binding *This = BINDING_THIS(iface);
451     FIXME("(%p)->(%ld)\n", This, nPriority);
452     return E_NOTIMPL;
453 }
454
455 static HRESULT WINAPI Binding_GetPriority(IBinding *iface, LONG *pnPriority)
456 {
457     Binding *This = BINDING_THIS(iface);
458     FIXME("(%p)->(%p)\n", This, pnPriority);
459     return E_NOTIMPL;
460 }
461
462 static HRESULT WINAPI Binding_GetBindResult(IBinding *iface, CLSID *pclsidProtocol,
463         DWORD *pdwResult, LPOLESTR *pszResult, DWORD *pdwReserved)
464 {
465     Binding *This = BINDING_THIS(iface);
466     FIXME("(%p)->(%p %p %p %p)\n", This, pclsidProtocol, pdwResult, pszResult, pdwReserved);
467     return E_NOTIMPL;
468 }
469
470 #undef BINDING_THIS
471
472 static const IBindingVtbl BindingVtbl = {
473     Binding_QueryInterface,
474     Binding_AddRef,
475     Binding_Release,
476     Binding_Abort,
477     Binding_Suspend,
478     Binding_Resume,
479     Binding_SetPriority,
480     Binding_GetPriority,
481     Binding_GetBindResult
482 };
483
484 #define PROTSINK_THIS(iface) DEFINE_THIS(Binding, InternetProtocolSink, iface)
485
486 static HRESULT WINAPI InternetProtocolSink_QueryInterface(IInternetProtocolSink *iface,
487         REFIID riid, void **ppv)
488 {
489     Binding *This = PROTSINK_THIS(iface);
490     return IBinding_QueryInterface(BINDING(This), riid, ppv);
491 }
492
493 static ULONG WINAPI InternetProtocolSink_AddRef(IInternetProtocolSink *iface)
494 {
495     Binding *This = PROTSINK_THIS(iface);
496     return IBinding_AddRef(BINDING(This));
497 }
498
499 static ULONG WINAPI InternetProtocolSink_Release(IInternetProtocolSink *iface)
500 {
501     Binding *This = PROTSINK_THIS(iface);
502     return IBinding_Release(BINDING(This));
503 }
504
505 static HRESULT WINAPI InternetProtocolSink_Switch(IInternetProtocolSink *iface,
506         PROTOCOLDATA *pProtocolData)
507 {
508     Binding *This = PROTSINK_THIS(iface);
509     FIXME("(%p)->(%p)\n", This, pProtocolData);
510     return E_NOTIMPL;
511 }
512
513 static HRESULT WINAPI InternetProtocolSink_ReportProgress(IInternetProtocolSink *iface,
514         ULONG ulStatusCode, LPCWSTR szStatusText)
515 {
516     Binding *This = PROTSINK_THIS(iface);
517
518     TRACE("(%p)->(%lu %s)\n", This, ulStatusCode, debugstr_w(szStatusText));
519
520     switch(ulStatusCode) {
521     case BINDSTATUS_MIMETYPEAVAILABLE: {
522         int len = strlenW(szStatusText)+1;
523         This->mime = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR));
524         memcpy(This->mime, szStatusText, len*sizeof(WCHAR));
525         break;
526     }
527     case BINDSTATUS_SENDINGREQUEST:
528         IBindStatusCallback_OnProgress(This->callback, 0, 0, BINDSTATUS_SENDINGREQUEST,
529                                        szStatusText);
530         break;
531     case BINDSTATUS_VERIFIEDMIMETYPEAVAILABLE:
532         IBindStatusCallback_OnProgress(This->callback, 0, 0,
533                                        BINDSTATUS_MIMETYPEAVAILABLE, szStatusText);
534         break;
535     case BINDSTATUS_CACHEFILENAMEAVAILABLE:
536         break;
537     default:
538         FIXME("Unhandled status code %ld\n", ulStatusCode);
539         return E_NOTIMPL;
540     };
541
542     return S_OK;
543 }
544
545 static HRESULT WINAPI InternetProtocolSink_ReportData(IInternetProtocolSink *iface,
546         DWORD grfBSCF, ULONG ulProgress, ULONG ulProgressMax)
547 {
548     Binding *This = PROTSINK_THIS(iface);
549     STGMEDIUM stgmed;
550     FORMATETC formatetc;
551
552     TRACE("(%p)->(%ld %lu %lu)\n", This, grfBSCF, ulProgress, ulProgressMax);
553
554     if(grfBSCF & BSCF_FIRSTDATANOTIFICATION) {
555         if(This->mime)
556             IBindStatusCallback_OnProgress(This->callback, ulProgress, ulProgressMax,
557                                            BINDSTATUS_MIMETYPEAVAILABLE, This->mime);
558         IBindStatusCallback_OnProgress(This->callback, ulProgress, ulProgressMax,
559                                        BINDSTATUS_BEGINDOWNLOADDATA, This->url);
560     }
561
562     if(grfBSCF & BSCF_LASTDATANOTIFICATION)
563         IBindStatusCallback_OnProgress(This->callback, ulProgress, ulProgressMax,
564                                        BINDSTATUS_ENDDOWNLOADDATA, This->url);
565
566     if(grfBSCF & BSCF_FIRSTDATANOTIFICATION)
567         IInternetProtocol_LockRequest(This->protocol, 0);
568
569     fill_stream_buffer(This->stream);
570
571     stgmed.tymed = TYMED_ISTREAM;
572     stgmed.u.pstm = STREAM(This->stream);
573
574     formatetc.cfFormat = 0; /* FIXME */
575     formatetc.ptd = NULL;
576     formatetc.dwAspect = 1;
577     formatetc.lindex = -1;
578     formatetc.tymed = TYMED_ISTREAM;
579
580     IBindStatusCallback_OnDataAvailable(This->callback, grfBSCF, This->stream->buf_size,
581             &formatetc, &stgmed);
582
583     if(grfBSCF & BSCF_LASTDATANOTIFICATION)
584         IBindStatusCallback_OnStopBinding(This->callback, S_OK, NULL);
585
586     return S_OK;
587 }
588
589 static HRESULT WINAPI InternetProtocolSink_ReportResult(IInternetProtocolSink *iface,
590         HRESULT hrResult, DWORD dwError, LPCWSTR szResult)
591 {
592     Binding *This = PROTSINK_THIS(iface);
593     FIXME("(%p)->(%08lx %ld %s)\n", This, hrResult, dwError, debugstr_w(szResult));
594     return E_NOTIMPL;
595 }
596
597 #undef PROTSINK_THIS
598
599 static const IInternetProtocolSinkVtbl InternetProtocolSinkVtbl = {
600     InternetProtocolSink_QueryInterface,
601     InternetProtocolSink_AddRef,
602     InternetProtocolSink_Release,
603     InternetProtocolSink_Switch,
604     InternetProtocolSink_ReportProgress,
605     InternetProtocolSink_ReportData,
606     InternetProtocolSink_ReportResult
607 };
608
609 #define BINDINF_THIS(iface) DEFINE_THIS(Binding, InternetBindInfo, iface)
610
611 static HRESULT WINAPI InternetBindInfo_QueryInterface(IInternetBindInfo *iface,
612         REFIID riid, void **ppv)
613 {
614     Binding *This = BINDINF_THIS(iface);
615     return IBinding_QueryInterface(BINDING(This), riid, ppv);
616 }
617
618 static ULONG WINAPI InternetBindInfo_AddRef(IInternetBindInfo *iface)
619 {
620     Binding *This = BINDINF_THIS(iface);
621     return IBinding_AddRef(BINDING(This));
622 }
623
624 static ULONG WINAPI InternetBindInfo_Release(IInternetBindInfo *iface)
625 {
626     Binding *This = BINDINF_THIS(iface);
627     return IBinding_Release(BINDING(This));
628 }
629
630 static HRESULT WINAPI InternetBindInfo_GetBindInfo(IInternetBindInfo *iface,
631         DWORD *grfBINDF, BINDINFO *pbindinfo)
632 {
633     Binding *This = BINDINF_THIS(iface);
634
635     TRACE("(%p)->(%p %p)\n", This, grfBINDF, pbindinfo);
636
637     *grfBINDF = This->bindf;
638
639     memcpy(pbindinfo, &This->bindinfo, sizeof(BINDINFO));
640
641     if(pbindinfo->szExtraInfo || pbindinfo->szCustomVerb)
642         FIXME("copy strings\n");
643
644     if(pbindinfo->pUnk)
645         IUnknown_AddRef(pbindinfo->pUnk);
646
647     return S_OK;
648 }
649
650 static HRESULT WINAPI InternetBindInfo_GetBindString(IInternetBindInfo *iface,
651         ULONG ulStringType, LPOLESTR *ppwzStr, ULONG cEl, ULONG *pcElFetched)
652 {
653     Binding *This = BINDINF_THIS(iface);
654
655     TRACE("(%p)->(%ld %p %ld %p)\n", This, ulStringType, ppwzStr, cEl, pcElFetched);
656
657     switch(ulStringType) {
658     case BINDSTRING_ACCEPT_MIMES: {
659         static const WCHAR wszMimes[] = {'*','/','*',0};
660
661         if(!ppwzStr || !pcElFetched)
662             return E_INVALIDARG;
663
664         ppwzStr[0] = CoTaskMemAlloc(sizeof(wszMimes));
665         memcpy(ppwzStr[0], wszMimes, sizeof(wszMimes));
666         *pcElFetched = 1;
667         return S_OK;
668     }
669     case BINDSTRING_USER_AGENT: {
670         IInternetBindInfo *bindinfo = NULL;
671         HRESULT hres;
672
673         hres = IBindStatusCallback_QueryInterface(This->callback, &IID_IInternetBindInfo,
674                                                   (void**)&bindinfo);
675         if(FAILED(hres))
676             return hres;
677
678         hres = IInternetBindInfo_GetBindString(bindinfo, ulStringType, ppwzStr,
679                                                cEl, pcElFetched);
680         IInternetBindInfo_Release(bindinfo);
681
682         return hres;
683     }
684     }
685
686     FIXME("not supported string type %ld\n", ulStringType);
687     return E_NOTIMPL;
688 }
689
690 #undef BINDF_THIS
691
692 static const IInternetBindInfoVtbl InternetBindInfoVtbl = {
693     InternetBindInfo_QueryInterface,
694     InternetBindInfo_AddRef,
695     InternetBindInfo_Release,
696     InternetBindInfo_GetBindInfo,
697     InternetBindInfo_GetBindString
698 };
699
700 #define SERVPROV_THIS(iface) DEFINE_THIS(Binding, ServiceProvider, iface)
701
702 static HRESULT WINAPI ServiceProvider_QueryInterface(IServiceProvider *iface,
703         REFIID riid, void **ppv)
704 {
705     Binding *This = SERVPROV_THIS(iface);
706     return IBinding_QueryInterface(BINDING(This), riid, ppv);
707 }
708
709 static ULONG WINAPI ServiceProvider_AddRef(IServiceProvider *iface)
710 {
711     Binding *This = SERVPROV_THIS(iface);
712     return IBinding_AddRef(BINDING(This));
713 }
714
715 static ULONG WINAPI ServiceProvider_Release(IServiceProvider *iface)
716 {
717     Binding *This = SERVPROV_THIS(iface);
718     return IBinding_Release(BINDING(This));
719 }
720
721 static HRESULT WINAPI ServiceProvider_QueryService(IServiceProvider *iface,
722         REFGUID guidService, REFIID riid, void **ppv)
723 {
724     Binding *This = SERVPROV_THIS(iface);
725     HRESULT hres;
726
727     TRACE("(%p)->(%s %s %p)\n", This, debugstr_guid(guidService), debugstr_guid(riid), ppv);
728
729     if(This->service_provider) {
730         hres = IServiceProvider_QueryService(This->service_provider, guidService,
731                                              riid, ppv);
732         if(SUCCEEDED(hres))
733             return hres;
734     }
735
736     if(IsEqualGUID(&IID_IHttpNegotiate, guidService)
737        || IsEqualGUID(&IID_IHttpNegotiate2, guidService))
738         return IHttpNegotiate2_QueryInterface(&HttpNegotiate, riid, ppv);
739
740     WARN("unknown service %s\n", debugstr_guid(guidService));
741     return E_NOTIMPL;
742 }
743
744 #undef SERVPROV_THIS
745
746 static const IServiceProviderVtbl ServiceProviderVtbl = {
747     ServiceProvider_QueryInterface,
748     ServiceProvider_AddRef,
749     ServiceProvider_Release,
750     ServiceProvider_QueryService
751 };
752
753 static HRESULT get_callback(IBindCtx *pbc, IBindStatusCallback **callback)
754 {
755     HRESULT hres;
756
757     static WCHAR wszBSCBHolder[] = { '_','B','S','C','B','_','H','o','l','d','e','r','_',0 };
758
759     hres = IBindCtx_GetObjectParam(pbc, wszBSCBHolder, (IUnknown**)callback);
760     if(FAILED(hres))
761         return MK_E_SYNTAX;
762
763     return S_OK;
764 }
765
766 static HRESULT get_protocol(Binding *This, LPCWSTR url)
767 {
768     IUnknown *unk = NULL;
769     IClassFactory *cf = NULL;
770     HRESULT hres;
771
772     hres = IBindStatusCallback_QueryInterface(This->callback, &IID_IInternetProtocol,
773             (void**)&This->protocol);
774     if(SUCCEEDED(hres))
775         return S_OK;
776
777     if(This->service_provider) {
778         hres = IServiceProvider_QueryService(This->service_provider, &IID_IInternetProtocol,
779                 &IID_IInternetProtocol, (void**)&This->protocol);
780         if(SUCCEEDED(hres))
781             return S_OK;
782     }
783
784     hres = get_protocol_iface(url, &unk);
785     if(FAILED(hres))
786         return hres;
787
788     hres = IUnknown_QueryInterface(unk, &IID_IClassFactory, (void**)&cf);
789     IUnknown_Release(unk);
790     if(FAILED(hres))
791         return hres;
792
793     hres = IClassFactory_CreateInstance(cf, NULL, &IID_IInternetProtocol, (void**)&This->protocol);
794     IClassFactory_Release(cf);
795
796     return hres;
797 }
798
799 static HRESULT Binding_Create(LPCWSTR url, IBindCtx *pbc, REFIID riid, Binding **binding)
800 {
801     Binding *ret;
802     int len;
803     HRESULT hres;
804
805     static const WCHAR wszFile[] = {'f','i','l','e',':'};
806
807     if(!IsEqualGUID(&IID_IStream, riid)) {
808         FIXME("Unsupported riid %s\n", debugstr_guid(riid));
809         return E_NOTIMPL;
810     }
811
812     ret = HeapAlloc(GetProcessHeap(), 0, sizeof(Binding));
813
814     ret->lpBindingVtbl              = &BindingVtbl;
815     ret->lpInternetProtocolSinkVtbl = &InternetProtocolSinkVtbl;
816     ret->lpInternetBindInfoVtbl     = &InternetBindInfoVtbl;
817     ret->lpServiceProviderVtbl      = &ServiceProviderVtbl;
818
819     ret->ref = 1;
820
821     ret->callback = NULL;
822     ret->protocol = NULL;
823     ret->service_provider = NULL;
824     ret->stream = NULL;
825     ret->mime = NULL;
826     ret->url = NULL;
827
828     memset(&ret->bindinfo, 0, sizeof(BINDINFO));
829     ret->bindinfo.cbSize = sizeof(BINDINFO);
830     ret->bindf = 0;
831
832     hres = get_callback(pbc, &ret->callback);
833     if(FAILED(hres)) {
834         WARN("Could not get IBindStatusCallback\n");
835         IBinding_Release(BINDING(ret));
836         return hres;
837     }
838
839     IBindStatusCallback_QueryInterface(ret->callback, &IID_IServiceProvider,
840                                        (void**)&ret->service_provider);
841
842     hres = get_protocol(ret, url);
843     if(FAILED(hres)) {
844         WARN("Could not get protocol handler\n");
845         IBinding_Release(BINDING(ret));
846         return hres;
847     }
848
849     hres = IBindStatusCallback_GetBindInfo(ret->callback, &ret->bindf, &ret->bindinfo);
850     if(FAILED(hres)) {
851         WARN("GetBindInfo failed: %08lx\n", hres);
852         IBinding_Release(BINDING(ret));
853         return hres;
854     }
855
856     ret->bindf |= BINDF_FROMURLMON;
857
858     len = strlenW(url)+1;
859
860     if(len < sizeof(wszFile)/sizeof(WCHAR) || memcmp(wszFile, url, sizeof(wszFile)))
861         ret->bindf |= BINDF_NEEDFILE;
862
863     ret->url = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR));
864     memcpy(ret->url, url, len*sizeof(WCHAR));
865
866     ret->stream = create_stream(ret->protocol);
867
868     *binding = ret;
869     return S_OK;
870 }
871
872 HRESULT start_binding(LPCWSTR url, IBindCtx *pbc, REFIID riid, void **ppv)
873 {
874     Binding *binding = NULL;
875     HRESULT hres;
876
877     *ppv = NULL;
878
879     hres = Binding_Create(url, pbc, riid, &binding);
880     if(FAILED(hres))
881         return hres;
882
883     hres = IBindStatusCallback_OnStartBinding(binding->callback, 0, BINDING(binding));
884     if(FAILED(hres)) {
885         WARN("OnStartBinding failed: %08lx\n", hres);
886         IBindStatusCallback_OnStopBinding(binding->callback, 0x800c0008, NULL);
887         IBinding_Release(BINDING(binding));
888         return hres;
889     }
890
891     hres = IInternetProtocol_Start(binding->protocol, url, PROTSINK(binding),
892              BINDINF(binding), 0, 0);
893     IInternetProtocol_Terminate(binding->protocol, 0);
894
895     if(SUCCEEDED(hres)) {
896         IInternetProtocol_UnlockRequest(binding->protocol);
897     }else {
898         WARN("Start failed: %08lx\n", hres);
899         IBindStatusCallback_OnStopBinding(binding->callback, S_OK, NULL);
900     }
901
902     IStream_AddRef(STREAM(binding->stream));
903     *ppv = binding->stream;
904
905     IBinding_Release(BINDING(binding));
906
907     return hres;
908 }