/* -*- 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 // for toupper() #include #include "nsArrayEnumerator.h" #include "nsCOMArray.h" #include "nsISupportsArray.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 #include "mozilla-config.h" #include "plvmx.h" #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 (!VMX_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 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 file; NS_GetSpecialDirectory(NS_WIN_FAVORITES_DIR, getter_AddRefs(file)); if (file) { nsCOMPtr 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 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(MOZ_UTF16("12"), &pulseLiteral); *target = pulseLiteral; return NS_OK; } } else if (isFileURI(source)) { if (property == mNC_Name) { nsCOMPtr 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 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 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 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 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 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 pulseLiteral; mRDFService->GetLiteral(MOZ_UTF16("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 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 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 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 pulseLiteral; mRDFService->GetLiteral(MOZ_UTF16("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 name; rv = GetName(source, getter_AddRefs(name)); if (NS_FAILED(rv)) return rv; return NS_NewSingletonEnumerator(targets, name); } else if (property == mNC_URL) { nsCOMPtr 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 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 pulseLiteral; rv = mRDFService->GetLiteral(MOZ_UTF16("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 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 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 resources; resources.SetCapacity(2); resources.AppendObject(mNC_Child); resources.AppendObject(mNC_pulse); return NS_NewArrayEnumerator(labels, resources); } else if (isFileURI(source)) { nsCOMArray 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/**/** commands) { return(NS_NewEmptyEnumerator(commands)); } NS_IMETHODIMP FileSystemDataSource::IsCommandEnabled(nsISupportsArray/**/* aSources, nsIRDFResource* aCommand, nsISupportsArray/**/* aArguments, bool* aResult) { return(NS_ERROR_NOT_IMPLEMENTED); } NS_IMETHODIMP FileSystemDataSource::DoCommand(nsISupportsArray/**/* aSources, nsIRDFResource* aCommand, nsISupportsArray/**/* 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 volumes; nsCOMPtr 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 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 isupports; if (NS_FAILED(rv = folderEnum->GetNext(getter_AddRefs(isupports)))) break; nsCOMPtr res = do_QueryInterface(isupports); if (!res) break; nsCOMPtr 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 aIURI; if (NS_FAILED(rv = NS_NewURI(getter_AddRefs(aIURI), nsDependentCString(parentURI)))) return(rv); nsCOMPtr fileURL = do_QueryInterface(aIURI); if (!fileURL) return NS_OK; nsCOMPtr aDir; if (NS_FAILED(rv = fileURL->GetFile(getter_AddRefs(aDir)))) return(rv); // ensure that we DO NOT resolve aliases aDir->SetFollowLinks(false); nsCOMPtr dirContents; if (NS_FAILED(rv = aDir->GetDirectoryEntries(getter_AddRefs(dirContents)))) return(rv); if (!dirContents) return(NS_ERROR_UNEXPECTED); nsCOMArray resources; bool hasMore; while(NS_SUCCEEDED(rv = dirContents->HasMoreElements(&hasMore)) && hasMore) { nsCOMPtr isupports; if (NS_FAILED(rv = dirContents->GetNext(getter_AddRefs(isupports)))) break; nsCOMPtr 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('/'); } char *escLeafStr = nsEscape(NS_ConvertUTF16toUTF8(leafStr).get(), url_Path); leafStr.Truncate(); if (!escLeafStr) continue; nsAutoCString leaf(escLeafStr); free(escLeafStr); escLeafStr = nullptr; // 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 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 aIURI; if (NS_FAILED(rv = NS_NewURI(getter_AddRefs(aIURI), nsDependentCString(uri)))) return(rv); nsCOMPtr fileURL = do_QueryInterface(aIURI); if (!fileURL) return NS_OK; nsCOMPtr 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 aIURI; if (NS_FAILED(rv = NS_NewURI(getter_AddRefs(aIURI), nsDependentCString(uri)))) return(rv); nsCOMPtr fileURL = do_QueryInterface(aIURI); if (!fileURL) return NS_OK; nsCOMPtr 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 aIURI; if (NS_FAILED(rv = NS_NewURI(getter_AddRefs(aIURI), nsDependentCString(uri)))) return(rv); nsCOMPtr fileURL = do_QueryInterface(aIURI); if (!fileURL) return NS_OK; nsCOMPtr 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 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 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 strm; NS_NewLocalFileInputStream(getter_AddRefs(strm),f); nsCOMPtr 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); }