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