mshtml: Use helper for IHTMLStyle::get_top implementation.
[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 /* 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     static const WCHAR mimeTextHtml[] = {'t','e','x','t','/','h','t','m','l',0};
1063
1064     DWORD read;
1065     nsresult nsres;
1066     HRESULT hres;
1067
1068     if(!This->nslistener) {
1069         BYTE buf[1024];
1070
1071         do {
1072             read = 0;
1073             hres = IStream_Read(stream, buf, sizeof(buf), &read);
1074         }while(hres == S_OK && read);
1075
1076         return S_OK;
1077     }
1078
1079     if(!This->nsstream)
1080         This->nsstream = create_nsprotocol_stream();
1081
1082     do {
1083         read = 0;
1084         hres = IStream_Read(stream, This->nsstream->buf+This->nsstream->buf_size,
1085                 sizeof(This->nsstream->buf)-This->nsstream->buf_size, &read);
1086         if(!read)
1087             break;
1088
1089         This->nsstream->buf_size += read;
1090
1091         if(!This->bsc.readed) {
1092             if(This->nsstream->buf_size >= 2
1093                && (BYTE)This->nsstream->buf[0] == 0xff
1094                && (BYTE)This->nsstream->buf[1] == 0xfe)
1095                 This->nschannel->charset = heap_strdupA(UTF16_STR);
1096             if(This->nsstream->buf_size >= 3
1097                && (BYTE)This->nsstream->buf[0] == 0xef
1098                && (BYTE)This->nsstream->buf[1] == 0xbb
1099                && (BYTE)This->nsstream->buf[2] == 0xbf)
1100                 This->nschannel->charset = heap_strdupA(UTF8_STR);
1101
1102             if(!This->nschannel->content_type) {
1103                 WCHAR *mime;
1104
1105                 hres = FindMimeFromData(NULL, NULL, This->nsstream->buf, This->nsstream->buf_size,
1106                         This->window ? mimeTextHtml : NULL, 0, &mime, 0);
1107                 if(FAILED(hres))
1108                     return hres;
1109
1110                 TRACE("Found MIME %s\n", debugstr_w(mime));
1111
1112                 This->nschannel->content_type = heap_strdupWtoA(mime);
1113                 CoTaskMemFree(mime);
1114                 if(!This->nschannel->content_type)
1115                     return E_OUTOFMEMORY;
1116             }
1117
1118             on_start_nsrequest(This);
1119         }
1120
1121         This->bsc.readed += This->nsstream->buf_size;
1122
1123         nsres = nsIStreamListener_OnDataAvailable(This->nslistener,
1124                 (nsIRequest*)&This->nschannel->nsIHttpChannel_iface, This->nscontext,
1125                 &This->nsstream->nsIInputStream_iface, This->bsc.readed-This->nsstream->buf_size,
1126                 This->nsstream->buf_size);
1127         if(NS_FAILED(nsres))
1128             ERR("OnDataAvailable failed: %08x\n", nsres);
1129
1130         if(This->nsstream->buf_size == sizeof(This->nsstream->buf)) {
1131             ERR("buffer is full\n");
1132             break;
1133         }
1134     }while(hres == S_OK);
1135
1136     return S_OK;
1137 }
1138
1139 typedef struct {
1140     nsIAsyncVerifyRedirectCallback nsIAsyncVerifyRedirectCallback_iface;
1141
1142     LONG ref;
1143
1144     nsChannel *nschannel;
1145     nsChannelBSC *bsc;
1146 } nsRedirectCallback;
1147
1148 static nsRedirectCallback *impl_from_nsIAsyncVerifyRedirectCallback(nsIAsyncVerifyRedirectCallback *iface)
1149 {
1150     return CONTAINING_RECORD(iface, nsRedirectCallback, nsIAsyncVerifyRedirectCallback_iface);
1151 }
1152
1153 static nsresult NSAPI nsAsyncVerifyRedirectCallback_QueryInterface(nsIAsyncVerifyRedirectCallback *iface,
1154         nsIIDRef riid, void **result)
1155 {
1156     nsRedirectCallback *This = impl_from_nsIAsyncVerifyRedirectCallback(iface);
1157
1158     if(IsEqualGUID(&IID_nsISupports, riid)) {
1159         TRACE("(%p)->(IID_nsISuports %p)\n", This, result);
1160         *result = &This->nsIAsyncVerifyRedirectCallback_iface;
1161     }else if(IsEqualGUID(&IID_nsIAsyncVerifyRedirectCallback, riid)) {
1162         TRACE("(%p)->(IID_nsIAsyncVerifyRedirectCallback %p)\n", This, result);
1163         *result = &This->nsIAsyncVerifyRedirectCallback_iface;
1164     }else {
1165         *result = NULL;
1166         WARN("unimplemented iface %s\n", debugstr_guid(riid));
1167         return NS_NOINTERFACE;
1168     }
1169
1170     nsISupports_AddRef((nsISupports*)*result);
1171     return NS_OK;
1172 }
1173
1174 static nsrefcnt NSAPI nsAsyncVerifyRedirectCallback_AddRef(nsIAsyncVerifyRedirectCallback *iface)
1175 {
1176     nsRedirectCallback *This = impl_from_nsIAsyncVerifyRedirectCallback(iface);
1177     LONG ref = InterlockedIncrement(&This->ref);
1178
1179     TRACE("(%p) ref=%d\n", This, ref);
1180
1181     return ref;
1182 }
1183
1184 static nsrefcnt NSAPI nsAsyncVerifyRedirectCallback_Release(nsIAsyncVerifyRedirectCallback *iface)
1185 {
1186     nsRedirectCallback *This = impl_from_nsIAsyncVerifyRedirectCallback(iface);
1187     LONG ref = InterlockedDecrement(&This->ref);
1188
1189     TRACE("(%p) ref=%d\n", This, ref);
1190
1191     if(!ref) {
1192         IBindStatusCallback_Release(&This->bsc->bsc.IBindStatusCallback_iface);
1193         nsIChannel_Release(&This->nschannel->nsIHttpChannel_iface);
1194         heap_free(This);
1195     }
1196
1197     return ref;
1198 }
1199
1200 static nsresult NSAPI nsAsyncVerifyRedirectCallback_AsyncOnChannelRedirect(nsIAsyncVerifyRedirectCallback *iface, nsresult result)
1201 {
1202     nsRedirectCallback *This = impl_from_nsIAsyncVerifyRedirectCallback(iface);
1203
1204     TRACE("(%p)->(%08x)\n", This, result);
1205
1206     if(This->bsc->nschannel)
1207         nsIHttpChannel_Release(&This->bsc->nschannel->nsIHttpChannel_iface);
1208     nsIChannel_AddRef(&This->nschannel->nsIHttpChannel_iface);
1209     This->bsc->nschannel = This->nschannel;
1210
1211     if(This->nschannel->load_group) {
1212         nsresult nsres;
1213
1214         nsres = nsILoadGroup_AddRequest(This->nschannel->load_group, (nsIRequest*)&This->nschannel->nsIHttpChannel_iface,
1215                 NULL);
1216         if(NS_FAILED(nsres))
1217             ERR("AddRequest failed: %08x\n", nsres);
1218     }
1219
1220     if(This->bsc->window) {
1221         IUri *uri = nsuri_get_uri(This->nschannel->uri);
1222
1223         if(uri) {
1224             set_current_uri(This->bsc->window, uri);
1225             IUri_Release(uri);
1226         }else {
1227             WARN("Could not get IUri from nsWineURI\n");
1228         }
1229     }
1230
1231     return NS_OK;
1232 }
1233
1234 static const nsIAsyncVerifyRedirectCallbackVtbl nsAsyncVerifyRedirectCallbackVtbl = {
1235     nsAsyncVerifyRedirectCallback_QueryInterface,
1236     nsAsyncVerifyRedirectCallback_AddRef,
1237     nsAsyncVerifyRedirectCallback_Release,
1238     nsAsyncVerifyRedirectCallback_AsyncOnChannelRedirect
1239 };
1240
1241 static HRESULT create_redirect_callback(nsChannel *nschannel, nsChannelBSC *bsc, nsRedirectCallback **ret)
1242 {
1243     nsRedirectCallback *callback;
1244
1245     callback = heap_alloc(sizeof(*callback));
1246     if(!callback)
1247         return E_OUTOFMEMORY;
1248
1249     callback->nsIAsyncVerifyRedirectCallback_iface.lpVtbl = &nsAsyncVerifyRedirectCallbackVtbl;
1250     callback->ref = 1;
1251
1252     nsIChannel_AddRef(&nschannel->nsIHttpChannel_iface);
1253     callback->nschannel = nschannel;
1254
1255     IBindStatusCallback_AddRef(&bsc->bsc.IBindStatusCallback_iface);
1256     callback->bsc = bsc;
1257
1258     *ret = callback;
1259     return S_OK;
1260 }
1261
1262 static inline nsChannelBSC *nsChannelBSC_from_BSCallback(BSCallback *iface)
1263 {
1264     return CONTAINING_RECORD(iface, nsChannelBSC, bsc);
1265 }
1266
1267 static void nsChannelBSC_destroy(BSCallback *bsc)
1268 {
1269     nsChannelBSC *This = nsChannelBSC_from_BSCallback(bsc);
1270
1271     if(This->nschannel)
1272         nsIChannel_Release(&This->nschannel->nsIHttpChannel_iface);
1273     if(This->nslistener)
1274         nsIStreamListener_Release(This->nslistener);
1275     if(This->nscontext)
1276         nsISupports_Release(This->nscontext);
1277     if(This->nsstream)
1278         nsIInputStream_Release(&This->nsstream->nsIInputStream_iface);
1279     heap_free(This);
1280 }
1281
1282 static HRESULT nsChannelBSC_start_binding(BSCallback *bsc)
1283 {
1284     nsChannelBSC *This = nsChannelBSC_from_BSCallback(bsc);
1285
1286     if(This->window)
1287         This->window->doc->skip_mutation_notif = FALSE;
1288
1289     return S_OK;
1290 }
1291
1292 static HRESULT nsChannelBSC_init_bindinfo(BSCallback *bsc)
1293 {
1294     nsChannelBSC *This = nsChannelBSC_from_BSCallback(bsc);
1295     HRESULT hres;
1296
1297     if(This->nschannel && This->nschannel->post_data_stream) {
1298         hres = read_post_data_stream(This, This->nschannel);
1299         if(FAILED(hres))
1300             return hres;
1301     }
1302
1303     return S_OK;
1304 }
1305
1306 typedef struct {
1307     task_t header;
1308     nsChannelBSC *bsc;
1309 } stop_request_task_t;
1310
1311 static void stop_request_proc(task_t *_task)
1312 {
1313     stop_request_task_t *task = (stop_request_task_t*)_task;
1314
1315     TRACE("(%p)\n", task->bsc);
1316
1317     list_remove(&task->bsc->bsc.entry);
1318     list_init(&task->bsc->bsc.entry);
1319     on_stop_nsrequest(task->bsc, S_OK);
1320 }
1321
1322 static void stop_request_task_destr(task_t *_task)
1323 {
1324     stop_request_task_t *task = (stop_request_task_t*)_task;
1325
1326     IBindStatusCallback_Release(&task->bsc->bsc.IBindStatusCallback_iface);
1327     heap_free(task);
1328 }
1329
1330 static HRESULT async_stop_request(nsChannelBSC *This)
1331 {
1332     stop_request_task_t *task;
1333
1334     if(!This->bsc.readed) {
1335         TRACE("No data read, calling OnStartRequest\n");
1336         on_start_nsrequest(This);
1337     }
1338
1339     task = heap_alloc(sizeof(*task));
1340     if(!task)
1341         return E_OUTOFMEMORY;
1342
1343     IBindStatusCallback_AddRef(&This->bsc.IBindStatusCallback_iface);
1344     task->bsc = This;
1345     push_task(&task->header, stop_request_proc, stop_request_task_destr, This->bsc.doc->basedoc.doc_obj->basedoc.task_magic);
1346     return S_OK;
1347 }
1348
1349 static void handle_navigation_error(nsChannelBSC *This, DWORD result)
1350 {
1351     HTMLDocumentObj *doc;
1352     IOleCommandTarget *olecmd;
1353     BOOL is_error_url;
1354     SAFEARRAY *sa;
1355     SAFEARRAYBOUND bound;
1356     VARIANT var, varOut;
1357     LONG ind;
1358     BSTR unk;
1359     HRESULT hres;
1360
1361     if(!This->window)
1362         return;
1363
1364     doc = This->window->doc_obj;
1365     if(!doc || !doc->doc_object_service || !doc->client)
1366         return;
1367
1368     hres = IDocObjectService_IsErrorUrl(doc->doc_object_service,
1369             This->window->url, &is_error_url);
1370     if(FAILED(hres) || is_error_url)
1371         return;
1372
1373     hres = IOleClientSite_QueryInterface(doc->client,
1374             &IID_IOleCommandTarget, (void**)&olecmd);
1375     if(FAILED(hres))
1376         return;
1377
1378     bound.lLbound = 0;
1379     bound.cElements = 8;
1380     sa = SafeArrayCreate(VT_VARIANT, 1, &bound);
1381     if(!sa) {
1382         IOleCommandTarget_Release(olecmd);
1383         return;
1384     }
1385
1386     ind = 0;
1387     V_VT(&var) = VT_I4;
1388     V_I4(&var) = result;
1389     SafeArrayPutElement(sa, &ind, &var);
1390
1391     ind = 1;
1392     V_VT(&var) = VT_BSTR;
1393     V_BSTR(&var) = This->window->url;
1394     SafeArrayPutElement(sa, &ind, &var);
1395
1396     ind = 3;
1397     V_VT(&var) = VT_UNKNOWN;
1398     V_UNKNOWN(&var) = (IUnknown*)&This->window->IHTMLWindow2_iface;
1399     SafeArrayPutElement(sa, &ind, &var);
1400
1401     /* FIXME: what are the following fields for? */
1402     ind = 2;
1403     V_VT(&var) = VT_UNKNOWN;
1404     V_UNKNOWN(&var) = NULL;
1405     SafeArrayPutElement(sa, &ind, &var);
1406
1407     ind = 4;
1408     V_VT(&var) = VT_BOOL;
1409     V_BOOL(&var) = FALSE;
1410     SafeArrayPutElement(sa, &ind, &var);
1411
1412     ind = 5;
1413     V_VT(&var) = VT_BOOL;
1414     V_BOOL(&var) = FALSE;
1415     SafeArrayPutElement(sa, &ind, &var);
1416
1417     ind = 6;
1418     V_VT(&var) = VT_BSTR;
1419     unk = SysAllocString(NULL);
1420     V_BSTR(&var) = unk;
1421     SafeArrayPutElement(sa, &ind, &var);
1422
1423     ind = 7;
1424     V_VT(&var) = VT_UNKNOWN;
1425     V_UNKNOWN(&var) = NULL;
1426     SafeArrayPutElement(sa, &ind, &var);
1427
1428     V_VT(&var) = VT_ARRAY;
1429     V_ARRAY(&var) = sa;
1430     V_VT(&varOut) = VT_BOOL;
1431     V_BOOL(&varOut) = VARIANT_TRUE;
1432     IOleCommandTarget_Exec(olecmd, &CGID_DocHostCmdPriv, 1, 0, &var, FAILED(hres)?NULL:&varOut);
1433
1434     SysFreeString(unk);
1435     SafeArrayDestroy(sa);
1436     IOleCommandTarget_Release(olecmd);
1437 }
1438
1439 static HRESULT nsChannelBSC_stop_binding(BSCallback *bsc, HRESULT result)
1440 {
1441     nsChannelBSC *This = nsChannelBSC_from_BSCallback(bsc);
1442
1443     if(result != E_ABORT) {
1444         if(FAILED(result))
1445             handle_navigation_error(This, result);
1446         else if(This->window) {
1447             result = async_stop_request(This);
1448             if(SUCCEEDED(result))
1449                 return S_OK;
1450         }
1451     }
1452
1453     on_stop_nsrequest(This, result);
1454     return S_OK;
1455 }
1456
1457 static HRESULT nsChannelBSC_read_data(BSCallback *bsc, IStream *stream)
1458 {
1459     nsChannelBSC *This = nsChannelBSC_from_BSCallback(bsc);
1460
1461     return read_stream_data(This, stream);
1462 }
1463
1464 static HRESULT handle_redirect(nsChannelBSC *This, const WCHAR *new_url)
1465 {
1466     nsRedirectCallback *callback;
1467     nsIChannelEventSink *sink;
1468     nsChannel *new_channel;
1469     nsresult nsres;
1470     HRESULT hres;
1471
1472     TRACE("(%p)->(%s)\n", This, debugstr_w(new_url));
1473
1474     if(!This->nschannel || !This->nschannel->notif_callback)
1475         return S_OK;
1476
1477     nsres = nsIInterfaceRequestor_GetInterface(This->nschannel->notif_callback, &IID_nsIChannelEventSink, (void**)&sink);
1478     if(NS_FAILED(nsres))
1479         return S_OK;
1480
1481     hres = create_redirect_nschannel(new_url, This->nschannel, &new_channel);
1482     if(SUCCEEDED(hres)) {
1483         hres = create_redirect_callback(new_channel, This, &callback);
1484         nsIChannel_Release(&new_channel->nsIHttpChannel_iface);
1485     }
1486
1487     if(SUCCEEDED(hres)) {
1488         nsres = nsIChannelEventSink_AsyncOnChannelRedirect(sink, (nsIChannel*)&This->nschannel->nsIHttpChannel_iface,
1489                 (nsIChannel*)&callback->nschannel->nsIHttpChannel_iface, REDIRECT_TEMPORARY, /* FIXME */
1490                 &callback->nsIAsyncVerifyRedirectCallback_iface);
1491
1492         if(NS_FAILED(nsres))
1493             FIXME("AsyncOnChannelRedirect failed: %08x\n", hres);
1494         else if(This->nschannel != callback->nschannel)
1495             FIXME("nschannel not updated\n");
1496
1497         nsIAsyncVerifyRedirectCallback_Release(&callback->nsIAsyncVerifyRedirectCallback_iface);
1498     }
1499
1500     nsIChannelEventSink_Release(sink);
1501     return hres;
1502 }
1503
1504 static HRESULT nsChannelBSC_on_progress(BSCallback *bsc, ULONG status_code, LPCWSTR status_text)
1505 {
1506     nsChannelBSC *This = nsChannelBSC_from_BSCallback(bsc);
1507
1508     switch(status_code) {
1509     case BINDSTATUS_MIMETYPEAVAILABLE:
1510         if(!This->nschannel)
1511             return S_OK;
1512
1513         heap_free(This->nschannel->content_type);
1514         This->nschannel->content_type = heap_strdupWtoA(status_text);
1515         break;
1516     case BINDSTATUS_REDIRECTING:
1517         return handle_redirect(This, status_text);
1518     case BINDSTATUS_BEGINDOWNLOADDATA: {
1519         IWinInetHttpInfo *http_info;
1520         DWORD status, size = sizeof(DWORD);
1521         HRESULT hres;
1522
1523         if(!This->bsc.binding)
1524             break;
1525
1526         hres = IBinding_QueryInterface(This->bsc.binding, &IID_IWinInetHttpInfo, (void**)&http_info);
1527         if(FAILED(hres))
1528             break;
1529
1530         hres = IWinInetHttpInfo_QueryInfo(http_info,
1531                 HTTP_QUERY_STATUS_CODE|HTTP_QUERY_FLAG_NUMBER, &status, &size, NULL, NULL);
1532         IWinInetHttpInfo_Release(http_info);
1533         if(FAILED(hres) || status == HTTP_STATUS_OK)
1534             break;
1535
1536         handle_navigation_error(This, status);
1537     }
1538     }
1539
1540     return S_OK;
1541 }
1542
1543 static HRESULT nsChannelBSC_on_response(BSCallback *bsc, DWORD response_code,
1544         LPCWSTR response_headers)
1545 {
1546     nsChannelBSC *This = nsChannelBSC_from_BSCallback(bsc);
1547     HRESULT hres;
1548
1549     This->nschannel->response_status = response_code;
1550
1551     if(response_headers) {
1552         const WCHAR *headers;
1553
1554         headers = strchrW(response_headers, '\r');
1555         if(headers && headers[1] == '\n') {
1556             headers += 2;
1557             hres = process_response_headers(This, headers);
1558             if(FAILED(hres)) {
1559                 WARN("parsing headers failed: %08x\n", hres);
1560                 return hres;
1561             }
1562         }
1563     }
1564
1565     return S_OK;
1566 }
1567
1568 static HRESULT nsChannelBSC_beginning_transaction(BSCallback *bsc, WCHAR **additional_headers)
1569 {
1570     nsChannelBSC *This = nsChannelBSC_from_BSCallback(bsc);
1571     http_header_t *iter;
1572     DWORD len = 0;
1573     WCHAR *ptr;
1574
1575     static const WCHAR content_lengthW[] =
1576         {'C','o','n','t','e','n','t','-','L','e','n','g','t','h',0};
1577
1578     if(!This->nschannel)
1579         return S_FALSE;
1580
1581     LIST_FOR_EACH_ENTRY(iter, &This->nschannel->request_headers, http_header_t, entry) {
1582         if(strcmpW(iter->header, content_lengthW))
1583             len += strlenW(iter->header) + 2 /* ": " */ + strlenW(iter->data) + 2 /* "\r\n" */;
1584     }
1585
1586     if(!len)
1587         return S_OK;
1588
1589     *additional_headers = ptr = CoTaskMemAlloc((len+1)*sizeof(WCHAR));
1590     if(!ptr)
1591         return E_OUTOFMEMORY;
1592
1593     LIST_FOR_EACH_ENTRY(iter, &This->nschannel->request_headers, http_header_t, entry) {
1594         if(!strcmpW(iter->header, content_lengthW))
1595             continue;
1596
1597         len = strlenW(iter->header);
1598         memcpy(ptr, iter->header, len*sizeof(WCHAR));
1599         ptr += len;
1600
1601         *ptr++ = ':';
1602         *ptr++ = ' ';
1603
1604         len = strlenW(iter->data);
1605         memcpy(ptr, iter->data, len*sizeof(WCHAR));
1606         ptr += len;
1607
1608         *ptr++ = '\r';
1609         *ptr++ = '\n';
1610     }
1611
1612     *ptr = 0;
1613
1614     return S_OK;
1615 }
1616
1617 static const BSCallbackVtbl nsChannelBSCVtbl = {
1618     nsChannelBSC_destroy,
1619     nsChannelBSC_init_bindinfo,
1620     nsChannelBSC_start_binding,
1621     nsChannelBSC_stop_binding,
1622     nsChannelBSC_read_data,
1623     nsChannelBSC_on_progress,
1624     nsChannelBSC_on_response,
1625     nsChannelBSC_beginning_transaction
1626 };
1627
1628 HRESULT create_channelbsc(IMoniker *mon, const WCHAR *headers, BYTE *post_data, DWORD post_data_size, nsChannelBSC **retval)
1629 {
1630     nsChannelBSC *ret;
1631
1632     ret = heap_alloc_zero(sizeof(*ret));
1633     if(!ret)
1634         return E_OUTOFMEMORY;
1635
1636     init_bscallback(&ret->bsc, &nsChannelBSCVtbl, mon, BINDF_ASYNCHRONOUS | BINDF_ASYNCSTORAGE | BINDF_PULLDATA);
1637
1638     if(headers) {
1639         ret->bsc.headers = heap_strdupW(headers);
1640         if(!ret->bsc.headers) {
1641             IBindStatusCallback_Release(&ret->bsc.IBindStatusCallback_iface);
1642             return E_OUTOFMEMORY;
1643         }
1644     }
1645
1646     if(post_data) {
1647         ret->bsc.post_data = GlobalAlloc(0, post_data_size);
1648         if(!ret->bsc.post_data) {
1649             heap_free(ret->bsc.headers);
1650             IBindStatusCallback_Release(&ret->bsc.IBindStatusCallback_iface);
1651             return E_OUTOFMEMORY;
1652         }
1653
1654         memcpy(ret->bsc.post_data, post_data, post_data_size);
1655         ret->bsc.post_data_len = post_data_size;
1656     }
1657
1658     *retval = ret;
1659     return S_OK;
1660 }
1661
1662 void set_window_bscallback(HTMLWindow *window, nsChannelBSC *callback)
1663 {
1664     if(window->bscallback) {
1665         if(window->bscallback->bsc.binding)
1666             IBinding_Abort(window->bscallback->bsc.binding);
1667         window->bscallback->bsc.doc = NULL;
1668         window->bscallback->window = NULL;
1669         IBindStatusCallback_Release(&window->bscallback->bsc.IBindStatusCallback_iface);
1670     }
1671
1672     window->bscallback = callback;
1673
1674     if(callback) {
1675         callback->window = window;
1676         IBindStatusCallback_AddRef(&callback->bsc.IBindStatusCallback_iface);
1677         callback->bsc.doc = window->doc;
1678     }
1679 }
1680
1681 typedef struct {
1682     task_t header;
1683     HTMLWindow *window;
1684     nsChannelBSC *bscallback;
1685 } start_doc_binding_task_t;
1686
1687 static void start_doc_binding_proc(task_t *_task)
1688 {
1689     start_doc_binding_task_t *task = (start_doc_binding_task_t*)_task;
1690
1691     start_binding(task->window, NULL, (BSCallback*)task->bscallback, NULL);
1692 }
1693
1694 static void start_doc_binding_task_destr(task_t *_task)
1695 {
1696     start_doc_binding_task_t *task = (start_doc_binding_task_t*)_task;
1697
1698     IBindStatusCallback_Release(&task->bscallback->bsc.IBindStatusCallback_iface);
1699     heap_free(task);
1700 }
1701
1702 HRESULT async_start_doc_binding(HTMLWindow *window, nsChannelBSC *bscallback)
1703 {
1704     start_doc_binding_task_t *task;
1705
1706     TRACE("%p\n", bscallback);
1707
1708     task = heap_alloc(sizeof(start_doc_binding_task_t));
1709     if(!task)
1710         return E_OUTOFMEMORY;
1711
1712     task->window = window;
1713     task->bscallback = bscallback;
1714     IBindStatusCallback_AddRef(&bscallback->bsc.IBindStatusCallback_iface);
1715
1716     push_task(&task->header, start_doc_binding_proc, start_doc_binding_task_destr, window->task_magic);
1717     return S_OK;
1718 }
1719
1720 void abort_document_bindings(HTMLDocumentNode *doc)
1721 {
1722     BSCallback *iter, *next;
1723
1724     LIST_FOR_EACH_ENTRY_SAFE(iter, next, &doc->bindings, BSCallback, entry) {
1725         TRACE("Aborting %p\n", iter);
1726
1727         if(iter->doc)
1728             remove_target_tasks(iter->doc->basedoc.task_magic);
1729
1730         if(iter->binding)
1731             IBinding_Abort(iter->binding);
1732         else {
1733             list_remove(&iter->entry);
1734             list_init(&iter->entry);
1735             iter->vtbl->stop_binding(iter, E_ABORT);
1736         }
1737
1738         iter->doc = NULL;
1739     }
1740 }
1741
1742 HRESULT channelbsc_load_stream(nsChannelBSC *bscallback, IStream *stream)
1743 {
1744     HRESULT hres = S_OK;
1745
1746     if(!bscallback->nschannel) {
1747         ERR("NULL nschannel\n");
1748         return E_FAIL;
1749     }
1750
1751     bscallback->nschannel->content_type = heap_strdupA("text/html");
1752     if(!bscallback->nschannel->content_type)
1753         return E_OUTOFMEMORY;
1754
1755     list_add_head(&bscallback->bsc.doc->bindings, &bscallback->bsc.entry);
1756     if(stream)
1757         hres = read_stream_data(bscallback, stream);
1758     if(SUCCEEDED(hres))
1759         hres = async_stop_request(bscallback);
1760     if(FAILED(hres))
1761         IBindStatusCallback_OnStopBinding(&bscallback->bsc.IBindStatusCallback_iface, hres,
1762                 ERROR_SUCCESS);
1763
1764     return hres;
1765 }
1766
1767 void channelbsc_set_channel(nsChannelBSC *This, nsChannel *channel, nsIStreamListener *listener, nsISupports *context)
1768 {
1769     nsIChannel_AddRef(&channel->nsIHttpChannel_iface);
1770     This->nschannel = channel;
1771
1772     nsIStreamListener_AddRef(listener);
1773     This->nslistener = listener;
1774
1775     if(context) {
1776         nsISupports_AddRef(context);
1777         This->nscontext = context;
1778     }
1779
1780     if(This->bsc.headers) {
1781         HRESULT hres;
1782
1783         hres = parse_headers(This->bsc.headers, &channel->request_headers);
1784         heap_free(This->bsc.headers);
1785         This->bsc.headers = NULL;
1786         if(FAILED(hres))
1787             WARN("parse_headers failed: %08x\n", hres);
1788     }
1789 }
1790
1791 typedef struct {
1792     task_t header;
1793     HTMLWindow *window;
1794     IUri *uri;
1795 } navigate_javascript_task_t;
1796
1797 static void navigate_javascript_proc(task_t *_task)
1798 {
1799     navigate_javascript_task_t *task = (navigate_javascript_task_t*)_task;
1800     HTMLWindow *window = task->window;
1801     VARIANT v;
1802     BSTR code;
1803     HRESULT hres;
1804
1805     static const WCHAR jscriptW[] = {'j','s','c','r','i','p','t',0};
1806
1807     task->window->readystate = READYSTATE_COMPLETE;
1808
1809     hres = IUri_GetPath(task->uri, &code);
1810     if(FAILED(hres))
1811         return;
1812
1813     set_download_state(window->doc_obj, 1);
1814
1815     V_VT(&v) = VT_EMPTY;
1816     hres = exec_script(window, code, jscriptW, &v);
1817     SysFreeString(code);
1818     if(SUCCEEDED(hres) && V_VT(&v) != VT_EMPTY) {
1819         FIXME("javascirpt URL returned %s\n", debugstr_variant(&v));
1820         VariantClear(&v);
1821     }
1822
1823     if(window->doc_obj->view_sink)
1824         IAdviseSink_OnViewChange(window->doc_obj->view_sink, DVASPECT_CONTENT, -1);
1825
1826     set_download_state(window->doc_obj, 0);
1827 }
1828
1829 static void navigate_javascript_task_destr(task_t *_task)
1830 {
1831     navigate_javascript_task_t *task = (navigate_javascript_task_t*)_task;
1832
1833     IUri_Release(task->uri);
1834     heap_free(task);
1835 }
1836
1837 typedef struct {
1838     task_t header;
1839     HTMLWindow *window;
1840     nsChannelBSC *bscallback;
1841     IMoniker *mon;
1842 } navigate_task_t;
1843
1844 static void navigate_proc(task_t *_task)
1845 {
1846     navigate_task_t *task = (navigate_task_t*)_task;
1847     HRESULT hres;
1848
1849     hres = set_moniker(&task->window->doc_obj->basedoc, task->mon, NULL, task->bscallback, TRUE);
1850     if(SUCCEEDED(hres))
1851         start_binding(task->window, NULL, (BSCallback*)task->bscallback, NULL);
1852 }
1853
1854 static void navigate_task_destr(task_t *_task)
1855 {
1856     navigate_task_t *task = (navigate_task_t*)_task;
1857
1858     IUnknown_Release((IUnknown*)task->bscallback);
1859     IMoniker_Release(task->mon);
1860     heap_free(task);
1861 }
1862
1863 static HRESULT navigate_fragment(HTMLWindow *window, IUri *uri)
1864 {
1865     nsIDOMLocation *nslocation;
1866     nsAString nsfrag_str;
1867     BSTR frag;
1868     nsresult nsres;
1869     HRESULT hres;
1870
1871     set_current_uri(window, uri);
1872
1873     nsres = nsIDOMWindow_GetLocation(window->nswindow, &nslocation);
1874     if(FAILED(nsres) || !nslocation)
1875         return E_FAIL;
1876
1877     hres = IUri_GetFragment(uri, &frag);
1878     if(FAILED(hres)) {
1879         nsIDOMLocation_Release(nslocation);
1880         return hres;
1881     }
1882
1883     nsAString_InitDepend(&nsfrag_str, frag);
1884     nsres = nsIDOMLocation_SetHash(nslocation, &nsfrag_str);
1885     nsAString_Finish(&nsfrag_str);
1886     nsIDOMLocation_Release(nslocation);
1887     SysFreeString(frag);
1888     if(NS_FAILED(nsres)) {
1889         ERR("SetHash failed: %08x\n", nsres);
1890         return E_FAIL;
1891     }
1892
1893     if(window->doc_obj->doc_object_service) {
1894         IDocObjectService_FireNavigateComplete2(window->doc_obj->doc_object_service, &window->IHTMLWindow2_iface, 0x10);
1895         IDocObjectService_FireDocumentComplete(window->doc_obj->doc_object_service, &window->IHTMLWindow2_iface, 0);
1896
1897     }
1898
1899     return S_OK;
1900 }
1901
1902 HRESULT super_navigate(HTMLWindow *window, IUri *uri, const WCHAR *headers, BYTE *post_data, DWORD post_data_size)
1903 {
1904     nsChannelBSC *bsc;
1905     IMoniker *mon;
1906     DWORD scheme;
1907     HRESULT hres;
1908
1909     if(window->doc_obj->client) {
1910         IOleCommandTarget *cmdtrg;
1911
1912         hres = IOleClientSite_QueryInterface(window->doc_obj->client, &IID_IOleCommandTarget, (void**)&cmdtrg);
1913         if(SUCCEEDED(hres)) {
1914             VARIANT in, out;
1915             BSTR url_str;
1916
1917             hres = IUri_GetDisplayUri(uri, &url_str);
1918             if(SUCCEEDED(hres)) {
1919                 V_VT(&in) = VT_BSTR;
1920                 V_BSTR(&in) = url_str;
1921                 V_VT(&out) = VT_BOOL;
1922                 V_BOOL(&out) = VARIANT_TRUE;
1923                 hres = IOleCommandTarget_Exec(cmdtrg, &CGID_ShellDocView, 67, 0, &in, &out);
1924                 IOleCommandTarget_Release(cmdtrg);
1925                 if(SUCCEEDED(hres))
1926                     VariantClear(&out);
1927                 SysFreeString(url_str);
1928             }
1929         }
1930     }
1931
1932     if(window->uri && !post_data_size && compare_ignoring_frag(window->uri, uri)) {
1933         TRACE("fragment navigate\n");
1934         return navigate_fragment(window, uri);
1935     }
1936
1937     hres = CreateURLMonikerEx2(NULL, uri, &mon, URL_MK_UNIFORM);
1938     if(FAILED(hres))
1939         return hres;
1940
1941     /* FIXME: Why not set_ready_state? */
1942     window->readystate = READYSTATE_UNINITIALIZED;
1943
1944     hres = create_channelbsc(mon, headers, post_data, post_data_size, &bsc);
1945     if(FAILED(hres)) {
1946         IMoniker_Release(mon);
1947         return hres;
1948     }
1949
1950     prepare_for_binding(&window->doc_obj->basedoc, mon, TRUE);
1951
1952     hres = IUri_GetScheme(uri, &scheme);
1953     if(SUCCEEDED(hres) && scheme != URL_SCHEME_JAVASCRIPT) {
1954         navigate_task_t *task;
1955
1956         task = heap_alloc(sizeof(*task));
1957         if(!task) {
1958             IUnknown_Release((IUnknown*)bsc);
1959             IMoniker_Release(mon);
1960             return E_OUTOFMEMORY;
1961         }
1962
1963         task->window = window;
1964         task->bscallback = bsc;
1965         task->mon = mon;
1966         push_task(&task->header, navigate_proc, navigate_task_destr, window->task_magic);
1967
1968         /* Silently and repeated when real loading starts? */
1969         window->readystate = READYSTATE_LOADING;
1970     }else {
1971         navigate_javascript_task_t *task;
1972
1973         IUnknown_Release((IUnknown*)bsc);
1974         IMoniker_Release(mon);
1975
1976         task = heap_alloc(sizeof(*task));
1977         if(!task)
1978             return E_OUTOFMEMORY;
1979
1980         IUri_AddRef(uri);
1981         task->window = window;
1982         task->uri = uri;
1983         push_task(&task->header, navigate_javascript_proc, navigate_javascript_task_destr, window->task_magic);
1984
1985         /* Why silently? */
1986         window->readystate = READYSTATE_COMPLETE;
1987     }
1988
1989     return S_OK;
1990 }
1991
1992 HRESULT navigate_new_window(HTMLWindow *window, IUri *uri, const WCHAR *name, IHTMLWindow2 **ret)
1993 {
1994     IWebBrowser2 *web_browser;
1995     IHTMLWindow2 *new_window;
1996     IBindCtx *bind_ctx;
1997     nsChannelBSC *bsc;
1998     HRESULT hres;
1999
2000     hres = create_channelbsc(NULL, NULL, NULL, 0, &bsc);
2001     if(FAILED(hres))
2002         return hres;
2003
2004     hres = CreateAsyncBindCtx(0, &bsc->bsc.IBindStatusCallback_iface, NULL, &bind_ctx);
2005     if(FAILED(hres)) {
2006         IBindStatusCallback_Release(&bsc->bsc.IBindStatusCallback_iface);
2007         return hres;
2008     }
2009
2010     hres = CoCreateInstance(&CLSID_InternetExplorer, NULL, CLSCTX_LOCAL_SERVER,
2011             &IID_IWebBrowser2, (void**)&web_browser);
2012     if(SUCCEEDED(hres)) {
2013         ITargetFramePriv2 *target_frame_priv;
2014
2015         hres = IWebBrowser_QueryInterface(web_browser, &IID_ITargetFramePriv2, (void**)&target_frame_priv);
2016         if(SUCCEEDED(hres)) {
2017             hres = ITargetFramePriv2_AggregatedNavigation2(target_frame_priv,
2018                     HLNF_DISABLEWINDOWRESTRICTIONS|HLNF_OPENINNEWWINDOW, bind_ctx, &bsc->bsc.IBindStatusCallback_iface,
2019                     name, uri, emptyW);
2020             ITargetFramePriv2_Release(target_frame_priv);
2021
2022             if(SUCCEEDED(hres))
2023                 hres = do_query_service((IUnknown*)web_browser, &SID_SHTMLWindow, &IID_IHTMLWindow2, (void**)&new_window);
2024         }
2025         if(FAILED(hres)) {
2026             IWebBrowser2_Quit(web_browser);
2027             IWebBrowser2_Release(web_browser);
2028         }
2029     }else {
2030         WARN("Could not create InternetExplorer instance: %08x\n", hres);
2031     }
2032
2033     IBindStatusCallback_Release(&bsc->bsc.IBindStatusCallback_iface);
2034     IBindCtx_Release(bind_ctx);
2035     if(FAILED(hres))
2036         return hres;
2037
2038     IWebBrowser2_put_Visible(web_browser, VARIANT_TRUE);
2039     IWebBrowser2_Release(web_browser);
2040
2041     if(ret)
2042         *ret = new_window;
2043     else
2044         IHTMLWindow2_Release(new_window);
2045     return S_OK;
2046 }
2047
2048 HRESULT hlink_frame_navigate(HTMLDocument *doc, LPCWSTR url, nsChannel *nschannel, DWORD hlnf, BOOL *cancel)
2049 {
2050     IHlinkFrame *hlink_frame;
2051     nsChannelBSC *callback;
2052     IBindCtx *bindctx;
2053     IMoniker *mon;
2054     IHlink *hlink;
2055     HRESULT hres;
2056
2057     *cancel = FALSE;
2058
2059     hres = do_query_service((IUnknown*)doc->doc_obj->client, &IID_IHlinkFrame, &IID_IHlinkFrame,
2060             (void**)&hlink_frame);
2061     if(FAILED(hres))
2062         return S_OK;
2063
2064     hres = create_channelbsc(NULL, NULL, NULL, 0, &callback);
2065     if(FAILED(hres)) {
2066         IHlinkFrame_Release(hlink_frame);
2067         return hres;
2068     }
2069
2070     if(nschannel)
2071         read_post_data_stream(callback, nschannel);
2072
2073     hres = CreateAsyncBindCtx(0, &callback->bsc.IBindStatusCallback_iface, NULL, &bindctx);
2074     if(SUCCEEDED(hres))
2075         hres = CoCreateInstance(&CLSID_StdHlink, NULL, CLSCTX_INPROC_SERVER,
2076                 &IID_IHlink, (LPVOID*)&hlink);
2077
2078     if(SUCCEEDED(hres))
2079         hres = CreateURLMoniker(NULL, url, &mon);
2080
2081     if(SUCCEEDED(hres)) {
2082         IHlink_SetMonikerReference(hlink, HLINKSETF_TARGET, mon, NULL);
2083
2084         if(hlnf & HLNF_OPENINNEWWINDOW) {
2085             static const WCHAR wszBlank[] = {'_','b','l','a','n','k',0};
2086             IHlink_SetTargetFrameName(hlink, wszBlank); /* FIXME */
2087         }
2088
2089         hres = IHlinkFrame_Navigate(hlink_frame, hlnf, bindctx,
2090                 &callback->bsc.IBindStatusCallback_iface, hlink);
2091         IMoniker_Release(mon);
2092         *cancel = hres == S_OK;
2093         hres = S_OK;
2094     }
2095
2096     IHlinkFrame_Release(hlink_frame);
2097     IBindCtx_Release(bindctx);
2098     IBindStatusCallback_Release(&callback->bsc.IBindStatusCallback_iface);
2099     return hres;
2100 }
2101
2102 HRESULT navigate_url(HTMLWindow *window, const WCHAR *new_url, const WCHAR *base_url)
2103 {
2104     WCHAR url[INTERNET_MAX_URL_LENGTH];
2105     nsWineURI *uri;
2106     HRESULT hres;
2107
2108     if(!new_url) {
2109         *url = 0;
2110     }else if(base_url) {
2111         DWORD len = 0;
2112
2113         hres = CoInternetCombineUrl(base_url, new_url, URL_ESCAPE_SPACES_ONLY|URL_DONT_ESCAPE_EXTRA_INFO,
2114                 url, sizeof(url)/sizeof(WCHAR), &len, 0);
2115         if(FAILED(hres))
2116             return hres;
2117     }else {
2118         strcpyW(url, new_url);
2119     }
2120
2121     if(window->doc_obj && window->doc_obj->hostui) {
2122         OLECHAR *translated_url = NULL;
2123
2124         hres = IDocHostUIHandler_TranslateUrl(window->doc_obj->hostui, 0, url,
2125                 &translated_url);
2126         if(hres == S_OK) {
2127             TRACE("%08x %s -> %s\n", hres, debugstr_w(url), debugstr_w(translated_url));
2128             strcpyW(url, translated_url);
2129             CoTaskMemFree(translated_url);
2130         }
2131     }
2132
2133     if(window->doc_obj && window->doc_obj->is_webbrowser && window == window->doc_obj->basedoc.window) {
2134         BOOL cancel = FALSE;
2135         IUri *uri;
2136
2137         hres = IDocObjectService_FireBeforeNavigate2(window->doc_obj->doc_object_service, NULL, url, 0x40,
2138                 NULL, NULL, 0, NULL, TRUE, &cancel);
2139         if(SUCCEEDED(hres) && cancel) {
2140             TRACE("Navigation canceled\n");
2141             return S_OK;
2142         }
2143
2144         hres = CreateUri(url, 0, 0, &uri);
2145         if(FAILED(hres))
2146             return hres;
2147
2148         hres = super_navigate(window, uri, NULL, NULL, 0);
2149         IUri_Release(uri);
2150         return hres;
2151     }
2152
2153     if(window->doc_obj && window == window->doc_obj->basedoc.window) {
2154         BOOL cancel;
2155
2156         hres = hlink_frame_navigate(&window->doc->basedoc, url, NULL, 0, &cancel);
2157         if(FAILED(hres))
2158             return hres;
2159
2160         if(cancel) {
2161             TRACE("Navigation handled by hlink frame\n");
2162             return S_OK;
2163         }
2164     }
2165
2166     hres = create_doc_uri(window, url, &uri);
2167     if(FAILED(hres))
2168         return hres;
2169
2170     hres = load_nsuri(window, uri, NULL, LOAD_FLAGS_NONE);
2171     nsISupports_Release((nsISupports*)uri);
2172     return hres;
2173 }