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