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