mshtml: Set proposed MIME to text/html on main document.
[wine] / dlls / mshtml / navigate.c
1 /*
2  * Copyright 2006-2010 Jacek Caban for CodeWeavers
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17  */
18
19 #include "config.h"
20
21 #include <stdarg.h>
22
23 #define COBJMACROS
24 #define NONAMELESSUNION
25 #define NONAMELESSSTRUCT
26
27 #include "windef.h"
28 #include "winbase.h"
29 #include "winuser.h"
30 #include "winreg.h"
31 #include "ole2.h"
32 #include "hlguids.h"
33 #include "shlguid.h"
34 #include "wininet.h"
35 #include "shlwapi.h"
36 #include "htiface.h"
37 #include "shdeprecated.h"
38
39 #include "wine/debug.h"
40
41 #include "mshtml_private.h"
42 #include "binding.h"
43
44 WINE_DEFAULT_DEBUG_CHANNEL(mshtml);
45
46 #define CONTENT_LENGTH "Content-Length"
47 #define UTF16_STR "utf-16"
48
49 static const WCHAR emptyW[] = {0};
50
51 struct nsProtocolStream {
52     nsIInputStream nsIInputStream_iface;
53
54     LONG ref;
55
56     char buf[1024];
57     DWORD buf_size;
58 };
59
60 struct BSCallbackVtbl {
61     void (*destroy)(BSCallback*);
62     HRESULT (*init_bindinfo)(BSCallback*);
63     HRESULT (*start_binding)(BSCallback*);
64     HRESULT (*stop_binding)(BSCallback*,HRESULT);
65     HRESULT (*read_data)(BSCallback*,IStream*);
66     HRESULT (*on_progress)(BSCallback*,ULONG,LPCWSTR);
67     HRESULT (*on_response)(BSCallback*,DWORD,LPCWSTR);
68     HRESULT (*beginning_transaction)(BSCallback*,WCHAR**);
69 };
70
71 static inline nsProtocolStream *impl_from_nsIInputStream(nsIInputStream *iface)
72 {
73     return CONTAINING_RECORD(iface, nsProtocolStream, nsIInputStream_iface);
74 }
75
76 static nsresult NSAPI nsInputStream_QueryInterface(nsIInputStream *iface, nsIIDRef riid,
77         void **result)
78 {
79     nsProtocolStream *This = impl_from_nsIInputStream(iface);
80
81     *result = NULL;
82
83     if(IsEqualGUID(&IID_nsISupports, riid)) {
84         TRACE("(%p)->(IID_nsISupports %p)\n", This, result);
85         *result  = &This->nsIInputStream_iface;
86     }else if(IsEqualGUID(&IID_nsIInputStream, riid)) {
87         TRACE("(%p)->(IID_nsIInputStream %p)\n", This, result);
88         *result  = &This->nsIInputStream_iface;
89     }
90
91     if(*result) {
92         nsIInputStream_AddRef(&This->nsIInputStream_iface);
93         return NS_OK;
94     }
95
96     WARN("unsupported interface %s\n", debugstr_guid(riid));
97     return NS_NOINTERFACE;
98 }
99
100 static nsrefcnt NSAPI nsInputStream_AddRef(nsIInputStream *iface)
101 {
102     nsProtocolStream *This = impl_from_nsIInputStream(iface);
103     LONG ref = InterlockedIncrement(&This->ref);
104
105     TRACE("(%p) ref=%d\n", This, ref);
106
107     return ref;
108 }
109
110
111 static nsrefcnt NSAPI nsInputStream_Release(nsIInputStream *iface)
112 {
113     nsProtocolStream *This = impl_from_nsIInputStream(iface);
114     LONG ref = InterlockedDecrement(&This->ref);
115
116     TRACE("(%p) ref=%d\n", This, ref);
117
118     if(!ref)
119         heap_free(This);
120
121     return ref;
122 }
123
124 static nsresult NSAPI nsInputStream_Close(nsIInputStream *iface)
125 {
126     nsProtocolStream *This = impl_from_nsIInputStream(iface);
127     FIXME("(%p)\n", This);
128     return NS_ERROR_NOT_IMPLEMENTED;
129 }
130
131 static nsresult NSAPI nsInputStream_Available(nsIInputStream *iface, PRUint32 *_retval)
132 {
133     nsProtocolStream *This = impl_from_nsIInputStream(iface);
134     FIXME("(%p)->(%p)\n", This, _retval);
135     return NS_ERROR_NOT_IMPLEMENTED;
136 }
137
138 static nsresult NSAPI nsInputStream_Read(nsIInputStream *iface, char *aBuf, PRUint32 aCount,
139                                          PRUint32 *_retval)
140 {
141     nsProtocolStream *This = impl_from_nsIInputStream(iface);
142     DWORD read = aCount;
143
144     TRACE("(%p)->(%p %d %p)\n", This, aBuf, aCount, _retval);
145
146     if(read > This->buf_size)
147         read = This->buf_size;
148
149     if(read) {
150         memcpy(aBuf, This->buf, read);
151         if(read < This->buf_size)
152             memmove(This->buf, This->buf+read, This->buf_size-read);
153         This->buf_size -= read;
154     }
155
156     *_retval = read;
157     return NS_OK;
158 }
159
160 static nsresult NSAPI nsInputStream_ReadSegments(nsIInputStream *iface,
161         nsresult (WINAPI *aWriter)(nsIInputStream*,void*,const char*,PRUint32,PRUint32,PRUint32*),
162         void *aClousure, PRUint32 aCount, PRUint32 *_retval)
163 {
164     nsProtocolStream *This = impl_from_nsIInputStream(iface);
165     PRUint32 written = 0;
166     nsresult nsres;
167
168     TRACE("(%p)->(%p %p %d %p)\n", This, aWriter, aClousure, aCount, _retval);
169
170     if(!This->buf_size)
171         return S_OK;
172
173     if(aCount > This->buf_size)
174         aCount = This->buf_size;
175
176     nsres = aWriter(&This->nsIInputStream_iface, aClousure, This->buf, 0, aCount, &written);
177     if(NS_FAILED(nsres))
178         TRACE("aWritter failed: %08x\n", nsres);
179     else if(written != This->buf_size)
180         FIXME("written %d != buf_size %d\n", written, This->buf_size);
181
182     This->buf_size -= written; 
183
184     *_retval = written;
185     return nsres;
186 }
187
188 static nsresult NSAPI nsInputStream_IsNonBlocking(nsIInputStream *iface, PRBool *_retval)
189 {
190     nsProtocolStream *This = impl_from_nsIInputStream(iface);
191     FIXME("(%p)->(%p)\n", This, _retval);
192     return NS_ERROR_NOT_IMPLEMENTED;
193 }
194
195 static const nsIInputStreamVtbl nsInputStreamVtbl = {
196     nsInputStream_QueryInterface,
197     nsInputStream_AddRef,
198     nsInputStream_Release,
199     nsInputStream_Close,
200     nsInputStream_Available,
201     nsInputStream_Read,
202     nsInputStream_ReadSegments,
203     nsInputStream_IsNonBlocking
204 };
205
206 static nsProtocolStream *create_nsprotocol_stream(void)
207 {
208     nsProtocolStream *ret = heap_alloc(sizeof(nsProtocolStream));
209
210     ret->nsIInputStream_iface.lpVtbl = &nsInputStreamVtbl;
211     ret->ref = 1;
212     ret->buf_size = 0;
213
214     return ret;
215 }
216
217 static inline BSCallback *impl_from_IBindStatusCallback(IBindStatusCallback *iface)
218 {
219     return CONTAINING_RECORD(iface, BSCallback, IBindStatusCallback_iface);
220 }
221
222 static HRESULT WINAPI BindStatusCallback_QueryInterface(IBindStatusCallback *iface,
223         REFIID riid, void **ppv)
224 {
225     BSCallback *This = impl_from_IBindStatusCallback(iface);
226
227     *ppv = NULL;
228     if(IsEqualGUID(&IID_IUnknown, riid)) {
229         TRACE("(%p)->(IID_IUnknown, %p)\n", This, ppv);
230         *ppv = &This->IBindStatusCallback_iface;
231     }else if(IsEqualGUID(&IID_IBindStatusCallback, riid)) {
232         TRACE("(%p)->(IID_IBindStatusCallback, %p)\n", This, ppv);
233         *ppv = &This->IBindStatusCallback_iface;
234     }else if(IsEqualGUID(&IID_IServiceProvider, riid)) {
235         TRACE("(%p)->(IID_IServiceProvider %p)\n", This, ppv);
236         *ppv = &This->IServiceProvider_iface;
237     }else if(IsEqualGUID(&IID_IHttpNegotiate, riid)) {
238         TRACE("(%p)->(IID_IHttpNegotiate %p)\n", This, ppv);
239         *ppv = &This->IHttpNegotiate2_iface;
240     }else if(IsEqualGUID(&IID_IHttpNegotiate2, riid)) {
241         TRACE("(%p)->(IID_IHttpNegotiate2 %p)\n", This, ppv);
242         *ppv = &This->IHttpNegotiate2_iface;
243     }else if(IsEqualGUID(&IID_IInternetBindInfo, riid)) {
244         TRACE("(%p)->(IID_IInternetBindInfo %p)\n", This, ppv);
245         *ppv = &This->IInternetBindInfo_iface;
246     }
247
248     if(*ppv) {
249         IBindStatusCallback_AddRef(&This->IBindStatusCallback_iface);
250         return S_OK;
251     }
252
253     TRACE("Unsupported riid = %s\n", debugstr_guid(riid));
254     return E_NOINTERFACE;
255 }
256
257 static ULONG WINAPI BindStatusCallback_AddRef(IBindStatusCallback *iface)
258 {
259     BSCallback *This = impl_from_IBindStatusCallback(iface);
260     LONG ref = InterlockedIncrement(&This->ref);
261
262     TRACE("(%p) ref = %d\n", This, ref);
263
264     return ref;
265 }
266
267 static ULONG WINAPI BindStatusCallback_Release(IBindStatusCallback *iface)
268 {
269     BSCallback *This = impl_from_IBindStatusCallback(iface);
270     LONG ref = InterlockedDecrement(&This->ref);
271
272     TRACE("(%p) ref = %d\n", This, ref);
273
274     if(!ref) {
275         if(This->post_data)
276             GlobalFree(This->post_data);
277         if(This->mon)
278             IMoniker_Release(This->mon);
279         if(This->binding)
280             IBinding_Release(This->binding);
281         list_remove(&This->entry);
282         list_init(&This->entry);
283         heap_free(This->headers);
284
285         This->vtbl->destroy(This);
286     }
287
288     return ref;
289 }
290
291 static HRESULT WINAPI BindStatusCallback_OnStartBinding(IBindStatusCallback *iface,
292         DWORD dwReserved, IBinding *pbind)
293 {
294     BSCallback *This = impl_from_IBindStatusCallback(iface);
295
296     TRACE("(%p)->(%d %p)\n", This, dwReserved, pbind);
297
298     IBinding_AddRef(pbind);
299     This->binding = pbind;
300
301     if(This->doc)
302         list_add_head(&This->doc->bindings, &This->entry);
303
304     return This->vtbl->start_binding(This);
305 }
306
307 static HRESULT WINAPI BindStatusCallback_GetPriority(IBindStatusCallback *iface, LONG *pnPriority)
308 {
309     BSCallback *This = impl_from_IBindStatusCallback(iface);
310     FIXME("(%p)->(%p)\n", This, pnPriority);
311     return E_NOTIMPL;
312 }
313
314 static HRESULT WINAPI BindStatusCallback_OnLowResource(IBindStatusCallback *iface, DWORD reserved)
315 {
316     BSCallback *This = impl_from_IBindStatusCallback(iface);
317     FIXME("(%p)->(%d)\n", This, reserved);
318     return E_NOTIMPL;
319 }
320
321 static HRESULT WINAPI BindStatusCallback_OnProgress(IBindStatusCallback *iface, ULONG ulProgress,
322         ULONG ulProgressMax, ULONG ulStatusCode, LPCWSTR szStatusText)
323 {
324     BSCallback *This = impl_from_IBindStatusCallback(iface);
325
326     TRACE("%p)->(%u %u %u %s)\n", This, ulProgress, ulProgressMax, ulStatusCode,
327             debugstr_w(szStatusText));
328
329     return This->vtbl->on_progress(This, ulStatusCode, szStatusText);
330 }
331
332 static HRESULT WINAPI BindStatusCallback_OnStopBinding(IBindStatusCallback *iface,
333         HRESULT hresult, LPCWSTR szError)
334 {
335     BSCallback *This = impl_from_IBindStatusCallback(iface);
336     HRESULT hres;
337
338     TRACE("(%p)->(%08x %s)\n", This, hresult, debugstr_w(szError));
339
340     /* NOTE: IE7 calls GetBindResult here */
341
342     hres = This->vtbl->stop_binding(This, hresult);
343
344     if(This->binding) {
345         IBinding_Release(This->binding);
346         This->binding = NULL;
347     }
348
349     list_remove(&This->entry);
350     list_init(&This->entry);
351     This->doc = NULL;
352
353     return hres;
354 }
355
356 static HRESULT WINAPI BindStatusCallback_GetBindInfo(IBindStatusCallback *iface,
357         DWORD *grfBINDF, BINDINFO *pbindinfo)
358 {
359     BSCallback *This = impl_from_IBindStatusCallback(iface);
360     DWORD size;
361
362     TRACE("(%p)->(%p %p)\n", This, grfBINDF, pbindinfo);
363
364     if(!This->bindinfo_ready) {
365         HRESULT hres;
366
367         hres = This->vtbl->init_bindinfo(This);
368         if(FAILED(hres))
369             return hres;
370
371         This->bindinfo_ready = TRUE;
372     }
373
374     *grfBINDF = This->bindf;
375
376     size = pbindinfo->cbSize;
377     memset(pbindinfo, 0, size);
378     pbindinfo->cbSize = size;
379
380     pbindinfo->cbstgmedData = This->post_data_len;
381     pbindinfo->dwCodePage = CP_UTF8;
382     pbindinfo->dwOptions = 0x80000;
383
384     if(This->post_data) {
385         pbindinfo->dwBindVerb = BINDVERB_POST;
386
387         pbindinfo->stgmedData.tymed = TYMED_HGLOBAL;
388         pbindinfo->stgmedData.u.hGlobal = This->post_data;
389         pbindinfo->stgmedData.pUnkForRelease = (IUnknown*)&This->IBindStatusCallback_iface;
390         IBindStatusCallback_AddRef(&This->IBindStatusCallback_iface);
391     }
392
393     return S_OK;
394 }
395
396 static HRESULT WINAPI BindStatusCallback_OnDataAvailable(IBindStatusCallback *iface,
397         DWORD grfBSCF, DWORD dwSize, FORMATETC *pformatetc, STGMEDIUM *pstgmed)
398 {
399     BSCallback *This = impl_from_IBindStatusCallback(iface);
400
401     TRACE("(%p)->(%08x %d %p %p)\n", This, grfBSCF, dwSize, pformatetc, pstgmed);
402
403     return This->vtbl->read_data(This, pstgmed->u.pstm);
404 }
405
406 static HRESULT WINAPI BindStatusCallback_OnObjectAvailable(IBindStatusCallback *iface,
407         REFIID riid, IUnknown *punk)
408 {
409     BSCallback *This = impl_from_IBindStatusCallback(iface);
410     FIXME("(%p)->(%s %p)\n", This, debugstr_guid(riid), punk);
411     return E_NOTIMPL;
412 }
413
414 static const IBindStatusCallbackVtbl BindStatusCallbackVtbl = {
415     BindStatusCallback_QueryInterface,
416     BindStatusCallback_AddRef,
417     BindStatusCallback_Release,
418     BindStatusCallback_OnStartBinding,
419     BindStatusCallback_GetPriority,
420     BindStatusCallback_OnLowResource,
421     BindStatusCallback_OnProgress,
422     BindStatusCallback_OnStopBinding,
423     BindStatusCallback_GetBindInfo,
424     BindStatusCallback_OnDataAvailable,
425     BindStatusCallback_OnObjectAvailable
426 };
427
428 static inline BSCallback *impl_from_IHttpNegotiate2(IHttpNegotiate2 *iface)
429 {
430     return CONTAINING_RECORD(iface, BSCallback, IHttpNegotiate2_iface);
431 }
432
433 static HRESULT WINAPI HttpNegotiate_QueryInterface(IHttpNegotiate2 *iface,
434                                                    REFIID riid, void **ppv)
435 {
436     BSCallback *This = impl_from_IHttpNegotiate2(iface);
437     return IBindStatusCallback_QueryInterface(&This->IBindStatusCallback_iface, riid, ppv);
438 }
439
440 static ULONG WINAPI HttpNegotiate_AddRef(IHttpNegotiate2 *iface)
441 {
442     BSCallback *This = impl_from_IHttpNegotiate2(iface);
443     return IBindStatusCallback_AddRef(&This->IBindStatusCallback_iface);
444 }
445
446 static ULONG WINAPI HttpNegotiate_Release(IHttpNegotiate2 *iface)
447 {
448     BSCallback *This = impl_from_IHttpNegotiate2(iface);
449     return IBindStatusCallback_Release(&This->IBindStatusCallback_iface);
450 }
451
452 static HRESULT WINAPI HttpNegotiate_BeginningTransaction(IHttpNegotiate2 *iface,
453         LPCWSTR szURL, LPCWSTR szHeaders, DWORD dwReserved, LPWSTR *pszAdditionalHeaders)
454 {
455     BSCallback *This = impl_from_IHttpNegotiate2(iface);
456     HRESULT hres;
457
458     TRACE("(%p)->(%s %s %d %p)\n", This, debugstr_w(szURL), debugstr_w(szHeaders),
459           dwReserved, pszAdditionalHeaders);
460
461     *pszAdditionalHeaders = NULL;
462
463     hres = This->vtbl->beginning_transaction(This, pszAdditionalHeaders);
464     if(hres != S_FALSE)
465         return hres;
466
467     if(This->headers) {
468         DWORD size;
469
470         size = (strlenW(This->headers)+1)*sizeof(WCHAR);
471         *pszAdditionalHeaders = CoTaskMemAlloc(size);
472         if(!*pszAdditionalHeaders)
473             return E_OUTOFMEMORY;
474         memcpy(*pszAdditionalHeaders, This->headers, size);
475     }
476
477     return S_OK;
478 }
479
480 static HRESULT WINAPI HttpNegotiate_OnResponse(IHttpNegotiate2 *iface, DWORD dwResponseCode,
481         LPCWSTR szResponseHeaders, LPCWSTR szRequestHeaders, LPWSTR *pszAdditionalRequestHeaders)
482 {
483     BSCallback *This = impl_from_IHttpNegotiate2(iface);
484
485     TRACE("(%p)->(%d %s %s %p)\n", This, dwResponseCode, debugstr_w(szResponseHeaders),
486           debugstr_w(szRequestHeaders), pszAdditionalRequestHeaders);
487
488     return This->vtbl->on_response(This, dwResponseCode, szResponseHeaders);
489 }
490
491 static HRESULT WINAPI HttpNegotiate_GetRootSecurityId(IHttpNegotiate2 *iface,
492         BYTE *pbSecurityId, DWORD *pcbSecurityId, DWORD_PTR dwReserved)
493 {
494     BSCallback *This = impl_from_IHttpNegotiate2(iface);
495     FIXME("(%p)->(%p %p %ld)\n", This, pbSecurityId, pcbSecurityId, dwReserved);
496     return E_NOTIMPL;
497 }
498
499 static const IHttpNegotiate2Vtbl HttpNegotiate2Vtbl = {
500     HttpNegotiate_QueryInterface,
501     HttpNegotiate_AddRef,
502     HttpNegotiate_Release,
503     HttpNegotiate_BeginningTransaction,
504     HttpNegotiate_OnResponse,
505     HttpNegotiate_GetRootSecurityId
506 };
507
508 static inline BSCallback *impl_from_IInternetBindInfo(IInternetBindInfo *iface)
509 {
510     return CONTAINING_RECORD(iface, BSCallback, IInternetBindInfo_iface);
511 }
512
513 static HRESULT WINAPI InternetBindInfo_QueryInterface(IInternetBindInfo *iface,
514                                                       REFIID riid, void **ppv)
515 {
516     BSCallback *This = impl_from_IInternetBindInfo(iface);
517     return IBindStatusCallback_QueryInterface(&This->IBindStatusCallback_iface, riid, ppv);
518 }
519
520 static ULONG WINAPI InternetBindInfo_AddRef(IInternetBindInfo *iface)
521 {
522     BSCallback *This = impl_from_IInternetBindInfo(iface);
523     return IBindStatusCallback_AddRef(&This->IBindStatusCallback_iface);
524 }
525
526 static ULONG WINAPI InternetBindInfo_Release(IInternetBindInfo *iface)
527 {
528     BSCallback *This = impl_from_IInternetBindInfo(iface);
529     return IBindStatusCallback_Release(&This->IBindStatusCallback_iface);
530 }
531
532 static HRESULT WINAPI InternetBindInfo_GetBindInfo(IInternetBindInfo *iface,
533                                                    DWORD *grfBINDF, BINDINFO *pbindinfo)
534 {
535     BSCallback *This = impl_from_IInternetBindInfo(iface);
536     FIXME("(%p)->(%p %p)\n", This, grfBINDF, pbindinfo);
537     return E_NOTIMPL;
538 }
539
540 static HRESULT WINAPI InternetBindInfo_GetBindString(IInternetBindInfo *iface,
541         ULONG ulStringType, LPOLESTR *ppwzStr, ULONG cEl, ULONG *pcElFetched)
542 {
543     BSCallback *This = impl_from_IInternetBindInfo(iface);
544     FIXME("(%p)->(%u %p %u %p)\n", This, ulStringType, ppwzStr, cEl, pcElFetched);
545     return E_NOTIMPL;
546 }
547
548 static const IInternetBindInfoVtbl InternetBindInfoVtbl = {
549     InternetBindInfo_QueryInterface,
550     InternetBindInfo_AddRef,
551     InternetBindInfo_Release,
552     InternetBindInfo_GetBindInfo,
553     InternetBindInfo_GetBindString
554 };
555
556 static inline BSCallback *impl_from_IServiceProvider(IServiceProvider *iface)
557 {
558     return CONTAINING_RECORD(iface, BSCallback, IServiceProvider_iface);
559 }
560
561 static HRESULT WINAPI BSCServiceProvider_QueryInterface(IServiceProvider *iface,
562                                                         REFIID riid, void **ppv)
563 {
564     BSCallback *This = impl_from_IServiceProvider(iface);
565     return IBindStatusCallback_QueryInterface(&This->IBindStatusCallback_iface, riid, ppv);
566 }
567
568 static ULONG WINAPI BSCServiceProvider_AddRef(IServiceProvider *iface)
569 {
570     BSCallback *This = impl_from_IServiceProvider(iface);
571     return IBindStatusCallback_AddRef(&This->IBindStatusCallback_iface);
572 }
573
574 static ULONG WINAPI BSCServiceProvider_Release(IServiceProvider *iface)
575 {
576     BSCallback *This = impl_from_IServiceProvider(iface);
577     return IBindStatusCallback_Release(&This->IBindStatusCallback_iface);
578 }
579
580 static HRESULT WINAPI BSCServiceProvider_QueryService(IServiceProvider *iface,
581         REFGUID guidService, REFIID riid, void **ppv)
582 {
583     BSCallback *This = impl_from_IServiceProvider(iface);
584     TRACE("(%p)->(%s %s %p)\n", This, debugstr_guid(guidService), debugstr_guid(riid), ppv);
585     return E_NOINTERFACE;
586 }
587
588 static const IServiceProviderVtbl ServiceProviderVtbl = {
589     BSCServiceProvider_QueryInterface,
590     BSCServiceProvider_AddRef,
591     BSCServiceProvider_Release,
592     BSCServiceProvider_QueryService
593 };
594
595 static void init_bscallback(BSCallback *This, const BSCallbackVtbl *vtbl, IMoniker *mon, DWORD bindf)
596 {
597     This->IBindStatusCallback_iface.lpVtbl = &BindStatusCallbackVtbl;
598     This->IServiceProvider_iface.lpVtbl = &ServiceProviderVtbl;
599     This->IHttpNegotiate2_iface.lpVtbl = &HttpNegotiate2Vtbl;
600     This->IInternetBindInfo_iface.lpVtbl = &InternetBindInfoVtbl;
601     This->vtbl = vtbl;
602     This->ref = 1;
603     This->bindf = bindf;
604
605     list_init(&This->entry);
606
607     if(mon)
608         IMoniker_AddRef(mon);
609     This->mon = mon;
610 }
611
612 /* Calls undocumented 84 cmd of CGID_ShellDocView */
613 static void call_docview_84(HTMLDocumentObj *doc)
614 {
615     IOleCommandTarget *olecmd;
616     VARIANT var;
617     HRESULT hres;
618
619     if(!doc->client)
620         return;
621
622     hres = IOleClientSite_QueryInterface(doc->client, &IID_IOleCommandTarget, (void**)&olecmd);
623     if(FAILED(hres))
624         return;
625
626     VariantInit(&var);
627     hres = IOleCommandTarget_Exec(olecmd, &CGID_ShellDocView, 84, 0, NULL, &var);
628     IOleCommandTarget_Release(olecmd);
629     if(SUCCEEDED(hres) && V_VT(&var) != VT_NULL)
630         FIXME("handle result\n");
631 }
632
633 static void parse_content_type(nsChannelBSC *This, const WCHAR *value)
634 {
635     const WCHAR *ptr;
636     size_t len;
637
638     static const WCHAR charsetW[] = {'c','h','a','r','s','e','t','='};
639
640     ptr = strchrW(value, ';');
641     if(!ptr)
642         return;
643
644     ptr++;
645     while(*ptr && isspaceW(*ptr))
646         ptr++;
647
648     len = strlenW(value);
649     if(ptr + sizeof(charsetW)/sizeof(WCHAR) < value+len && !memicmpW(ptr, charsetW, sizeof(charsetW)/sizeof(WCHAR))) {
650         size_t charset_len, lena;
651         nsACString charset_str;
652         const WCHAR *charset;
653         char *charseta;
654
655         ptr += sizeof(charsetW)/sizeof(WCHAR);
656
657         if(*ptr == '\'') {
658             FIXME("Quoted value\n");
659             return;
660         }else {
661             charset = ptr;
662             while(*ptr && *ptr != ',')
663                 ptr++;
664             charset_len = ptr-charset;
665         }
666
667         lena = WideCharToMultiByte(CP_ACP, 0, charset, charset_len, NULL, 0, NULL, NULL);
668         charseta = heap_alloc(lena+1);
669         if(!charseta)
670             return;
671
672         WideCharToMultiByte(CP_ACP, 0, charset, charset_len, charseta, lena, NULL, NULL);
673         charseta[lena] = 0;
674
675         nsACString_InitDepend(&charset_str, charseta);
676         nsIHttpChannel_SetContentCharset(&This->nschannel->nsIHttpChannel_iface, &charset_str);
677         nsACString_Finish(&charset_str);
678         heap_free(charseta);
679     }else {
680         FIXME("unhandled: %s\n", debugstr_wn(ptr, len - (ptr-value)));
681     }
682 }
683
684 static HRESULT parse_headers(const WCHAR *headers, struct list *headers_list)
685 {
686     const WCHAR *header, *header_end, *colon, *value;
687     HRESULT hres;
688
689     header = headers;
690     while(*header) {
691         if(header[0] == '\r' && header[1] == '\n' && !header[2])
692             break;
693         for(colon = header; *colon && *colon != ':' && *colon != '\r'; colon++);
694         if(*colon != ':')
695             return E_FAIL;
696
697         value = colon+1;
698         while(*value == ' ')
699             value++;
700         if(!*value)
701             return E_FAIL;
702
703         for(header_end = value+1; *header_end && *header_end != '\r'; header_end++);
704
705         hres = set_http_header(headers_list, header, colon-header, value, header_end-value);
706         if(FAILED(hres))
707             return hres;
708
709         header = header_end;
710         if(header[0] == '\r' && header[1] == '\n')
711             header += 2;
712     }
713
714     return S_OK;
715 }
716
717 static HRESULT process_response_headers(nsChannelBSC *This, const WCHAR *headers)
718 {
719     http_header_t *iter;
720     HRESULT hres;
721
722     static const WCHAR content_typeW[] = {'c','o','n','t','e','n','t','-','t','y','p','e',0};
723
724     hres = parse_headers(headers, &This->nschannel->response_headers);
725     if(FAILED(hres))
726         return hres;
727
728     LIST_FOR_EACH_ENTRY(iter, &This->nschannel->response_headers, http_header_t, entry) {
729         if(!strcmpiW(iter->header, content_typeW))
730             parse_content_type(This, iter->data);
731     }
732
733     return S_OK;
734 }
735
736 HRESULT start_binding(HTMLWindow *window, HTMLDocumentNode *doc, BSCallback *bscallback, IBindCtx *bctx)
737 {
738     IStream *str = NULL;
739     HRESULT hres;
740
741     TRACE("(%p %p %p %p)\n", window, doc, bscallback, bctx);
742
743     bscallback->doc = doc;
744
745     /* NOTE: IE7 calls IsSystemMoniker here*/
746
747     if(window) {
748         if(bscallback->mon != window->mon)
749             set_current_mon(window, bscallback->mon);
750         call_docview_84(window->doc_obj);
751     }
752
753     if(bctx) {
754         RegisterBindStatusCallback(bctx, &bscallback->IBindStatusCallback_iface, NULL, 0);
755         IBindCtx_AddRef(bctx);
756     }else {
757         hres = CreateAsyncBindCtx(0, &bscallback->IBindStatusCallback_iface, NULL, &bctx);
758         if(FAILED(hres)) {
759             WARN("CreateAsyncBindCtx failed: %08x\n", hres);
760             bscallback->vtbl->stop_binding(bscallback, hres);
761             return hres;
762         }
763     }
764
765     hres = IMoniker_BindToStorage(bscallback->mon, bctx, NULL, &IID_IStream, (void**)&str);
766     IBindCtx_Release(bctx);
767     if(FAILED(hres)) {
768         WARN("BindToStorage failed: %08x\n", hres);
769         bscallback->vtbl->stop_binding(bscallback, hres);
770         return hres;
771     }
772
773     if(str)
774         IStream_Release(str);
775
776     IMoniker_Release(bscallback->mon);
777     bscallback->mon = NULL;
778
779     return S_OK;
780 }
781
782 typedef struct {
783     BSCallback bsc;
784
785     DWORD size;
786     BYTE *buf;
787     HRESULT hres;
788 } BufferBSC;
789
790 static inline BufferBSC *BufferBSC_from_BSCallback(BSCallback *iface)
791 {
792     return CONTAINING_RECORD(iface, BufferBSC, bsc);
793 }
794
795 static void BufferBSC_destroy(BSCallback *bsc)
796 {
797     BufferBSC *This = BufferBSC_from_BSCallback(bsc);
798
799     heap_free(This->buf);
800     heap_free(This);
801 }
802
803 static HRESULT BufferBSC_init_bindinfo(BSCallback *bsc)
804 {
805     return S_OK;
806 }
807
808 static HRESULT BufferBSC_start_binding(BSCallback *bsc)
809 {
810     return S_OK;
811 }
812
813 static HRESULT BufferBSC_stop_binding(BSCallback *bsc, HRESULT result)
814 {
815     BufferBSC *This = BufferBSC_from_BSCallback(bsc);
816
817     This->hres = result;
818
819     if(FAILED(result)) {
820         heap_free(This->buf);
821         This->buf = NULL;
822         This->size = 0;
823     }
824
825     return S_OK;
826 }
827
828 static HRESULT BufferBSC_read_data(BSCallback *bsc, IStream *stream)
829 {
830     BufferBSC *This = BufferBSC_from_BSCallback(bsc);
831     DWORD readed;
832     HRESULT hres;
833
834     if(!This->buf) {
835         This->size = 128;
836         This->buf = heap_alloc(This->size);
837     }
838
839     do {
840         if(This->bsc.readed == This->size) {
841             This->size <<= 1;
842             This->buf = heap_realloc(This->buf, This->size);
843         }
844
845         readed = 0;
846         hres = IStream_Read(stream, This->buf+This->bsc.readed, This->size-This->bsc.readed, &readed);
847         This->bsc.readed += readed;
848     }while(hres == S_OK);
849
850     return S_OK;
851 }
852
853 static HRESULT BufferBSC_on_progress(BSCallback *bsc, ULONG status_code, LPCWSTR status_text)
854 {
855     return S_OK;
856 }
857
858 static HRESULT BufferBSC_on_response(BSCallback *bsc, DWORD response_code,
859         LPCWSTR response_headers)
860 {
861     return S_OK;
862 }
863
864 static HRESULT BufferBSC_beginning_transaction(BSCallback *bsc, WCHAR **additional_headers)
865 {
866     return S_FALSE;
867 }
868
869 static const BSCallbackVtbl BufferBSCVtbl = {
870     BufferBSC_destroy,
871     BufferBSC_init_bindinfo,
872     BufferBSC_start_binding,
873     BufferBSC_stop_binding,
874     BufferBSC_read_data,
875     BufferBSC_on_progress,
876     BufferBSC_on_response,
877     BufferBSC_beginning_transaction
878 };
879
880
881 static BufferBSC *create_bufferbsc(IMoniker *mon)
882 {
883     BufferBSC *ret = heap_alloc_zero(sizeof(*ret));
884
885     init_bscallback(&ret->bsc, &BufferBSCVtbl, mon, 0);
886     ret->hres = E_FAIL;
887
888     return ret;
889 }
890
891 HRESULT bind_mon_to_buffer(HTMLDocumentNode *doc, IMoniker *mon, void **buf, DWORD *size)
892 {
893     BufferBSC *bsc = create_bufferbsc(mon);
894     HRESULT hres;
895
896     *buf = NULL;
897
898     hres = start_binding(NULL, doc, &bsc->bsc, NULL);
899     if(SUCCEEDED(hres)) {
900         hres = bsc->hres;
901         if(SUCCEEDED(hres)) {
902             *buf = bsc->buf;
903             bsc->buf = NULL;
904             *size = bsc->bsc.readed;
905             bsc->size = 0;
906         }
907     }
908
909     IBindStatusCallback_Release(&bsc->bsc.IBindStatusCallback_iface);
910
911     return hres;
912 }
913
914 static HRESULT read_post_data_stream(nsChannelBSC *This, nsChannel *nschannel)
915 {
916     PRUint32 data_len = 0, available = 0;
917     char *data, *post_data;
918     nsresult nsres;
919     HRESULT hres = S_OK;
920
921     if(!nschannel->post_data_stream)
922         return S_OK;
923
924     nsres =  nsIInputStream_Available(nschannel->post_data_stream, &available);
925     if(NS_FAILED(nsres))
926         return E_FAIL;
927
928     post_data = data = GlobalAlloc(0, available);
929     if(!data)
930         return E_OUTOFMEMORY;
931
932     nsres = nsIInputStream_Read(nschannel->post_data_stream, data, available, &data_len);
933     if(NS_FAILED(nsres)) {
934         GlobalFree(data);
935         return E_FAIL;
936     }
937
938     if(nschannel->post_data_contains_headers) {
939         if(data_len >= 2 && data[0] == '\r' && data[1] == '\n') {
940             post_data = data+2;
941             data_len -= 2;
942         }else {
943             WCHAR *headers;
944             DWORD size;
945             char *ptr;
946
947             post_data += data_len;
948             for(ptr = data; ptr+4 < data+data_len; ptr++) {
949                 if(!memcmp(ptr, "\r\n\r\n", 4)) {
950                     post_data = ptr+4;
951                     break;
952                 }
953             }
954
955             data_len -= post_data-data;
956
957             size = MultiByteToWideChar(CP_ACP, 0, data, post_data-data, NULL, 0);
958             headers = heap_alloc((size+1)*sizeof(WCHAR));
959             if(headers) {
960                 MultiByteToWideChar(CP_ACP, 0, data, post_data-data, headers, size);
961                 headers[size] = 0;
962                 hres = parse_headers(headers , &nschannel->request_headers);
963                 if(SUCCEEDED(hres))
964                     This->bsc.headers = headers;
965                 else
966                     heap_free(headers);
967             }else {
968                 hres = E_OUTOFMEMORY;
969             }
970         }
971     }
972
973     if(FAILED(hres)) {
974         GlobalFree(data);
975         return hres;
976     }
977
978     if(!data_len) {
979         GlobalFree(data);
980         post_data = NULL;
981     }else if(post_data != data) {
982         char *new_data;
983
984         new_data = GlobalAlloc(0, data_len);
985         if(new_data)
986             memcpy(new_data, post_data, data_len);
987         GlobalFree(data);
988         if(!new_data)
989             return E_OUTOFMEMORY;
990         post_data = new_data;
991     }
992
993     This->bsc.post_data = post_data;
994     This->bsc.post_data_len = data_len;
995     TRACE("post_data = %s\n", debugstr_a(This->bsc.post_data));
996     return S_OK;
997 }
998
999 static HRESULT on_start_nsrequest(nsChannelBSC *This)
1000 {
1001     nsresult nsres;
1002
1003     /* FIXME: it's needed for http connections from BindToObject. */
1004     if(!This->nschannel->response_status)
1005         This->nschannel->response_status = 200;
1006
1007     nsres = nsIStreamListener_OnStartRequest(This->nslistener,
1008             (nsIRequest*)&This->nschannel->nsIHttpChannel_iface, This->nscontext);
1009     if(NS_FAILED(nsres)) {
1010         FIXME("OnStartRequest failed: %08x\n", nsres);
1011         return E_FAIL;
1012     }
1013
1014     if(This->window) {
1015         list_remove(&This->bsc.entry);
1016         list_init(&This->bsc.entry);
1017         update_window_doc(This->window);
1018         if(This->window->doc != This->bsc.doc)
1019             This->bsc.doc = This->window->doc;
1020         list_add_head(&This->bsc.doc->bindings, &This->bsc.entry);
1021         if(This->window->readystate != READYSTATE_LOADING)
1022             set_ready_state(This->window, READYSTATE_LOADING);
1023     }
1024
1025     return S_OK;
1026 }
1027
1028 static void on_stop_nsrequest(nsChannelBSC *This, HRESULT result)
1029 {
1030     nsresult nsres, request_result;
1031
1032     switch(result) {
1033     case S_OK:
1034         request_result = NS_OK;
1035         break;
1036     case E_ABORT:
1037         request_result = NS_BINDING_ABORTED;
1038         break;
1039     default:
1040         request_result = NS_ERROR_FAILURE;
1041     }
1042
1043     if(This->nslistener) {
1044         nsres = nsIStreamListener_OnStopRequest(This->nslistener,
1045                  (nsIRequest*)&This->nschannel->nsIHttpChannel_iface, This->nscontext,
1046                  request_result);
1047         if(NS_FAILED(nsres))
1048             WARN("OnStopRequest failed: %08x\n", nsres);
1049     }
1050
1051     if(This->nschannel->load_group) {
1052         nsres = nsILoadGroup_RemoveRequest(This->nschannel->load_group,
1053                 (nsIRequest*)&This->nschannel->nsIHttpChannel_iface, NULL, request_result);
1054         if(NS_FAILED(nsres))
1055             ERR("RemoveRequest failed: %08x\n", nsres);
1056     }
1057 }
1058
1059 static HRESULT read_stream_data(nsChannelBSC *This, IStream *stream)
1060 {
1061     static const WCHAR mimeTextHtml[] = {'t','e','x','t','/','h','t','m','l',0};
1062
1063     DWORD read;
1064     nsresult nsres;
1065     HRESULT hres;
1066
1067     if(!This->nslistener) {
1068         BYTE buf[1024];
1069
1070         do {
1071             read = 0;
1072             hres = IStream_Read(stream, buf, sizeof(buf), &read);
1073         }while(hres == S_OK && read);
1074
1075         return S_OK;
1076     }
1077
1078     if(!This->nsstream)
1079         This->nsstream = create_nsprotocol_stream();
1080
1081     do {
1082         read = 0;
1083         hres = IStream_Read(stream, This->nsstream->buf+This->nsstream->buf_size,
1084                 sizeof(This->nsstream->buf)-This->nsstream->buf_size, &read);
1085         if(!read)
1086             break;
1087
1088         This->nsstream->buf_size += read;
1089
1090         if(!This->bsc.readed) {
1091             if(This->nsstream->buf_size >= 2
1092                && (BYTE)This->nsstream->buf[0] == 0xff
1093                && (BYTE)This->nsstream->buf[1] == 0xfe)
1094                 This->nschannel->charset = heap_strdupA(UTF16_STR);
1095
1096             if(!This->nschannel->content_type) {
1097                 WCHAR *mime;
1098
1099                 hres = FindMimeFromData(NULL, NULL, This->nsstream->buf, This->nsstream->buf_size,
1100                         This->window ? mimeTextHtml : NULL, 0, &mime, 0);
1101                 if(FAILED(hres))
1102                     return hres;
1103
1104                 TRACE("Found MIME %s\n", debugstr_w(mime));
1105
1106                 This->nschannel->content_type = heap_strdupWtoA(mime);
1107                 CoTaskMemFree(mime);
1108                 if(!This->nschannel->content_type)
1109                     return E_OUTOFMEMORY;
1110             }
1111
1112             on_start_nsrequest(This);
1113         }
1114
1115         This->bsc.readed += This->nsstream->buf_size;
1116
1117         nsres = nsIStreamListener_OnDataAvailable(This->nslistener,
1118                 (nsIRequest*)&This->nschannel->nsIHttpChannel_iface, This->nscontext,
1119                 &This->nsstream->nsIInputStream_iface, This->bsc.readed-This->nsstream->buf_size,
1120                 This->nsstream->buf_size);
1121         if(NS_FAILED(nsres))
1122             ERR("OnDataAvailable failed: %08x\n", nsres);
1123
1124         if(This->nsstream->buf_size == sizeof(This->nsstream->buf)) {
1125             ERR("buffer is full\n");
1126             break;
1127         }
1128     }while(hres == S_OK);
1129
1130     return S_OK;
1131 }
1132
1133 typedef struct {
1134     nsIAsyncVerifyRedirectCallback nsIAsyncVerifyRedirectCallback_iface;
1135
1136     LONG ref;
1137
1138     nsChannel *nschannel;
1139     nsChannelBSC *bsc;
1140 } nsRedirectCallback;
1141
1142 static nsRedirectCallback *impl_from_nsIAsyncVerifyRedirectCallback(nsIAsyncVerifyRedirectCallback *iface)
1143 {
1144     return CONTAINING_RECORD(iface, nsRedirectCallback, nsIAsyncVerifyRedirectCallback_iface);
1145 }
1146
1147 static nsresult NSAPI nsAsyncVerifyRedirectCallback_QueryInterface(nsIAsyncVerifyRedirectCallback *iface,
1148         nsIIDRef riid, void **result)
1149 {
1150     nsRedirectCallback *This = impl_from_nsIAsyncVerifyRedirectCallback(iface);
1151
1152     if(IsEqualGUID(&IID_nsISupports, riid)) {
1153         TRACE("(%p)->(IID_nsISuports %p)\n", This, result);
1154         *result = &This->nsIAsyncVerifyRedirectCallback_iface;
1155     }else if(IsEqualGUID(&IID_nsIAsyncVerifyRedirectCallback, riid)) {
1156         TRACE("(%p)->(IID_nsIAsyncVerifyRedirectCallback %p)\n", This, result);
1157         *result = &This->nsIAsyncVerifyRedirectCallback_iface;
1158     }else {
1159         *result = NULL;
1160         WARN("unimplemented iface %s\n", debugstr_guid(riid));
1161         return NS_NOINTERFACE;
1162     }
1163
1164     nsISupports_AddRef((nsISupports*)*result);
1165     return NS_OK;
1166 }
1167
1168 static nsrefcnt NSAPI nsAsyncVerifyRedirectCallback_AddRef(nsIAsyncVerifyRedirectCallback *iface)
1169 {
1170     nsRedirectCallback *This = impl_from_nsIAsyncVerifyRedirectCallback(iface);
1171     LONG ref = InterlockedIncrement(&This->ref);
1172
1173     TRACE("(%p) ref=%d\n", This, ref);
1174
1175     return ref;
1176 }
1177
1178 static nsrefcnt NSAPI nsAsyncVerifyRedirectCallback_Release(nsIAsyncVerifyRedirectCallback *iface)
1179 {
1180     nsRedirectCallback *This = impl_from_nsIAsyncVerifyRedirectCallback(iface);
1181     LONG ref = InterlockedDecrement(&This->ref);
1182
1183     TRACE("(%p) ref=%d\n", This, ref);
1184
1185     if(!ref) {
1186         IBindStatusCallback_Release(&This->bsc->bsc.IBindStatusCallback_iface);
1187         nsIChannel_Release(&This->nschannel->nsIHttpChannel_iface);
1188         heap_free(This);
1189     }
1190
1191     return ref;
1192 }
1193
1194 static nsresult NSAPI nsAsyncVerifyRedirectCallback_AsyncOnChannelRedirect(nsIAsyncVerifyRedirectCallback *iface, nsresult result)
1195 {
1196     nsRedirectCallback *This = impl_from_nsIAsyncVerifyRedirectCallback(iface);
1197
1198     TRACE("(%p)->(%08x)\n", This, result);
1199
1200     if(This->bsc->nschannel)
1201         nsIHttpChannel_Release(&This->bsc->nschannel->nsIHttpChannel_iface);
1202     nsIChannel_AddRef(&This->nschannel->nsIHttpChannel_iface);
1203     This->bsc->nschannel = This->nschannel;
1204
1205     if(This->nschannel->load_group) {
1206         nsresult nsres;
1207
1208         nsres = nsILoadGroup_AddRequest(This->nschannel->load_group, (nsIRequest*)&This->nschannel->nsIHttpChannel_iface,
1209                 NULL);
1210         if(NS_FAILED(nsres))
1211             ERR("AddRequest failed: %08x\n", nsres);
1212     }
1213
1214     if(This->bsc->window) {
1215         IUri *uri = nsuri_get_uri(This->nschannel->uri);
1216
1217         if(uri) {
1218             set_current_uri(This->bsc->window, uri);
1219             IUri_Release(uri);
1220         }else {
1221             WARN("Could not get IUri from nsWineURI\n");
1222         }
1223     }
1224
1225     return NS_OK;
1226 }
1227
1228 static const nsIAsyncVerifyRedirectCallbackVtbl nsAsyncVerifyRedirectCallbackVtbl = {
1229     nsAsyncVerifyRedirectCallback_QueryInterface,
1230     nsAsyncVerifyRedirectCallback_AddRef,
1231     nsAsyncVerifyRedirectCallback_Release,
1232     nsAsyncVerifyRedirectCallback_AsyncOnChannelRedirect
1233 };
1234
1235 static HRESULT create_redirect_callback(nsChannel *nschannel, nsChannelBSC *bsc, nsRedirectCallback **ret)
1236 {
1237     nsRedirectCallback *callback;
1238
1239     callback = heap_alloc(sizeof(*callback));
1240     if(!callback)
1241         return E_OUTOFMEMORY;
1242
1243     callback->nsIAsyncVerifyRedirectCallback_iface.lpVtbl = &nsAsyncVerifyRedirectCallbackVtbl;
1244     callback->ref = 1;
1245
1246     nsIChannel_AddRef(&nschannel->nsIHttpChannel_iface);
1247     callback->nschannel = nschannel;
1248
1249     IBindStatusCallback_AddRef(&bsc->bsc.IBindStatusCallback_iface);
1250     callback->bsc = bsc;
1251
1252     *ret = callback;
1253     return S_OK;
1254 }
1255
1256 static inline nsChannelBSC *nsChannelBSC_from_BSCallback(BSCallback *iface)
1257 {
1258     return CONTAINING_RECORD(iface, nsChannelBSC, bsc);
1259 }
1260
1261 static void nsChannelBSC_destroy(BSCallback *bsc)
1262 {
1263     nsChannelBSC *This = nsChannelBSC_from_BSCallback(bsc);
1264
1265     if(This->nschannel)
1266         nsIChannel_Release(&This->nschannel->nsIHttpChannel_iface);
1267     if(This->nslistener)
1268         nsIStreamListener_Release(This->nslistener);
1269     if(This->nscontext)
1270         nsISupports_Release(This->nscontext);
1271     if(This->nsstream)
1272         nsIInputStream_Release(&This->nsstream->nsIInputStream_iface);
1273     heap_free(This);
1274 }
1275
1276 static HRESULT nsChannelBSC_start_binding(BSCallback *bsc)
1277 {
1278     nsChannelBSC *This = nsChannelBSC_from_BSCallback(bsc);
1279
1280     if(This->window)
1281         This->window->doc->skip_mutation_notif = FALSE;
1282
1283     return S_OK;
1284 }
1285
1286 static HRESULT nsChannelBSC_init_bindinfo(BSCallback *bsc)
1287 {
1288     nsChannelBSC *This = nsChannelBSC_from_BSCallback(bsc);
1289     HRESULT hres;
1290
1291     if(This->nschannel && This->nschannel->post_data_stream) {
1292         hres = read_post_data_stream(This, This->nschannel);
1293         if(FAILED(hres))
1294             return hres;
1295     }
1296
1297     return S_OK;
1298 }
1299
1300 typedef struct {
1301     task_t header;
1302     nsChannelBSC *bsc;
1303 } stop_request_task_t;
1304
1305 static void stop_request_proc(task_t *_task)
1306 {
1307     stop_request_task_t *task = (stop_request_task_t*)_task;
1308
1309     TRACE("(%p)\n", task->bsc);
1310
1311     list_remove(&task->bsc->bsc.entry);
1312     list_init(&task->bsc->bsc.entry);
1313     on_stop_nsrequest(task->bsc, S_OK);
1314 }
1315
1316 static void stop_request_task_destr(task_t *_task)
1317 {
1318     stop_request_task_t *task = (stop_request_task_t*)_task;
1319
1320     IBindStatusCallback_Release(&task->bsc->bsc.IBindStatusCallback_iface);
1321     heap_free(task);
1322 }
1323
1324 static HRESULT async_stop_request(nsChannelBSC *This)
1325 {
1326     stop_request_task_t *task;
1327
1328     if(!This->bsc.readed) {
1329         TRACE("No data read, calling OnStartRequest\n");
1330         on_start_nsrequest(This);
1331     }
1332
1333     task = heap_alloc(sizeof(*task));
1334     if(!task)
1335         return E_OUTOFMEMORY;
1336
1337     IBindStatusCallback_AddRef(&This->bsc.IBindStatusCallback_iface);
1338     task->bsc = This;
1339     push_task(&task->header, stop_request_proc, stop_request_task_destr, This->bsc.doc->basedoc.doc_obj->basedoc.task_magic);
1340     return S_OK;
1341 }
1342
1343 static void handle_navigation_error(nsChannelBSC *This, DWORD result)
1344 {
1345     HTMLDocumentObj *doc;
1346     IOleCommandTarget *olecmd;
1347     BOOL is_error_url;
1348     SAFEARRAY *sa;
1349     SAFEARRAYBOUND bound;
1350     VARIANT var, varOut;
1351     LONG ind;
1352     BSTR unk;
1353     HRESULT hres;
1354
1355     if(!This->window)
1356         return;
1357
1358     doc = This->window->doc_obj;
1359     if(!doc || !doc->doc_object_service || !doc->client)
1360         return;
1361
1362     hres = IDocObjectService_IsErrorUrl(doc->doc_object_service,
1363             This->window->url, &is_error_url);
1364     if(FAILED(hres) || is_error_url)
1365         return;
1366
1367     hres = IOleClientSite_QueryInterface(doc->client,
1368             &IID_IOleCommandTarget, (void**)&olecmd);
1369     if(FAILED(hres))
1370         return;
1371
1372     bound.lLbound = 0;
1373     bound.cElements = 8;
1374     sa = SafeArrayCreate(VT_VARIANT, 1, &bound);
1375     if(!sa) {
1376         IOleCommandTarget_Release(olecmd);
1377         return;
1378     }
1379
1380     ind = 0;
1381     V_VT(&var) = VT_I4;
1382     V_I4(&var) = result;
1383     SafeArrayPutElement(sa, &ind, &var);
1384
1385     ind = 1;
1386     V_VT(&var) = VT_BSTR;
1387     V_BSTR(&var) = This->window->url;
1388     SafeArrayPutElement(sa, &ind, &var);
1389
1390     ind = 3;
1391     V_VT(&var) = VT_UNKNOWN;
1392     V_UNKNOWN(&var) = (IUnknown*)&This->window->IHTMLWindow2_iface;
1393     SafeArrayPutElement(sa, &ind, &var);
1394
1395     /* FIXME: what are the following fields for? */
1396     ind = 2;
1397     V_VT(&var) = VT_UNKNOWN;
1398     V_UNKNOWN(&var) = NULL;
1399     SafeArrayPutElement(sa, &ind, &var);
1400
1401     ind = 4;
1402     V_VT(&var) = VT_BOOL;
1403     V_BOOL(&var) = FALSE;
1404     SafeArrayPutElement(sa, &ind, &var);
1405
1406     ind = 5;
1407     V_VT(&var) = VT_BOOL;
1408     V_BOOL(&var) = FALSE;
1409     SafeArrayPutElement(sa, &ind, &var);
1410
1411     ind = 6;
1412     V_VT(&var) = VT_BSTR;
1413     unk = SysAllocString(NULL);
1414     V_BSTR(&var) = unk;
1415     SafeArrayPutElement(sa, &ind, &var);
1416
1417     ind = 7;
1418     V_VT(&var) = VT_UNKNOWN;
1419     V_UNKNOWN(&var) = NULL;
1420     SafeArrayPutElement(sa, &ind, &var);
1421
1422     V_VT(&var) = VT_ARRAY;
1423     V_ARRAY(&var) = sa;
1424     V_VT(&varOut) = VT_BOOL;
1425     V_BOOL(&varOut) = VARIANT_TRUE;
1426     IOleCommandTarget_Exec(olecmd, &CGID_DocHostCmdPriv, 1, 0, &var, FAILED(hres)?NULL:&varOut);
1427
1428     SysFreeString(unk);
1429     SafeArrayDestroy(sa);
1430     IOleCommandTarget_Release(olecmd);
1431 }
1432
1433 static HRESULT nsChannelBSC_stop_binding(BSCallback *bsc, HRESULT result)
1434 {
1435     nsChannelBSC *This = nsChannelBSC_from_BSCallback(bsc);
1436
1437     if(result != E_ABORT) {
1438         if(FAILED(result))
1439             handle_navigation_error(This, result);
1440         else if(This->window) {
1441             result = async_stop_request(This);
1442             if(SUCCEEDED(result))
1443                 return S_OK;
1444         }
1445     }
1446
1447     on_stop_nsrequest(This, result);
1448     return S_OK;
1449 }
1450
1451 static HRESULT nsChannelBSC_read_data(BSCallback *bsc, IStream *stream)
1452 {
1453     nsChannelBSC *This = nsChannelBSC_from_BSCallback(bsc);
1454
1455     return read_stream_data(This, stream);
1456 }
1457
1458 static HRESULT handle_redirect(nsChannelBSC *This, const WCHAR *new_url)
1459 {
1460     nsRedirectCallback *callback;
1461     nsIChannelEventSink *sink;
1462     nsChannel *new_channel;
1463     nsresult nsres;
1464     HRESULT hres;
1465
1466     TRACE("(%p)->(%s)\n", This, debugstr_w(new_url));
1467
1468     if(!This->nschannel || !This->nschannel->notif_callback)
1469         return S_OK;
1470
1471     nsres = nsIInterfaceRequestor_GetInterface(This->nschannel->notif_callback, &IID_nsIChannelEventSink, (void**)&sink);
1472     if(NS_FAILED(nsres))
1473         return S_OK;
1474
1475     hres = create_redirect_nschannel(new_url, This->nschannel, &new_channel);
1476     if(SUCCEEDED(hres)) {
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(HTMLWindow *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     HTMLWindow *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(HTMLWindow *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     HTMLWindow *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     HTMLWindow *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     HTMLWindow *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(HTMLWindow *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->IHTMLWindow2_iface, 0x10);
1889         IDocObjectService_FireDocumentComplete(window->doc_obj->doc_object_service, &window->IHTMLWindow2_iface, 0);
1890
1891     }
1892
1893     return S_OK;
1894 }
1895
1896 HRESULT super_navigate(HTMLWindow *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         task->window = window;
1958         task->bscallback = bsc;
1959         task->mon = mon;
1960         push_task(&task->header, navigate_proc, navigate_task_destr, window->task_magic);
1961
1962         /* Silently and repeated when real loading starts? */
1963         window->readystate = READYSTATE_LOADING;
1964     }else {
1965         navigate_javascript_task_t *task;
1966
1967         IUnknown_Release((IUnknown*)bsc);
1968         IMoniker_Release(mon);
1969
1970         task = heap_alloc(sizeof(*task));
1971         if(!task)
1972             return E_OUTOFMEMORY;
1973
1974         IUri_AddRef(uri);
1975         task->window = window;
1976         task->uri = uri;
1977         push_task(&task->header, navigate_javascript_proc, navigate_javascript_task_destr, window->task_magic);
1978
1979         /* Why silently? */
1980         window->readystate = READYSTATE_COMPLETE;
1981     }
1982
1983     return S_OK;
1984 }
1985
1986 HRESULT navigate_new_window(HTMLWindow *window, IUri *uri, const WCHAR *name, IHTMLWindow2 **ret)
1987 {
1988     IWebBrowser2 *web_browser;
1989     IHTMLWindow2 *new_window;
1990     IBindCtx *bind_ctx;
1991     nsChannelBSC *bsc;
1992     HRESULT hres;
1993
1994     hres = create_channelbsc(NULL, NULL, NULL, 0, &bsc);
1995     if(FAILED(hres))
1996         return hres;
1997
1998     hres = CreateAsyncBindCtx(0, &bsc->bsc.IBindStatusCallback_iface, NULL, &bind_ctx);
1999     if(FAILED(hres)) {
2000         IBindStatusCallback_Release(&bsc->bsc.IBindStatusCallback_iface);
2001         return hres;
2002     }
2003
2004     hres = CoCreateInstance(&CLSID_InternetExplorer, NULL, CLSCTX_LOCAL_SERVER,
2005             &IID_IWebBrowser2, (void**)&web_browser);
2006     if(SUCCEEDED(hres)) {
2007         ITargetFramePriv2 *target_frame_priv;
2008
2009         hres = IWebBrowser_QueryInterface(web_browser, &IID_ITargetFramePriv2, (void**)&target_frame_priv);
2010         if(SUCCEEDED(hres)) {
2011             hres = ITargetFramePriv2_AggregatedNavigation2(target_frame_priv,
2012                     HLNF_DISABLEWINDOWRESTRICTIONS|HLNF_OPENINNEWWINDOW, bind_ctx, &bsc->bsc.IBindStatusCallback_iface,
2013                     name, uri, emptyW);
2014             ITargetFramePriv2_Release(target_frame_priv);
2015
2016             if(SUCCEEDED(hres))
2017                 hres = do_query_service((IUnknown*)web_browser, &SID_SHTMLWindow, &IID_IHTMLWindow2, (void**)&new_window);
2018         }
2019         if(FAILED(hres)) {
2020             IWebBrowser2_Quit(web_browser);
2021             IWebBrowser2_Release(web_browser);
2022         }
2023     }else {
2024         WARN("Could not create InternetExplorer instance: %08x\n", hres);
2025     }
2026
2027     IBindStatusCallback_Release(&bsc->bsc.IBindStatusCallback_iface);
2028     IBindCtx_Release(bind_ctx);
2029     if(FAILED(hres))
2030         return hres;
2031
2032     IWebBrowser2_put_Visible(web_browser, VARIANT_TRUE);
2033     IWebBrowser2_Release(web_browser);
2034
2035     if(ret)
2036         *ret = new_window;
2037     else
2038         IHTMLWindow2_Release(new_window);
2039     return S_OK;
2040 }
2041
2042 HRESULT hlink_frame_navigate(HTMLDocument *doc, LPCWSTR url, nsChannel *nschannel, DWORD hlnf, BOOL *cancel)
2043 {
2044     IHlinkFrame *hlink_frame;
2045     nsChannelBSC *callback;
2046     IBindCtx *bindctx;
2047     IMoniker *mon;
2048     IHlink *hlink;
2049     HRESULT hres;
2050
2051     *cancel = FALSE;
2052
2053     hres = do_query_service((IUnknown*)doc->doc_obj->client, &IID_IHlinkFrame, &IID_IHlinkFrame,
2054             (void**)&hlink_frame);
2055     if(FAILED(hres))
2056         return S_OK;
2057
2058     hres = create_channelbsc(NULL, NULL, NULL, 0, &callback);
2059     if(FAILED(hres)) {
2060         IHlinkFrame_Release(hlink_frame);
2061         return hres;
2062     }
2063
2064     if(nschannel)
2065         read_post_data_stream(callback, nschannel);
2066
2067     hres = CreateAsyncBindCtx(0, &callback->bsc.IBindStatusCallback_iface, NULL, &bindctx);
2068     if(SUCCEEDED(hres))
2069         hres = CoCreateInstance(&CLSID_StdHlink, NULL, CLSCTX_INPROC_SERVER,
2070                 &IID_IHlink, (LPVOID*)&hlink);
2071
2072     if(SUCCEEDED(hres))
2073         hres = CreateURLMoniker(NULL, url, &mon);
2074
2075     if(SUCCEEDED(hres)) {
2076         IHlink_SetMonikerReference(hlink, HLINKSETF_TARGET, mon, NULL);
2077
2078         if(hlnf & HLNF_OPENINNEWWINDOW) {
2079             static const WCHAR wszBlank[] = {'_','b','l','a','n','k',0};
2080             IHlink_SetTargetFrameName(hlink, wszBlank); /* FIXME */
2081         }
2082
2083         hres = IHlinkFrame_Navigate(hlink_frame, hlnf, bindctx,
2084                 &callback->bsc.IBindStatusCallback_iface, hlink);
2085         IMoniker_Release(mon);
2086         *cancel = hres == S_OK;
2087         hres = S_OK;
2088     }
2089
2090     IHlinkFrame_Release(hlink_frame);
2091     IBindCtx_Release(bindctx);
2092     IBindStatusCallback_Release(&callback->bsc.IBindStatusCallback_iface);
2093     return hres;
2094 }
2095
2096 HRESULT navigate_url(HTMLWindow *window, const WCHAR *new_url, const WCHAR *base_url)
2097 {
2098     WCHAR url[INTERNET_MAX_URL_LENGTH];
2099     nsWineURI *uri;
2100     HRESULT hres;
2101
2102     if(!new_url) {
2103         *url = 0;
2104     }else if(base_url) {
2105         DWORD len = 0;
2106
2107         hres = CoInternetCombineUrl(base_url, new_url, URL_ESCAPE_SPACES_ONLY|URL_DONT_ESCAPE_EXTRA_INFO,
2108                 url, sizeof(url)/sizeof(WCHAR), &len, 0);
2109         if(FAILED(hres))
2110             return hres;
2111     }else {
2112         strcpyW(url, new_url);
2113     }
2114
2115     if(window->doc_obj && window->doc_obj->hostui) {
2116         OLECHAR *translated_url = NULL;
2117
2118         hres = IDocHostUIHandler_TranslateUrl(window->doc_obj->hostui, 0, url,
2119                 &translated_url);
2120         if(hres == S_OK) {
2121             TRACE("%08x %s -> %s\n", hres, debugstr_w(url), debugstr_w(translated_url));
2122             strcpyW(url, translated_url);
2123             CoTaskMemFree(translated_url);
2124         }
2125     }
2126
2127     if(window->doc_obj && window->doc_obj->is_webbrowser && window == window->doc_obj->basedoc.window) {
2128         BOOL cancel = FALSE;
2129         IUri *uri;
2130
2131         hres = IDocObjectService_FireBeforeNavigate2(window->doc_obj->doc_object_service, NULL, url, 0x40,
2132                 NULL, NULL, 0, NULL, TRUE, &cancel);
2133         if(SUCCEEDED(hres) && cancel) {
2134             TRACE("Navigation canceled\n");
2135             return S_OK;
2136         }
2137
2138         hres = CreateUri(url, 0, 0, &uri);
2139         if(FAILED(hres))
2140             return hres;
2141
2142         hres = super_navigate(window, uri, NULL, NULL, 0);
2143         IUri_Release(uri);
2144         return hres;
2145     }
2146
2147     if(window->doc_obj && window == window->doc_obj->basedoc.window) {
2148         BOOL cancel;
2149
2150         hres = hlink_frame_navigate(&window->doc->basedoc, url, NULL, 0, &cancel);
2151         if(FAILED(hres))
2152             return hres;
2153
2154         if(cancel) {
2155             TRACE("Navigation handled by hlink frame\n");
2156             return S_OK;
2157         }
2158     }
2159
2160     hres = create_doc_uri(window, url, &uri);
2161     if(FAILED(hres))
2162         return hres;
2163
2164     hres = load_nsuri(window, uri, NULL, LOAD_FLAGS_NONE);
2165     nsISupports_Release((nsISupports*)uri);
2166     return hres;
2167 }