user32: Improve the HiliteMenuItem tests so they reflect actual behaviour on Windows.
[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         nsIChannel_AddRef(NSCHANNEL(This));
689         container->bscallback->nschannel = This;
690
691         nsIStreamListener_AddRef(listener);
692         container->bscallback->nslistener = listener;
693
694         if(context) {
695             nsISupports_AddRef(context);
696             container->bscallback->nscontext = context;
697         }
698
699         if(container->doc && container->doc->mime) {
700             DWORD len;
701
702             heap_free(This->content);
703
704             len = WideCharToMultiByte(CP_ACP, 0, container->doc->mime, -1, NULL, 0, NULL, NULL);
705             This->content = heap_alloc(len);
706             WideCharToMultiByte(CP_ACP, 0, container->doc->mime, -1, This->content, -1, NULL, NULL);
707         }
708
709         if(do_load_from_moniker_hack(This))
710             return WINE_NS_LOAD_FROM_MONIKER;
711     }else  {
712         BOOL cont = before_async_open(This, container);
713
714         if(!cont) {
715             TRACE("canceled\n");
716             return NS_ERROR_UNEXPECTED;
717         }
718
719         if(!container->doc) {
720             return This->channel
721                 ?  nsIChannel_AsyncOpen(This->channel, listener, context)
722                 : NS_ERROR_UNEXPECTED;
723         }
724
725         hres = create_mon_for_nschannel(This, &mon);
726         if(FAILED(hres)) {
727             return NS_ERROR_UNEXPECTED;
728         }
729         set_current_mon(container->doc, mon);
730     }
731
732     *open = TRUE;
733     return NS_OK;
734 }
735
736 static nsresult async_open(nsChannel *This, NSContainer *container, nsIStreamListener *listener,
737         nsISupports *context)
738 {
739     BSCallback *bscallback;
740     IMoniker *mon = NULL;
741     nsresult nsres;
742     task_t *task;
743     HRESULT hres;
744
745     if(This->channel) {
746         if(This->post_data_stream) {
747             nsIUploadChannel *upload_channel;
748
749             nsres = nsIChannel_QueryInterface(This->channel, &IID_nsIUploadChannel,
750                                           (void**)&upload_channel);
751             if(NS_SUCCEEDED(nsres)) {
752                 nsACString empty_string;
753                 nsACString_Init(&empty_string, "");
754
755                 nsres = nsIUploadChannel_SetUploadStream(upload_channel, This->post_data_stream,
756                                                          &empty_string, -1);
757                 nsIUploadChannel_Release(upload_channel);
758                 if(NS_FAILED(nsres))
759                     WARN("SetUploadStream failed: %08x\n", nsres);
760
761                 nsACString_Finish(&empty_string);
762             }
763         }
764
765         nsres = nsIChannel_AsyncOpen(This->channel, listener, context);
766
767         if(mon)
768             IMoniker_Release(mon);
769
770         if(NS_FAILED(nsres) && (This->load_flags & LOAD_INITIAL_DOCUMENT_URI))
771             return WINE_NS_LOAD_FROM_MONIKER;
772         return nsres;
773     }
774
775     TRACE("channel == NULL\n");
776
777     hres = create_mon_for_nschannel(This, &mon);
778     if(FAILED(hres))
779         return NS_ERROR_UNEXPECTED;
780
781     bscallback = create_bscallback(mon);
782     IMoniker_Release(mon);
783
784     nsIChannel_AddRef(NSCHANNEL(This));
785     bscallback->nschannel = This;
786
787     nsIStreamListener_AddRef(listener);
788     bscallback->nslistener = listener;
789
790     if(context) {
791         nsISupports_AddRef(context);
792         bscallback->nscontext = context;
793     }
794
795     task = heap_alloc(sizeof(task_t));
796
797     task->doc = container->doc;
798     task->task_id = TASK_START_BINDING;
799     task->next = NULL;
800     task->bscallback = bscallback;
801
802     push_task(task);
803
804     return NS_OK;
805 }
806
807 static nsresult NSAPI nsChannel_AsyncOpen(nsIHttpChannel *iface, nsIStreamListener *aListener,
808                                           nsISupports *aContext)
809 {
810     nsChannel *This = NSCHANNEL_THIS(iface);
811     NSContainer *container;
812     PRBool is_doc_uri;
813     BOOL open = TRUE;
814     nsresult nsres = NS_OK;
815
816     TRACE("(%p)->(%p %p)\n", This, aListener, aContext);
817
818     nsIWineURI_GetNSContainer(This->uri, &container);
819
820     if(!container && This->load_group) {
821         container = get_nscontainer_from_load_group(This);
822         if(container)
823             nsIWineURI_SetNSContainer(This->uri, container);
824     }
825
826     if(!container) {
827         TRACE("container = NULL\n");
828         return This->channel
829             ? nsIChannel_AsyncOpen(This->channel, aListener, aContext)
830             : NS_ERROR_UNEXPECTED;
831     }
832
833     nsIWineURI_GetIsDocumentURI(This->uri, &is_doc_uri);
834
835     if(is_doc_uri && (This->load_flags & LOAD_INITIAL_DOCUMENT_URI))
836         nsres = async_open_doc_uri(This, container, aListener, aContext, &open);
837
838     if(open)
839         nsres = async_open(This, container, aListener, aContext);
840
841     nsIWebBrowserChrome_Release(NSWBCHROME(container));
842     return nsres;
843 }
844
845 static nsresult NSAPI nsChannel_GetRequestMethod(nsIHttpChannel *iface, nsACString *aRequestMethod)
846 {
847     nsChannel *This = NSCHANNEL_THIS(iface);
848
849     TRACE("(%p)->(%p)\n", This, aRequestMethod);
850
851     if(This->http_channel)
852         return nsIHttpChannel_GetRequestMethod(This->http_channel, aRequestMethod);
853
854     return NS_ERROR_NOT_IMPLEMENTED;
855 }
856
857 static nsresult NSAPI nsChannel_SetRequestMethod(nsIHttpChannel *iface,
858                                                  const nsACString *aRequestMethod)
859 {
860     nsChannel *This = NSCHANNEL_THIS(iface);
861
862     TRACE("(%p)->(%p)\n", This, aRequestMethod);
863
864     if(This->http_channel)
865         return nsIHttpChannel_SetRequestMethod(This->http_channel, aRequestMethod);
866
867     return NS_ERROR_NOT_IMPLEMENTED;
868 }
869
870 static nsresult NSAPI nsChannel_GetReferrer(nsIHttpChannel *iface, nsIURI **aReferrer)
871 {
872     nsChannel *This = NSCHANNEL_THIS(iface);
873
874     TRACE("(%p)->(%p)\n", This, aReferrer);
875
876     if(This->http_channel)
877         return nsIHttpChannel_GetReferrer(This->http_channel, aReferrer);
878
879     return NS_ERROR_NOT_IMPLEMENTED;
880 }
881
882 static nsresult NSAPI nsChannel_SetReferrer(nsIHttpChannel *iface, nsIURI *aReferrer)
883 {
884     nsChannel *This = NSCHANNEL_THIS(iface);
885
886     TRACE("(%p)->(%p)\n", This, aReferrer);
887
888     if(This->http_channel)
889         return nsIHttpChannel_SetReferrer(This->http_channel, aReferrer);
890
891     return NS_ERROR_NOT_IMPLEMENTED;
892 }
893
894 static nsresult NSAPI nsChannel_GetRequestHeader(nsIHttpChannel *iface,
895          const nsACString *aHeader, nsACString *_retval)
896 {
897     nsChannel *This = NSCHANNEL_THIS(iface);
898
899     TRACE("(%p)->(%p %p)\n", This, aHeader, _retval);
900
901     if(This->http_channel)
902         return nsIHttpChannel_GetRequestHeader(This->http_channel, aHeader, _retval);
903
904     return NS_ERROR_NOT_IMPLEMENTED;
905 }
906
907 static nsresult NSAPI nsChannel_SetRequestHeader(nsIHttpChannel *iface,
908          const nsACString *aHeader, const nsACString *aValue, PRBool aMerge)
909 {
910     nsChannel *This = NSCHANNEL_THIS(iface);
911
912     TRACE("(%p)->(%p %p %x)\n", This, aHeader, aValue, aMerge);
913
914     if(This->http_channel)
915         return nsIHttpChannel_SetRequestHeader(This->http_channel, aHeader, aValue, aMerge);
916
917     return NS_ERROR_NOT_IMPLEMENTED;
918 }
919
920 static nsresult NSAPI nsChannel_VisitRequestHeaders(nsIHttpChannel *iface,
921                                                     nsIHttpHeaderVisitor *aVisitor)
922 {
923     nsChannel *This = NSCHANNEL_THIS(iface);
924
925     TRACE("(%p)->(%p)\n", This, aVisitor);
926
927     if(This->http_channel)
928         return nsIHttpChannel_VisitRequestHeaders(This->http_channel, aVisitor);
929
930     return NS_ERROR_NOT_IMPLEMENTED;
931 }
932
933 static nsresult NSAPI nsChannel_GetAllowPipelining(nsIHttpChannel *iface, PRBool *aAllowPipelining)
934 {
935     nsChannel *This = NSCHANNEL_THIS(iface);
936
937     TRACE("(%p)->(%p)\n", This, aAllowPipelining);
938
939     if(This->http_channel)
940         return nsIHttpChannel_GetAllowPipelining(This->http_channel, aAllowPipelining);
941
942     return NS_ERROR_NOT_IMPLEMENTED;
943 }
944
945 static nsresult NSAPI nsChannel_SetAllowPipelining(nsIHttpChannel *iface, PRBool aAllowPipelining)
946 {
947     nsChannel *This = NSCHANNEL_THIS(iface);
948
949     TRACE("(%p)->(%x)\n", This, aAllowPipelining);
950
951     if(This->http_channel)
952         return nsIHttpChannel_SetAllowPipelining(This->http_channel, aAllowPipelining);
953
954     return NS_ERROR_NOT_IMPLEMENTED;
955 }
956
957 static nsresult NSAPI nsChannel_GetRedirectionLimit(nsIHttpChannel *iface, PRUint32 *aRedirectionLimit)
958 {
959     nsChannel *This = NSCHANNEL_THIS(iface);
960
961     TRACE("(%p)->(%p)\n", This, aRedirectionLimit);
962
963     if(This->http_channel)
964         return nsIHttpChannel_GetRedirectionLimit(This->http_channel, aRedirectionLimit);
965
966     return NS_ERROR_NOT_IMPLEMENTED;
967 }
968
969 static nsresult NSAPI nsChannel_SetRedirectionLimit(nsIHttpChannel *iface, PRUint32 aRedirectionLimit)
970 {
971     nsChannel *This = NSCHANNEL_THIS(iface);
972
973     TRACE("(%p)->(%u)\n", This, aRedirectionLimit);
974
975     if(This->http_channel)
976         return nsIHttpChannel_SetRedirectionLimit(This->http_channel, aRedirectionLimit);
977
978     return NS_ERROR_NOT_IMPLEMENTED;
979 }
980
981 static nsresult NSAPI nsChannel_GetResponseStatus(nsIHttpChannel *iface, PRUint32 *aResponseStatus)
982 {
983     nsChannel *This = NSCHANNEL_THIS(iface);
984
985     TRACE("(%p)->(%p)\n", This, aResponseStatus);
986
987     if(This->http_channel)
988         return nsIHttpChannel_GetResponseStatus(This->http_channel, aResponseStatus);
989
990     return NS_ERROR_NOT_IMPLEMENTED;
991 }
992
993 static nsresult NSAPI nsChannel_GetResponseStatusText(nsIHttpChannel *iface,
994                                                       nsACString *aResponseStatusText)
995 {
996     nsChannel *This = NSCHANNEL_THIS(iface);
997
998     TRACE("(%p)->(%p)\n", This, aResponseStatusText);
999
1000     if(This->http_channel)
1001         return nsIHttpChannel_GetResponseStatusText(This->http_channel, aResponseStatusText);
1002
1003     return NS_ERROR_NOT_IMPLEMENTED;
1004 }
1005
1006 static nsresult NSAPI nsChannel_GetRequestSucceeded(nsIHttpChannel *iface,
1007                                                     PRBool *aRequestSucceeded)
1008 {
1009     nsChannel *This = NSCHANNEL_THIS(iface);
1010
1011     TRACE("(%p)->(%p)\n", This, aRequestSucceeded);
1012
1013     if(This->http_channel)
1014         return nsIHttpChannel_GetRequestSucceeded(This->http_channel, aRequestSucceeded);
1015
1016     return NS_ERROR_NOT_IMPLEMENTED;
1017 }
1018
1019 static nsresult NSAPI nsChannel_GetResponseHeader(nsIHttpChannel *iface,
1020          const nsACString *header, nsACString *_retval)
1021 {
1022     nsChannel *This = NSCHANNEL_THIS(iface);
1023
1024     TRACE("(%p)->(%p %p)\n", This, header, _retval);
1025
1026     if(This->http_channel)
1027         return nsIHttpChannel_GetResponseHeader(This->http_channel, header, _retval);
1028
1029     return NS_ERROR_NOT_IMPLEMENTED;
1030 }
1031
1032 static nsresult NSAPI nsChannel_SetResponseHeader(nsIHttpChannel *iface,
1033         const nsACString *header, const nsACString *value, PRBool merge)
1034 {
1035     nsChannel *This = NSCHANNEL_THIS(iface);
1036
1037     TRACE("(%p)->(%p %p %x)\n", This, header, value, merge);
1038
1039     if(This->http_channel)
1040         return nsIHttpChannel_SetResponseHeader(This->http_channel, header, value, merge);
1041
1042     return NS_ERROR_NOT_IMPLEMENTED;
1043 }
1044
1045 static nsresult NSAPI nsChannel_VisitResponseHeaders(nsIHttpChannel *iface,
1046         nsIHttpHeaderVisitor *aVisitor)
1047 {
1048     nsChannel *This = NSCHANNEL_THIS(iface);
1049
1050     TRACE("(%p)->(%p)\n", This, aVisitor);
1051
1052     if(This->http_channel)
1053         return nsIHttpChannel_VisitResponseHeaders(This->http_channel, aVisitor);
1054
1055     return NS_ERROR_NOT_IMPLEMENTED;
1056 }
1057
1058 static nsresult NSAPI nsChannel_IsNoStoreResponse(nsIHttpChannel *iface, PRBool *_retval)
1059 {
1060     nsChannel *This = NSCHANNEL_THIS(iface);
1061
1062     TRACE("(%p)->(%p)\n", This, _retval);
1063
1064     if(This->http_channel)
1065         return nsIHttpChannel_IsNoStoreResponse(This->http_channel, _retval);
1066
1067     return NS_ERROR_NOT_IMPLEMENTED;
1068 }
1069
1070 static nsresult NSAPI nsChannel_IsNoCacheResponse(nsIHttpChannel *iface, PRBool *_retval)
1071 {
1072     nsChannel *This = NSCHANNEL_THIS(iface);
1073
1074     TRACE("(%p)->(%p)\n", This, _retval);
1075
1076     if(This->http_channel)
1077         return nsIHttpChannel_IsNoCacheResponse(This->http_channel, _retval);
1078
1079     return NS_ERROR_NOT_IMPLEMENTED;
1080 }
1081
1082 #undef NSCHANNEL_THIS
1083
1084 static const nsIHttpChannelVtbl nsChannelVtbl = {
1085     nsChannel_QueryInterface,
1086     nsChannel_AddRef,
1087     nsChannel_Release,
1088     nsChannel_GetName,
1089     nsChannel_IsPending,
1090     nsChannel_GetStatus,
1091     nsChannel_Cancel,
1092     nsChannel_Suspend,
1093     nsChannel_Resume,
1094     nsChannel_GetLoadGroup,
1095     nsChannel_SetLoadGroup,
1096     nsChannel_GetLoadFlags,
1097     nsChannel_SetLoadFlags,
1098     nsChannel_GetOriginalURI,
1099     nsChannel_SetOriginalURI,
1100     nsChannel_GetURI,
1101     nsChannel_GetOwner,
1102     nsChannel_SetOwner,
1103     nsChannel_GetNotificationCallbacks,
1104     nsChannel_SetNotificationCallbacks,
1105     nsChannel_GetSecurityInfo,
1106     nsChannel_GetContentType,
1107     nsChannel_SetContentType,
1108     nsChannel_GetContentCharset,
1109     nsChannel_SetContentCharset,
1110     nsChannel_GetContentLength,
1111     nsChannel_SetContentLength,
1112     nsChannel_Open,
1113     nsChannel_AsyncOpen,
1114     nsChannel_GetRequestMethod,
1115     nsChannel_SetRequestMethod,
1116     nsChannel_GetReferrer,
1117     nsChannel_SetReferrer,
1118     nsChannel_GetRequestHeader,
1119     nsChannel_SetRequestHeader,
1120     nsChannel_VisitRequestHeaders,
1121     nsChannel_GetAllowPipelining,
1122     nsChannel_SetAllowPipelining,
1123     nsChannel_GetRedirectionLimit,
1124     nsChannel_SetRedirectionLimit,
1125     nsChannel_GetResponseStatus,
1126     nsChannel_GetResponseStatusText,
1127     nsChannel_GetRequestSucceeded,
1128     nsChannel_GetResponseHeader,
1129     nsChannel_SetResponseHeader,
1130     nsChannel_VisitResponseHeaders,
1131     nsChannel_IsNoStoreResponse,
1132     nsChannel_IsNoCacheResponse
1133 };
1134
1135 #define NSUPCHANNEL_THIS(iface) DEFINE_THIS(nsChannel, UploadChannel, iface)
1136
1137 static nsresult NSAPI nsUploadChannel_QueryInterface(nsIUploadChannel *iface, nsIIDRef riid,
1138                                                      nsQIResult result)
1139 {
1140     nsChannel *This = NSUPCHANNEL_THIS(iface);
1141     return nsIChannel_QueryInterface(NSCHANNEL(This), riid, result);
1142 }
1143
1144 static nsrefcnt NSAPI nsUploadChannel_AddRef(nsIUploadChannel *iface)
1145 {
1146     nsChannel *This = NSUPCHANNEL_THIS(iface);
1147     return nsIChannel_AddRef(NSCHANNEL(This));
1148 }
1149
1150 static nsrefcnt NSAPI nsUploadChannel_Release(nsIUploadChannel *iface)
1151 {
1152     nsChannel *This = NSUPCHANNEL_THIS(iface);
1153     return nsIChannel_Release(NSCHANNEL(This));
1154 }
1155
1156 static nsresult NSAPI nsUploadChannel_SetUploadStream(nsIUploadChannel *iface,
1157         nsIInputStream *aStream, const nsACString *aContentType, PRInt32 aContentLength)
1158 {
1159     nsChannel *This = NSUPCHANNEL_THIS(iface);
1160     const char *content_type;
1161
1162     TRACE("(%p)->(%p %p %d)\n", This, aStream, aContentType, aContentLength);
1163
1164     if(This->post_data_stream)
1165         nsIInputStream_Release(This->post_data_stream);
1166
1167     if(aContentType) {
1168         nsACString_GetData(aContentType, &content_type);
1169         if(*content_type)
1170             FIXME("Unsupported aContentType argument: %s\n", debugstr_a(content_type));
1171     }
1172
1173     if(aContentLength != -1)
1174         FIXME("Unsupported acontentLength = %d\n", aContentLength);
1175
1176     if(aStream)
1177         nsIInputStream_AddRef(aStream);
1178     This->post_data_stream = aStream;
1179
1180     return NS_OK;
1181 }
1182
1183 static nsresult NSAPI nsUploadChannel_GetUploadStream(nsIUploadChannel *iface,
1184         nsIInputStream **aUploadStream)
1185 {
1186     nsChannel *This = NSUPCHANNEL_THIS(iface);
1187
1188     TRACE("(%p)->(%p)\n", This, aUploadStream);
1189
1190     if(This->post_data_stream)
1191         nsIInputStream_AddRef(This->post_data_stream);
1192
1193     *aUploadStream = This->post_data_stream;
1194     return NS_OK;
1195 }
1196
1197 #undef NSUPCHANNEL_THIS
1198
1199 static const nsIUploadChannelVtbl nsUploadChannelVtbl = {
1200     nsUploadChannel_QueryInterface,
1201     nsUploadChannel_AddRef,
1202     nsUploadChannel_Release,
1203     nsUploadChannel_SetUploadStream,
1204     nsUploadChannel_GetUploadStream
1205 };
1206
1207 #define NSURI_THIS(iface) DEFINE_THIS(nsURI, WineURI, iface)
1208
1209 static nsresult NSAPI nsURI_QueryInterface(nsIWineURI *iface, nsIIDRef riid, nsQIResult result)
1210 {
1211     nsURI *This = NSURI_THIS(iface);
1212
1213     *result = NULL;
1214
1215     if(IsEqualGUID(&IID_nsISupports, riid)) {
1216         TRACE("(%p)->(IID_nsISupports %p)\n", This, result);
1217         *result = NSURI(This);
1218     }else if(IsEqualGUID(&IID_nsIURI, riid)) {
1219         TRACE("(%p)->(IID_nsIURI %p)\n", This, result);
1220         *result = NSURI(This);
1221     }else if(IsEqualGUID(&IID_nsIWineURI, riid)) {
1222         TRACE("(%p)->(IID_nsIWineURI %p)\n", This, result);
1223         *result = NSURI(This);
1224     }
1225
1226     if(*result) {
1227         nsIURI_AddRef(NSURI(This));
1228         return NS_OK;
1229     }
1230
1231     TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), result);
1232     return This->uri ? nsIURI_QueryInterface(This->uri, riid, result) : NS_NOINTERFACE;
1233 }
1234
1235 static nsrefcnt NSAPI nsURI_AddRef(nsIWineURI *iface)
1236 {
1237     nsURI *This = NSURI_THIS(iface);
1238     LONG ref = InterlockedIncrement(&This->ref);
1239
1240     TRACE("(%p) ref=%d\n", This, ref);
1241
1242     return ref;
1243 }
1244
1245 static nsrefcnt NSAPI nsURI_Release(nsIWineURI *iface)
1246 {
1247     nsURI *This = NSURI_THIS(iface);
1248     LONG ref = InterlockedDecrement(&This->ref);
1249
1250     TRACE("(%p) ref=%d\n", This, ref);
1251
1252     if(!ref) {
1253         if(This->container)
1254             nsIWebBrowserChrome_Release(NSWBCHROME(This->container));
1255         if(This->uri)
1256             nsIURI_Release(This->uri);
1257         heap_free(This->wine_url);
1258         heap_free(This);
1259     }
1260
1261     return ref;
1262 }
1263
1264 static nsresult NSAPI nsURI_GetSpec(nsIWineURI *iface, nsACString *aSpec)
1265 {
1266     nsURI *This = NSURI_THIS(iface);
1267
1268     TRACE("(%p)->(%p)\n", This, aSpec);
1269
1270     if(This->use_wine_url) {
1271         char speca[INTERNET_MAX_URL_LENGTH] = "wine:";
1272         WideCharToMultiByte(CP_ACP, 0, This->wine_url, -1, speca+5, sizeof(speca)-5, NULL, NULL);
1273         nsACString_SetData(aSpec, speca);
1274
1275         return NS_OK;
1276     }
1277
1278     if(This->uri)
1279         return nsIURI_GetSpec(This->uri, aSpec);
1280
1281     TRACE("returning error\n");
1282     return NS_ERROR_NOT_IMPLEMENTED;
1283
1284 }
1285
1286 static nsresult NSAPI nsURI_SetSpec(nsIWineURI *iface, const nsACString *aSpec)
1287 {
1288     nsURI *This = NSURI_THIS(iface);
1289
1290     TRACE("(%p)->(%p)\n", This, aSpec);
1291
1292     if(This->uri)
1293         return nsIURI_SetSpec(This->uri, aSpec);
1294
1295     FIXME("default action not implemented\n");
1296     return NS_ERROR_NOT_IMPLEMENTED;
1297 }
1298
1299 static nsresult NSAPI nsURI_GetPrePath(nsIWineURI *iface, nsACString *aPrePath)
1300 {
1301     nsURI *This = NSURI_THIS(iface);
1302
1303     TRACE("(%p)->(%p)\n", This, aPrePath);
1304
1305     if(This->uri)
1306         return nsIURI_GetPrePath(This->uri, aPrePath);
1307
1308     FIXME("default action not implemented\n");
1309     return NS_ERROR_NOT_IMPLEMENTED;
1310 }
1311
1312 static nsresult NSAPI nsURI_GetScheme(nsIWineURI *iface, nsACString *aScheme)
1313 {
1314     nsURI *This = NSURI_THIS(iface);
1315
1316     TRACE("(%p)->(%p)\n", This, aScheme);
1317
1318     if(This->use_wine_url && strcmpW(This->wine_url, about_blankW)) {
1319         /*
1320          * For Gecko we set scheme to unknown so it won't be handled
1321          * as any special case.
1322          */
1323         nsACString_SetData(aScheme, "wine");
1324         return NS_OK;
1325     }
1326
1327     if(This->uri)
1328         return nsIURI_GetScheme(This->uri, aScheme);
1329
1330     TRACE("returning error\n");
1331     return NS_ERROR_NOT_IMPLEMENTED;
1332 }
1333
1334 static nsresult NSAPI nsURI_SetScheme(nsIWineURI *iface, const nsACString *aScheme)
1335 {
1336     nsURI *This = NSURI_THIS(iface);
1337
1338     TRACE("(%p)->(%p)\n", This, aScheme);
1339
1340     if(This->uri)
1341         return nsIURI_SetScheme(This->uri, aScheme);
1342
1343     FIXME("default action not implemented\n");
1344     return NS_ERROR_NOT_IMPLEMENTED;
1345 }
1346
1347 static nsresult NSAPI nsURI_GetUserPass(nsIWineURI *iface, nsACString *aUserPass)
1348 {
1349     nsURI *This = NSURI_THIS(iface);
1350
1351     TRACE("(%p)->(%p)\n", This, aUserPass);
1352
1353     if(This->uri)
1354         return nsIURI_GetUserPass(This->uri, aUserPass);
1355
1356     FIXME("default action not implemented\n");
1357     return NS_ERROR_NOT_IMPLEMENTED;
1358 }
1359
1360 static nsresult NSAPI nsURI_SetUserPass(nsIWineURI *iface, const nsACString *aUserPass)
1361 {
1362     nsURI *This = NSURI_THIS(iface);
1363
1364     TRACE("(%p)->(%p)\n", This, aUserPass);
1365
1366     if(This->uri)
1367         return nsIURI_SetUserPass(This->uri, aUserPass);
1368
1369     FIXME("default action not implemented\n");
1370     return NS_ERROR_NOT_IMPLEMENTED;
1371 }
1372
1373 static nsresult NSAPI nsURI_GetUsername(nsIWineURI *iface, nsACString *aUsername)
1374 {
1375     nsURI *This = NSURI_THIS(iface);
1376
1377     TRACE("(%p)->(%p)\n", This, aUsername);
1378
1379     if(This->uri)
1380         return nsIURI_GetUsername(This->uri, aUsername);
1381
1382     FIXME("default action not implemented\n");
1383     return NS_ERROR_NOT_IMPLEMENTED;
1384 }
1385
1386 static nsresult NSAPI nsURI_SetUsername(nsIWineURI *iface, const nsACString *aUsername)
1387 {
1388     nsURI *This = NSURI_THIS(iface);
1389
1390     TRACE("(%p)->(%p)\n", This, aUsername);
1391
1392     if(This->uri)
1393         return nsIURI_SetUsername(This->uri, aUsername);
1394
1395     FIXME("default action not implemented\n");
1396     return NS_ERROR_NOT_IMPLEMENTED;
1397 }
1398
1399 static nsresult NSAPI nsURI_GetPassword(nsIWineURI *iface, nsACString *aPassword)
1400 {
1401     nsURI *This = NSURI_THIS(iface);
1402
1403     TRACE("(%p)->(%p)\n", This, aPassword);
1404
1405     if(This->uri)
1406         return nsIURI_GetPassword(This->uri, aPassword);
1407
1408     FIXME("default action not implemented\n");
1409     return NS_ERROR_NOT_IMPLEMENTED;
1410 }
1411
1412 static nsresult NSAPI nsURI_SetPassword(nsIWineURI *iface, const nsACString *aPassword)
1413 {
1414     nsURI *This = NSURI_THIS(iface);
1415
1416     TRACE("(%p)->(%p)\n", This, aPassword);
1417
1418     if(This->uri)
1419         return nsIURI_SetPassword(This->uri, aPassword);
1420
1421     FIXME("default action not implemented\n");
1422     return NS_ERROR_NOT_IMPLEMENTED;
1423 }
1424
1425 static nsresult NSAPI nsURI_GetHostPort(nsIWineURI *iface, nsACString *aHostPort)
1426 {
1427     nsURI *This = NSURI_THIS(iface);
1428
1429     TRACE("(%p)->(%p)\n", This, aHostPort);
1430
1431     if(This->uri)
1432         return nsIURI_GetHostPort(This->uri, aHostPort);
1433
1434     FIXME("default action not implemented\n");
1435     return NS_ERROR_NOT_IMPLEMENTED;
1436 }
1437
1438 static nsresult NSAPI nsURI_SetHostPort(nsIWineURI *iface, const nsACString *aHostPort)
1439 {
1440     nsURI *This = NSURI_THIS(iface);
1441
1442     TRACE("(%p)->(%p)\n", This, aHostPort);
1443
1444     if(This->uri)
1445         return nsIURI_SetHostPort(This->uri, aHostPort);
1446
1447     FIXME("default action not implemented\n");
1448     return NS_ERROR_NOT_IMPLEMENTED;
1449 }
1450
1451 static nsresult NSAPI nsURI_GetHost(nsIWineURI *iface, nsACString *aHost)
1452 {
1453     nsURI *This = NSURI_THIS(iface);
1454
1455     TRACE("(%p)->(%p)\n", This, aHost);
1456
1457     if(This->uri)
1458         return nsIURI_GetHost(This->uri, aHost);
1459
1460     FIXME("default action not implemented\n");
1461     return NS_ERROR_NOT_IMPLEMENTED;
1462 }
1463
1464 static nsresult NSAPI nsURI_SetHost(nsIWineURI *iface, const nsACString *aHost)
1465 {
1466     nsURI *This = NSURI_THIS(iface);
1467
1468     TRACE("(%p)->(%p)\n", This, aHost);
1469
1470     if(This->uri)
1471         return nsIURI_SetHost(This->uri, aHost);
1472
1473     FIXME("default action not implemented\n");
1474     return NS_ERROR_NOT_IMPLEMENTED;
1475 }
1476
1477 static nsresult NSAPI nsURI_GetPort(nsIWineURI *iface, PRInt32 *aPort)
1478 {
1479     nsURI *This = NSURI_THIS(iface);
1480
1481     TRACE("(%p)->(%p)\n", This, aPort);
1482
1483     if(This->uri)
1484         return nsIURI_GetPort(This->uri, aPort);
1485
1486     FIXME("default action not implemented\n");
1487     return NS_ERROR_NOT_IMPLEMENTED;
1488 }
1489
1490 static nsresult NSAPI nsURI_SetPort(nsIWineURI *iface, PRInt32 aPort)
1491 {
1492     nsURI *This = NSURI_THIS(iface);
1493
1494     TRACE("(%p)->(%d)\n", This, aPort);
1495
1496     if(This->uri)
1497         return nsIURI_SetPort(This->uri, aPort);
1498
1499     FIXME("default action not implemented\n");
1500     return NS_ERROR_NOT_IMPLEMENTED;
1501 }
1502
1503 static nsresult NSAPI nsURI_GetPath(nsIWineURI *iface, nsACString *aPath)
1504 {
1505     nsURI *This = NSURI_THIS(iface);
1506
1507     TRACE("(%p)->(%p)\n", This, aPath);
1508
1509     if(This->uri)
1510         return nsIURI_GetPath(This->uri, aPath);
1511
1512     FIXME("default action not implemented\n");
1513     return NS_ERROR_NOT_IMPLEMENTED;
1514 }
1515
1516 static nsresult NSAPI nsURI_SetPath(nsIWineURI *iface, const nsACString *aPath)
1517 {
1518     nsURI *This = NSURI_THIS(iface);
1519     const char *path;
1520
1521     nsACString_GetData(aPath, &path);
1522     TRACE("(%p)->(%p(%s))\n", This, aPath, debugstr_a(path));
1523
1524
1525     if(This->wine_url) {
1526         WCHAR new_url[INTERNET_MAX_URL_LENGTH];
1527         DWORD size = sizeof(new_url)/sizeof(WCHAR);
1528         LPWSTR pathw;
1529         HRESULT hres;
1530
1531         pathw = heap_strdupAtoW(path);
1532         hres = UrlCombineW(This->wine_url, pathw, new_url, &size, 0);
1533         heap_free(pathw);
1534         if(SUCCEEDED(hres))
1535             nsIWineURI_SetWineURL(NSWINEURI(This), new_url);
1536         else
1537             WARN("UrlCombine failed: %08x\n", hres);
1538     }
1539
1540     if(!This->uri)
1541         return NS_OK;
1542
1543     return nsIURI_SetPath(This->uri, aPath);
1544 }
1545
1546 static nsresult NSAPI nsURI_Equals(nsIWineURI *iface, nsIURI *other, PRBool *_retval)
1547 {
1548     nsURI *This = NSURI_THIS(iface);
1549     nsIWineURI *wine_uri;
1550     LPCWSTR other_url = NULL;
1551     nsresult nsres;
1552
1553     TRACE("(%p)->(%p %p)\n", This, other, _retval);
1554
1555     if(This->uri)
1556         return nsIURI_Equals(This->uri, other, _retval);
1557
1558     nsres = nsIURI_QueryInterface(other, &IID_nsIWineURI, (void**)&wine_uri);
1559     if(NS_FAILED(nsres)) {
1560         TRACE("Could not get nsIWineURI interface\n");
1561         *_retval = FALSE;
1562         return NS_OK;
1563     }
1564
1565     nsIWineURI_GetWineURL(wine_uri, &other_url);
1566     *_retval = !UrlCompareW(This->wine_url, other_url, TRUE);
1567     nsIWineURI_Release(wine_uri);
1568
1569     return NS_OK;
1570 }
1571
1572 static nsresult NSAPI nsURI_SchemeIs(nsIWineURI *iface, const char *scheme, PRBool *_retval)
1573 {
1574     nsURI *This = NSURI_THIS(iface);
1575
1576     TRACE("(%p)->(%s %p)\n", This, debugstr_a(scheme), _retval);
1577
1578     if(This->use_wine_url) {
1579         WCHAR buf[INTERNET_MAX_SCHEME_LENGTH];
1580         int len = MultiByteToWideChar(CP_ACP, 0, scheme, -1, buf, sizeof(buf)/sizeof(WCHAR))-1;
1581
1582         *_retval = strlenW(This->wine_url) > len
1583             && This->wine_url[len] == ':'
1584             && !memcmp(buf, This->wine_url, len*sizeof(WCHAR));
1585         return NS_OK;
1586     }
1587
1588     if(This->uri)
1589         return nsIURI_SchemeIs(This->uri, scheme, _retval);
1590
1591     TRACE("returning error\n");
1592     return NS_ERROR_NOT_IMPLEMENTED;
1593 }
1594
1595 static nsresult NSAPI nsURI_Clone(nsIWineURI *iface, nsIURI **_retval)
1596 {
1597     nsURI *This = NSURI_THIS(iface);
1598     nsIURI *nsuri = NULL;
1599     nsIWineURI *wine_uri;
1600     nsresult nsres;
1601
1602     TRACE("(%p)->(%p)\n", This, _retval);
1603
1604     if(This->uri) {
1605         nsres = nsIURI_Clone(This->uri, &nsuri);
1606         if(NS_FAILED(nsres)) {
1607             WARN("Clone failed: %08x\n", nsres);
1608             return nsres;
1609         }
1610     }
1611
1612     nsres = create_uri(nsuri, This->container, &wine_uri);
1613     if(NS_FAILED(nsres)) {
1614         WARN("create_uri failed: %08x\n", nsres);
1615         return nsres;
1616     }
1617
1618     *_retval = (nsIURI*)wine_uri;
1619     return nsIWineURI_SetWineURL(wine_uri, This->wine_url);
1620 }
1621
1622 static nsresult NSAPI nsURI_Resolve(nsIWineURI *iface, const nsACString *arelativePath,
1623         nsACString *_retval)
1624 {
1625     nsURI *This = NSURI_THIS(iface);
1626
1627     TRACE("(%p)->(%p %p)\n", This, arelativePath, _retval);
1628
1629     if(This->uri)
1630         return nsIURI_Resolve(This->uri, arelativePath, _retval);
1631
1632     FIXME("default action not implemented\n");
1633     return NS_ERROR_NOT_IMPLEMENTED;
1634 }
1635
1636 static nsresult NSAPI nsURI_GetAsciiSpec(nsIWineURI *iface, nsACString *aAsciiSpec)
1637 {
1638     nsURI *This = NSURI_THIS(iface);
1639
1640     TRACE("(%p)->(%p)\n", This, aAsciiSpec);
1641
1642     if(This->use_wine_url)
1643         return nsIURI_GetSpec(NSURI(This), aAsciiSpec);
1644
1645     if(This->uri)
1646         return nsIURI_GetAsciiSpec(This->uri, aAsciiSpec);
1647
1648     TRACE("returning error\n");
1649     return NS_ERROR_NOT_IMPLEMENTED;
1650 }
1651
1652 static nsresult NSAPI nsURI_GetAsciiHost(nsIWineURI *iface, nsACString *aAsciiHost)
1653 {
1654     nsURI *This = NSURI_THIS(iface);
1655
1656     TRACE("(%p)->(%p)\n", This, aAsciiHost);
1657
1658     if(This->uri)
1659         return nsIURI_GetAsciiHost(This->uri, aAsciiHost);
1660
1661     FIXME("default action not implemented\n");
1662     return NS_ERROR_NOT_IMPLEMENTED;
1663 }
1664
1665 static nsresult NSAPI nsURI_GetOriginCharset(nsIWineURI *iface, nsACString *aOriginCharset)
1666 {
1667     nsURI *This = NSURI_THIS(iface);
1668
1669     TRACE("(%p)->(%p)\n", This, aOriginCharset);
1670
1671     if(This->uri)
1672         return nsIURI_GetOriginCharset(This->uri, aOriginCharset);
1673
1674     FIXME("default action not implemented\n");
1675     return NS_ERROR_NOT_IMPLEMENTED;
1676 }
1677
1678 static nsresult NSAPI nsURI_GetNSContainer(nsIWineURI *iface, NSContainer **aContainer)
1679 {
1680     nsURI *This = NSURI_THIS(iface);
1681
1682     TRACE("(%p)->(%p)\n", This, aContainer);
1683
1684     if(This->container)
1685         nsIWebBrowserChrome_AddRef(NSWBCHROME(This->container));
1686     *aContainer = This->container;
1687
1688     return NS_OK;
1689 }
1690
1691 static nsresult NSAPI nsURI_SetNSContainer(nsIWineURI *iface, NSContainer *aContainer)
1692 {
1693     nsURI *This = NSURI_THIS(iface);
1694
1695     TRACE("(%p)->(%p)\n", This, aContainer);
1696
1697     if(This->container) {
1698         if(This->container == aContainer)
1699             return NS_OK;
1700         TRACE("Changing %p -> %p\n", This->container, aContainer);
1701         nsIWebBrowserChrome_Release(NSWBCHROME(This->container));
1702     }
1703
1704     if(aContainer)
1705         nsIWebBrowserChrome_AddRef(NSWBCHROME(aContainer));
1706     This->container = aContainer;
1707
1708     return NS_OK;
1709 }
1710
1711 static nsresult NSAPI nsURI_GetIsDocumentURI(nsIWineURI *iface, PRBool *aIsDocumentURI)
1712 {
1713     nsURI *This = NSURI_THIS(iface);
1714
1715     TRACE("(%p)->(%p)\n", This, aIsDocumentURI);
1716
1717     *aIsDocumentURI = This->is_doc_uri;
1718     return NS_OK;
1719 }
1720
1721 static nsresult NSAPI nsURI_SetIsDocumentURI(nsIWineURI *iface, PRBool aIsDocumentURI)
1722 {
1723     nsURI *This = NSURI_THIS(iface);
1724
1725     TRACE("(%p)->(%x)\n", This, aIsDocumentURI);
1726
1727     This->is_doc_uri = aIsDocumentURI;
1728     return NS_OK;
1729 }
1730
1731 static nsresult NSAPI nsURI_GetWineURL(nsIWineURI *iface, LPCWSTR *aURL)
1732 {
1733     nsURI *This = NSURI_THIS(iface);
1734
1735     TRACE("(%p)->(%p)\n", This, aURL);
1736
1737     *aURL = This->wine_url;
1738     return NS_OK;
1739 }
1740
1741 static nsresult NSAPI nsURI_SetWineURL(nsIWineURI *iface, LPCWSTR aURL)
1742 {
1743     nsURI *This = NSURI_THIS(iface);
1744
1745     static const WCHAR wszFtp[]   = {'f','t','p',':'};
1746     static const WCHAR wszHttp[]  = {'h','t','t','p',':'};
1747     static const WCHAR wszHttps[] = {'h','t','t','p','s',':'};
1748
1749     TRACE("(%p)->(%s)\n", This, debugstr_w(aURL));
1750
1751     heap_free(This->wine_url);
1752
1753     if(aURL) {
1754         int len = strlenW(aURL)+1;
1755         This->wine_url = heap_alloc(len*sizeof(WCHAR));
1756         memcpy(This->wine_url, aURL, len*sizeof(WCHAR));
1757
1758         /* FIXME: Always use wine url */
1759         This->use_wine_url =
1760                strncmpW(aURL, wszFtp,   sizeof(wszFtp)/sizeof(WCHAR))
1761             && strncmpW(aURL, wszHttp,  sizeof(wszHttp)/sizeof(WCHAR))
1762             && strncmpW(aURL, wszHttps, sizeof(wszHttps)/sizeof(WCHAR));
1763     }else {
1764         This->wine_url = NULL;
1765         This->use_wine_url = FALSE;
1766     }
1767
1768     return NS_OK;
1769 }
1770
1771 #undef NSURI_THIS
1772
1773 static const nsIWineURIVtbl nsWineURIVtbl = {
1774     nsURI_QueryInterface,
1775     nsURI_AddRef,
1776     nsURI_Release,
1777     nsURI_GetSpec,
1778     nsURI_SetSpec,
1779     nsURI_GetPrePath,
1780     nsURI_GetScheme,
1781     nsURI_SetScheme,
1782     nsURI_GetUserPass,
1783     nsURI_SetUserPass,
1784     nsURI_GetUsername,
1785     nsURI_SetUsername,
1786     nsURI_GetPassword,
1787     nsURI_SetPassword,
1788     nsURI_GetHostPort,
1789     nsURI_SetHostPort,
1790     nsURI_GetHost,
1791     nsURI_SetHost,
1792     nsURI_GetPort,
1793     nsURI_SetPort,
1794     nsURI_GetPath,
1795     nsURI_SetPath,
1796     nsURI_Equals,
1797     nsURI_SchemeIs,
1798     nsURI_Clone,
1799     nsURI_Resolve,
1800     nsURI_GetAsciiSpec,
1801     nsURI_GetAsciiHost,
1802     nsURI_GetOriginCharset,
1803     nsURI_GetNSContainer,
1804     nsURI_SetNSContainer,
1805     nsURI_GetIsDocumentURI,
1806     nsURI_SetIsDocumentURI,
1807     nsURI_GetWineURL,
1808     nsURI_SetWineURL
1809 };
1810
1811 static nsresult create_uri(nsIURI *uri, NSContainer *container, nsIWineURI **_retval)
1812 {
1813     nsURI *ret = heap_alloc(sizeof(nsURI));
1814
1815     ret->lpWineURIVtbl = &nsWineURIVtbl;
1816     ret->ref = 1;
1817     ret->uri = uri;
1818     ret->container = container;
1819     ret->wine_url = NULL;
1820     ret->is_doc_uri = FALSE;
1821     ret->use_wine_url = FALSE;
1822
1823     if(container)
1824         nsIWebBrowserChrome_AddRef(NSWBCHROME(container));
1825
1826     TRACE("retval=%p\n", ret);
1827     *_retval = NSWINEURI(ret);
1828     return NS_OK;
1829 }
1830
1831 typedef struct {
1832     const nsIProtocolHandlerVtbl  *lpProtocolHandlerVtbl;
1833
1834     LONG ref;
1835
1836     nsIProtocolHandler *nshandler;
1837 } nsProtocolHandler;
1838
1839 #define NSPROTHANDLER(x)  ((nsIProtocolHandler*)  &(x)->lpProtocolHandlerVtbl)
1840
1841 #define NSPROTHANDLER_THIS(iface) DEFINE_THIS(nsProtocolHandler, ProtocolHandler, iface)
1842
1843 static nsresult NSAPI nsProtocolHandler_QueryInterface(nsIProtocolHandler *iface, nsIIDRef riid,
1844         nsQIResult result)
1845 {
1846     nsProtocolHandler *This = NSPROTHANDLER_THIS(iface);
1847
1848     *result = NULL;
1849
1850     if(IsEqualGUID(&IID_nsISupports, riid)) {
1851         TRACE("(%p)->(IID_nsISupports %p)\n", This, result);
1852         *result = NSPROTHANDLER(This);
1853     }else if(IsEqualGUID(&IID_nsIProtocolHandler, riid)) {
1854         TRACE("(%p)->(IID_nsIProtocolHandler %p)\n", This, result);
1855         *result = NSPROTHANDLER(This);
1856     }else if(IsEqualGUID(&IID_nsIExternalProtocolHandler, riid)) {
1857         TRACE("(%p)->(IID_nsIExternalProtocolHandler %p), returning NULL\n", This, result);
1858         return NS_NOINTERFACE;
1859     }
1860
1861     if(*result) {
1862         nsISupports_AddRef((nsISupports*)*result);
1863         return NS_OK;
1864     }
1865
1866     WARN("(%s %p)\n", debugstr_guid(riid), result);
1867     return NS_NOINTERFACE;
1868 }
1869
1870 static nsrefcnt NSAPI nsProtocolHandler_AddRef(nsIProtocolHandler *iface)
1871 {
1872     nsProtocolHandler *This = NSPROTHANDLER_THIS(iface);
1873     LONG ref = InterlockedIncrement(&This->ref);
1874
1875     TRACE("(%p) ref=%d\n", This, ref);
1876
1877     return ref;
1878 }
1879
1880 static nsrefcnt NSAPI nsProtocolHandler_Release(nsIProtocolHandler *iface)
1881 {
1882     nsProtocolHandler *This = NSPROTHANDLER_THIS(iface);
1883     LONG ref = InterlockedDecrement(&This->ref);
1884
1885     TRACE("(%p) ref=%d\n", This, ref);
1886
1887     if(!ref) {
1888         if(This->nshandler)
1889             nsIProtocolHandler_Release(This->nshandler);
1890         heap_free(This);
1891     }
1892
1893     return ref;
1894 }
1895
1896 static nsresult NSAPI nsProtocolHandler_GetScheme(nsIProtocolHandler *iface, nsACString *aScheme)
1897 {
1898     nsProtocolHandler *This = NSPROTHANDLER_THIS(iface);
1899
1900     TRACE("(%p)->(%p)\n", This, aScheme);
1901
1902     if(This->nshandler)
1903         return nsIProtocolHandler_GetScheme(This->nshandler, aScheme);
1904     return NS_ERROR_NOT_IMPLEMENTED;
1905 }
1906
1907 static nsresult NSAPI nsProtocolHandler_GetDefaultPort(nsIProtocolHandler *iface,
1908         PRInt32 *aDefaultPort)
1909 {
1910     nsProtocolHandler *This = NSPROTHANDLER_THIS(iface);
1911
1912     TRACE("(%p)->(%p)\n", This, aDefaultPort);
1913
1914     if(This->nshandler)
1915         return nsIProtocolHandler_GetDefaultPort(This->nshandler, aDefaultPort);
1916     return NS_ERROR_NOT_IMPLEMENTED;
1917 }
1918
1919 static nsresult NSAPI nsProtocolHandler_GetProtocolFlags(nsIProtocolHandler *iface,
1920                                                          PRUint32 *aProtocolFlags)
1921 {
1922     nsProtocolHandler *This = NSPROTHANDLER_THIS(iface);
1923
1924     TRACE("(%p)->(%p)\n", This, aProtocolFlags);
1925
1926     if(This->nshandler)
1927         return nsIProtocolHandler_GetProtocolFlags(This->nshandler, aProtocolFlags);
1928     return NS_ERROR_NOT_IMPLEMENTED;
1929 }
1930
1931 static nsresult NSAPI nsProtocolHandler_NewURI(nsIProtocolHandler *iface,
1932         const nsACString *aSpec, const char *aOriginCharset, nsIURI *aBaseURI, nsIURI **_retval)
1933 {
1934     nsProtocolHandler *This = NSPROTHANDLER_THIS(iface);
1935
1936     TRACE("((%p)->%p %s %p %p)\n", This, aSpec, debugstr_a(aOriginCharset), aBaseURI, _retval);
1937
1938     if(This->nshandler)
1939         return nsIProtocolHandler_NewURI(This->nshandler, aSpec, aOriginCharset, aBaseURI, _retval);
1940     return NS_ERROR_NOT_IMPLEMENTED;
1941 }
1942
1943 static nsresult NSAPI nsProtocolHandler_NewChannel(nsIProtocolHandler *iface,
1944         nsIURI *aURI, nsIChannel **_retval)
1945 {
1946     nsProtocolHandler *This = NSPROTHANDLER_THIS(iface);
1947
1948     TRACE("(%p)->(%p %p)\n", This, aURI, _retval);
1949
1950     if(This->nshandler)
1951         return nsIProtocolHandler_NewChannel(This->nshandler, aURI, _retval);
1952     return NS_ERROR_NOT_IMPLEMENTED;
1953 }
1954
1955 static nsresult NSAPI nsProtocolHandler_AllowPort(nsIProtocolHandler *iface,
1956         PRInt32 port, const char *scheme, PRBool *_retval)
1957 {
1958     nsProtocolHandler *This = NSPROTHANDLER_THIS(iface);
1959
1960     TRACE("(%p)->(%d %s %p)\n", This, port, debugstr_a(scheme), _retval);
1961
1962     if(This->nshandler)
1963         return nsIProtocolHandler_AllowPort(This->nshandler, port, scheme, _retval);
1964     return NS_ERROR_NOT_IMPLEMENTED;
1965 }
1966
1967 #undef NSPROTHANDLER_THIS
1968
1969 static const nsIProtocolHandlerVtbl nsProtocolHandlerVtbl = {
1970     nsProtocolHandler_QueryInterface,
1971     nsProtocolHandler_AddRef,
1972     nsProtocolHandler_Release,
1973     nsProtocolHandler_GetScheme,
1974     nsProtocolHandler_GetDefaultPort,
1975     nsProtocolHandler_GetProtocolFlags,
1976     nsProtocolHandler_NewURI,
1977     nsProtocolHandler_NewChannel,
1978     nsProtocolHandler_AllowPort
1979 };
1980
1981 static nsIProtocolHandler *create_protocol_handler(nsIProtocolHandler *nshandler)
1982 {
1983     nsProtocolHandler *ret = heap_alloc(sizeof(nsProtocolHandler));
1984
1985     ret->lpProtocolHandlerVtbl = &nsProtocolHandlerVtbl;
1986     ret->ref = 1;
1987     ret->nshandler = nshandler;
1988
1989     return NSPROTHANDLER(ret);
1990 }
1991
1992 static nsresult NSAPI nsIOService_QueryInterface(nsIIOService*,nsIIDRef,nsQIResult);
1993
1994 static nsrefcnt NSAPI nsIOService_AddRef(nsIIOService *iface)
1995 {
1996     return 2;
1997 }
1998
1999 static nsrefcnt NSAPI nsIOService_Release(nsIIOService *iface)
2000 {
2001     return 1;
2002 }
2003
2004 static nsresult NSAPI nsIOService_GetProtocolHandler(nsIIOService *iface, const char *aScheme,
2005                                                      nsIProtocolHandler **_retval)
2006 {
2007     nsIExternalProtocolHandler *nsexthandler;
2008     nsIProtocolHandler *nshandler;
2009     nsresult nsres;
2010
2011     TRACE("(%s %p)\n", debugstr_a(aScheme), _retval);
2012
2013     nsres = nsIIOService_GetProtocolHandler(nsio, aScheme, &nshandler);
2014     if(NS_FAILED(nsres)) {
2015         WARN("GetProtocolHandler failed: %08x\n", nsres);
2016         return nsres;
2017     }
2018
2019     nsres = nsIProtocolHandler_QueryInterface(nshandler, &IID_nsIExternalProtocolHandler,
2020                                               (void**)&nsexthandler);
2021     if(NS_FAILED(nsres)) {
2022         *_retval = nshandler;
2023         return NS_OK;
2024     }
2025
2026     nsIExternalProtocolHandler_Release(nsexthandler);
2027     *_retval = create_protocol_handler(nshandler);
2028     TRACE("return %p\n", *_retval);
2029     return NS_OK;
2030 }
2031
2032 static nsresult NSAPI nsIOService_GetProtocolFlags(nsIIOService *iface, const char *aScheme,
2033                                                     PRUint32 *_retval)
2034 {
2035     TRACE("(%s %p)\n", debugstr_a(aScheme), _retval);
2036     return nsIIOService_GetProtocolFlags(nsio, aScheme, _retval);
2037 }
2038
2039 static BOOL is_gecko_special_uri(const char *spec)
2040 {
2041     static const char chromeW[] = "chrome:";
2042     static const char jarW[] = "jar:";
2043     static const char resourceW[] = "resource:";
2044     static const char javascriptW[] = "javascript:";
2045
2046     return !strncasecmp(spec, chromeW,     sizeof(chromeW)-1)
2047         || !strncasecmp(spec, resourceW,   sizeof(resourceW)-1)
2048         || !strncasecmp(spec, jarW,        sizeof(jarW)-1)
2049         || !strncasecmp(spec, javascriptW, sizeof(javascriptW)-1);
2050 }
2051
2052 static nsresult NSAPI nsIOService_NewURI(nsIIOService *iface, const nsACString *aSpec,
2053         const char *aOriginCharset, nsIURI *aBaseURI, nsIURI **_retval)
2054 {
2055     const char *spec = NULL;
2056     nsACString spec_str;
2057     NSContainer *nscontainer = NULL;
2058     nsIURI *uri = NULL;
2059     LPCWSTR base_wine_url = NULL;
2060     nsIWineURI *base_wine_uri = NULL, *wine_uri;
2061     BOOL is_wine_uri = FALSE;
2062     nsresult nsres;
2063
2064     nsACString_GetData(aSpec, &spec);
2065
2066     TRACE("(%p(%s) %s %p %p)\n", aSpec, debugstr_a(spec), debugstr_a(aOriginCharset),
2067           aBaseURI, _retval);
2068
2069     if(is_gecko_special_uri(spec))
2070         return nsIIOService_NewURI(nsio, aSpec, aOriginCharset, aBaseURI, _retval);
2071
2072     if(!strncmp(spec, "wine:", 5)) {
2073         spec += 5;
2074         is_wine_uri = TRUE;
2075     }
2076
2077     if(aBaseURI) {
2078         nsACString base_uri_str;
2079         const char *base_uri = NULL;
2080
2081         nsACString_Init(&base_uri_str, NULL);
2082
2083         nsres = nsIURI_GetSpec(aBaseURI, &base_uri_str);
2084         if(NS_SUCCEEDED(nsres)) {
2085             nsACString_GetData(&base_uri_str, &base_uri);
2086             TRACE("base_uri=%s\n", debugstr_a(base_uri));
2087         }else {
2088             ERR("GetSpec failed: %08x\n", nsres);
2089         }
2090
2091         nsACString_Finish(&base_uri_str);
2092     }
2093
2094     nsACString_Init(&spec_str, spec);
2095     nsres = nsIIOService_NewURI(nsio, &spec_str, aOriginCharset, aBaseURI, &uri);
2096     nsACString_Finish(&spec_str);
2097     if(NS_FAILED(nsres))
2098         TRACE("NewURI failed: %08x\n", nsres);
2099
2100     if(aBaseURI) {
2101         nsres = nsIURI_QueryInterface(aBaseURI, &IID_nsIWineURI, (void**)&base_wine_uri);
2102         if(NS_SUCCEEDED(nsres)) {
2103             nsIWineURI_GetNSContainer(base_wine_uri, &nscontainer);
2104             nsIWineURI_GetWineURL(base_wine_uri, &base_wine_url);
2105         }else {
2106             TRACE("Could not get base nsIWineURI: %08x\n", nsres);
2107         }
2108     }
2109
2110     TRACE("nscontainer = %p\n", nscontainer);
2111
2112     nsres = create_uri(uri, nscontainer, &wine_uri);
2113     *_retval = (nsIURI*)wine_uri;
2114
2115     if(nscontainer)
2116         nsIWebBrowserChrome_Release(NSWBCHROME(nscontainer));
2117
2118     if(base_wine_url) {
2119         WCHAR url[INTERNET_MAX_URL_LENGTH], rel_url[INTERNET_MAX_URL_LENGTH];
2120         DWORD len;
2121         HRESULT hres;
2122
2123         MultiByteToWideChar(CP_ACP, 0, spec, -1, rel_url, sizeof(rel_url)/sizeof(WCHAR));
2124
2125         hres = CoInternetCombineUrl(base_wine_url, rel_url,
2126                                     URL_ESCAPE_SPACES_ONLY|URL_DONT_ESCAPE_EXTRA_INFO,
2127                                     url, sizeof(url)/sizeof(WCHAR), &len, 0);
2128         if(SUCCEEDED(hres))
2129             nsIWineURI_SetWineURL(wine_uri, url);
2130         else
2131              WARN("CoCombineUrl failed: %08x\n", hres);
2132     }else if(is_wine_uri) {
2133         WCHAR url[INTERNET_MAX_URL_LENGTH];
2134
2135         MultiByteToWideChar(CP_ACP, 0, spec, -1, url, sizeof(url)/sizeof(WCHAR));
2136         nsIWineURI_SetWineURL(wine_uri, url);
2137     }
2138
2139     if(base_wine_uri)
2140         nsIWineURI_Release(base_wine_uri);
2141
2142     return nsres;
2143 }
2144
2145 static nsresult NSAPI nsIOService_NewFileURI(nsIIOService *iface, nsIFile *aFile,
2146                                              nsIURI **_retval)
2147 {
2148     TRACE("(%p %p)\n", aFile, _retval);
2149     return nsIIOService_NewFileURI(nsio, aFile, _retval);
2150 }
2151
2152 static nsresult NSAPI nsIOService_NewChannelFromURI(nsIIOService *iface, nsIURI *aURI,
2153                                                      nsIChannel **_retval)
2154 {
2155     nsIChannel *channel = NULL;
2156     nsChannel *ret;
2157     nsIWineURI *wine_uri;
2158     nsresult nsres;
2159
2160     TRACE("(%p %p)\n", aURI, _retval);
2161
2162     nsres = nsIIOService_NewChannelFromURI(nsio, aURI, &channel);
2163     if(NS_FAILED(nsres) && nsres != NS_ERROR_UNKNOWN_PROTOCOL) {
2164         WARN("NewChannelFromURI failed: %08x\n", nsres);
2165         *_retval = channel;
2166         return nsres;
2167     }
2168
2169     nsres = nsIURI_QueryInterface(aURI, &IID_nsIWineURI, (void**)&wine_uri);
2170     if(NS_FAILED(nsres)) {
2171         WARN("Could not get nsIWineURI: %08x\n", nsres);
2172         *_retval = channel;
2173         return channel ? NS_OK : NS_ERROR_UNEXPECTED;
2174     }
2175
2176     ret = heap_alloc(sizeof(nsChannel));
2177
2178     ret->lpHttpChannelVtbl = &nsChannelVtbl;
2179     ret->lpUploadChannelVtbl = &nsUploadChannelVtbl;
2180     ret->ref = 1;
2181     ret->channel = channel;
2182     ret->http_channel = NULL;
2183     ret->uri = wine_uri;
2184     ret->post_data_stream = NULL;
2185     ret->load_group = NULL;
2186     ret->notif_callback = NULL;
2187     ret->load_flags = 0;
2188     ret->content = NULL;
2189     ret->charset = NULL;
2190
2191     nsIURI_AddRef(aURI);
2192     ret->original_uri = aURI;
2193
2194     if(channel)
2195         nsIChannel_QueryInterface(channel, &IID_nsIHttpChannel, (void**)&ret->http_channel);
2196
2197     *_retval = NSCHANNEL(ret);
2198     return NS_OK;
2199 }
2200
2201 static nsresult NSAPI nsIOService_NewChannel(nsIIOService *iface, const nsACString *aSpec,
2202         const char *aOriginCharset, nsIURI *aBaseURI, nsIChannel **_retval)
2203 {
2204     TRACE("(%p %s %p %p)\n", aSpec, debugstr_a(aOriginCharset), aBaseURI, _retval);
2205     return nsIIOService_NewChannel(nsio, aSpec, aOriginCharset, aBaseURI, _retval);
2206 }
2207
2208 static nsresult NSAPI nsIOService_GetOffline(nsIIOService *iface, PRBool *aOffline)
2209 {
2210     TRACE("(%p)\n", aOffline);
2211     return nsIIOService_GetOffline(nsio, aOffline);
2212 }
2213
2214 static nsresult NSAPI nsIOService_SetOffline(nsIIOService *iface, PRBool aOffline)
2215 {
2216     TRACE("(%x)\n", aOffline);
2217     return nsIIOService_SetOffline(nsio, aOffline);
2218 }
2219
2220 static nsresult NSAPI nsIOService_AllowPort(nsIIOService *iface, PRInt32 aPort,
2221                                              const char *aScheme, PRBool *_retval)
2222 {
2223     TRACE("(%d %s %p)\n", aPort, debugstr_a(aScheme), _retval);
2224     return nsIIOService_AllowPort(nsio, aPort, debugstr_a(aScheme), _retval);
2225 }
2226
2227 static nsresult NSAPI nsIOService_ExtractScheme(nsIIOService *iface, const nsACString *urlString,
2228                                                  nsACString * _retval)
2229 {
2230     TRACE("(%p %p)\n", urlString, _retval);
2231     return nsIIOService_ExtractScheme(nsio, urlString, _retval);
2232 }
2233
2234 static const nsIIOServiceVtbl nsIOServiceVtbl = {
2235     nsIOService_QueryInterface,
2236     nsIOService_AddRef,
2237     nsIOService_Release,
2238     nsIOService_GetProtocolHandler,
2239     nsIOService_GetProtocolFlags,
2240     nsIOService_NewURI,
2241     nsIOService_NewFileURI,
2242     nsIOService_NewChannelFromURI,
2243     nsIOService_NewChannel,
2244     nsIOService_GetOffline,
2245     nsIOService_SetOffline,
2246     nsIOService_AllowPort,
2247     nsIOService_ExtractScheme
2248 };
2249
2250 static nsIIOService nsIOService = { &nsIOServiceVtbl };
2251
2252 static nsresult NSAPI nsNetUtil_QueryInterface(nsINetUtil *iface, nsIIDRef riid,
2253                                                nsQIResult result)
2254 {
2255     return nsIIOService_QueryInterface(&nsIOService, riid, result);
2256 }
2257
2258 static nsrefcnt NSAPI nsNetUtil_AddRef(nsINetUtil *iface)
2259 {
2260     return 2;
2261 }
2262
2263 static nsrefcnt NSAPI nsNetUtil_Release(nsINetUtil *iface)
2264 {
2265     return 1;
2266 }
2267
2268 static nsresult NSAPI nsNetUtil_ParseContentType(nsINetUtil *iface, const nsACString *aTypeHeader,
2269         nsACString *aCharset, PRBool *aHadCharset, nsACString *aContentType)
2270 {
2271     nsINetUtil *net_util;
2272     nsresult nsres;
2273
2274     TRACE("(%p %p %p %p)\n", aTypeHeader, aCharset, aHadCharset, aContentType);
2275
2276     nsres = nsIIOService_QueryInterface(nsio, &IID_nsINetUtil, (void**)&net_util);
2277     if(NS_FAILED(nsres)) {
2278         WARN("Could not get nsINetUtil interface: %08x\n", nsres);
2279         return nsres;
2280     }
2281
2282     nsres = nsINetUtil_ParseContentType(net_util, aTypeHeader, aCharset, aHadCharset, aContentType);
2283
2284     nsINetUtil_Release(net_util);
2285     return nsres;
2286 }
2287
2288 static const nsINetUtilVtbl nsNetUtilVtbl = {
2289     nsNetUtil_QueryInterface,
2290     nsNetUtil_AddRef,
2291     nsNetUtil_Release,
2292     nsNetUtil_ParseContentType
2293 };
2294
2295 static nsINetUtil nsNetUtil = { &nsNetUtilVtbl };
2296
2297 static nsresult NSAPI nsIOService_QueryInterface(nsIIOService *iface, nsIIDRef riid,
2298                                                  nsQIResult result)
2299 {
2300     *result = NULL;
2301
2302     if(IsEqualGUID(&IID_nsISupports, riid))
2303         *result = &nsIOService;
2304     else if(IsEqualGUID(&IID_nsIIOService, riid))
2305         *result = &nsIOService;
2306     else if(IsEqualGUID(&IID_nsINetUtil, riid))
2307         *result = &nsNetUtil;
2308
2309     if(*result) {
2310         nsISupports_AddRef((nsISupports*)*result);
2311         return NS_OK;
2312     }
2313
2314     FIXME("(%s %p)\n", debugstr_guid(riid), result);
2315     return NS_NOINTERFACE;
2316 }
2317
2318 static nsresult NSAPI nsIOServiceFactory_QueryInterface(nsIFactory *iface, nsIIDRef riid,
2319                                                         nsQIResult result)
2320 {
2321     *result = NULL;
2322
2323     if(IsEqualGUID(&IID_nsISupports, riid)) {
2324         TRACE("(IID_nsISupports %p)\n", result);
2325         *result = iface;
2326     }else if(IsEqualGUID(&IID_nsIFactory, riid)) {
2327         TRACE("(IID_nsIFactory %p)\n", result);
2328         *result = iface;
2329     }
2330
2331     if(*result) {
2332         nsIFactory_AddRef(iface);
2333         return NS_OK;
2334     }
2335
2336     WARN("(%s %p)\n", debugstr_guid(riid), result);
2337     return NS_NOINTERFACE;
2338 }
2339
2340 static nsrefcnt NSAPI nsIOServiceFactory_AddRef(nsIFactory *iface)
2341 {
2342     return 2;
2343 }
2344
2345 static nsrefcnt NSAPI nsIOServiceFactory_Release(nsIFactory *iface)
2346 {
2347     return 1;
2348 }
2349
2350 static nsresult NSAPI nsIOServiceFactory_CreateInstance(nsIFactory *iface,
2351         nsISupports *aOuter, const nsIID *iid, void **result)
2352 {
2353     return nsIIOService_QueryInterface(&nsIOService, iid, result);
2354 }
2355
2356 static nsresult NSAPI nsIOServiceFactory_LockFactory(nsIFactory *iface, PRBool lock)
2357 {
2358     WARN("(%x)\n", lock);
2359     return NS_OK;
2360 }
2361
2362 static const nsIFactoryVtbl nsIOServiceFactoryVtbl = {
2363     nsIOServiceFactory_QueryInterface,
2364     nsIOServiceFactory_AddRef,
2365     nsIOServiceFactory_Release,
2366     nsIOServiceFactory_CreateInstance,
2367     nsIOServiceFactory_LockFactory
2368 };
2369
2370 static nsIFactory nsIOServiceFactory = { &nsIOServiceFactoryVtbl };
2371
2372 void init_nsio(nsIComponentManager *component_manager, nsIComponentRegistrar *registrar)
2373 {
2374     nsIFactory *old_factory = NULL;
2375     nsresult nsres;
2376
2377     nsres = nsIComponentManager_GetClassObject(component_manager, &NS_IOSERVICE_CID,
2378                                                &IID_nsIFactory, (void**)&old_factory);
2379     if(NS_FAILED(nsres)) {
2380         ERR("Could not get factory: %08x\n", nsres);
2381         return;
2382     }
2383
2384     nsres = nsIFactory_CreateInstance(old_factory, NULL, &IID_nsIIOService, (void**)&nsio);
2385     if(NS_FAILED(nsres)) {
2386         ERR("Couldn not create nsIOService instance %08x\n", nsres);
2387         nsIFactory_Release(old_factory);
2388         return;
2389     }
2390
2391     nsres = nsIComponentRegistrar_UnregisterFactory(registrar, &NS_IOSERVICE_CID, old_factory);
2392     nsIFactory_Release(old_factory);
2393     if(NS_FAILED(nsres))
2394         ERR("UnregisterFactory failed: %08x\n", nsres);
2395
2396     nsres = nsIComponentRegistrar_RegisterFactory(registrar, &NS_IOSERVICE_CID,
2397             NS_IOSERVICE_CLASSNAME, NS_IOSERVICE_CONTRACTID, &nsIOServiceFactory);
2398     if(NS_FAILED(nsres))
2399         ERR("RegisterFactory failed: %08x\n", nsres);
2400 }