diff options
Diffstat (limited to 'rdf/datasource')
-rw-r--r-- | rdf/datasource/moz.build | 22 | ||||
-rw-r--r-- | rdf/datasource/nsFileSystemDataSource.cpp | 1328 | ||||
-rw-r--r-- | rdf/datasource/nsFileSystemDataSource.h | 79 | ||||
-rw-r--r-- | rdf/datasource/nsILocalStore.h | 34 | ||||
-rw-r--r-- | rdf/datasource/nsIRDFFTP.h | 33 | ||||
-rw-r--r-- | rdf/datasource/nsLocalStore.cpp | 481 | ||||
-rw-r--r-- | rdf/datasource/nsRDFBuiltInDataSources.h | 27 |
7 files changed, 2004 insertions, 0 deletions
diff --git a/rdf/datasource/moz.build b/rdf/datasource/moz.build new file mode 100644 index 000000000..5341562ff --- /dev/null +++ b/rdf/datasource/moz.build @@ -0,0 +1,22 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +EXPORTS += [ + 'nsILocalStore.h', +] + +UNIFIED_SOURCES += [ + 'nsFileSystemDataSource.cpp', + 'nsLocalStore.cpp', +] + +FINAL_LIBRARY = 'xul' + +# "This is a dependency on rdfutil.h: it'll go away once that becomes +# a first-class XPCOM interface." +LOCAL_INCLUDES += [ + '/rdf/base', +] diff --git a/rdf/datasource/nsFileSystemDataSource.cpp b/rdf/datasource/nsFileSystemDataSource.cpp new file mode 100644 index 000000000..35632d1a3 --- /dev/null +++ b/rdf/datasource/nsFileSystemDataSource.cpp @@ -0,0 +1,1328 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* + Implementation for a file system RDF data store. + */ + +#include "nsFileSystemDataSource.h" + +#include <ctype.h> // for toupper() +#include <stdio.h> +#include "nsArrayEnumerator.h" +#include "nsCOMArray.h" +#include "nsIRDFDataSource.h" +#include "nsIRDFObserver.h" +#include "nsIServiceManager.h" +#include "nsXPIDLString.h" +#include "nsRDFCID.h" +#include "rdfutil.h" +#include "rdf.h" +#include "nsEnumeratorUtils.h" +#include "nsIURL.h" +#include "nsIFileURL.h" +#include "nsNetUtil.h" +#include "nsIInputStream.h" +#include "nsIChannel.h" +#include "nsIFile.h" +#include "nsEscape.h" +#include "nsCRTGlue.h" +#include "nsAutoPtr.h" +#include "prtime.h" + +#ifdef XP_WIN +#include "windef.h" +#include "winbase.h" +#include "nsILineInputStream.h" +#include "nsDirectoryServiceDefs.h" +#endif + +#define NS_MOZICON_SCHEME "moz-icon:" + +static const char kFileProtocol[] = "file://"; + +bool +FileSystemDataSource::isFileURI(nsIRDFResource *r) +{ + bool isFileURIFlag = false; + const char *uri = nullptr; + + r->GetValueConst(&uri); + if ((uri) && (!strncmp(uri, kFileProtocol, sizeof(kFileProtocol) - 1))) + { + // XXX HACK HACK HACK + if (!strchr(uri, '#')) + { + isFileURIFlag = true; + } + } + return(isFileURIFlag); +} + + + +bool +FileSystemDataSource::isDirURI(nsIRDFResource* source) +{ + nsresult rv; + const char *uri = nullptr; + + rv = source->GetValueConst(&uri); + if (NS_FAILED(rv)) return(false); + + nsCOMPtr<nsIFile> aDir; + + rv = NS_GetFileFromURLSpec(nsDependentCString(uri), getter_AddRefs(aDir)); + if (NS_FAILED(rv)) return(false); + + bool isDirFlag = false; + + rv = aDir->IsDirectory(&isDirFlag); + if (NS_FAILED(rv)) return(false); + + return(isDirFlag); +} + + +nsresult +FileSystemDataSource::Init() +{ + nsresult rv; + + mRDFService = do_GetService("@mozilla.org/rdf/rdf-service;1"); + NS_ENSURE_TRUE(mRDFService, NS_ERROR_FAILURE); + + rv = mRDFService->GetResource(NS_LITERAL_CSTRING("NC:FilesRoot"), + getter_AddRefs(mNC_FileSystemRoot)); + nsresult tmp = mRDFService->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "child"), + getter_AddRefs(mNC_Child)); + if (NS_FAILED(tmp)) { + rv = tmp; + } + tmp = mRDFService->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "Name"), + getter_AddRefs(mNC_Name)); + if (NS_FAILED(tmp)) { + rv = tmp; + } + tmp = mRDFService->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "URL"), + getter_AddRefs(mNC_URL)); + if (NS_FAILED(tmp)) { + rv = tmp; + } + tmp = mRDFService->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "Icon"), + getter_AddRefs(mNC_Icon)); + if (NS_FAILED(tmp)) { + rv = tmp; + } + tmp = mRDFService->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "Content-Length"), + getter_AddRefs(mNC_Length)); + if (NS_FAILED(tmp)) { + rv = tmp; + } + tmp = mRDFService->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "IsDirectory"), + getter_AddRefs(mNC_IsDirectory)); + if (NS_FAILED(tmp)) { + rv = tmp; + } + tmp = mRDFService->GetResource(NS_LITERAL_CSTRING(WEB_NAMESPACE_URI "LastModifiedDate"), + getter_AddRefs(mWEB_LastMod)); + if (NS_FAILED(tmp)) { + rv = tmp; + } + tmp = mRDFService->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "FileSystemObject"), + getter_AddRefs(mNC_FileSystemObject)); + if (NS_FAILED(tmp)) { + rv = tmp; + } + tmp = mRDFService->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "pulse"), + getter_AddRefs(mNC_pulse)); + if (NS_FAILED(tmp)) { + rv = tmp; + } + tmp = mRDFService->GetResource(NS_LITERAL_CSTRING(RDF_NAMESPACE_URI "instanceOf"), + getter_AddRefs(mRDF_InstanceOf)); + if (NS_FAILED(tmp)) { + rv = tmp; + } + tmp = mRDFService->GetResource(NS_LITERAL_CSTRING(RDF_NAMESPACE_URI "type"), + getter_AddRefs(mRDF_type)); + + static const char16_t kTrue[] = {'t','r','u','e','\0'}; + static const char16_t kFalse[] = {'f','a','l','s','e','\0'}; + + tmp = mRDFService->GetLiteral(kTrue, getter_AddRefs(mLiteralTrue)); + if (NS_FAILED(tmp)) { + rv = tmp; + } + tmp = mRDFService->GetLiteral(kFalse, getter_AddRefs(mLiteralFalse)); + if (NS_FAILED(tmp)) { + rv = tmp; + } + NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE); + +#ifdef USE_NC_EXTENSION + rv = mRDFService->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "extension"), + getter_AddRefs(mNC_extension)); + NS_ENSURE_SUCCESS(rv, rv); +#endif + +#ifdef XP_WIN + rv = mRDFService->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "IEFavorite"), + getter_AddRefs(mNC_IEFavoriteObject)); + tmp = mRDFService->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "IEFavoriteFolder"), + getter_AddRefs(mNC_IEFavoriteFolder)); + if (NS_FAILED(tmp)) { + rv = tmp; + } + NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE); + + nsCOMPtr<nsIFile> file; + NS_GetSpecialDirectory(NS_WIN_FAVORITES_DIR, getter_AddRefs(file)); + if (file) + { + nsCOMPtr<nsIURI> furi; + NS_NewFileURI(getter_AddRefs(furi), file); + NS_ENSURE_TRUE(furi, NS_ERROR_FAILURE); + + file->GetNativePath(ieFavoritesDir); + } +#endif + + return NS_OK; +} + +//static +nsresult +FileSystemDataSource::Create(nsISupports* aOuter, const nsIID& aIID, void **aResult) +{ + NS_ENSURE_NO_AGGREGATION(aOuter); + + RefPtr<FileSystemDataSource> self = new FileSystemDataSource(); + if (!self) + return NS_ERROR_OUT_OF_MEMORY; + + nsresult rv = self->Init(); + NS_ENSURE_SUCCESS(rv, rv); + + return self->QueryInterface(aIID, aResult); +} + +NS_IMPL_ISUPPORTS(FileSystemDataSource, nsIRDFDataSource) + +NS_IMETHODIMP +FileSystemDataSource::GetURI(char **uri) +{ + NS_PRECONDITION(uri != nullptr, "null ptr"); + if (! uri) + return NS_ERROR_NULL_POINTER; + + if ((*uri = NS_strdup("rdf:files")) == nullptr) + return NS_ERROR_OUT_OF_MEMORY; + + return NS_OK; +} + + + +NS_IMETHODIMP +FileSystemDataSource::GetSource(nsIRDFResource* property, + nsIRDFNode* target, + bool tv, + nsIRDFResource** source /* out */) +{ + NS_PRECONDITION(property != nullptr, "null ptr"); + if (! property) + return NS_ERROR_NULL_POINTER; + + NS_PRECONDITION(target != nullptr, "null ptr"); + if (! target) + return NS_ERROR_NULL_POINTER; + + NS_PRECONDITION(source != nullptr, "null ptr"); + if (! source) + return NS_ERROR_NULL_POINTER; + + *source = nullptr; + return NS_RDF_NO_VALUE; +} + + + +NS_IMETHODIMP +FileSystemDataSource::GetSources(nsIRDFResource *property, + nsIRDFNode *target, + bool tv, + nsISimpleEnumerator **sources /* out */) +{ +// NS_NOTYETIMPLEMENTED("write me"); + return NS_ERROR_NOT_IMPLEMENTED; +} + + + +NS_IMETHODIMP +FileSystemDataSource::GetTarget(nsIRDFResource *source, + nsIRDFResource *property, + bool tv, + nsIRDFNode **target /* out */) +{ + NS_PRECONDITION(source != nullptr, "null ptr"); + if (! source) + return NS_ERROR_NULL_POINTER; + + NS_PRECONDITION(property != nullptr, "null ptr"); + if (! property) + return NS_ERROR_NULL_POINTER; + + NS_PRECONDITION(target != nullptr, "null ptr"); + if (! target) + return NS_ERROR_NULL_POINTER; + + *target = nullptr; + + nsresult rv = NS_RDF_NO_VALUE; + + // we only have positive assertions in the file system data source. + if (! tv) + return NS_RDF_NO_VALUE; + + if (source == mNC_FileSystemRoot) + { + if (property == mNC_pulse) + { + nsIRDFLiteral *pulseLiteral; + mRDFService->GetLiteral(u"12", &pulseLiteral); + *target = pulseLiteral; + return NS_OK; + } + } + else if (isFileURI(source)) + { + if (property == mNC_Name) + { + nsCOMPtr<nsIRDFLiteral> name; + rv = GetName(source, getter_AddRefs(name)); + if (NS_FAILED(rv)) return(rv); + if (!name) rv = NS_RDF_NO_VALUE; + if (rv == NS_RDF_NO_VALUE) return(rv); + return name->QueryInterface(NS_GET_IID(nsIRDFNode), (void**) target); + } + else if (property == mNC_URL) + { + nsCOMPtr<nsIRDFLiteral> url; + rv = GetURL(source, nullptr, getter_AddRefs(url)); + if (NS_FAILED(rv)) return(rv); + if (!url) rv = NS_RDF_NO_VALUE; + if (rv == NS_RDF_NO_VALUE) return(rv); + + return url->QueryInterface(NS_GET_IID(nsIRDFNode), (void**) target); + } + else if (property == mNC_Icon) + { + nsCOMPtr<nsIRDFLiteral> url; + bool isFavorite = false; + rv = GetURL(source, &isFavorite, getter_AddRefs(url)); + if (NS_FAILED(rv)) return(rv); + if (isFavorite || !url) rv = NS_RDF_NO_VALUE; + if (rv == NS_RDF_NO_VALUE) return(rv); + + const char16_t *uni = nullptr; + url->GetValueConst(&uni); + if (!uni) return(NS_RDF_NO_VALUE); + nsAutoString urlStr; + urlStr.AssignLiteral(NS_MOZICON_SCHEME); + urlStr.Append(uni); + + rv = mRDFService->GetLiteral(urlStr.get(), getter_AddRefs(url)); + if (NS_FAILED(rv) || !url) return(NS_RDF_NO_VALUE); + return url->QueryInterface(NS_GET_IID(nsIRDFNode), (void**) target); + } + else if (property == mNC_Length) + { + nsCOMPtr<nsIRDFInt> fileSize; + rv = GetFileSize(source, getter_AddRefs(fileSize)); + if (NS_FAILED(rv)) return(rv); + if (!fileSize) rv = NS_RDF_NO_VALUE; + if (rv == NS_RDF_NO_VALUE) return(rv); + + return fileSize->QueryInterface(NS_GET_IID(nsIRDFNode), (void**) target); + } + else if (property == mNC_IsDirectory) + { + *target = (isDirURI(source)) ? mLiteralTrue : mLiteralFalse; + NS_ADDREF(*target); + return NS_OK; + } + else if (property == mWEB_LastMod) + { + nsCOMPtr<nsIRDFDate> lastMod; + rv = GetLastMod(source, getter_AddRefs(lastMod)); + if (NS_FAILED(rv)) return(rv); + if (!lastMod) rv = NS_RDF_NO_VALUE; + if (rv == NS_RDF_NO_VALUE) return(rv); + + return lastMod->QueryInterface(NS_GET_IID(nsIRDFNode), (void**) target); + } + else if (property == mRDF_type) + { + nsCString type; + rv = mNC_FileSystemObject->GetValueUTF8(type); + if (NS_FAILED(rv)) return(rv); + +#ifdef XP_WIN + // under Windows, if its an IE favorite, return that type + if (!ieFavoritesDir.IsEmpty()) + { + nsCString uri; + rv = source->GetValueUTF8(uri); + if (NS_FAILED(rv)) return(rv); + + NS_ConvertUTF8toUTF16 theURI(uri); + + if (theURI.Find(ieFavoritesDir) == 0) + { + if (theURI[theURI.Length() - 1] == '/') + { + rv = mNC_IEFavoriteFolder->GetValueUTF8(type); + } + else + { + rv = mNC_IEFavoriteObject->GetValueUTF8(type); + } + if (NS_FAILED(rv)) return(rv); + } + } +#endif + + NS_ConvertUTF8toUTF16 url(type); + nsCOMPtr<nsIRDFLiteral> literal; + mRDFService->GetLiteral(url.get(), getter_AddRefs(literal)); + rv = literal->QueryInterface(NS_GET_IID(nsIRDFNode), (void**) target); + return(rv); + } + else if (property == mNC_pulse) + { + nsCOMPtr<nsIRDFLiteral> pulseLiteral; + mRDFService->GetLiteral(u"12", getter_AddRefs(pulseLiteral)); + rv = pulseLiteral->QueryInterface(NS_GET_IID(nsIRDFNode), (void**) target); + return(rv); + } + else if (property == mNC_Child) + { + // Oh this is evil. Somebody kill me now. + nsCOMPtr<nsISimpleEnumerator> children; + rv = GetFolderList(source, false, true, getter_AddRefs(children)); + if (NS_FAILED(rv) || (rv == NS_RDF_NO_VALUE)) return(rv); + + bool hasMore; + rv = children->HasMoreElements(&hasMore); + if (NS_FAILED(rv)) return(rv); + + if (hasMore) + { + nsCOMPtr<nsISupports> isupports; + rv = children->GetNext(getter_AddRefs(isupports)); + if (NS_FAILED(rv)) return(rv); + + return isupports->QueryInterface(NS_GET_IID(nsIRDFNode), (void**) target); + } + } +#ifdef USE_NC_EXTENSION + else if (property == mNC_extension) + { + nsCOMPtr<nsIRDFLiteral> extension; + rv = GetExtension(source, getter_AddRefs(extension)); + if (!extension) rv = NS_RDF_NO_VALUE; + if (rv == NS_RDF_NO_VALUE) return(rv); + return extension->QueryInterface(NS_GET_IID(nsIRDFNode), (void**) target); + } +#endif + } + + return(NS_RDF_NO_VALUE); +} + + + +NS_IMETHODIMP +FileSystemDataSource::GetTargets(nsIRDFResource *source, + nsIRDFResource *property, + bool tv, + nsISimpleEnumerator **targets /* out */) +{ + NS_PRECONDITION(source != nullptr, "null ptr"); + if (! source) + return NS_ERROR_NULL_POINTER; + + NS_PRECONDITION(property != nullptr, "null ptr"); + if (! property) + return NS_ERROR_NULL_POINTER; + + NS_PRECONDITION(targets != nullptr, "null ptr"); + if (! targets) + return NS_ERROR_NULL_POINTER; + + *targets = nullptr; + + // we only have positive assertions in the file system data source. + if (! tv) + return NS_RDF_NO_VALUE; + + nsresult rv; + + if (source == mNC_FileSystemRoot) + { + if (property == mNC_Child) + { + return GetVolumeList(targets); + } + else if (property == mNC_pulse) + { + nsCOMPtr<nsIRDFLiteral> pulseLiteral; + mRDFService->GetLiteral(u"12", + getter_AddRefs(pulseLiteral)); + return NS_NewSingletonEnumerator(targets, pulseLiteral); + } + } + else if (isFileURI(source)) + { + if (property == mNC_Child) + { + return GetFolderList(source, false, false, targets); + } + else if (property == mNC_Name) + { + nsCOMPtr<nsIRDFLiteral> name; + rv = GetName(source, getter_AddRefs(name)); + if (NS_FAILED(rv)) return rv; + + return NS_NewSingletonEnumerator(targets, name); + } + else if (property == mNC_URL) + { + nsCOMPtr<nsIRDFLiteral> url; + rv = GetURL(source, nullptr, getter_AddRefs(url)); + if (NS_FAILED(rv)) return rv; + + return NS_NewSingletonEnumerator(targets, url); + } + else if (property == mRDF_type) + { + nsCString uri; + rv = mNC_FileSystemObject->GetValueUTF8(uri); + if (NS_FAILED(rv)) return rv; + + NS_ConvertUTF8toUTF16 url(uri); + + nsCOMPtr<nsIRDFLiteral> literal; + rv = mRDFService->GetLiteral(url.get(), getter_AddRefs(literal)); + if (NS_FAILED(rv)) return rv; + + return NS_NewSingletonEnumerator(targets, literal); + } + else if (property == mNC_pulse) + { + nsCOMPtr<nsIRDFLiteral> pulseLiteral; + rv = mRDFService->GetLiteral(u"12", + getter_AddRefs(pulseLiteral)); + if (NS_FAILED(rv)) return rv; + + return NS_NewSingletonEnumerator(targets, pulseLiteral); + } + } + + return NS_NewEmptyEnumerator(targets); +} + + + +NS_IMETHODIMP +FileSystemDataSource::Assert(nsIRDFResource *source, + nsIRDFResource *property, + nsIRDFNode *target, + bool tv) +{ + return NS_RDF_ASSERTION_REJECTED; +} + + + +NS_IMETHODIMP +FileSystemDataSource::Unassert(nsIRDFResource *source, + nsIRDFResource *property, + nsIRDFNode *target) +{ + return NS_RDF_ASSERTION_REJECTED; +} + + + +NS_IMETHODIMP +FileSystemDataSource::Change(nsIRDFResource* aSource, + nsIRDFResource* aProperty, + nsIRDFNode* aOldTarget, + nsIRDFNode* aNewTarget) +{ + return NS_RDF_ASSERTION_REJECTED; +} + + + +NS_IMETHODIMP +FileSystemDataSource::Move(nsIRDFResource* aOldSource, + nsIRDFResource* aNewSource, + nsIRDFResource* aProperty, + nsIRDFNode* aTarget) +{ + return NS_RDF_ASSERTION_REJECTED; +} + + + +NS_IMETHODIMP +FileSystemDataSource::HasAssertion(nsIRDFResource *source, + nsIRDFResource *property, + nsIRDFNode *target, + bool tv, + bool *hasAssertion /* out */) +{ + NS_PRECONDITION(source != nullptr, "null ptr"); + if (! source) + return NS_ERROR_NULL_POINTER; + + NS_PRECONDITION(property != nullptr, "null ptr"); + if (! property) + return NS_ERROR_NULL_POINTER; + + NS_PRECONDITION(target != nullptr, "null ptr"); + if (! target) + return NS_ERROR_NULL_POINTER; + + NS_PRECONDITION(hasAssertion != nullptr, "null ptr"); + if (! hasAssertion) + return NS_ERROR_NULL_POINTER; + + // we only have positive assertions in the file system data source. + *hasAssertion = false; + + if (! tv) { + return NS_OK; + } + + if ((source == mNC_FileSystemRoot) || isFileURI(source)) + { + if (property == mRDF_type) + { + nsCOMPtr<nsIRDFResource> resource( do_QueryInterface(target) ); + if (resource.get() == mRDF_type) + { + *hasAssertion = true; + } + } +#ifdef USE_NC_EXTENSION + else if (property == mNC_extension) + { + // Cheat just a little here by making dirs always match + if (isDirURI(source)) + { + *hasAssertion = true; + } + else + { + nsCOMPtr<nsIRDFLiteral> extension; + GetExtension(source, getter_AddRefs(extension)); + if (extension.get() == target) + { + *hasAssertion = true; + } + } + } +#endif + else if (property == mNC_IsDirectory) + { + bool isDir = isDirURI(source); + bool isEqual = false; + target->EqualsNode(mLiteralTrue, &isEqual); + if (isEqual) + { + *hasAssertion = isDir; + } + else + { + target->EqualsNode(mLiteralFalse, &isEqual); + if (isEqual) + *hasAssertion = !isDir; + } + } + } + + return NS_OK; +} + + + +NS_IMETHODIMP +FileSystemDataSource::HasArcIn(nsIRDFNode *aNode, nsIRDFResource *aArc, bool *result) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + + + +NS_IMETHODIMP +FileSystemDataSource::HasArcOut(nsIRDFResource *aSource, nsIRDFResource *aArc, bool *result) +{ + *result = false; + + if (aSource == mNC_FileSystemRoot) + { + *result = (aArc == mNC_Child || aArc == mNC_pulse); + } + else if (isFileURI(aSource)) + { + if (aArc == mNC_pulse) + { + *result = true; + } + else if (isDirURI(aSource)) + { +#ifdef XP_WIN + *result = isValidFolder(aSource); +#else + *result = true; +#endif + } + else if (aArc == mNC_pulse || aArc == mNC_Name || aArc == mNC_Icon || + aArc == mNC_URL || aArc == mNC_Length || aArc == mWEB_LastMod || + aArc == mNC_FileSystemObject || aArc == mRDF_InstanceOf || + aArc == mRDF_type) + { + *result = true; + } + } + return NS_OK; +} + + + +NS_IMETHODIMP +FileSystemDataSource::ArcLabelsIn(nsIRDFNode *node, + nsISimpleEnumerator ** labels /* out */) +{ +// NS_NOTYETIMPLEMENTED("write me"); + return NS_ERROR_NOT_IMPLEMENTED; +} + + + +NS_IMETHODIMP +FileSystemDataSource::ArcLabelsOut(nsIRDFResource *source, + nsISimpleEnumerator **labels /* out */) +{ + NS_PRECONDITION(source != nullptr, "null ptr"); + if (! source) + return NS_ERROR_NULL_POINTER; + + NS_PRECONDITION(labels != nullptr, "null ptr"); + if (! labels) + return NS_ERROR_NULL_POINTER; + + if (source == mNC_FileSystemRoot) + { + nsCOMArray<nsIRDFResource> resources; + resources.SetCapacity(2); + + resources.AppendObject(mNC_Child); + resources.AppendObject(mNC_pulse); + + return NS_NewArrayEnumerator(labels, resources); + } + else if (isFileURI(source)) + { + nsCOMArray<nsIRDFResource> resources; + resources.SetCapacity(2); + + if (isDirURI(source)) + { +#ifdef XP_WIN + if (isValidFolder(source)) + { + resources.AppendObject(mNC_Child); + } +#else + resources.AppendObject(mNC_Child); +#endif + resources.AppendObject(mNC_pulse); + } + + return NS_NewArrayEnumerator(labels, resources); + } + + return NS_NewEmptyEnumerator(labels); +} + + + +NS_IMETHODIMP +FileSystemDataSource::GetAllResources(nsISimpleEnumerator** aCursor) +{ + NS_NOTYETIMPLEMENTED("sorry!"); + return NS_ERROR_NOT_IMPLEMENTED; +} + + + +NS_IMETHODIMP +FileSystemDataSource::AddObserver(nsIRDFObserver *n) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + + + +NS_IMETHODIMP +FileSystemDataSource::RemoveObserver(nsIRDFObserver *n) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + + + +NS_IMETHODIMP +FileSystemDataSource::GetAllCmds(nsIRDFResource* source, + nsISimpleEnumerator/*<nsIRDFResource>*/** commands) +{ + return(NS_NewEmptyEnumerator(commands)); +} + + + +NS_IMETHODIMP +FileSystemDataSource::IsCommandEnabled(nsISupports/*<nsIRDFResource>*/* aSources, + nsIRDFResource* aCommand, + nsISupports/*<nsIRDFResource>*/* aArguments, + bool* aResult) +{ + return(NS_ERROR_NOT_IMPLEMENTED); +} + + + +NS_IMETHODIMP +FileSystemDataSource::DoCommand(nsISupports/*<nsIRDFResource>*/* aSources, + nsIRDFResource* aCommand, + nsISupports/*<nsIRDFResource>*/* aArguments) +{ + return(NS_ERROR_NOT_IMPLEMENTED); +} + + + +NS_IMETHODIMP +FileSystemDataSource::BeginUpdateBatch() +{ + return NS_OK; +} + + + +NS_IMETHODIMP +FileSystemDataSource::EndUpdateBatch() +{ + return NS_OK; +} + + + +nsresult +FileSystemDataSource::GetVolumeList(nsISimpleEnumerator** aResult) +{ + nsCOMArray<nsIRDFResource> volumes; + nsCOMPtr<nsIRDFResource> vol; + +#ifdef XP_WIN + + int32_t driveType; + wchar_t drive[32]; + int32_t volNum; + + for (volNum = 0; volNum < 26; volNum++) + { + swprintf_s(drive, 32, L"%c:\\", volNum + (char16_t)'A'); + + driveType = GetDriveTypeW(drive); + if (driveType != DRIVE_UNKNOWN && driveType != DRIVE_NO_ROOT_DIR) + { + nsAutoCString url; + url.AppendPrintf("file:///%c|/", volNum + 'A'); + nsresult rv = mRDFService->GetResource(url, getter_AddRefs(vol)); + if (NS_FAILED(rv)) + return rv; + + volumes.AppendObject(vol); + } + } +#endif + +#ifdef XP_UNIX + mRDFService->GetResource(NS_LITERAL_CSTRING("file:///"), getter_AddRefs(vol)); + volumes.AppendObject(vol); +#endif + + return NS_NewArrayEnumerator(aResult, volumes); +} + + + +#ifdef XP_WIN +bool +FileSystemDataSource::isValidFolder(nsIRDFResource *source) +{ + bool isValid = true; + if (ieFavoritesDir.IsEmpty()) return(isValid); + + nsresult rv; + nsCString uri; + rv = source->GetValueUTF8(uri); + if (NS_FAILED(rv)) return(isValid); + + NS_ConvertUTF8toUTF16 theURI(uri); + if (theURI.Find(ieFavoritesDir) == 0) + { + isValid = false; + + nsCOMPtr<nsISimpleEnumerator> folderEnum; + if (NS_SUCCEEDED(rv = GetFolderList(source, true, false, getter_AddRefs(folderEnum)))) + { + bool hasAny = false, hasMore; + while (NS_SUCCEEDED(folderEnum->HasMoreElements(&hasMore)) && + hasMore) + { + hasAny = true; + + nsCOMPtr<nsISupports> isupports; + if (NS_FAILED(rv = folderEnum->GetNext(getter_AddRefs(isupports)))) + break; + nsCOMPtr<nsIRDFResource> res = do_QueryInterface(isupports); + if (!res) break; + + nsCOMPtr<nsIRDFLiteral> nameLiteral; + if (NS_FAILED(rv = GetName(res, getter_AddRefs(nameLiteral)))) + break; + + const char16_t *uniName; + if (NS_FAILED(rv = nameLiteral->GetValueConst(&uniName))) + break; + nsAutoString name(uniName); + + // An empty folder, or a folder that contains just "desktop.ini", + // is considered to be a IE Favorite; otherwise, its a folder + if (!name.LowerCaseEqualsLiteral("desktop.ini")) + { + isValid = true; + break; + } + } + if (!hasAny) isValid = true; + } + } + return(isValid); +} +#endif + + + +nsresult +FileSystemDataSource::GetFolderList(nsIRDFResource *source, bool allowHidden, + bool onlyFirst, nsISimpleEnumerator** aResult) +{ + if (!isDirURI(source)) + return(NS_RDF_NO_VALUE); + + nsresult rv; + + const char *parentURI = nullptr; + rv = source->GetValueConst(&parentURI); + if (NS_FAILED(rv)) + return(rv); + if (!parentURI) + return(NS_ERROR_UNEXPECTED); + + nsCOMPtr<nsIURI> aIURI; + if (NS_FAILED(rv = NS_NewURI(getter_AddRefs(aIURI), nsDependentCString(parentURI)))) + return(rv); + + nsCOMPtr<nsIFileURL> fileURL = do_QueryInterface(aIURI); + if (!fileURL) + return NS_OK; + + nsCOMPtr<nsIFile> aDir; + if (NS_FAILED(rv = fileURL->GetFile(getter_AddRefs(aDir)))) + return(rv); + + // ensure that we DO NOT resolve aliases + aDir->SetFollowLinks(false); + + nsCOMPtr<nsISimpleEnumerator> dirContents; + if (NS_FAILED(rv = aDir->GetDirectoryEntries(getter_AddRefs(dirContents)))) + return(rv); + if (!dirContents) + return(NS_ERROR_UNEXPECTED); + + nsCOMArray<nsIRDFResource> resources; + bool hasMore; + while(NS_SUCCEEDED(rv = dirContents->HasMoreElements(&hasMore)) && + hasMore) + { + nsCOMPtr<nsISupports> isupports; + if (NS_FAILED(rv = dirContents->GetNext(getter_AddRefs(isupports)))) + break; + + nsCOMPtr<nsIFile> aFile = do_QueryInterface(isupports); + if (!aFile) + break; + + if (!allowHidden) + { + bool hiddenFlag = false; + if (NS_FAILED(rv = aFile->IsHidden(&hiddenFlag))) + break; + if (hiddenFlag) + continue; + } + + nsAutoString leafStr; + if (NS_FAILED(rv = aFile->GetLeafName(leafStr))) + break; + if (leafStr.IsEmpty()) + continue; + + nsAutoCString fullURI; + fullURI.Assign(parentURI); + if (fullURI.Last() != '/') + { + fullURI.Append('/'); + } + + nsAutoCString leaf; + bool escaped = NS_Escape(NS_ConvertUTF16toUTF8(leafStr), leaf, url_Path); + leafStr.Truncate(); + + if (!escaped) { + continue; + } + + // using nsEscape() [above] doesn't escape slashes, so do that by hand + int32_t aOffset; + while ((aOffset = leaf.FindChar('/')) >= 0) + { + leaf.Cut((uint32_t)aOffset, 1); + leaf.Insert("%2F", (uint32_t)aOffset); + } + + // append the encoded name + fullURI.Append(leaf); + + bool dirFlag = false; + rv = aFile->IsDirectory(&dirFlag); + if (NS_SUCCEEDED(rv) && dirFlag) + { + fullURI.Append('/'); + } + + nsCOMPtr<nsIRDFResource> fileRes; + mRDFService->GetResource(fullURI, getter_AddRefs(fileRes)); + + resources.AppendObject(fileRes); + + if (onlyFirst) + break; + } + + return NS_NewArrayEnumerator(aResult, resources); +} + +nsresult +FileSystemDataSource::GetLastMod(nsIRDFResource *source, nsIRDFDate **aResult) +{ + *aResult = nullptr; + + nsresult rv; + const char *uri = nullptr; + + rv = source->GetValueConst(&uri); + if (NS_FAILED(rv)) return(rv); + if (!uri) + return(NS_ERROR_UNEXPECTED); + + nsCOMPtr<nsIURI> aIURI; + if (NS_FAILED(rv = NS_NewURI(getter_AddRefs(aIURI), nsDependentCString(uri)))) + return(rv); + + nsCOMPtr<nsIFileURL> fileURL = do_QueryInterface(aIURI); + if (!fileURL) + return NS_OK; + + nsCOMPtr<nsIFile> aFile; + if (NS_FAILED(rv = fileURL->GetFile(getter_AddRefs(aFile)))) + return(rv); + if (!aFile) + return(NS_ERROR_UNEXPECTED); + + // ensure that we DO NOT resolve aliases + aFile->SetFollowLinks(false); + + PRTime lastModDate; + if (NS_FAILED(rv = aFile->GetLastModifiedTime(&lastModDate))) + return(rv); + + // convert from milliseconds to seconds + mRDFService->GetDateLiteral(lastModDate * PR_MSEC_PER_SEC, aResult); + + return(NS_OK); +} + + + +nsresult +FileSystemDataSource::GetFileSize(nsIRDFResource *source, nsIRDFInt **aResult) +{ + *aResult = nullptr; + + nsresult rv; + const char *uri = nullptr; + + rv = source->GetValueConst(&uri); + if (NS_FAILED(rv)) + return(rv); + if (!uri) + return(NS_ERROR_UNEXPECTED); + + nsCOMPtr<nsIURI> aIURI; + if (NS_FAILED(rv = NS_NewURI(getter_AddRefs(aIURI), nsDependentCString(uri)))) + return(rv); + + nsCOMPtr<nsIFileURL> fileURL = do_QueryInterface(aIURI); + if (!fileURL) + return NS_OK; + + nsCOMPtr<nsIFile> aFile; + if (NS_FAILED(rv = fileURL->GetFile(getter_AddRefs(aFile)))) + return(rv); + if (!aFile) + return(NS_ERROR_UNEXPECTED); + + // ensure that we DO NOT resolve aliases + aFile->SetFollowLinks(false); + + // don't do anything with directories + bool isDir = false; + if (NS_FAILED(rv = aFile->IsDirectory(&isDir))) + return(rv); + if (isDir) + return(NS_RDF_NO_VALUE); + + int64_t aFileSize64; + if (NS_FAILED(rv = aFile->GetFileSize(&aFileSize64))) + return(rv); + + // convert 64bits to 32bits + int32_t aFileSize32 = int32_t(aFileSize64); + mRDFService->GetIntLiteral(aFileSize32, aResult); + + return(NS_OK); +} + + + +nsresult +FileSystemDataSource::GetName(nsIRDFResource *source, nsIRDFLiteral **aResult) +{ + nsresult rv; + const char *uri = nullptr; + + rv = source->GetValueConst(&uri); + if (NS_FAILED(rv)) + return(rv); + if (!uri) + return(NS_ERROR_UNEXPECTED); + + nsCOMPtr<nsIURI> aIURI; + if (NS_FAILED(rv = NS_NewURI(getter_AddRefs(aIURI), nsDependentCString(uri)))) + return(rv); + + nsCOMPtr<nsIFileURL> fileURL = do_QueryInterface(aIURI); + if (!fileURL) + return NS_OK; + + nsCOMPtr<nsIFile> aFile; + if (NS_FAILED(rv = fileURL->GetFile(getter_AddRefs(aFile)))) + return(rv); + if (!aFile) + return(NS_ERROR_UNEXPECTED); + + // ensure that we DO NOT resolve aliases + aFile->SetFollowLinks(false); + + nsAutoString name; + if (NS_FAILED(rv = aFile->GetLeafName(name))) + return(rv); + if (name.IsEmpty()) + return(NS_ERROR_UNEXPECTED); + +#ifdef XP_WIN + // special hack for IE favorites under Windows; strip off the + // trailing ".url" or ".lnk" at the end of IE favorites names + int32_t nameLen = name.Length(); + if ((strncmp(uri, ieFavoritesDir.get(), ieFavoritesDir.Length()) == 0) && (nameLen > 4)) + { + nsAutoString extension; + name.Right(extension, 4); + if (extension.LowerCaseEqualsLiteral(".url") || + extension.LowerCaseEqualsLiteral(".lnk")) + { + name.Truncate(nameLen - 4); + } + } +#endif + + mRDFService->GetLiteral(name.get(), aResult); + + return NS_OK; +} + + + +#ifdef USE_NC_EXTENSION +nsresult +FileSystemDataSource::GetExtension(nsIRDFResource *source, nsIRDFLiteral **aResult) +{ + nsCOMPtr<nsIRDFLiteral> name; + nsresult rv = GetName(source, getter_AddRefs(name)); + if (NS_FAILED(rv)) + return rv; + + const char16_t* unicodeLeafName; + rv = name->GetValueConst(&unicodeLeafName); + if (NS_FAILED(rv)) + return rv; + + nsAutoString filename(unicodeLeafName); + int32_t lastDot = filename.RFindChar('.'); + if (lastDot == -1) + { + mRDFService->GetLiteral(EmptyString().get(), aResult); + } + else + { + nsAutoString extension; + filename.Right(extension, (filename.Length() - lastDot)); + mRDFService->GetLiteral(extension.get(), aResult); + } + + return NS_OK; +} +#endif + +#ifdef XP_WIN +nsresult +FileSystemDataSource::getIEFavoriteURL(nsIRDFResource *source, nsString aFileURL, nsIRDFLiteral **urlLiteral) +{ + nsresult rv = NS_OK; + + *urlLiteral = nullptr; + + nsCOMPtr<nsIFile> f; + NS_GetFileFromURLSpec(NS_ConvertUTF16toUTF8(aFileURL), getter_AddRefs(f)); + + bool value; + + if (NS_SUCCEEDED(f->IsDirectory(&value)) && value) + { + if (isValidFolder(source)) + return(NS_RDF_NO_VALUE); + aFileURL.AppendLiteral("desktop.ini"); + } + else if (aFileURL.Length() > 4) + { + nsAutoString extension; + + aFileURL.Right(extension, 4); + if (!extension.LowerCaseEqualsLiteral(".url")) + { + return(NS_RDF_NO_VALUE); + } + } + + nsCOMPtr<nsIInputStream> strm; + NS_NewLocalFileInputStream(getter_AddRefs(strm),f); + nsCOMPtr<nsILineInputStream> linereader = do_QueryInterface(strm, &rv); + + nsAutoString line; + nsAutoCString cLine; + while(NS_SUCCEEDED(rv)) + { + bool isEOF; + rv = linereader->ReadLine(cLine, &isEOF); + CopyASCIItoUTF16(cLine, line); + + if (isEOF) + { + if (line.Find("URL=", true) == 0) + { + line.Cut(0, 4); + rv = mRDFService->GetLiteral(line.get(), urlLiteral); + break; + } + else if (line.Find("CDFURL=", true) == 0) + { + line.Cut(0, 7); + rv = mRDFService->GetLiteral(line.get(), urlLiteral); + break; + } + line.Truncate(); + } + } + + return(rv); +} +#endif + + + +nsresult +FileSystemDataSource::GetURL(nsIRDFResource *source, bool *isFavorite, nsIRDFLiteral** aResult) +{ + if (isFavorite) *isFavorite = false; + + nsresult rv; + nsCString uri; + + rv = source->GetValueUTF8(uri); + if (NS_FAILED(rv)) + return(rv); + + NS_ConvertUTF8toUTF16 url(uri); + +#ifdef XP_WIN + // under Windows, if its an IE favorite, munge the URL + if (!ieFavoritesDir.IsEmpty()) + { + if (url.Find(ieFavoritesDir) == 0) + { + if (isFavorite) *isFavorite = true; + rv = getIEFavoriteURL(source, url, aResult); + return(rv); + } + } +#endif + + // if we fall through to here, its not any type of bookmark + // stored in the platform native file system, so just set the URL + + mRDFService->GetLiteral(url.get(), aResult); + + return(NS_OK); +} diff --git a/rdf/datasource/nsFileSystemDataSource.h b/rdf/datasource/nsFileSystemDataSource.h new file mode 100644 index 000000000..09fa17400 --- /dev/null +++ b/rdf/datasource/nsFileSystemDataSource.h @@ -0,0 +1,79 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef nsFileSystemDataSource_h__ +#define nsFileSystemDataSource_h__ + +#include "nsIRDFDataSource.h" +#include "nsIRDFLiteral.h" +#include "nsIRDFResource.h" +#include "nsIRDFService.h" +#include "nsCOMPtr.h" +#include "nsString.h" +#include "mozilla/Attributes.h" + +#if defined(XP_UNIX) || defined(XP_WIN) +#define USE_NC_EXTENSION +#endif + +class FileSystemDataSource final : public nsIRDFDataSource +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSIRDFDATASOURCE + + static nsresult Create(nsISupports* aOuter, + const nsIID& aIID, void **aResult); + + nsresult Init(); + +private: + FileSystemDataSource() { } + ~FileSystemDataSource() { } + + // helper methods + bool isFileURI(nsIRDFResource* aResource); + bool isDirURI(nsIRDFResource* aSource); + nsresult GetVolumeList(nsISimpleEnumerator **aResult); + nsresult GetFolderList(nsIRDFResource *source, bool allowHidden, bool onlyFirst, nsISimpleEnumerator **aResult); + nsresult GetName(nsIRDFResource *source, nsIRDFLiteral** aResult); + nsresult GetURL(nsIRDFResource *source, bool *isFavorite, nsIRDFLiteral** aResult); + nsresult GetFileSize(nsIRDFResource *source, nsIRDFInt** aResult); + nsresult GetLastMod(nsIRDFResource *source, nsIRDFDate** aResult); + + nsCOMPtr<nsIRDFService> mRDFService; + + // pseudo-constants + nsCOMPtr<nsIRDFResource> mNC_FileSystemRoot; + nsCOMPtr<nsIRDFResource> mNC_Child; + nsCOMPtr<nsIRDFResource> mNC_Name; + nsCOMPtr<nsIRDFResource> mNC_URL; + nsCOMPtr<nsIRDFResource> mNC_Icon; + nsCOMPtr<nsIRDFResource> mNC_Length; + nsCOMPtr<nsIRDFResource> mNC_IsDirectory; + nsCOMPtr<nsIRDFResource> mWEB_LastMod; + nsCOMPtr<nsIRDFResource> mNC_FileSystemObject; + nsCOMPtr<nsIRDFResource> mNC_pulse; + nsCOMPtr<nsIRDFResource> mRDF_InstanceOf; + nsCOMPtr<nsIRDFResource> mRDF_type; + + nsCOMPtr<nsIRDFLiteral> mLiteralTrue; + nsCOMPtr<nsIRDFLiteral> mLiteralFalse; + +#ifdef USE_NC_EXTENSION + nsresult GetExtension(nsIRDFResource *source, nsIRDFLiteral** aResult); + nsCOMPtr<nsIRDFResource> mNC_extension; +#endif + +#ifdef XP_WIN + bool isValidFolder(nsIRDFResource *source); + nsresult getIEFavoriteURL(nsIRDFResource *source, nsString aFileURL, nsIRDFLiteral **urlLiteral); + nsCOMPtr<nsIRDFResource> mNC_IEFavoriteObject; + nsCOMPtr<nsIRDFResource> mNC_IEFavoriteFolder; + nsCString ieFavoritesDir; +#endif +}; + +#endif // nsFileSystemDataSource_h__ diff --git a/rdf/datasource/nsILocalStore.h b/rdf/datasource/nsILocalStore.h new file mode 100644 index 000000000..b41226593 --- /dev/null +++ b/rdf/datasource/nsILocalStore.h @@ -0,0 +1,34 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef nsILocalStore_h__ +#define nsILocalStore_h__ + +#include "rdf.h" +#include "nsISupports.h" + +// {DF71C6F1-EC53-11d2-BDCA-000064657374} +#define NS_ILOCALSTORE_IID \ +{ 0xdf71c6f1, 0xec53, 0x11d2, { 0xbd, 0xca, 0x0, 0x0, 0x64, 0x65, 0x73, 0x74 } } + +// {DF71C6F0-EC53-11d2-BDCA-000064657374} +#define NS_LOCALSTORE_CID \ +{ 0xdf71c6f0, 0xec53, 0x11d2, { 0xbd, 0xca, 0x0, 0x0, 0x64, 0x65, 0x73, 0x74 } } + +#define NS_LOCALSTORE_CONTRACTID NS_RDF_DATASOURCE_CONTRACTID_PREFIX "local-store" + +class nsILocalStore : public nsISupports +{ +public: + NS_DECLARE_STATIC_IID_ACCESSOR(NS_ILOCALSTORE_IID) +}; + +NS_DEFINE_STATIC_IID_ACCESSOR(nsILocalStore, NS_ILOCALSTORE_IID) + +extern nsresult +NS_NewLocalStore(nsISupports* aOuter, REFNSIID aIID, void** aResult); + + +#endif // nsILocalStore_h__ diff --git a/rdf/datasource/nsIRDFFTP.h b/rdf/datasource/nsIRDFFTP.h new file mode 100644 index 000000000..8965b4a38 --- /dev/null +++ b/rdf/datasource/nsIRDFFTP.h @@ -0,0 +1,33 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef nsIRDFFTP_h__ +#define nsIRDFFTP_h__ + +#include "nscore.h" +#include "nsISupports.h" +#include "nsIRDFNode.h" + + + +#define NS_IRDFFTPDATAOURCE_IID \ +{ 0x1222e6f0, 0xa5e3, 0x11d2, { 0x8b, 0x7c, 0x00, 0x80, 0x5f, 0x8a, 0x7d, 0xb7 } } + +class nsIRDFFTPDataSource : public nsIRDFDataSource +{ +public: +}; + + +#define NS_IRDFFTPDATASOURCECALLBACK_IID \ +{ 0x204a1a00, 0xa5e4, 0x11d2, { 0x8b, 0x7c, 0x00, 0x80, 0x5f, 0x8a, 0x7d, 0xb8 } } + +class nsIRDFFTPDataSourceCallback : public nsIStreamListener +{ +public: +}; + + +#endif // nsIRDFFTP_h__ diff --git a/rdf/datasource/nsLocalStore.cpp b/rdf/datasource/nsLocalStore.cpp new file mode 100644 index 000000000..b6218b425 --- /dev/null +++ b/rdf/datasource/nsLocalStore.cpp @@ -0,0 +1,481 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* vim: set cindent tabstop=4 expandtab shiftwidth=4: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* + + Implementation for the local store + + */ + +#include "nsNetUtil.h" +#include "nsIFile.h" +#include "nsIURI.h" +#include "nsIIOService.h" +#include "nsIOutputStream.h" +#include "nsIComponentManager.h" +#include "nsILocalStore.h" +#include "nsIRDFDataSource.h" +#include "nsIRDFRemoteDataSource.h" +#include "nsIRDFService.h" +#include "nsIServiceManager.h" +#include "nsRDFCID.h" +#include "nsXPIDLString.h" +#include "plstr.h" +#include "rdf.h" +#include "nsCOMPtr.h" +#include "nsWeakPtr.h" +#include "nsAppDirectoryServiceDefs.h" +#include "nsIObserver.h" +#include "nsIObserverService.h" +#include "nsWeakReference.h" +#include "nsCRTGlue.h" +#include "nsCRT.h" +#include "nsEnumeratorUtils.h" +#include "nsCycleCollectionParticipant.h" + +//////////////////////////////////////////////////////////////////////// + +class LocalStoreImpl : public nsILocalStore, + public nsIRDFDataSource, + public nsIRDFRemoteDataSource, + public nsIObserver, + public nsSupportsWeakReference +{ +protected: + nsCOMPtr<nsIRDFDataSource> mInner; + + LocalStoreImpl(); + virtual ~LocalStoreImpl(); + nsresult Init(); + nsresult CreateLocalStore(nsIFile* aFile); + nsresult LoadData(); + + friend nsresult + NS_NewLocalStore(nsISupports* aOuter, REFNSIID aIID, void** aResult); + + nsCOMPtr<nsIRDFService> mRDFService; + +public: + // nsISupports interface + NS_DECL_CYCLE_COLLECTING_ISUPPORTS + NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(LocalStoreImpl, nsILocalStore) + + // nsILocalStore interface + + // nsIRDFDataSource interface. Most of these are just delegated to + // the inner, in-memory datasource. + NS_IMETHOD GetURI(char* *aURI) override; + + NS_IMETHOD GetSource(nsIRDFResource* aProperty, + nsIRDFNode* aTarget, + bool aTruthValue, + nsIRDFResource** aSource) override { + return mInner->GetSource(aProperty, aTarget, aTruthValue, aSource); + } + + NS_IMETHOD GetSources(nsIRDFResource* aProperty, + nsIRDFNode* aTarget, + bool aTruthValue, + nsISimpleEnumerator** aSources) override { + return mInner->GetSources(aProperty, aTarget, aTruthValue, aSources); + } + + NS_IMETHOD GetTarget(nsIRDFResource* aSource, + nsIRDFResource* aProperty, + bool aTruthValue, + nsIRDFNode** aTarget) override { + return mInner->GetTarget(aSource, aProperty, aTruthValue, aTarget); + } + + NS_IMETHOD GetTargets(nsIRDFResource* aSource, + nsIRDFResource* aProperty, + bool aTruthValue, + nsISimpleEnumerator** aTargets) override { + return mInner->GetTargets(aSource, aProperty, aTruthValue, aTargets); + } + + NS_IMETHOD Assert(nsIRDFResource* aSource, + nsIRDFResource* aProperty, + nsIRDFNode* aTarget, + bool aTruthValue) override { + return mInner->Assert(aSource, aProperty, aTarget, aTruthValue); + } + + NS_IMETHOD Unassert(nsIRDFResource* aSource, + nsIRDFResource* aProperty, + nsIRDFNode* aTarget) override { + return mInner->Unassert(aSource, aProperty, aTarget); + } + + NS_IMETHOD Change(nsIRDFResource* aSource, + nsIRDFResource* aProperty, + nsIRDFNode* aOldTarget, + nsIRDFNode* aNewTarget) override { + return mInner->Change(aSource, aProperty, aOldTarget, aNewTarget); + } + + NS_IMETHOD Move(nsIRDFResource* aOldSource, + nsIRDFResource* aNewSource, + nsIRDFResource* aProperty, + nsIRDFNode* aTarget) override { + return mInner->Move(aOldSource, aNewSource, aProperty, aTarget); + } + + NS_IMETHOD HasAssertion(nsIRDFResource* aSource, + nsIRDFResource* aProperty, + nsIRDFNode* aTarget, + bool aTruthValue, + bool* hasAssertion) override { + return mInner->HasAssertion(aSource, aProperty, aTarget, aTruthValue, hasAssertion); + } + + NS_IMETHOD AddObserver(nsIRDFObserver* aObserver) override { + return NS_ERROR_NOT_IMPLEMENTED; + } + + NS_IMETHOD RemoveObserver(nsIRDFObserver* aObserver) override { + return NS_ERROR_NOT_IMPLEMENTED; + } + + NS_IMETHOD HasArcIn(nsIRDFNode *aNode, nsIRDFResource *aArc, bool *_retval) override { + return mInner->HasArcIn(aNode, aArc, _retval); + } + + NS_IMETHOD HasArcOut(nsIRDFResource *aSource, nsIRDFResource *aArc, bool *_retval) override { + return mInner->HasArcOut(aSource, aArc, _retval); + } + + NS_IMETHOD ArcLabelsIn(nsIRDFNode* aNode, + nsISimpleEnumerator** aLabels) override { + return mInner->ArcLabelsIn(aNode, aLabels); + } + + NS_IMETHOD ArcLabelsOut(nsIRDFResource* aSource, + nsISimpleEnumerator** aLabels) override { + return mInner->ArcLabelsOut(aSource, aLabels); + } + + NS_IMETHOD GetAllResources(nsISimpleEnumerator** aResult) override { + return mInner->GetAllResources(aResult); + } + + NS_IMETHOD GetAllCmds(nsIRDFResource* aSource, + nsISimpleEnumerator/*<nsIRDFResource>*/** aCommands) override; + + NS_IMETHOD IsCommandEnabled(nsISupports* aSources, + nsIRDFResource* aCommand, + nsISupports* aArguments, + bool* aResult) override; + + NS_IMETHOD DoCommand(nsISupports* aSources, + nsIRDFResource* aCommand, + nsISupports* aArguments) override; + + NS_IMETHOD BeginUpdateBatch() override { + return mInner->BeginUpdateBatch(); + } + + NS_IMETHOD EndUpdateBatch() override { + return mInner->EndUpdateBatch(); + } + + NS_IMETHOD GetLoaded(bool* _result) override; + NS_IMETHOD Init(const char *uri) override; + NS_IMETHOD Flush() override; + NS_IMETHOD FlushTo(const char *aURI) override; + NS_IMETHOD Refresh(bool sync) override; + + // nsIObserver + NS_DECL_NSIOBSERVER +}; + +//////////////////////////////////////////////////////////////////////// + + +LocalStoreImpl::LocalStoreImpl(void) +{ +} + +LocalStoreImpl::~LocalStoreImpl(void) +{ + if (mRDFService) + mRDFService->UnregisterDataSource(this); +} + + +nsresult +NS_NewLocalStore(nsISupports* aOuter, REFNSIID aIID, void** aResult) +{ + NS_PRECONDITION(aOuter == nullptr, "no aggregation"); + if (aOuter) + return NS_ERROR_NO_AGGREGATION; + + NS_PRECONDITION(aResult != nullptr, "null ptr"); + if (! aResult) + return NS_ERROR_NULL_POINTER; + + LocalStoreImpl* impl = new LocalStoreImpl(); + if (! impl) + return NS_ERROR_OUT_OF_MEMORY; + + NS_ADDREF(impl); + + nsresult rv; + rv = impl->Init(); + if (NS_SUCCEEDED(rv)) { + // Set up the result pointer + rv = impl->QueryInterface(aIID, aResult); + } + + NS_RELEASE(impl); + return rv; +} + +NS_IMPL_CYCLE_COLLECTION(LocalStoreImpl, mInner) +NS_IMPL_CYCLE_COLLECTING_ADDREF(LocalStoreImpl) +NS_IMPL_CYCLE_COLLECTING_RELEASE(LocalStoreImpl) + +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(LocalStoreImpl) + NS_INTERFACE_MAP_ENTRY(nsILocalStore) + NS_INTERFACE_MAP_ENTRY(nsIRDFDataSource) + NS_INTERFACE_MAP_ENTRY(nsIRDFRemoteDataSource) + NS_INTERFACE_MAP_ENTRY(nsIObserver) + NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference) + NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsILocalStore) +NS_INTERFACE_MAP_END + +// nsILocalStore interface + +// nsIRDFDataSource interface + +NS_IMETHODIMP +LocalStoreImpl::GetLoaded(bool* _result) +{ + nsCOMPtr<nsIRDFRemoteDataSource> remote = do_QueryInterface(mInner); + NS_ASSERTION(remote != nullptr, "not an nsIRDFRemoteDataSource"); + if (! remote) + return NS_ERROR_UNEXPECTED; + + return remote->GetLoaded(_result); +} + + +NS_IMETHODIMP +LocalStoreImpl::Init(const char *uri) +{ + return(NS_OK); +} + +NS_IMETHODIMP +LocalStoreImpl::Flush() +{ + nsCOMPtr<nsIRDFRemoteDataSource> remote = do_QueryInterface(mInner); + // FIXME Bug 340242: Temporarily make this a warning rather than an + // assertion until we sort out the ordering of how we write + // everything to the localstore, flush it, and disconnect it when + // we're getting profile-change notifications. + NS_WARNING_ASSERTION(remote != nullptr, "not an nsIRDFRemoteDataSource"); + if (! remote) + return NS_ERROR_UNEXPECTED; + + return remote->Flush(); +} + +NS_IMETHODIMP +LocalStoreImpl::FlushTo(const char *aURI) +{ + // Do not ever implement this (security) + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +LocalStoreImpl::Refresh(bool sync) +{ + nsCOMPtr<nsIRDFRemoteDataSource> remote = do_QueryInterface(mInner); + NS_ASSERTION(remote != nullptr, "not an nsIRDFRemoteDataSource"); + if (! remote) + return NS_ERROR_UNEXPECTED; + + return remote->Refresh(sync); +} + +nsresult +LocalStoreImpl::Init() +{ + nsresult rv; + + rv = LoadData(); + if (NS_FAILED(rv)) return rv; + + // register this as a named data source with the RDF service + mRDFService = do_GetService(NS_RDF_CONTRACTID "/rdf-service;1", &rv); + if (NS_FAILED(rv)) return rv; + + mRDFService->RegisterDataSource(this, false); + + // Register as an observer of profile changes + nsCOMPtr<nsIObserverService> obs = + do_GetService("@mozilla.org/observer-service;1"); + + if (obs) { + obs->AddObserver(this, "profile-before-change", true); + obs->AddObserver(this, "profile-do-change", true); + } + + return NS_OK; +} + +nsresult +LocalStoreImpl::CreateLocalStore(nsIFile* aFile) +{ + nsresult rv; + + rv = aFile->Create(nsIFile::NORMAL_FILE_TYPE, 0666); + if (NS_FAILED(rv)) return rv; + + nsCOMPtr<nsIOutputStream> outStream; + rv = NS_NewLocalFileOutputStream(getter_AddRefs(outStream), aFile); + if (NS_FAILED(rv)) return rv; + + const char defaultRDF[] = + "<?xml version=\"1.0\"?>\n" \ + "<RDF:RDF xmlns:RDF=\"" RDF_NAMESPACE_URI "\"\n" \ + " xmlns:NC=\"" NC_NAMESPACE_URI "\">\n" \ + " <!-- Empty -->\n" \ + "</RDF:RDF>\n"; + + uint32_t count; + rv = outStream->Write(defaultRDF, sizeof(defaultRDF)-1, &count); + if (NS_FAILED(rv)) return rv; + + if (count != sizeof(defaultRDF)-1) + return NS_ERROR_UNEXPECTED; + + // Okay, now see if the file exists _for real_. If it's still + // not there, it could be that the profile service gave us + // back a read-only directory. Whatever. + bool fileExistsFlag = false; + aFile->Exists(&fileExistsFlag); + if (!fileExistsFlag) + return NS_ERROR_UNEXPECTED; + + return NS_OK; +} + +nsresult +LocalStoreImpl::LoadData() +{ + nsresult rv; + + // Look for localstore.rdf in the current profile + // directory. Bomb if we can't find it. + + nsCOMPtr<nsIFile> aFile; + rv = NS_GetSpecialDirectory(NS_APP_LOCALSTORE_50_FILE, getter_AddRefs(aFile)); + if (NS_FAILED(rv)) return rv; + + bool fileExistsFlag = false; + (void)aFile->Exists(&fileExistsFlag); + if (!fileExistsFlag) { + // if file doesn't exist, create it + rv = CreateLocalStore(aFile); + if (NS_FAILED(rv)) return rv; + } + + mInner = do_CreateInstance(NS_RDF_DATASOURCE_CONTRACTID_PREFIX "xml-datasource", &rv); + if (NS_FAILED(rv)) return rv; + + nsCOMPtr<nsIRDFRemoteDataSource> remote = do_QueryInterface(mInner, &rv); + if (NS_FAILED(rv)) return rv; + + nsCOMPtr<nsIURI> aURI; + rv = NS_NewFileURI(getter_AddRefs(aURI), aFile); + if (NS_FAILED(rv)) return rv; + + nsAutoCString spec; + rv = aURI->GetSpec(spec); + if (NS_FAILED(rv)) return rv; + + rv = remote->Init(spec.get()); + if (NS_FAILED(rv)) return rv; + + // Read the datasource synchronously. + rv = remote->Refresh(true); + + if (NS_FAILED(rv)) { + // Load failed, delete and recreate a fresh localstore + aFile->Remove(true); + rv = CreateLocalStore(aFile); + if (NS_FAILED(rv)) return rv; + + rv = remote->Refresh(true); + } + + return rv; +} + + +NS_IMETHODIMP +LocalStoreImpl::GetURI(char* *aURI) +{ + NS_PRECONDITION(aURI != nullptr, "null ptr"); + if (! aURI) + return NS_ERROR_NULL_POINTER; + + *aURI = NS_strdup("rdf:local-store"); + if (! *aURI) + return NS_ERROR_OUT_OF_MEMORY; + + return NS_OK; +} + + +NS_IMETHODIMP +LocalStoreImpl::GetAllCmds(nsIRDFResource* aSource, + nsISimpleEnumerator/*<nsIRDFResource>*/** aCommands) +{ + return(NS_NewEmptyEnumerator(aCommands)); +} + +NS_IMETHODIMP +LocalStoreImpl::IsCommandEnabled(nsISupports* aSources, + nsIRDFResource* aCommand, + nsISupports* aArguments, + bool* aResult) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +LocalStoreImpl::DoCommand(nsISupports* aSources, + nsIRDFResource* aCommand, + nsISupports* aArguments) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +LocalStoreImpl::Observe(nsISupports *aSubject, const char *aTopic, const char16_t *someData) +{ + nsresult rv = NS_OK; + + if (!nsCRT::strcmp(aTopic, "profile-before-change")) { + // Write out the old datasource's contents. + if (mInner) { + nsCOMPtr<nsIRDFRemoteDataSource> remote = do_QueryInterface(mInner); + if (remote) + remote->Flush(); + } + + // Create an in-memory datasource for use while we're + // profile-less. + mInner = do_CreateInstance(NS_RDF_DATASOURCE_CONTRACTID_PREFIX "in-memory-datasource"); + } + else if (!nsCRT::strcmp(aTopic, "profile-do-change")) { + rv = LoadData(); + } + return rv; +} diff --git a/rdf/datasource/nsRDFBuiltInDataSources.h b/rdf/datasource/nsRDFBuiltInDataSources.h new file mode 100644 index 000000000..297fe7164 --- /dev/null +++ b/rdf/datasource/nsRDFBuiltInDataSources.h @@ -0,0 +1,27 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* + + This header file just contains prototypes for the factory methods + for "builtin" data sources that are included in rdf.dll. + + Each of these data sources is exposed to the external world via its + CID in ../include/nsRDFCID.h. + + */ + +#ifndef nsBuiltinDataSources_h__ +#define nsBuiltinDataSources_h__ + +#include "nsError.h" + +class nsIRDFDataSource; + +// in nsFileSystemDataSource.cpp +nsresult NS_NewRDFFileSystemDataSource(nsIRDFDataSource** result); + +#endif // nsBuiltinDataSources_h__ + |