Release 1.4.1.
[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, PRBool *_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 /* Calls undocumented 84 cmd of CGID_ShellDocView */
614 static void call_docview_84(HTMLDocumentObj *doc)
615 {
616     IOleCommandTarget *olecmd;
617     VARIANT var;
618     HRESULT hres;
619
620     if(!doc->client)
621         return;
622
623     hres = IOleClientSite_QueryInterface(doc->client, &IID_IOleCommandTarget, (void**)&olecmd);
624     if(FAILED(hres))
625         return;
626
627     VariantInit(&var);
628     hres = IOleCommandTarget_Exec(olecmd, &CGID_ShellDocView, 84, 0, NULL, &var);
629     IOleCommandTarget_Release(olecmd);
630     if(SUCCEEDED(hres) && V_VT(&var) != VT_NULL)
631         FIXME("handle result\n");
632 }
633
634 static void parse_content_type(nsChannelBSC *This, const WCHAR *value)
635 {
636     const WCHAR *ptr;
637     size_t len;
638
639     static const WCHAR charsetW[] = {'c','h','a','r','s','e','t','='};
640
641     ptr = strchrW(value, ';');
642     if(!ptr)
643         return;
644
645     ptr++;
646     while(*ptr && isspaceW(*ptr))
647         ptr++;
648
649     len = strlenW(value);
650     if(ptr + sizeof(charsetW)/sizeof(WCHAR) < value+len && !memicmpW(ptr, charsetW, sizeof(charsetW)/sizeof(WCHAR))) {
651         size_t charset_len, lena;
652         nsACString charset_str;
653         const WCHAR *charset;
654         char *charseta;
655
656         ptr += sizeof(charsetW)/sizeof(WCHAR);
657
658         if(*ptr == '\'') {
659             FIXME("Quoted value\n");
660             return;
661         }else {
662             charset = ptr;
663             while(*ptr && *ptr != ',')
664                 ptr++;
665             charset_len = ptr-charset;
666         }
667
668         lena = WideCharToMultiByte(CP_ACP, 0, charset, charset_len, NULL, 0, NULL, NULL);
669         charseta = heap_alloc(lena+1);
670         if(!charseta)
671             return;
672
673         WideCharToMultiByte(CP_ACP, 0, charset, charset_len, charseta, lena, NULL, NULL);
674         charseta[lena] = 0;
675
676         nsACString_InitDepend(&charset_str, charseta);
677         nsIHttpChannel_SetContentCharset(&This->nschannel->nsIHttpChannel_iface, &charset_str);
678         nsACString_Finish(&charset_str);
679         heap_free(charseta);
680     }else {
681         FIXME("unhandled: %s\n", debugstr_wn(ptr, len - (ptr-value)));
682     }
683 }
684
685 static HRESULT parse_headers(const WCHAR *headers, struct list *headers_list)
686 {
687     const WCHAR *header, *header_end, *colon, *value;
688     HRESULT hres;
689
690     header = headers;
691     while(*header) {
692         if(header[0] == '\r' && header[1] == '\n' && !header[2])
693             break;
694         for(colon = header; *colon && *colon != ':' && *colon != '\r'; colon++);
695         if(*colon != ':')
696             return E_FAIL;
697
698         value = colon+1;
699         while(*value == ' ')
700             value++;
701         if(!*value)
702             return E_FAIL;
703
704         for(header_end = value+1; *header_end && *header_end != '\r'; header_end++);
705
706         hres = set_http_header(headers_list, header, colon-header, value, header_end-value);
707         if(FAILED(hres))
708             return hres;
709
710         header = header_end;
711         if(header[0] == '\r' && header[1] == '\n')
712             header += 2;
713     }
714
715     return S_OK;
716 }
717
718 static HRESULT process_response_headers(nsChannelBSC *This, const WCHAR *headers)
719 {
720     http_header_t *iter;
721     HRESULT hres;
722
723     static const WCHAR content_typeW[] = {'c','o','n','t','e','n','t','-','t','y','p','e',0};
724
725     hres = parse_headers(headers, &This->nschannel->response_headers);
726     if(FAILED(hres))
727         return hres;
728
729     LIST_FOR_EACH_ENTRY(iter, &This->nschannel->response_headers, http_header_t, entry) {
730         if(!strcmpiW(iter->header, content_typeW))
731             parse_content_type(This, iter->data);
732     }
733
734     return S_OK;
735 }
736
737 HRESULT start_binding(HTMLWindow *window, HTMLDocumentNode *doc, BSCallback *bscallback, IBindCtx *bctx)
738 {
739     IStream *str = NULL;
740     HRESULT hres;
741
742     TRACE("(%p %p %p %p)\n", window, doc, bscallback, bctx);
743
744     bscallback->doc = doc;
745
746     /* NOTE: IE7 calls IsSystemMoniker here*/
747
748     if(window) {
749         if(bscallback->mon != window->mon)
750             set_current_mon(window, bscallback->mon);
751         call_docview_84(window->doc_obj);
752     }
753
754     if(bctx) {
755         RegisterBindStatusCallback(bctx, &bscallback->IBindStatusCallback_iface, NULL, 0);
756         IBindCtx_AddRef(bctx);
757     }else {
758         hres = CreateAsyncBindCtx(0, &bscallback->IBindStatusCallback_iface, NULL, &bctx);
759         if(FAILED(hres)) {
760             WARN("CreateAsyncBindCtx failed: %08x\n", hres);
761             bscallback->vtbl->stop_binding(bscallback, hres);
762             return hres;
763         }
764     }
765
766     hres = IMoniker_BindToStorage(bscallback->mon, bctx, NULL, &IID_IStream, (void**)&str);
767     IBindCtx_Release(bctx);
768     if(FAILED(hres)) {
769         WARN("BindToStorage failed: %08x\n", hres);
770         bscallback->vtbl->stop_binding(bscallback, hres);
771         return hres;
772     }
773
774     if(str)
775         IStream_Release(str);
776
777     IMoniker_Release(bscallback->mon);
778     bscallback->mon = NULL;
779
780     return S_OK;
781 }
782
783 typedef struct {
784     BSCallback bsc;
785
786     DWORD size;
787     BYTE *buf;
788     HRESULT hres;
789 } BufferBSC;
790
791 static inline BufferBSC *BufferBSC_from_BSCallback(BSCallback *iface)
792 {
793     return CONTAINING_RECORD(iface, BufferBSC, bsc);
794 }
795
796 static void BufferBSC_destroy(BSCallback *bsc)
797 {
798     BufferBSC *This = BufferBSC_from_BSCallback(bsc);
799
800     heap_free(This->buf);
801     heap_free(This);
802 }
803
804 static HRESULT BufferBSC_init_bindinfo(BSCallback *bsc)
805 {
806     return S_OK;
807 }
808
809 static HRESULT BufferBSC_start_binding(BSCallback *bsc)
810 {
811     return S_OK;
812 }
813
814 static HRESULT BufferBSC_stop_binding(BSCallback *bsc, HRESULT result)
815 {
816     BufferBSC *This = BufferBSC_from_BSCallback(bsc);
817
818     This->hres = result;
819
820     if(FAILED(result)) {
821         heap_free(This->buf);
822         This->buf = NULL;
823         This->size = 0;
824     }
825
826     return S_OK;
827 }
828
829 static HRESULT BufferBSC_read_data(BSCallback *bsc, IStream *stream)
830 {
831     BufferBSC *This = BufferBSC_from_BSCallback(bsc);
832     DWORD readed;
833     HRESULT hres;
834
835     if(!This->buf) {
836         This->size = 128;
837         This->buf = heap_alloc(This->size);
838     }
839
840     do {
841         if(This->bsc.readed == This->size) {
842             This->size <<= 1;
843             This->buf = heap_realloc(This->buf, This->size);
844         }
845
846         readed = 0;
847         hres = IStream_Read(stream, This->buf+This->bsc.readed, This->size-This->bsc.readed, &readed);
848         This->bsc.readed += readed;
849     }while(hres == S_OK);
850
851     return S_OK;
852 }
853
854 static HRESULT BufferBSC_on_progress(BSCallback *bsc, ULONG status_code, LPCWSTR status_text)
855 {
856     return S_OK;
857 }
858
859 static HRESULT BufferBSC_on_response(BSCallback *bsc, DWORD response_code,
860         LPCWSTR response_headers)
861 {
862     return S_OK;
863 }
864
865 static HRESULT BufferBSC_beginning_transaction(BSCallback *bsc, WCHAR **additional_headers)
866 {
867     return S_FALSE;
868 }
869
870 static const BSCallbackVtbl BufferBSCVtbl = {
871     BufferBSC_destroy,
872     BufferBSC_init_bindinfo,
873     BufferBSC_start_binding,
874     BufferBSC_stop_binding,
875     BufferBSC_read_data,
876     BufferBSC_on_progress,
877     BufferBSC_on_response,
878     BufferBSC_beginning_transaction
879 };
880
881
882 static BufferBSC *create_bufferbsc(IMoniker *mon)
883 {
884     BufferBSC *ret = heap_alloc_zero(sizeof(*ret));
885
886     init_bscallback(&ret->bsc, &BufferBSCVtbl, mon, 0);
887     ret->hres = E_FAIL;
888
889     return ret;
890 }
891
892 HRESULT bind_mon_to_buffer(HTMLDocumentNode *doc, IMoniker *mon, void **buf, DWORD *size)
893 {
894     BufferBSC *bsc = create_bufferbsc(mon);
895     HRESULT hres;
896
897     *buf = NULL;
898
899     hres = start_binding(NULL, doc, &bsc->bsc, NULL);
900     if(SUCCEEDED(hres)) {
901         hres = bsc->hres;
902         if(SUCCEEDED(hres)) {
903             *buf = bsc->buf;
904             bsc->buf = NULL;
905             *size = bsc->bsc.readed;
906             bsc->size = 0;
907         }
908     }
909
910     IBindStatusCallback_Release(&bsc->bsc.IBindStatusCallback_iface);
911
912     return hres;
913 }
914
915 static HRESULT read_post_data_stream(nsChannelBSC *This, nsChannel *nschannel)
916 {
917     PRUint32 data_len = 0, available = 0;
918     char *data, *post_data;
919     nsresult nsres;
920     HRESULT hres = S_OK;
921
922     if(!nschannel->post_data_stream)
923         return S_OK;
924
925     nsres =  nsIInputStream_Available(nschannel->post_data_stream, &available);
926     if(NS_FAILED(nsres))
927         return E_FAIL;
928
929     post_data = data = GlobalAlloc(0, available);
930     if(!data)
931         return E_OUTOFMEMORY;
932
933     nsres = nsIInputStream_Read(nschannel->post_data_stream, data, available, &data_len);
934     if(NS_FAILED(nsres)) {
935         GlobalFree(data);
936         return E_FAIL;
937     }
938
939     if(nschannel->post_data_contains_headers) {
940         if(data_len >= 2 && data[0] == '\r' && data[1] == '\n') {
941             post_data = data+2;
942             data_len -= 2;
943         }else {
944             WCHAR *headers;
945             DWORD size;
946             char *ptr;
947
948             post_data += data_len;
949             for(ptr = data; ptr+4 < data+data_len; ptr++) {
950                 if(!memcmp(ptr, "\r\n\r\n", 4)) {
951                     post_data = ptr+4;
952                     break;
953                 }
954             }
955
956             data_len -= post_data-data;
957
958             size = MultiByteToWideChar(CP_ACP, 0, data, post_data-data, NULL, 0);
959             headers = heap_alloc((size+1)*sizeof(WCHAR));
960             if(headers) {
961                 MultiByteToWideChar(CP_ACP, 0, data, post_data-data, headers, size);
962                 headers[size] = 0;
963                 hres = parse_headers(headers , &nschannel->request_headers);
964                 if(SUCCEEDED(hres))
965                     This->bsc.headers = headers;
966                 else
967                     heap_free(headers);
968             }else {
969                 hres = E_OUTOFMEMORY;
970             }
971         }
972     }
973
974     if(FAILED(hres)) {
975         GlobalFree(data);
976         return hres;
977     }
978
979     if(!data_len) {
980         GlobalFree(data);
981         post_data = NULL;
982     }else if(post_data != data) {
983         char *new_data;
984
985         new_data = GlobalAlloc(0, data_len);
986         if(new_data)
987             memcpy(new_data, post_data, data_len);
988         GlobalFree(data);
989         if(!new_data)
990             return E_OUTOFMEMORY;
991         post_data = new_data;
992     }
993
994     This->bsc.post_data = post_data;
995     This->bsc.post_data_len = data_len;
996     TRACE("post_data = %s\n", debugstr_a(This->bsc.post_data));
997     return S_OK;
998 }
999
1000 static HRESULT on_start_nsrequest(nsChannelBSC *This)
1001 {
1002     nsresult nsres;
1003
1004     /* FIXME: it's needed for http connections from BindToObject. */
1005     if(!This->nschannel->response_status)
1006         This->nschannel->response_status = 200;
1007
1008     nsres = nsIStreamListener_OnStartRequest(This->nslistener,
1009             (nsIRequest*)&This->nschannel->nsIHttpChannel_iface, This->nscontext);
1010     if(NS_FAILED(nsres)) {
1011         FIXME("OnStartRequest failed: %08x\n", nsres);
1012         return E_FAIL;
1013     }
1014
1015     if(This->window) {
1016         list_remove(&This->bsc.entry);
1017         list_init(&This->bsc.entry);
1018         update_window_doc(This->window);
1019         if(This->window->doc != This->bsc.doc)
1020             This->bsc.doc = This->window->doc;
1021         list_add_head(&This->bsc.doc->bindings, &This->bsc.entry);
1022         if(This->window->readystate != READYSTATE_LOADING)
1023             set_ready_state(This->window, READYSTATE_LOADING);
1024     }
1025
1026     return S_OK;
1027 }
1028
1029 static void on_stop_nsrequest(nsChannelBSC *This, HRESULT result)
1030 {
1031     nsresult nsres, request_result;
1032
1033     switch(result) {
1034     case S_OK:
1035         request_result = NS_OK;
1036         break;
1037     case E_ABORT:
1038         request_result = NS_BINDING_ABORTED;
1039         break;
1040     default:
1041         request_result = NS_ERROR_FAILURE;
1042     }
1043
1044     if(This->nslistener) {
1045         nsres = nsIStreamListener_OnStopRequest(This->nslistener,
1046                  (nsIRequest*)&This->nschannel->nsIHttpChannel_iface, This->nscontext,
1047                  request_result);
1048         if(NS_FAILED(nsres))
1049             WARN("OnStopRequest failed: %08x\n", nsres);
1050     }
1051
1052     if(This->nschannel->load_group) {
1053         nsres = nsILoadGroup_RemoveRequest(This->nschannel->load_group,
1054                 (nsIRequest*)&This->nschannel->nsIHttpChannel_iface, NULL, request_result);
1055         if(NS_FAILED(nsres))
1056             ERR("RemoveRequest failed: %08x\n", nsres);
1057     }
1058 }
1059
1060 static HRESULT read_stream_data(nsChannelBSC *This, IStream *stream)
1061 {
1062     DWORD read;
1063     nsresult nsres;
1064     HRESULT hres;
1065
1066     if(!This->nslistener) {
1067         BYTE buf[1024];
1068
1069         do {
1070             read = 0;
1071             hres = IStream_Read(stream, buf, sizeof(buf), &read);
1072         }while(hres == S_OK && read);
1073
1074         return S_OK;
1075     }
1076
1077     if(!This->nsstream)
1078         This->nsstream = create_nsprotocol_stream();
1079
1080     do {
1081         read = 0;
1082         hres = IStream_Read(stream, This->nsstream->buf+This->nsstream->buf_size,
1083                 sizeof(This->nsstream->buf)-This->nsstream->buf_size, &read);
1084         if(!read)
1085             break;
1086
1087         This->nsstream->buf_size += read;
1088
1089         if(!This->bsc.readed) {
1090             if(This->nsstream->buf_size >= 2
1091                && (BYTE)This->nsstream->buf[0] == 0xff
1092                && (BYTE)This->nsstream->buf[1] == 0xfe)
1093                 This->nschannel->charset = heap_strdupA(UTF16_STR);
1094             if(This->nsstream->buf_size >= 3
1095                && (BYTE)This->nsstream->buf[0] == 0xef
1096                && (BYTE)This->nsstream->buf[1] == 0xbb
1097                && (BYTE)This->nsstream->buf[2] == 0xbf)
1098                 This->nschannel->charset = heap_strdupA(UTF8_STR);
1099
1100             if(!This->nschannel->content_type) {
1101                 WCHAR *mime;
1102
1103                 hres = FindMimeFromData(NULL, NULL, This->nsstream->buf, This->nsstream->buf_size, NULL, 0, &mime, 0);
1104                 if(FAILED(hres))
1105                     return hres;
1106
1107                 TRACE("Found MIME %s\n", debugstr_w(mime));
1108
1109                 This->nschannel->content_type = heap_strdupWtoA(mime);
1110                 CoTaskMemFree(mime);
1111                 if(!This->nschannel->content_type)
1112                     return E_OUTOFMEMORY;
1113             }
1114
1115             on_start_nsrequest(This);
1116         }
1117
1118         This->bsc.readed += This->nsstream->buf_size;
1119
1120         nsres = nsIStreamListener_OnDataAvailable(This->nslistener,
1121                 (nsIRequest*)&This->nschannel->nsIHttpChannel_iface, This->nscontext,
1122                 &This->nsstream->nsIInputStream_iface, This->bsc.readed-This->nsstream->buf_size,
1123                 This->nsstream->buf_size);
1124         if(NS_FAILED(nsres))
1125             ERR("OnDataAvailable failed: %08x\n", nsres);
1126
1127         if(This->nsstream->buf_size == sizeof(This->nsstream->buf)) {
1128             ERR("buffer is full\n");
1129             break;
1130         }
1131     }while(hres == S_OK);
1132
1133     return S_OK;
1134 }
1135
1136 typedef struct {
1137     nsIAsyncVerifyRedirectCallback nsIAsyncVerifyRedirectCallback_iface;
1138
1139     LONG ref;
1140
1141     nsChannel *nschannel;
1142     nsChannelBSC *bsc;
1143 } nsRedirectCallback;
1144
1145 static nsRedirectCallback *impl_from_nsIAsyncVerifyRedirectCallback(nsIAsyncVerifyRedirectCallback *iface)
1146 {
1147     return CONTAINING_RECORD(iface, nsRedirectCallback, nsIAsyncVerifyRedirectCallback_iface);
1148 }
1149
1150 static nsresult NSAPI nsAsyncVerifyRedirectCallback_QueryInterface(nsIAsyncVerifyRedirectCallback *iface,
1151         nsIIDRef riid, void **result)
1152 {
1153     nsRedirectCallback *This = impl_from_nsIAsyncVerifyRedirectCallback(iface);
1154
1155     if(IsEqualGUID(&IID_nsISupports, riid)) {
1156         TRACE("(%p)->(IID_nsISuports %p)\n", This, result);
1157         *result = &This->nsIAsyncVerifyRedirectCallback_iface;
1158     }else if(IsEqualGUID(&IID_nsIAsyncVerifyRedirectCallback, riid)) {
1159         TRACE("(%p)->(IID_nsIAsyncVerifyRedirectCallback %p)\n", This, result);
1160         *result = &This->nsIAsyncVerifyRedirectCallback_iface;
1161     }else {
1162         *result = NULL;
1163         WARN("unimplemented iface %s\n", debugstr_guid(riid));
1164         return NS_NOINTERFACE;
1165     }
1166
1167     nsISupports_AddRef((nsISupports*)*result);
1168     return NS_OK;
1169 }
1170
1171 static nsrefcnt NSAPI nsAsyncVerifyRedirectCallback_AddRef(nsIAsyncVerifyRedirectCallback *iface)
1172 {
1173     nsRedirectCallback *This = impl_from_nsIAsyncVerifyRedirectCallback(iface);
1174     LONG ref = InterlockedIncrement(&This->ref);
1175
1176     TRACE("(%p) ref=%d\n", This, ref);
1177
1178     return ref;
1179 }
1180
1181 static nsrefcnt NSAPI nsAsyncVerifyRedirectCallback_Release(nsIAsyncVerifyRedirectCallback *iface)
1182 {
1183     nsRedirectCallback *This = impl_from_nsIAsyncVerifyRedirectCallback(iface);
1184     LONG ref = InterlockedDecrement(&This->ref);
1185
1186     TRACE("(%p) ref=%d\n", This, ref);
1187
1188     if(!ref) {
1189         IBindStatusCallback_Release(&This->bsc->bsc.IBindStatusCallback_iface);
1190         nsIChannel_Release(&This->nschannel->nsIHttpChannel_iface);
1191         heap_free(This);
1192     }
1193
1194     return ref;
1195 }
1196
1197 static nsresult NSAPI nsAsyncVerifyRedirectCallback_AsyncOnChannelRedirect(nsIAsyncVerifyRedirectCallback *iface, nsresult result)
1198 {
1199     nsRedirectCallback *This = impl_from_nsIAsyncVerifyRedirectCallback(iface);
1200
1201     TRACE("(%p)->(%08x)\n", This, result);
1202
1203     if(This->bsc->nschannel)
1204         nsIHttpChannel_Release(&This->bsc->nschannel->nsIHttpChannel_iface);
1205     nsIChannel_AddRef(&This->nschannel->nsIHttpChannel_iface);
1206     This->bsc->nschannel = This->nschannel;
1207
1208     if(This->nschannel->load_group) {
1209         nsresult nsres;
1210
1211         nsres = nsILoadGroup_AddRequest(This->nschannel->load_group, (nsIRequest*)&This->nschannel->nsIHttpChannel_iface,
1212                 NULL);
1213         if(NS_FAILED(nsres))
1214             ERR("AddRequest failed: %08x\n", nsres);
1215     }
1216
1217     if(This->bsc->window) {
1218         IUri *uri = nsuri_get_uri(This->nschannel->uri);
1219
1220         if(uri) {
1221             set_current_uri(This->bsc->window, uri);
1222             IUri_Release(uri);
1223         }else {
1224             WARN("Could not get IUri from nsWineURI\n");
1225         }
1226     }
1227
1228     return NS_OK;
1229 }
1230
1231 static const nsIAsyncVerifyRedirectCallbackVtbl nsAsyncVerifyRedirectCallbackVtbl = {
1232     nsAsyncVerifyRedirectCallback_QueryInterface,
1233     nsAsyncVerifyRedirectCallback_AddRef,
1234     nsAsyncVerifyRedirectCallback_Release,
1235     nsAsyncVerifyRedirectCallback_AsyncOnChannelRedirect
1236 };
1237
1238 static HRESULT create_redirect_callback(nsChannel *nschannel, nsChannelBSC *bsc, nsRedirectCallback **ret)
1239 {
1240     nsRedirectCallback *callback;
1241
1242     callback = heap_alloc(sizeof(*callback));
1243     if(!callback)
1244         return E_OUTOFMEMORY;
1245
1246     callback->nsIAsyncVerifyRedirectCallback_iface.lpVtbl = &nsAsyncVerifyRedirectCallbackVtbl;
1247     callback->ref = 1;
1248
1249     nsIChannel_AddRef(&nschannel->nsIHttpChannel_iface);
1250     callback->nschannel = nschannel;
1251
1252     IBindStatusCallback_AddRef(&bsc->bsc.IBindStatusCallback_iface);
1253     callback->bsc = bsc;
1254
1255     *ret = callback;
1256     return S_OK;
1257 }
1258
1259 static inline nsChannelBSC *nsChannelBSC_from_BSCallback(BSCallback *iface)
1260 {
1261     return CONTAINING_RECORD(iface, nsChannelBSC, bsc);
1262 }
1263
1264 static void nsChannelBSC_destroy(BSCallback *bsc)
1265 {
1266     nsChannelBSC *This = nsChannelBSC_from_BSCallback(bsc);
1267
1268     if(This->nschannel)
1269         nsIChannel_Release(&This->nschannel->nsIHttpChannel_iface);
1270     if(This->nslistener)
1271         nsIStreamListener_Release(This->nslistener);
1272     if(This->nscontext)
1273         nsISupports_Release(This->nscontext);
1274     if(This->nsstream)
1275         nsIInputStream_Release(&This->nsstream->nsIInputStream_iface);
1276     heap_free(This);
1277 }
1278
1279 static HRESULT nsChannelBSC_start_binding(BSCallback *bsc)
1280 {
1281     nsChannelBSC *This = nsChannelBSC_from_BSCallback(bsc);
1282
1283     if(This->window)
1284         This->window->doc->skip_mutation_notif = FALSE;
1285
1286     return S_OK;
1287 }
1288
1289 static HRESULT nsChannelBSC_init_bindinfo(BSCallback *bsc)
1290 {
1291     nsChannelBSC *This = nsChannelBSC_from_BSCallback(bsc);
1292     HRESULT hres;
1293
1294     if(This->nschannel && This->nschannel->post_data_stream) {
1295         hres = read_post_data_stream(This, This->nschannel);
1296         if(FAILED(hres))
1297             return hres;
1298     }
1299
1300     return S_OK;
1301 }
1302
1303 typedef struct {
1304     task_t header;
1305     nsChannelBSC *bsc;
1306 } stop_request_task_t;
1307
1308 static void stop_request_proc(task_t *_task)
1309 {
1310     stop_request_task_t *task = (stop_request_task_t*)_task;
1311
1312     TRACE("(%p)\n", task->bsc);
1313
1314     list_remove(&task->bsc->bsc.entry);
1315     list_init(&task->bsc->bsc.entry);
1316     on_stop_nsrequest(task->bsc, S_OK);
1317 }
1318
1319 static void stop_request_task_destr(task_t *_task)
1320 {
1321     stop_request_task_t *task = (stop_request_task_t*)_task;
1322
1323     IBindStatusCallback_Release(&task->bsc->bsc.IBindStatusCallback_iface);
1324     heap_free(task);
1325 }
1326
1327 static HRESULT async_stop_request(nsChannelBSC *This)
1328 {
1329     stop_request_task_t *task;
1330
1331     if(!This->bsc.readed) {
1332         TRACE("No data read, calling OnStartRequest\n");
1333         on_start_nsrequest(This);
1334     }
1335
1336     task = heap_alloc(sizeof(*task));
1337     if(!task)
1338         return E_OUTOFMEMORY;
1339
1340     IBindStatusCallback_AddRef(&This->bsc.IBindStatusCallback_iface);
1341     task->bsc = This;
1342     push_task(&task->header, stop_request_proc, stop_request_task_destr, This->bsc.doc->basedoc.doc_obj->basedoc.task_magic);
1343     return S_OK;
1344 }
1345
1346 static void handle_navigation_error(nsChannelBSC *This, DWORD result)
1347 {
1348     HTMLDocumentObj *doc;
1349     IOleCommandTarget *olecmd;
1350     BOOL is_error_url;
1351     SAFEARRAY *sa;
1352     SAFEARRAYBOUND bound;
1353     VARIANT var, varOut;
1354     LONG ind;
1355     BSTR unk;
1356     HRESULT hres;
1357
1358     if(!This->window)
1359         return;
1360
1361     doc = This->window->doc_obj;
1362     if(!doc || !doc->doc_object_service || !doc->client)
1363         return;
1364
1365     hres = IDocObjectService_IsErrorUrl(doc->doc_object_service,
1366             This->window->url, &is_error_url);
1367     if(FAILED(hres) || is_error_url)
1368         return;
1369
1370     hres = IOleClientSite_QueryInterface(doc->client,
1371             &IID_IOleCommandTarget, (void**)&olecmd);
1372     if(FAILED(hres))
1373         return;
1374
1375     bound.lLbound = 0;
1376     bound.cElements = 8;
1377     sa = SafeArrayCreate(VT_VARIANT, 1, &bound);
1378     if(!sa) {
1379         IOleCommandTarget_Release(olecmd);
1380         return;
1381     }
1382
1383     ind = 0;
1384     V_VT(&var) = VT_I4;
1385     V_I4(&var) = result;
1386     SafeArrayPutElement(sa, &ind, &var);
1387
1388     ind = 1;
1389     V_VT(&var) = VT_BSTR;
1390     V_BSTR(&var) = This->window->url;
1391     SafeArrayPutElement(sa, &ind, &var);
1392
1393     ind = 3;
1394     V_VT(&var) = VT_UNKNOWN;
1395     V_UNKNOWN(&var) = (IUnknown*)&This->window->IHTMLWindow2_iface;
1396     SafeArrayPutElement(sa, &ind, &var);
1397
1398     /* FIXME: what are the following fields for? */
1399     ind = 2;
1400     V_VT(&var) = VT_UNKNOWN;
1401     V_UNKNOWN(&var) = NULL;
1402     SafeArrayPutElement(sa, &ind, &var);
1403
1404     ind = 4;
1405     V_VT(&var) = VT_BOOL;
1406     V_BOOL(&var) = FALSE;
1407     SafeArrayPutElement(sa, &ind, &var);
1408
1409     ind = 5;
1410     V_VT(&var) = VT_BOOL;
1411     V_BOOL(&var) = FALSE;
1412     SafeArrayPutElement(sa, &ind, &var);
1413
1414     ind = 6;
1415     V_VT(&var) = VT_BSTR;
1416     unk = SysAllocString(NULL);
1417     V_BSTR(&var) = unk;
1418     SafeArrayPutElement(sa, &ind, &var);
1419
1420     ind = 7;
1421     V_VT(&var) = VT_UNKNOWN;
1422     V_UNKNOWN(&var) = NULL;
1423     SafeArrayPutElement(sa, &ind, &var);
1424
1425     V_VT(&var) = VT_ARRAY;
1426     V_ARRAY(&var) = sa;
1427     V_VT(&varOut) = VT_BOOL;
1428     V_BOOL(&varOut) = VARIANT_TRUE;
1429     IOleCommandTarget_Exec(olecmd, &CGID_DocHostCmdPriv, 1, 0, &var, FAILED(hres)?NULL:&varOut);
1430
1431     SysFreeString(unk);
1432     SafeArrayDestroy(sa);
1433     IOleCommandTarget_Release(olecmd);
1434 }
1435
1436 static HRESULT nsChannelBSC_stop_binding(BSCallback *bsc, HRESULT result)
1437 {
1438     nsChannelBSC *This = nsChannelBSC_from_BSCallback(bsc);
1439
1440     if(result != E_ABORT) {
1441         if(FAILED(result))
1442             handle_navigation_error(This, result);
1443         else if(This->window) {
1444             result = async_stop_request(This);
1445             if(SUCCEEDED(result))
1446                 return S_OK;
1447         }
1448     }
1449
1450     on_stop_nsrequest(This, result);
1451     return S_OK;
1452 }
1453
1454 static HRESULT nsChannelBSC_read_data(BSCallback *bsc, IStream *stream)
1455 {
1456     nsChannelBSC *This = nsChannelBSC_from_BSCallback(bsc);
1457
1458     return read_stream_data(This, stream);
1459 }
1460
1461 static HRESULT handle_redirect(nsChannelBSC *This, const WCHAR *new_url)
1462 {
1463     nsRedirectCallback *callback;
1464     nsIChannelEventSink *sink;
1465     nsChannel *new_channel;
1466     nsresult nsres;
1467     HRESULT hres;
1468
1469     TRACE("(%p)->(%s)\n", This, debugstr_w(new_url));
1470
1471     if(!This->nschannel || !This->nschannel->notif_callback)
1472         return S_OK;
1473
1474     nsres = nsIInterfaceRequestor_GetInterface(This->nschannel->notif_callback, &IID_nsIChannelEventSink, (void**)&sink);
1475     if(NS_FAILED(nsres))
1476         return S_OK;
1477
1478     hres = create_redirect_nschannel(new_url, This->nschannel, &new_channel);
1479     if(SUCCEEDED(hres)) {
1480         hres = create_redirect_callback(new_channel, This, &callback);
1481         nsIChannel_Release(&new_channel->nsIHttpChannel_iface);
1482     }
1483
1484     if(SUCCEEDED(hres)) {
1485         nsres = nsIChannelEventSink_AsyncOnChannelRedirect(sink, (nsIChannel*)&This->nschannel->nsIHttpChannel_iface,
1486                 (nsIChannel*)&callback->nschannel->nsIHttpChannel_iface, REDIRECT_TEMPORARY, /* FIXME */
1487                 &callback->nsIAsyncVerifyRedirectCallback_iface);
1488
1489         if(NS_FAILED(nsres))
1490             FIXME("AsyncOnChannelRedirect failed: %08x\n", hres);
1491         else if(This->nschannel != callback->nschannel)
1492             FIXME("nschannel not updated\n");
1493
1494         nsIAsyncVerifyRedirectCallback_Release(&callback->nsIAsyncVerifyRedirectCallback_iface);
1495     }
1496
1497     nsIChannelEventSink_Release(sink);
1498     return hres;
1499 }
1500
1501 static HRESULT nsChannelBSC_on_progress(BSCallback *bsc, ULONG status_code, LPCWSTR status_text)
1502 {
1503     nsChannelBSC *This = nsChannelBSC_from_BSCallback(bsc);
1504
1505     switch(status_code) {
1506     case BINDSTATUS_MIMETYPEAVAILABLE:
1507         if(!This->nschannel)
1508             return S_OK;
1509
1510         heap_free(This->nschannel->content_type);
1511         This->nschannel->content_type = heap_strdupWtoA(status_text);
1512         break;
1513     case BINDSTATUS_REDIRECTING:
1514         return handle_redirect(This, status_text);
1515     case BINDSTATUS_BEGINDOWNLOADDATA: {
1516         IWinInetHttpInfo *http_info;
1517         DWORD status, size = sizeof(DWORD);
1518         HRESULT hres;
1519
1520         if(!This->bsc.binding)
1521             break;
1522
1523         hres = IBinding_QueryInterface(This->bsc.binding, &IID_IWinInetHttpInfo, (void**)&http_info);
1524         if(FAILED(hres))
1525             break;
1526
1527         hres = IWinInetHttpInfo_QueryInfo(http_info,
1528                 HTTP_QUERY_STATUS_CODE|HTTP_QUERY_FLAG_NUMBER, &status, &size, NULL, NULL);
1529         IWinInetHttpInfo_Release(http_info);
1530         if(FAILED(hres) || status == HTTP_STATUS_OK)
1531             break;
1532
1533         handle_navigation_error(This, status);
1534     }
1535     }
1536
1537     return S_OK;
1538 }
1539
1540 static HRESULT nsChannelBSC_on_response(BSCallback *bsc, DWORD response_code,
1541         LPCWSTR response_headers)
1542 {
1543     nsChannelBSC *This = nsChannelBSC_from_BSCallback(bsc);
1544     HRESULT hres;
1545
1546     This->nschannel->response_status = response_code;
1547
1548     if(response_headers) {
1549         const WCHAR *headers;
1550
1551         headers = strchrW(response_headers, '\r');
1552         if(headers && headers[1] == '\n') {
1553             headers += 2;
1554             hres = process_response_headers(This, headers);
1555             if(FAILED(hres)) {
1556                 WARN("parsing headers failed: %08x\n", hres);
1557                 return hres;
1558             }
1559         }
1560     }
1561
1562     return S_OK;
1563 }
1564
1565 static HRESULT nsChannelBSC_beginning_transaction(BSCallback *bsc, WCHAR **additional_headers)
1566 {
1567     nsChannelBSC *This = nsChannelBSC_from_BSCallback(bsc);
1568     http_header_t *iter;
1569     DWORD len = 0;
1570     WCHAR *ptr;
1571
1572     static const WCHAR content_lengthW[] =
1573         {'C','o','n','t','e','n','t','-','L','e','n','g','t','h',0};
1574
1575     if(!This->nschannel)
1576         return S_FALSE;
1577
1578     LIST_FOR_EACH_ENTRY(iter, &This->nschannel->request_headers, http_header_t, entry) {
1579         if(strcmpW(iter->header, content_lengthW))
1580             len += strlenW(iter->header) + 2 /* ": " */ + strlenW(iter->data) + 2 /* "\r\n" */;
1581     }
1582
1583     if(!len)
1584         return S_OK;
1585
1586     *additional_headers = ptr = CoTaskMemAlloc((len+1)*sizeof(WCHAR));
1587     if(!ptr)
1588         return E_OUTOFMEMORY;
1589
1590     LIST_FOR_EACH_ENTRY(iter, &This->nschannel->request_headers, http_header_t, entry) {
1591         if(!strcmpW(iter->header, content_lengthW))
1592             continue;
1593
1594         len = strlenW(iter->header);
1595         memcpy(ptr, iter->header, len*sizeof(WCHAR));
1596         ptr += len;
1597
1598         *ptr++ = ':';
1599         *ptr++ = ' ';
1600
1601         len = strlenW(iter->data);
1602         memcpy(ptr, iter->data, len*sizeof(WCHAR));
1603         ptr += len;
1604
1605         *ptr++ = '\r';
1606         *ptr++ = '\n';
1607     }
1608
1609     *ptr = 0;
1610
1611     return S_OK;
1612 }
1613
1614 static const BSCallbackVtbl nsChannelBSCVtbl = {
1615     nsChannelBSC_destroy,
1616     nsChannelBSC_init_bindinfo,
1617     nsChannelBSC_start_binding,
1618     nsChannelBSC_stop_binding,
1619     nsChannelBSC_read_data,
1620     nsChannelBSC_on_progress,
1621     nsChannelBSC_on_response,
1622     nsChannelBSC_beginning_transaction
1623 };
1624
1625 HRESULT create_channelbsc(IMoniker *mon, const WCHAR *headers, BYTE *post_data, DWORD post_data_size, nsChannelBSC **retval)
1626 {
1627     nsChannelBSC *ret;
1628
1629     ret = heap_alloc_zero(sizeof(*ret));
1630     if(!ret)
1631         return E_OUTOFMEMORY;
1632
1633     init_bscallback(&ret->bsc, &nsChannelBSCVtbl, mon, BINDF_ASYNCHRONOUS | BINDF_ASYNCSTORAGE | BINDF_PULLDATA);
1634
1635     if(headers) {
1636         ret->bsc.headers = heap_strdupW(headers);
1637         if(!ret->bsc.headers) {
1638             IBindStatusCallback_Release(&ret->bsc.IBindStatusCallback_iface);
1639             return E_OUTOFMEMORY;
1640         }
1641     }
1642
1643     if(post_data) {
1644         ret->bsc.post_data = GlobalAlloc(0, post_data_size);
1645         if(!ret->bsc.post_data) {
1646             heap_free(ret->bsc.headers);
1647             IBindStatusCallback_Release(&ret->bsc.IBindStatusCallback_iface);
1648             return E_OUTOFMEMORY;
1649         }
1650
1651         memcpy(ret->bsc.post_data, post_data, post_data_size);
1652         ret->bsc.post_data_len = post_data_size;
1653     }
1654
1655     *retval = ret;
1656     return S_OK;
1657 }
1658
1659 void set_window_bscallback(HTMLWindow *window, nsChannelBSC *callback)
1660 {
1661     if(window->bscallback) {
1662         if(window->bscallback->bsc.binding)
1663             IBinding_Abort(window->bscallback->bsc.binding);
1664         window->bscallback->bsc.doc = NULL;
1665         window->bscallback->window = NULL;
1666         IBindStatusCallback_Release(&window->bscallback->bsc.IBindStatusCallback_iface);
1667     }
1668
1669     window->bscallback = callback;
1670
1671     if(callback) {
1672         callback->window = window;
1673         IBindStatusCallback_AddRef(&callback->bsc.IBindStatusCallback_iface);
1674         callback->bsc.doc = window->doc;
1675     }
1676 }
1677
1678 typedef struct {
1679     task_t header;
1680     HTMLWindow *window;
1681     nsChannelBSC *bscallback;
1682 } start_doc_binding_task_t;
1683
1684 static void start_doc_binding_proc(task_t *_task)
1685 {
1686     start_doc_binding_task_t *task = (start_doc_binding_task_t*)_task;
1687
1688     start_binding(task->window, NULL, (BSCallback*)task->bscallback, NULL);
1689 }
1690
1691 static void start_doc_binding_task_destr(task_t *_task)
1692 {
1693     start_doc_binding_task_t *task = (start_doc_binding_task_t*)_task;
1694
1695     IBindStatusCallback_Release(&task->bscallback->bsc.IBindStatusCallback_iface);
1696     heap_free(task);
1697 }
1698
1699 HRESULT async_start_doc_binding(HTMLWindow *window, nsChannelBSC *bscallback)
1700 {
1701     start_doc_binding_task_t *task;
1702
1703     TRACE("%p\n", bscallback);
1704
1705     task = heap_alloc(sizeof(start_doc_binding_task_t));
1706     if(!task)
1707         return E_OUTOFMEMORY;
1708
1709     task->window = window;
1710     task->bscallback = bscallback;
1711     IBindStatusCallback_AddRef(&bscallback->bsc.IBindStatusCallback_iface);
1712
1713     push_task(&task->header, start_doc_binding_proc, start_doc_binding_task_destr, window->task_magic);
1714     return S_OK;
1715 }
1716
1717 void abort_document_bindings(HTMLDocumentNode *doc)
1718 {
1719     BSCallback *iter, *next;
1720
1721     LIST_FOR_EACH_ENTRY_SAFE(iter, next, &doc->bindings, BSCallback, entry) {
1722         TRACE("Aborting %p\n", iter);
1723
1724         if(iter->doc)
1725             remove_target_tasks(iter->doc->basedoc.task_magic);
1726
1727         if(iter->binding)
1728             IBinding_Abort(iter->binding);
1729         else {
1730             list_remove(&iter->entry);
1731             list_init(&iter->entry);
1732             iter->vtbl->stop_binding(iter, E_ABORT);
1733         }
1734
1735         iter->doc = NULL;
1736     }
1737 }
1738
1739 HRESULT channelbsc_load_stream(nsChannelBSC *bscallback, IStream *stream)
1740 {
1741     HRESULT hres = S_OK;
1742
1743     if(!bscallback->nschannel) {
1744         ERR("NULL nschannel\n");
1745         return E_FAIL;
1746     }
1747
1748     bscallback->nschannel->content_type = heap_strdupA("text/html");
1749     if(!bscallback->nschannel->content_type)
1750         return E_OUTOFMEMORY;
1751
1752     list_add_head(&bscallback->bsc.doc->bindings, &bscallback->bsc.entry);
1753     if(stream)
1754         hres = read_stream_data(bscallback, stream);
1755     if(SUCCEEDED(hres))
1756         hres = async_stop_request(bscallback);
1757     if(FAILED(hres))
1758         IBindStatusCallback_OnStopBinding(&bscallback->bsc.IBindStatusCallback_iface, hres,
1759                 ERROR_SUCCESS);
1760
1761     return hres;
1762 }
1763
1764 void channelbsc_set_channel(nsChannelBSC *This, nsChannel *channel, nsIStreamListener *listener, nsISupports *context)
1765 {
1766     nsIChannel_AddRef(&channel->nsIHttpChannel_iface);
1767     This->nschannel = channel;
1768
1769     nsIStreamListener_AddRef(listener);
1770     This->nslistener = listener;
1771
1772     if(context) {
1773         nsISupports_AddRef(context);
1774         This->nscontext = context;
1775     }
1776
1777     if(This->bsc.headers) {
1778         HRESULT hres;
1779
1780         hres = parse_headers(This->bsc.headers, &channel->request_headers);
1781         heap_free(This->bsc.headers);
1782         This->bsc.headers = NULL;
1783         if(FAILED(hres))
1784             WARN("parse_headers failed: %08x\n", hres);
1785     }
1786 }
1787
1788 typedef struct {
1789     task_t header;
1790     HTMLWindow *window;
1791     IUri *uri;
1792 } navigate_javascript_task_t;
1793
1794 static void navigate_javascript_proc(task_t *_task)
1795 {
1796     navigate_javascript_task_t *task = (navigate_javascript_task_t*)_task;
1797     HTMLWindow *window = task->window;
1798     VARIANT v;
1799     BSTR code;
1800     HRESULT hres;
1801
1802     static const WCHAR jscriptW[] = {'j','s','c','r','i','p','t',0};
1803
1804     task->window->readystate = READYSTATE_COMPLETE;
1805
1806     hres = IUri_GetPath(task->uri, &code);
1807     if(FAILED(hres))
1808         return;
1809
1810     set_download_state(window->doc_obj, 1);
1811
1812     V_VT(&v) = VT_EMPTY;
1813     hres = exec_script(window, code, jscriptW, &v);
1814     SysFreeString(code);
1815     if(SUCCEEDED(hres) && V_VT(&v) != VT_EMPTY) {
1816         FIXME("javascirpt URL returned %s\n", debugstr_variant(&v));
1817         VariantClear(&v);
1818     }
1819
1820     if(window->doc_obj->view_sink)
1821         IAdviseSink_OnViewChange(window->doc_obj->view_sink, DVASPECT_CONTENT, -1);
1822
1823     set_download_state(window->doc_obj, 0);
1824 }
1825
1826 static void navigate_javascript_task_destr(task_t *_task)
1827 {
1828     navigate_javascript_task_t *task = (navigate_javascript_task_t*)_task;
1829
1830     IUri_Release(task->uri);
1831     heap_free(task);
1832 }
1833
1834 typedef struct {
1835     task_t header;
1836     HTMLWindow *window;
1837     nsChannelBSC *bscallback;
1838     IMoniker *mon;
1839 } navigate_task_t;
1840
1841 static void navigate_proc(task_t *_task)
1842 {
1843     navigate_task_t *task = (navigate_task_t*)_task;
1844     HRESULT hres;
1845
1846     hres = set_moniker(&task->window->doc_obj->basedoc, task->mon, NULL, task->bscallback, TRUE);
1847     if(SUCCEEDED(hres))
1848         start_binding(task->window, NULL, (BSCallback*)task->bscallback, NULL);
1849 }
1850
1851 static void navigate_task_destr(task_t *_task)
1852 {
1853     navigate_task_t *task = (navigate_task_t*)_task;
1854
1855     IUnknown_Release((IUnknown*)task->bscallback);
1856     IMoniker_Release(task->mon);
1857     heap_free(task);
1858 }
1859
1860 static HRESULT navigate_fragment(HTMLWindow *window, IUri *uri)
1861 {
1862     nsIDOMLocation *nslocation;
1863     nsAString nsfrag_str;
1864     BSTR frag;
1865     nsresult nsres;
1866     HRESULT hres;
1867
1868     set_current_uri(window, uri);
1869
1870     nsres = nsIDOMWindow_GetLocation(window->nswindow, &nslocation);
1871     if(FAILED(nsres) || !nslocation)
1872         return E_FAIL;
1873
1874     hres = IUri_GetFragment(uri, &frag);
1875     if(FAILED(hres)) {
1876         nsIDOMLocation_Release(nslocation);
1877         return hres;
1878     }
1879
1880     nsAString_InitDepend(&nsfrag_str, frag);
1881     nsres = nsIDOMLocation_SetHash(nslocation, &nsfrag_str);
1882     nsAString_Finish(&nsfrag_str);
1883     nsIDOMLocation_Release(nslocation);
1884     SysFreeString(frag);
1885     if(NS_FAILED(nsres)) {
1886         ERR("SetHash failed: %08x\n", nsres);
1887         return E_FAIL;
1888     }
1889
1890     if(window->doc_obj->doc_object_service) {
1891         IDocObjectService_FireNavigateComplete2(window->doc_obj->doc_object_service, &window->IHTMLWindow2_iface, 0x10);
1892         IDocObjectService_FireDocumentComplete(window->doc_obj->doc_object_service, &window->IHTMLWindow2_iface, 0);
1893
1894     }
1895
1896     return S_OK;
1897 }
1898
1899 HRESULT super_navigate(HTMLWindow *window, IUri *uri, const WCHAR *headers, BYTE *post_data, DWORD post_data_size)
1900 {
1901     nsChannelBSC *bsc;
1902     IMoniker *mon;
1903     DWORD scheme;
1904     HRESULT hres;
1905
1906     if(window->doc_obj->client) {
1907         IOleCommandTarget *cmdtrg;
1908
1909         hres = IOleClientSite_QueryInterface(window->doc_obj->client, &IID_IOleCommandTarget, (void**)&cmdtrg);
1910         if(SUCCEEDED(hres)) {
1911             VARIANT in, out;
1912             BSTR url_str;
1913
1914             hres = IUri_GetDisplayUri(uri, &url_str);
1915             if(SUCCEEDED(hres)) {
1916                 V_VT(&in) = VT_BSTR;
1917                 V_BSTR(&in) = url_str;
1918                 V_VT(&out) = VT_BOOL;
1919                 V_BOOL(&out) = VARIANT_TRUE;
1920                 hres = IOleCommandTarget_Exec(cmdtrg, &CGID_ShellDocView, 67, 0, &in, &out);
1921                 IOleCommandTarget_Release(cmdtrg);
1922                 if(SUCCEEDED(hres))
1923                     VariantClear(&out);
1924                 SysFreeString(url_str);
1925             }
1926         }
1927     }
1928
1929     if(window->uri && !post_data_size && compare_ignoring_frag(window->uri, uri)) {
1930         TRACE("fragment navigate\n");
1931         return navigate_fragment(window, uri);
1932     }
1933
1934     hres = CreateURLMonikerEx2(NULL, uri, &mon, URL_MK_UNIFORM);
1935     if(FAILED(hres))
1936         return hres;
1937
1938     /* FIXME: Why not set_ready_state? */
1939     window->readystate = READYSTATE_UNINITIALIZED;
1940
1941     hres = create_channelbsc(mon, headers, post_data, post_data_size, &bsc);
1942     if(FAILED(hres)) {
1943         IMoniker_Release(mon);
1944         return hres;
1945     }
1946
1947     prepare_for_binding(&window->doc_obj->basedoc, mon, TRUE);
1948
1949     hres = IUri_GetScheme(uri, &scheme);
1950     if(SUCCEEDED(hres) && scheme != URL_SCHEME_JAVASCRIPT) {
1951         navigate_task_t *task;
1952
1953         task = heap_alloc(sizeof(*task));
1954         if(!task) {
1955             IUnknown_Release((IUnknown*)bsc);
1956             IMoniker_Release(mon);
1957             return E_OUTOFMEMORY;
1958         }
1959
1960         task->window = window;
1961         task->bscallback = bsc;
1962         task->mon = mon;
1963         push_task(&task->header, navigate_proc, navigate_task_destr, window->task_magic);
1964
1965         /* Silently and repeated when real loading starts? */
1966         window->readystate = READYSTATE_LOADING;
1967     }else {
1968         navigate_javascript_task_t *task;
1969
1970         IUnknown_Release((IUnknown*)bsc);
1971         IMoniker_Release(mon);
1972
1973         task = heap_alloc(sizeof(*task));
1974         if(!task)
1975             return E_OUTOFMEMORY;
1976
1977         IUri_AddRef(uri);
1978         task->window = window;
1979         task->uri = uri;
1980         push_task(&task->header, navigate_javascript_proc, navigate_javascript_task_destr, window->task_magic);
1981
1982         /* Why silently? */
1983         window->readystate = READYSTATE_COMPLETE;
1984     }
1985
1986     return S_OK;
1987 }
1988
1989 HRESULT navigate_new_window(HTMLWindow *window, IUri *uri, const WCHAR *name, IHTMLWindow2 **ret)
1990 {
1991     IWebBrowser2 *web_browser;
1992     IHTMLWindow2 *new_window;
1993     IBindCtx *bind_ctx;
1994     nsChannelBSC *bsc;
1995     HRESULT hres;
1996
1997     hres = create_channelbsc(NULL, NULL, NULL, 0, &bsc);
1998     if(FAILED(hres))
1999         return hres;
2000
2001     hres = CreateAsyncBindCtx(0, &bsc->bsc.IBindStatusCallback_iface, NULL, &bind_ctx);
2002     if(FAILED(hres)) {
2003         IBindStatusCallback_Release(&bsc->bsc.IBindStatusCallback_iface);
2004         return hres;
2005     }
2006
2007     hres = CoCreateInstance(&CLSID_InternetExplorer, NULL, CLSCTX_LOCAL_SERVER,
2008             &IID_IWebBrowser2, (void**)&web_browser);
2009     if(SUCCEEDED(hres)) {
2010         ITargetFramePriv2 *target_frame_priv;
2011
2012         hres = IWebBrowser_QueryInterface(web_browser, &IID_ITargetFramePriv2, (void**)&target_frame_priv);
2013         if(SUCCEEDED(hres)) {
2014             hres = ITargetFramePriv2_AggregatedNavigation2(target_frame_priv,
2015                     HLNF_DISABLEWINDOWRESTRICTIONS|HLNF_OPENINNEWWINDOW, bind_ctx, &bsc->bsc.IBindStatusCallback_iface,
2016                     name, uri, emptyW);
2017             ITargetFramePriv2_Release(target_frame_priv);
2018
2019             if(SUCCEEDED(hres))
2020                 hres = do_query_service((IUnknown*)web_browser, &SID_SHTMLWindow, &IID_IHTMLWindow2, (void**)&new_window);
2021         }
2022         if(FAILED(hres)) {
2023             IWebBrowser2_Quit(web_browser);
2024             IWebBrowser2_Release(web_browser);
2025         }
2026     }else {
2027         WARN("Could not create InternetExplorer instance: %08x\n", hres);
2028     }
2029
2030     IBindStatusCallback_Release(&bsc->bsc.IBindStatusCallback_iface);
2031     IBindCtx_Release(bind_ctx);
2032     if(FAILED(hres))
2033         return hres;
2034
2035     IWebBrowser2_put_Visible(web_browser, VARIANT_TRUE);
2036     IWebBrowser2_Release(web_browser);
2037
2038     if(ret)
2039         *ret = new_window;
2040     else
2041         IHTMLWindow2_Release(new_window);
2042     return S_OK;
2043 }
2044
2045 HRESULT hlink_frame_navigate(HTMLDocument *doc, LPCWSTR url, nsChannel *nschannel, DWORD hlnf, BOOL *cancel)
2046 {
2047     IHlinkFrame *hlink_frame;
2048     nsChannelBSC *callback;
2049     IBindCtx *bindctx;
2050     IMoniker *mon;
2051     IHlink *hlink;
2052     HRESULT hres;
2053
2054     *cancel = FALSE;
2055
2056     hres = do_query_service((IUnknown*)doc->doc_obj->client, &IID_IHlinkFrame, &IID_IHlinkFrame,
2057             (void**)&hlink_frame);
2058     if(FAILED(hres))
2059         return S_OK;
2060
2061     hres = create_channelbsc(NULL, NULL, NULL, 0, &callback);
2062     if(FAILED(hres)) {
2063         IHlinkFrame_Release(hlink_frame);
2064         return hres;
2065     }
2066
2067     if(nschannel)
2068         read_post_data_stream(callback, nschannel);
2069
2070     hres = CreateAsyncBindCtx(0, &callback->bsc.IBindStatusCallback_iface, NULL, &bindctx);
2071     if(SUCCEEDED(hres))
2072         hres = CoCreateInstance(&CLSID_StdHlink, NULL, CLSCTX_INPROC_SERVER,
2073                 &IID_IHlink, (LPVOID*)&hlink);
2074
2075     if(SUCCEEDED(hres))
2076         hres = CreateURLMoniker(NULL, url, &mon);
2077
2078     if(SUCCEEDED(hres)) {
2079         IHlink_SetMonikerReference(hlink, HLINKSETF_TARGET, mon, NULL);
2080
2081         if(hlnf & HLNF_OPENINNEWWINDOW) {
2082             static const WCHAR wszBlank[] = {'_','b','l','a','n','k',0};
2083             IHlink_SetTargetFrameName(hlink, wszBlank); /* FIXME */
2084         }
2085
2086         hres = IHlinkFrame_Navigate(hlink_frame, hlnf, bindctx,
2087                 &callback->bsc.IBindStatusCallback_iface, hlink);
2088         IMoniker_Release(mon);
2089         *cancel = hres == S_OK;
2090         hres = S_OK;
2091     }
2092
2093     IHlinkFrame_Release(hlink_frame);
2094     IBindCtx_Release(bindctx);
2095     IBindStatusCallback_Release(&callback->bsc.IBindStatusCallback_iface);
2096     return hres;
2097 }
2098
2099 HRESULT navigate_url(HTMLWindow *window, const WCHAR *new_url, const WCHAR *base_url)
2100 {
2101     WCHAR url[INTERNET_MAX_URL_LENGTH];
2102     nsWineURI *uri;
2103     HRESULT hres;
2104
2105     if(!new_url) {
2106         *url = 0;
2107     }else if(base_url) {
2108         DWORD len = 0;
2109
2110         hres = CoInternetCombineUrl(base_url, new_url, URL_ESCAPE_SPACES_ONLY|URL_DONT_ESCAPE_EXTRA_INFO,
2111                 url, sizeof(url)/sizeof(WCHAR), &len, 0);
2112         if(FAILED(hres))
2113             return hres;
2114     }else {
2115         strcpyW(url, new_url);
2116     }
2117
2118     if(window->doc_obj && window->doc_obj->hostui) {
2119         OLECHAR *translated_url = NULL;
2120
2121         hres = IDocHostUIHandler_TranslateUrl(window->doc_obj->hostui, 0, url,
2122                 &translated_url);
2123         if(hres == S_OK) {
2124             TRACE("%08x %s -> %s\n", hres, debugstr_w(url), debugstr_w(translated_url));
2125             strcpyW(url, translated_url);
2126             CoTaskMemFree(translated_url);
2127         }
2128     }
2129
2130     if(window->doc_obj && window->doc_obj->is_webbrowser && window == window->doc_obj->basedoc.window) {
2131         BOOL cancel = FALSE;
2132         IUri *uri;
2133
2134         hres = IDocObjectService_FireBeforeNavigate2(window->doc_obj->doc_object_service, NULL, url, 0x40,
2135                 NULL, NULL, 0, NULL, TRUE, &cancel);
2136         if(SUCCEEDED(hres) && cancel) {
2137             TRACE("Navigation canceled\n");
2138             return S_OK;
2139         }
2140
2141         hres = CreateUri(url, 0, 0, &uri);
2142         if(FAILED(hres))
2143             return hres;
2144
2145         hres = super_navigate(window, uri, NULL, NULL, 0);
2146         IUri_Release(uri);
2147         return hres;
2148     }
2149
2150     if(window->doc_obj && window == window->doc_obj->basedoc.window) {
2151         BOOL cancel;
2152
2153         hres = hlink_frame_navigate(&window->doc->basedoc, url, NULL, 0, &cancel);
2154         if(FAILED(hres))
2155             return hres;
2156
2157         if(cancel) {
2158             TRACE("Navigation handled by hlink frame\n");
2159             return S_OK;
2160         }
2161     }
2162
2163     hres = create_doc_uri(window, url, &uri);
2164     if(FAILED(hres))
2165         return hres;
2166
2167     hres = load_nsuri(window, uri, NULL, LOAD_FLAGS_NONE);
2168     nsISupports_Release((nsISupports*)uri);
2169     return hres;
2170 }