michael@0: /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: /* michael@0: michael@0: A directory viewer object. Parses "application/http-index-format" michael@0: per Lou Montulli's original spec: michael@0: michael@0: http://www.mozilla.org/projects/netlib/dirindexformat.html michael@0: michael@0: One added change is for a description entry, for when the michael@0: target does not match the filename michael@0: michael@0: */ michael@0: michael@0: #include "nsDirectoryViewer.h" michael@0: #include "nsIDirIndex.h" michael@0: #include "nsIDocShell.h" michael@0: #include "jsapi.h" michael@0: #include "nsCOMPtr.h" michael@0: #include "nsCRT.h" michael@0: #include "nsEnumeratorUtils.h" michael@0: #include "nsEscape.h" michael@0: #include "nsIRDFService.h" michael@0: #include "nsRDFCID.h" michael@0: #include "rdf.h" michael@0: #include "nsIScriptContext.h" michael@0: #include "nsIScriptGlobalObject.h" michael@0: #include "nsIServiceManager.h" michael@0: #include "nsISupportsArray.h" michael@0: #include "nsIXPConnect.h" michael@0: #include "nsEnumeratorUtils.h" michael@0: #include "nsString.h" michael@0: #include "nsXPIDLString.h" michael@0: #include "nsReadableUtils.h" michael@0: #include "nsITextToSubURI.h" michael@0: #include "nsIInterfaceRequestor.h" michael@0: #include "nsIInterfaceRequestorUtils.h" michael@0: #include "nsIFTPChannel.h" michael@0: #include "nsIWindowWatcher.h" michael@0: #include "nsIPrompt.h" michael@0: #include "nsIAuthPrompt.h" michael@0: #include "nsIProgressEventSink.h" michael@0: #include "nsIDOMWindow.h" michael@0: #include "nsIDOMWindowCollection.h" michael@0: #include "nsIDOMElement.h" michael@0: #include "nsIStreamConverterService.h" michael@0: #include "nsICategoryManager.h" michael@0: #include "nsXPCOMCID.h" michael@0: #include "nsIDocument.h" michael@0: #include "mozilla/Preferences.h" michael@0: #include "nsCxPusher.h" michael@0: michael@0: using namespace mozilla; michael@0: michael@0: static const int FORMAT_XUL = 3; michael@0: michael@0: //---------------------------------------------------------------------- michael@0: // michael@0: // Common CIDs michael@0: // michael@0: michael@0: static NS_DEFINE_CID(kRDFServiceCID, NS_RDFSERVICE_CID); michael@0: michael@0: // Various protocols we have to special case michael@0: static const char kFTPProtocol[] = "ftp://"; michael@0: michael@0: //---------------------------------------------------------------------- michael@0: // michael@0: // nsHTTPIndex michael@0: // michael@0: michael@0: NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsHTTPIndex) michael@0: NS_INTERFACE_MAP_ENTRY(nsIHTTPIndex) michael@0: NS_INTERFACE_MAP_ENTRY(nsIRDFDataSource) michael@0: NS_INTERFACE_MAP_ENTRY(nsIStreamListener) michael@0: NS_INTERFACE_MAP_ENTRY(nsIDirIndexListener) michael@0: NS_INTERFACE_MAP_ENTRY(nsIRequestObserver) michael@0: NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor) michael@0: NS_INTERFACE_MAP_ENTRY(nsIFTPEventSink) michael@0: NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIHTTPIndex) michael@0: NS_INTERFACE_MAP_END michael@0: michael@0: NS_IMPL_CYCLE_COLLECTION(nsHTTPIndex, mInner) michael@0: NS_IMPL_CYCLE_COLLECTING_ADDREF(nsHTTPIndex) michael@0: NS_IMPL_CYCLE_COLLECTING_RELEASE(nsHTTPIndex) michael@0: michael@0: NS_IMETHODIMP michael@0: nsHTTPIndex::GetInterface(const nsIID &anIID, void **aResult ) michael@0: { michael@0: if (anIID.Equals(NS_GET_IID(nsIFTPEventSink))) { michael@0: // If we don't have a container to store the logged data michael@0: // then don't report ourselves back to the caller michael@0: michael@0: if (!mRequestor) michael@0: return NS_ERROR_NO_INTERFACE; michael@0: *aResult = static_cast(this); michael@0: NS_ADDREF(this); michael@0: return NS_OK; michael@0: } michael@0: michael@0: if (anIID.Equals(NS_GET_IID(nsIPrompt))) { michael@0: michael@0: if (!mRequestor) michael@0: return NS_ERROR_NO_INTERFACE; michael@0: michael@0: nsCOMPtr aDOMWindow = do_GetInterface(mRequestor); michael@0: if (!aDOMWindow) michael@0: return NS_ERROR_NO_INTERFACE; michael@0: michael@0: nsCOMPtr wwatch(do_GetService(NS_WINDOWWATCHER_CONTRACTID)); michael@0: michael@0: return wwatch->GetNewPrompter(aDOMWindow, (nsIPrompt**)aResult); michael@0: } michael@0: michael@0: if (anIID.Equals(NS_GET_IID(nsIAuthPrompt))) { michael@0: michael@0: if (!mRequestor) michael@0: return NS_ERROR_NO_INTERFACE; michael@0: michael@0: nsCOMPtr aDOMWindow = do_GetInterface(mRequestor); michael@0: if (!aDOMWindow) michael@0: return NS_ERROR_NO_INTERFACE; michael@0: michael@0: nsCOMPtr wwatch(do_GetService(NS_WINDOWWATCHER_CONTRACTID)); michael@0: michael@0: return wwatch->GetNewAuthPrompter(aDOMWindow, (nsIAuthPrompt**)aResult); michael@0: } michael@0: michael@0: if (anIID.Equals(NS_GET_IID(nsIProgressEventSink))) { michael@0: michael@0: if (!mRequestor) michael@0: return NS_ERROR_NO_INTERFACE; michael@0: michael@0: nsCOMPtr sink = do_GetInterface(mRequestor); michael@0: if (!sink) michael@0: return NS_ERROR_NO_INTERFACE; michael@0: michael@0: *aResult = sink; michael@0: NS_ADDREF((nsISupports*)*aResult); michael@0: return NS_OK; michael@0: } michael@0: michael@0: return NS_ERROR_NO_INTERFACE; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsHTTPIndex::OnFTPControlLog(bool server, const char *msg) michael@0: { michael@0: NS_ENSURE_TRUE(mRequestor, NS_OK); michael@0: michael@0: nsCOMPtr scriptGlobal(do_GetInterface(mRequestor)); michael@0: NS_ENSURE_TRUE(scriptGlobal, NS_OK); michael@0: michael@0: nsIScriptContext *context = scriptGlobal->GetContext(); michael@0: NS_ENSURE_TRUE(context, NS_OK); michael@0: michael@0: AutoPushJSContext cx(context->GetNativeContext()); michael@0: NS_ENSURE_TRUE(cx, NS_OK); michael@0: michael@0: JS::Rooted global(cx, JS::CurrentGlobalOrNull(cx)); michael@0: NS_ENSURE_TRUE(global, NS_OK); michael@0: michael@0: nsString unicodeMsg; michael@0: unicodeMsg.AssignWithConversion(msg); michael@0: JSString* jsMsgStr = JS_NewUCStringCopyZ(cx, unicodeMsg.get()); michael@0: NS_ENSURE_TRUE(jsMsgStr, NS_ERROR_OUT_OF_MEMORY); michael@0: michael@0: JS::AutoValueArray<2> params(cx); michael@0: params[0].setBoolean(server); michael@0: params[1].setString(jsMsgStr); michael@0: michael@0: JS::Rooted val(cx); michael@0: JS_CallFunctionName(cx, michael@0: global, michael@0: "OnFTPControlLog", michael@0: params, michael@0: &val); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsHTTPIndex::SetEncoding(const char *encoding) michael@0: { michael@0: mEncoding = encoding; michael@0: return(NS_OK); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsHTTPIndex::GetEncoding(char **encoding) michael@0: { michael@0: NS_PRECONDITION(encoding, "null ptr"); michael@0: if (! encoding) michael@0: return(NS_ERROR_NULL_POINTER); michael@0: michael@0: *encoding = ToNewCString(mEncoding); michael@0: if (!*encoding) michael@0: return(NS_ERROR_OUT_OF_MEMORY); michael@0: michael@0: return(NS_OK); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsHTTPIndex::OnStartRequest(nsIRequest *request, nsISupports* aContext) michael@0: { michael@0: nsresult rv; michael@0: michael@0: mParser = do_CreateInstance(NS_DIRINDEXPARSER_CONTRACTID, &rv); michael@0: if (NS_FAILED(rv)) return rv; michael@0: michael@0: rv = mParser->SetEncoding(mEncoding.get()); michael@0: if (NS_FAILED(rv)) return rv; michael@0: michael@0: rv = mParser->SetListener(this); michael@0: if (NS_FAILED(rv)) return rv; michael@0: michael@0: rv = mParser->OnStartRequest(request,aContext); michael@0: if (NS_FAILED(rv)) return rv; michael@0: michael@0: // This should only run once... michael@0: // Unless we don't have a container to start with michael@0: // (ie called from bookmarks as an rdf datasource) michael@0: if (mBindToGlobalObject && mRequestor) { michael@0: mBindToGlobalObject = false; michael@0: michael@0: // Now get the content viewer container's script object. michael@0: nsCOMPtr scriptGlobal(do_GetInterface(mRequestor)); michael@0: NS_ENSURE_TRUE(scriptGlobal, NS_ERROR_FAILURE); michael@0: michael@0: nsIScriptContext *context = scriptGlobal->GetContext(); michael@0: NS_ENSURE_TRUE(context, NS_ERROR_FAILURE); michael@0: michael@0: AutoPushJSContext cx(context->GetNativeContext()); michael@0: JS::Rooted global(cx, JS::CurrentGlobalOrNull(cx)); michael@0: michael@0: // Using XPConnect, wrap the HTTP index object... michael@0: static NS_DEFINE_CID(kXPConnectCID, NS_XPCONNECT_CID); michael@0: nsCOMPtr xpc(do_GetService(kXPConnectCID, &rv)); michael@0: if (NS_FAILED(rv)) return rv; michael@0: michael@0: nsCOMPtr wrapper; michael@0: rv = xpc->WrapNative(cx, michael@0: global, michael@0: static_cast(this), michael@0: NS_GET_IID(nsIHTTPIndex), michael@0: getter_AddRefs(wrapper)); michael@0: michael@0: NS_ASSERTION(NS_SUCCEEDED(rv), "unable to xpconnect-wrap http-index"); michael@0: if (NS_FAILED(rv)) return rv; michael@0: michael@0: JS::Rooted jsobj(cx, wrapper->GetJSObject()); michael@0: NS_ASSERTION(jsobj, michael@0: "unable to get jsobj from xpconnect wrapper"); michael@0: if (!jsobj) return NS_ERROR_UNEXPECTED; michael@0: michael@0: JS::Rooted jslistener(cx, OBJECT_TO_JSVAL(jsobj)); michael@0: michael@0: // ...and stuff it into the global context michael@0: bool ok = JS_SetProperty(cx, global, "HTTPIndex", jslistener); michael@0: NS_ASSERTION(ok, "unable to set Listener property"); michael@0: if (!ok) michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: if (!aContext) { michael@0: nsCOMPtr channel(do_QueryInterface(request)); michael@0: NS_ASSERTION(channel, "request should be a channel"); michael@0: michael@0: // lets hijack the notifications: michael@0: channel->SetNotificationCallbacks(this); michael@0: michael@0: // now create the top most resource michael@0: nsCOMPtr uri; michael@0: channel->GetURI(getter_AddRefs(uri)); michael@0: michael@0: nsAutoCString entryuriC; michael@0: uri->GetSpec(entryuriC); michael@0: michael@0: nsCOMPtr entry; michael@0: rv = mDirRDF->GetResource(entryuriC, getter_AddRefs(entry)); michael@0: michael@0: NS_ConvertUTF8toUTF16 uriUnicode(entryuriC); michael@0: michael@0: nsCOMPtr URLVal; michael@0: rv = mDirRDF->GetLiteral(uriUnicode.get(), getter_AddRefs(URLVal)); michael@0: michael@0: Assert(entry, kNC_URL, URLVal, true); michael@0: mDirectory = do_QueryInterface(entry); michael@0: } michael@0: else michael@0: { michael@0: // Get the directory from the context michael@0: mDirectory = do_QueryInterface(aContext); michael@0: } michael@0: michael@0: if (!mDirectory) { michael@0: request->Cancel(NS_BINDING_ABORTED); michael@0: return NS_BINDING_ABORTED; michael@0: } michael@0: michael@0: // Mark the directory as "loading" michael@0: rv = Assert(mDirectory, kNC_Loading, michael@0: kTrueLiteral, true); michael@0: if (NS_FAILED(rv)) return rv; michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: michael@0: NS_IMETHODIMP michael@0: nsHTTPIndex::OnStopRequest(nsIRequest *request, michael@0: nsISupports* aContext, michael@0: nsresult aStatus) michael@0: { michael@0: // If mDirectory isn't set, then we should just bail. Either an michael@0: // error occurred and OnStartRequest() never got called, or michael@0: // something exploded in OnStartRequest(). michael@0: if (! mDirectory) michael@0: return NS_BINDING_ABORTED; michael@0: michael@0: mParser->OnStopRequest(request,aContext,aStatus); michael@0: michael@0: nsresult rv; michael@0: michael@0: nsXPIDLCString commentStr; michael@0: mParser->GetComment(getter_Copies(commentStr)); michael@0: michael@0: nsCOMPtr comment; michael@0: rv = mDirRDF->GetLiteral(NS_ConvertASCIItoUTF16(commentStr).get(), getter_AddRefs(comment)); michael@0: if (NS_FAILED(rv)) return rv; michael@0: michael@0: rv = Assert(mDirectory, kNC_Comment, comment, true); michael@0: if (NS_FAILED(rv)) return rv; michael@0: michael@0: // hack: Remove the 'loading' annotation (ignore errors) michael@0: AddElement(mDirectory, kNC_Loading, kTrueLiteral); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: michael@0: NS_IMETHODIMP michael@0: nsHTTPIndex::OnDataAvailable(nsIRequest *request, michael@0: nsISupports* aContext, michael@0: nsIInputStream* aStream, michael@0: uint64_t aSourceOffset, michael@0: uint32_t aCount) michael@0: { michael@0: // If mDirectory isn't set, then we should just bail. Either an michael@0: // error occurred and OnStartRequest() never got called, or michael@0: // something exploded in OnStartRequest(). michael@0: if (! mDirectory) michael@0: return NS_BINDING_ABORTED; michael@0: michael@0: return mParser->OnDataAvailable(request, mDirectory, aStream, aSourceOffset, aCount); michael@0: } michael@0: michael@0: michael@0: nsresult michael@0: nsHTTPIndex::OnIndexAvailable(nsIRequest* aRequest, nsISupports *aContext, michael@0: nsIDirIndex* aIndex) michael@0: { michael@0: nsCOMPtr parentRes = do_QueryInterface(aContext); michael@0: if (!parentRes) { michael@0: NS_ERROR("Could not obtain parent resource"); michael@0: return(NS_ERROR_UNEXPECTED); michael@0: } michael@0: michael@0: const char* baseStr; michael@0: parentRes->GetValueConst(&baseStr); michael@0: if (! baseStr) { michael@0: NS_ERROR("Could not reconstruct base uri"); michael@0: return NS_ERROR_UNEXPECTED; michael@0: } michael@0: michael@0: // we found the filename; construct a resource for its entry michael@0: nsAutoCString entryuriC(baseStr); michael@0: michael@0: nsXPIDLCString filename; michael@0: nsresult rv = aIndex->GetLocation(getter_Copies(filename)); michael@0: if (NS_FAILED(rv)) return rv; michael@0: entryuriC.Append(filename); michael@0: michael@0: // if its a directory, make sure it ends with a trailing slash. michael@0: uint32_t type; michael@0: rv = aIndex->GetType(&type); michael@0: if (NS_FAILED(rv)) michael@0: return rv; michael@0: michael@0: bool isDirType = (type == nsIDirIndex::TYPE_DIRECTORY); michael@0: if (isDirType && entryuriC.Last() != '/') { michael@0: entryuriC.Append('/'); michael@0: } michael@0: michael@0: nsCOMPtr entry; michael@0: rv = mDirRDF->GetResource(entryuriC, getter_AddRefs(entry)); michael@0: michael@0: // At this point, we'll (hopefully) have found the filename and michael@0: // constructed a resource for it, stored in entry. So now take a michael@0: // second pass through the values and add as statements to the RDF michael@0: // datasource. michael@0: michael@0: if (entry && NS_SUCCEEDED(rv)) { michael@0: nsCOMPtr lit; michael@0: nsString str; michael@0: michael@0: str.AssignWithConversion(entryuriC.get()); michael@0: michael@0: rv = mDirRDF->GetLiteral(str.get(), getter_AddRefs(lit)); michael@0: michael@0: if (NS_SUCCEEDED(rv)) { michael@0: rv = Assert(entry, kNC_URL, lit, true); michael@0: if (NS_FAILED(rv)) return rv; michael@0: michael@0: nsXPIDLString xpstr; michael@0: michael@0: // description michael@0: rv = aIndex->GetDescription(getter_Copies(xpstr)); michael@0: if (NS_FAILED(rv)) return rv; michael@0: if (xpstr.Last() == '/') michael@0: xpstr.Truncate(xpstr.Length() - 1); michael@0: michael@0: rv = mDirRDF->GetLiteral(xpstr.get(), getter_AddRefs(lit)); michael@0: if (NS_FAILED(rv)) return rv; michael@0: rv = Assert(entry, kNC_Description, lit, true); michael@0: if (NS_FAILED(rv)) return rv; michael@0: michael@0: // contentlength michael@0: int64_t size; michael@0: rv = aIndex->GetSize(&size); michael@0: if (NS_FAILED(rv)) return rv; michael@0: int64_t minus1 = UINT64_MAX; michael@0: if (size != minus1) { michael@0: int32_t intSize = int32_t(size); michael@0: // XXX RDF should support 64 bit integers (bug 240160) michael@0: nsCOMPtr val; michael@0: rv = mDirRDF->GetIntLiteral(intSize, getter_AddRefs(val)); michael@0: if (NS_FAILED(rv)) return rv; michael@0: rv = Assert(entry, kNC_ContentLength, val, true); michael@0: if (NS_FAILED(rv)) return rv; michael@0: } michael@0: michael@0: // lastmodified michael@0: PRTime tm; michael@0: rv = aIndex->GetLastModified(&tm); michael@0: if (NS_FAILED(rv)) return rv; michael@0: if (tm != -1) { michael@0: nsCOMPtr val; michael@0: rv = mDirRDF->GetDateLiteral(tm, getter_AddRefs(val)); michael@0: if (NS_FAILED(rv)) return rv; michael@0: rv = Assert(entry, kNC_LastModified, val, true); michael@0: } michael@0: michael@0: // filetype michael@0: uint32_t type; michael@0: rv = aIndex->GetType(&type); michael@0: switch (type) { michael@0: case nsIDirIndex::TYPE_UNKNOWN: michael@0: rv = mDirRDF->GetLiteral(MOZ_UTF16("UNKNOWN"), getter_AddRefs(lit)); michael@0: break; michael@0: case nsIDirIndex::TYPE_DIRECTORY: michael@0: rv = mDirRDF->GetLiteral(MOZ_UTF16("DIRECTORY"), getter_AddRefs(lit)); michael@0: break; michael@0: case nsIDirIndex::TYPE_FILE: michael@0: rv = mDirRDF->GetLiteral(MOZ_UTF16("FILE"), getter_AddRefs(lit)); michael@0: break; michael@0: case nsIDirIndex::TYPE_SYMLINK: michael@0: rv = mDirRDF->GetLiteral(MOZ_UTF16("SYMLINK"), getter_AddRefs(lit)); michael@0: break; michael@0: } michael@0: michael@0: if (NS_FAILED(rv)) return rv; michael@0: rv = Assert(entry, kNC_FileType, lit, true); michael@0: if (NS_FAILED(rv)) return rv; michael@0: } michael@0: michael@0: // Since the definition of a directory depends on the protocol, we would have michael@0: // to do string comparisons all the time. michael@0: // But we're told if we're a container right here - so save that fact michael@0: if (isDirType) michael@0: Assert(entry, kNC_IsContainer, kTrueLiteral, true); michael@0: else michael@0: Assert(entry, kNC_IsContainer, kFalseLiteral, true); michael@0: michael@0: // instead of michael@0: // rv = Assert(parentRes, kNC_Child, entry, true); michael@0: // if (NS_FAILED(rv)) return rv; michael@0: // defer insertion onto a timer so that the UI isn't starved michael@0: AddElement(parentRes, kNC_Child, entry); michael@0: } michael@0: michael@0: return rv; michael@0: } michael@0: michael@0: nsresult michael@0: nsHTTPIndex::OnInformationAvailable(nsIRequest *aRequest, michael@0: nsISupports *aCtxt, michael@0: const nsAString& aInfo) { michael@0: return NS_ERROR_NOT_IMPLEMENTED; michael@0: } michael@0: michael@0: //---------------------------------------------------------------------- michael@0: // michael@0: // nsHTTPIndex implementation michael@0: // michael@0: michael@0: nsHTTPIndex::nsHTTPIndex() michael@0: : mBindToGlobalObject(true), michael@0: mRequestor(nullptr) michael@0: { michael@0: } michael@0: michael@0: michael@0: nsHTTPIndex::nsHTTPIndex(nsIInterfaceRequestor* aRequestor) michael@0: : mBindToGlobalObject(true), michael@0: mRequestor(aRequestor) michael@0: { michael@0: } michael@0: michael@0: michael@0: nsHTTPIndex::~nsHTTPIndex() michael@0: { michael@0: // note: these are NOT statics due to the native of nsHTTPIndex michael@0: // where it may or may not be treated as a singleton michael@0: michael@0: if (mTimer) michael@0: { michael@0: // be sure to cancel the timer, as it holds a michael@0: // weak reference back to nsHTTPIndex michael@0: mTimer->Cancel(); michael@0: mTimer = nullptr; michael@0: } michael@0: michael@0: mConnectionList = nullptr; michael@0: mNodeList = nullptr; michael@0: michael@0: if (mDirRDF) michael@0: { michael@0: // UnregisterDataSource() may fail; just ignore errors michael@0: mDirRDF->UnregisterDataSource(this); michael@0: } michael@0: } michael@0: michael@0: michael@0: michael@0: nsresult michael@0: nsHTTPIndex::CommonInit() michael@0: { michael@0: nsresult rv = NS_OK; michael@0: michael@0: // set initial/default encoding to ISO-8859-1 (not UTF-8) michael@0: mEncoding = "ISO-8859-1"; michael@0: michael@0: mDirRDF = do_GetService(kRDFServiceCID, &rv); michael@0: NS_ASSERTION(NS_SUCCEEDED(rv), "unable to get RDF service"); michael@0: if (NS_FAILED(rv)) { michael@0: return(rv); michael@0: } michael@0: michael@0: mInner = do_CreateInstance("@mozilla.org/rdf/datasource;1?name=in-memory-datasource", &rv); michael@0: michael@0: if (NS_FAILED(rv)) michael@0: return rv; michael@0: michael@0: mDirRDF->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "child"), michael@0: getter_AddRefs(kNC_Child)); michael@0: mDirRDF->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "loading"), michael@0: getter_AddRefs(kNC_Loading)); michael@0: mDirRDF->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "Comment"), michael@0: getter_AddRefs(kNC_Comment)); michael@0: mDirRDF->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "URL"), michael@0: getter_AddRefs(kNC_URL)); michael@0: mDirRDF->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "Name"), michael@0: getter_AddRefs(kNC_Description)); michael@0: mDirRDF->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "Content-Length"), michael@0: getter_AddRefs(kNC_ContentLength)); michael@0: mDirRDF->GetResource(NS_LITERAL_CSTRING(WEB_NAMESPACE_URI "LastModifiedDate"), michael@0: getter_AddRefs(kNC_LastModified)); michael@0: mDirRDF->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "Content-Type"), michael@0: getter_AddRefs(kNC_ContentType)); michael@0: mDirRDF->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "File-Type"), michael@0: getter_AddRefs(kNC_FileType)); michael@0: mDirRDF->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "IsContainer"), michael@0: getter_AddRefs(kNC_IsContainer)); michael@0: michael@0: rv = mDirRDF->GetLiteral(MOZ_UTF16("true"), getter_AddRefs(kTrueLiteral)); michael@0: if (NS_FAILED(rv)) return(rv); michael@0: rv = mDirRDF->GetLiteral(MOZ_UTF16("false"), getter_AddRefs(kFalseLiteral)); michael@0: if (NS_FAILED(rv)) return(rv); michael@0: michael@0: rv = NS_NewISupportsArray(getter_AddRefs(mConnectionList)); michael@0: if (NS_FAILED(rv)) return(rv); michael@0: michael@0: // note: don't register DS here michael@0: return rv; michael@0: } michael@0: michael@0: michael@0: nsresult michael@0: nsHTTPIndex::Init() michael@0: { michael@0: nsresult rv; michael@0: michael@0: // set initial/default encoding to ISO-8859-1 (not UTF-8) michael@0: mEncoding = "ISO-8859-1"; michael@0: michael@0: rv = CommonInit(); michael@0: if (NS_FAILED(rv)) return(rv); michael@0: michael@0: // (do this last) register this as a named data source with the RDF service michael@0: rv = mDirRDF->RegisterDataSource(this, false); michael@0: if (NS_FAILED(rv)) return(rv); michael@0: michael@0: return(NS_OK); michael@0: } michael@0: michael@0: michael@0: michael@0: nsresult michael@0: nsHTTPIndex::Init(nsIURI* aBaseURL) michael@0: { michael@0: NS_PRECONDITION(aBaseURL != nullptr, "null ptr"); michael@0: if (! aBaseURL) michael@0: return NS_ERROR_NULL_POINTER; michael@0: michael@0: nsresult rv; michael@0: michael@0: rv = CommonInit(); michael@0: if (NS_FAILED(rv)) return(rv); michael@0: michael@0: // note: don't register DS here (singleton case) michael@0: michael@0: rv = aBaseURL->GetSpec(mBaseURL); michael@0: if (NS_FAILED(rv)) return rv; michael@0: michael@0: // Mark the base url as a container michael@0: nsCOMPtr baseRes; michael@0: mDirRDF->GetResource(mBaseURL, getter_AddRefs(baseRes)); michael@0: Assert(baseRes, kNC_IsContainer, kTrueLiteral, true); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: michael@0: michael@0: nsresult michael@0: nsHTTPIndex::Create(nsIURI* aBaseURL, nsIInterfaceRequestor* aRequestor, michael@0: nsIHTTPIndex** aResult) michael@0: { michael@0: *aResult = nullptr; michael@0: michael@0: nsHTTPIndex* result = new nsHTTPIndex(aRequestor); michael@0: if (! result) michael@0: return NS_ERROR_OUT_OF_MEMORY; michael@0: michael@0: nsresult rv = result->Init(aBaseURL); michael@0: if (NS_SUCCEEDED(rv)) michael@0: { michael@0: NS_ADDREF(result); michael@0: *aResult = result; michael@0: } michael@0: else michael@0: { michael@0: delete result; michael@0: } michael@0: return rv; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsHTTPIndex::GetBaseURL(char** _result) michael@0: { michael@0: *_result = ToNewCString(mBaseURL); michael@0: if (! *_result) michael@0: return NS_ERROR_OUT_OF_MEMORY; michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsHTTPIndex::GetDataSource(nsIRDFDataSource** _result) michael@0: { michael@0: NS_ADDREF(*_result = this); michael@0: return NS_OK; michael@0: } michael@0: michael@0: // This function finds the destination when following a given nsIRDFResource michael@0: // If the resource has a URL attribute, we use that. If not, just use michael@0: // the uri. michael@0: // michael@0: // Do NOT try to get the destination of a uri in any other way michael@0: void nsHTTPIndex::GetDestination(nsIRDFResource* r, nsXPIDLCString& dest) { michael@0: // First try the URL attribute michael@0: nsCOMPtr node; michael@0: michael@0: GetTarget(r, kNC_URL, true, getter_AddRefs(node)); michael@0: nsCOMPtr url; michael@0: michael@0: if (node) michael@0: url = do_QueryInterface(node); michael@0: michael@0: if (!url) { michael@0: const char* temp; michael@0: r->GetValueConst(&temp); michael@0: dest.Adopt(temp ? strdup(temp) : 0); michael@0: } else { michael@0: const char16_t* uri; michael@0: url->GetValueConst(&uri); michael@0: dest.Adopt(ToNewUTF8String(nsDependentString(uri))); michael@0: } michael@0: } michael@0: michael@0: // rjc: isWellknownContainerURI() decides whether a URI is a container for which, michael@0: // when asked (say, by the template builder), we'll make a network connection michael@0: // to get its contents. For the moment, all we speak is ftp:// URLs, even though michael@0: // a) we can get "http-index" mimetypes for really anything michael@0: // b) we could easily handle file:// URLs here michael@0: // Q: Why don't we? michael@0: // A: The file system datasource ("rdf:file"); at some point, the two michael@0: // should be perhaps united. Until then, we can't aggregate both michael@0: // "rdf:file" and "http-index" (such as with bookmarks) because we'd michael@0: // get double the # of answers we really want... also, "rdf:file" is michael@0: // less expensive in terms of both memory usage as well as speed michael@0: michael@0: michael@0: michael@0: // We use an rdf attribute to mark if this is a container or not. michael@0: // Note that we still have to do string comparisons as a fallback michael@0: // because stuff like the personal toolbar and bookmarks check whether michael@0: // a URL is a container, and we have no attribute in that case. michael@0: bool michael@0: nsHTTPIndex::isWellknownContainerURI(nsIRDFResource *r) michael@0: { michael@0: nsCOMPtr node; michael@0: GetTarget(r, kNC_IsContainer, true, getter_AddRefs(node)); michael@0: if (node) { michael@0: bool isContainerFlag; michael@0: if (NS_SUCCEEDED(node->EqualsNode(kTrueLiteral, &isContainerFlag))) michael@0: return isContainerFlag; michael@0: } michael@0: michael@0: nsXPIDLCString uri; michael@0: GetDestination(r, uri); michael@0: return uri.get() && !strncmp(uri, kFTPProtocol, sizeof(kFTPProtocol) - 1) && michael@0: (uri.Last() == '/'); michael@0: } michael@0: michael@0: michael@0: NS_IMETHODIMP michael@0: nsHTTPIndex::GetURI(char * *uri) michael@0: { michael@0: NS_PRECONDITION(uri != nullptr, "null ptr"); michael@0: if (! uri) michael@0: return(NS_ERROR_NULL_POINTER); michael@0: michael@0: if ((*uri = strdup("rdf:httpindex")) == nullptr) michael@0: return(NS_ERROR_OUT_OF_MEMORY); michael@0: michael@0: return(NS_OK); michael@0: } michael@0: michael@0: michael@0: michael@0: NS_IMETHODIMP michael@0: nsHTTPIndex::GetSource(nsIRDFResource *aProperty, nsIRDFNode *aTarget, bool aTruthValue, michael@0: nsIRDFResource **_retval) michael@0: { michael@0: nsresult rv = NS_ERROR_UNEXPECTED; michael@0: michael@0: *_retval = nullptr; michael@0: michael@0: if (mInner) michael@0: { michael@0: rv = mInner->GetSource(aProperty, aTarget, aTruthValue, _retval); michael@0: } michael@0: return(rv); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsHTTPIndex::GetSources(nsIRDFResource *aProperty, nsIRDFNode *aTarget, bool aTruthValue, michael@0: nsISimpleEnumerator **_retval) michael@0: { michael@0: nsresult rv = NS_ERROR_UNEXPECTED; michael@0: michael@0: if (mInner) michael@0: { michael@0: rv = mInner->GetSources(aProperty, aTarget, aTruthValue, _retval); michael@0: } michael@0: else michael@0: { michael@0: rv = NS_NewEmptyEnumerator(_retval); michael@0: } michael@0: return(rv); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsHTTPIndex::GetTarget(nsIRDFResource *aSource, nsIRDFResource *aProperty, bool aTruthValue, michael@0: nsIRDFNode **_retval) michael@0: { michael@0: nsresult rv = NS_ERROR_UNEXPECTED; michael@0: michael@0: *_retval = nullptr; michael@0: michael@0: if ((aTruthValue) && (aProperty == kNC_Child) && isWellknownContainerURI(aSource)) michael@0: { michael@0: // fake out the generic builder (i.e. return anything in this case) michael@0: // so that search containers never appear to be empty michael@0: NS_IF_ADDREF(aSource); michael@0: *_retval = aSource; michael@0: return(NS_OK); michael@0: } michael@0: michael@0: if (mInner) michael@0: { michael@0: rv = mInner->GetTarget(aSource, aProperty, aTruthValue, _retval); michael@0: } michael@0: return(rv); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsHTTPIndex::GetTargets(nsIRDFResource *aSource, nsIRDFResource *aProperty, bool aTruthValue, michael@0: nsISimpleEnumerator **_retval) michael@0: { michael@0: nsresult rv = NS_ERROR_UNEXPECTED; michael@0: michael@0: if (mInner) michael@0: { michael@0: rv = mInner->GetTargets(aSource, aProperty, aTruthValue, _retval); michael@0: } michael@0: else michael@0: { michael@0: rv = NS_NewEmptyEnumerator(_retval); michael@0: } michael@0: michael@0: if ((aProperty == kNC_Child) && isWellknownContainerURI(aSource)) michael@0: { michael@0: bool doNetworkRequest = true; michael@0: if (NS_SUCCEEDED(rv) && (_retval)) michael@0: { michael@0: // check and see if we already have data for the search in question; michael@0: // if we do, don't bother doing the search again michael@0: bool hasResults; michael@0: if (NS_SUCCEEDED((*_retval)->HasMoreElements(&hasResults)) && michael@0: hasResults) michael@0: doNetworkRequest = false; michael@0: } michael@0: michael@0: // Note: if we need to do a network request, do it out-of-band michael@0: // (because the XUL template builder isn't re-entrant) michael@0: // by using a global connection list and an immediately-firing timer michael@0: if (doNetworkRequest && mConnectionList) michael@0: { michael@0: int32_t connectionIndex = mConnectionList->IndexOf(aSource); michael@0: if (connectionIndex < 0) michael@0: { michael@0: // add aSource into list of connections to make michael@0: mConnectionList->AppendElement(aSource); michael@0: michael@0: // if we don't have a timer about to fire, create one michael@0: // which should fire as soon as possible (out-of-band) michael@0: if (!mTimer) michael@0: { michael@0: mTimer = do_CreateInstance("@mozilla.org/timer;1", &rv); michael@0: NS_ASSERTION(NS_SUCCEEDED(rv), "unable to create a timer"); michael@0: if (NS_SUCCEEDED(rv)) michael@0: { michael@0: mTimer->InitWithFuncCallback(nsHTTPIndex::FireTimer, this, 1, michael@0: nsITimer::TYPE_ONE_SHOT); michael@0: // Note: don't addref "this" as we'll cancel the michael@0: // timer in the httpIndex destructor michael@0: } michael@0: } michael@0: } michael@0: } michael@0: } michael@0: michael@0: return(rv); michael@0: } michael@0: michael@0: michael@0: nsresult michael@0: nsHTTPIndex::AddElement(nsIRDFResource *parent, nsIRDFResource *prop, nsIRDFNode *child) michael@0: { michael@0: nsresult rv; michael@0: michael@0: if (!mNodeList) michael@0: { michael@0: rv = NS_NewISupportsArray(getter_AddRefs(mNodeList)); michael@0: if (NS_FAILED(rv)) return(rv); michael@0: } michael@0: michael@0: // order required: parent, prop, then child michael@0: mNodeList->AppendElement(parent); michael@0: mNodeList->AppendElement(prop); michael@0: mNodeList->AppendElement(child); michael@0: michael@0: if (!mTimer) michael@0: { michael@0: mTimer = do_CreateInstance("@mozilla.org/timer;1", &rv); michael@0: NS_ASSERTION(NS_SUCCEEDED(rv), "unable to create a timer"); michael@0: if (NS_FAILED(rv)) return(rv); michael@0: michael@0: mTimer->InitWithFuncCallback(nsHTTPIndex::FireTimer, this, 1, michael@0: nsITimer::TYPE_ONE_SHOT); michael@0: // Note: don't addref "this" as we'll cancel the michael@0: // timer in the httpIndex destructor michael@0: } michael@0: michael@0: return(NS_OK); michael@0: } michael@0: michael@0: void michael@0: nsHTTPIndex::FireTimer(nsITimer* aTimer, void* aClosure) michael@0: { michael@0: nsHTTPIndex *httpIndex = static_cast(aClosure); michael@0: if (!httpIndex) return; michael@0: michael@0: // don't return out of this loop as mTimer may need to be cancelled afterwards michael@0: uint32_t numItems = 0; michael@0: if (httpIndex->mConnectionList) michael@0: { michael@0: httpIndex->mConnectionList->Count(&numItems); michael@0: if (numItems > 0) michael@0: { michael@0: nsCOMPtr isupports; michael@0: httpIndex->mConnectionList->GetElementAt((uint32_t)0, getter_AddRefs(isupports)); michael@0: httpIndex->mConnectionList->RemoveElementAt((uint32_t)0); michael@0: michael@0: nsCOMPtr aSource; michael@0: if (isupports) aSource = do_QueryInterface(isupports); michael@0: michael@0: nsXPIDLCString uri; michael@0: if (aSource) { michael@0: httpIndex->GetDestination(aSource, uri); michael@0: } michael@0: michael@0: if (!uri) { michael@0: NS_ERROR("Could not reconstruct uri"); michael@0: return; michael@0: } michael@0: michael@0: nsresult rv = NS_OK; michael@0: nsCOMPtr url; michael@0: michael@0: rv = NS_NewURI(getter_AddRefs(url), uri.get()); michael@0: nsCOMPtr channel; michael@0: if (NS_SUCCEEDED(rv) && (url)) { michael@0: rv = NS_NewChannel(getter_AddRefs(channel), url, nullptr, nullptr); michael@0: } michael@0: if (NS_SUCCEEDED(rv) && (channel)) { michael@0: channel->SetNotificationCallbacks(httpIndex); michael@0: rv = channel->AsyncOpen(httpIndex, aSource); michael@0: } michael@0: } michael@0: } michael@0: if (httpIndex->mNodeList) michael@0: { michael@0: httpIndex->mNodeList->Count(&numItems); michael@0: if (numItems > 0) michael@0: { michael@0: // account for order required: src, prop, then target michael@0: numItems /=3; michael@0: if (numItems > 10) numItems = 10; michael@0: michael@0: int32_t loop; michael@0: for (loop=0; loop<(int32_t)numItems; loop++) michael@0: { michael@0: nsCOMPtr isupports; michael@0: httpIndex->mNodeList->GetElementAt((uint32_t)0, getter_AddRefs(isupports)); michael@0: httpIndex->mNodeList->RemoveElementAt((uint32_t)0); michael@0: nsCOMPtr src; michael@0: if (isupports) src = do_QueryInterface(isupports); michael@0: httpIndex->mNodeList->GetElementAt((uint32_t)0, getter_AddRefs(isupports)); michael@0: httpIndex->mNodeList->RemoveElementAt((uint32_t)0); michael@0: nsCOMPtr prop; michael@0: if (isupports) prop = do_QueryInterface(isupports); michael@0: michael@0: httpIndex->mNodeList->GetElementAt((uint32_t)0, getter_AddRefs(isupports)); michael@0: httpIndex->mNodeList->RemoveElementAt((uint32_t)0); michael@0: nsCOMPtr target; michael@0: if (isupports) target = do_QueryInterface(isupports); michael@0: michael@0: if (src && prop && target) michael@0: { michael@0: if (prop.get() == httpIndex->kNC_Loading) michael@0: { michael@0: httpIndex->Unassert(src, prop, target); michael@0: } michael@0: else michael@0: { michael@0: httpIndex->Assert(src, prop, target, true); michael@0: } michael@0: } michael@0: } michael@0: } michael@0: } michael@0: michael@0: bool refireTimer = false; michael@0: // check both lists to see if the timer needs to continue firing michael@0: if (httpIndex->mConnectionList) michael@0: { michael@0: httpIndex->mConnectionList->Count(&numItems); michael@0: if (numItems > 0) michael@0: { michael@0: refireTimer = true; michael@0: } michael@0: else michael@0: { michael@0: httpIndex->mConnectionList->Clear(); michael@0: } michael@0: } michael@0: if (httpIndex->mNodeList) michael@0: { michael@0: httpIndex->mNodeList->Count(&numItems); michael@0: if (numItems > 0) michael@0: { michael@0: refireTimer = true; michael@0: } michael@0: else michael@0: { michael@0: httpIndex->mNodeList->Clear(); michael@0: } michael@0: } michael@0: michael@0: // be sure to cancel the timer, as it holds a michael@0: // weak reference back to nsHTTPIndex michael@0: httpIndex->mTimer->Cancel(); michael@0: httpIndex->mTimer = nullptr; michael@0: michael@0: // after firing off any/all of the connections be sure michael@0: // to cancel the timer if we don't need to refire it michael@0: if (refireTimer) michael@0: { michael@0: httpIndex->mTimer = do_CreateInstance("@mozilla.org/timer;1"); michael@0: if (httpIndex->mTimer) michael@0: { michael@0: httpIndex->mTimer->InitWithFuncCallback(nsHTTPIndex::FireTimer, aClosure, 10, michael@0: nsITimer::TYPE_ONE_SHOT); michael@0: // Note: don't addref "this" as we'll cancel the michael@0: // timer in the httpIndex destructor michael@0: } michael@0: } michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsHTTPIndex::Assert(nsIRDFResource *aSource, nsIRDFResource *aProperty, nsIRDFNode *aTarget, michael@0: bool aTruthValue) michael@0: { michael@0: nsresult rv = NS_ERROR_UNEXPECTED; michael@0: if (mInner) michael@0: { michael@0: rv = mInner->Assert(aSource, aProperty, aTarget, aTruthValue); michael@0: } michael@0: return(rv); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsHTTPIndex::Unassert(nsIRDFResource *aSource, nsIRDFResource *aProperty, nsIRDFNode *aTarget) michael@0: { michael@0: nsresult rv = NS_ERROR_UNEXPECTED; michael@0: if (mInner) michael@0: { michael@0: rv = mInner->Unassert(aSource, aProperty, aTarget); michael@0: } michael@0: return(rv); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsHTTPIndex::Change(nsIRDFResource *aSource, nsIRDFResource *aProperty, michael@0: nsIRDFNode *aOldTarget, nsIRDFNode *aNewTarget) michael@0: { michael@0: nsresult rv = NS_ERROR_UNEXPECTED; michael@0: if (mInner) michael@0: { michael@0: rv = mInner->Change(aSource, aProperty, aOldTarget, aNewTarget); michael@0: } michael@0: return(rv); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsHTTPIndex::Move(nsIRDFResource *aOldSource, nsIRDFResource *aNewSource, michael@0: nsIRDFResource *aProperty, nsIRDFNode *aTarget) michael@0: { michael@0: nsresult rv = NS_ERROR_UNEXPECTED; michael@0: if (mInner) michael@0: { michael@0: rv = mInner->Move(aOldSource, aNewSource, aProperty, aTarget); michael@0: } michael@0: return(rv); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsHTTPIndex::HasAssertion(nsIRDFResource *aSource, nsIRDFResource *aProperty, michael@0: nsIRDFNode *aTarget, bool aTruthValue, bool *_retval) michael@0: { michael@0: nsresult rv = NS_ERROR_UNEXPECTED; michael@0: if (mInner) michael@0: { michael@0: rv = mInner->HasAssertion(aSource, aProperty, aTarget, aTruthValue, _retval); michael@0: } michael@0: return(rv); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsHTTPIndex::AddObserver(nsIRDFObserver *aObserver) michael@0: { michael@0: nsresult rv = NS_ERROR_UNEXPECTED; michael@0: if (mInner) michael@0: { michael@0: rv = mInner->AddObserver(aObserver); michael@0: } michael@0: return(rv); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsHTTPIndex::RemoveObserver(nsIRDFObserver *aObserver) michael@0: { michael@0: nsresult rv = NS_ERROR_UNEXPECTED; michael@0: if (mInner) michael@0: { michael@0: rv = mInner->RemoveObserver(aObserver); michael@0: } michael@0: return(rv); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsHTTPIndex::HasArcIn(nsIRDFNode *aNode, nsIRDFResource *aArc, bool *result) michael@0: { michael@0: if (!mInner) { michael@0: *result = false; michael@0: return NS_OK; michael@0: } michael@0: return mInner->HasArcIn(aNode, aArc, result); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsHTTPIndex::HasArcOut(nsIRDFResource *aSource, nsIRDFResource *aArc, bool *result) michael@0: { michael@0: if (aArc == kNC_Child && isWellknownContainerURI(aSource)) { michael@0: *result = true; michael@0: return NS_OK; michael@0: } michael@0: michael@0: if (mInner) { michael@0: return mInner->HasArcOut(aSource, aArc, result); michael@0: } michael@0: michael@0: *result = false; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsHTTPIndex::ArcLabelsIn(nsIRDFNode *aNode, nsISimpleEnumerator **_retval) michael@0: { michael@0: nsresult rv = NS_ERROR_UNEXPECTED; michael@0: if (mInner) michael@0: { michael@0: rv = mInner->ArcLabelsIn(aNode, _retval); michael@0: } michael@0: return(rv); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsHTTPIndex::ArcLabelsOut(nsIRDFResource *aSource, nsISimpleEnumerator **_retval) michael@0: { michael@0: *_retval = nullptr; michael@0: michael@0: nsCOMPtr child, anonArcs; michael@0: if (isWellknownContainerURI(aSource)) michael@0: { michael@0: NS_NewSingletonEnumerator(getter_AddRefs(child), kNC_Child); michael@0: } michael@0: michael@0: if (mInner) michael@0: { michael@0: mInner->ArcLabelsOut(aSource, getter_AddRefs(anonArcs)); michael@0: } michael@0: michael@0: return NS_NewUnionEnumerator(_retval, child, anonArcs); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsHTTPIndex::GetAllResources(nsISimpleEnumerator **_retval) michael@0: { michael@0: nsresult rv = NS_ERROR_UNEXPECTED; michael@0: if (mInner) michael@0: { michael@0: rv = mInner->GetAllResources(_retval); michael@0: } michael@0: return(rv); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsHTTPIndex::IsCommandEnabled(nsISupportsArray *aSources, nsIRDFResource *aCommand, michael@0: nsISupportsArray *aArguments, bool *_retval) michael@0: { michael@0: nsresult rv = NS_ERROR_UNEXPECTED; michael@0: if (mInner) michael@0: { michael@0: rv = mInner->IsCommandEnabled(aSources, aCommand, aArguments, _retval); michael@0: } michael@0: return(rv); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsHTTPIndex::DoCommand(nsISupportsArray *aSources, nsIRDFResource *aCommand, michael@0: nsISupportsArray *aArguments) michael@0: { michael@0: nsresult rv = NS_ERROR_UNEXPECTED; michael@0: if (mInner) michael@0: { michael@0: rv = mInner->DoCommand(aSources, aCommand, aArguments); michael@0: } michael@0: return(rv); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsHTTPIndex::BeginUpdateBatch() michael@0: { michael@0: return mInner->BeginUpdateBatch(); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsHTTPIndex::EndUpdateBatch() michael@0: { michael@0: return mInner->EndUpdateBatch(); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsHTTPIndex::GetAllCmds(nsIRDFResource *aSource, nsISimpleEnumerator **_retval) michael@0: { michael@0: nsresult rv = NS_ERROR_UNEXPECTED; michael@0: if (mInner) michael@0: { michael@0: rv = mInner->GetAllCmds(aSource, _retval); michael@0: } michael@0: return(rv); michael@0: } michael@0: michael@0: michael@0: //---------------------------------------------------------------------- michael@0: // michael@0: // nsDirectoryViewerFactory michael@0: // michael@0: nsDirectoryViewerFactory::nsDirectoryViewerFactory() michael@0: { michael@0: } michael@0: michael@0: michael@0: michael@0: nsDirectoryViewerFactory::~nsDirectoryViewerFactory() michael@0: { michael@0: } michael@0: michael@0: michael@0: NS_IMPL_ISUPPORTS(nsDirectoryViewerFactory, nsIDocumentLoaderFactory) michael@0: michael@0: michael@0: michael@0: NS_IMETHODIMP michael@0: nsDirectoryViewerFactory::CreateInstance(const char *aCommand, michael@0: nsIChannel* aChannel, michael@0: nsILoadGroup* aLoadGroup, michael@0: const char* aContentType, michael@0: nsIDocShell* aContainer, michael@0: nsISupports* aExtraInfo, michael@0: nsIStreamListener** aDocListenerResult, michael@0: nsIContentViewer** aDocViewerResult) michael@0: { michael@0: nsresult rv; michael@0: michael@0: bool viewSource = (PL_strstr(aContentType,"view-source") != 0); michael@0: michael@0: if (!viewSource && michael@0: Preferences::GetInt("network.dir.format", FORMAT_XUL) == FORMAT_XUL) { michael@0: // ... and setup the original channel's content type michael@0: (void)aChannel->SetContentType(NS_LITERAL_CSTRING("application/vnd.mozilla.xul+xml")); michael@0: michael@0: // This is where we shunt the HTTP/Index stream into our datasource, michael@0: // and open the directory viewer XUL file as the content stream to michael@0: // load in its place. michael@0: michael@0: // Create a dummy loader that will load a stub XUL document. michael@0: nsCOMPtr catMan(do_GetService(NS_CATEGORYMANAGER_CONTRACTID, &rv)); michael@0: if (NS_FAILED(rv)) michael@0: return rv; michael@0: nsXPIDLCString contractID; michael@0: rv = catMan->GetCategoryEntry("Gecko-Content-Viewers", "application/vnd.mozilla.xul+xml", michael@0: getter_Copies(contractID)); michael@0: if (NS_FAILED(rv)) michael@0: return rv; michael@0: michael@0: nsCOMPtr factory(do_GetService(contractID, &rv)); michael@0: if (NS_FAILED(rv)) return rv; michael@0: michael@0: nsCOMPtr uri; michael@0: rv = NS_NewURI(getter_AddRefs(uri), "chrome://communicator/content/directory/directory.xul"); michael@0: if (NS_FAILED(rv)) return rv; michael@0: michael@0: nsCOMPtr channel; michael@0: rv = NS_NewChannel(getter_AddRefs(channel), uri, nullptr, aLoadGroup); michael@0: if (NS_FAILED(rv)) return rv; michael@0: michael@0: nsCOMPtr listener; michael@0: rv = factory->CreateInstance(aCommand, channel, aLoadGroup, "application/vnd.mozilla.xul+xml", michael@0: aContainer, aExtraInfo, getter_AddRefs(listener), michael@0: aDocViewerResult); michael@0: if (NS_FAILED(rv)) return rv; michael@0: michael@0: rv = channel->AsyncOpen(listener, nullptr); michael@0: if (NS_FAILED(rv)) return rv; michael@0: michael@0: // Create an HTTPIndex object so that we can stuff it into the script context michael@0: nsCOMPtr baseuri; michael@0: rv = aChannel->GetURI(getter_AddRefs(baseuri)); michael@0: if (NS_FAILED(rv)) return rv; michael@0: michael@0: nsCOMPtr requestor = do_QueryInterface(aContainer,&rv); michael@0: if (NS_FAILED(rv)) return rv; michael@0: michael@0: nsCOMPtr httpindex; michael@0: rv = nsHTTPIndex::Create(baseuri, requestor, getter_AddRefs(httpindex)); michael@0: if (NS_FAILED(rv)) return rv; michael@0: michael@0: // Now shanghai the stream into our http-index parsing datasource michael@0: // wrapper beastie. michael@0: listener = do_QueryInterface(httpindex,&rv); michael@0: *aDocListenerResult = listener.get(); michael@0: NS_ADDREF(*aDocListenerResult); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: // setup the original channel's content type michael@0: (void)aChannel->SetContentType(NS_LITERAL_CSTRING("text/html")); michael@0: michael@0: // Otherwise, lets use the html listing michael@0: nsCOMPtr catMan(do_GetService(NS_CATEGORYMANAGER_CONTRACTID, &rv)); michael@0: if (NS_FAILED(rv)) michael@0: return rv; michael@0: nsXPIDLCString contractID; michael@0: rv = catMan->GetCategoryEntry("Gecko-Content-Viewers", "text/html", michael@0: getter_Copies(contractID)); michael@0: if (NS_FAILED(rv)) michael@0: return rv; michael@0: michael@0: nsCOMPtr factory(do_GetService(contractID, &rv)); michael@0: if (NS_FAILED(rv)) return rv; michael@0: michael@0: nsCOMPtr listener; michael@0: michael@0: if (viewSource) { michael@0: rv = factory->CreateInstance("view-source", aChannel, aLoadGroup, "text/html; x-view-type=view-source", michael@0: aContainer, aExtraInfo, getter_AddRefs(listener), michael@0: aDocViewerResult); michael@0: } else { michael@0: rv = factory->CreateInstance("view", aChannel, aLoadGroup, "text/html", michael@0: aContainer, aExtraInfo, getter_AddRefs(listener), michael@0: aDocViewerResult); michael@0: } michael@0: michael@0: if (NS_FAILED(rv)) return rv; michael@0: michael@0: nsCOMPtr scs = do_GetService("@mozilla.org/streamConverters;1", &rv); michael@0: if (NS_FAILED(rv)) return rv; michael@0: michael@0: rv = scs->AsyncConvertData("application/http-index-format", michael@0: "text/html", michael@0: listener, michael@0: nullptr, michael@0: aDocListenerResult); michael@0: michael@0: if (NS_FAILED(rv)) return rv; michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: michael@0: michael@0: NS_IMETHODIMP michael@0: nsDirectoryViewerFactory::CreateInstanceForDocument(nsISupports* aContainer, michael@0: nsIDocument* aDocument, michael@0: const char *aCommand, michael@0: nsIContentViewer** aDocViewerResult) michael@0: { michael@0: NS_NOTYETIMPLEMENTED("didn't expect to get here"); michael@0: return NS_ERROR_NOT_IMPLEMENTED; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsDirectoryViewerFactory::CreateBlankDocument(nsILoadGroup *aLoadGroup, michael@0: nsIPrincipal *aPrincipal, michael@0: nsIDocument **_retval) { michael@0: michael@0: NS_NOTYETIMPLEMENTED("didn't expect to get here"); michael@0: return NS_ERROR_NOT_IMPLEMENTED; michael@0: }