mshtml: Don't access BSCallback directly in nsio.c.
[wine] / dlls / mshtml / nsio.c
1 /*
2  * Copyright 2006-2007 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
25 #include "windef.h"
26 #include "winbase.h"
27 #include "winuser.h"
28 #include "winreg.h"
29 #include "ole2.h"
30 #include "shlguid.h"
31 #include "wininet.h"
32 #include "shlwapi.h"
33
34 #include "wine/debug.h"
35 #include "wine/unicode.h"
36
37 #include "mshtml_private.h"
38
39 WINE_DEFAULT_DEBUG_CHANNEL(mshtml);
40
41 #define LOAD_INITIAL_DOCUMENT_URI 0x80000
42
43 #define NS_IOSERVICE_CLASSNAME "nsIOService"
44 #define NS_IOSERVICE_CONTRACTID "@mozilla.org/network/io-service;1"
45
46 static const IID NS_IOSERVICE_CID =
47     {0x9ac9e770, 0x18bc, 0x11d3, {0x93, 0x37, 0x00, 0x10, 0x4b, 0xa0, 0xfd, 0x40}};
48
49 static nsIIOService *nsio = NULL;
50
51 static const WCHAR about_blankW[] = {'a','b','o','u','t',':','b','l','a','n','k',0};
52
53 typedef struct {
54     const nsIWineURIVtbl *lpWineURIVtbl;
55
56     LONG ref;
57
58     nsIURI *uri;
59     NSContainer *container;
60     LPWSTR wine_url;
61     PRBool is_doc_uri;
62     BOOL use_wine_url;
63 } nsURI;
64
65 #define NSURI(x)         ((nsIURI*)            &(x)->lpWineURIVtbl)
66 #define NSWINEURI(x)     ((nsIWineURI*)        &(x)->lpWineURIVtbl)
67
68 static nsresult create_uri(nsIURI*,NSContainer*,nsIWineURI**);
69
70 static BOOL exec_shldocvw_67(HTMLDocument *doc, LPCWSTR url)
71 {
72     IOleCommandTarget *cmdtrg = NULL;
73     HRESULT hres;
74
75     hres = IOleClientSite_QueryInterface(doc->client, &IID_IOleCommandTarget,
76                                          (void**)&cmdtrg);
77     if(SUCCEEDED(hres)) {
78         VARIANT varUrl, varRes;
79
80         V_VT(&varUrl) = VT_BSTR;
81         V_BSTR(&varUrl) = SysAllocString(url);
82         V_VT(&varRes) = VT_BOOL;
83
84         hres = IOleCommandTarget_Exec(cmdtrg, &CGID_ShellDocView, 67, 0, &varUrl, &varRes);
85
86         IOleCommandTarget_Release(cmdtrg);
87         SysFreeString(V_BSTR(&varUrl));
88
89         if(SUCCEEDED(hres) && !V_BOOL(&varRes)) {
90             TRACE("got VARIANT_FALSE, do not load\n");
91             return FALSE;
92         }
93     }
94
95     return TRUE;
96 }
97
98 static BOOL before_async_open(nsChannel *channel, NSContainer *container)
99 {
100     IServiceProvider *service_provider;
101     HTMLDocument *doc = container->doc;
102     DWORD hlnf = 0;
103     LPCWSTR uri;
104     HRESULT hres;
105
106     nsIWineURI_GetWineURL(channel->uri, &uri);
107     if(!uri) {
108         ERR("GetWineURL returned NULL\n");
109         return TRUE;
110     }
111
112     if(!doc) {
113         NSContainer *container_iter = container;
114
115         hlnf = HLNF_OPENINNEWWINDOW;
116         while(!container_iter->doc)
117             container_iter = container_iter->parent;
118         doc = container_iter->doc;
119     }
120
121     if(!doc->client)
122         return TRUE;
123
124     if(!hlnf && !exec_shldocvw_67(doc, uri))
125         return FALSE;
126
127     hres = IOleClientSite_QueryInterface(doc->client, &IID_IServiceProvider,
128                                          (void**)&service_provider);
129     if(SUCCEEDED(hres)) {
130         IHlinkFrame *hlink_frame;
131
132         hres = IServiceProvider_QueryService(service_provider, &IID_IHlinkFrame,
133                                              &IID_IHlinkFrame, (void**)&hlink_frame);
134         IServiceProvider_Release(service_provider);
135         if(SUCCEEDED(hres)) {
136             hlink_frame_navigate(doc, hlink_frame, uri, channel->post_data_stream, hlnf);
137             IHlinkFrame_Release(hlink_frame);
138
139             return FALSE;
140         }
141     }
142
143     return TRUE;
144 }
145
146 #define NSCHANNEL_THIS(iface) DEFINE_THIS(nsChannel, HttpChannel, iface)
147
148 static nsresult NSAPI nsChannel_QueryInterface(nsIHttpChannel *iface, nsIIDRef riid, nsQIResult result)
149 {
150     nsChannel *This = NSCHANNEL_THIS(iface);
151
152     *result = NULL;
153
154     if(IsEqualGUID(&IID_nsISupports, riid)) {
155         TRACE("(%p)->(IID_nsISupports %p)\n", This, result);
156         *result = NSCHANNEL(This);
157     }else if(IsEqualGUID(&IID_nsIRequest, riid)) {
158         TRACE("(%p)->(IID_nsIRequest %p)\n", This, result);
159         *result = NSCHANNEL(This);
160     }else if(IsEqualGUID(&IID_nsIChannel, riid)) {
161         TRACE("(%p)->(IID_nsIChannel %p)\n", This, result);
162         *result = NSCHANNEL(This);
163     }else if(This->http_channel && IsEqualGUID(&IID_nsIHttpChannel, riid)) {
164         TRACE("(%p)->(IID_nsIHttpChannel %p)\n", This, result);
165         *result = NSHTTPCHANNEL(This);
166     }else if(IsEqualGUID(&IID_nsIUploadChannel, riid)) {
167         TRACE("(%p)->(IID_nsIUploadChannel %p)\n", This, result);
168         *result = NSUPCHANNEL(This);
169     }
170
171     if(*result) {
172         nsIChannel_AddRef(NSCHANNEL(This));
173         return NS_OK;
174     }
175
176     TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), result);
177
178     if(This->channel)
179         return nsIChannel_QueryInterface(This->channel, riid, result);
180     return NS_NOINTERFACE;
181 }
182
183 static nsrefcnt NSAPI nsChannel_AddRef(nsIHttpChannel *iface)
184 {
185     nsChannel *This = NSCHANNEL_THIS(iface);
186     nsrefcnt ref = InterlockedIncrement(&This->ref);
187
188     TRACE("(%p) ref=%d\n", This, ref);
189
190     return ref;
191 }
192
193 static nsrefcnt NSAPI nsChannel_Release(nsIHttpChannel *iface)
194 {
195     nsChannel *This = NSCHANNEL_THIS(iface);
196     LONG ref = InterlockedDecrement(&This->ref);
197
198     if(!ref) {
199         nsIWineURI_Release(This->uri);
200         if(This->channel)
201             nsIChannel_Release(This->channel);
202         if(This->http_channel)
203             nsIHttpChannel_Release(This->http_channel);
204         if(This->post_data_stream)
205             nsIInputStream_Release(This->post_data_stream);
206         if(This->load_group)
207             nsILoadGroup_Release(This->load_group);
208         if(This->notif_callback)
209             nsIInterfaceRequestor_Release(This->notif_callback);
210         if(This->original_uri)
211             nsIURI_Release(This->original_uri);
212         heap_free(This->content);
213         heap_free(This->charset);
214         heap_free(This);
215     }
216
217     return ref;
218 }
219
220 static nsresult NSAPI nsChannel_GetName(nsIHttpChannel *iface, nsACString *aName)
221 {
222     nsChannel *This = NSCHANNEL_THIS(iface);
223
224     TRACE("(%p)->(%p)\n", This, aName);
225
226     if(This->channel)
227         return nsIChannel_GetName(This->channel, aName);
228
229     return NS_ERROR_NOT_IMPLEMENTED;
230 }
231
232 static nsresult NSAPI nsChannel_IsPending(nsIHttpChannel *iface, PRBool *_retval)
233 {
234     nsChannel *This = NSCHANNEL_THIS(iface);
235
236     TRACE("(%p)->(%p)\n", This, _retval);
237
238     if(This->channel)
239         return nsIChannel_IsPending(This->channel, _retval);
240
241     FIXME("default action not implemented\n");
242     return NS_ERROR_NOT_IMPLEMENTED;
243 }
244
245 static nsresult NSAPI nsChannel_GetStatus(nsIHttpChannel *iface, nsresult *aStatus)
246 {
247     nsChannel *This = NSCHANNEL_THIS(iface);
248
249     TRACE("(%p)->(%p)\n", This, aStatus);
250
251     if(This->channel)
252         return nsIChannel_GetStatus(This->channel, aStatus);
253
254     TRACE("returning NS_OK\n");
255     return *aStatus = NS_OK;
256 }
257
258 static nsresult NSAPI nsChannel_Cancel(nsIHttpChannel *iface, nsresult aStatus)
259 {
260     nsChannel *This = NSCHANNEL_THIS(iface);
261
262     TRACE("(%p)->(%08x)\n", This, aStatus);
263
264     if(This->channel)
265         return nsIChannel_Cancel(This->channel, aStatus);
266
267     FIXME("default action not implemented\n");
268     return NS_ERROR_NOT_IMPLEMENTED;
269 }
270
271 static nsresult NSAPI nsChannel_Suspend(nsIHttpChannel *iface)
272 {
273     nsChannel *This = NSCHANNEL_THIS(iface);
274
275     TRACE("(%p)\n", This);
276
277     if(This->channel)
278         return nsIChannel_Suspend(This->channel);
279
280     FIXME("default action not implemented\n");
281     return NS_ERROR_NOT_IMPLEMENTED;
282 }
283
284 static nsresult NSAPI nsChannel_Resume(nsIHttpChannel *iface)
285 {
286     nsChannel *This = NSCHANNEL_THIS(iface);
287
288     TRACE("(%p)\n", This);
289
290     if(This->channel)
291         return nsIChannel_Resume(This->channel);
292
293     FIXME("default action not implemented\n");
294     return NS_ERROR_NOT_IMPLEMENTED;
295 }
296
297 static nsresult NSAPI nsChannel_GetLoadGroup(nsIHttpChannel *iface, nsILoadGroup **aLoadGroup)
298 {
299     nsChannel *This = NSCHANNEL_THIS(iface);
300
301     TRACE("(%p)->(%p)\n", This, aLoadGroup);
302
303     if(This->load_group)
304         nsILoadGroup_AddRef(This->load_group);
305
306     *aLoadGroup = This->load_group;
307     return NS_OK;
308 }
309
310 static nsresult NSAPI nsChannel_SetLoadGroup(nsIHttpChannel *iface, nsILoadGroup *aLoadGroup)
311 {
312     nsChannel *This = NSCHANNEL_THIS(iface);
313
314     TRACE("(%p)->(%p)\n", This, aLoadGroup);
315
316     if(This->load_group)
317         nsILoadGroup_Release(This->load_group);
318     if(aLoadGroup)
319         nsILoadGroup_AddRef(aLoadGroup);
320
321     This->load_group = aLoadGroup;
322
323     if(This->channel)
324         return nsIChannel_SetLoadGroup(This->channel, aLoadGroup);
325     return NS_OK;
326 }
327
328 static nsresult NSAPI nsChannel_GetLoadFlags(nsIHttpChannel *iface, nsLoadFlags *aLoadFlags)
329 {
330     nsChannel *This = NSCHANNEL_THIS(iface);
331
332     TRACE("(%p)->(%p)\n", This, aLoadFlags);
333
334     *aLoadFlags = This->load_flags;
335     return NS_OK;
336 }
337
338 static nsresult NSAPI nsChannel_SetLoadFlags(nsIHttpChannel *iface, nsLoadFlags aLoadFlags)
339 {
340     nsChannel *This = NSCHANNEL_THIS(iface);
341
342     TRACE("(%p)->(%08x)\n", This, aLoadFlags);
343
344     This->load_flags = aLoadFlags;
345
346     if(This->channel)
347         return nsIChannel_SetLoadFlags(This->channel, aLoadFlags);
348     return NS_OK;
349 }
350
351 static nsresult NSAPI nsChannel_GetOriginalURI(nsIHttpChannel *iface, nsIURI **aOriginalURI)
352 {
353     nsChannel *This = NSCHANNEL_THIS(iface);
354
355     TRACE("(%p)->(%p)\n", This, aOriginalURI);
356
357     if(This->original_uri)
358         nsIURI_AddRef(This->original_uri);
359
360     *aOriginalURI = This->original_uri;
361     return NS_OK;
362 }
363
364 static nsresult NSAPI nsChannel_SetOriginalURI(nsIHttpChannel *iface, nsIURI *aOriginalURI)
365 {
366     nsChannel *This = NSCHANNEL_THIS(iface);
367
368     TRACE("(%p)->(%p)\n", This, aOriginalURI);
369
370     if(This->original_uri)
371         nsIURI_Release(This->original_uri);
372
373     nsIURI_AddRef(aOriginalURI);
374     This->original_uri = aOriginalURI;
375
376     if(This->channel)
377         return nsIChannel_SetOriginalURI(This->channel, aOriginalURI);
378     return NS_OK;
379 }
380
381 static nsresult NSAPI nsChannel_GetURI(nsIHttpChannel *iface, nsIURI **aURI)
382 {
383     nsChannel *This = NSCHANNEL_THIS(iface);
384
385     TRACE("(%p)->(%p)\n", This, aURI);
386
387     nsIWineURI_AddRef(This->uri);
388     *aURI = (nsIURI*)This->uri;
389
390     return NS_OK;
391 }
392
393 static nsresult NSAPI nsChannel_GetOwner(nsIHttpChannel *iface, nsISupports **aOwner)
394 {
395     nsChannel *This = NSCHANNEL_THIS(iface);
396
397     TRACE("(%p)->(%p)\n", This, aOwner);
398
399     if(This->channel)
400         return nsIChannel_GetOwner(This->channel, aOwner);
401
402     FIXME("default action not implemented\n");
403     return NS_ERROR_NOT_IMPLEMENTED;
404 }
405
406 static nsresult NSAPI nsChannel_SetOwner(nsIHttpChannel *iface, nsISupports *aOwner)
407 {
408     nsChannel *This = NSCHANNEL_THIS(iface);
409
410     TRACE("(%p)->(%p)\n", This, aOwner);
411
412     if(This->channel)
413         return nsIChannel_SetOwner(This->channel, aOwner);
414
415     FIXME("default action not implemented\n");
416     return NS_ERROR_NOT_IMPLEMENTED;
417 }
418
419 static nsresult NSAPI nsChannel_GetNotificationCallbacks(nsIHttpChannel *iface,
420         nsIInterfaceRequestor **aNotificationCallbacks)
421 {
422     nsChannel *This = NSCHANNEL_THIS(iface);
423
424     TRACE("(%p)->(%p)\n", This, aNotificationCallbacks);
425
426     if(This->notif_callback)
427         nsIInterfaceRequestor_AddRef(This->notif_callback);
428     *aNotificationCallbacks = This->notif_callback;
429
430     return NS_OK;
431 }
432
433 static nsresult NSAPI nsChannel_SetNotificationCallbacks(nsIHttpChannel *iface,
434         nsIInterfaceRequestor *aNotificationCallbacks)
435 {
436     nsChannel *This = NSCHANNEL_THIS(iface);
437
438     TRACE("(%p)->(%p)\n", This, aNotificationCallbacks);
439
440     if(This->notif_callback)
441         nsIInterfaceRequestor_Release(This->notif_callback);
442     if(aNotificationCallbacks)
443         nsIInterfaceRequestor_AddRef(aNotificationCallbacks);
444
445     This->notif_callback = aNotificationCallbacks;
446
447     if(This->channel)
448         return nsIChannel_SetNotificationCallbacks(This->channel, aNotificationCallbacks);
449     return NS_OK;
450 }
451
452 static nsresult NSAPI nsChannel_GetSecurityInfo(nsIHttpChannel *iface, nsISupports **aSecurityInfo)
453 {
454     nsChannel *This = NSCHANNEL_THIS(iface);
455
456     TRACE("(%p)->(%p)\n", This, aSecurityInfo);
457
458     if(This->channel)
459         return nsIChannel_GetSecurityInfo(This->channel, aSecurityInfo);
460
461     FIXME("default action not implemented\n");
462     return NS_ERROR_NOT_IMPLEMENTED;
463 }
464
465 static nsresult NSAPI nsChannel_GetContentType(nsIHttpChannel *iface, nsACString *aContentType)
466 {
467     nsChannel *This = NSCHANNEL_THIS(iface);
468
469     TRACE("(%p)->(%p)\n", This, aContentType);
470
471     if(This->content) {
472         nsACString_SetData(aContentType, This->content);
473         return S_OK;
474     }
475
476     if(This->channel)
477         return nsIChannel_GetContentType(This->channel, aContentType);
478
479     TRACE("returning default text/html\n");
480     nsACString_SetData(aContentType, "text/html");
481     return NS_OK;
482 }
483
484 static nsresult NSAPI nsChannel_SetContentType(nsIHttpChannel *iface,
485                                                const nsACString *aContentType)
486 {
487     nsChannel *This = NSCHANNEL_THIS(iface);
488
489     TRACE("(%p)->(%p)\n", This, aContentType);
490
491     if(This->channel)
492         return nsIChannel_SetContentType(This->channel, aContentType);
493
494     FIXME("default action not implemented\n");
495     return NS_ERROR_NOT_IMPLEMENTED;
496 }
497
498 static nsresult NSAPI nsChannel_GetContentCharset(nsIHttpChannel *iface,
499                                                   nsACString *aContentCharset)
500 {
501     nsChannel *This = NSCHANNEL_THIS(iface);
502
503     TRACE("(%p)->(%p)\n", This, aContentCharset);
504
505     if(This->charset) {
506         nsACString_SetData(aContentCharset, This->charset);
507         return NS_OK;
508     }
509
510     if(This->channel) {
511         nsresult nsres = nsIChannel_GetContentCharset(This->channel, aContentCharset);
512         const char *ch;
513         nsACString_GetData(aContentCharset, &ch);
514         return nsres;
515     }
516
517     nsACString_SetData(aContentCharset, "");
518     return NS_OK;
519 }
520
521 static nsresult NSAPI nsChannel_SetContentCharset(nsIHttpChannel *iface,
522                                                   const nsACString *aContentCharset)
523 {
524     nsChannel *This = NSCHANNEL_THIS(iface);
525
526     TRACE("(%p)->(%p)\n", This, aContentCharset);
527
528     if(This->channel)
529         return nsIChannel_SetContentCharset(This->channel, aContentCharset);
530
531     FIXME("default action not implemented\n");
532     return NS_ERROR_NOT_IMPLEMENTED;
533 }
534
535 static nsresult NSAPI nsChannel_GetContentLength(nsIHttpChannel *iface, PRInt32 *aContentLength)
536 {
537     nsChannel *This = NSCHANNEL_THIS(iface);
538
539     TRACE("(%p)->(%p)\n", This, aContentLength);
540
541     if(This->channel)
542         return nsIChannel_GetContentLength(This->channel, aContentLength);
543
544     FIXME("default action not implemented\n");
545     return NS_ERROR_NOT_IMPLEMENTED;
546 }
547
548 static nsresult NSAPI nsChannel_SetContentLength(nsIHttpChannel *iface, PRInt32 aContentLength)
549 {
550     nsChannel *This = NSCHANNEL_THIS(iface);
551
552     TRACE("(%p)->(%d)\n", This, aContentLength);
553
554     if(This->channel)
555         return nsIChannel_SetContentLength(This->channel, aContentLength);
556
557     FIXME("default action not implemented\n");
558     return NS_ERROR_NOT_IMPLEMENTED;
559 }
560
561 static nsresult NSAPI nsChannel_Open(nsIHttpChannel *iface, nsIInputStream **_retval)
562 {
563     nsChannel *This = NSCHANNEL_THIS(iface);
564
565     TRACE("(%p)->(%p)\n", This, _retval);
566
567     if(This->channel)
568         return nsIChannel_Open(This->channel, _retval);
569
570     FIXME("default action not implemented\n");
571     return NS_ERROR_NOT_IMPLEMENTED;
572 }
573
574 static BOOL do_load_from_moniker_hack(nsChannel *This)
575 {
576     nsACString scheme_str;
577     nsresult nsres;
578     BOOL ret = TRUE;
579
580     /* 
581      * We should always load the page from IMoniker, but Wine is not yet
582      * ready for this. This function is a heuristic, that decides which
583      * way of loading is better (Gecko implementation or IMoniker). The
584      * aim is to always return TRUE.
585      */
586
587     /* Load from moniker if there is no Gecko channel available */
588     if(!This->channel)
589         return TRUE;
590
591     nsACString_Init(&scheme_str, NULL);
592     nsres = nsIWineURI_GetScheme(This->uri, &scheme_str);
593
594     if(NS_SUCCEEDED(nsres)) {
595         const char *scheme;
596
597         nsACString_GetData(&scheme_str, &scheme);
598         ret = !strcmp(scheme, "wine") || !strcmp(scheme, "about");
599     }
600
601     nsACString_Finish(&scheme_str);
602     return ret;
603 }
604
605 static HRESULT create_mon_for_nschannel(nsChannel *channel, IMoniker **mon)
606 {
607     nsIWineURI *wine_uri;
608     LPCWSTR wine_url;
609     nsresult nsres;
610     HRESULT hres;
611
612     if(!channel->original_uri) {
613         ERR("original_uri == NULL\n");
614         return E_FAIL;
615     }
616
617     nsres = nsIURI_QueryInterface(channel->original_uri, &IID_nsIWineURI, (void**)&wine_uri);
618     if(NS_FAILED(nsres)) {
619         ERR("Could not get nsIWineURI: %08x\n", nsres);
620         return E_FAIL;
621     }
622
623     nsIWineURI_GetWineURL(wine_uri, &wine_url);
624     nsIWineURI_Release(wine_uri);
625     if(!wine_url) {
626         TRACE("wine_url == NULL\n");
627         return E_FAIL;
628     }
629
630     hres = CreateURLMoniker(NULL, wine_url, mon);
631     if(FAILED(hres))
632         WARN("CreateURLMonikrer failed: %08x\n", hres);
633
634     return hres;
635 }
636
637 static NSContainer *get_nscontainer_from_load_group(nsChannel *This)
638 {
639     NSContainer *container;
640     nsIChannel *channel;
641     nsIRequest *req;
642     nsIWineURI *wine_uri;
643     nsIURI *uri;
644     nsresult nsres;
645
646     nsres = nsILoadGroup_GetDefaultLoadRequest(This->load_group, &req);
647     if(NS_FAILED(nsres)) {
648         ERR("GetDefaultLoadRequest failed: %08x\n", nsres);
649         return NULL;
650     }
651
652     nsres = nsIRequest_QueryInterface(req, &IID_nsIChannel, (void**)&channel);
653     nsIRequest_Release(req);
654     if(NS_FAILED(nsres)) {
655         WARN("Could not get nsIChannel interface: %08x\n", nsres);
656         return NULL;
657     }
658
659     nsres = nsIChannel_GetURI(channel, &uri);
660     nsIChannel_Release(channel);
661     if(NS_FAILED(nsres)) {
662         ERR("GetURI failed: %08x\n", nsres);
663         return NULL;
664     }
665
666     nsres = nsIURI_QueryInterface(uri, &IID_nsIWineURI, (void**)&wine_uri);
667     nsIURI_Release(uri);
668     if(NS_FAILED(nsres)) {
669         TRACE("Could not get nsIWineURI: %08x\n", nsres);
670         return NULL;
671     }
672
673     nsIWineURI_GetNSContainer(wine_uri, &container);
674     nsIWineURI_Release(wine_uri);
675
676     return container;
677 }
678
679 static nsresult async_open_doc_uri(nsChannel *This, NSContainer *container,
680         nsIStreamListener *listener, nsISupports *context, BOOL *open)
681 {
682     IMoniker *mon;
683     HRESULT hres;
684
685     *open = FALSE;
686
687     if(container->bscallback) {
688         channelbsc_set_channel(container->bscallback, This, listener, context);
689
690         if(container->doc && container->doc->mime) {
691             DWORD len;
692
693             heap_free(This->content);
694
695             len = WideCharToMultiByte(CP_ACP, 0, container->doc->mime, -1, NULL, 0, NULL, NULL);
696             This->content = heap_alloc(len);
697             WideCharToMultiByte(CP_ACP, 0, container->doc->mime, -1, This->content, -1, NULL, NULL);
698         }
699
700         if(do_load_from_moniker_hack(This))
701             return WINE_NS_LOAD_FROM_MONIKER;
702     }else  {
703         BOOL cont = before_async_open(This, container);
704
705         if(!cont) {
706             TRACE("canceled\n");
707             return NS_ERROR_UNEXPECTED;
708         }
709
710         if(!container->doc) {
711             return This->channel
712                 ?  nsIChannel_AsyncOpen(This->channel, listener, context)
713                 : NS_ERROR_UNEXPECTED;
714         }
715
716         hres = create_mon_for_nschannel(This, &mon);
717         if(FAILED(hres)) {
718             return NS_ERROR_UNEXPECTED;
719         }
720         set_current_mon(container->doc, mon);
721     }
722
723     *open = TRUE;
724     return NS_OK;
725 }
726
727 static nsresult async_open(nsChannel *This, NSContainer *container, nsIStreamListener *listener,
728         nsISupports *context)
729 {
730     BSCallback *bscallback;
731     IMoniker *mon = NULL;
732     nsresult nsres;
733     task_t *task;
734     HRESULT hres;
735
736     if(This->channel) {
737         if(This->post_data_stream) {
738             nsIUploadChannel *upload_channel;
739
740             nsres = nsIChannel_QueryInterface(This->channel, &IID_nsIUploadChannel,
741                                           (void**)&upload_channel);
742             if(NS_SUCCEEDED(nsres)) {
743                 nsACString empty_string;
744                 nsACString_Init(&empty_string, "");
745
746                 nsres = nsIUploadChannel_SetUploadStream(upload_channel, This->post_data_stream,
747                                                          &empty_string, -1);
748                 nsIUploadChannel_Release(upload_channel);
749                 if(NS_FAILED(nsres))
750                     WARN("SetUploadStream failed: %08x\n", nsres);
751
752                 nsACString_Finish(&empty_string);
753             }
754         }
755
756         nsres = nsIChannel_AsyncOpen(This->channel, listener, context);
757
758         if(mon)
759             IMoniker_Release(mon);
760
761         if(NS_FAILED(nsres) && (This->load_flags & LOAD_INITIAL_DOCUMENT_URI))
762             return WINE_NS_LOAD_FROM_MONIKER;
763         return nsres;
764     }
765
766     TRACE("channel == NULL\n");
767
768     hres = create_mon_for_nschannel(This, &mon);
769     if(FAILED(hres))
770         return NS_ERROR_UNEXPECTED;
771
772     bscallback = create_bscallback(mon);
773     IMoniker_Release(mon);
774
775     channelbsc_set_channel(bscallback, This, listener, context);
776
777     task = heap_alloc(sizeof(task_t));
778
779     task->doc = container->doc;
780     task->task_id = TASK_START_BINDING;
781     task->next = NULL;
782     task->bscallback = bscallback;
783
784     push_task(task);
785
786     return NS_OK;
787 }
788
789 static nsresult NSAPI nsChannel_AsyncOpen(nsIHttpChannel *iface, nsIStreamListener *aListener,
790                                           nsISupports *aContext)
791 {
792     nsChannel *This = NSCHANNEL_THIS(iface);
793     NSContainer *container;
794     PRBool is_doc_uri;
795     BOOL open = TRUE;
796     nsresult nsres = NS_OK;
797
798     TRACE("(%p)->(%p %p)\n", This, aListener, aContext);
799
800     nsIWineURI_GetNSContainer(This->uri, &container);
801
802     if(!container && This->load_group) {
803         container = get_nscontainer_from_load_group(This);
804         if(container)
805             nsIWineURI_SetNSContainer(This->uri, container);
806     }
807
808     if(!container) {
809         TRACE("container = NULL\n");
810         return This->channel
811             ? nsIChannel_AsyncOpen(This->channel, aListener, aContext)
812             : NS_ERROR_UNEXPECTED;
813     }
814
815     nsIWineURI_GetIsDocumentURI(This->uri, &is_doc_uri);
816
817     if(is_doc_uri && (This->load_flags & LOAD_INITIAL_DOCUMENT_URI))
818         nsres = async_open_doc_uri(This, container, aListener, aContext, &open);
819
820     if(open)
821         nsres = async_open(This, container, aListener, aContext);
822
823     nsIWebBrowserChrome_Release(NSWBCHROME(container));
824     return nsres;
825 }
826
827 static nsresult NSAPI nsChannel_GetRequestMethod(nsIHttpChannel *iface, nsACString *aRequestMethod)
828 {
829     nsChannel *This = NSCHANNEL_THIS(iface);
830
831     TRACE("(%p)->(%p)\n", This, aRequestMethod);
832
833     if(This->http_channel)
834         return nsIHttpChannel_GetRequestMethod(This->http_channel, aRequestMethod);
835
836     return NS_ERROR_NOT_IMPLEMENTED;
837 }
838
839 static nsresult NSAPI nsChannel_SetRequestMethod(nsIHttpChannel *iface,
840                                                  const nsACString *aRequestMethod)
841 {
842     nsChannel *This = NSCHANNEL_THIS(iface);
843
844     TRACE("(%p)->(%p)\n", This, aRequestMethod);
845
846     if(This->http_channel)
847         return nsIHttpChannel_SetRequestMethod(This->http_channel, aRequestMethod);
848
849     return NS_ERROR_NOT_IMPLEMENTED;
850 }
851
852 static nsresult NSAPI nsChannel_GetReferrer(nsIHttpChannel *iface, nsIURI **aReferrer)
853 {
854     nsChannel *This = NSCHANNEL_THIS(iface);
855
856     TRACE("(%p)->(%p)\n", This, aReferrer);
857
858     if(This->http_channel)
859         return nsIHttpChannel_GetReferrer(This->http_channel, aReferrer);
860
861     return NS_ERROR_NOT_IMPLEMENTED;
862 }
863
864 static nsresult NSAPI nsChannel_SetReferrer(nsIHttpChannel *iface, nsIURI *aReferrer)
865 {
866     nsChannel *This = NSCHANNEL_THIS(iface);
867
868     TRACE("(%p)->(%p)\n", This, aReferrer);
869
870     if(This->http_channel)
871         return nsIHttpChannel_SetReferrer(This->http_channel, aReferrer);
872
873     return NS_ERROR_NOT_IMPLEMENTED;
874 }
875
876 static nsresult NSAPI nsChannel_GetRequestHeader(nsIHttpChannel *iface,
877          const nsACString *aHeader, nsACString *_retval)
878 {
879     nsChannel *This = NSCHANNEL_THIS(iface);
880
881     TRACE("(%p)->(%p %p)\n", This, aHeader, _retval);
882
883     if(This->http_channel)
884         return nsIHttpChannel_GetRequestHeader(This->http_channel, aHeader, _retval);
885
886     return NS_ERROR_NOT_IMPLEMENTED;
887 }
888
889 static nsresult NSAPI nsChannel_SetRequestHeader(nsIHttpChannel *iface,
890          const nsACString *aHeader, const nsACString *aValue, PRBool aMerge)
891 {
892     nsChannel *This = NSCHANNEL_THIS(iface);
893
894     TRACE("(%p)->(%p %p %x)\n", This, aHeader, aValue, aMerge);
895
896     if(This->http_channel)
897         return nsIHttpChannel_SetRequestHeader(This->http_channel, aHeader, aValue, aMerge);
898
899     return NS_ERROR_NOT_IMPLEMENTED;
900 }
901
902 static nsresult NSAPI nsChannel_VisitRequestHeaders(nsIHttpChannel *iface,
903                                                     nsIHttpHeaderVisitor *aVisitor)
904 {
905     nsChannel *This = NSCHANNEL_THIS(iface);
906
907     TRACE("(%p)->(%p)\n", This, aVisitor);
908
909     if(This->http_channel)
910         return nsIHttpChannel_VisitRequestHeaders(This->http_channel, aVisitor);
911
912     return NS_ERROR_NOT_IMPLEMENTED;
913 }
914
915 static nsresult NSAPI nsChannel_GetAllowPipelining(nsIHttpChannel *iface, PRBool *aAllowPipelining)
916 {
917     nsChannel *This = NSCHANNEL_THIS(iface);
918
919     TRACE("(%p)->(%p)\n", This, aAllowPipelining);
920
921     if(This->http_channel)
922         return nsIHttpChannel_GetAllowPipelining(This->http_channel, aAllowPipelining);
923
924     return NS_ERROR_NOT_IMPLEMENTED;
925 }
926
927 static nsresult NSAPI nsChannel_SetAllowPipelining(nsIHttpChannel *iface, PRBool aAllowPipelining)
928 {
929     nsChannel *This = NSCHANNEL_THIS(iface);
930
931     TRACE("(%p)->(%x)\n", This, aAllowPipelining);
932
933     if(This->http_channel)
934         return nsIHttpChannel_SetAllowPipelining(This->http_channel, aAllowPipelining);
935
936     return NS_ERROR_NOT_IMPLEMENTED;
937 }
938
939 static nsresult NSAPI nsChannel_GetRedirectionLimit(nsIHttpChannel *iface, PRUint32 *aRedirectionLimit)
940 {
941     nsChannel *This = NSCHANNEL_THIS(iface);
942
943     TRACE("(%p)->(%p)\n", This, aRedirectionLimit);
944
945     if(This->http_channel)
946         return nsIHttpChannel_GetRedirectionLimit(This->http_channel, aRedirectionLimit);
947
948     return NS_ERROR_NOT_IMPLEMENTED;
949 }
950
951 static nsresult NSAPI nsChannel_SetRedirectionLimit(nsIHttpChannel *iface, PRUint32 aRedirectionLimit)
952 {
953     nsChannel *This = NSCHANNEL_THIS(iface);
954
955     TRACE("(%p)->(%u)\n", This, aRedirectionLimit);
956
957     if(This->http_channel)
958         return nsIHttpChannel_SetRedirectionLimit(This->http_channel, aRedirectionLimit);
959
960     return NS_ERROR_NOT_IMPLEMENTED;
961 }
962
963 static nsresult NSAPI nsChannel_GetResponseStatus(nsIHttpChannel *iface, PRUint32 *aResponseStatus)
964 {
965     nsChannel *This = NSCHANNEL_THIS(iface);
966
967     TRACE("(%p)->(%p)\n", This, aResponseStatus);
968
969     if(This->http_channel)
970         return nsIHttpChannel_GetResponseStatus(This->http_channel, aResponseStatus);
971
972     return NS_ERROR_NOT_IMPLEMENTED;
973 }
974
975 static nsresult NSAPI nsChannel_GetResponseStatusText(nsIHttpChannel *iface,
976                                                       nsACString *aResponseStatusText)
977 {
978     nsChannel *This = NSCHANNEL_THIS(iface);
979
980     TRACE("(%p)->(%p)\n", This, aResponseStatusText);
981
982     if(This->http_channel)
983         return nsIHttpChannel_GetResponseStatusText(This->http_channel, aResponseStatusText);
984
985     return NS_ERROR_NOT_IMPLEMENTED;
986 }
987
988 static nsresult NSAPI nsChannel_GetRequestSucceeded(nsIHttpChannel *iface,
989                                                     PRBool *aRequestSucceeded)
990 {
991     nsChannel *This = NSCHANNEL_THIS(iface);
992
993     TRACE("(%p)->(%p)\n", This, aRequestSucceeded);
994
995     if(This->http_channel)
996         return nsIHttpChannel_GetRequestSucceeded(This->http_channel, aRequestSucceeded);
997
998     return NS_ERROR_NOT_IMPLEMENTED;
999 }
1000
1001 static nsresult NSAPI nsChannel_GetResponseHeader(nsIHttpChannel *iface,
1002          const nsACString *header, nsACString *_retval)
1003 {
1004     nsChannel *This = NSCHANNEL_THIS(iface);
1005
1006     TRACE("(%p)->(%p %p)\n", This, header, _retval);
1007
1008     if(This->http_channel)
1009         return nsIHttpChannel_GetResponseHeader(This->http_channel, header, _retval);
1010
1011     return NS_ERROR_NOT_IMPLEMENTED;
1012 }
1013
1014 static nsresult NSAPI nsChannel_SetResponseHeader(nsIHttpChannel *iface,
1015         const nsACString *header, const nsACString *value, PRBool merge)
1016 {
1017     nsChannel *This = NSCHANNEL_THIS(iface);
1018
1019     TRACE("(%p)->(%p %p %x)\n", This, header, value, merge);
1020
1021     if(This->http_channel)
1022         return nsIHttpChannel_SetResponseHeader(This->http_channel, header, value, merge);
1023
1024     return NS_ERROR_NOT_IMPLEMENTED;
1025 }
1026
1027 static nsresult NSAPI nsChannel_VisitResponseHeaders(nsIHttpChannel *iface,
1028         nsIHttpHeaderVisitor *aVisitor)
1029 {
1030     nsChannel *This = NSCHANNEL_THIS(iface);
1031
1032     TRACE("(%p)->(%p)\n", This, aVisitor);
1033
1034     if(This->http_channel)
1035         return nsIHttpChannel_VisitResponseHeaders(This->http_channel, aVisitor);
1036
1037     return NS_ERROR_NOT_IMPLEMENTED;
1038 }
1039
1040 static nsresult NSAPI nsChannel_IsNoStoreResponse(nsIHttpChannel *iface, PRBool *_retval)
1041 {
1042     nsChannel *This = NSCHANNEL_THIS(iface);
1043
1044     TRACE("(%p)->(%p)\n", This, _retval);
1045
1046     if(This->http_channel)
1047         return nsIHttpChannel_IsNoStoreResponse(This->http_channel, _retval);
1048
1049     return NS_ERROR_NOT_IMPLEMENTED;
1050 }
1051
1052 static nsresult NSAPI nsChannel_IsNoCacheResponse(nsIHttpChannel *iface, PRBool *_retval)
1053 {
1054     nsChannel *This = NSCHANNEL_THIS(iface);
1055
1056     TRACE("(%p)->(%p)\n", This, _retval);
1057
1058     if(This->http_channel)
1059         return nsIHttpChannel_IsNoCacheResponse(This->http_channel, _retval);
1060
1061     return NS_ERROR_NOT_IMPLEMENTED;
1062 }
1063
1064 #undef NSCHANNEL_THIS
1065
1066 static const nsIHttpChannelVtbl nsChannelVtbl = {
1067     nsChannel_QueryInterface,
1068     nsChannel_AddRef,
1069     nsChannel_Release,
1070     nsChannel_GetName,
1071     nsChannel_IsPending,
1072     nsChannel_GetStatus,
1073     nsChannel_Cancel,
1074     nsChannel_Suspend,
1075     nsChannel_Resume,
1076     nsChannel_GetLoadGroup,
1077     nsChannel_SetLoadGroup,
1078     nsChannel_GetLoadFlags,
1079     nsChannel_SetLoadFlags,
1080     nsChannel_GetOriginalURI,
1081     nsChannel_SetOriginalURI,
1082     nsChannel_GetURI,
1083     nsChannel_GetOwner,
1084     nsChannel_SetOwner,
1085     nsChannel_GetNotificationCallbacks,
1086     nsChannel_SetNotificationCallbacks,
1087     nsChannel_GetSecurityInfo,
1088     nsChannel_GetContentType,
1089     nsChannel_SetContentType,
1090     nsChannel_GetContentCharset,
1091     nsChannel_SetContentCharset,
1092     nsChannel_GetContentLength,
1093     nsChannel_SetContentLength,
1094     nsChannel_Open,
1095     nsChannel_AsyncOpen,
1096     nsChannel_GetRequestMethod,
1097     nsChannel_SetRequestMethod,
1098     nsChannel_GetReferrer,
1099     nsChannel_SetReferrer,
1100     nsChannel_GetRequestHeader,
1101     nsChannel_SetRequestHeader,
1102     nsChannel_VisitRequestHeaders,
1103     nsChannel_GetAllowPipelining,
1104     nsChannel_SetAllowPipelining,
1105     nsChannel_GetRedirectionLimit,
1106     nsChannel_SetRedirectionLimit,
1107     nsChannel_GetResponseStatus,
1108     nsChannel_GetResponseStatusText,
1109     nsChannel_GetRequestSucceeded,
1110     nsChannel_GetResponseHeader,
1111     nsChannel_SetResponseHeader,
1112     nsChannel_VisitResponseHeaders,
1113     nsChannel_IsNoStoreResponse,
1114     nsChannel_IsNoCacheResponse
1115 };
1116
1117 #define NSUPCHANNEL_THIS(iface) DEFINE_THIS(nsChannel, UploadChannel, iface)
1118
1119 static nsresult NSAPI nsUploadChannel_QueryInterface(nsIUploadChannel *iface, nsIIDRef riid,
1120                                                      nsQIResult result)
1121 {
1122     nsChannel *This = NSUPCHANNEL_THIS(iface);
1123     return nsIChannel_QueryInterface(NSCHANNEL(This), riid, result);
1124 }
1125
1126 static nsrefcnt NSAPI nsUploadChannel_AddRef(nsIUploadChannel *iface)
1127 {
1128     nsChannel *This = NSUPCHANNEL_THIS(iface);
1129     return nsIChannel_AddRef(NSCHANNEL(This));
1130 }
1131
1132 static nsrefcnt NSAPI nsUploadChannel_Release(nsIUploadChannel *iface)
1133 {
1134     nsChannel *This = NSUPCHANNEL_THIS(iface);
1135     return nsIChannel_Release(NSCHANNEL(This));
1136 }
1137
1138 static nsresult NSAPI nsUploadChannel_SetUploadStream(nsIUploadChannel *iface,
1139         nsIInputStream *aStream, const nsACString *aContentType, PRInt32 aContentLength)
1140 {
1141     nsChannel *This = NSUPCHANNEL_THIS(iface);
1142     const char *content_type;
1143
1144     TRACE("(%p)->(%p %p %d)\n", This, aStream, aContentType, aContentLength);
1145
1146     if(This->post_data_stream)
1147         nsIInputStream_Release(This->post_data_stream);
1148
1149     if(aContentType) {
1150         nsACString_GetData(aContentType, &content_type);
1151         if(*content_type)
1152             FIXME("Unsupported aContentType argument: %s\n", debugstr_a(content_type));
1153     }
1154
1155     if(aContentLength != -1)
1156         FIXME("Unsupported acontentLength = %d\n", aContentLength);
1157
1158     if(aStream)
1159         nsIInputStream_AddRef(aStream);
1160     This->post_data_stream = aStream;
1161
1162     return NS_OK;
1163 }
1164
1165 static nsresult NSAPI nsUploadChannel_GetUploadStream(nsIUploadChannel *iface,
1166         nsIInputStream **aUploadStream)
1167 {
1168     nsChannel *This = NSUPCHANNEL_THIS(iface);
1169
1170     TRACE("(%p)->(%p)\n", This, aUploadStream);
1171
1172     if(This->post_data_stream)
1173         nsIInputStream_AddRef(This->post_data_stream);
1174
1175     *aUploadStream = This->post_data_stream;
1176     return NS_OK;
1177 }
1178
1179 #undef NSUPCHANNEL_THIS
1180
1181 static const nsIUploadChannelVtbl nsUploadChannelVtbl = {
1182     nsUploadChannel_QueryInterface,
1183     nsUploadChannel_AddRef,
1184     nsUploadChannel_Release,
1185     nsUploadChannel_SetUploadStream,
1186     nsUploadChannel_GetUploadStream
1187 };
1188
1189 #define NSURI_THIS(iface) DEFINE_THIS(nsURI, WineURI, iface)
1190
1191 static nsresult NSAPI nsURI_QueryInterface(nsIWineURI *iface, nsIIDRef riid, nsQIResult result)
1192 {
1193     nsURI *This = NSURI_THIS(iface);
1194
1195     *result = NULL;
1196
1197     if(IsEqualGUID(&IID_nsISupports, riid)) {
1198         TRACE("(%p)->(IID_nsISupports %p)\n", This, result);
1199         *result = NSURI(This);
1200     }else if(IsEqualGUID(&IID_nsIURI, riid)) {
1201         TRACE("(%p)->(IID_nsIURI %p)\n", This, result);
1202         *result = NSURI(This);
1203     }else if(IsEqualGUID(&IID_nsIWineURI, riid)) {
1204         TRACE("(%p)->(IID_nsIWineURI %p)\n", This, result);
1205         *result = NSURI(This);
1206     }
1207
1208     if(*result) {
1209         nsIURI_AddRef(NSURI(This));
1210         return NS_OK;
1211     }
1212
1213     TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), result);
1214     return This->uri ? nsIURI_QueryInterface(This->uri, riid, result) : NS_NOINTERFACE;
1215 }
1216
1217 static nsrefcnt NSAPI nsURI_AddRef(nsIWineURI *iface)
1218 {
1219     nsURI *This = NSURI_THIS(iface);
1220     LONG ref = InterlockedIncrement(&This->ref);
1221
1222     TRACE("(%p) ref=%d\n", This, ref);
1223
1224     return ref;
1225 }
1226
1227 static nsrefcnt NSAPI nsURI_Release(nsIWineURI *iface)
1228 {
1229     nsURI *This = NSURI_THIS(iface);
1230     LONG ref = InterlockedDecrement(&This->ref);
1231
1232     TRACE("(%p) ref=%d\n", This, ref);
1233
1234     if(!ref) {
1235         if(This->container)
1236             nsIWebBrowserChrome_Release(NSWBCHROME(This->container));
1237         if(This->uri)
1238             nsIURI_Release(This->uri);
1239         heap_free(This->wine_url);
1240         heap_free(This);
1241     }
1242
1243     return ref;
1244 }
1245
1246 static nsresult NSAPI nsURI_GetSpec(nsIWineURI *iface, nsACString *aSpec)
1247 {
1248     nsURI *This = NSURI_THIS(iface);
1249
1250     TRACE("(%p)->(%p)\n", This, aSpec);
1251
1252     if(This->use_wine_url) {
1253         char speca[INTERNET_MAX_URL_LENGTH] = "wine:";
1254         WideCharToMultiByte(CP_ACP, 0, This->wine_url, -1, speca+5, sizeof(speca)-5, NULL, NULL);
1255         nsACString_SetData(aSpec, speca);
1256
1257         return NS_OK;
1258     }
1259
1260     if(This->uri)
1261         return nsIURI_GetSpec(This->uri, aSpec);
1262
1263     TRACE("returning error\n");
1264     return NS_ERROR_NOT_IMPLEMENTED;
1265
1266 }
1267
1268 static nsresult NSAPI nsURI_SetSpec(nsIWineURI *iface, const nsACString *aSpec)
1269 {
1270     nsURI *This = NSURI_THIS(iface);
1271
1272     TRACE("(%p)->(%p)\n", This, aSpec);
1273
1274     if(This->uri)
1275         return nsIURI_SetSpec(This->uri, aSpec);
1276
1277     FIXME("default action not implemented\n");
1278     return NS_ERROR_NOT_IMPLEMENTED;
1279 }
1280
1281 static nsresult NSAPI nsURI_GetPrePath(nsIWineURI *iface, nsACString *aPrePath)
1282 {
1283     nsURI *This = NSURI_THIS(iface);
1284
1285     TRACE("(%p)->(%p)\n", This, aPrePath);
1286
1287     if(This->uri)
1288         return nsIURI_GetPrePath(This->uri, aPrePath);
1289
1290     FIXME("default action not implemented\n");
1291     return NS_ERROR_NOT_IMPLEMENTED;
1292 }
1293
1294 static nsresult NSAPI nsURI_GetScheme(nsIWineURI *iface, nsACString *aScheme)
1295 {
1296     nsURI *This = NSURI_THIS(iface);
1297
1298     TRACE("(%p)->(%p)\n", This, aScheme);
1299
1300     if(This->use_wine_url && strcmpW(This->wine_url, about_blankW)) {
1301         /*
1302          * For Gecko we set scheme to unknown so it won't be handled
1303          * as any special case.
1304          */
1305         nsACString_SetData(aScheme, "wine");
1306         return NS_OK;
1307     }
1308
1309     if(This->uri)
1310         return nsIURI_GetScheme(This->uri, aScheme);
1311
1312     TRACE("returning error\n");
1313     return NS_ERROR_NOT_IMPLEMENTED;
1314 }
1315
1316 static nsresult NSAPI nsURI_SetScheme(nsIWineURI *iface, const nsACString *aScheme)
1317 {
1318     nsURI *This = NSURI_THIS(iface);
1319
1320     TRACE("(%p)->(%p)\n", This, aScheme);
1321
1322     if(This->uri)
1323         return nsIURI_SetScheme(This->uri, aScheme);
1324
1325     FIXME("default action not implemented\n");
1326     return NS_ERROR_NOT_IMPLEMENTED;
1327 }
1328
1329 static nsresult NSAPI nsURI_GetUserPass(nsIWineURI *iface, nsACString *aUserPass)
1330 {
1331     nsURI *This = NSURI_THIS(iface);
1332
1333     TRACE("(%p)->(%p)\n", This, aUserPass);
1334
1335     if(This->uri)
1336         return nsIURI_GetUserPass(This->uri, aUserPass);
1337
1338     FIXME("default action not implemented\n");
1339     return NS_ERROR_NOT_IMPLEMENTED;
1340 }
1341
1342 static nsresult NSAPI nsURI_SetUserPass(nsIWineURI *iface, const nsACString *aUserPass)
1343 {
1344     nsURI *This = NSURI_THIS(iface);
1345
1346     TRACE("(%p)->(%p)\n", This, aUserPass);
1347
1348     if(This->uri)
1349         return nsIURI_SetUserPass(This->uri, aUserPass);
1350
1351     FIXME("default action not implemented\n");
1352     return NS_ERROR_NOT_IMPLEMENTED;
1353 }
1354
1355 static nsresult NSAPI nsURI_GetUsername(nsIWineURI *iface, nsACString *aUsername)
1356 {
1357     nsURI *This = NSURI_THIS(iface);
1358
1359     TRACE("(%p)->(%p)\n", This, aUsername);
1360
1361     if(This->uri)
1362         return nsIURI_GetUsername(This->uri, aUsername);
1363
1364     FIXME("default action not implemented\n");
1365     return NS_ERROR_NOT_IMPLEMENTED;
1366 }
1367
1368 static nsresult NSAPI nsURI_SetUsername(nsIWineURI *iface, const nsACString *aUsername)
1369 {
1370     nsURI *This = NSURI_THIS(iface);
1371
1372     TRACE("(%p)->(%p)\n", This, aUsername);
1373
1374     if(This->uri)
1375         return nsIURI_SetUsername(This->uri, aUsername);
1376
1377     FIXME("default action not implemented\n");
1378     return NS_ERROR_NOT_IMPLEMENTED;
1379 }
1380
1381 static nsresult NSAPI nsURI_GetPassword(nsIWineURI *iface, nsACString *aPassword)
1382 {
1383     nsURI *This = NSURI_THIS(iface);
1384
1385     TRACE("(%p)->(%p)\n", This, aPassword);
1386
1387     if(This->uri)
1388         return nsIURI_GetPassword(This->uri, aPassword);
1389
1390     FIXME("default action not implemented\n");
1391     return NS_ERROR_NOT_IMPLEMENTED;
1392 }
1393
1394 static nsresult NSAPI nsURI_SetPassword(nsIWineURI *iface, const nsACString *aPassword)
1395 {
1396     nsURI *This = NSURI_THIS(iface);
1397
1398     TRACE("(%p)->(%p)\n", This, aPassword);
1399
1400     if(This->uri)
1401         return nsIURI_SetPassword(This->uri, aPassword);
1402
1403     FIXME("default action not implemented\n");
1404     return NS_ERROR_NOT_IMPLEMENTED;
1405 }
1406
1407 static nsresult NSAPI nsURI_GetHostPort(nsIWineURI *iface, nsACString *aHostPort)
1408 {
1409     nsURI *This = NSURI_THIS(iface);
1410
1411     TRACE("(%p)->(%p)\n", This, aHostPort);
1412
1413     if(This->uri)
1414         return nsIURI_GetHostPort(This->uri, aHostPort);
1415
1416     FIXME("default action not implemented\n");
1417     return NS_ERROR_NOT_IMPLEMENTED;
1418 }
1419
1420 static nsresult NSAPI nsURI_SetHostPort(nsIWineURI *iface, const nsACString *aHostPort)
1421 {
1422     nsURI *This = NSURI_THIS(iface);
1423
1424     TRACE("(%p)->(%p)\n", This, aHostPort);
1425
1426     if(This->uri)
1427         return nsIURI_SetHostPort(This->uri, aHostPort);
1428
1429     FIXME("default action not implemented\n");
1430     return NS_ERROR_NOT_IMPLEMENTED;
1431 }
1432
1433 static nsresult NSAPI nsURI_GetHost(nsIWineURI *iface, nsACString *aHost)
1434 {
1435     nsURI *This = NSURI_THIS(iface);
1436
1437     TRACE("(%p)->(%p)\n", This, aHost);
1438
1439     if(This->uri)
1440         return nsIURI_GetHost(This->uri, aHost);
1441
1442     FIXME("default action not implemented\n");
1443     return NS_ERROR_NOT_IMPLEMENTED;
1444 }
1445
1446 static nsresult NSAPI nsURI_SetHost(nsIWineURI *iface, const nsACString *aHost)
1447 {
1448     nsURI *This = NSURI_THIS(iface);
1449
1450     TRACE("(%p)->(%p)\n", This, aHost);
1451
1452     if(This->uri)
1453         return nsIURI_SetHost(This->uri, aHost);
1454
1455     FIXME("default action not implemented\n");
1456     return NS_ERROR_NOT_IMPLEMENTED;
1457 }
1458
1459 static nsresult NSAPI nsURI_GetPort(nsIWineURI *iface, PRInt32 *aPort)
1460 {
1461     nsURI *This = NSURI_THIS(iface);
1462
1463     TRACE("(%p)->(%p)\n", This, aPort);
1464
1465     if(This->uri)
1466         return nsIURI_GetPort(This->uri, aPort);
1467
1468     FIXME("default action not implemented\n");
1469     return NS_ERROR_NOT_IMPLEMENTED;
1470 }
1471
1472 static nsresult NSAPI nsURI_SetPort(nsIWineURI *iface, PRInt32 aPort)
1473 {
1474     nsURI *This = NSURI_THIS(iface);
1475
1476     TRACE("(%p)->(%d)\n", This, aPort);
1477
1478     if(This->uri)
1479         return nsIURI_SetPort(This->uri, aPort);
1480
1481     FIXME("default action not implemented\n");
1482     return NS_ERROR_NOT_IMPLEMENTED;
1483 }
1484
1485 static nsresult NSAPI nsURI_GetPath(nsIWineURI *iface, nsACString *aPath)
1486 {
1487     nsURI *This = NSURI_THIS(iface);
1488
1489     TRACE("(%p)->(%p)\n", This, aPath);
1490
1491     if(This->uri)
1492         return nsIURI_GetPath(This->uri, aPath);
1493
1494     FIXME("default action not implemented\n");
1495     return NS_ERROR_NOT_IMPLEMENTED;
1496 }
1497
1498 static nsresult NSAPI nsURI_SetPath(nsIWineURI *iface, const nsACString *aPath)
1499 {
1500     nsURI *This = NSURI_THIS(iface);
1501     const char *path;
1502
1503     nsACString_GetData(aPath, &path);
1504     TRACE("(%p)->(%p(%s))\n", This, aPath, debugstr_a(path));
1505
1506
1507     if(This->wine_url) {
1508         WCHAR new_url[INTERNET_MAX_URL_LENGTH];
1509         DWORD size = sizeof(new_url)/sizeof(WCHAR);
1510         LPWSTR pathw;
1511         HRESULT hres;
1512
1513         pathw = heap_strdupAtoW(path);
1514         hres = UrlCombineW(This->wine_url, pathw, new_url, &size, 0);
1515         heap_free(pathw);
1516         if(SUCCEEDED(hres))
1517             nsIWineURI_SetWineURL(NSWINEURI(This), new_url);
1518         else
1519             WARN("UrlCombine failed: %08x\n", hres);
1520     }
1521
1522     if(!This->uri)
1523         return NS_OK;
1524
1525     return nsIURI_SetPath(This->uri, aPath);
1526 }
1527
1528 static nsresult NSAPI nsURI_Equals(nsIWineURI *iface, nsIURI *other, PRBool *_retval)
1529 {
1530     nsURI *This = NSURI_THIS(iface);
1531     nsIWineURI *wine_uri;
1532     LPCWSTR other_url = NULL;
1533     nsresult nsres;
1534
1535     TRACE("(%p)->(%p %p)\n", This, other, _retval);
1536
1537     if(This->uri)
1538         return nsIURI_Equals(This->uri, other, _retval);
1539
1540     nsres = nsIURI_QueryInterface(other, &IID_nsIWineURI, (void**)&wine_uri);
1541     if(NS_FAILED(nsres)) {
1542         TRACE("Could not get nsIWineURI interface\n");
1543         *_retval = FALSE;
1544         return NS_OK;
1545     }
1546
1547     nsIWineURI_GetWineURL(wine_uri, &other_url);
1548     *_retval = !UrlCompareW(This->wine_url, other_url, TRUE);
1549     nsIWineURI_Release(wine_uri);
1550
1551     return NS_OK;
1552 }
1553
1554 static nsresult NSAPI nsURI_SchemeIs(nsIWineURI *iface, const char *scheme, PRBool *_retval)
1555 {
1556     nsURI *This = NSURI_THIS(iface);
1557
1558     TRACE("(%p)->(%s %p)\n", This, debugstr_a(scheme), _retval);
1559
1560     if(This->use_wine_url) {
1561         WCHAR buf[INTERNET_MAX_SCHEME_LENGTH];
1562         int len = MultiByteToWideChar(CP_ACP, 0, scheme, -1, buf, sizeof(buf)/sizeof(WCHAR))-1;
1563
1564         *_retval = strlenW(This->wine_url) > len
1565             && This->wine_url[len] == ':'
1566             && !memcmp(buf, This->wine_url, len*sizeof(WCHAR));
1567         return NS_OK;
1568     }
1569
1570     if(This->uri)
1571         return nsIURI_SchemeIs(This->uri, scheme, _retval);
1572
1573     TRACE("returning error\n");
1574     return NS_ERROR_NOT_IMPLEMENTED;
1575 }
1576
1577 static nsresult NSAPI nsURI_Clone(nsIWineURI *iface, nsIURI **_retval)
1578 {
1579     nsURI *This = NSURI_THIS(iface);
1580     nsIURI *nsuri = NULL;
1581     nsIWineURI *wine_uri;
1582     nsresult nsres;
1583
1584     TRACE("(%p)->(%p)\n", This, _retval);
1585
1586     if(This->uri) {
1587         nsres = nsIURI_Clone(This->uri, &nsuri);
1588         if(NS_FAILED(nsres)) {
1589             WARN("Clone failed: %08x\n", nsres);
1590             return nsres;
1591         }
1592     }
1593
1594     nsres = create_uri(nsuri, This->container, &wine_uri);
1595     if(NS_FAILED(nsres)) {
1596         WARN("create_uri failed: %08x\n", nsres);
1597         return nsres;
1598     }
1599
1600     *_retval = (nsIURI*)wine_uri;
1601     return nsIWineURI_SetWineURL(wine_uri, This->wine_url);
1602 }
1603
1604 static nsresult NSAPI nsURI_Resolve(nsIWineURI *iface, const nsACString *arelativePath,
1605         nsACString *_retval)
1606 {
1607     nsURI *This = NSURI_THIS(iface);
1608
1609     TRACE("(%p)->(%p %p)\n", This, arelativePath, _retval);
1610
1611     if(This->uri)
1612         return nsIURI_Resolve(This->uri, arelativePath, _retval);
1613
1614     FIXME("default action not implemented\n");
1615     return NS_ERROR_NOT_IMPLEMENTED;
1616 }
1617
1618 static nsresult NSAPI nsURI_GetAsciiSpec(nsIWineURI *iface, nsACString *aAsciiSpec)
1619 {
1620     nsURI *This = NSURI_THIS(iface);
1621
1622     TRACE("(%p)->(%p)\n", This, aAsciiSpec);
1623
1624     if(This->use_wine_url)
1625         return nsIURI_GetSpec(NSURI(This), aAsciiSpec);
1626
1627     if(This->uri)
1628         return nsIURI_GetAsciiSpec(This->uri, aAsciiSpec);
1629
1630     TRACE("returning error\n");
1631     return NS_ERROR_NOT_IMPLEMENTED;
1632 }
1633
1634 static nsresult NSAPI nsURI_GetAsciiHost(nsIWineURI *iface, nsACString *aAsciiHost)
1635 {
1636     nsURI *This = NSURI_THIS(iface);
1637
1638     TRACE("(%p)->(%p)\n", This, aAsciiHost);
1639
1640     if(This->uri)
1641         return nsIURI_GetAsciiHost(This->uri, aAsciiHost);
1642
1643     FIXME("default action not implemented\n");
1644     return NS_ERROR_NOT_IMPLEMENTED;
1645 }
1646
1647 static nsresult NSAPI nsURI_GetOriginCharset(nsIWineURI *iface, nsACString *aOriginCharset)
1648 {
1649     nsURI *This = NSURI_THIS(iface);
1650
1651     TRACE("(%p)->(%p)\n", This, aOriginCharset);
1652
1653     if(This->uri)
1654         return nsIURI_GetOriginCharset(This->uri, aOriginCharset);
1655
1656     FIXME("default action not implemented\n");
1657     return NS_ERROR_NOT_IMPLEMENTED;
1658 }
1659
1660 static nsresult NSAPI nsURI_GetNSContainer(nsIWineURI *iface, NSContainer **aContainer)
1661 {
1662     nsURI *This = NSURI_THIS(iface);
1663
1664     TRACE("(%p)->(%p)\n", This, aContainer);
1665
1666     if(This->container)
1667         nsIWebBrowserChrome_AddRef(NSWBCHROME(This->container));
1668     *aContainer = This->container;
1669
1670     return NS_OK;
1671 }
1672
1673 static nsresult NSAPI nsURI_SetNSContainer(nsIWineURI *iface, NSContainer *aContainer)
1674 {
1675     nsURI *This = NSURI_THIS(iface);
1676
1677     TRACE("(%p)->(%p)\n", This, aContainer);
1678
1679     if(This->container) {
1680         if(This->container == aContainer)
1681             return NS_OK;
1682         TRACE("Changing %p -> %p\n", This->container, aContainer);
1683         nsIWebBrowserChrome_Release(NSWBCHROME(This->container));
1684     }
1685
1686     if(aContainer)
1687         nsIWebBrowserChrome_AddRef(NSWBCHROME(aContainer));
1688     This->container = aContainer;
1689
1690     return NS_OK;
1691 }
1692
1693 static nsresult NSAPI nsURI_GetIsDocumentURI(nsIWineURI *iface, PRBool *aIsDocumentURI)
1694 {
1695     nsURI *This = NSURI_THIS(iface);
1696
1697     TRACE("(%p)->(%p)\n", This, aIsDocumentURI);
1698
1699     *aIsDocumentURI = This->is_doc_uri;
1700     return NS_OK;
1701 }
1702
1703 static nsresult NSAPI nsURI_SetIsDocumentURI(nsIWineURI *iface, PRBool aIsDocumentURI)
1704 {
1705     nsURI *This = NSURI_THIS(iface);
1706
1707     TRACE("(%p)->(%x)\n", This, aIsDocumentURI);
1708
1709     This->is_doc_uri = aIsDocumentURI;
1710     return NS_OK;
1711 }
1712
1713 static nsresult NSAPI nsURI_GetWineURL(nsIWineURI *iface, LPCWSTR *aURL)
1714 {
1715     nsURI *This = NSURI_THIS(iface);
1716
1717     TRACE("(%p)->(%p)\n", This, aURL);
1718
1719     *aURL = This->wine_url;
1720     return NS_OK;
1721 }
1722
1723 static nsresult NSAPI nsURI_SetWineURL(nsIWineURI *iface, LPCWSTR aURL)
1724 {
1725     nsURI *This = NSURI_THIS(iface);
1726
1727     static const WCHAR wszFtp[]   = {'f','t','p',':'};
1728     static const WCHAR wszHttp[]  = {'h','t','t','p',':'};
1729     static const WCHAR wszHttps[] = {'h','t','t','p','s',':'};
1730
1731     TRACE("(%p)->(%s)\n", This, debugstr_w(aURL));
1732
1733     heap_free(This->wine_url);
1734
1735     if(aURL) {
1736         int len = strlenW(aURL)+1;
1737         This->wine_url = heap_alloc(len*sizeof(WCHAR));
1738         memcpy(This->wine_url, aURL, len*sizeof(WCHAR));
1739
1740         /* FIXME: Always use wine url */
1741         This->use_wine_url =
1742                strncmpW(aURL, wszFtp,   sizeof(wszFtp)/sizeof(WCHAR))
1743             && strncmpW(aURL, wszHttp,  sizeof(wszHttp)/sizeof(WCHAR))
1744             && strncmpW(aURL, wszHttps, sizeof(wszHttps)/sizeof(WCHAR));
1745     }else {
1746         This->wine_url = NULL;
1747         This->use_wine_url = FALSE;
1748     }
1749
1750     return NS_OK;
1751 }
1752
1753 #undef NSURI_THIS
1754
1755 static const nsIWineURIVtbl nsWineURIVtbl = {
1756     nsURI_QueryInterface,
1757     nsURI_AddRef,
1758     nsURI_Release,
1759     nsURI_GetSpec,
1760     nsURI_SetSpec,
1761     nsURI_GetPrePath,
1762     nsURI_GetScheme,
1763     nsURI_SetScheme,
1764     nsURI_GetUserPass,
1765     nsURI_SetUserPass,
1766     nsURI_GetUsername,
1767     nsURI_SetUsername,
1768     nsURI_GetPassword,
1769     nsURI_SetPassword,
1770     nsURI_GetHostPort,
1771     nsURI_SetHostPort,
1772     nsURI_GetHost,
1773     nsURI_SetHost,
1774     nsURI_GetPort,
1775     nsURI_SetPort,
1776     nsURI_GetPath,
1777     nsURI_SetPath,
1778     nsURI_Equals,
1779     nsURI_SchemeIs,
1780     nsURI_Clone,
1781     nsURI_Resolve,
1782     nsURI_GetAsciiSpec,
1783     nsURI_GetAsciiHost,
1784     nsURI_GetOriginCharset,
1785     nsURI_GetNSContainer,
1786     nsURI_SetNSContainer,
1787     nsURI_GetIsDocumentURI,
1788     nsURI_SetIsDocumentURI,
1789     nsURI_GetWineURL,
1790     nsURI_SetWineURL
1791 };
1792
1793 static nsresult create_uri(nsIURI *uri, NSContainer *container, nsIWineURI **_retval)
1794 {
1795     nsURI *ret = heap_alloc(sizeof(nsURI));
1796
1797     ret->lpWineURIVtbl = &nsWineURIVtbl;
1798     ret->ref = 1;
1799     ret->uri = uri;
1800     ret->container = container;
1801     ret->wine_url = NULL;
1802     ret->is_doc_uri = FALSE;
1803     ret->use_wine_url = FALSE;
1804
1805     if(container)
1806         nsIWebBrowserChrome_AddRef(NSWBCHROME(container));
1807
1808     TRACE("retval=%p\n", ret);
1809     *_retval = NSWINEURI(ret);
1810     return NS_OK;
1811 }
1812
1813 typedef struct {
1814     const nsIProtocolHandlerVtbl  *lpProtocolHandlerVtbl;
1815
1816     LONG ref;
1817
1818     nsIProtocolHandler *nshandler;
1819 } nsProtocolHandler;
1820
1821 #define NSPROTHANDLER(x)  ((nsIProtocolHandler*)  &(x)->lpProtocolHandlerVtbl)
1822
1823 #define NSPROTHANDLER_THIS(iface) DEFINE_THIS(nsProtocolHandler, ProtocolHandler, iface)
1824
1825 static nsresult NSAPI nsProtocolHandler_QueryInterface(nsIProtocolHandler *iface, nsIIDRef riid,
1826         nsQIResult result)
1827 {
1828     nsProtocolHandler *This = NSPROTHANDLER_THIS(iface);
1829
1830     *result = NULL;
1831
1832     if(IsEqualGUID(&IID_nsISupports, riid)) {
1833         TRACE("(%p)->(IID_nsISupports %p)\n", This, result);
1834         *result = NSPROTHANDLER(This);
1835     }else if(IsEqualGUID(&IID_nsIProtocolHandler, riid)) {
1836         TRACE("(%p)->(IID_nsIProtocolHandler %p)\n", This, result);
1837         *result = NSPROTHANDLER(This);
1838     }else if(IsEqualGUID(&IID_nsIExternalProtocolHandler, riid)) {
1839         TRACE("(%p)->(IID_nsIExternalProtocolHandler %p), returning NULL\n", This, result);
1840         return NS_NOINTERFACE;
1841     }
1842
1843     if(*result) {
1844         nsISupports_AddRef((nsISupports*)*result);
1845         return NS_OK;
1846     }
1847
1848     WARN("(%s %p)\n", debugstr_guid(riid), result);
1849     return NS_NOINTERFACE;
1850 }
1851
1852 static nsrefcnt NSAPI nsProtocolHandler_AddRef(nsIProtocolHandler *iface)
1853 {
1854     nsProtocolHandler *This = NSPROTHANDLER_THIS(iface);
1855     LONG ref = InterlockedIncrement(&This->ref);
1856
1857     TRACE("(%p) ref=%d\n", This, ref);
1858
1859     return ref;
1860 }
1861
1862 static nsrefcnt NSAPI nsProtocolHandler_Release(nsIProtocolHandler *iface)
1863 {
1864     nsProtocolHandler *This = NSPROTHANDLER_THIS(iface);
1865     LONG ref = InterlockedDecrement(&This->ref);
1866
1867     TRACE("(%p) ref=%d\n", This, ref);
1868
1869     if(!ref) {
1870         if(This->nshandler)
1871             nsIProtocolHandler_Release(This->nshandler);
1872         heap_free(This);
1873     }
1874
1875     return ref;
1876 }
1877
1878 static nsresult NSAPI nsProtocolHandler_GetScheme(nsIProtocolHandler *iface, nsACString *aScheme)
1879 {
1880     nsProtocolHandler *This = NSPROTHANDLER_THIS(iface);
1881
1882     TRACE("(%p)->(%p)\n", This, aScheme);
1883
1884     if(This->nshandler)
1885         return nsIProtocolHandler_GetScheme(This->nshandler, aScheme);
1886     return NS_ERROR_NOT_IMPLEMENTED;
1887 }
1888
1889 static nsresult NSAPI nsProtocolHandler_GetDefaultPort(nsIProtocolHandler *iface,
1890         PRInt32 *aDefaultPort)
1891 {
1892     nsProtocolHandler *This = NSPROTHANDLER_THIS(iface);
1893
1894     TRACE("(%p)->(%p)\n", This, aDefaultPort);
1895
1896     if(This->nshandler)
1897         return nsIProtocolHandler_GetDefaultPort(This->nshandler, aDefaultPort);
1898     return NS_ERROR_NOT_IMPLEMENTED;
1899 }
1900
1901 static nsresult NSAPI nsProtocolHandler_GetProtocolFlags(nsIProtocolHandler *iface,
1902                                                          PRUint32 *aProtocolFlags)
1903 {
1904     nsProtocolHandler *This = NSPROTHANDLER_THIS(iface);
1905
1906     TRACE("(%p)->(%p)\n", This, aProtocolFlags);
1907
1908     if(This->nshandler)
1909         return nsIProtocolHandler_GetProtocolFlags(This->nshandler, aProtocolFlags);
1910     return NS_ERROR_NOT_IMPLEMENTED;
1911 }
1912
1913 static nsresult NSAPI nsProtocolHandler_NewURI(nsIProtocolHandler *iface,
1914         const nsACString *aSpec, const char *aOriginCharset, nsIURI *aBaseURI, nsIURI **_retval)
1915 {
1916     nsProtocolHandler *This = NSPROTHANDLER_THIS(iface);
1917
1918     TRACE("((%p)->%p %s %p %p)\n", This, aSpec, debugstr_a(aOriginCharset), aBaseURI, _retval);
1919
1920     if(This->nshandler)
1921         return nsIProtocolHandler_NewURI(This->nshandler, aSpec, aOriginCharset, aBaseURI, _retval);
1922     return NS_ERROR_NOT_IMPLEMENTED;
1923 }
1924
1925 static nsresult NSAPI nsProtocolHandler_NewChannel(nsIProtocolHandler *iface,
1926         nsIURI *aURI, nsIChannel **_retval)
1927 {
1928     nsProtocolHandler *This = NSPROTHANDLER_THIS(iface);
1929
1930     TRACE("(%p)->(%p %p)\n", This, aURI, _retval);
1931
1932     if(This->nshandler)
1933         return nsIProtocolHandler_NewChannel(This->nshandler, aURI, _retval);
1934     return NS_ERROR_NOT_IMPLEMENTED;
1935 }
1936
1937 static nsresult NSAPI nsProtocolHandler_AllowPort(nsIProtocolHandler *iface,
1938         PRInt32 port, const char *scheme, PRBool *_retval)
1939 {
1940     nsProtocolHandler *This = NSPROTHANDLER_THIS(iface);
1941
1942     TRACE("(%p)->(%d %s %p)\n", This, port, debugstr_a(scheme), _retval);
1943
1944     if(This->nshandler)
1945         return nsIProtocolHandler_AllowPort(This->nshandler, port, scheme, _retval);
1946     return NS_ERROR_NOT_IMPLEMENTED;
1947 }
1948
1949 #undef NSPROTHANDLER_THIS
1950
1951 static const nsIProtocolHandlerVtbl nsProtocolHandlerVtbl = {
1952     nsProtocolHandler_QueryInterface,
1953     nsProtocolHandler_AddRef,
1954     nsProtocolHandler_Release,
1955     nsProtocolHandler_GetScheme,
1956     nsProtocolHandler_GetDefaultPort,
1957     nsProtocolHandler_GetProtocolFlags,
1958     nsProtocolHandler_NewURI,
1959     nsProtocolHandler_NewChannel,
1960     nsProtocolHandler_AllowPort
1961 };
1962
1963 static nsIProtocolHandler *create_protocol_handler(nsIProtocolHandler *nshandler)
1964 {
1965     nsProtocolHandler *ret = heap_alloc(sizeof(nsProtocolHandler));
1966
1967     ret->lpProtocolHandlerVtbl = &nsProtocolHandlerVtbl;
1968     ret->ref = 1;
1969     ret->nshandler = nshandler;
1970
1971     return NSPROTHANDLER(ret);
1972 }
1973
1974 static nsresult NSAPI nsIOService_QueryInterface(nsIIOService*,nsIIDRef,nsQIResult);
1975
1976 static nsrefcnt NSAPI nsIOService_AddRef(nsIIOService *iface)
1977 {
1978     return 2;
1979 }
1980
1981 static nsrefcnt NSAPI nsIOService_Release(nsIIOService *iface)
1982 {
1983     return 1;
1984 }
1985
1986 static nsresult NSAPI nsIOService_GetProtocolHandler(nsIIOService *iface, const char *aScheme,
1987                                                      nsIProtocolHandler **_retval)
1988 {
1989     nsIExternalProtocolHandler *nsexthandler;
1990     nsIProtocolHandler *nshandler;
1991     nsresult nsres;
1992
1993     TRACE("(%s %p)\n", debugstr_a(aScheme), _retval);
1994
1995     nsres = nsIIOService_GetProtocolHandler(nsio, aScheme, &nshandler);
1996     if(NS_FAILED(nsres)) {
1997         WARN("GetProtocolHandler failed: %08x\n", nsres);
1998         return nsres;
1999     }
2000
2001     nsres = nsIProtocolHandler_QueryInterface(nshandler, &IID_nsIExternalProtocolHandler,
2002                                               (void**)&nsexthandler);
2003     if(NS_FAILED(nsres)) {
2004         *_retval = nshandler;
2005         return NS_OK;
2006     }
2007
2008     nsIExternalProtocolHandler_Release(nsexthandler);
2009     *_retval = create_protocol_handler(nshandler);
2010     TRACE("return %p\n", *_retval);
2011     return NS_OK;
2012 }
2013
2014 static nsresult NSAPI nsIOService_GetProtocolFlags(nsIIOService *iface, const char *aScheme,
2015                                                     PRUint32 *_retval)
2016 {
2017     TRACE("(%s %p)\n", debugstr_a(aScheme), _retval);
2018     return nsIIOService_GetProtocolFlags(nsio, aScheme, _retval);
2019 }
2020
2021 static BOOL is_gecko_special_uri(const char *spec)
2022 {
2023     static const char chromeW[] = "chrome:";
2024     static const char jarW[] = "jar:";
2025     static const char resourceW[] = "resource:";
2026     static const char javascriptW[] = "javascript:";
2027
2028     return !strncasecmp(spec, chromeW,     sizeof(chromeW)-1)
2029         || !strncasecmp(spec, resourceW,   sizeof(resourceW)-1)
2030         || !strncasecmp(spec, jarW,        sizeof(jarW)-1)
2031         || !strncasecmp(spec, javascriptW, sizeof(javascriptW)-1);
2032 }
2033
2034 static nsresult NSAPI nsIOService_NewURI(nsIIOService *iface, const nsACString *aSpec,
2035         const char *aOriginCharset, nsIURI *aBaseURI, nsIURI **_retval)
2036 {
2037     const char *spec = NULL;
2038     nsACString spec_str;
2039     NSContainer *nscontainer = NULL;
2040     nsIURI *uri = NULL;
2041     LPCWSTR base_wine_url = NULL;
2042     nsIWineURI *base_wine_uri = NULL, *wine_uri;
2043     BOOL is_wine_uri = FALSE;
2044     nsresult nsres;
2045
2046     nsACString_GetData(aSpec, &spec);
2047
2048     TRACE("(%p(%s) %s %p %p)\n", aSpec, debugstr_a(spec), debugstr_a(aOriginCharset),
2049           aBaseURI, _retval);
2050
2051     if(is_gecko_special_uri(spec))
2052         return nsIIOService_NewURI(nsio, aSpec, aOriginCharset, aBaseURI, _retval);
2053
2054     if(!strncmp(spec, "wine:", 5)) {
2055         spec += 5;
2056         is_wine_uri = TRUE;
2057     }
2058
2059     if(aBaseURI) {
2060         nsACString base_uri_str;
2061         const char *base_uri = NULL;
2062
2063         nsACString_Init(&base_uri_str, NULL);
2064
2065         nsres = nsIURI_GetSpec(aBaseURI, &base_uri_str);
2066         if(NS_SUCCEEDED(nsres)) {
2067             nsACString_GetData(&base_uri_str, &base_uri);
2068             TRACE("base_uri=%s\n", debugstr_a(base_uri));
2069         }else {
2070             ERR("GetSpec failed: %08x\n", nsres);
2071         }
2072
2073         nsACString_Finish(&base_uri_str);
2074     }
2075
2076     nsACString_Init(&spec_str, spec);
2077     nsres = nsIIOService_NewURI(nsio, &spec_str, aOriginCharset, aBaseURI, &uri);
2078     nsACString_Finish(&spec_str);
2079     if(NS_FAILED(nsres))
2080         TRACE("NewURI failed: %08x\n", nsres);
2081
2082     if(aBaseURI) {
2083         nsres = nsIURI_QueryInterface(aBaseURI, &IID_nsIWineURI, (void**)&base_wine_uri);
2084         if(NS_SUCCEEDED(nsres)) {
2085             nsIWineURI_GetNSContainer(base_wine_uri, &nscontainer);
2086             nsIWineURI_GetWineURL(base_wine_uri, &base_wine_url);
2087         }else {
2088             TRACE("Could not get base nsIWineURI: %08x\n", nsres);
2089         }
2090     }
2091
2092     TRACE("nscontainer = %p\n", nscontainer);
2093
2094     nsres = create_uri(uri, nscontainer, &wine_uri);
2095     *_retval = (nsIURI*)wine_uri;
2096
2097     if(nscontainer)
2098         nsIWebBrowserChrome_Release(NSWBCHROME(nscontainer));
2099
2100     if(base_wine_url) {
2101         WCHAR url[INTERNET_MAX_URL_LENGTH], rel_url[INTERNET_MAX_URL_LENGTH];
2102         DWORD len;
2103         HRESULT hres;
2104
2105         MultiByteToWideChar(CP_ACP, 0, spec, -1, rel_url, sizeof(rel_url)/sizeof(WCHAR));
2106
2107         hres = CoInternetCombineUrl(base_wine_url, rel_url,
2108                                     URL_ESCAPE_SPACES_ONLY|URL_DONT_ESCAPE_EXTRA_INFO,
2109                                     url, sizeof(url)/sizeof(WCHAR), &len, 0);
2110         if(SUCCEEDED(hres))
2111             nsIWineURI_SetWineURL(wine_uri, url);
2112         else
2113              WARN("CoCombineUrl failed: %08x\n", hres);
2114     }else if(is_wine_uri) {
2115         WCHAR url[INTERNET_MAX_URL_LENGTH];
2116
2117         MultiByteToWideChar(CP_ACP, 0, spec, -1, url, sizeof(url)/sizeof(WCHAR));
2118         nsIWineURI_SetWineURL(wine_uri, url);
2119     }
2120
2121     if(base_wine_uri)
2122         nsIWineURI_Release(base_wine_uri);
2123
2124     return nsres;
2125 }
2126
2127 static nsresult NSAPI nsIOService_NewFileURI(nsIIOService *iface, nsIFile *aFile,
2128                                              nsIURI **_retval)
2129 {
2130     TRACE("(%p %p)\n", aFile, _retval);
2131     return nsIIOService_NewFileURI(nsio, aFile, _retval);
2132 }
2133
2134 static nsresult NSAPI nsIOService_NewChannelFromURI(nsIIOService *iface, nsIURI *aURI,
2135                                                      nsIChannel **_retval)
2136 {
2137     nsIChannel *channel = NULL;
2138     nsChannel *ret;
2139     nsIWineURI *wine_uri;
2140     nsresult nsres;
2141
2142     TRACE("(%p %p)\n", aURI, _retval);
2143
2144     nsres = nsIIOService_NewChannelFromURI(nsio, aURI, &channel);
2145     if(NS_FAILED(nsres) && nsres != NS_ERROR_UNKNOWN_PROTOCOL) {
2146         WARN("NewChannelFromURI failed: %08x\n", nsres);
2147         *_retval = channel;
2148         return nsres;
2149     }
2150
2151     nsres = nsIURI_QueryInterface(aURI, &IID_nsIWineURI, (void**)&wine_uri);
2152     if(NS_FAILED(nsres)) {
2153         WARN("Could not get nsIWineURI: %08x\n", nsres);
2154         *_retval = channel;
2155         return channel ? NS_OK : NS_ERROR_UNEXPECTED;
2156     }
2157
2158     ret = heap_alloc(sizeof(nsChannel));
2159
2160     ret->lpHttpChannelVtbl = &nsChannelVtbl;
2161     ret->lpUploadChannelVtbl = &nsUploadChannelVtbl;
2162     ret->ref = 1;
2163     ret->channel = channel;
2164     ret->http_channel = NULL;
2165     ret->uri = wine_uri;
2166     ret->post_data_stream = NULL;
2167     ret->load_group = NULL;
2168     ret->notif_callback = NULL;
2169     ret->load_flags = 0;
2170     ret->content = NULL;
2171     ret->charset = NULL;
2172
2173     nsIURI_AddRef(aURI);
2174     ret->original_uri = aURI;
2175
2176     if(channel)
2177         nsIChannel_QueryInterface(channel, &IID_nsIHttpChannel, (void**)&ret->http_channel);
2178
2179     *_retval = NSCHANNEL(ret);
2180     return NS_OK;
2181 }
2182
2183 static nsresult NSAPI nsIOService_NewChannel(nsIIOService *iface, const nsACString *aSpec,
2184         const char *aOriginCharset, nsIURI *aBaseURI, nsIChannel **_retval)
2185 {
2186     TRACE("(%p %s %p %p)\n", aSpec, debugstr_a(aOriginCharset), aBaseURI, _retval);
2187     return nsIIOService_NewChannel(nsio, aSpec, aOriginCharset, aBaseURI, _retval);
2188 }
2189
2190 static nsresult NSAPI nsIOService_GetOffline(nsIIOService *iface, PRBool *aOffline)
2191 {
2192     TRACE("(%p)\n", aOffline);
2193     return nsIIOService_GetOffline(nsio, aOffline);
2194 }
2195
2196 static nsresult NSAPI nsIOService_SetOffline(nsIIOService *iface, PRBool aOffline)
2197 {
2198     TRACE("(%x)\n", aOffline);
2199     return nsIIOService_SetOffline(nsio, aOffline);
2200 }
2201
2202 static nsresult NSAPI nsIOService_AllowPort(nsIIOService *iface, PRInt32 aPort,
2203                                              const char *aScheme, PRBool *_retval)
2204 {
2205     TRACE("(%d %s %p)\n", aPort, debugstr_a(aScheme), _retval);
2206     return nsIIOService_AllowPort(nsio, aPort, debugstr_a(aScheme), _retval);
2207 }
2208
2209 static nsresult NSAPI nsIOService_ExtractScheme(nsIIOService *iface, const nsACString *urlString,
2210                                                  nsACString * _retval)
2211 {
2212     TRACE("(%p %p)\n", urlString, _retval);
2213     return nsIIOService_ExtractScheme(nsio, urlString, _retval);
2214 }
2215
2216 static const nsIIOServiceVtbl nsIOServiceVtbl = {
2217     nsIOService_QueryInterface,
2218     nsIOService_AddRef,
2219     nsIOService_Release,
2220     nsIOService_GetProtocolHandler,
2221     nsIOService_GetProtocolFlags,
2222     nsIOService_NewURI,
2223     nsIOService_NewFileURI,
2224     nsIOService_NewChannelFromURI,
2225     nsIOService_NewChannel,
2226     nsIOService_GetOffline,
2227     nsIOService_SetOffline,
2228     nsIOService_AllowPort,
2229     nsIOService_ExtractScheme
2230 };
2231
2232 static nsIIOService nsIOService = { &nsIOServiceVtbl };
2233
2234 static nsresult NSAPI nsNetUtil_QueryInterface(nsINetUtil *iface, nsIIDRef riid,
2235                                                nsQIResult result)
2236 {
2237     return nsIIOService_QueryInterface(&nsIOService, riid, result);
2238 }
2239
2240 static nsrefcnt NSAPI nsNetUtil_AddRef(nsINetUtil *iface)
2241 {
2242     return 2;
2243 }
2244
2245 static nsrefcnt NSAPI nsNetUtil_Release(nsINetUtil *iface)
2246 {
2247     return 1;
2248 }
2249
2250 static nsresult NSAPI nsNetUtil_ParseContentType(nsINetUtil *iface, const nsACString *aTypeHeader,
2251         nsACString *aCharset, PRBool *aHadCharset, nsACString *aContentType)
2252 {
2253     nsINetUtil *net_util;
2254     nsresult nsres;
2255
2256     TRACE("(%p %p %p %p)\n", aTypeHeader, aCharset, aHadCharset, aContentType);
2257
2258     nsres = nsIIOService_QueryInterface(nsio, &IID_nsINetUtil, (void**)&net_util);
2259     if(NS_FAILED(nsres)) {
2260         WARN("Could not get nsINetUtil interface: %08x\n", nsres);
2261         return nsres;
2262     }
2263
2264     nsres = nsINetUtil_ParseContentType(net_util, aTypeHeader, aCharset, aHadCharset, aContentType);
2265
2266     nsINetUtil_Release(net_util);
2267     return nsres;
2268 }
2269
2270 static const nsINetUtilVtbl nsNetUtilVtbl = {
2271     nsNetUtil_QueryInterface,
2272     nsNetUtil_AddRef,
2273     nsNetUtil_Release,
2274     nsNetUtil_ParseContentType
2275 };
2276
2277 static nsINetUtil nsNetUtil = { &nsNetUtilVtbl };
2278
2279 static nsresult NSAPI nsIOService_QueryInterface(nsIIOService *iface, nsIIDRef riid,
2280                                                  nsQIResult result)
2281 {
2282     *result = NULL;
2283
2284     if(IsEqualGUID(&IID_nsISupports, riid))
2285         *result = &nsIOService;
2286     else if(IsEqualGUID(&IID_nsIIOService, riid))
2287         *result = &nsIOService;
2288     else if(IsEqualGUID(&IID_nsINetUtil, riid))
2289         *result = &nsNetUtil;
2290
2291     if(*result) {
2292         nsISupports_AddRef((nsISupports*)*result);
2293         return NS_OK;
2294     }
2295
2296     FIXME("(%s %p)\n", debugstr_guid(riid), result);
2297     return NS_NOINTERFACE;
2298 }
2299
2300 static nsresult NSAPI nsIOServiceFactory_QueryInterface(nsIFactory *iface, nsIIDRef riid,
2301                                                         nsQIResult result)
2302 {
2303     *result = NULL;
2304
2305     if(IsEqualGUID(&IID_nsISupports, riid)) {
2306         TRACE("(IID_nsISupports %p)\n", result);
2307         *result = iface;
2308     }else if(IsEqualGUID(&IID_nsIFactory, riid)) {
2309         TRACE("(IID_nsIFactory %p)\n", result);
2310         *result = iface;
2311     }
2312
2313     if(*result) {
2314         nsIFactory_AddRef(iface);
2315         return NS_OK;
2316     }
2317
2318     WARN("(%s %p)\n", debugstr_guid(riid), result);
2319     return NS_NOINTERFACE;
2320 }
2321
2322 static nsrefcnt NSAPI nsIOServiceFactory_AddRef(nsIFactory *iface)
2323 {
2324     return 2;
2325 }
2326
2327 static nsrefcnt NSAPI nsIOServiceFactory_Release(nsIFactory *iface)
2328 {
2329     return 1;
2330 }
2331
2332 static nsresult NSAPI nsIOServiceFactory_CreateInstance(nsIFactory *iface,
2333         nsISupports *aOuter, const nsIID *iid, void **result)
2334 {
2335     return nsIIOService_QueryInterface(&nsIOService, iid, result);
2336 }
2337
2338 static nsresult NSAPI nsIOServiceFactory_LockFactory(nsIFactory *iface, PRBool lock)
2339 {
2340     WARN("(%x)\n", lock);
2341     return NS_OK;
2342 }
2343
2344 static const nsIFactoryVtbl nsIOServiceFactoryVtbl = {
2345     nsIOServiceFactory_QueryInterface,
2346     nsIOServiceFactory_AddRef,
2347     nsIOServiceFactory_Release,
2348     nsIOServiceFactory_CreateInstance,
2349     nsIOServiceFactory_LockFactory
2350 };
2351
2352 static nsIFactory nsIOServiceFactory = { &nsIOServiceFactoryVtbl };
2353
2354 void init_nsio(nsIComponentManager *component_manager, nsIComponentRegistrar *registrar)
2355 {
2356     nsIFactory *old_factory = NULL;
2357     nsresult nsres;
2358
2359     nsres = nsIComponentManager_GetClassObject(component_manager, &NS_IOSERVICE_CID,
2360                                                &IID_nsIFactory, (void**)&old_factory);
2361     if(NS_FAILED(nsres)) {
2362         ERR("Could not get factory: %08x\n", nsres);
2363         return;
2364     }
2365
2366     nsres = nsIFactory_CreateInstance(old_factory, NULL, &IID_nsIIOService, (void**)&nsio);
2367     if(NS_FAILED(nsres)) {
2368         ERR("Couldn not create nsIOService instance %08x\n", nsres);
2369         nsIFactory_Release(old_factory);
2370         return;
2371     }
2372
2373     nsres = nsIComponentRegistrar_UnregisterFactory(registrar, &NS_IOSERVICE_CID, old_factory);
2374     nsIFactory_Release(old_factory);
2375     if(NS_FAILED(nsres))
2376         ERR("UnregisterFactory failed: %08x\n", nsres);
2377
2378     nsres = nsIComponentRegistrar_RegisterFactory(registrar, &NS_IOSERVICE_CID,
2379             NS_IOSERVICE_CLASSNAME, NS_IOSERVICE_CONTRACTID, &nsIOServiceFactory);
2380     if(NS_FAILED(nsres))
2381         ERR("RegisterFactory failed: %08x\n", nsres);
2382 }