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