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