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