Follow up to bug 451392, add hgToolsTag to older configs
[mozilla-1.9.git] / xpfe / components / directory / nsDirectoryViewer.cpp
blobdc0bfdaeb84518b05968d855533b596ddcade886
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
13 * License.
15 * The Original Code is Mozilla Communicator client code.
17 * The Initial Developer of the Original Code is
18 * Netscape Communications Corporation.
19 * Portions created by the Initial Developer are Copyright (C) 1998
20 * the Initial Developer. All Rights Reserved.
22 * Contributor(s):
23 * Chris Waterson <waterson@netscape.com>
24 * Robert John Churchill <rjc@netscape.com>
25 * Pierre Phaneuf <pp@ludusdesign.com>
26 * Bradley Baetz <bbaetz@student.usyd.edu.au>
28 * Alternatively, the contents of this file may be used under the terms of
29 * either of the GNU General Public License Version 2 or later (the "GPL"),
30 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
31 * in which case the provisions of the GPL or the LGPL are applicable instead
32 * of those above. If you wish to allow use of your version of this file only
33 * under the terms of either the GPL or the LGPL, and not to allow others to
34 * use your version of this file under the terms of the MPL, indicate your
35 * decision by deleting the provisions above and replace them with the notice
36 * and other provisions required by the GPL or the LGPL. If you do not delete
37 * the provisions above, a recipient may use your version of this file under
38 * the terms of any one of the MPL, the GPL or the LGPL.
40 * ***** END LICENSE BLOCK ***** */
44 A directory viewer object. Parses "application/http-index-format"
45 per Lou Montulli's original spec:
47 http://www.mozilla.org/projects/netlib/dirindexformat.html
49 One added change is for a description entry, for when the
50 target does not match the filename (ie gopher)
54 #include "nsDirectoryViewer.h"
55 #include "nsIDirIndex.h"
56 #include "jsapi.h"
57 #include "nsCOMPtr.h"
58 #include "nsCRT.h"
59 #include "nsEscape.h"
60 #include "nsIEnumerator.h"
61 #ifdef MOZ_RDF
62 #include "nsIRDFService.h"
63 #include "nsRDFCID.h"
64 #include "rdf.h"
65 #endif
66 #include "nsIScriptContext.h"
67 #include "nsIScriptGlobalObject.h"
68 #include "nsIServiceManager.h"
69 #include "nsISupportsArray.h"
70 #include "nsIXPConnect.h"
71 #include "nsEnumeratorUtils.h"
72 #include "nsString.h"
73 #include "nsXPIDLString.h"
74 #include "nsReadableUtils.h"
75 #include "nsITextToSubURI.h"
76 #include "nsIInterfaceRequestor.h"
77 #include "nsIInterfaceRequestorUtils.h"
78 #include "nsIFTPChannel.h"
79 #include "nsIWindowWatcher.h"
80 #include "nsIPrompt.h"
81 #include "nsIAuthPrompt.h"
82 #include "nsIProgressEventSink.h"
83 #include "nsIDOMWindow.h"
84 #include "nsIDOMWindowInternal.h"
85 #include "nsIDOMWindowCollection.h"
86 #include "nsIDOMDocument.h"
87 #include "nsIDOMElement.h"
88 #include "nsIDOMText.h"
89 #include "nsIPrefService.h"
90 #include "nsIPrefBranch.h"
91 #include "nsIStreamConverterService.h"
92 #include "nsICategoryManager.h"
93 #include "nsXPCOMCID.h"
94 #include "nsIDocument.h"
96 static const int FORMAT_HTML = 2;
97 static const int FORMAT_XUL = 3;
99 //----------------------------------------------------------------------
101 // Common CIDs
104 #ifdef MOZ_RDF
105 static NS_DEFINE_CID(kRDFServiceCID, NS_RDFSERVICE_CID);
106 #endif
108 // Various protocols we have to special case
109 static const char kFTPProtocol[] = "ftp://";
110 static const char kGopherProtocol[] = "gopher://";
112 //----------------------------------------------------------------------
114 // nsHTTPIndex
117 #ifdef MOZ_RDF
118 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsHTTPIndex)
119 NS_INTERFACE_MAP_ENTRY(nsIHTTPIndex)
120 NS_INTERFACE_MAP_ENTRY(nsIRDFDataSource)
121 NS_INTERFACE_MAP_ENTRY(nsIStreamListener)
122 NS_INTERFACE_MAP_ENTRY(nsIDirIndexListener)
123 NS_INTERFACE_MAP_ENTRY(nsIRequestObserver)
124 NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor)
125 NS_INTERFACE_MAP_ENTRY(nsIFTPEventSink)
126 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIHTTPIndex)
127 NS_INTERFACE_MAP_END
129 NS_IMPL_CYCLE_COLLECTION_1(nsHTTPIndex, mInner)
130 NS_IMPL_CYCLE_COLLECTING_ADDREF_AMBIGUOUS(nsHTTPIndex, nsIHttpIndex)
131 NS_IMPL_CYCLE_COLLECTING_RELEASE_AMBIGUOUS(nsHTTPIndex, nsIHttpIndex)
133 NS_IMETHODIMP
134 nsHTTPIndex::GetInterface(const nsIID &anIID, void **aResult )
136 if (anIID.Equals(NS_GET_IID(nsIFTPEventSink))) {
137 // If we don't have a container to store the logged data
138 // then don't report ourselves back to the caller
140 if (!mRequestor)
141 return NS_ERROR_NO_INTERFACE;
142 *aResult = static_cast<nsIFTPEventSink*>(this);
143 NS_ADDREF(this);
144 return NS_OK;
147 if (anIID.Equals(NS_GET_IID(nsIPrompt))) {
149 if (!mRequestor)
150 return NS_ERROR_NO_INTERFACE;
152 nsCOMPtr<nsIDOMWindow> aDOMWindow = do_GetInterface(mRequestor);
153 if (!aDOMWindow)
154 return NS_ERROR_NO_INTERFACE;
156 nsCOMPtr<nsIWindowWatcher> wwatch(do_GetService(NS_WINDOWWATCHER_CONTRACTID));
158 return wwatch->GetNewPrompter(aDOMWindow, (nsIPrompt**)aResult);
161 if (anIID.Equals(NS_GET_IID(nsIAuthPrompt))) {
163 if (!mRequestor)
164 return NS_ERROR_NO_INTERFACE;
166 nsCOMPtr<nsIDOMWindow> aDOMWindow = do_GetInterface(mRequestor);
167 if (!aDOMWindow)
168 return NS_ERROR_NO_INTERFACE;
170 nsCOMPtr<nsIWindowWatcher> wwatch(do_GetService(NS_WINDOWWATCHER_CONTRACTID));
172 return wwatch->GetNewAuthPrompter(aDOMWindow, (nsIAuthPrompt**)aResult);
175 if (anIID.Equals(NS_GET_IID(nsIProgressEventSink))) {
177 if (!mRequestor)
178 return NS_ERROR_NO_INTERFACE;
180 nsCOMPtr<nsIProgressEventSink> sink = do_GetInterface(mRequestor);
181 if (!sink)
182 return NS_ERROR_NO_INTERFACE;
184 *aResult = sink;
185 NS_ADDREF((nsISupports*)*aResult);
186 return NS_OK;
189 return NS_ERROR_NO_INTERFACE;
192 NS_IMETHODIMP
193 nsHTTPIndex::OnFTPControlLog(PRBool server, const char *msg)
195 NS_ENSURE_TRUE(mRequestor, NS_OK);
197 nsCOMPtr<nsIScriptGlobalObject> scriptGlobal(do_GetInterface(mRequestor));
198 NS_ENSURE_TRUE(scriptGlobal, NS_OK);
200 nsIScriptContext *context = scriptGlobal->GetContext();
201 NS_ENSURE_TRUE(context, NS_OK);
203 JSContext* jscontext = reinterpret_cast<JSContext*>
204 (context->GetNativeContext());
205 NS_ENSURE_TRUE(jscontext, NS_OK);
207 JSObject* global = JS_GetGlobalObject(jscontext);
208 NS_ENSURE_TRUE(global, NS_OK);
210 jsval params[2];
212 nsString unicodeMsg;
213 unicodeMsg.AssignWithConversion(msg);
214 JSString* jsMsgStr = JS_NewUCStringCopyZ(jscontext, (jschar*) unicodeMsg.get());
216 params[0] = BOOLEAN_TO_JSVAL(server);
217 params[1] = STRING_TO_JSVAL(jsMsgStr);
219 jsval val;
220 JS_CallFunctionName(jscontext,
221 global,
222 "OnFTPControlLog",
224 params,
225 &val);
226 return NS_OK;
229 NS_IMETHODIMP
230 nsHTTPIndex::SetEncoding(const char *encoding)
232 mEncoding = encoding;
233 return(NS_OK);
236 NS_IMETHODIMP
237 nsHTTPIndex::GetEncoding(char **encoding)
239 NS_PRECONDITION(encoding, "null ptr");
240 if (! encoding)
241 return(NS_ERROR_NULL_POINTER);
243 *encoding = ToNewCString(mEncoding);
244 if (!*encoding)
245 return(NS_ERROR_OUT_OF_MEMORY);
247 return(NS_OK);
250 NS_IMETHODIMP
251 nsHTTPIndex::OnStartRequest(nsIRequest *request, nsISupports* aContext)
253 nsresult rv;
255 mParser = do_CreateInstance(NS_DIRINDEXPARSER_CONTRACTID, &rv);
256 if (NS_FAILED(rv)) return rv;
258 rv = mParser->SetEncoding(mEncoding.get());
259 if (NS_FAILED(rv)) return rv;
261 rv = mParser->SetListener(this);
262 if (NS_FAILED(rv)) return rv;
264 rv = mParser->OnStartRequest(request,aContext);
265 if (NS_FAILED(rv)) return rv;
267 // This should only run once...
268 // Unless we don't have a container to start with
269 // (ie called from bookmarks as an rdf datasource)
270 if (mBindToGlobalObject && mRequestor) {
271 mBindToGlobalObject = PR_FALSE;
273 // Now get the content viewer container's script object.
274 nsCOMPtr<nsIScriptGlobalObject> scriptGlobal(do_GetInterface(mRequestor));
275 NS_ENSURE_TRUE(scriptGlobal, NS_ERROR_FAILURE);
277 nsIScriptContext *context = scriptGlobal->GetContext();
278 NS_ENSURE_TRUE(context, NS_ERROR_FAILURE);
280 JSContext* jscontext = reinterpret_cast<JSContext*>
281 (context->GetNativeContext());
282 JSObject* global = JS_GetGlobalObject(jscontext);
284 // Using XPConnect, wrap the HTTP index object...
285 static NS_DEFINE_CID(kXPConnectCID, NS_XPCONNECT_CID);
286 nsCOMPtr<nsIXPConnect> xpc(do_GetService(kXPConnectCID, &rv));
287 if (NS_FAILED(rv)) return rv;
289 nsCOMPtr<nsIXPConnectJSObjectHolder> wrapper;
290 rv = xpc->WrapNative(jscontext,
291 global,
292 static_cast<nsIHTTPIndex*>(this),
293 NS_GET_IID(nsIHTTPIndex),
294 getter_AddRefs(wrapper));
296 NS_ASSERTION(NS_SUCCEEDED(rv), "unable to xpconnect-wrap http-index");
297 if (NS_FAILED(rv)) return rv;
299 JSObject* jsobj;
300 rv = wrapper->GetJSObject(&jsobj);
301 NS_ASSERTION(NS_SUCCEEDED(rv),
302 "unable to get jsobj from xpconnect wrapper");
303 if (NS_FAILED(rv)) return rv;
305 jsval jslistener = OBJECT_TO_JSVAL(jsobj);
307 // ...and stuff it into the global context
308 PRBool ok;
309 ok = JS_SetProperty(jscontext, global, "HTTPIndex", &jslistener);
311 NS_ASSERTION(ok, "unable to set Listener property");
312 if (! ok)
313 return NS_ERROR_FAILURE;
315 if (!aContext) {
316 nsCOMPtr<nsIChannel> channel(do_QueryInterface(request));
317 NS_ASSERTION(channel, "request should be a channel");
319 // lets hijack the notifications:
320 channel->SetNotificationCallbacks(this);
322 // now create the top most resource
323 nsCOMPtr<nsIURI> uri;
324 channel->GetURI(getter_AddRefs(uri));
326 nsCAutoString entryuriC;
327 uri->GetSpec(entryuriC);
329 nsCOMPtr<nsIRDFResource> entry;
330 rv = mDirRDF->GetResource(entryuriC, getter_AddRefs(entry));
332 NS_ConvertUTF8toUTF16 uriUnicode(entryuriC);
334 nsCOMPtr<nsIRDFLiteral> URLVal;
335 rv = mDirRDF->GetLiteral(uriUnicode.get(), getter_AddRefs(URLVal));
337 Assert(entry, kNC_URL, URLVal, PR_TRUE);
338 mDirectory = do_QueryInterface(entry);
340 else
342 // Get the directory from the context
343 mDirectory = do_QueryInterface(aContext);
346 if (!mDirectory) {
347 request->Cancel(NS_BINDING_ABORTED);
348 return NS_BINDING_ABORTED;
351 // Mark the directory as "loading"
352 rv = Assert(mDirectory, kNC_Loading,
353 kTrueLiteral, PR_TRUE);
354 if (NS_FAILED(rv)) return rv;
356 return NS_OK;
360 NS_IMETHODIMP
361 nsHTTPIndex::OnStopRequest(nsIRequest *request,
362 nsISupports* aContext,
363 nsresult aStatus)
365 // If mDirectory isn't set, then we should just bail. Either an
366 // error occurred and OnStartRequest() never got called, or
367 // something exploded in OnStartRequest().
368 if (! mDirectory)
369 return NS_BINDING_ABORTED;
371 mParser->OnStopRequest(request,aContext,aStatus);
373 nsresult rv;
375 nsXPIDLCString commentStr;
376 mParser->GetComment(getter_Copies(commentStr));
378 nsCOMPtr<nsIRDFLiteral> comment;
379 rv = mDirRDF->GetLiteral(NS_ConvertASCIItoUTF16(commentStr).get(), getter_AddRefs(comment));
380 if (NS_FAILED(rv)) return rv;
382 rv = Assert(mDirectory, kNC_Comment, comment, PR_TRUE);
383 if (NS_FAILED(rv)) return rv;
385 // hack: Remove the 'loading' annotation (ignore errors)
386 AddElement(mDirectory, kNC_Loading, kTrueLiteral);
388 return NS_OK;
392 NS_IMETHODIMP
393 nsHTTPIndex::OnDataAvailable(nsIRequest *request,
394 nsISupports* aContext,
395 nsIInputStream* aStream,
396 PRUint32 aSourceOffset,
397 PRUint32 aCount)
399 // If mDirectory isn't set, then we should just bail. Either an
400 // error occurred and OnStartRequest() never got called, or
401 // something exploded in OnStartRequest().
402 if (! mDirectory)
403 return NS_BINDING_ABORTED;
405 return mParser->OnDataAvailable(request, mDirectory, aStream, aSourceOffset, aCount);
409 nsresult
410 nsHTTPIndex::OnIndexAvailable(nsIRequest* aRequest, nsISupports *aContext,
411 nsIDirIndex* aIndex)
413 nsCOMPtr<nsIRDFResource> parentRes = do_QueryInterface(aContext);
414 if (!parentRes) {
415 NS_ERROR("Could not obtain parent resource");
416 return(NS_ERROR_UNEXPECTED);
419 const char* baseStr;
420 parentRes->GetValueConst(&baseStr);
421 if (! baseStr) {
422 NS_ERROR("Could not reconstruct base uri\n");
423 return NS_ERROR_UNEXPECTED;
426 // we found the filename; construct a resource for its entry
427 nsCAutoString entryuriC(baseStr);
429 // gopher resources don't point to an entry in the same directory
430 // like ftp uris. So the entryuriC is just a unique string, while
431 // the URL attribute is the destination of this element
432 // The naming scheme for the attributes is taken from the bookmarks
433 nsXPIDLCString filename;
434 nsresult rv = aIndex->GetLocation(getter_Copies(filename));
435 if (NS_FAILED(rv)) return rv;
436 entryuriC.Append(filename);
438 // if its a directory, make sure it ends with a trailing slash.
439 // This doesn't matter for gopher, (where directories don't have
440 // to end in a trailing /), because the filename is used for the URL
441 // attribute.
442 PRUint32 type;
443 rv = aIndex->GetType(&type);
444 if (NS_FAILED(rv))
445 return rv;
447 PRBool isDirType = (type == nsIDirIndex::TYPE_DIRECTORY);
449 if (isDirType && entryuriC.Last() != '/') {
450 entryuriC.Append('/');
453 nsCOMPtr<nsIRDFResource> entry;
454 rv = mDirRDF->GetResource(entryuriC, getter_AddRefs(entry));
456 // At this point, we'll (hopefully) have found the filename and
457 // constructed a resource for it, stored in entry. So now take a
458 // second pass through the values and add as statements to the RDF
459 // datasource.
461 if (entry && NS_SUCCEEDED(rv)) {
462 nsCOMPtr<nsIRDFLiteral> lit;
463 nsString str;
465 // For gopher, the target is the filename. We still have to do all
466 // the above string manipulation though, because we need the entryuric
467 // as the key for the RDF data source
468 if (!strncmp(entryuriC.get(), kGopherProtocol, sizeof(kGopherProtocol)-1))
469 str.AssignWithConversion(filename);
470 else {
471 str.AssignWithConversion(entryuriC.get());
474 rv = mDirRDF->GetLiteral(str.get(), getter_AddRefs(lit));
476 if (NS_SUCCEEDED(rv)) {
477 rv = Assert(entry, kNC_URL, lit, PR_TRUE);
478 if (NS_FAILED(rv)) return rv;
480 nsXPIDLString xpstr;
482 // description
483 rv = aIndex->GetDescription(getter_Copies(xpstr));
484 if (NS_FAILED(rv)) return rv;
485 if (xpstr.Last() == '/')
486 xpstr.Truncate(xpstr.Length() - 1);
488 rv = mDirRDF->GetLiteral(xpstr.get(), getter_AddRefs(lit));
489 if (NS_FAILED(rv)) return rv;
490 rv = Assert(entry, kNC_Description, lit, PR_TRUE);
491 if (NS_FAILED(rv)) return rv;
493 // contentlength
494 PRInt64 size;
495 rv = aIndex->GetSize(&size);
496 if (NS_FAILED(rv)) return rv;
497 PRInt64 minus1 = LL_MAXUINT;
498 if (LL_NE(size, minus1)) {
499 PRInt32 intSize;
500 LL_L2I(intSize, size);
501 // XXX RDF should support 64 bit integers (bug 240160)
502 nsCOMPtr<nsIRDFInt> val;
503 rv = mDirRDF->GetIntLiteral(intSize, getter_AddRefs(val));
504 if (NS_FAILED(rv)) return rv;
505 rv = Assert(entry, kNC_ContentLength, val, PR_TRUE);
506 if (NS_FAILED(rv)) return rv;
509 // lastmodified
510 PRTime tm;
511 rv = aIndex->GetLastModified(&tm);
512 if (NS_FAILED(rv)) return rv;
513 if (tm != -1) {
514 nsCOMPtr<nsIRDFDate> val;
515 rv = mDirRDF->GetDateLiteral(tm, getter_AddRefs(val));
516 if (NS_FAILED(rv)) return rv;
517 rv = Assert(entry, kNC_LastModified, val, PR_TRUE);
520 // filetype
521 PRUint32 type;
522 rv = aIndex->GetType(&type);
523 switch (type) {
524 case nsIDirIndex::TYPE_UNKNOWN:
525 rv = mDirRDF->GetLiteral(NS_LITERAL_STRING("UNKNOWN").get(), getter_AddRefs(lit));
526 break;
527 case nsIDirIndex::TYPE_DIRECTORY:
528 rv = mDirRDF->GetLiteral(NS_LITERAL_STRING("DIRECTORY").get(), getter_AddRefs(lit));
529 break;
530 case nsIDirIndex::TYPE_FILE:
531 rv = mDirRDF->GetLiteral(NS_LITERAL_STRING("FILE").get(), getter_AddRefs(lit));
532 break;
533 case nsIDirIndex::TYPE_SYMLINK:
534 rv = mDirRDF->GetLiteral(NS_LITERAL_STRING("SYMLINK").get(), getter_AddRefs(lit));
535 break;
538 if (NS_FAILED(rv)) return rv;
539 rv = Assert(entry, kNC_FileType, lit, PR_TRUE);
540 if (NS_FAILED(rv)) return rv;
543 // Since the definition of a directory depends on the protocol, we would have
544 // to do string comparisons all the time.
545 // But we're told if we're a container right here - so save that fact
546 if (isDirType)
547 Assert(entry, kNC_IsContainer, kTrueLiteral, PR_TRUE);
548 else
549 Assert(entry, kNC_IsContainer, kFalseLiteral, PR_TRUE);
551 // instead of
552 // rv = Assert(parentRes, kNC_Child, entry, PR_TRUE);
553 // if (NS_FAILED(rv)) return rv;
554 // defer insertion onto a timer so that the UI isn't starved
555 AddElement(parentRes, kNC_Child, entry);
558 return rv;
561 nsresult
562 nsHTTPIndex::OnInformationAvailable(nsIRequest *aRequest,
563 nsISupports *aCtxt,
564 const nsAString& aInfo) {
565 return NS_ERROR_NOT_IMPLEMENTED;
568 //----------------------------------------------------------------------
570 // nsHTTPIndex implementation
573 nsHTTPIndex::nsHTTPIndex()
574 : mBindToGlobalObject(PR_TRUE),
575 mRequestor(nsnull)
580 nsHTTPIndex::nsHTTPIndex(nsIInterfaceRequestor* aRequestor)
581 : mBindToGlobalObject(PR_TRUE),
582 mRequestor(aRequestor)
587 nsHTTPIndex::~nsHTTPIndex()
589 // note: these are NOT statics due to the native of nsHTTPIndex
590 // where it may or may not be treated as a singleton
592 if (mTimer)
594 // be sure to cancel the timer, as it holds a
595 // weak reference back to nsHTTPIndex
596 mTimer->Cancel();
597 mTimer = nsnull;
600 mConnectionList = nsnull;
601 mNodeList = nsnull;
603 if (mDirRDF)
605 // UnregisterDataSource() may fail; just ignore errors
606 mDirRDF->UnregisterDataSource(this);
612 nsresult
613 nsHTTPIndex::CommonInit()
615 nsresult rv = NS_OK;
617 // set initial/default encoding to ISO-8859-1 (not UTF-8)
618 mEncoding = "ISO-8859-1";
620 mDirRDF = do_GetService(kRDFServiceCID, &rv);
621 NS_ASSERTION(NS_SUCCEEDED(rv), "unable to get RDF service");
622 if (NS_FAILED(rv)) {
623 return(rv);
626 mInner = do_CreateInstance("@mozilla.org/rdf/datasource;1?name=in-memory-datasource", &rv);
628 if (NS_FAILED(rv))
629 return rv;
631 mDirRDF->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "child"),
632 getter_AddRefs(kNC_Child));
633 mDirRDF->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "loading"),
634 getter_AddRefs(kNC_Loading));
635 mDirRDF->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "Comment"),
636 getter_AddRefs(kNC_Comment));
637 mDirRDF->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "URL"),
638 getter_AddRefs(kNC_URL));
639 mDirRDF->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "Name"),
640 getter_AddRefs(kNC_Description));
641 mDirRDF->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "Content-Length"),
642 getter_AddRefs(kNC_ContentLength));
643 mDirRDF->GetResource(NS_LITERAL_CSTRING(WEB_NAMESPACE_URI "LastModifiedDate"),
644 getter_AddRefs(kNC_LastModified));
645 mDirRDF->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "Content-Type"),
646 getter_AddRefs(kNC_ContentType));
647 mDirRDF->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "File-Type"),
648 getter_AddRefs(kNC_FileType));
649 mDirRDF->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "IsContainer"),
650 getter_AddRefs(kNC_IsContainer));
652 rv = mDirRDF->GetLiteral(NS_LITERAL_STRING("true").get(), getter_AddRefs(kTrueLiteral));
653 if (NS_FAILED(rv)) return(rv);
654 rv = mDirRDF->GetLiteral(NS_LITERAL_STRING("false").get(), getter_AddRefs(kFalseLiteral));
655 if (NS_FAILED(rv)) return(rv);
657 rv = NS_NewISupportsArray(getter_AddRefs(mConnectionList));
658 if (NS_FAILED(rv)) return(rv);
660 // note: don't register DS here
661 return rv;
665 nsresult
666 nsHTTPIndex::Init()
668 nsresult rv;
670 // set initial/default encoding to ISO-8859-1 (not UTF-8)
671 mEncoding = "ISO-8859-1";
673 rv = CommonInit();
674 if (NS_FAILED(rv)) return(rv);
676 // (do this last) register this as a named data source with the RDF service
677 rv = mDirRDF->RegisterDataSource(this, PR_FALSE);
678 if (NS_FAILED(rv)) return(rv);
680 return(NS_OK);
685 nsresult
686 nsHTTPIndex::Init(nsIURI* aBaseURL)
688 NS_PRECONDITION(aBaseURL != nsnull, "null ptr");
689 if (! aBaseURL)
690 return NS_ERROR_NULL_POINTER;
692 nsresult rv;
694 rv = CommonInit();
695 if (NS_FAILED(rv)) return(rv);
697 // note: don't register DS here (singleton case)
699 rv = aBaseURL->GetSpec(mBaseURL);
700 if (NS_FAILED(rv)) return rv;
702 // Mark the base url as a container
703 nsCOMPtr<nsIRDFResource> baseRes;
704 mDirRDF->GetResource(mBaseURL, getter_AddRefs(baseRes));
705 Assert(baseRes, kNC_IsContainer, kTrueLiteral, PR_TRUE);
707 return NS_OK;
712 nsresult
713 nsHTTPIndex::Create(nsIURI* aBaseURL, nsIInterfaceRequestor* aRequestor,
714 nsIHTTPIndex** aResult)
716 *aResult = nsnull;
718 nsHTTPIndex* result = new nsHTTPIndex(aRequestor);
719 if (! result)
720 return NS_ERROR_OUT_OF_MEMORY;
722 nsresult rv = result->Init(aBaseURL);
723 if (NS_SUCCEEDED(rv))
725 NS_ADDREF(result);
726 *aResult = result;
728 else
730 delete result;
732 return rv;
735 NS_IMETHODIMP
736 nsHTTPIndex::GetBaseURL(char** _result)
738 *_result = ToNewCString(mBaseURL);
739 if (! *_result)
740 return NS_ERROR_OUT_OF_MEMORY;
742 return NS_OK;
745 NS_IMETHODIMP
746 nsHTTPIndex::GetDataSource(nsIRDFDataSource** _result)
748 NS_ADDREF(*_result = this);
749 return NS_OK;
752 // This function finds the destination when following a given nsIRDFResource
753 // If the resource has a URL attribute, we use that. If not, just use
754 // the uri.
756 // Do NOT try to get the destination of a uri in any other way
757 void nsHTTPIndex::GetDestination(nsIRDFResource* r, nsXPIDLCString& dest) {
758 // First try the URL attribute
759 nsCOMPtr<nsIRDFNode> node;
761 GetTarget(r, kNC_URL, PR_TRUE, getter_AddRefs(node));
762 nsCOMPtr<nsIRDFLiteral> url;
764 if (node)
765 url = do_QueryInterface(node);
767 if (!url) {
768 const char* temp;
769 r->GetValueConst(&temp);
770 dest.Adopt(temp ? nsCRT::strdup(temp) : 0);
771 } else {
772 const PRUnichar* uri;
773 url->GetValueConst(&uri);
774 dest.Adopt(ToNewUTF8String(nsDependentString(uri)));
778 // rjc: isWellknownContainerURI() decides whether a URI is a container for which,
779 // when asked (say, by the template builder), we'll make a network connection
780 // to get its contents. For the moment, all we speak is ftp:// URLs, even though
781 // a) we can get "http-index" mimetypes for really anything
782 // b) we could easily handle file:// URLs here
783 // Q: Why don't we?
784 // A: The file system datasource ("rdf:file"); at some point, the two
785 // should be perhaps united. Until then, we can't aggregate both
786 // "rdf:file" and "http-index" (such as with bookmarks) because we'd
787 // get double the # of answers we really want... also, "rdf:file" is
788 // less expensive in terms of both memory usage as well as speed
790 // We also handle gopher now
793 // We use an rdf attribute to mark if this is a container or not.
794 // Note that we still have to do string comparisons as a fallback
795 // because stuff like the personal toolbar and bookmarks check whether
796 // a URL is a container, and we have no attribute in that case.
797 PRBool
798 nsHTTPIndex::isWellknownContainerURI(nsIRDFResource *r)
800 nsCOMPtr<nsIRDFNode> node;
801 GetTarget(r, kNC_IsContainer, PR_TRUE, getter_AddRefs(node));
803 PRBool isContainerFlag = PR_FALSE;
805 if (node && NS_SUCCEEDED(node->EqualsNode(kTrueLiteral, &isContainerFlag))) {
806 return isContainerFlag;
807 } else {
808 nsXPIDLCString uri;
810 // For gopher, we need to follow the URL attribute to get the
811 // real destination
812 GetDestination(r,uri);
814 if ((uri.get()) && (!strncmp(uri, kFTPProtocol, sizeof(kFTPProtocol) - 1))) {
815 if (uri.Last() == '/') {
816 isContainerFlag = PR_TRUE;
820 // A gopher url is of the form:
821 // gopher://example.com/xFileNameToGet
822 // where x is a single character representing the type of file
823 // 1 is a directory, and 7 is a search.
824 // Searches will cause a dialog to be popped up (asking the user what
825 // to search for), and so even though searches return a directory as a
826 // result, don't treat it as a directory here.
828 // The isContainerFlag test above will correctly handle this when a
829 // search url is passed in as the baseuri
830 if ((uri.get()) &&
831 (!strncmp(uri,kGopherProtocol, sizeof(kGopherProtocol)-1))) {
832 char* pos = PL_strchr(uri+sizeof(kGopherProtocol)-1, '/');
833 if (!pos || pos[1] == '\0' || pos[1] == '1')
834 isContainerFlag = PR_TRUE;
837 return isContainerFlag;
841 NS_IMETHODIMP
842 nsHTTPIndex::GetURI(char * *uri)
844 NS_PRECONDITION(uri != nsnull, "null ptr");
845 if (! uri)
846 return(NS_ERROR_NULL_POINTER);
848 if ((*uri = nsCRT::strdup("rdf:httpindex")) == nsnull)
849 return(NS_ERROR_OUT_OF_MEMORY);
851 return(NS_OK);
856 NS_IMETHODIMP
857 nsHTTPIndex::GetSource(nsIRDFResource *aProperty, nsIRDFNode *aTarget, PRBool aTruthValue,
858 nsIRDFResource **_retval)
860 nsresult rv = NS_ERROR_UNEXPECTED;
862 *_retval = nsnull;
864 if (mInner)
866 rv = mInner->GetSource(aProperty, aTarget, aTruthValue, _retval);
868 return(rv);
871 NS_IMETHODIMP
872 nsHTTPIndex::GetSources(nsIRDFResource *aProperty, nsIRDFNode *aTarget, PRBool aTruthValue,
873 nsISimpleEnumerator **_retval)
875 nsresult rv = NS_ERROR_UNEXPECTED;
877 if (mInner)
879 rv = mInner->GetSources(aProperty, aTarget, aTruthValue, _retval);
881 else
883 rv = NS_NewEmptyEnumerator(_retval);
885 return(rv);
888 NS_IMETHODIMP
889 nsHTTPIndex::GetTarget(nsIRDFResource *aSource, nsIRDFResource *aProperty, PRBool aTruthValue,
890 nsIRDFNode **_retval)
892 nsresult rv = NS_ERROR_UNEXPECTED;
894 *_retval = nsnull;
896 if ((aTruthValue) && (aProperty == kNC_Child) && isWellknownContainerURI(aSource))
898 // fake out the generic builder (i.e. return anything in this case)
899 // so that search containers never appear to be empty
900 NS_IF_ADDREF(aSource);
901 *_retval = aSource;
902 return(NS_OK);
905 if (mInner)
907 rv = mInner->GetTarget(aSource, aProperty, aTruthValue, _retval);
909 return(rv);
912 NS_IMETHODIMP
913 nsHTTPIndex::GetTargets(nsIRDFResource *aSource, nsIRDFResource *aProperty, PRBool aTruthValue,
914 nsISimpleEnumerator **_retval)
916 nsresult rv = NS_ERROR_UNEXPECTED;
918 if (mInner)
920 rv = mInner->GetTargets(aSource, aProperty, aTruthValue, _retval);
922 else
924 rv = NS_NewEmptyEnumerator(_retval);
927 if ((aProperty == kNC_Child) && isWellknownContainerURI(aSource))
929 PRBool doNetworkRequest = PR_TRUE;
930 if (NS_SUCCEEDED(rv) && (_retval))
932 // check and see if we already have data for the search in question;
933 // if we do, don't bother doing the search again
934 PRBool hasResults = PR_FALSE;
935 if (NS_SUCCEEDED((*_retval)->HasMoreElements(&hasResults)) &&
936 (hasResults == PR_TRUE))
938 doNetworkRequest = PR_FALSE;
942 // Note: if we need to do a network request, do it out-of-band
943 // (because the XUL template builder isn't re-entrant)
944 // by using a global connection list and an immediately-firing timer
946 if ((doNetworkRequest == PR_TRUE) && (mConnectionList))
948 PRInt32 connectionIndex = mConnectionList->IndexOf(aSource);
949 if (connectionIndex < 0)
951 // add aSource into list of connections to make
952 mConnectionList->AppendElement(aSource);
954 // if we don't have a timer about to fire, create one
955 // which should fire as soon as possible (out-of-band)
956 if (!mTimer)
958 mTimer = do_CreateInstance("@mozilla.org/timer;1", &rv);
959 NS_ASSERTION(NS_SUCCEEDED(rv), "unable to create a timer");
960 if (NS_SUCCEEDED(rv))
962 mTimer->InitWithFuncCallback(nsHTTPIndex::FireTimer, this, 1,
963 nsITimer::TYPE_ONE_SHOT);
964 // Note: don't addref "this" as we'll cancel the
965 // timer in the httpIndex destructor
972 return(rv);
976 nsresult
977 nsHTTPIndex::AddElement(nsIRDFResource *parent, nsIRDFResource *prop, nsIRDFNode *child)
979 nsresult rv;
981 if (!mNodeList)
983 rv = NS_NewISupportsArray(getter_AddRefs(mNodeList));
984 if (NS_FAILED(rv)) return(rv);
987 // order required: parent, prop, then child
988 mNodeList->AppendElement(parent);
989 mNodeList->AppendElement(prop);
990 mNodeList->AppendElement(child);
992 if (!mTimer)
994 mTimer = do_CreateInstance("@mozilla.org/timer;1", &rv);
995 NS_ASSERTION(NS_SUCCEEDED(rv), "unable to create a timer");
996 if (NS_FAILED(rv)) return(rv);
998 mTimer->InitWithFuncCallback(nsHTTPIndex::FireTimer, this, 1,
999 nsITimer::TYPE_ONE_SHOT);
1000 // Note: don't addref "this" as we'll cancel the
1001 // timer in the httpIndex destructor
1004 return(NS_OK);
1007 void
1008 nsHTTPIndex::FireTimer(nsITimer* aTimer, void* aClosure)
1010 nsHTTPIndex *httpIndex = static_cast<nsHTTPIndex *>(aClosure);
1011 if (!httpIndex) return;
1013 // don't return out of this loop as mTimer may need to be cancelled afterwards
1014 PRBool refireTimer = PR_FALSE;
1016 PRUint32 numItems = 0;
1017 if (httpIndex->mConnectionList)
1019 httpIndex->mConnectionList->Count(&numItems);
1020 if (numItems > 0)
1022 nsCOMPtr<nsISupports> isupports;
1023 httpIndex->mConnectionList->GetElementAt((PRUint32)0, getter_AddRefs(isupports));
1024 httpIndex->mConnectionList->RemoveElementAt((PRUint32)0);
1026 nsCOMPtr<nsIRDFResource> aSource;
1027 if (isupports) aSource = do_QueryInterface(isupports);
1029 nsXPIDLCString uri;
1030 if (aSource) {
1031 httpIndex->GetDestination(aSource, uri);
1034 if (!uri) {
1035 NS_ERROR("Could not reconstruct uri");
1036 return;
1039 nsresult rv = NS_OK;
1040 nsCOMPtr<nsIURI> url;
1042 rv = NS_NewURI(getter_AddRefs(url), uri.get());
1043 nsCOMPtr<nsIChannel> channel;
1044 if (NS_SUCCEEDED(rv) && (url)) {
1045 rv = NS_NewChannel(getter_AddRefs(channel), url, nsnull, nsnull);
1047 if (NS_SUCCEEDED(rv) && (channel)) {
1048 channel->SetNotificationCallbacks(httpIndex);
1049 rv = channel->AsyncOpen(httpIndex, aSource);
1053 if (httpIndex->mNodeList)
1055 httpIndex->mNodeList->Count(&numItems);
1056 if (numItems > 0)
1058 // account for order required: src, prop, then target
1059 numItems /=3;
1060 if (numItems > 10) numItems = 10;
1062 PRInt32 loop;
1063 for (loop=0; loop<(PRInt32)numItems; loop++)
1065 nsCOMPtr<nsISupports> isupports;
1066 httpIndex->mNodeList->GetElementAt((PRUint32)0, getter_AddRefs(isupports));
1067 httpIndex->mNodeList->RemoveElementAt((PRUint32)0);
1068 nsCOMPtr<nsIRDFResource> src;
1069 if (isupports) src = do_QueryInterface(isupports);
1070 httpIndex->mNodeList->GetElementAt((PRUint32)0, getter_AddRefs(isupports));
1071 httpIndex->mNodeList->RemoveElementAt((PRUint32)0);
1072 nsCOMPtr<nsIRDFResource> prop;
1073 if (isupports) prop = do_QueryInterface(isupports);
1075 httpIndex->mNodeList->GetElementAt((PRUint32)0, getter_AddRefs(isupports));
1076 httpIndex->mNodeList->RemoveElementAt((PRUint32)0);
1077 nsCOMPtr<nsIRDFNode> target;
1078 if (isupports) target = do_QueryInterface(isupports);
1080 if (src && prop && target)
1082 if (prop.get() == httpIndex->kNC_Loading)
1084 httpIndex->Unassert(src, prop, target);
1086 else
1088 httpIndex->Assert(src, prop, target, PR_TRUE);
1095 // check both lists to see if the timer needs to continue firing
1096 if (httpIndex->mConnectionList)
1098 httpIndex->mConnectionList->Count(&numItems);
1099 if (numItems > 0)
1101 refireTimer = PR_TRUE;
1103 else
1105 httpIndex->mConnectionList->Clear();
1108 if (httpIndex->mNodeList)
1110 httpIndex->mNodeList->Count(&numItems);
1111 if (numItems > 0)
1113 refireTimer = PR_TRUE;
1115 else
1117 httpIndex->mNodeList->Clear();
1121 // be sure to cancel the timer, as it holds a
1122 // weak reference back to nsHTTPIndex
1123 httpIndex->mTimer->Cancel();
1124 httpIndex->mTimer = nsnull;
1126 // after firing off any/all of the connections be sure
1127 // to cancel the timer if we don't need to refire it
1128 if (refireTimer)
1130 httpIndex->mTimer = do_CreateInstance("@mozilla.org/timer;1");
1131 if (httpIndex->mTimer)
1133 httpIndex->mTimer->InitWithFuncCallback(nsHTTPIndex::FireTimer, aClosure, 10,
1134 nsITimer::TYPE_ONE_SHOT);
1135 // Note: don't addref "this" as we'll cancel the
1136 // timer in the httpIndex destructor
1141 NS_IMETHODIMP
1142 nsHTTPIndex::Assert(nsIRDFResource *aSource, nsIRDFResource *aProperty, nsIRDFNode *aTarget,
1143 PRBool aTruthValue)
1145 nsresult rv = NS_ERROR_UNEXPECTED;
1146 if (mInner)
1148 rv = mInner->Assert(aSource, aProperty, aTarget, aTruthValue);
1150 return(rv);
1153 NS_IMETHODIMP
1154 nsHTTPIndex::Unassert(nsIRDFResource *aSource, nsIRDFResource *aProperty, nsIRDFNode *aTarget)
1156 nsresult rv = NS_ERROR_UNEXPECTED;
1157 if (mInner)
1159 rv = mInner->Unassert(aSource, aProperty, aTarget);
1161 return(rv);
1164 NS_IMETHODIMP
1165 nsHTTPIndex::Change(nsIRDFResource *aSource, nsIRDFResource *aProperty,
1166 nsIRDFNode *aOldTarget, nsIRDFNode *aNewTarget)
1168 nsresult rv = NS_ERROR_UNEXPECTED;
1169 if (mInner)
1171 rv = mInner->Change(aSource, aProperty, aOldTarget, aNewTarget);
1173 return(rv);
1176 NS_IMETHODIMP
1177 nsHTTPIndex::Move(nsIRDFResource *aOldSource, nsIRDFResource *aNewSource,
1178 nsIRDFResource *aProperty, nsIRDFNode *aTarget)
1180 nsresult rv = NS_ERROR_UNEXPECTED;
1181 if (mInner)
1183 rv = mInner->Move(aOldSource, aNewSource, aProperty, aTarget);
1185 return(rv);
1188 NS_IMETHODIMP
1189 nsHTTPIndex::HasAssertion(nsIRDFResource *aSource, nsIRDFResource *aProperty,
1190 nsIRDFNode *aTarget, PRBool aTruthValue, PRBool *_retval)
1192 nsresult rv = NS_ERROR_UNEXPECTED;
1193 if (mInner)
1195 rv = mInner->HasAssertion(aSource, aProperty, aTarget, aTruthValue, _retval);
1197 return(rv);
1200 NS_IMETHODIMP
1201 nsHTTPIndex::AddObserver(nsIRDFObserver *aObserver)
1203 nsresult rv = NS_ERROR_UNEXPECTED;
1204 if (mInner)
1206 rv = mInner->AddObserver(aObserver);
1208 return(rv);
1211 NS_IMETHODIMP
1212 nsHTTPIndex::RemoveObserver(nsIRDFObserver *aObserver)
1214 nsresult rv = NS_ERROR_UNEXPECTED;
1215 if (mInner)
1217 rv = mInner->RemoveObserver(aObserver);
1219 return(rv);
1222 NS_IMETHODIMP
1223 nsHTTPIndex::HasArcIn(nsIRDFNode *aNode, nsIRDFResource *aArc, PRBool *result)
1225 if (!mInner) {
1226 *result = PR_FALSE;
1227 return NS_OK;
1229 return mInner->HasArcIn(aNode, aArc, result);
1232 NS_IMETHODIMP
1233 nsHTTPIndex::HasArcOut(nsIRDFResource *aSource, nsIRDFResource *aArc, PRBool *result)
1235 if (aArc == kNC_Child && isWellknownContainerURI(aSource)) {
1236 *result = PR_TRUE;
1237 return NS_OK;
1240 if (mInner) {
1241 return mInner->HasArcOut(aSource, aArc, result);
1244 *result = PR_FALSE;
1245 return NS_OK;
1248 NS_IMETHODIMP
1249 nsHTTPIndex::ArcLabelsIn(nsIRDFNode *aNode, nsISimpleEnumerator **_retval)
1251 nsresult rv = NS_ERROR_UNEXPECTED;
1252 if (mInner)
1254 rv = mInner->ArcLabelsIn(aNode, _retval);
1256 return(rv);
1259 NS_IMETHODIMP
1260 nsHTTPIndex::ArcLabelsOut(nsIRDFResource *aSource, nsISimpleEnumerator **_retval)
1262 nsresult rv = NS_ERROR_UNEXPECTED;
1264 *_retval = nsnull;
1266 nsCOMPtr<nsISupportsArray> array;
1267 rv = NS_NewISupportsArray(getter_AddRefs(array));
1268 if (NS_FAILED(rv)) return rv;
1270 if (isWellknownContainerURI(aSource))
1272 array->AppendElement(kNC_Child);
1275 if (mInner)
1277 nsCOMPtr<nsISimpleEnumerator> anonArcs;
1278 rv = mInner->ArcLabelsOut(aSource, getter_AddRefs(anonArcs));
1279 PRBool hasResults = PR_TRUE;
1280 while (NS_SUCCEEDED(rv) &&
1281 NS_SUCCEEDED(anonArcs->HasMoreElements(&hasResults)) &&
1282 hasResults == PR_TRUE)
1284 nsCOMPtr<nsISupports> anonArc;
1285 if (NS_FAILED(anonArcs->GetNext(getter_AddRefs(anonArc))))
1286 break;
1287 array->AppendElement(anonArc);
1291 return NS_NewArrayEnumerator(_retval, array);
1294 NS_IMETHODIMP
1295 nsHTTPIndex::GetAllResources(nsISimpleEnumerator **_retval)
1297 nsresult rv = NS_ERROR_UNEXPECTED;
1298 if (mInner)
1300 rv = mInner->GetAllResources(_retval);
1302 return(rv);
1305 NS_IMETHODIMP
1306 nsHTTPIndex::IsCommandEnabled(nsISupportsArray *aSources, nsIRDFResource *aCommand,
1307 nsISupportsArray *aArguments, PRBool *_retval)
1309 nsresult rv = NS_ERROR_UNEXPECTED;
1310 if (mInner)
1312 rv = mInner->IsCommandEnabled(aSources, aCommand, aArguments, _retval);
1314 return(rv);
1317 NS_IMETHODIMP
1318 nsHTTPIndex::DoCommand(nsISupportsArray *aSources, nsIRDFResource *aCommand,
1319 nsISupportsArray *aArguments)
1321 nsresult rv = NS_ERROR_UNEXPECTED;
1322 if (mInner)
1324 rv = mInner->DoCommand(aSources, aCommand, aArguments);
1326 return(rv);
1329 NS_IMETHODIMP
1330 nsHTTPIndex::BeginUpdateBatch()
1332 return mInner->BeginUpdateBatch();
1335 NS_IMETHODIMP
1336 nsHTTPIndex::EndUpdateBatch()
1338 return mInner->EndUpdateBatch();
1341 NS_IMETHODIMP
1342 nsHTTPIndex::GetAllCmds(nsIRDFResource *aSource, nsISimpleEnumerator **_retval)
1344 nsresult rv = NS_ERROR_UNEXPECTED;
1345 if (mInner)
1347 rv = mInner->GetAllCmds(aSource, _retval);
1349 return(rv);
1352 #endif /* MOZ_RDF */
1355 //----------------------------------------------------------------------
1357 // nsDirectoryViewerFactory
1359 nsDirectoryViewerFactory::nsDirectoryViewerFactory()
1365 nsDirectoryViewerFactory::~nsDirectoryViewerFactory()
1370 NS_IMPL_ISUPPORTS1(nsDirectoryViewerFactory, nsIDocumentLoaderFactory)
1374 NS_IMETHODIMP
1375 nsDirectoryViewerFactory::CreateInstance(const char *aCommand,
1376 nsIChannel* aChannel,
1377 nsILoadGroup* aLoadGroup,
1378 const char* aContentType,
1379 nsISupports* aContainer,
1380 nsISupports* aExtraInfo,
1381 nsIStreamListener** aDocListenerResult,
1382 nsIContentViewer** aDocViewerResult)
1384 nsresult rv;
1386 // OK - are we going to be using the html listing or not?
1387 nsCOMPtr<nsIPrefBranch> prefSrv = do_GetService(NS_PREFSERVICE_CONTRACTID, &rv);
1388 if (NS_FAILED(rv)) return rv;
1390 PRBool useXUL = PR_FALSE;
1391 PRBool viewSource = (PL_strstr(aContentType,"view-source") != 0);
1393 #ifdef MOZ_RDF
1394 PRInt32 dirPref;
1395 rv = prefSrv->GetIntPref("network.dir.format", &dirPref);
1396 if (NS_SUCCEEDED(rv) && dirPref == FORMAT_XUL) {
1397 useXUL = PR_TRUE;
1400 if ((NS_FAILED(rv) || useXUL) && !viewSource) {
1401 // ... and setup the original channel's content type
1402 (void)aChannel->SetContentType(NS_LITERAL_CSTRING("application/vnd.mozilla.xul+xml"));
1404 // This is where we shunt the HTTP/Index stream into our datasource,
1405 // and open the directory viewer XUL file as the content stream to
1406 // load in its place.
1408 // Create a dummy loader that will load a stub XUL document.
1409 nsCOMPtr<nsICategoryManager> catMan(do_GetService(NS_CATEGORYMANAGER_CONTRACTID, &rv));
1410 if (NS_FAILED(rv))
1411 return rv;
1412 nsXPIDLCString contractID;
1413 rv = catMan->GetCategoryEntry("Gecko-Content-Viewers", "application/vnd.mozilla.xul+xml",
1414 getter_Copies(contractID));
1415 if (NS_FAILED(rv))
1416 return rv;
1418 nsCOMPtr<nsIDocumentLoaderFactory> factory(do_GetService(contractID, &rv));
1419 if (NS_FAILED(rv)) return rv;
1421 nsCOMPtr<nsIURI> uri;
1422 rv = NS_NewURI(getter_AddRefs(uri), "chrome://communicator/content/directory/directory.xul");
1423 if (NS_FAILED(rv)) return rv;
1425 nsCOMPtr<nsIChannel> channel;
1426 rv = NS_NewChannel(getter_AddRefs(channel), uri, nsnull, aLoadGroup);
1427 if (NS_FAILED(rv)) return rv;
1429 nsCOMPtr<nsIStreamListener> listener;
1430 rv = factory->CreateInstance(aCommand, channel, aLoadGroup, "application/vnd.mozilla.xul+xml",
1431 aContainer, aExtraInfo, getter_AddRefs(listener),
1432 aDocViewerResult);
1433 if (NS_FAILED(rv)) return rv;
1435 rv = channel->AsyncOpen(listener, nsnull);
1436 if (NS_FAILED(rv)) return rv;
1438 // Create an HTTPIndex object so that we can stuff it into the script context
1439 nsCOMPtr<nsIURI> baseuri;
1440 rv = aChannel->GetURI(getter_AddRefs(baseuri));
1441 if (NS_FAILED(rv)) return rv;
1443 nsCOMPtr<nsIInterfaceRequestor> requestor = do_QueryInterface(aContainer,&rv);
1444 if (NS_FAILED(rv)) return rv;
1446 nsCOMPtr<nsIHTTPIndex> httpindex;
1447 rv = nsHTTPIndex::Create(baseuri, requestor, getter_AddRefs(httpindex));
1448 if (NS_FAILED(rv)) return rv;
1450 // Now shanghai the stream into our http-index parsing datasource
1451 // wrapper beastie.
1452 listener = do_QueryInterface(httpindex,&rv);
1453 *aDocListenerResult = listener.get();
1454 NS_ADDREF(*aDocListenerResult);
1456 return NS_OK;
1458 #endif
1460 // setup the original channel's content type
1461 (void)aChannel->SetContentType(NS_LITERAL_CSTRING("text/html"));
1463 // Otherwise, lets use the html listing
1464 nsCOMPtr<nsICategoryManager> catMan(do_GetService(NS_CATEGORYMANAGER_CONTRACTID, &rv));
1465 if (NS_FAILED(rv))
1466 return rv;
1467 nsXPIDLCString contractID;
1468 rv = catMan->GetCategoryEntry("Gecko-Content-Viewers", "text/html",
1469 getter_Copies(contractID));
1470 if (NS_FAILED(rv))
1471 return rv;
1473 nsCOMPtr<nsIDocumentLoaderFactory> factory(do_GetService(contractID, &rv));
1474 if (NS_FAILED(rv)) return rv;
1476 nsCOMPtr<nsIStreamListener> listener;
1478 if (viewSource) {
1479 rv = factory->CreateInstance("view-source", aChannel, aLoadGroup, "text/html; x-view-type=view-source",
1480 aContainer, aExtraInfo, getter_AddRefs(listener),
1481 aDocViewerResult);
1482 } else {
1483 rv = factory->CreateInstance("view", aChannel, aLoadGroup, "text/html",
1484 aContainer, aExtraInfo, getter_AddRefs(listener),
1485 aDocViewerResult);
1488 if (NS_FAILED(rv)) return rv;
1490 nsCOMPtr<nsIStreamConverterService> scs = do_GetService("@mozilla.org/streamConverters;1", &rv);
1491 if (NS_FAILED(rv)) return rv;
1493 rv = scs->AsyncConvertData("application/http-index-format",
1494 "text/html",
1495 listener,
1496 nsnull,
1497 aDocListenerResult);
1499 if (NS_FAILED(rv)) return rv;
1501 return NS_OK;
1506 NS_IMETHODIMP
1507 nsDirectoryViewerFactory::CreateInstanceForDocument(nsISupports* aContainer,
1508 nsIDocument* aDocument,
1509 const char *aCommand,
1510 nsIContentViewer** aDocViewerResult)
1512 NS_NOTYETIMPLEMENTED("didn't expect to get here");
1513 return NS_ERROR_NOT_IMPLEMENTED;
1516 NS_IMETHODIMP
1517 nsDirectoryViewerFactory::CreateBlankDocument(nsILoadGroup *aLoadGroup,
1518 nsIPrincipal *aPrincipal,
1519 nsIDocument **_retval) {
1521 NS_NOTYETIMPLEMENTED("didn't expect to get here");
1522 return NS_ERROR_NOT_IMPLEMENTED;