oleaut32/tests: Use a better invalid color for the olepicture icon test.
[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 #include "htiface.h"
37 #include "shdeprecated.h"
38
39 #include "wine/debug.h"
40
41 #include "mshtml_private.h"
42 #include "binding.h"
43
44 WINE_DEFAULT_DEBUG_CHANNEL(mshtml);
45
46 #define CONTENT_LENGTH "Content-Length"
47 #define UTF16_STR "utf-16"
48
49 static const WCHAR emptyW[] = {0};
50
51 struct nsProtocolStream {
52     nsIInputStream nsIInputStream_iface;
53
54     LONG ref;
55
56     char buf[1024];
57     DWORD buf_size;
58 };
59
60 struct BSCallbackVtbl {
61     void (*destroy)(BSCallback*);
62     HRESULT (*init_bindinfo)(BSCallback*);
63     HRESULT (*start_binding)(BSCallback*);
64     HRESULT (*stop_binding)(BSCallback*,HRESULT);
65     HRESULT (*read_data)(BSCallback*,IStream*);
66     HRESULT (*on_progress)(BSCallback*,ULONG,LPCWSTR);
67     HRESULT (*on_response)(BSCallback*,DWORD,LPCWSTR);
68     HRESULT (*beginning_transaction)(BSCallback*,WCHAR**);
69 };
70
71 static inline nsProtocolStream *impl_from_nsIInputStream(nsIInputStream *iface)
72 {
73     return CONTAINING_RECORD(iface, nsProtocolStream, nsIInputStream_iface);
74 }
75
76 static nsresult NSAPI nsInputStream_QueryInterface(nsIInputStream *iface, nsIIDRef riid,
77         void **result)
78 {
79     nsProtocolStream *This = impl_from_nsIInputStream(iface);
80
81     *result = NULL;
82
83     if(IsEqualGUID(&IID_nsISupports, riid)) {
84         TRACE("(%p)->(IID_nsISupports %p)\n", This, result);
85         *result  = &This->nsIInputStream_iface;
86     }else if(IsEqualGUID(&IID_nsIInputStream, riid)) {
87         TRACE("(%p)->(IID_nsIInputStream %p)\n", This, result);
88         *result  = &This->nsIInputStream_iface;
89     }
90
91     if(*result) {
92         nsIInputStream_AddRef(&This->nsIInputStream_iface);
93         return NS_OK;
94     }
95
96     WARN("unsupported interface %s\n", debugstr_guid(riid));
97     return NS_NOINTERFACE;
98 }
99
100 static nsrefcnt NSAPI nsInputStream_AddRef(nsIInputStream *iface)
101 {
102     nsProtocolStream *This = impl_from_nsIInputStream(iface);
103     LONG ref = InterlockedIncrement(&This->ref);
104
105     TRACE("(%p) ref=%d\n", This, ref);
106
107     return ref;
108 }
109
110
111 static nsrefcnt NSAPI nsInputStream_Release(nsIInputStream *iface)
112 {
113     nsProtocolStream *This = impl_from_nsIInputStream(iface);
114     LONG ref = InterlockedDecrement(&This->ref);
115
116     TRACE("(%p) ref=%d\n", This, ref);
117
118     if(!ref)
119         heap_free(This);
120
121     return ref;
122 }
123
124 static nsresult NSAPI nsInputStream_Close(nsIInputStream *iface)
125 {
126     nsProtocolStream *This = impl_from_nsIInputStream(iface);
127     FIXME("(%p)\n", This);
128     return NS_ERROR_NOT_IMPLEMENTED;
129 }
130
131 static nsresult NSAPI nsInputStream_Available(nsIInputStream *iface, PRUint32 *_retval)
132 {
133     nsProtocolStream *This = impl_from_nsIInputStream(iface);
134     FIXME("(%p)->(%p)\n", This, _retval);
135     return NS_ERROR_NOT_IMPLEMENTED;
136 }
137
138 static nsresult NSAPI nsInputStream_Read(nsIInputStream *iface, char *aBuf, PRUint32 aCount,
139                                          PRUint32 *_retval)
140 {
141     nsProtocolStream *This = impl_from_nsIInputStream(iface);
142     DWORD read = aCount;
143
144     TRACE("(%p)->(%p %d %p)\n", This, aBuf, aCount, _retval);
145
146     if(read > This->buf_size)
147         read = This->buf_size;
148
149     if(read) {
150         memcpy(aBuf, This->buf, read);
151         if(read < This->buf_size)
152             memmove(This->buf, This->buf+read, This->buf_size-read);
153         This->buf_size -= read;
154     }
155
156     *_retval = read;
157     return NS_OK;
158 }
159
160 static nsresult NSAPI nsInputStream_ReadSegments(nsIInputStream *iface,
161         nsresult (WINAPI *aWriter)(nsIInputStream*,void*,const char*,PRUint32,PRUint32,PRUint32*),
162         void *aClousure, PRUint32 aCount, PRUint32 *_retval)
163 {
164     nsProtocolStream *This = impl_from_nsIInputStream(iface);
165     PRUint32 written = 0;
166     nsresult nsres;
167
168     TRACE("(%p)->(%p %p %d %p)\n", This, aWriter, aClousure, aCount, _retval);
169
170     if(!This->buf_size)
171         return S_OK;
172
173     if(aCount > This->buf_size)
174         aCount = This->buf_size;
175
176     nsres = aWriter(&This->nsIInputStream_iface, aClousure, This->buf, 0, aCount, &written);
177     if(NS_FAILED(nsres))
178         TRACE("aWritter failed: %08x\n", nsres);
179     else if(written != This->buf_size)
180         FIXME("written %d != buf_size %d\n", written, This->buf_size);
181
182     This->buf_size -= written; 
183
184     *_retval = written;
185     return nsres;
186 }
187
188 static nsresult NSAPI nsInputStream_IsNonBlocking(nsIInputStream *iface, PRBool *_retval)
189 {
190     nsProtocolStream *This = impl_from_nsIInputStream(iface);
191     FIXME("(%p)->(%p)\n", This, _retval);
192     return NS_ERROR_NOT_IMPLEMENTED;
193 }
194
195 static const nsIInputStreamVtbl nsInputStreamVtbl = {
196     nsInputStream_QueryInterface,
197     nsInputStream_AddRef,
198     nsInputStream_Release,
199     nsInputStream_Close,
200     nsInputStream_Available,
201     nsInputStream_Read,
202     nsInputStream_ReadSegments,
203     nsInputStream_IsNonBlocking
204 };
205
206 static nsProtocolStream *create_nsprotocol_stream(void)
207 {
208     nsProtocolStream *ret = heap_alloc(sizeof(nsProtocolStream));
209
210     ret->nsIInputStream_iface.lpVtbl = &nsInputStreamVtbl;
211     ret->ref = 1;
212     ret->buf_size = 0;
213
214     return ret;
215 }
216
217 static inline BSCallback *impl_from_IBindStatusCallback(IBindStatusCallback *iface)
218 {
219     return CONTAINING_RECORD(iface, BSCallback, IBindStatusCallback_iface);
220 }
221
222 static HRESULT WINAPI BindStatusCallback_QueryInterface(IBindStatusCallback *iface,
223         REFIID riid, void **ppv)
224 {
225     BSCallback *This = impl_from_IBindStatusCallback(iface);
226
227     *ppv = NULL;
228     if(IsEqualGUID(&IID_IUnknown, riid)) {
229         TRACE("(%p)->(IID_IUnknown, %p)\n", This, ppv);
230         *ppv = &This->IBindStatusCallback_iface;
231     }else if(IsEqualGUID(&IID_IBindStatusCallback, riid)) {
232         TRACE("(%p)->(IID_IBindStatusCallback, %p)\n", This, ppv);
233         *ppv = &This->IBindStatusCallback_iface;
234     }else if(IsEqualGUID(&IID_IServiceProvider, riid)) {
235         TRACE("(%p)->(IID_IServiceProvider %p)\n", This, ppv);
236         *ppv = &This->IServiceProvider_iface;
237     }else if(IsEqualGUID(&IID_IHttpNegotiate, riid)) {
238         TRACE("(%p)->(IID_IHttpNegotiate %p)\n", This, ppv);
239         *ppv = &This->IHttpNegotiate2_iface;
240     }else if(IsEqualGUID(&IID_IHttpNegotiate2, riid)) {
241         TRACE("(%p)->(IID_IHttpNegotiate2 %p)\n", This, ppv);
242         *ppv = &This->IHttpNegotiate2_iface;
243     }else if(IsEqualGUID(&IID_IInternetBindInfo, riid)) {
244         TRACE("(%p)->(IID_IInternetBindInfo %p)\n", This, ppv);
245         *ppv = &This->IInternetBindInfo_iface;
246     }
247
248     if(*ppv) {
249         IBindStatusCallback_AddRef(&This->IBindStatusCallback_iface);
250         return S_OK;
251     }
252
253     TRACE("Unsupported riid = %s\n", debugstr_guid(riid));
254     return E_NOINTERFACE;
255 }
256
257 static ULONG WINAPI BindStatusCallback_AddRef(IBindStatusCallback *iface)
258 {
259     BSCallback *This = impl_from_IBindStatusCallback(iface);
260     LONG ref = InterlockedIncrement(&This->ref);
261
262     TRACE("(%p) ref = %d\n", This, ref);
263
264     return ref;
265 }
266
267 static ULONG WINAPI BindStatusCallback_Release(IBindStatusCallback *iface)
268 {
269     BSCallback *This = impl_from_IBindStatusCallback(iface);
270     LONG ref = InterlockedDecrement(&This->ref);
271
272     TRACE("(%p) ref = %d\n", This, ref);
273
274     if(!ref) {
275         if(This->post_data)
276             GlobalFree(This->post_data);
277         if(This->mon)
278             IMoniker_Release(This->mon);
279         if(This->binding)
280             IBinding_Release(This->binding);
281         list_remove(&This->entry);
282         list_init(&This->entry);
283         heap_free(This->headers);
284
285         This->vtbl->destroy(This);
286     }
287
288     return ref;
289 }
290
291 static HRESULT WINAPI BindStatusCallback_OnStartBinding(IBindStatusCallback *iface,
292         DWORD dwReserved, IBinding *pbind)
293 {
294     BSCallback *This = impl_from_IBindStatusCallback(iface);
295
296     TRACE("(%p)->(%d %p)\n", This, dwReserved, pbind);
297
298     IBinding_AddRef(pbind);
299     This->binding = pbind;
300
301     if(This->doc)
302         list_add_head(&This->doc->bindings, &This->entry);
303
304     return This->vtbl->start_binding(This);
305 }
306
307 static HRESULT WINAPI BindStatusCallback_GetPriority(IBindStatusCallback *iface, LONG *pnPriority)
308 {
309     BSCallback *This = impl_from_IBindStatusCallback(iface);
310     FIXME("(%p)->(%p)\n", This, pnPriority);
311     return E_NOTIMPL;
312 }
313
314 static HRESULT WINAPI BindStatusCallback_OnLowResource(IBindStatusCallback *iface, DWORD reserved)
315 {
316     BSCallback *This = impl_from_IBindStatusCallback(iface);
317     FIXME("(%p)->(%d)\n", This, reserved);
318     return E_NOTIMPL;
319 }
320
321 static HRESULT WINAPI BindStatusCallback_OnProgress(IBindStatusCallback *iface, ULONG ulProgress,
322         ULONG ulProgressMax, ULONG ulStatusCode, LPCWSTR szStatusText)
323 {
324     BSCallback *This = impl_from_IBindStatusCallback(iface);
325
326     TRACE("%p)->(%u %u %u %s)\n", This, ulProgress, ulProgressMax, ulStatusCode,
327             debugstr_w(szStatusText));
328
329     return This->vtbl->on_progress(This, ulStatusCode, szStatusText);
330 }
331
332 static HRESULT WINAPI BindStatusCallback_OnStopBinding(IBindStatusCallback *iface,
333         HRESULT hresult, LPCWSTR szError)
334 {
335     BSCallback *This = impl_from_IBindStatusCallback(iface);
336     HRESULT hres;
337
338     TRACE("(%p)->(%08x %s)\n", This, hresult, debugstr_w(szError));
339
340     /* NOTE: IE7 calls GetBindResult here */
341
342     hres = This->vtbl->stop_binding(This, hresult);
343
344     if(This->binding) {
345         IBinding_Release(This->binding);
346         This->binding = NULL;
347     }
348
349     list_remove(&This->entry);
350     list_init(&This->entry);
351     This->doc = NULL;
352
353     return hres;
354 }
355
356 static HRESULT WINAPI BindStatusCallback_GetBindInfo(IBindStatusCallback *iface,
357         DWORD *grfBINDF, BINDINFO *pbindinfo)
358 {
359     BSCallback *This = impl_from_IBindStatusCallback(iface);
360     DWORD size;
361
362     TRACE("(%p)->(%p %p)\n", This, grfBINDF, pbindinfo);
363
364     if(!This->bindinfo_ready) {
365         HRESULT hres;
366
367         hres = This->vtbl->init_bindinfo(This);
368         if(FAILED(hres))
369             return hres;
370
371         This->bindinfo_ready = TRUE;
372     }
373
374     *grfBINDF = This->bindf;
375
376     size = pbindinfo->cbSize;
377     memset(pbindinfo, 0, size);
378     pbindinfo->cbSize = size;
379
380     pbindinfo->cbstgmedData = This->post_data_len;
381     pbindinfo->dwCodePage = CP_UTF8;
382     pbindinfo->dwOptions = 0x80000;
383
384     if(This->post_data) {
385         pbindinfo->dwBindVerb = BINDVERB_POST;
386
387         pbindinfo->stgmedData.tymed = TYMED_HGLOBAL;
388         pbindinfo->stgmedData.u.hGlobal = This->post_data;
389         pbindinfo->stgmedData.pUnkForRelease = (IUnknown*)&This->IBindStatusCallback_iface;
390         IBindStatusCallback_AddRef(&This->IBindStatusCallback_iface);
391     }
392
393     return S_OK;
394 }
395
396 static HRESULT WINAPI BindStatusCallback_OnDataAvailable(IBindStatusCallback *iface,
397         DWORD grfBSCF, DWORD dwSize, FORMATETC *pformatetc, STGMEDIUM *pstgmed)
398 {
399     BSCallback *This = impl_from_IBindStatusCallback(iface);
400
401     TRACE("(%p)->(%08x %d %p %p)\n", This, grfBSCF, dwSize, pformatetc, pstgmed);
402
403     return This->vtbl->read_data(This, pstgmed->u.pstm);
404 }
405
406 static HRESULT WINAPI BindStatusCallback_OnObjectAvailable(IBindStatusCallback *iface,
407         REFIID riid, IUnknown *punk)
408 {
409     BSCallback *This = impl_from_IBindStatusCallback(iface);
410     FIXME("(%p)->(%s %p)\n", This, debugstr_guid(riid), punk);
411     return E_NOTIMPL;
412 }
413
414 static const IBindStatusCallbackVtbl BindStatusCallbackVtbl = {
415     BindStatusCallback_QueryInterface,
416     BindStatusCallback_AddRef,
417     BindStatusCallback_Release,
418     BindStatusCallback_OnStartBinding,
419     BindStatusCallback_GetPriority,
420     BindStatusCallback_OnLowResource,
421     BindStatusCallback_OnProgress,
422     BindStatusCallback_OnStopBinding,
423     BindStatusCallback_GetBindInfo,
424     BindStatusCallback_OnDataAvailable,
425     BindStatusCallback_OnObjectAvailable
426 };
427
428 static inline BSCallback *impl_from_IHttpNegotiate2(IHttpNegotiate2 *iface)
429 {
430     return CONTAINING_RECORD(iface, BSCallback, IHttpNegotiate2_iface);
431 }
432
433 static HRESULT WINAPI HttpNegotiate_QueryInterface(IHttpNegotiate2 *iface,
434                                                    REFIID riid, void **ppv)
435 {
436     BSCallback *This = impl_from_IHttpNegotiate2(iface);
437     return IBindStatusCallback_QueryInterface(&This->IBindStatusCallback_iface, riid, ppv);
438 }
439
440 static ULONG WINAPI HttpNegotiate_AddRef(IHttpNegotiate2 *iface)
441 {
442     BSCallback *This = impl_from_IHttpNegotiate2(iface);
443     return IBindStatusCallback_AddRef(&This->IBindStatusCallback_iface);
444 }
445
446 static ULONG WINAPI HttpNegotiate_Release(IHttpNegotiate2 *iface)
447 {
448     BSCallback *This = impl_from_IHttpNegotiate2(iface);
449     return IBindStatusCallback_Release(&This->IBindStatusCallback_iface);
450 }
451
452 static HRESULT WINAPI HttpNegotiate_BeginningTransaction(IHttpNegotiate2 *iface,
453         LPCWSTR szURL, LPCWSTR szHeaders, DWORD dwReserved, LPWSTR *pszAdditionalHeaders)
454 {
455     BSCallback *This = impl_from_IHttpNegotiate2(iface);
456     HRESULT hres;
457
458     TRACE("(%p)->(%s %s %d %p)\n", This, debugstr_w(szURL), debugstr_w(szHeaders),
459           dwReserved, pszAdditionalHeaders);
460
461     *pszAdditionalHeaders = NULL;
462
463     hres = This->vtbl->beginning_transaction(This, pszAdditionalHeaders);
464     if(hres != S_FALSE)
465         return hres;
466
467     if(This->headers) {
468         DWORD size;
469
470         size = (strlenW(This->headers)+1)*sizeof(WCHAR);
471         *pszAdditionalHeaders = CoTaskMemAlloc(size);
472         if(!*pszAdditionalHeaders)
473             return E_OUTOFMEMORY;
474         memcpy(*pszAdditionalHeaders, This->headers, size);
475     }
476
477     return S_OK;
478 }
479
480 static HRESULT WINAPI HttpNegotiate_OnResponse(IHttpNegotiate2 *iface, DWORD dwResponseCode,
481         LPCWSTR szResponseHeaders, LPCWSTR szRequestHeaders, LPWSTR *pszAdditionalRequestHeaders)
482 {
483     BSCallback *This = impl_from_IHttpNegotiate2(iface);
484
485     TRACE("(%p)->(%d %s %s %p)\n", This, dwResponseCode, debugstr_w(szResponseHeaders),
486           debugstr_w(szRequestHeaders), pszAdditionalRequestHeaders);
487
488     return This->vtbl->on_response(This, dwResponseCode, szResponseHeaders);
489 }
490
491 static HRESULT WINAPI HttpNegotiate_GetRootSecurityId(IHttpNegotiate2 *iface,
492         BYTE *pbSecurityId, DWORD *pcbSecurityId, DWORD_PTR dwReserved)
493 {
494     BSCallback *This = impl_from_IHttpNegotiate2(iface);
495     FIXME("(%p)->(%p %p %ld)\n", This, pbSecurityId, pcbSecurityId, dwReserved);
496     return E_NOTIMPL;
497 }
498
499 static const IHttpNegotiate2Vtbl HttpNegotiate2Vtbl = {
500     HttpNegotiate_QueryInterface,
501     HttpNegotiate_AddRef,
502     HttpNegotiate_Release,
503     HttpNegotiate_BeginningTransaction,
504     HttpNegotiate_OnResponse,
505     HttpNegotiate_GetRootSecurityId
506 };
507
508 static inline BSCallback *impl_from_IInternetBindInfo(IInternetBindInfo *iface)
509 {
510     return CONTAINING_RECORD(iface, BSCallback, IInternetBindInfo_iface);
511 }
512
513 static HRESULT WINAPI InternetBindInfo_QueryInterface(IInternetBindInfo *iface,
514                                                       REFIID riid, void **ppv)
515 {
516     BSCallback *This = impl_from_IInternetBindInfo(iface);
517     return IBindStatusCallback_QueryInterface(&This->IBindStatusCallback_iface, riid, ppv);
518 }
519
520 static ULONG WINAPI InternetBindInfo_AddRef(IInternetBindInfo *iface)
521 {
522     BSCallback *This = impl_from_IInternetBindInfo(iface);
523     return IBindStatusCallback_AddRef(&This->IBindStatusCallback_iface);
524 }
525
526 static ULONG WINAPI InternetBindInfo_Release(IInternetBindInfo *iface)
527 {
528     BSCallback *This = impl_from_IInternetBindInfo(iface);
529     return IBindStatusCallback_Release(&This->IBindStatusCallback_iface);
530 }
531
532 static HRESULT WINAPI InternetBindInfo_GetBindInfo(IInternetBindInfo *iface,
533                                                    DWORD *grfBINDF, BINDINFO *pbindinfo)
534 {
535     BSCallback *This = impl_from_IInternetBindInfo(iface);
536     FIXME("(%p)->(%p %p)\n", This, grfBINDF, pbindinfo);
537     return E_NOTIMPL;
538 }
539
540 static HRESULT WINAPI InternetBindInfo_GetBindString(IInternetBindInfo *iface,
541         ULONG ulStringType, LPOLESTR *ppwzStr, ULONG cEl, ULONG *pcElFetched)
542 {
543     BSCallback *This = impl_from_IInternetBindInfo(iface);
544     FIXME("(%p)->(%u %p %u %p)\n", This, ulStringType, ppwzStr, cEl, pcElFetched);
545     return E_NOTIMPL;
546 }
547
548 static const IInternetBindInfoVtbl InternetBindInfoVtbl = {
549     InternetBindInfo_QueryInterface,
550     InternetBindInfo_AddRef,
551     InternetBindInfo_Release,
552     InternetBindInfo_GetBindInfo,
553     InternetBindInfo_GetBindString
554 };
555
556 static inline BSCallback *impl_from_IServiceProvider(IServiceProvider *iface)
557 {
558     return CONTAINING_RECORD(iface, BSCallback, IServiceProvider_iface);
559 }
560
561 static HRESULT WINAPI BSCServiceProvider_QueryInterface(IServiceProvider *iface,
562                                                         REFIID riid, void **ppv)
563 {
564     BSCallback *This = impl_from_IServiceProvider(iface);
565     return IBindStatusCallback_QueryInterface(&This->IBindStatusCallback_iface, riid, ppv);
566 }
567
568 static ULONG WINAPI BSCServiceProvider_AddRef(IServiceProvider *iface)
569 {
570     BSCallback *This = impl_from_IServiceProvider(iface);
571     return IBindStatusCallback_AddRef(&This->IBindStatusCallback_iface);
572 }
573
574 static ULONG WINAPI BSCServiceProvider_Release(IServiceProvider *iface)
575 {
576     BSCallback *This = impl_from_IServiceProvider(iface);
577     return IBindStatusCallback_Release(&This->IBindStatusCallback_iface);
578 }
579
580 static HRESULT WINAPI BSCServiceProvider_QueryService(IServiceProvider *iface,
581         REFGUID guidService, REFIID riid, void **ppv)
582 {
583     BSCallback *This = impl_from_IServiceProvider(iface);
584     TRACE("(%p)->(%s %s %p)\n", This, debugstr_guid(guidService), debugstr_guid(riid), ppv);
585     return E_NOINTERFACE;
586 }
587
588 static const IServiceProviderVtbl ServiceProviderVtbl = {
589     BSCServiceProvider_QueryInterface,
590     BSCServiceProvider_AddRef,
591     BSCServiceProvider_Release,
592     BSCServiceProvider_QueryService
593 };
594
595 static void init_bscallback(BSCallback *This, const BSCallbackVtbl *vtbl, IMoniker *mon, DWORD bindf)
596 {
597     This->IBindStatusCallback_iface.lpVtbl = &BindStatusCallbackVtbl;
598     This->IServiceProvider_iface.lpVtbl = &ServiceProviderVtbl;
599     This->IHttpNegotiate2_iface.lpVtbl = &HttpNegotiate2Vtbl;
600     This->IInternetBindInfo_iface.lpVtbl = &InternetBindInfoVtbl;
601     This->vtbl = vtbl;
602     This->ref = 1;
603     This->bindf = bindf;
604
605     list_init(&This->entry);
606
607     if(mon)
608         IMoniker_AddRef(mon);
609     This->mon = mon;
610 }
611
612 /* Calls undocumented 84 cmd of CGID_ShellDocView */
613 static void call_docview_84(HTMLDocumentObj *doc)
614 {
615     IOleCommandTarget *olecmd;
616     VARIANT var;
617     HRESULT hres;
618
619     if(!doc->client)
620         return;
621
622     hres = IOleClientSite_QueryInterface(doc->client, &IID_IOleCommandTarget, (void**)&olecmd);
623     if(FAILED(hres))
624         return;
625
626     VariantInit(&var);
627     hres = IOleCommandTarget_Exec(olecmd, &CGID_ShellDocView, 84, 0, NULL, &var);
628     IOleCommandTarget_Release(olecmd);
629     if(SUCCEEDED(hres) && V_VT(&var) != VT_NULL)
630         FIXME("handle result\n");
631 }
632
633 static void parse_content_type(nsChannelBSC *This, const WCHAR *value)
634 {
635     const WCHAR *ptr;
636     size_t len;
637
638     static const WCHAR charsetW[] = {'c','h','a','r','s','e','t','='};
639
640     ptr = strchrW(value, ';');
641     if(!ptr)
642         return;
643
644     ptr++;
645     while(*ptr && isspaceW(*ptr))
646         ptr++;
647
648     len = strlenW(value);
649     if(ptr + sizeof(charsetW)/sizeof(WCHAR) < value+len && !memicmpW(ptr, charsetW, sizeof(charsetW)/sizeof(WCHAR))) {
650         size_t charset_len, lena;
651         nsACString charset_str;
652         const WCHAR *charset;
653         char *charseta;
654
655         ptr += sizeof(charsetW)/sizeof(WCHAR);
656
657         if(*ptr == '\'') {
658             FIXME("Quoted value\n");
659             return;
660         }else {
661             charset = ptr;
662             while(*ptr && *ptr != ',')
663                 ptr++;
664             charset_len = ptr-charset;
665         }
666
667         lena = WideCharToMultiByte(CP_ACP, 0, charset, charset_len, NULL, 0, NULL, NULL);
668         charseta = heap_alloc(lena+1);
669         if(!charseta)
670             return;
671
672         WideCharToMultiByte(CP_ACP, 0, charset, charset_len, charseta, lena, NULL, NULL);
673         charseta[lena] = 0;
674
675         nsACString_InitDepend(&charset_str, charseta);
676         nsIHttpChannel_SetContentCharset(&This->nschannel->nsIHttpChannel_iface, &charset_str);
677         nsACString_Finish(&charset_str);
678         heap_free(charseta);
679     }else {
680         FIXME("unhandled: %s\n", debugstr_wn(ptr, len - (ptr-value)));
681     }
682 }
683
684 static HRESULT parse_headers(const WCHAR *headers, struct list *headers_list)
685 {
686     const WCHAR *header, *header_end, *colon, *value;
687     HRESULT hres;
688
689     header = headers;
690     while(*header) {
691         if(header[0] == '\r' && header[1] == '\n' && !header[2])
692             break;
693         for(colon = header; *colon && *colon != ':' && *colon != '\r'; colon++);
694         if(*colon != ':')
695             return E_FAIL;
696
697         value = colon+1;
698         while(*value == ' ')
699             value++;
700         if(!*value)
701             return E_FAIL;
702
703         for(header_end = value+1; *header_end && *header_end != '\r'; header_end++);
704
705         hres = set_http_header(headers_list, header, colon-header, value, header_end-value);
706         if(FAILED(hres))
707             return hres;
708
709         header = header_end;
710         if(header[0] == '\r' && header[1] == '\n')
711             header += 2;
712     }
713
714     return S_OK;
715 }
716
717 static HRESULT process_response_headers(nsChannelBSC *This, const WCHAR *headers)
718 {
719     http_header_t *iter;
720     HRESULT hres;
721
722     static const WCHAR content_typeW[] = {'c','o','n','t','e','n','t','-','t','y','p','e',0};
723
724     hres = parse_headers(headers, &This->nschannel->response_headers);
725     if(FAILED(hres))
726         return hres;
727
728     LIST_FOR_EACH_ENTRY(iter, &This->nschannel->response_headers, http_header_t, entry) {
729         if(!strcmpiW(iter->header, content_typeW))
730             parse_content_type(This, iter->data);
731     }
732
733     return S_OK;
734 }
735
736 HRESULT start_binding(HTMLWindow *window, HTMLDocumentNode *doc, BSCallback *bscallback, IBindCtx *bctx)
737 {
738     IStream *str = NULL;
739     HRESULT hres;
740
741     TRACE("(%p %p %p %p)\n", window, doc, bscallback, bctx);
742
743     bscallback->doc = doc;
744
745     /* NOTE: IE7 calls IsSystemMoniker here*/
746
747     if(window) {
748         if(bscallback->mon != window->mon)
749             set_current_mon(window, bscallback->mon);
750         call_docview_84(window->doc_obj);
751     }
752
753     if(bctx) {
754         RegisterBindStatusCallback(bctx, &bscallback->IBindStatusCallback_iface, NULL, 0);
755         IBindCtx_AddRef(bctx);
756     }else {
757         hres = CreateAsyncBindCtx(0, &bscallback->IBindStatusCallback_iface, NULL, &bctx);
758         if(FAILED(hres)) {
759             WARN("CreateAsyncBindCtx failed: %08x\n", hres);
760             bscallback->vtbl->stop_binding(bscallback, hres);
761             return hres;
762         }
763     }
764
765     hres = IMoniker_BindToStorage(bscallback->mon, bctx, NULL, &IID_IStream, (void**)&str);
766     IBindCtx_Release(bctx);
767     if(FAILED(hres)) {
768         WARN("BindToStorage failed: %08x\n", hres);
769         bscallback->vtbl->stop_binding(bscallback, hres);
770         return hres;
771     }
772
773     if(str)
774         IStream_Release(str);
775
776     IMoniker_Release(bscallback->mon);
777     bscallback->mon = NULL;
778
779     return S_OK;
780 }
781
782 typedef struct {
783     BSCallback bsc;
784
785     DWORD size;
786     BYTE *buf;
787     HRESULT hres;
788 } BufferBSC;
789
790 static inline BufferBSC *BufferBSC_from_BSCallback(BSCallback *iface)
791 {
792     return CONTAINING_RECORD(iface, BufferBSC, bsc);
793 }
794
795 static void BufferBSC_destroy(BSCallback *bsc)
796 {
797     BufferBSC *This = BufferBSC_from_BSCallback(bsc);
798
799     heap_free(This->buf);
800     heap_free(This);
801 }
802
803 static HRESULT BufferBSC_init_bindinfo(BSCallback *bsc)
804 {
805     return S_OK;
806 }
807
808 static HRESULT BufferBSC_start_binding(BSCallback *bsc)
809 {
810     return S_OK;
811 }
812
813 static HRESULT BufferBSC_stop_binding(BSCallback *bsc, HRESULT result)
814 {
815     BufferBSC *This = BufferBSC_from_BSCallback(bsc);
816
817     This->hres = result;
818
819     if(FAILED(result)) {
820         heap_free(This->buf);
821         This->buf = NULL;
822         This->size = 0;
823     }
824
825     return S_OK;
826 }
827
828 static HRESULT BufferBSC_read_data(BSCallback *bsc, IStream *stream)
829 {
830     BufferBSC *This = BufferBSC_from_BSCallback(bsc);
831     DWORD readed;
832     HRESULT hres;
833
834     if(!This->buf) {
835         This->size = 128;
836         This->buf = heap_alloc(This->size);
837     }
838
839     do {
840         if(This->bsc.readed == This->size) {
841             This->size <<= 1;
842             This->buf = heap_realloc(This->buf, This->size);
843         }
844
845         readed = 0;
846         hres = IStream_Read(stream, This->buf+This->bsc.readed, This->size-This->bsc.readed, &readed);
847         This->bsc.readed += readed;
848     }while(hres == S_OK);
849
850     return S_OK;
851 }
852
853 static HRESULT BufferBSC_on_progress(BSCallback *bsc, ULONG status_code, LPCWSTR status_text)
854 {
855     return S_OK;
856 }
857
858 static HRESULT BufferBSC_on_response(BSCallback *bsc, DWORD response_code,
859         LPCWSTR response_headers)
860 {
861     return S_OK;
862 }
863
864 static HRESULT BufferBSC_beginning_transaction(BSCallback *bsc, WCHAR **additional_headers)
865 {
866     return S_FALSE;
867 }
868
869 static const BSCallbackVtbl BufferBSCVtbl = {
870     BufferBSC_destroy,
871     BufferBSC_init_bindinfo,
872     BufferBSC_start_binding,
873     BufferBSC_stop_binding,
874     BufferBSC_read_data,
875     BufferBSC_on_progress,
876     BufferBSC_on_response,
877     BufferBSC_beginning_transaction
878 };
879
880
881 static BufferBSC *create_bufferbsc(IMoniker *mon)
882 {
883     BufferBSC *ret = heap_alloc_zero(sizeof(*ret));
884
885     init_bscallback(&ret->bsc, &BufferBSCVtbl, mon, 0);
886     ret->hres = E_FAIL;
887
888     return ret;
889 }
890
891 HRESULT bind_mon_to_buffer(HTMLDocumentNode *doc, IMoniker *mon, void **buf, DWORD *size)
892 {
893     BufferBSC *bsc = create_bufferbsc(mon);
894     HRESULT hres;
895
896     *buf = NULL;
897
898     hres = start_binding(NULL, doc, &bsc->bsc, NULL);
899     if(SUCCEEDED(hres)) {
900         hres = bsc->hres;
901         if(SUCCEEDED(hres)) {
902             *buf = bsc->buf;
903             bsc->buf = NULL;
904             *size = bsc->bsc.readed;
905             bsc->size = 0;
906         }
907     }
908
909     IBindStatusCallback_Release(&bsc->bsc.IBindStatusCallback_iface);
910
911     return hres;
912 }
913
914 static HRESULT read_post_data_stream(nsChannelBSC *This, nsChannel *nschannel)
915 {
916     PRUint32 data_len = 0, available = 0;
917     char *data, *post_data;
918     nsresult nsres;
919     HRESULT hres = S_OK;
920
921     if(!nschannel->post_data_stream)
922         return S_OK;
923
924     nsres =  nsIInputStream_Available(nschannel->post_data_stream, &available);
925     if(NS_FAILED(nsres))
926         return E_FAIL;
927
928     post_data = data = GlobalAlloc(0, available);
929     if(!data)
930         return E_OUTOFMEMORY;
931
932     nsres = nsIInputStream_Read(nschannel->post_data_stream, data, available, &data_len);
933     if(NS_FAILED(nsres)) {
934         GlobalFree(data);
935         return E_FAIL;
936     }
937
938     if(nschannel->post_data_contains_headers) {
939         if(data_len >= 2 && data[0] == '\r' && data[1] == '\n') {
940             post_data = data+2;
941             data_len -= 2;
942         }else {
943             WCHAR *headers;
944             DWORD size;
945             char *ptr;
946
947             post_data += data_len;
948             for(ptr = data; ptr+4 < data+data_len; ptr++) {
949                 if(!memcmp(ptr, "\r\n\r\n", 4)) {
950                     post_data = ptr+4;
951                     break;
952                 }
953             }
954
955             data_len -= post_data-data;
956
957             size = MultiByteToWideChar(CP_ACP, 0, data, post_data-data, NULL, 0);
958             headers = heap_alloc((size+1)*sizeof(WCHAR));
959             if(headers) {
960                 MultiByteToWideChar(CP_ACP, 0, data, post_data-data, headers, size);
961                 headers[size] = 0;
962                 hres = parse_headers(headers , &nschannel->request_headers);
963                 if(SUCCEEDED(hres))
964                     This->bsc.headers = headers;
965                 else
966                     heap_free(headers);
967             }else {
968                 hres = E_OUTOFMEMORY;
969             }
970         }
971     }
972
973     if(FAILED(hres)) {
974         GlobalFree(data);
975         return hres;
976     }
977
978     if(!data_len) {
979         GlobalFree(data);
980         post_data = NULL;
981     }else if(post_data != data) {
982         char *new_data;
983
984         new_data = GlobalAlloc(0, data_len);
985         if(new_data)
986             memcpy(new_data, post_data, data_len);
987         GlobalFree(data);
988         if(!new_data)
989             return E_OUTOFMEMORY;
990         post_data = new_data;
991     }
992
993     This->bsc.post_data = post_data;
994     This->bsc.post_data_len = data_len;
995     TRACE("post_data = %s\n", debugstr_a(This->bsc.post_data));
996     return S_OK;
997 }
998
999 static HRESULT on_start_nsrequest(nsChannelBSC *This)
1000 {
1001     nsresult nsres;
1002
1003     /* FIXME: it's needed for http connections from BindToObject. */
1004     if(!This->nschannel->response_status)
1005         This->nschannel->response_status = 200;
1006
1007     nsres = nsIStreamListener_OnStartRequest(This->nslistener,
1008             (nsIRequest*)&This->nschannel->nsIHttpChannel_iface, This->nscontext);
1009     if(NS_FAILED(nsres)) {
1010         FIXME("OnStartRequest failed: %08x\n", nsres);
1011         return E_FAIL;
1012     }
1013
1014     if(This->window) {
1015         list_remove(&This->bsc.entry);
1016         list_init(&This->bsc.entry);
1017         update_window_doc(This->window);
1018         if(This->window->doc != This->bsc.doc)
1019             This->bsc.doc = This->window->doc;
1020         list_add_head(&This->bsc.doc->bindings, &This->bsc.entry);
1021         if(This->window->readystate != READYSTATE_LOADING)
1022             set_ready_state(This->window, READYSTATE_LOADING);
1023     }
1024
1025     return S_OK;
1026 }
1027
1028 static void on_stop_nsrequest(nsChannelBSC *This, HRESULT result)
1029 {
1030     nsresult nsres, request_result;
1031
1032     switch(result) {
1033     case S_OK:
1034         request_result = NS_OK;
1035         break;
1036     case E_ABORT:
1037         request_result = NS_BINDING_ABORTED;
1038         break;
1039     default:
1040         request_result = NS_ERROR_FAILURE;
1041     }
1042
1043     if(This->nslistener) {
1044         nsres = nsIStreamListener_OnStopRequest(This->nslistener,
1045                  (nsIRequest*)&This->nschannel->nsIHttpChannel_iface, This->nscontext,
1046                  request_result);
1047         if(NS_FAILED(nsres))
1048             WARN("OnStopRequest failed: %08x\n", nsres);
1049     }
1050
1051     if(This->nschannel->load_group) {
1052         nsres = nsILoadGroup_RemoveRequest(This->nschannel->load_group,
1053                 (nsIRequest*)&This->nschannel->nsIHttpChannel_iface, NULL, request_result);
1054         if(NS_FAILED(nsres))
1055             ERR("RemoveRequest failed: %08x\n", nsres);
1056     }
1057 }
1058
1059 static HRESULT read_stream_data(nsChannelBSC *This, IStream *stream)
1060 {
1061     DWORD read;
1062     nsresult nsres;
1063     HRESULT hres;
1064
1065     if(!This->nslistener) {
1066         BYTE buf[1024];
1067
1068         do {
1069             read = 0;
1070             hres = IStream_Read(stream, buf, sizeof(buf), &read);
1071         }while(hres == S_OK && read);
1072
1073         return S_OK;
1074     }
1075
1076     if(!This->nsstream)
1077         This->nsstream = create_nsprotocol_stream();
1078
1079     do {
1080         read = 0;
1081         hres = IStream_Read(stream, This->nsstream->buf+This->nsstream->buf_size,
1082                 sizeof(This->nsstream->buf)-This->nsstream->buf_size, &read);
1083         if(!read)
1084             break;
1085
1086         This->nsstream->buf_size += read;
1087
1088         if(!This->bsc.readed) {
1089             if(This->nsstream->buf_size >= 2
1090                && (BYTE)This->nsstream->buf[0] == 0xff
1091                && (BYTE)This->nsstream->buf[1] == 0xfe)
1092                 This->nschannel->charset = heap_strdupA(UTF16_STR);
1093
1094             if(!This->nschannel->content_type) {
1095                 WCHAR *mime;
1096
1097                 hres = FindMimeFromData(NULL, NULL, This->nsstream->buf, This->nsstream->buf_size, NULL, 0, &mime, 0);
1098                 if(FAILED(hres))
1099                     return hres;
1100
1101                 TRACE("Found MIME %s\n", debugstr_w(mime));
1102
1103                 This->nschannel->content_type = heap_strdupWtoA(mime);
1104                 CoTaskMemFree(mime);
1105                 if(!This->nschannel->content_type)
1106                     return E_OUTOFMEMORY;
1107             }
1108
1109             on_start_nsrequest(This);
1110         }
1111
1112         This->bsc.readed += This->nsstream->buf_size;
1113
1114         nsres = nsIStreamListener_OnDataAvailable(This->nslistener,
1115                 (nsIRequest*)&This->nschannel->nsIHttpChannel_iface, This->nscontext,
1116                 &This->nsstream->nsIInputStream_iface, This->bsc.readed-This->nsstream->buf_size,
1117                 This->nsstream->buf_size);
1118         if(NS_FAILED(nsres))
1119             ERR("OnDataAvailable failed: %08x\n", nsres);
1120
1121         if(This->nsstream->buf_size == sizeof(This->nsstream->buf)) {
1122             ERR("buffer is full\n");
1123             break;
1124         }
1125     }while(hres == S_OK);
1126
1127     return S_OK;
1128 }
1129
1130 typedef struct {
1131     nsIAsyncVerifyRedirectCallback nsIAsyncVerifyRedirectCallback_iface;
1132
1133     LONG ref;
1134
1135     nsChannel *nschannel;
1136     nsChannelBSC *bsc;
1137 } nsRedirectCallback;
1138
1139 static nsRedirectCallback *impl_from_nsIAsyncVerifyRedirectCallback(nsIAsyncVerifyRedirectCallback *iface)
1140 {
1141     return CONTAINING_RECORD(iface, nsRedirectCallback, nsIAsyncVerifyRedirectCallback_iface);
1142 }
1143
1144 static nsresult NSAPI nsAsyncVerifyRedirectCallback_QueryInterface(nsIAsyncVerifyRedirectCallback *iface,
1145         nsIIDRef riid, void **result)
1146 {
1147     nsRedirectCallback *This = impl_from_nsIAsyncVerifyRedirectCallback(iface);
1148
1149     if(IsEqualGUID(&IID_nsISupports, riid)) {
1150         TRACE("(%p)->(IID_nsISuports %p)\n", This, result);
1151         *result = &This->nsIAsyncVerifyRedirectCallback_iface;
1152     }else if(IsEqualGUID(&IID_nsIAsyncVerifyRedirectCallback, riid)) {
1153         TRACE("(%p)->(IID_nsIAsyncVerifyRedirectCallback %p)\n", This, result);
1154         *result = &This->nsIAsyncVerifyRedirectCallback_iface;
1155     }else {
1156         *result = NULL;
1157         WARN("unimplemented iface %s\n", debugstr_guid(riid));
1158         return NS_NOINTERFACE;
1159     }
1160
1161     nsISupports_AddRef((nsISupports*)*result);
1162     return NS_OK;
1163 }
1164
1165 static nsrefcnt NSAPI nsAsyncVerifyRedirectCallback_AddRef(nsIAsyncVerifyRedirectCallback *iface)
1166 {
1167     nsRedirectCallback *This = impl_from_nsIAsyncVerifyRedirectCallback(iface);
1168     LONG ref = InterlockedIncrement(&This->ref);
1169
1170     TRACE("(%p) ref=%d\n", This, ref);
1171
1172     return ref;
1173 }
1174
1175 static nsrefcnt NSAPI nsAsyncVerifyRedirectCallback_Release(nsIAsyncVerifyRedirectCallback *iface)
1176 {
1177     nsRedirectCallback *This = impl_from_nsIAsyncVerifyRedirectCallback(iface);
1178     LONG ref = InterlockedDecrement(&This->ref);
1179
1180     TRACE("(%p) ref=%d\n", This, ref);
1181
1182     if(!ref) {
1183         IBindStatusCallback_Release(&This->bsc->bsc.IBindStatusCallback_iface);
1184         nsIChannel_Release(&This->nschannel->nsIHttpChannel_iface);
1185         heap_free(This);
1186     }
1187
1188     return ref;
1189 }
1190
1191 static nsresult NSAPI nsAsyncVerifyRedirectCallback_AsyncOnChannelRedirect(nsIAsyncVerifyRedirectCallback *iface, nsresult result)
1192 {
1193     nsRedirectCallback *This = impl_from_nsIAsyncVerifyRedirectCallback(iface);
1194
1195     TRACE("(%p)->(%08x)\n", This, result);
1196
1197     if(This->bsc->nschannel)
1198         nsIHttpChannel_Release(&This->bsc->nschannel->nsIHttpChannel_iface);
1199     nsIChannel_AddRef(&This->nschannel->nsIHttpChannel_iface);
1200     This->bsc->nschannel = This->nschannel;
1201
1202     if(This->nschannel->load_group) {
1203         nsresult nsres;
1204
1205         nsres = nsILoadGroup_AddRequest(This->nschannel->load_group, (nsIRequest*)&This->nschannel->nsIHttpChannel_iface,
1206                 NULL);
1207         if(NS_FAILED(nsres))
1208             ERR("AddRequest failed: %08x\n", nsres);
1209     }
1210
1211     if(This->bsc->window) {
1212         IUri *uri = nsuri_get_uri(This->nschannel->uri);
1213
1214         if(uri) {
1215             set_current_uri(This->bsc->window, uri);
1216             IUri_Release(uri);
1217         }else {
1218             WARN("Could not get IUri from nsWineURI\n");
1219         }
1220     }
1221
1222     return NS_OK;
1223 }
1224
1225 static const nsIAsyncVerifyRedirectCallbackVtbl nsAsyncVerifyRedirectCallbackVtbl = {
1226     nsAsyncVerifyRedirectCallback_QueryInterface,
1227     nsAsyncVerifyRedirectCallback_AddRef,
1228     nsAsyncVerifyRedirectCallback_Release,
1229     nsAsyncVerifyRedirectCallback_AsyncOnChannelRedirect
1230 };
1231
1232 static HRESULT create_redirect_callback(nsChannel *nschannel, nsChannelBSC *bsc, nsRedirectCallback **ret)
1233 {
1234     nsRedirectCallback *callback;
1235
1236     callback = heap_alloc(sizeof(*callback));
1237     if(!callback)
1238         return E_OUTOFMEMORY;
1239
1240     callback->nsIAsyncVerifyRedirectCallback_iface.lpVtbl = &nsAsyncVerifyRedirectCallbackVtbl;
1241     callback->ref = 1;
1242
1243     nsIChannel_AddRef(&nschannel->nsIHttpChannel_iface);
1244     callback->nschannel = nschannel;
1245
1246     IBindStatusCallback_AddRef(&bsc->bsc.IBindStatusCallback_iface);
1247     callback->bsc = bsc;
1248
1249     *ret = callback;
1250     return S_OK;
1251 }
1252
1253 static inline nsChannelBSC *nsChannelBSC_from_BSCallback(BSCallback *iface)
1254 {
1255     return CONTAINING_RECORD(iface, nsChannelBSC, bsc);
1256 }
1257
1258 static void nsChannelBSC_destroy(BSCallback *bsc)
1259 {
1260     nsChannelBSC *This = nsChannelBSC_from_BSCallback(bsc);
1261
1262     if(This->nschannel)
1263         nsIChannel_Release(&This->nschannel->nsIHttpChannel_iface);
1264     if(This->nslistener)
1265         nsIStreamListener_Release(This->nslistener);
1266     if(This->nscontext)
1267         nsISupports_Release(This->nscontext);
1268     if(This->nsstream)
1269         nsIInputStream_Release(&This->nsstream->nsIInputStream_iface);
1270     heap_free(This);
1271 }
1272
1273 static HRESULT nsChannelBSC_start_binding(BSCallback *bsc)
1274 {
1275     nsChannelBSC *This = nsChannelBSC_from_BSCallback(bsc);
1276
1277     if(This->window)
1278         This->window->doc->skip_mutation_notif = FALSE;
1279
1280     return S_OK;
1281 }
1282
1283 static HRESULT nsChannelBSC_init_bindinfo(BSCallback *bsc)
1284 {
1285     nsChannelBSC *This = nsChannelBSC_from_BSCallback(bsc);
1286     HRESULT hres;
1287
1288     if(This->nschannel && This->nschannel->post_data_stream) {
1289         hres = read_post_data_stream(This, This->nschannel);
1290         if(FAILED(hres))
1291             return hres;
1292     }
1293
1294     return S_OK;
1295 }
1296
1297 typedef struct {
1298     task_t header;
1299     nsChannelBSC *bsc;
1300 } stop_request_task_t;
1301
1302 static void stop_request_proc(task_t *_task)
1303 {
1304     stop_request_task_t *task = (stop_request_task_t*)_task;
1305
1306     TRACE("(%p)\n", task->bsc);
1307
1308     list_remove(&task->bsc->bsc.entry);
1309     list_init(&task->bsc->bsc.entry);
1310     on_stop_nsrequest(task->bsc, S_OK);
1311 }
1312
1313 static void stop_request_task_destr(task_t *_task)
1314 {
1315     stop_request_task_t *task = (stop_request_task_t*)_task;
1316
1317     IBindStatusCallback_Release(&task->bsc->bsc.IBindStatusCallback_iface);
1318     heap_free(task);
1319 }
1320
1321 static HRESULT async_stop_request(nsChannelBSC *This)
1322 {
1323     stop_request_task_t *task;
1324
1325     if(!This->bsc.readed) {
1326         TRACE("No data read, calling OnStartRequest\n");
1327         on_start_nsrequest(This);
1328     }
1329
1330     task = heap_alloc(sizeof(*task));
1331     if(!task)
1332         return E_OUTOFMEMORY;
1333
1334     IBindStatusCallback_AddRef(&This->bsc.IBindStatusCallback_iface);
1335     task->bsc = This;
1336     push_task(&task->header, stop_request_proc, stop_request_task_destr, This->bsc.doc->basedoc.doc_obj->basedoc.task_magic);
1337     return S_OK;
1338 }
1339
1340 static void handle_navigation_error(nsChannelBSC *This, DWORD result)
1341 {
1342     HTMLDocumentObj *doc;
1343     IOleCommandTarget *olecmd;
1344     BOOL is_error_url;
1345     SAFEARRAY *sa;
1346     SAFEARRAYBOUND bound;
1347     VARIANT var, varOut;
1348     LONG ind;
1349     BSTR unk;
1350     HRESULT hres;
1351
1352     if(!This->window)
1353         return;
1354
1355     doc = This->window->doc_obj;
1356     if(!doc || !doc->doc_object_service || !doc->client)
1357         return;
1358
1359     hres = IDocObjectService_IsErrorUrl(doc->doc_object_service,
1360             This->window->url, &is_error_url);
1361     if(FAILED(hres) || is_error_url)
1362         return;
1363
1364     hres = IOleClientSite_QueryInterface(doc->client,
1365             &IID_IOleCommandTarget, (void**)&olecmd);
1366     if(FAILED(hres))
1367         return;
1368
1369     bound.lLbound = 0;
1370     bound.cElements = 8;
1371     sa = SafeArrayCreate(VT_VARIANT, 1, &bound);
1372     if(!sa) {
1373         IOleCommandTarget_Release(olecmd);
1374         return;
1375     }
1376
1377     ind = 0;
1378     V_VT(&var) = VT_I4;
1379     V_I4(&var) = result;
1380     SafeArrayPutElement(sa, &ind, &var);
1381
1382     ind = 1;
1383     V_VT(&var) = VT_BSTR;
1384     V_BSTR(&var) = This->window->url;
1385     SafeArrayPutElement(sa, &ind, &var);
1386
1387     ind = 3;
1388     V_VT(&var) = VT_UNKNOWN;
1389     V_UNKNOWN(&var) = (IUnknown*)&This->window->IHTMLWindow2_iface;
1390     SafeArrayPutElement(sa, &ind, &var);
1391
1392     /* FIXME: what are the following fields for? */
1393     ind = 2;
1394     V_VT(&var) = VT_UNKNOWN;
1395     V_UNKNOWN(&var) = NULL;
1396     SafeArrayPutElement(sa, &ind, &var);
1397
1398     ind = 4;
1399     V_VT(&var) = VT_BOOL;
1400     V_BOOL(&var) = FALSE;
1401     SafeArrayPutElement(sa, &ind, &var);
1402
1403     ind = 5;
1404     V_VT(&var) = VT_BOOL;
1405     V_BOOL(&var) = FALSE;
1406     SafeArrayPutElement(sa, &ind, &var);
1407
1408     ind = 6;
1409     V_VT(&var) = VT_BSTR;
1410     unk = SysAllocString(NULL);
1411     V_BSTR(&var) = unk;
1412     SafeArrayPutElement(sa, &ind, &var);
1413
1414     ind = 7;
1415     V_VT(&var) = VT_UNKNOWN;
1416     V_UNKNOWN(&var) = NULL;
1417     SafeArrayPutElement(sa, &ind, &var);
1418
1419     V_VT(&var) = VT_ARRAY;
1420     V_ARRAY(&var) = sa;
1421     V_VT(&varOut) = VT_BOOL;
1422     V_BOOL(&varOut) = VARIANT_TRUE;
1423     IOleCommandTarget_Exec(olecmd, &CGID_DocHostCmdPriv, 1, 0, &var, FAILED(hres)?NULL:&varOut);
1424
1425     SysFreeString(unk);
1426     SafeArrayDestroy(sa);
1427     IOleCommandTarget_Release(olecmd);
1428 }
1429
1430 static HRESULT nsChannelBSC_stop_binding(BSCallback *bsc, HRESULT result)
1431 {
1432     nsChannelBSC *This = nsChannelBSC_from_BSCallback(bsc);
1433
1434     if(result != E_ABORT) {
1435         if(FAILED(result))
1436             handle_navigation_error(This, result);
1437         else if(This->window) {
1438             result = async_stop_request(This);
1439             if(SUCCEEDED(result))
1440                 return S_OK;
1441         }
1442     }
1443
1444     on_stop_nsrequest(This, result);
1445     return S_OK;
1446 }
1447
1448 static HRESULT nsChannelBSC_read_data(BSCallback *bsc, IStream *stream)
1449 {
1450     nsChannelBSC *This = nsChannelBSC_from_BSCallback(bsc);
1451
1452     return read_stream_data(This, stream);
1453 }
1454
1455 static HRESULT handle_redirect(nsChannelBSC *This, const WCHAR *new_url)
1456 {
1457     nsRedirectCallback *callback;
1458     nsIChannelEventSink *sink;
1459     nsChannel *new_channel;
1460     nsresult nsres;
1461     HRESULT hres;
1462
1463     TRACE("(%p)->(%s)\n", This, debugstr_w(new_url));
1464
1465     if(!This->nschannel || !This->nschannel->notif_callback)
1466         return S_OK;
1467
1468     nsres = nsIInterfaceRequestor_GetInterface(This->nschannel->notif_callback, &IID_nsIChannelEventSink, (void**)&sink);
1469     if(NS_FAILED(nsres))
1470         return S_OK;
1471
1472     hres = create_redirect_nschannel(new_url, This->nschannel, &new_channel);
1473     if(SUCCEEDED(hres)) {
1474         hres = create_redirect_callback(new_channel, This, &callback);
1475         nsIChannel_Release(&new_channel->nsIHttpChannel_iface);
1476     }
1477
1478     if(SUCCEEDED(hres)) {
1479         nsres = nsIChannelEventSink_AsyncOnChannelRedirect(sink, (nsIChannel*)&This->nschannel->nsIHttpChannel_iface,
1480                 (nsIChannel*)&callback->nschannel->nsIHttpChannel_iface, REDIRECT_TEMPORARY, /* FIXME */
1481                 &callback->nsIAsyncVerifyRedirectCallback_iface);
1482
1483         if(NS_FAILED(nsres))
1484             FIXME("AsyncOnChannelRedirect failed: %08x\n", hres);
1485         else if(This->nschannel != callback->nschannel)
1486             FIXME("nschannel not updated\n");
1487
1488         nsIAsyncVerifyRedirectCallback_Release(&callback->nsIAsyncVerifyRedirectCallback_iface);
1489     }
1490
1491     nsIChannelEventSink_Release(sink);
1492     return hres;
1493 }
1494
1495 static HRESULT nsChannelBSC_on_progress(BSCallback *bsc, ULONG status_code, LPCWSTR status_text)
1496 {
1497     nsChannelBSC *This = nsChannelBSC_from_BSCallback(bsc);
1498
1499     switch(status_code) {
1500     case BINDSTATUS_MIMETYPEAVAILABLE:
1501         if(!This->nschannel)
1502             return S_OK;
1503
1504         heap_free(This->nschannel->content_type);
1505         This->nschannel->content_type = heap_strdupWtoA(status_text);
1506         break;
1507     case BINDSTATUS_REDIRECTING:
1508         return handle_redirect(This, status_text);
1509     case BINDSTATUS_BEGINDOWNLOADDATA: {
1510         IWinInetHttpInfo *http_info;
1511         DWORD status, size = sizeof(DWORD);
1512         HRESULT hres;
1513
1514         if(!This->bsc.binding)
1515             break;
1516
1517         hres = IBinding_QueryInterface(This->bsc.binding, &IID_IWinInetHttpInfo, (void**)&http_info);
1518         if(FAILED(hres))
1519             break;
1520
1521         hres = IWinInetHttpInfo_QueryInfo(http_info,
1522                 HTTP_QUERY_STATUS_CODE|HTTP_QUERY_FLAG_NUMBER, &status, &size, NULL, NULL);
1523         IWinInetHttpInfo_Release(http_info);
1524         if(FAILED(hres) || status == HTTP_STATUS_OK)
1525             break;
1526
1527         handle_navigation_error(This, status);
1528     }
1529     }
1530
1531     return S_OK;
1532 }
1533
1534 static HRESULT nsChannelBSC_on_response(BSCallback *bsc, DWORD response_code,
1535         LPCWSTR response_headers)
1536 {
1537     nsChannelBSC *This = nsChannelBSC_from_BSCallback(bsc);
1538     HRESULT hres;
1539
1540     This->nschannel->response_status = response_code;
1541
1542     if(response_headers) {
1543         const WCHAR *headers;
1544
1545         headers = strchrW(response_headers, '\r');
1546         if(headers && headers[1] == '\n') {
1547             headers += 2;
1548             hres = process_response_headers(This, headers);
1549             if(FAILED(hres)) {
1550                 WARN("parsing headers failed: %08x\n", hres);
1551                 return hres;
1552             }
1553         }
1554     }
1555
1556     return S_OK;
1557 }
1558
1559 static HRESULT nsChannelBSC_beginning_transaction(BSCallback *bsc, WCHAR **additional_headers)
1560 {
1561     nsChannelBSC *This = nsChannelBSC_from_BSCallback(bsc);
1562     http_header_t *iter;
1563     DWORD len = 0;
1564     WCHAR *ptr;
1565
1566     static const WCHAR content_lengthW[] =
1567         {'C','o','n','t','e','n','t','-','L','e','n','g','t','h',0};
1568
1569     if(!This->nschannel)
1570         return S_FALSE;
1571
1572     LIST_FOR_EACH_ENTRY(iter, &This->nschannel->request_headers, http_header_t, entry) {
1573         if(strcmpW(iter->header, content_lengthW))
1574             len += strlenW(iter->header) + 2 /* ": " */ + strlenW(iter->data) + 2 /* "\r\n" */;
1575     }
1576
1577     if(!len)
1578         return S_OK;
1579
1580     *additional_headers = ptr = CoTaskMemAlloc((len+1)*sizeof(WCHAR));
1581     if(!ptr)
1582         return E_OUTOFMEMORY;
1583
1584     LIST_FOR_EACH_ENTRY(iter, &This->nschannel->request_headers, http_header_t, entry) {
1585         if(!strcmpW(iter->header, content_lengthW))
1586             continue;
1587
1588         len = strlenW(iter->header);
1589         memcpy(ptr, iter->header, len*sizeof(WCHAR));
1590         ptr += len;
1591
1592         *ptr++ = ':';
1593         *ptr++ = ' ';
1594
1595         len = strlenW(iter->data);
1596         memcpy(ptr, iter->data, len*sizeof(WCHAR));
1597         ptr += len;
1598
1599         *ptr++ = '\r';
1600         *ptr++ = '\n';
1601     }
1602
1603     *ptr = 0;
1604
1605     return S_OK;
1606 }
1607
1608 static const BSCallbackVtbl nsChannelBSCVtbl = {
1609     nsChannelBSC_destroy,
1610     nsChannelBSC_init_bindinfo,
1611     nsChannelBSC_start_binding,
1612     nsChannelBSC_stop_binding,
1613     nsChannelBSC_read_data,
1614     nsChannelBSC_on_progress,
1615     nsChannelBSC_on_response,
1616     nsChannelBSC_beginning_transaction
1617 };
1618
1619 HRESULT create_channelbsc(IMoniker *mon, const WCHAR *headers, BYTE *post_data, DWORD post_data_size, nsChannelBSC **retval)
1620 {
1621     nsChannelBSC *ret;
1622
1623     ret = heap_alloc_zero(sizeof(*ret));
1624     if(!ret)
1625         return E_OUTOFMEMORY;
1626
1627     init_bscallback(&ret->bsc, &nsChannelBSCVtbl, mon, BINDF_ASYNCHRONOUS | BINDF_ASYNCSTORAGE | BINDF_PULLDATA);
1628
1629     if(headers) {
1630         ret->bsc.headers = heap_strdupW(headers);
1631         if(!ret->bsc.headers) {
1632             IBindStatusCallback_Release(&ret->bsc.IBindStatusCallback_iface);
1633             return E_OUTOFMEMORY;
1634         }
1635     }
1636
1637     if(post_data) {
1638         ret->bsc.post_data = GlobalAlloc(0, post_data_size);
1639         if(!ret->bsc.post_data) {
1640             heap_free(ret->bsc.headers);
1641             IBindStatusCallback_Release(&ret->bsc.IBindStatusCallback_iface);
1642             return E_OUTOFMEMORY;
1643         }
1644
1645         memcpy(ret->bsc.post_data, post_data, post_data_size);
1646         ret->bsc.post_data_len = post_data_size;
1647     }
1648
1649     *retval = ret;
1650     return S_OK;
1651 }
1652
1653 void set_window_bscallback(HTMLWindow *window, nsChannelBSC *callback)
1654 {
1655     if(window->bscallback) {
1656         if(window->bscallback->bsc.binding)
1657             IBinding_Abort(window->bscallback->bsc.binding);
1658         window->bscallback->bsc.doc = NULL;
1659         window->bscallback->window = NULL;
1660         IBindStatusCallback_Release(&window->bscallback->bsc.IBindStatusCallback_iface);
1661     }
1662
1663     window->bscallback = callback;
1664
1665     if(callback) {
1666         callback->window = window;
1667         IBindStatusCallback_AddRef(&callback->bsc.IBindStatusCallback_iface);
1668         callback->bsc.doc = window->doc;
1669     }
1670 }
1671
1672 typedef struct {
1673     task_t header;
1674     HTMLWindow *window;
1675     nsChannelBSC *bscallback;
1676 } start_doc_binding_task_t;
1677
1678 static void start_doc_binding_proc(task_t *_task)
1679 {
1680     start_doc_binding_task_t *task = (start_doc_binding_task_t*)_task;
1681
1682     start_binding(task->window, NULL, (BSCallback*)task->bscallback, NULL);
1683 }
1684
1685 static void start_doc_binding_task_destr(task_t *_task)
1686 {
1687     start_doc_binding_task_t *task = (start_doc_binding_task_t*)_task;
1688
1689     IBindStatusCallback_Release(&task->bscallback->bsc.IBindStatusCallback_iface);
1690     heap_free(task);
1691 }
1692
1693 HRESULT async_start_doc_binding(HTMLWindow *window, nsChannelBSC *bscallback)
1694 {
1695     start_doc_binding_task_t *task;
1696
1697     TRACE("%p\n", bscallback);
1698
1699     task = heap_alloc(sizeof(start_doc_binding_task_t));
1700     if(!task)
1701         return E_OUTOFMEMORY;
1702
1703     task->window = window;
1704     task->bscallback = bscallback;
1705     IBindStatusCallback_AddRef(&bscallback->bsc.IBindStatusCallback_iface);
1706
1707     push_task(&task->header, start_doc_binding_proc, start_doc_binding_task_destr, window->task_magic);
1708     return S_OK;
1709 }
1710
1711 void abort_document_bindings(HTMLDocumentNode *doc)
1712 {
1713     BSCallback *iter, *next;
1714
1715     LIST_FOR_EACH_ENTRY_SAFE(iter, next, &doc->bindings, BSCallback, entry) {
1716         TRACE("Aborting %p\n", iter);
1717
1718         if(iter->doc)
1719             remove_target_tasks(iter->doc->basedoc.task_magic);
1720
1721         if(iter->binding)
1722             IBinding_Abort(iter->binding);
1723         else {
1724             list_remove(&iter->entry);
1725             list_init(&iter->entry);
1726             iter->vtbl->stop_binding(iter, E_ABORT);
1727         }
1728
1729         iter->doc = NULL;
1730     }
1731 }
1732
1733 HRESULT channelbsc_load_stream(nsChannelBSC *bscallback, IStream *stream)
1734 {
1735     HRESULT hres = S_OK;
1736
1737     if(!bscallback->nschannel) {
1738         ERR("NULL nschannel\n");
1739         return E_FAIL;
1740     }
1741
1742     bscallback->nschannel->content_type = heap_strdupA("text/html");
1743     if(!bscallback->nschannel->content_type)
1744         return E_OUTOFMEMORY;
1745
1746     list_add_head(&bscallback->bsc.doc->bindings, &bscallback->bsc.entry);
1747     if(stream)
1748         hres = read_stream_data(bscallback, stream);
1749     if(SUCCEEDED(hres))
1750         hres = async_stop_request(bscallback);
1751     if(FAILED(hres))
1752         IBindStatusCallback_OnStopBinding(&bscallback->bsc.IBindStatusCallback_iface, hres,
1753                 ERROR_SUCCESS);
1754
1755     return hres;
1756 }
1757
1758 void channelbsc_set_channel(nsChannelBSC *This, nsChannel *channel, nsIStreamListener *listener, nsISupports *context)
1759 {
1760     nsIChannel_AddRef(&channel->nsIHttpChannel_iface);
1761     This->nschannel = channel;
1762
1763     nsIStreamListener_AddRef(listener);
1764     This->nslistener = listener;
1765
1766     if(context) {
1767         nsISupports_AddRef(context);
1768         This->nscontext = context;
1769     }
1770
1771     if(This->bsc.headers) {
1772         HRESULT hres;
1773
1774         hres = parse_headers(This->bsc.headers, &channel->request_headers);
1775         heap_free(This->bsc.headers);
1776         This->bsc.headers = NULL;
1777         if(FAILED(hres))
1778             WARN("parse_headers failed: %08x\n", hres);
1779     }
1780 }
1781
1782 typedef struct {
1783     task_t header;
1784     HTMLWindow *window;
1785     IUri *uri;
1786 } navigate_javascript_task_t;
1787
1788 static void navigate_javascript_proc(task_t *_task)
1789 {
1790     navigate_javascript_task_t *task = (navigate_javascript_task_t*)_task;
1791     HTMLWindow *window = task->window;
1792     VARIANT v;
1793     BSTR code;
1794     HRESULT hres;
1795
1796     static const WCHAR jscriptW[] = {'j','s','c','r','i','p','t',0};
1797
1798     task->window->readystate = READYSTATE_COMPLETE;
1799
1800     hres = IUri_GetPath(task->uri, &code);
1801     if(FAILED(hres))
1802         return;
1803
1804     set_download_state(window->doc_obj, 1);
1805
1806     V_VT(&v) = VT_EMPTY;
1807     hres = exec_script(window, code, jscriptW, &v);
1808     SysFreeString(code);
1809     if(SUCCEEDED(hres) && V_VT(&v) != VT_EMPTY) {
1810         FIXME("javascirpt URL returned %s\n", debugstr_variant(&v));
1811         VariantClear(&v);
1812     }
1813
1814     if(window->doc_obj->view_sink)
1815         IAdviseSink_OnViewChange(window->doc_obj->view_sink, DVASPECT_CONTENT, -1);
1816
1817     set_download_state(window->doc_obj, 0);
1818 }
1819
1820 static void navigate_javascript_task_destr(task_t *_task)
1821 {
1822     navigate_javascript_task_t *task = (navigate_javascript_task_t*)_task;
1823
1824     IUri_Release(task->uri);
1825     heap_free(task);
1826 }
1827
1828 typedef struct {
1829     task_t header;
1830     HTMLWindow *window;
1831     nsChannelBSC *bscallback;
1832     IMoniker *mon;
1833 } navigate_task_t;
1834
1835 static void navigate_proc(task_t *_task)
1836 {
1837     navigate_task_t *task = (navigate_task_t*)_task;
1838     HRESULT hres;
1839
1840     hres = set_moniker(&task->window->doc_obj->basedoc, task->mon, NULL, task->bscallback, TRUE);
1841     if(SUCCEEDED(hres))
1842         start_binding(task->window, NULL, (BSCallback*)task->bscallback, NULL);
1843 }
1844
1845 static void navigate_task_destr(task_t *_task)
1846 {
1847     navigate_task_t *task = (navigate_task_t*)_task;
1848
1849     IUnknown_Release((IUnknown*)task->bscallback);
1850     IMoniker_Release(task->mon);
1851     heap_free(task);
1852 }
1853
1854 static HRESULT navigate_fragment(HTMLWindow *window, IUri *uri)
1855 {
1856     nsIDOMLocation *nslocation;
1857     nsAString nsfrag_str;
1858     BSTR frag;
1859     nsresult nsres;
1860     HRESULT hres;
1861
1862     set_current_uri(window, uri);
1863
1864     nsres = nsIDOMWindow_GetLocation(window->nswindow, &nslocation);
1865     if(FAILED(nsres) || !nslocation)
1866         return E_FAIL;
1867
1868     hres = IUri_GetFragment(uri, &frag);
1869     if(FAILED(hres)) {
1870         nsIDOMLocation_Release(nslocation);
1871         return hres;
1872     }
1873
1874     nsAString_InitDepend(&nsfrag_str, frag);
1875     nsres = nsIDOMLocation_SetHash(nslocation, &nsfrag_str);
1876     nsAString_Finish(&nsfrag_str);
1877     nsIDOMLocation_Release(nslocation);
1878     SysFreeString(frag);
1879     if(NS_FAILED(nsres)) {
1880         ERR("SetHash failed: %08x\n", nsres);
1881         return E_FAIL;
1882     }
1883
1884     if(window->doc_obj->doc_object_service) {
1885         IDocObjectService_FireNavigateComplete2(window->doc_obj->doc_object_service, &window->IHTMLWindow2_iface, 0x10);
1886         IDocObjectService_FireDocumentComplete(window->doc_obj->doc_object_service, &window->IHTMLWindow2_iface, 0);
1887
1888     }
1889
1890     return S_OK;
1891 }
1892
1893 HRESULT super_navigate(HTMLWindow *window, IUri *uri, const WCHAR *headers, BYTE *post_data, DWORD post_data_size)
1894 {
1895     nsChannelBSC *bsc;
1896     IMoniker *mon;
1897     DWORD scheme;
1898     HRESULT hres;
1899
1900     if(window->doc_obj->client) {
1901         IOleCommandTarget *cmdtrg;
1902
1903         hres = IOleClientSite_QueryInterface(window->doc_obj->client, &IID_IOleCommandTarget, (void**)&cmdtrg);
1904         if(SUCCEEDED(hres)) {
1905             VARIANT in, out;
1906             BSTR url_str;
1907
1908             hres = IUri_GetDisplayUri(uri, &url_str);
1909             if(SUCCEEDED(hres)) {
1910                 V_VT(&in) = VT_BSTR;
1911                 V_BSTR(&in) = url_str;
1912                 V_VT(&out) = VT_BOOL;
1913                 V_BOOL(&out) = VARIANT_TRUE;
1914                 hres = IOleCommandTarget_Exec(cmdtrg, &CGID_ShellDocView, 67, 0, &in, &out);
1915                 IOleCommandTarget_Release(cmdtrg);
1916                 if(SUCCEEDED(hres))
1917                     VariantClear(&out);
1918                 SysFreeString(url_str);
1919             }
1920         }
1921     }
1922
1923     if(window->uri && compare_ignoring_frag(window->uri, uri)) {
1924         TRACE("fragment navigate\n");
1925         return navigate_fragment(window, uri);
1926     }
1927
1928     hres = CreateURLMonikerEx2(NULL, uri, &mon, URL_MK_UNIFORM);
1929     if(FAILED(hres))
1930         return hres;
1931
1932     /* FIXME: Why not set_ready_state? */
1933     window->readystate = READYSTATE_UNINITIALIZED;
1934
1935     hres = create_channelbsc(mon, headers, post_data, post_data_size, &bsc);
1936     if(FAILED(hres)) {
1937         IMoniker_Release(mon);
1938         return hres;
1939     }
1940
1941     prepare_for_binding(&window->doc_obj->basedoc, mon, TRUE);
1942
1943     hres = IUri_GetScheme(uri, &scheme);
1944
1945     if(scheme != URL_SCHEME_JAVASCRIPT) {
1946         navigate_task_t *task;
1947
1948         task = heap_alloc(sizeof(*task));
1949         if(!task) {
1950             IUnknown_Release((IUnknown*)bsc);
1951             IMoniker_Release(mon);
1952             return E_OUTOFMEMORY;
1953         }
1954
1955         task->window = window;
1956         task->bscallback = bsc;
1957         task->mon = mon;
1958         push_task(&task->header, navigate_proc, navigate_task_destr, window->task_magic);
1959
1960         /* Silently and repeated when real loading starts? */
1961         window->readystate = READYSTATE_LOADING;
1962     }else {
1963         navigate_javascript_task_t *task;
1964
1965         IUnknown_Release((IUnknown*)bsc);
1966         IMoniker_Release(mon);
1967
1968         task = heap_alloc(sizeof(*task));
1969         if(!task)
1970             return E_OUTOFMEMORY;
1971
1972         IUri_AddRef(uri);
1973         task->window = window;
1974         task->uri = uri;
1975         push_task(&task->header, navigate_javascript_proc, navigate_javascript_task_destr, window->task_magic);
1976
1977         /* Why silently? */
1978         window->readystate = READYSTATE_COMPLETE;
1979     }
1980
1981     return S_OK;
1982 }
1983
1984 HRESULT navigate_new_window(HTMLWindow *window, IUri *uri, const WCHAR *name, IHTMLWindow2 **ret)
1985 {
1986     IWebBrowser2 *web_browser;
1987     IHTMLWindow2 *new_window;
1988     IBindCtx *bind_ctx;
1989     nsChannelBSC *bsc;
1990     HRESULT hres;
1991
1992     hres = create_channelbsc(NULL, NULL, NULL, 0, &bsc);
1993     if(FAILED(hres))
1994         return hres;
1995
1996     hres = CreateAsyncBindCtx(0, &bsc->bsc.IBindStatusCallback_iface, NULL, &bind_ctx);
1997     if(FAILED(hres)) {
1998         IBindStatusCallback_Release(&bsc->bsc.IBindStatusCallback_iface);
1999         return hres;
2000     }
2001
2002     hres = CoCreateInstance(&CLSID_InternetExplorer, NULL, CLSCTX_LOCAL_SERVER,
2003             &IID_IWebBrowser2, (void**)&web_browser);
2004     if(SUCCEEDED(hres)) {
2005         ITargetFramePriv2 *target_frame_priv;
2006
2007         hres = IWebBrowser_QueryInterface(web_browser, &IID_ITargetFramePriv2, (void**)&target_frame_priv);
2008         if(SUCCEEDED(hres)) {
2009             hres = ITargetFramePriv2_AggregatedNavigation2(target_frame_priv,
2010                     HLNF_DISABLEWINDOWRESTRICTIONS|HLNF_OPENINNEWWINDOW, bind_ctx, &bsc->bsc.IBindStatusCallback_iface,
2011                     name, uri, emptyW);
2012             ITargetFramePriv2_Release(target_frame_priv);
2013
2014             if(SUCCEEDED(hres))
2015                 hres = do_query_service((IUnknown*)web_browser, &SID_SHTMLWindow, &IID_IHTMLWindow2, (void**)&new_window);
2016         }
2017         if(FAILED(hres)) {
2018             IWebBrowser2_Quit(web_browser);
2019             IWebBrowser2_Release(web_browser);
2020         }
2021     }else {
2022         WARN("Could not create InternetExplorer instance: %08x\n", hres);
2023     }
2024
2025     IBindStatusCallback_Release(&bsc->bsc.IBindStatusCallback_iface);
2026     IBindCtx_Release(bind_ctx);
2027     if(FAILED(hres))
2028         return hres;
2029
2030     IWebBrowser2_put_Visible(web_browser, VARIANT_TRUE);
2031     IWebBrowser2_Release(web_browser);
2032
2033     if(ret)
2034         *ret = new_window;
2035     else
2036         IHTMLWindow2_Release(new_window);
2037     return S_OK;
2038 }
2039
2040 HRESULT hlink_frame_navigate(HTMLDocument *doc, LPCWSTR url, nsChannel *nschannel, DWORD hlnf, BOOL *cancel)
2041 {
2042     IHlinkFrame *hlink_frame;
2043     nsChannelBSC *callback;
2044     IBindCtx *bindctx;
2045     IMoniker *mon;
2046     IHlink *hlink;
2047     HRESULT hres;
2048
2049     *cancel = FALSE;
2050
2051     hres = do_query_service((IUnknown*)doc->doc_obj->client, &IID_IHlinkFrame, &IID_IHlinkFrame,
2052             (void**)&hlink_frame);
2053     if(FAILED(hres))
2054         return S_OK;
2055
2056     hres = create_channelbsc(NULL, NULL, NULL, 0, &callback);
2057     if(FAILED(hres)) {
2058         IHlinkFrame_Release(hlink_frame);
2059         return hres;
2060     }
2061
2062     if(nschannel)
2063         read_post_data_stream(callback, nschannel);
2064
2065     hres = CreateAsyncBindCtx(0, &callback->bsc.IBindStatusCallback_iface, NULL, &bindctx);
2066     if(SUCCEEDED(hres))
2067         hres = CoCreateInstance(&CLSID_StdHlink, NULL, CLSCTX_INPROC_SERVER,
2068                 &IID_IHlink, (LPVOID*)&hlink);
2069
2070     if(SUCCEEDED(hres))
2071         hres = CreateURLMoniker(NULL, url, &mon);
2072
2073     if(SUCCEEDED(hres)) {
2074         IHlink_SetMonikerReference(hlink, HLINKSETF_TARGET, mon, NULL);
2075
2076         if(hlnf & HLNF_OPENINNEWWINDOW) {
2077             static const WCHAR wszBlank[] = {'_','b','l','a','n','k',0};
2078             IHlink_SetTargetFrameName(hlink, wszBlank); /* FIXME */
2079         }
2080
2081         hres = IHlinkFrame_Navigate(hlink_frame, hlnf, bindctx,
2082                 &callback->bsc.IBindStatusCallback_iface, hlink);
2083         IMoniker_Release(mon);
2084         *cancel = hres == S_OK;
2085         hres = S_OK;
2086     }
2087
2088     IHlinkFrame_Release(hlink_frame);
2089     IBindCtx_Release(bindctx);
2090     IBindStatusCallback_Release(&callback->bsc.IBindStatusCallback_iface);
2091     return hres;
2092 }
2093
2094 HRESULT navigate_url(HTMLWindow *window, const WCHAR *new_url, const WCHAR *base_url)
2095 {
2096     WCHAR url[INTERNET_MAX_URL_LENGTH];
2097     nsWineURI *uri;
2098     HRESULT hres;
2099
2100     if(!new_url) {
2101         *url = 0;
2102     }else if(base_url) {
2103         DWORD len = 0;
2104
2105         hres = CoInternetCombineUrl(base_url, new_url, URL_ESCAPE_SPACES_ONLY|URL_DONT_ESCAPE_EXTRA_INFO,
2106                 url, sizeof(url)/sizeof(WCHAR), &len, 0);
2107         if(FAILED(hres))
2108             return hres;
2109     }else {
2110         strcpyW(url, new_url);
2111     }
2112
2113     if(window->doc_obj && window->doc_obj->hostui) {
2114         OLECHAR *translated_url = NULL;
2115
2116         hres = IDocHostUIHandler_TranslateUrl(window->doc_obj->hostui, 0, url,
2117                 &translated_url);
2118         if(hres == S_OK) {
2119             TRACE("%08x %s -> %s\n", hres, debugstr_w(url), debugstr_w(translated_url));
2120             strcpyW(url, translated_url);
2121             CoTaskMemFree(translated_url);
2122         }
2123     }
2124
2125     if(window->doc_obj && window->doc_obj->is_webbrowser && window == window->doc_obj->basedoc.window) {
2126         BOOL cancel = FALSE;
2127         IUri *uri;
2128
2129         hres = IDocObjectService_FireBeforeNavigate2(window->doc_obj->doc_object_service, NULL, url, 0x40,
2130                 NULL, NULL, 0, NULL, TRUE, &cancel);
2131         if(SUCCEEDED(hres) && cancel) {
2132             TRACE("Navigation canceled\n");
2133             return S_OK;
2134         }
2135
2136         hres = CreateUri(url, 0, 0, &uri);
2137         if(FAILED(hres))
2138             return hres;
2139
2140         hres = super_navigate(window, uri, NULL, NULL, 0);
2141         IUri_Release(uri);
2142         return hres;
2143     }
2144
2145     if(window->doc_obj && window == window->doc_obj->basedoc.window) {
2146         BOOL cancel;
2147
2148         hres = hlink_frame_navigate(&window->doc->basedoc, url, NULL, 0, &cancel);
2149         if(FAILED(hres))
2150             return hres;
2151
2152         if(cancel) {
2153             TRACE("Navigation handled by hlink frame\n");
2154             return S_OK;
2155         }
2156     }
2157
2158     hres = create_doc_uri(window, url, &uri);
2159     if(FAILED(hres))
2160         return hres;
2161
2162     hres = load_nsuri(window, uri, NULL, LOAD_FLAGS_NONE);
2163     nsISupports_Release((nsISupports*)uri);
2164     return hres;
2165 }