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