wiaservc: Convert the remaining registrations to IRegistrar format.
[wine] / dlls / mshtml / navigate.c
1 /*
2  * Copyright 2006-2010 Jacek Caban for CodeWeavers
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17  */
18
19 #include "config.h"
20
21 #include <stdarg.h>
22
23 #define COBJMACROS
24 #define NONAMELESSUNION
25 #define NONAMELESSSTRUCT
26
27 #include "windef.h"
28 #include "winbase.h"
29 #include "winuser.h"
30 #include "winreg.h"
31 #include "ole2.h"
32 #include "hlguids.h"
33 #include "shlguid.h"
34 #include "wininet.h"
35 #include "shlwapi.h"
36
37 #include "wine/debug.h"
38 #include "wine/unicode.h"
39
40 #include "mshtml_private.h"
41 #include "binding.h"
42
43 WINE_DEFAULT_DEBUG_CHANNEL(mshtml);
44
45 #define CONTENT_LENGTH "Content-Length"
46 #define UTF16_STR "utf-16"
47
48 struct nsProtocolStream {
49     nsIInputStream nsIInputStream_iface;
50
51     LONG ref;
52
53     char buf[1024];
54     DWORD buf_size;
55 };
56
57 struct BSCallbackVtbl {
58     void (*destroy)(BSCallback*);
59     HRESULT (*init_bindinfo)(BSCallback*);
60     HRESULT (*start_binding)(BSCallback*);
61     HRESULT (*stop_binding)(BSCallback*,HRESULT);
62     HRESULT (*read_data)(BSCallback*,IStream*);
63     HRESULT (*on_progress)(BSCallback*,ULONG,LPCWSTR);
64     HRESULT (*on_response)(BSCallback*,DWORD,LPCWSTR);
65     HRESULT (*beginning_transaction)(BSCallback*,WCHAR**);
66 };
67
68 static inline nsProtocolStream *impl_from_nsIInputStream(nsIInputStream *iface)
69 {
70     return CONTAINING_RECORD(iface, nsProtocolStream, nsIInputStream_iface);
71 }
72
73 static nsresult NSAPI nsInputStream_QueryInterface(nsIInputStream *iface, nsIIDRef riid,
74         void **result)
75 {
76     nsProtocolStream *This = impl_from_nsIInputStream(iface);
77
78     *result = NULL;
79
80     if(IsEqualGUID(&IID_nsISupports, riid)) {
81         TRACE("(%p)->(IID_nsISupports %p)\n", This, result);
82         *result  = &This->nsIInputStream_iface;
83     }else if(IsEqualGUID(&IID_nsIInputStream, riid)) {
84         TRACE("(%p)->(IID_nsIInputStream %p)\n", This, result);
85         *result  = &This->nsIInputStream_iface;
86     }
87
88     if(*result) {
89         nsIInputStream_AddRef(&This->nsIInputStream_iface);
90         return NS_OK;
91     }
92
93     WARN("unsupported interface %s\n", debugstr_guid(riid));
94     return NS_NOINTERFACE;
95 }
96
97 static nsrefcnt NSAPI nsInputStream_AddRef(nsIInputStream *iface)
98 {
99     nsProtocolStream *This = impl_from_nsIInputStream(iface);
100     LONG ref = InterlockedIncrement(&This->ref);
101
102     TRACE("(%p) ref=%d\n", This, ref);
103
104     return ref;
105 }
106
107
108 static nsrefcnt NSAPI nsInputStream_Release(nsIInputStream *iface)
109 {
110     nsProtocolStream *This = impl_from_nsIInputStream(iface);
111     LONG ref = InterlockedDecrement(&This->ref);
112
113     TRACE("(%p) ref=%d\n", This, ref);
114
115     if(!ref)
116         heap_free(This);
117
118     return ref;
119 }
120
121 static nsresult NSAPI nsInputStream_Close(nsIInputStream *iface)
122 {
123     nsProtocolStream *This = impl_from_nsIInputStream(iface);
124     FIXME("(%p)\n", This);
125     return NS_ERROR_NOT_IMPLEMENTED;
126 }
127
128 static nsresult NSAPI nsInputStream_Available(nsIInputStream *iface, PRUint32 *_retval)
129 {
130     nsProtocolStream *This = impl_from_nsIInputStream(iface);
131     FIXME("(%p)->(%p)\n", This, _retval);
132     return NS_ERROR_NOT_IMPLEMENTED;
133 }
134
135 static nsresult NSAPI nsInputStream_Read(nsIInputStream *iface, char *aBuf, PRUint32 aCount,
136                                          PRUint32 *_retval)
137 {
138     nsProtocolStream *This = impl_from_nsIInputStream(iface);
139     DWORD read = aCount;
140
141     TRACE("(%p)->(%p %d %p)\n", This, aBuf, aCount, _retval);
142
143     if(read > This->buf_size)
144         read = This->buf_size;
145
146     if(read) {
147         memcpy(aBuf, This->buf, read);
148         if(read < This->buf_size)
149             memmove(This->buf, This->buf+read, This->buf_size-read);
150         This->buf_size -= read;
151     }
152
153     *_retval = read;
154     return NS_OK;
155 }
156
157 static nsresult NSAPI nsInputStream_ReadSegments(nsIInputStream *iface,
158         nsresult (WINAPI *aWriter)(nsIInputStream*,void*,const char*,PRUint32,PRUint32,PRUint32*),
159         void *aClousure, PRUint32 aCount, PRUint32 *_retval)
160 {
161     nsProtocolStream *This = impl_from_nsIInputStream(iface);
162     PRUint32 written = 0;
163     nsresult nsres;
164
165     TRACE("(%p)->(%p %p %d %p)\n", This, aWriter, aClousure, aCount, _retval);
166
167     if(!This->buf_size)
168         return S_OK;
169
170     if(aCount > This->buf_size)
171         aCount = This->buf_size;
172
173     nsres = aWriter(&This->nsIInputStream_iface, aClousure, This->buf, 0, aCount, &written);
174     if(NS_FAILED(nsres))
175         TRACE("aWritter failed: %08x\n", nsres);
176     else if(written != This->buf_size)
177         FIXME("written %d != buf_size %d\n", written, This->buf_size);
178
179     This->buf_size -= written; 
180
181     *_retval = written;
182     return nsres;
183 }
184
185 static nsresult NSAPI nsInputStream_IsNonBlocking(nsIInputStream *iface, PRBool *_retval)
186 {
187     nsProtocolStream *This = impl_from_nsIInputStream(iface);
188     FIXME("(%p)->(%p)\n", This, _retval);
189     return NS_ERROR_NOT_IMPLEMENTED;
190 }
191
192 static const nsIInputStreamVtbl nsInputStreamVtbl = {
193     nsInputStream_QueryInterface,
194     nsInputStream_AddRef,
195     nsInputStream_Release,
196     nsInputStream_Close,
197     nsInputStream_Available,
198     nsInputStream_Read,
199     nsInputStream_ReadSegments,
200     nsInputStream_IsNonBlocking
201 };
202
203 static nsProtocolStream *create_nsprotocol_stream(void)
204 {
205     nsProtocolStream *ret = heap_alloc(sizeof(nsProtocolStream));
206
207     ret->nsIInputStream_iface.lpVtbl = &nsInputStreamVtbl;
208     ret->ref = 1;
209     ret->buf_size = 0;
210
211     return ret;
212 }
213
214 static inline BSCallback *impl_from_IBindStatusCallback(IBindStatusCallback *iface)
215 {
216     return CONTAINING_RECORD(iface, BSCallback, IBindStatusCallback_iface);
217 }
218
219 static HRESULT WINAPI BindStatusCallback_QueryInterface(IBindStatusCallback *iface,
220         REFIID riid, void **ppv)
221 {
222     BSCallback *This = impl_from_IBindStatusCallback(iface);
223
224     *ppv = NULL;
225     if(IsEqualGUID(&IID_IUnknown, riid)) {
226         TRACE("(%p)->(IID_IUnknown, %p)\n", This, ppv);
227         *ppv = &This->IBindStatusCallback_iface;
228     }else if(IsEqualGUID(&IID_IBindStatusCallback, riid)) {
229         TRACE("(%p)->(IID_IBindStatusCallback, %p)\n", This, ppv);
230         *ppv = &This->IBindStatusCallback_iface;
231     }else if(IsEqualGUID(&IID_IServiceProvider, riid)) {
232         TRACE("(%p)->(IID_IServiceProvider %p)\n", This, ppv);
233         *ppv = &This->IServiceProvider_iface;
234     }else if(IsEqualGUID(&IID_IHttpNegotiate, riid)) {
235         TRACE("(%p)->(IID_IHttpNegotiate %p)\n", This, ppv);
236         *ppv = &This->IHttpNegotiate2_iface;
237     }else if(IsEqualGUID(&IID_IHttpNegotiate2, riid)) {
238         TRACE("(%p)->(IID_IHttpNegotiate2 %p)\n", This, ppv);
239         *ppv = &This->IHttpNegotiate2_iface;
240     }else if(IsEqualGUID(&IID_IInternetBindInfo, riid)) {
241         TRACE("(%p)->(IID_IInternetBindInfo %p)\n", This, ppv);
242         *ppv = &This->IInternetBindInfo_iface;
243     }
244
245     if(*ppv) {
246         IBindStatusCallback_AddRef(&This->IBindStatusCallback_iface);
247         return S_OK;
248     }
249
250     TRACE("Unsupported riid = %s\n", debugstr_guid(riid));
251     return E_NOINTERFACE;
252 }
253
254 static ULONG WINAPI BindStatusCallback_AddRef(IBindStatusCallback *iface)
255 {
256     BSCallback *This = impl_from_IBindStatusCallback(iface);
257     LONG ref = InterlockedIncrement(&This->ref);
258
259     TRACE("(%p) ref = %d\n", This, ref);
260
261     return ref;
262 }
263
264 static ULONG WINAPI BindStatusCallback_Release(IBindStatusCallback *iface)
265 {
266     BSCallback *This = impl_from_IBindStatusCallback(iface);
267     LONG ref = InterlockedDecrement(&This->ref);
268
269     TRACE("(%p) ref = %d\n", This, ref);
270
271     if(!ref) {
272         if(This->post_data)
273             GlobalFree(This->post_data);
274         if(This->mon)
275             IMoniker_Release(This->mon);
276         if(This->binding)
277             IBinding_Release(This->binding);
278         list_remove(&This->entry);
279         list_init(&This->entry);
280         heap_free(This->headers);
281
282         This->vtbl->destroy(This);
283     }
284
285     return ref;
286 }
287
288 static HRESULT WINAPI BindStatusCallback_OnStartBinding(IBindStatusCallback *iface,
289         DWORD dwReserved, IBinding *pbind)
290 {
291     BSCallback *This = impl_from_IBindStatusCallback(iface);
292
293     TRACE("(%p)->(%d %p)\n", This, dwReserved, pbind);
294
295     IBinding_AddRef(pbind);
296     This->binding = pbind;
297
298     if(This->doc)
299         list_add_head(&This->doc->bindings, &This->entry);
300
301     return This->vtbl->start_binding(This);
302 }
303
304 static HRESULT WINAPI BindStatusCallback_GetPriority(IBindStatusCallback *iface, LONG *pnPriority)
305 {
306     BSCallback *This = impl_from_IBindStatusCallback(iface);
307     FIXME("(%p)->(%p)\n", This, pnPriority);
308     return E_NOTIMPL;
309 }
310
311 static HRESULT WINAPI BindStatusCallback_OnLowResource(IBindStatusCallback *iface, DWORD reserved)
312 {
313     BSCallback *This = impl_from_IBindStatusCallback(iface);
314     FIXME("(%p)->(%d)\n", This, reserved);
315     return E_NOTIMPL;
316 }
317
318 static HRESULT WINAPI BindStatusCallback_OnProgress(IBindStatusCallback *iface, ULONG ulProgress,
319         ULONG ulProgressMax, ULONG ulStatusCode, LPCWSTR szStatusText)
320 {
321     BSCallback *This = impl_from_IBindStatusCallback(iface);
322
323     TRACE("%p)->(%u %u %u %s)\n", This, ulProgress, ulProgressMax, ulStatusCode,
324             debugstr_w(szStatusText));
325
326     return This->vtbl->on_progress(This, ulStatusCode, szStatusText);
327 }
328
329 static HRESULT WINAPI BindStatusCallback_OnStopBinding(IBindStatusCallback *iface,
330         HRESULT hresult, LPCWSTR szError)
331 {
332     BSCallback *This = impl_from_IBindStatusCallback(iface);
333     HRESULT hres;
334
335     TRACE("(%p)->(%08x %s)\n", This, hresult, debugstr_w(szError));
336
337     /* NOTE: IE7 calls GetBindResult here */
338
339     hres = This->vtbl->stop_binding(This, hresult);
340
341     if(This->binding) {
342         IBinding_Release(This->binding);
343         This->binding = NULL;
344     }
345
346     list_remove(&This->entry);
347     list_init(&This->entry);
348     This->doc = NULL;
349
350     return hres;
351 }
352
353 static HRESULT WINAPI BindStatusCallback_GetBindInfo(IBindStatusCallback *iface,
354         DWORD *grfBINDF, BINDINFO *pbindinfo)
355 {
356     BSCallback *This = impl_from_IBindStatusCallback(iface);
357     DWORD size;
358
359     TRACE("(%p)->(%p %p)\n", This, grfBINDF, pbindinfo);
360
361     if(!This->bindinfo_ready) {
362         HRESULT hres;
363
364         hres = This->vtbl->init_bindinfo(This);
365         if(FAILED(hres))
366             return hres;
367
368         This->bindinfo_ready = TRUE;
369     }
370
371     *grfBINDF = This->bindf;
372
373     size = pbindinfo->cbSize;
374     memset(pbindinfo, 0, size);
375     pbindinfo->cbSize = size;
376
377     pbindinfo->cbstgmedData = This->post_data_len;
378     pbindinfo->dwCodePage = CP_UTF8;
379     pbindinfo->dwOptions = 0x80000;
380
381     if(This->post_data) {
382         pbindinfo->dwBindVerb = BINDVERB_POST;
383
384         pbindinfo->stgmedData.tymed = TYMED_HGLOBAL;
385         pbindinfo->stgmedData.u.hGlobal = This->post_data;
386         pbindinfo->stgmedData.pUnkForRelease = (IUnknown*)&This->IBindStatusCallback_iface;
387         IBindStatusCallback_AddRef(&This->IBindStatusCallback_iface);
388     }
389
390     return S_OK;
391 }
392
393 static HRESULT WINAPI BindStatusCallback_OnDataAvailable(IBindStatusCallback *iface,
394         DWORD grfBSCF, DWORD dwSize, FORMATETC *pformatetc, STGMEDIUM *pstgmed)
395 {
396     BSCallback *This = impl_from_IBindStatusCallback(iface);
397
398     TRACE("(%p)->(%08x %d %p %p)\n", This, grfBSCF, dwSize, pformatetc, pstgmed);
399
400     return This->vtbl->read_data(This, pstgmed->u.pstm);
401 }
402
403 static HRESULT WINAPI BindStatusCallback_OnObjectAvailable(IBindStatusCallback *iface,
404         REFIID riid, IUnknown *punk)
405 {
406     BSCallback *This = impl_from_IBindStatusCallback(iface);
407     FIXME("(%p)->(%s %p)\n", This, debugstr_guid(riid), punk);
408     return E_NOTIMPL;
409 }
410
411 static const IBindStatusCallbackVtbl BindStatusCallbackVtbl = {
412     BindStatusCallback_QueryInterface,
413     BindStatusCallback_AddRef,
414     BindStatusCallback_Release,
415     BindStatusCallback_OnStartBinding,
416     BindStatusCallback_GetPriority,
417     BindStatusCallback_OnLowResource,
418     BindStatusCallback_OnProgress,
419     BindStatusCallback_OnStopBinding,
420     BindStatusCallback_GetBindInfo,
421     BindStatusCallback_OnDataAvailable,
422     BindStatusCallback_OnObjectAvailable
423 };
424
425 static inline BSCallback *impl_from_IHttpNegotiate2(IHttpNegotiate2 *iface)
426 {
427     return CONTAINING_RECORD(iface, BSCallback, IHttpNegotiate2_iface);
428 }
429
430 static HRESULT WINAPI HttpNegotiate_QueryInterface(IHttpNegotiate2 *iface,
431                                                    REFIID riid, void **ppv)
432 {
433     BSCallback *This = impl_from_IHttpNegotiate2(iface);
434     return IBindStatusCallback_QueryInterface(&This->IBindStatusCallback_iface, riid, ppv);
435 }
436
437 static ULONG WINAPI HttpNegotiate_AddRef(IHttpNegotiate2 *iface)
438 {
439     BSCallback *This = impl_from_IHttpNegotiate2(iface);
440     return IBindStatusCallback_AddRef(&This->IBindStatusCallback_iface);
441 }
442
443 static ULONG WINAPI HttpNegotiate_Release(IHttpNegotiate2 *iface)
444 {
445     BSCallback *This = impl_from_IHttpNegotiate2(iface);
446     return IBindStatusCallback_Release(&This->IBindStatusCallback_iface);
447 }
448
449 static HRESULT WINAPI HttpNegotiate_BeginningTransaction(IHttpNegotiate2 *iface,
450         LPCWSTR szURL, LPCWSTR szHeaders, DWORD dwReserved, LPWSTR *pszAdditionalHeaders)
451 {
452     BSCallback *This = impl_from_IHttpNegotiate2(iface);
453     HRESULT hres;
454
455     TRACE("(%p)->(%s %s %d %p)\n", This, debugstr_w(szURL), debugstr_w(szHeaders),
456           dwReserved, pszAdditionalHeaders);
457
458     *pszAdditionalHeaders = NULL;
459
460     hres = This->vtbl->beginning_transaction(This, pszAdditionalHeaders);
461     if(hres != S_FALSE)
462         return hres;
463
464     if(This->headers) {
465         DWORD size;
466
467         size = (strlenW(This->headers)+1)*sizeof(WCHAR);
468         *pszAdditionalHeaders = CoTaskMemAlloc(size);
469         if(!*pszAdditionalHeaders)
470             return E_OUTOFMEMORY;
471         memcpy(*pszAdditionalHeaders, This->headers, size);
472     }
473
474     return S_OK;
475 }
476
477 static HRESULT WINAPI HttpNegotiate_OnResponse(IHttpNegotiate2 *iface, DWORD dwResponseCode,
478         LPCWSTR szResponseHeaders, LPCWSTR szRequestHeaders, LPWSTR *pszAdditionalRequestHeaders)
479 {
480     BSCallback *This = impl_from_IHttpNegotiate2(iface);
481
482     TRACE("(%p)->(%d %s %s %p)\n", This, dwResponseCode, debugstr_w(szResponseHeaders),
483           debugstr_w(szRequestHeaders), pszAdditionalRequestHeaders);
484
485     return This->vtbl->on_response(This, dwResponseCode, szResponseHeaders);
486 }
487
488 static HRESULT WINAPI HttpNegotiate_GetRootSecurityId(IHttpNegotiate2 *iface,
489         BYTE *pbSecurityId, DWORD *pcbSecurityId, DWORD_PTR dwReserved)
490 {
491     BSCallback *This = impl_from_IHttpNegotiate2(iface);
492     FIXME("(%p)->(%p %p %ld)\n", This, pbSecurityId, pcbSecurityId, dwReserved);
493     return E_NOTIMPL;
494 }
495
496 static const IHttpNegotiate2Vtbl HttpNegotiate2Vtbl = {
497     HttpNegotiate_QueryInterface,
498     HttpNegotiate_AddRef,
499     HttpNegotiate_Release,
500     HttpNegotiate_BeginningTransaction,
501     HttpNegotiate_OnResponse,
502     HttpNegotiate_GetRootSecurityId
503 };
504
505 static inline BSCallback *impl_from_IInternetBindInfo(IInternetBindInfo *iface)
506 {
507     return CONTAINING_RECORD(iface, BSCallback, IInternetBindInfo_iface);
508 }
509
510 static HRESULT WINAPI InternetBindInfo_QueryInterface(IInternetBindInfo *iface,
511                                                       REFIID riid, void **ppv)
512 {
513     BSCallback *This = impl_from_IInternetBindInfo(iface);
514     return IBindStatusCallback_QueryInterface(&This->IBindStatusCallback_iface, riid, ppv);
515 }
516
517 static ULONG WINAPI InternetBindInfo_AddRef(IInternetBindInfo *iface)
518 {
519     BSCallback *This = impl_from_IInternetBindInfo(iface);
520     return IBindStatusCallback_AddRef(&This->IBindStatusCallback_iface);
521 }
522
523 static ULONG WINAPI InternetBindInfo_Release(IInternetBindInfo *iface)
524 {
525     BSCallback *This = impl_from_IInternetBindInfo(iface);
526     return IBindStatusCallback_Release(&This->IBindStatusCallback_iface);
527 }
528
529 static HRESULT WINAPI InternetBindInfo_GetBindInfo(IInternetBindInfo *iface,
530                                                    DWORD *grfBINDF, BINDINFO *pbindinfo)
531 {
532     BSCallback *This = impl_from_IInternetBindInfo(iface);
533     FIXME("(%p)->(%p %p)\n", This, grfBINDF, pbindinfo);
534     return E_NOTIMPL;
535 }
536
537 static HRESULT WINAPI InternetBindInfo_GetBindString(IInternetBindInfo *iface,
538         ULONG ulStringType, LPOLESTR *ppwzStr, ULONG cEl, ULONG *pcElFetched)
539 {
540     BSCallback *This = impl_from_IInternetBindInfo(iface);
541     FIXME("(%p)->(%u %p %u %p)\n", This, ulStringType, ppwzStr, cEl, pcElFetched);
542     return E_NOTIMPL;
543 }
544
545 static const IInternetBindInfoVtbl InternetBindInfoVtbl = {
546     InternetBindInfo_QueryInterface,
547     InternetBindInfo_AddRef,
548     InternetBindInfo_Release,
549     InternetBindInfo_GetBindInfo,
550     InternetBindInfo_GetBindString
551 };
552
553 static inline BSCallback *impl_from_IServiceProvider(IServiceProvider *iface)
554 {
555     return CONTAINING_RECORD(iface, BSCallback, IServiceProvider_iface);
556 }
557
558 static HRESULT WINAPI BSCServiceProvider_QueryInterface(IServiceProvider *iface,
559                                                         REFIID riid, void **ppv)
560 {
561     BSCallback *This = impl_from_IServiceProvider(iface);
562     return IBindStatusCallback_QueryInterface(&This->IBindStatusCallback_iface, riid, ppv);
563 }
564
565 static ULONG WINAPI BSCServiceProvider_AddRef(IServiceProvider *iface)
566 {
567     BSCallback *This = impl_from_IServiceProvider(iface);
568     return IBindStatusCallback_AddRef(&This->IBindStatusCallback_iface);
569 }
570
571 static ULONG WINAPI BSCServiceProvider_Release(IServiceProvider *iface)
572 {
573     BSCallback *This = impl_from_IServiceProvider(iface);
574     return IBindStatusCallback_Release(&This->IBindStatusCallback_iface);
575 }
576
577 static HRESULT WINAPI BSCServiceProvider_QueryService(IServiceProvider *iface,
578         REFGUID guidService, REFIID riid, void **ppv)
579 {
580     BSCallback *This = impl_from_IServiceProvider(iface);
581     TRACE("(%p)->(%s %s %p)\n", This, debugstr_guid(guidService), debugstr_guid(riid), ppv);
582     return E_NOINTERFACE;
583 }
584
585 static const IServiceProviderVtbl ServiceProviderVtbl = {
586     BSCServiceProvider_QueryInterface,
587     BSCServiceProvider_AddRef,
588     BSCServiceProvider_Release,
589     BSCServiceProvider_QueryService
590 };
591
592 static void init_bscallback(BSCallback *This, const BSCallbackVtbl *vtbl, IMoniker *mon, DWORD bindf)
593 {
594     This->IBindStatusCallback_iface.lpVtbl = &BindStatusCallbackVtbl;
595     This->IServiceProvider_iface.lpVtbl = &ServiceProviderVtbl;
596     This->IHttpNegotiate2_iface.lpVtbl = &HttpNegotiate2Vtbl;
597     This->IInternetBindInfo_iface.lpVtbl = &InternetBindInfoVtbl;
598     This->vtbl = vtbl;
599     This->ref = 1;
600     This->bindf = bindf;
601
602     list_init(&This->entry);
603
604     if(mon)
605         IMoniker_AddRef(mon);
606     This->mon = mon;
607 }
608
609 /* Calls undocumented 84 cmd of CGID_ShellDocView */
610 static void call_docview_84(HTMLDocumentObj *doc)
611 {
612     IOleCommandTarget *olecmd;
613     VARIANT var;
614     HRESULT hres;
615
616     if(!doc->client)
617         return;
618
619     hres = IOleClientSite_QueryInterface(doc->client, &IID_IOleCommandTarget, (void**)&olecmd);
620     if(FAILED(hres))
621         return;
622
623     VariantInit(&var);
624     hres = IOleCommandTarget_Exec(olecmd, &CGID_ShellDocView, 84, 0, NULL, &var);
625     IOleCommandTarget_Release(olecmd);
626     if(SUCCEEDED(hres) && V_VT(&var) != VT_NULL)
627         FIXME("handle result\n");
628 }
629
630 static HRESULT parse_headers(const WCHAR *headers, struct list *headers_list)
631 {
632     const WCHAR *header, *header_end, *colon, *value;
633     HRESULT hres;
634
635     header = headers;
636     while(*header) {
637         if(header[0] == '\r' && header[1] == '\n' && !header[2])
638             break;
639         for(colon = header; *colon && *colon != ':' && *colon != '\r'; colon++);
640         if(*colon != ':')
641             return E_FAIL;
642
643         value = colon+1;
644         while(*value == ' ')
645             value++;
646         if(!*value)
647             return E_FAIL;
648
649         for(header_end = value+1; *header_end && *header_end != '\r'; header_end++);
650
651         hres = set_http_header(headers_list, header, colon-header, value, header_end-value);
652         if(FAILED(hres))
653             return hres;
654
655         header = header_end;
656         if(header[0] == '\r' && header[1] == '\n')
657             header += 2;
658     }
659
660     return S_OK;
661 }
662
663 HRESULT start_binding(HTMLWindow *window, HTMLDocumentNode *doc, BSCallback *bscallback, IBindCtx *bctx)
664 {
665     IStream *str = NULL;
666     HRESULT hres;
667
668     TRACE("(%p %p %p %p)\n", window, doc, bscallback, bctx);
669
670     bscallback->doc = doc;
671
672     /* NOTE: IE7 calls IsSystemMoniker here*/
673
674     if(window) {
675         if(bscallback->mon != window->mon)
676             set_current_mon(window, bscallback->mon);
677         call_docview_84(window->doc_obj);
678     }
679
680     if(bctx) {
681         RegisterBindStatusCallback(bctx, &bscallback->IBindStatusCallback_iface, NULL, 0);
682         IBindCtx_AddRef(bctx);
683     }else {
684         hres = CreateAsyncBindCtx(0, &bscallback->IBindStatusCallback_iface, NULL, &bctx);
685         if(FAILED(hres)) {
686             WARN("CreateAsyncBindCtx failed: %08x\n", hres);
687             bscallback->vtbl->stop_binding(bscallback, hres);
688             return hres;
689         }
690     }
691
692     hres = IMoniker_BindToStorage(bscallback->mon, bctx, NULL, &IID_IStream, (void**)&str);
693     IBindCtx_Release(bctx);
694     if(FAILED(hres)) {
695         WARN("BindToStorage failed: %08x\n", hres);
696         bscallback->vtbl->stop_binding(bscallback, hres);
697         return hres;
698     }
699
700     if(str)
701         IStream_Release(str);
702
703     IMoniker_Release(bscallback->mon);
704     bscallback->mon = NULL;
705
706     return S_OK;
707 }
708
709 typedef struct {
710     BSCallback bsc;
711
712     DWORD size;
713     BYTE *buf;
714     HRESULT hres;
715 } BufferBSC;
716
717 static inline BufferBSC *BufferBSC_from_BSCallback(BSCallback *iface)
718 {
719     return CONTAINING_RECORD(iface, BufferBSC, bsc);
720 }
721
722 static void BufferBSC_destroy(BSCallback *bsc)
723 {
724     BufferBSC *This = BufferBSC_from_BSCallback(bsc);
725
726     heap_free(This->buf);
727     heap_free(This);
728 }
729
730 static HRESULT BufferBSC_init_bindinfo(BSCallback *bsc)
731 {
732     return S_OK;
733 }
734
735 static HRESULT BufferBSC_start_binding(BSCallback *bsc)
736 {
737     return S_OK;
738 }
739
740 static HRESULT BufferBSC_stop_binding(BSCallback *bsc, HRESULT result)
741 {
742     BufferBSC *This = BufferBSC_from_BSCallback(bsc);
743
744     This->hres = result;
745
746     if(FAILED(result)) {
747         heap_free(This->buf);
748         This->buf = NULL;
749         This->size = 0;
750     }
751
752     return S_OK;
753 }
754
755 static HRESULT BufferBSC_read_data(BSCallback *bsc, IStream *stream)
756 {
757     BufferBSC *This = BufferBSC_from_BSCallback(bsc);
758     DWORD readed;
759     HRESULT hres;
760
761     if(!This->buf) {
762         This->size = 128;
763         This->buf = heap_alloc(This->size);
764     }
765
766     do {
767         if(This->bsc.readed == This->size) {
768             This->size <<= 1;
769             This->buf = heap_realloc(This->buf, This->size);
770         }
771
772         readed = 0;
773         hres = IStream_Read(stream, This->buf+This->bsc.readed, This->size-This->bsc.readed, &readed);
774         This->bsc.readed += readed;
775     }while(hres == S_OK);
776
777     return S_OK;
778 }
779
780 static HRESULT BufferBSC_on_progress(BSCallback *bsc, ULONG status_code, LPCWSTR status_text)
781 {
782     return S_OK;
783 }
784
785 static HRESULT BufferBSC_on_response(BSCallback *bsc, DWORD response_code,
786         LPCWSTR response_headers)
787 {
788     return S_OK;
789 }
790
791 static HRESULT BufferBSC_beginning_transaction(BSCallback *bsc, WCHAR **additional_headers)
792 {
793     return S_FALSE;
794 }
795
796 static const BSCallbackVtbl BufferBSCVtbl = {
797     BufferBSC_destroy,
798     BufferBSC_init_bindinfo,
799     BufferBSC_start_binding,
800     BufferBSC_stop_binding,
801     BufferBSC_read_data,
802     BufferBSC_on_progress,
803     BufferBSC_on_response,
804     BufferBSC_beginning_transaction
805 };
806
807
808 static BufferBSC *create_bufferbsc(IMoniker *mon)
809 {
810     BufferBSC *ret = heap_alloc_zero(sizeof(*ret));
811
812     init_bscallback(&ret->bsc, &BufferBSCVtbl, mon, 0);
813     ret->hres = E_FAIL;
814
815     return ret;
816 }
817
818 HRESULT bind_mon_to_buffer(HTMLDocumentNode *doc, IMoniker *mon, void **buf, DWORD *size)
819 {
820     BufferBSC *bsc = create_bufferbsc(mon);
821     HRESULT hres;
822
823     *buf = NULL;
824
825     hres = start_binding(NULL, doc, &bsc->bsc, NULL);
826     if(SUCCEEDED(hres)) {
827         hres = bsc->hres;
828         if(SUCCEEDED(hres)) {
829             *buf = bsc->buf;
830             bsc->buf = NULL;
831             *size = bsc->bsc.readed;
832             bsc->size = 0;
833         }
834     }
835
836     IBindStatusCallback_Release(&bsc->bsc.IBindStatusCallback_iface);
837
838     return hres;
839 }
840
841 static HRESULT read_post_data_stream(nsChannelBSC *This, nsChannel *nschannel)
842 {
843     PRUint32 data_len = 0, available = 0;
844     char *data, *post_data;
845     nsresult nsres;
846     HRESULT hres = S_OK;
847
848     if(!nschannel->post_data_stream)
849         return S_OK;
850
851     nsres =  nsIInputStream_Available(nschannel->post_data_stream, &available);
852     if(NS_FAILED(nsres))
853         return E_FAIL;
854
855     post_data = data = GlobalAlloc(0, available);
856     if(!data)
857         return E_OUTOFMEMORY;
858
859     nsres = nsIInputStream_Read(nschannel->post_data_stream, data, available, &data_len);
860     if(NS_FAILED(nsres)) {
861         GlobalFree(data);
862         return E_FAIL;
863     }
864
865     if(nschannel->post_data_contains_headers) {
866         if(data_len >= 2 && data[0] == '\r' && data[1] == '\n') {
867             post_data = data+2;
868             data_len -= 2;
869         }else {
870             WCHAR *headers;
871             DWORD size;
872             char *ptr;
873
874             post_data += data_len;
875             for(ptr = data; ptr+4 < data+data_len; ptr++) {
876                 if(!memcmp(ptr, "\r\n\r\n", 4)) {
877                     post_data = ptr+4;
878                     break;
879                 }
880             }
881
882             data_len -= post_data-data;
883
884             size = MultiByteToWideChar(CP_ACP, 0, data, post_data-data, NULL, 0);
885             headers = heap_alloc((size+1)*sizeof(WCHAR));
886             if(headers) {
887                 MultiByteToWideChar(CP_ACP, 0, data, post_data-data, headers, size);
888                 headers[size] = 0;
889                 hres = parse_headers(headers , &nschannel->request_headers);
890                 if(SUCCEEDED(hres))
891                     This->bsc.headers = headers;
892                 else
893                     heap_free(headers);
894             }else {
895                 hres = E_OUTOFMEMORY;
896             }
897         }
898     }
899
900     if(FAILED(hres)) {
901         GlobalFree(data);
902         return hres;
903     }
904
905     if(!data_len) {
906         GlobalFree(data);
907         post_data = NULL;
908     }else if(post_data != data) {
909         char *new_data;
910
911         new_data = GlobalAlloc(0, data_len);
912         if(new_data)
913             memcpy(new_data, post_data, data_len);
914         GlobalFree(data);
915         if(!new_data)
916             return E_OUTOFMEMORY;
917         post_data = new_data;
918     }
919
920     This->bsc.post_data = post_data;
921     This->bsc.post_data_len = data_len;
922     TRACE("post_data = %s\n", debugstr_a(This->bsc.post_data));
923     return S_OK;
924 }
925
926 static HRESULT on_start_nsrequest(nsChannelBSC *This)
927 {
928     nsresult nsres;
929
930     /* FIXME: it's needed for http connections from BindToObject. */
931     if(!This->nschannel->response_status)
932         This->nschannel->response_status = 200;
933
934     nsres = nsIStreamListener_OnStartRequest(This->nslistener,
935             (nsIRequest*)&This->nschannel->nsIHttpChannel_iface, This->nscontext);
936     if(NS_FAILED(nsres)) {
937         FIXME("OnStartRequest failed: %08x\n", nsres);
938         return E_FAIL;
939     }
940
941     if(This->window) {
942         list_remove(&This->bsc.entry);
943         list_init(&This->bsc.entry);
944         update_window_doc(This->window);
945         if(This->window->doc != This->bsc.doc)
946             This->bsc.doc = This->window->doc;
947         list_add_head(&This->bsc.doc->bindings, &This->bsc.entry);
948         if(This->window->readystate != READYSTATE_LOADING)
949             set_ready_state(This->window, READYSTATE_LOADING);
950     }
951
952     return S_OK;
953 }
954
955 static void on_stop_nsrequest(nsChannelBSC *This, HRESULT result)
956 {
957     nsresult nsres, request_result;
958
959     switch(result) {
960     case S_OK:
961         request_result = NS_OK;
962         break;
963     case E_ABORT:
964         request_result = NS_BINDING_ABORTED;
965         break;
966     default:
967         request_result = NS_ERROR_FAILURE;
968     }
969
970     if(This->nslistener) {
971         nsres = nsIStreamListener_OnStopRequest(This->nslistener,
972                  (nsIRequest*)&This->nschannel->nsIHttpChannel_iface, This->nscontext,
973                  request_result);
974         if(NS_FAILED(nsres))
975             WARN("OnStopRequet failed: %08x\n", nsres);
976     }
977
978     if(This->nschannel->load_group) {
979         nsres = nsILoadGroup_RemoveRequest(This->nschannel->load_group,
980                 (nsIRequest*)&This->nschannel->nsIHttpChannel_iface, NULL, request_result);
981         if(NS_FAILED(nsres))
982             ERR("RemoveRequest failed: %08x\n", nsres);
983     }
984 }
985
986 static HRESULT read_stream_data(nsChannelBSC *This, IStream *stream)
987 {
988     DWORD read;
989     nsresult nsres;
990     HRESULT hres;
991
992     if(!This->nslistener) {
993         BYTE buf[1024];
994
995         do {
996             read = 0;
997             hres = IStream_Read(stream, buf, sizeof(buf), &read);
998         }while(hres == S_OK && read);
999
1000         return S_OK;
1001     }
1002
1003     if(!This->nsstream)
1004         This->nsstream = create_nsprotocol_stream();
1005
1006     do {
1007         read = 0;
1008         hres = IStream_Read(stream, This->nsstream->buf+This->nsstream->buf_size,
1009                 sizeof(This->nsstream->buf)-This->nsstream->buf_size, &read);
1010         if(!read)
1011             break;
1012
1013         This->nsstream->buf_size += read;
1014
1015         if(!This->bsc.readed) {
1016             if(This->nsstream->buf_size >= 2
1017                && (BYTE)This->nsstream->buf[0] == 0xff
1018                && (BYTE)This->nsstream->buf[1] == 0xfe)
1019                 This->nschannel->charset = heap_strdupA(UTF16_STR);
1020
1021             if(!This->nschannel->content_type) {
1022                 WCHAR *mime;
1023
1024                 hres = FindMimeFromData(NULL, NULL, This->nsstream->buf, This->nsstream->buf_size, NULL, 0, &mime, 0);
1025                 if(FAILED(hres))
1026                     return hres;
1027
1028                 TRACE("Found MIME %s\n", debugstr_w(mime));
1029
1030                 This->nschannel->content_type = heap_strdupWtoA(mime);
1031                 CoTaskMemFree(mime);
1032                 if(!This->nschannel->content_type)
1033                     return E_OUTOFMEMORY;
1034             }
1035
1036             on_start_nsrequest(This);
1037         }
1038
1039         This->bsc.readed += This->nsstream->buf_size;
1040
1041         nsres = nsIStreamListener_OnDataAvailable(This->nslistener,
1042                 (nsIRequest*)&This->nschannel->nsIHttpChannel_iface, This->nscontext,
1043                 &This->nsstream->nsIInputStream_iface, This->bsc.readed-This->nsstream->buf_size,
1044                 This->nsstream->buf_size);
1045         if(NS_FAILED(nsres))
1046             ERR("OnDataAvailable failed: %08x\n", nsres);
1047
1048         if(This->nsstream->buf_size == sizeof(This->nsstream->buf)) {
1049             ERR("buffer is full\n");
1050             break;
1051         }
1052     }while(hres == S_OK);
1053
1054     return S_OK;
1055 }
1056
1057 typedef struct {
1058     nsIAsyncVerifyRedirectCallback nsIAsyncVerifyRedirectCallback_iface;
1059
1060     LONG ref;
1061
1062     nsChannel *nschannel;
1063     nsChannelBSC *bsc;
1064 } nsRedirectCallback;
1065
1066 static nsRedirectCallback *impl_from_nsIAsyncVerifyRedirectCallback(nsIAsyncVerifyRedirectCallback *iface)
1067 {
1068     return CONTAINING_RECORD(iface, nsRedirectCallback, nsIAsyncVerifyRedirectCallback_iface);
1069 }
1070
1071 static nsresult NSAPI nsAsyncVerifyRedirectCallback_QueryInterface(nsIAsyncVerifyRedirectCallback *iface,
1072         nsIIDRef riid, void **result)
1073 {
1074     nsRedirectCallback *This = impl_from_nsIAsyncVerifyRedirectCallback(iface);
1075
1076     if(IsEqualGUID(&IID_nsISupports, riid)) {
1077         TRACE("(%p)->(IID_nsISuports %p)\n", This, result);
1078         *result = &This->nsIAsyncVerifyRedirectCallback_iface;
1079     }else if(IsEqualGUID(&IID_nsIAsyncVerifyRedirectCallback, riid)) {
1080         TRACE("(%p)->(IID_nsIAsyncVerifyRedirectCallback %p)\n", This, result);
1081         *result = &This->nsIAsyncVerifyRedirectCallback_iface;
1082     }else {
1083         *result = NULL;
1084         WARN("unimplemented iface %s\n", debugstr_guid(riid));
1085         return NS_NOINTERFACE;
1086     }
1087
1088     nsISupports_AddRef((nsISupports*)*result);
1089     return NS_OK;
1090 }
1091
1092 static nsrefcnt NSAPI nsAsyncVerifyRedirectCallback_AddRef(nsIAsyncVerifyRedirectCallback *iface)
1093 {
1094     nsRedirectCallback *This = impl_from_nsIAsyncVerifyRedirectCallback(iface);
1095     LONG ref = InterlockedIncrement(&This->ref);
1096
1097     TRACE("(%p) ref=%d\n", This, ref);
1098
1099     return ref;
1100 }
1101
1102 static nsrefcnt NSAPI nsAsyncVerifyRedirectCallback_Release(nsIAsyncVerifyRedirectCallback *iface)
1103 {
1104     nsRedirectCallback *This = impl_from_nsIAsyncVerifyRedirectCallback(iface);
1105     LONG ref = InterlockedDecrement(&This->ref);
1106
1107     TRACE("(%p) ref=%d\n", This, ref);
1108
1109     if(!ref) {
1110         IBindStatusCallback_Release(&This->bsc->bsc.IBindStatusCallback_iface);
1111         nsIChannel_Release(&This->nschannel->nsIHttpChannel_iface);
1112         heap_free(This);
1113     }
1114
1115     return ref;
1116 }
1117
1118 static nsresult NSAPI nsAsyncVerifyRedirectCallback_AsyncOnChannelRedirect(nsIAsyncVerifyRedirectCallback *iface, nsresult result)
1119 {
1120     nsRedirectCallback *This = impl_from_nsIAsyncVerifyRedirectCallback(iface);
1121
1122     TRACE("(%p)->(%08x)\n", This, result);
1123
1124     if(This->bsc->nschannel)
1125         nsIHttpChannel_Release(&This->bsc->nschannel->nsIHttpChannel_iface);
1126     nsIChannel_AddRef(&This->nschannel->nsIHttpChannel_iface);
1127     This->bsc->nschannel = This->nschannel;
1128
1129     if(This->nschannel->load_group) {
1130         nsresult nsres;
1131
1132         nsres = nsILoadGroup_AddRequest(This->nschannel->load_group, (nsIRequest*)&This->nschannel->nsIHttpChannel_iface,
1133                 NULL);
1134         if(NS_FAILED(nsres))
1135             ERR("AddRequest failed: %08x\n", nsres);
1136     }
1137
1138     return NS_OK;
1139 }
1140
1141 static const nsIAsyncVerifyRedirectCallbackVtbl nsAsyncVerifyRedirectCallbackVtbl = {
1142     nsAsyncVerifyRedirectCallback_QueryInterface,
1143     nsAsyncVerifyRedirectCallback_AddRef,
1144     nsAsyncVerifyRedirectCallback_Release,
1145     nsAsyncVerifyRedirectCallback_AsyncOnChannelRedirect
1146 };
1147
1148 static HRESULT create_redirect_callback(nsChannel *nschannel, nsChannelBSC *bsc, nsRedirectCallback **ret)
1149 {
1150     nsRedirectCallback *callback;
1151
1152     callback = heap_alloc(sizeof(*callback));
1153     if(!callback)
1154         return E_OUTOFMEMORY;
1155
1156     callback->nsIAsyncVerifyRedirectCallback_iface.lpVtbl = &nsAsyncVerifyRedirectCallbackVtbl;
1157     callback->ref = 1;
1158
1159     nsIChannel_AddRef(&nschannel->nsIHttpChannel_iface);
1160     callback->nschannel = nschannel;
1161
1162     IBindStatusCallback_AddRef(&bsc->bsc.IBindStatusCallback_iface);
1163     callback->bsc = bsc;
1164
1165     *ret = callback;
1166     return S_OK;
1167 }
1168
1169 static inline nsChannelBSC *nsChannelBSC_from_BSCallback(BSCallback *iface)
1170 {
1171     return CONTAINING_RECORD(iface, nsChannelBSC, bsc);
1172 }
1173
1174 static void nsChannelBSC_destroy(BSCallback *bsc)
1175 {
1176     nsChannelBSC *This = nsChannelBSC_from_BSCallback(bsc);
1177
1178     if(This->nschannel)
1179         nsIChannel_Release(&This->nschannel->nsIHttpChannel_iface);
1180     if(This->nslistener)
1181         nsIStreamListener_Release(This->nslistener);
1182     if(This->nscontext)
1183         nsISupports_Release(This->nscontext);
1184     if(This->nsstream)
1185         nsIInputStream_Release(&This->nsstream->nsIInputStream_iface);
1186     heap_free(This);
1187 }
1188
1189 static HRESULT nsChannelBSC_start_binding(BSCallback *bsc)
1190 {
1191     nsChannelBSC *This = nsChannelBSC_from_BSCallback(bsc);
1192
1193     if(This->window)
1194         This->window->doc->skip_mutation_notif = FALSE;
1195
1196     return S_OK;
1197 }
1198
1199 static HRESULT nsChannelBSC_init_bindinfo(BSCallback *bsc)
1200 {
1201     nsChannelBSC *This = nsChannelBSC_from_BSCallback(bsc);
1202     HRESULT hres;
1203
1204     if(This->nschannel && This->nschannel->post_data_stream) {
1205         hres = read_post_data_stream(This, This->nschannel);
1206         if(FAILED(hres))
1207             return hres;
1208     }
1209
1210     return S_OK;
1211 }
1212
1213 typedef struct {
1214     task_t header;
1215     nsChannelBSC *bsc;
1216 } stop_request_task_t;
1217
1218 static void stop_request_proc(task_t *_task)
1219 {
1220     stop_request_task_t *task = (stop_request_task_t*)_task;
1221
1222     TRACE("(%p)\n", task->bsc);
1223
1224     list_remove(&task->bsc->bsc.entry);
1225     list_init(&task->bsc->bsc.entry);
1226     on_stop_nsrequest(task->bsc, S_OK);
1227     IBindStatusCallback_Release(&task->bsc->bsc.IBindStatusCallback_iface);
1228 }
1229
1230 static HRESULT async_stop_request(nsChannelBSC *This)
1231 {
1232     stop_request_task_t *task;
1233
1234     if(!This->bsc.readed) {
1235         TRACE("No data read, calling OnStartRequest\n");
1236         on_start_nsrequest(This);
1237     }
1238
1239     task = heap_alloc(sizeof(*task));
1240     if(!task)
1241         return E_OUTOFMEMORY;
1242
1243     IBindStatusCallback_AddRef(&This->bsc.IBindStatusCallback_iface);
1244     task->bsc = This;
1245     push_task(&task->header, stop_request_proc, This->bsc.doc->basedoc.doc_obj->basedoc.task_magic);
1246     return S_OK;
1247 }
1248
1249 static void handle_navigation_error(nsChannelBSC *This, DWORD result)
1250 {
1251     HTMLDocumentObj *doc;
1252     IOleCommandTarget *olecmd;
1253     BOOL is_error_url;
1254     SAFEARRAY *sa;
1255     SAFEARRAYBOUND bound;
1256     VARIANT var, varOut;
1257     LONG ind;
1258     BSTR url, unk;
1259     HRESULT hres;
1260
1261     if(!This->window)
1262         return;
1263
1264     doc = This->window->doc_obj;
1265     if(!doc || !doc->doc_object_service || !doc->client)
1266         return;
1267
1268     hres = IDocObjectService_IsErrorUrl(doc->doc_object_service,
1269             This->window->url, &is_error_url);
1270     if(FAILED(hres) || is_error_url)
1271         return;
1272
1273     hres = IOleClientSite_QueryInterface(doc->client,
1274             &IID_IOleCommandTarget, (void**)&olecmd);
1275     if(FAILED(hres))
1276         return;
1277
1278     bound.lLbound = 0;
1279     bound.cElements = 8;
1280     sa = SafeArrayCreate(VT_VARIANT, 1, &bound);
1281     if(!sa) {
1282         IOleCommandTarget_Release(olecmd);
1283         return;
1284     }
1285
1286     ind = 0;
1287     V_VT(&var) = VT_I4;
1288     V_I4(&var) = result;
1289     SafeArrayPutElement(sa, &ind, &var);
1290
1291     ind = 1;
1292     V_VT(&var) = VT_BSTR;
1293     url = SysAllocString(This->window->url);
1294     V_BSTR(&var) = url;
1295     SafeArrayPutElement(sa, &ind, &var);
1296
1297     ind = 3;
1298     V_VT(&var) = VT_UNKNOWN;
1299     V_UNKNOWN(&var) = (IUnknown*)&This->window->IHTMLWindow2_iface;
1300     SafeArrayPutElement(sa, &ind, &var);
1301
1302     /* FIXME: what are the following fields for? */
1303     ind = 2;
1304     V_VT(&var) = VT_UNKNOWN;
1305     V_UNKNOWN(&var) = NULL;
1306     SafeArrayPutElement(sa, &ind, &var);
1307
1308     ind = 4;
1309     V_VT(&var) = VT_BOOL;
1310     V_BOOL(&var) = FALSE;
1311     SafeArrayPutElement(sa, &ind, &var);
1312
1313     ind = 5;
1314     V_VT(&var) = VT_BOOL;
1315     V_BOOL(&var) = FALSE;
1316     SafeArrayPutElement(sa, &ind, &var);
1317
1318     ind = 6;
1319     V_VT(&var) = VT_BSTR;
1320     unk = SysAllocString(NULL);
1321     V_BSTR(&var) = unk;
1322     SafeArrayPutElement(sa, &ind, &var);
1323
1324     ind = 7;
1325     V_VT(&var) = VT_UNKNOWN;
1326     V_UNKNOWN(&var) = NULL;
1327     SafeArrayPutElement(sa, &ind, &var);
1328
1329     V_VT(&var) = VT_ARRAY;
1330     V_ARRAY(&var) = sa;
1331     V_VT(&varOut) = VT_BOOL;
1332     V_BOOL(&varOut) = VARIANT_TRUE;
1333     IOleCommandTarget_Exec(olecmd, &CGID_DocHostCmdPriv, 1, 0, &var, FAILED(hres)?NULL:&varOut);
1334
1335     SysFreeString(url);
1336     SysFreeString(unk);
1337     SafeArrayDestroy(sa);
1338     IOleCommandTarget_Release(olecmd);
1339 }
1340
1341 static HRESULT nsChannelBSC_stop_binding(BSCallback *bsc, HRESULT result)
1342 {
1343     nsChannelBSC *This = nsChannelBSC_from_BSCallback(bsc);
1344
1345     if(result != E_ABORT) {
1346         if(FAILED(result))
1347             handle_navigation_error(This, result);
1348         else if(This->window) {
1349             result = async_stop_request(This);
1350             if(SUCCEEDED(result))
1351                 return S_OK;
1352         }
1353     }
1354
1355     on_stop_nsrequest(This, result);
1356     return S_OK;
1357 }
1358
1359 static HRESULT nsChannelBSC_read_data(BSCallback *bsc, IStream *stream)
1360 {
1361     nsChannelBSC *This = nsChannelBSC_from_BSCallback(bsc);
1362
1363     return read_stream_data(This, stream);
1364 }
1365
1366 static HRESULT handle_redirect(nsChannelBSC *This, const WCHAR *new_url)
1367 {
1368     nsRedirectCallback *callback;
1369     nsIChannelEventSink *sink;
1370     nsChannel *new_channel;
1371     nsresult nsres;
1372     HRESULT hres;
1373
1374     TRACE("(%p)->(%s)\n", This, debugstr_w(new_url));
1375
1376     if(!This->nschannel || !This->nschannel->notif_callback)
1377         return S_OK;
1378
1379     nsres = nsIInterfaceRequestor_GetInterface(This->nschannel->notif_callback, &IID_nsIChannelEventSink, (void**)&sink);
1380     if(NS_FAILED(nsres))
1381         return S_OK;
1382
1383     hres = create_redirect_nschannel(new_url, This->nschannel, &new_channel);
1384     if(SUCCEEDED(hres)) {
1385         hres = create_redirect_callback(new_channel, This, &callback);
1386         nsIChannel_Release(&new_channel->nsIHttpChannel_iface);
1387     }
1388
1389     if(SUCCEEDED(hres)) {
1390         nsres = nsIChannelEventSink_AsyncOnChannelRedirect(sink, (nsIChannel*)&This->nschannel->nsIHttpChannel_iface,
1391                 (nsIChannel*)&callback->nschannel->nsIHttpChannel_iface, REDIRECT_TEMPORARY, /* FIXME */
1392                 &callback->nsIAsyncVerifyRedirectCallback_iface);
1393
1394         if(NS_FAILED(nsres))
1395             FIXME("AsyncOnChannelRedirect failed: %08x\n", hres);
1396         else if(This->nschannel != callback->nschannel)
1397             FIXME("nschannel not updated\n");
1398
1399         nsIAsyncVerifyRedirectCallback_Release(&callback->nsIAsyncVerifyRedirectCallback_iface);
1400     }
1401
1402     nsIChannelEventSink_Release(sink);
1403     return hres;
1404 }
1405
1406 static HRESULT nsChannelBSC_on_progress(BSCallback *bsc, ULONG status_code, LPCWSTR status_text)
1407 {
1408     nsChannelBSC *This = nsChannelBSC_from_BSCallback(bsc);
1409
1410     switch(status_code) {
1411     case BINDSTATUS_MIMETYPEAVAILABLE:
1412         if(!This->nschannel)
1413             return S_OK;
1414
1415         heap_free(This->nschannel->content_type);
1416         This->nschannel->content_type = heap_strdupWtoA(status_text);
1417         break;
1418     case BINDSTATUS_REDIRECTING:
1419         return handle_redirect(This, status_text);
1420     case BINDSTATUS_BEGINDOWNLOADDATA: {
1421         IWinInetHttpInfo *http_info;
1422         DWORD status, size = sizeof(DWORD);
1423         HRESULT hres;
1424
1425         if(!This->bsc.binding)
1426             break;
1427
1428         hres = IBinding_QueryInterface(This->bsc.binding, &IID_IWinInetHttpInfo, (void**)&http_info);
1429         if(FAILED(hres))
1430             break;
1431
1432         hres = IWinInetHttpInfo_QueryInfo(http_info,
1433                 HTTP_QUERY_STATUS_CODE|HTTP_QUERY_FLAG_NUMBER, &status, &size, NULL, NULL);
1434         IWinInetHttpInfo_Release(http_info);
1435         if(FAILED(hres) || status == HTTP_STATUS_OK)
1436             break;
1437
1438         handle_navigation_error(This, status);
1439     }
1440     }
1441
1442     return S_OK;
1443 }
1444
1445 static HRESULT nsChannelBSC_on_response(BSCallback *bsc, DWORD response_code,
1446         LPCWSTR response_headers)
1447 {
1448     nsChannelBSC *This = nsChannelBSC_from_BSCallback(bsc);
1449     HRESULT hres;
1450
1451     This->nschannel->response_status = response_code;
1452
1453     if(response_headers) {
1454         const WCHAR *headers;
1455
1456         headers = strchrW(response_headers, '\r');
1457         if(headers && headers[1] == '\n') {
1458             headers += 2;
1459             hres = parse_headers(headers, &This->nschannel->response_headers);
1460             if(FAILED(hres)) {
1461                 WARN("parsing headers failed: %08x\n", hres);
1462                 return hres;
1463             }
1464         }
1465     }
1466
1467     return S_OK;
1468 }
1469
1470 static HRESULT nsChannelBSC_beginning_transaction(BSCallback *bsc, WCHAR **additional_headers)
1471 {
1472     nsChannelBSC *This = nsChannelBSC_from_BSCallback(bsc);
1473     http_header_t *iter;
1474     DWORD len = 0;
1475     WCHAR *ptr;
1476
1477     static const WCHAR content_lengthW[] =
1478         {'C','o','n','t','e','n','t','-','L','e','n','g','t','h',0};
1479
1480     if(!This->nschannel)
1481         return S_FALSE;
1482
1483     LIST_FOR_EACH_ENTRY(iter, &This->nschannel->request_headers, http_header_t, entry) {
1484         if(strcmpW(iter->header, content_lengthW))
1485             len += strlenW(iter->header) + 2 /* ": " */ + strlenW(iter->data) + 2 /* "\r\n" */;
1486     }
1487
1488     if(!len)
1489         return S_OK;
1490
1491     *additional_headers = ptr = CoTaskMemAlloc((len+1)*sizeof(WCHAR));
1492     if(!ptr)
1493         return E_OUTOFMEMORY;
1494
1495     LIST_FOR_EACH_ENTRY(iter, &This->nschannel->request_headers, http_header_t, entry) {
1496         if(!strcmpW(iter->header, content_lengthW))
1497             continue;
1498
1499         len = strlenW(iter->header);
1500         memcpy(ptr, iter->header, len*sizeof(WCHAR));
1501         ptr += len;
1502
1503         *ptr++ = ':';
1504         *ptr++ = ' ';
1505
1506         len = strlenW(iter->data);
1507         memcpy(ptr, iter->data, len*sizeof(WCHAR));
1508         ptr += len;
1509
1510         *ptr++ = '\r';
1511         *ptr++ = '\n';
1512     }
1513
1514     *ptr = 0;
1515
1516     return S_OK;
1517 }
1518
1519 static const BSCallbackVtbl nsChannelBSCVtbl = {
1520     nsChannelBSC_destroy,
1521     nsChannelBSC_init_bindinfo,
1522     nsChannelBSC_start_binding,
1523     nsChannelBSC_stop_binding,
1524     nsChannelBSC_read_data,
1525     nsChannelBSC_on_progress,
1526     nsChannelBSC_on_response,
1527     nsChannelBSC_beginning_transaction
1528 };
1529
1530 HRESULT create_channelbsc(IMoniker *mon, WCHAR *headers, BYTE *post_data, DWORD post_data_size, nsChannelBSC **retval)
1531 {
1532     nsChannelBSC *ret;
1533
1534     ret = heap_alloc_zero(sizeof(*ret));
1535     if(!ret)
1536         return E_OUTOFMEMORY;
1537
1538     init_bscallback(&ret->bsc, &nsChannelBSCVtbl, mon, BINDF_ASYNCHRONOUS | BINDF_ASYNCSTORAGE | BINDF_PULLDATA);
1539
1540     if(headers) {
1541         ret->bsc.headers = heap_strdupW(headers);
1542         if(!ret->bsc.headers) {
1543             IBindStatusCallback_Release(&ret->bsc.IBindStatusCallback_iface);
1544             return E_OUTOFMEMORY;
1545         }
1546     }
1547
1548     if(post_data) {
1549         ret->bsc.post_data = GlobalAlloc(0, post_data_size);
1550         if(!ret->bsc.post_data) {
1551             heap_free(ret->bsc.headers);
1552             IBindStatusCallback_Release(&ret->bsc.IBindStatusCallback_iface);
1553             return E_OUTOFMEMORY;
1554         }
1555
1556         memcpy(ret->bsc.post_data, post_data, post_data_size);
1557         ret->bsc.post_data_len = post_data_size;
1558     }
1559
1560     *retval = ret;
1561     return S_OK;
1562 }
1563
1564 void set_window_bscallback(HTMLWindow *window, nsChannelBSC *callback)
1565 {
1566     if(window->bscallback) {
1567         if(window->bscallback->bsc.binding)
1568             IBinding_Abort(window->bscallback->bsc.binding);
1569         window->bscallback->bsc.doc = NULL;
1570         window->bscallback->window = NULL;
1571         IBindStatusCallback_Release(&window->bscallback->bsc.IBindStatusCallback_iface);
1572     }
1573
1574     window->bscallback = callback;
1575
1576     if(callback) {
1577         callback->window = window;
1578         IBindStatusCallback_AddRef(&callback->bsc.IBindStatusCallback_iface);
1579         callback->bsc.doc = window->doc;
1580     }
1581 }
1582
1583 typedef struct {
1584     task_t header;
1585     HTMLWindow *window;
1586     nsChannelBSC *bscallback;
1587 } start_doc_binding_task_t;
1588
1589 static void start_doc_binding_proc(task_t *_task)
1590 {
1591     start_doc_binding_task_t *task = (start_doc_binding_task_t*)_task;
1592
1593     start_binding(task->window, NULL, (BSCallback*)task->bscallback, NULL);
1594     IBindStatusCallback_Release(&task->bscallback->bsc.IBindStatusCallback_iface);
1595 }
1596
1597 HRESULT async_start_doc_binding(HTMLWindow *window, nsChannelBSC *bscallback)
1598 {
1599     start_doc_binding_task_t *task;
1600
1601     task = heap_alloc(sizeof(start_doc_binding_task_t));
1602     if(!task)
1603         return E_OUTOFMEMORY;
1604
1605     task->window = window;
1606     task->bscallback = bscallback;
1607     IBindStatusCallback_AddRef(&bscallback->bsc.IBindStatusCallback_iface);
1608
1609     push_task(&task->header, start_doc_binding_proc, window->task_magic);
1610     return S_OK;
1611 }
1612
1613 void abort_document_bindings(HTMLDocumentNode *doc)
1614 {
1615     BSCallback *iter, *next;
1616
1617     LIST_FOR_EACH_ENTRY_SAFE(iter, next, &doc->bindings, BSCallback, entry) {
1618         TRACE("Aborting %p\n", iter);
1619
1620         if(iter->doc)
1621             remove_target_tasks(iter->doc->basedoc.task_magic);
1622
1623         if(iter->binding)
1624             IBinding_Abort(iter->binding);
1625         else {
1626             list_remove(&iter->entry);
1627             list_init(&iter->entry);
1628             iter->vtbl->stop_binding(iter, E_ABORT);
1629         }
1630
1631         iter->doc = NULL;
1632     }
1633 }
1634
1635 HRESULT channelbsc_load_stream(nsChannelBSC *bscallback, IStream *stream)
1636 {
1637     HRESULT hres = S_OK;
1638
1639     if(!bscallback->nschannel) {
1640         ERR("NULL nschannel\n");
1641         return E_FAIL;
1642     }
1643
1644     bscallback->nschannel->content_type = heap_strdupA("text/html");
1645     if(!bscallback->nschannel->content_type)
1646         return E_OUTOFMEMORY;
1647
1648     list_add_head(&bscallback->bsc.doc->bindings, &bscallback->bsc.entry);
1649     if(stream)
1650         hres = read_stream_data(bscallback, stream);
1651     if(SUCCEEDED(hres))
1652         hres = async_stop_request(bscallback);
1653     if(FAILED(hres))
1654         IBindStatusCallback_OnStopBinding(&bscallback->bsc.IBindStatusCallback_iface, hres,
1655                 ERROR_SUCCESS);
1656
1657     return hres;
1658 }
1659
1660 void channelbsc_set_channel(nsChannelBSC *This, nsChannel *channel, nsIStreamListener *listener, nsISupports *context)
1661 {
1662     nsIChannel_AddRef(&channel->nsIHttpChannel_iface);
1663     This->nschannel = channel;
1664
1665     nsIStreamListener_AddRef(listener);
1666     This->nslistener = listener;
1667
1668     if(context) {
1669         nsISupports_AddRef(context);
1670         This->nscontext = context;
1671     }
1672
1673     if(This->bsc.headers) {
1674         HRESULT hres;
1675
1676         hres = parse_headers(This->bsc.headers, &channel->request_headers);
1677         heap_free(This->bsc.headers);
1678         This->bsc.headers = NULL;
1679         if(FAILED(hres))
1680             WARN("parse_headers failed: %08x\n", hres);
1681     }
1682 }
1683
1684 HRESULT hlink_frame_navigate(HTMLDocument *doc, LPCWSTR url, nsChannel *nschannel, DWORD hlnf, BOOL *cancel)
1685 {
1686     IHlinkFrame *hlink_frame;
1687     nsChannelBSC *callback;
1688     IServiceProvider *sp;
1689     IBindCtx *bindctx;
1690     IMoniker *mon;
1691     IHlink *hlink;
1692     HRESULT hres;
1693
1694     *cancel = FALSE;
1695
1696     hres = IOleClientSite_QueryInterface(doc->doc_obj->client, &IID_IServiceProvider,
1697             (void**)&sp);
1698     if(FAILED(hres))
1699         return S_OK;
1700
1701     hres = IServiceProvider_QueryService(sp, &IID_IHlinkFrame, &IID_IHlinkFrame,
1702             (void**)&hlink_frame);
1703     IServiceProvider_Release(sp);
1704     if(FAILED(hres))
1705         return S_OK;
1706
1707     hres = create_channelbsc(NULL, NULL, NULL, 0, &callback);
1708     if(FAILED(hres)) {
1709         IHlinkFrame_Release(hlink_frame);
1710         return hres;
1711     }
1712
1713     if(nschannel)
1714         read_post_data_stream(callback, nschannel);
1715
1716     hres = CreateAsyncBindCtx(0, &callback->bsc.IBindStatusCallback_iface, NULL, &bindctx);
1717     if(SUCCEEDED(hres))
1718         hres = CoCreateInstance(&CLSID_StdHlink, NULL, CLSCTX_INPROC_SERVER,
1719                 &IID_IHlink, (LPVOID*)&hlink);
1720
1721     if(SUCCEEDED(hres))
1722         hres = CreateURLMoniker(NULL, url, &mon);
1723
1724     if(SUCCEEDED(hres)) {
1725         IHlink_SetMonikerReference(hlink, HLINKSETF_TARGET, mon, NULL);
1726
1727         if(hlnf & HLNF_OPENINNEWWINDOW) {
1728             static const WCHAR wszBlank[] = {'_','b','l','a','n','k',0};
1729             IHlink_SetTargetFrameName(hlink, wszBlank); /* FIXME */
1730         }
1731
1732         hres = IHlinkFrame_Navigate(hlink_frame, hlnf, bindctx,
1733                 &callback->bsc.IBindStatusCallback_iface, hlink);
1734         IMoniker_Release(mon);
1735         *cancel = hres == S_OK;
1736         hres = S_OK;
1737     }
1738
1739     IHlinkFrame_Release(hlink_frame);
1740     IBindCtx_Release(bindctx);
1741     IBindStatusCallback_Release(&callback->bsc.IBindStatusCallback_iface);
1742     return hres;
1743 }
1744
1745 HRESULT navigate_url(HTMLWindow *window, const WCHAR *new_url, const WCHAR *base_url)
1746 {
1747     WCHAR url[INTERNET_MAX_URL_LENGTH];
1748     nsWineURI *uri;
1749     HRESULT hres;
1750
1751     if(!new_url) {
1752         *url = 0;
1753     }else if(base_url) {
1754         DWORD len = 0;
1755
1756         hres = CoInternetCombineUrl(base_url, new_url, URL_ESCAPE_SPACES_ONLY|URL_DONT_ESCAPE_EXTRA_INFO,
1757                 url, sizeof(url)/sizeof(WCHAR), &len, 0);
1758         if(FAILED(hres))
1759             return hres;
1760     }else {
1761         strcpyW(url, new_url);
1762     }
1763
1764     if(window->doc_obj && window->doc_obj->hostui) {
1765         OLECHAR *translated_url = NULL;
1766
1767         hres = IDocHostUIHandler_TranslateUrl(window->doc_obj->hostui, 0, url,
1768                 &translated_url);
1769         if(hres == S_OK) {
1770             TRACE("%08x %s -> %s\n", hres, debugstr_w(url), debugstr_w(translated_url));
1771             strcpyW(url, translated_url);
1772             CoTaskMemFree(translated_url);
1773         }
1774     }
1775
1776     if(window->doc_obj && window == window->doc_obj->basedoc.window) {
1777         BOOL cancel;
1778
1779         hres = hlink_frame_navigate(&window->doc->basedoc, url, NULL, 0, &cancel);
1780         if(FAILED(hres))
1781             return hres;
1782
1783         if(cancel) {
1784             TRACE("Navigation handled by hlink frame\n");
1785             return S_OK;
1786         }
1787     }
1788
1789     hres = create_doc_uri(window, url, &uri);
1790     if(FAILED(hres))
1791         return hres;
1792
1793     hres = load_nsuri(window, uri, NULL, LOAD_FLAGS_NONE);
1794     nsISupports_Release((nsISupports*)uri);
1795     return hres;
1796 }