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: #include "nsIDirectoryService.h" michael@0: #include "DirectoryProvider.h" michael@0: michael@0: #include "nsIFile.h" michael@0: #include "nsISimpleEnumerator.h" michael@0: #include "nsIPrefService.h" michael@0: #include "nsIPrefBranch.h" michael@0: michael@0: #include "nsArrayEnumerator.h" michael@0: #include "nsEnumeratorUtils.h" michael@0: #include "nsAppDirectoryServiceDefs.h" michael@0: #include "nsDirectoryServiceDefs.h" michael@0: #include "nsCategoryManagerUtils.h" michael@0: #include "nsComponentManagerUtils.h" michael@0: #include "nsCOMArray.h" michael@0: #include "nsDirectoryServiceUtils.h" michael@0: #include "mozilla/ModuleUtils.h" michael@0: #include "nsServiceManagerUtils.h" michael@0: #include "nsStringAPI.h" michael@0: #include "nsXULAppAPI.h" michael@0: #include "nsIPrefLocalizedString.h" michael@0: michael@0: namespace mozilla { michael@0: namespace browser { michael@0: michael@0: NS_IMPL_ISUPPORTS(DirectoryProvider, michael@0: nsIDirectoryServiceProvider, michael@0: nsIDirectoryServiceProvider2) michael@0: michael@0: NS_IMETHODIMP michael@0: DirectoryProvider::GetFile(const char *aKey, bool *aPersist, nsIFile* *aResult) michael@0: { michael@0: nsresult rv; michael@0: michael@0: *aResult = nullptr; michael@0: michael@0: // NOTE: This function can be reentrant through the NS_GetSpecialDirectory michael@0: // call, so be careful not to cause infinite recursion. michael@0: michael@0: nsCOMPtr file; michael@0: michael@0: char const* leafName = nullptr; michael@0: michael@0: if (!strcmp(aKey, NS_APP_BOOKMARKS_50_FILE)) { michael@0: leafName = "bookmarks.html"; michael@0: michael@0: nsCOMPtr prefs(do_GetService(NS_PREFSERVICE_CONTRACTID)); michael@0: if (prefs) { michael@0: nsCString path; michael@0: rv = prefs->GetCharPref("browser.bookmarks.file", getter_Copies(path)); michael@0: if (NS_SUCCEEDED(rv)) { michael@0: NS_NewNativeLocalFile(path, true, getter_AddRefs(file)); michael@0: } michael@0: } michael@0: } michael@0: else { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: nsDependentCString leafstr(leafName); michael@0: michael@0: nsCOMPtr parentDir; michael@0: if (file) { michael@0: rv = file->GetParent(getter_AddRefs(parentDir)); michael@0: if (NS_FAILED(rv)) michael@0: return rv; michael@0: } michael@0: else { michael@0: rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR, getter_AddRefs(parentDir)); michael@0: if (NS_FAILED(rv)) michael@0: return rv; michael@0: michael@0: rv = parentDir->Clone(getter_AddRefs(file)); michael@0: if (NS_FAILED(rv)) michael@0: return rv; michael@0: michael@0: file->AppendNative(leafstr); michael@0: } michael@0: michael@0: *aPersist = true; michael@0: NS_ADDREF(*aResult = file); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: static void michael@0: AppendFileKey(const char *key, nsIProperties* aDirSvc, michael@0: nsCOMArray &array) michael@0: { michael@0: nsCOMPtr file; michael@0: nsresult rv = aDirSvc->Get(key, NS_GET_IID(nsIFile), getter_AddRefs(file)); michael@0: if (NS_FAILED(rv)) michael@0: return; michael@0: michael@0: bool exists; michael@0: rv = file->Exists(&exists); michael@0: if (NS_FAILED(rv) || !exists) michael@0: return; michael@0: michael@0: array.AppendObject(file); michael@0: } michael@0: michael@0: // Appends the distribution-specific search engine directories to the michael@0: // array. The directory structure is as follows: michael@0: michael@0: // appdir/ michael@0: // \- distribution/ michael@0: // \- searchplugins/ michael@0: // |- common/ michael@0: // \- locale/ michael@0: // |- / michael@0: // ... michael@0: // \- / michael@0: michael@0: // common engines are loaded for all locales. If there is no locale michael@0: // directory for the current locale, there is a pref: michael@0: // "distribution.searchplugins.defaultLocale" michael@0: // which specifies a default locale to use. michael@0: michael@0: static void michael@0: AppendDistroSearchDirs(nsIProperties* aDirSvc, nsCOMArray &array) michael@0: { michael@0: nsCOMPtr searchPlugins; michael@0: nsresult rv = aDirSvc->Get(XRE_EXECUTABLE_FILE, michael@0: NS_GET_IID(nsIFile), michael@0: getter_AddRefs(searchPlugins)); michael@0: if (NS_FAILED(rv)) michael@0: return; michael@0: searchPlugins->SetNativeLeafName(NS_LITERAL_CSTRING("distribution")); michael@0: searchPlugins->AppendNative(NS_LITERAL_CSTRING("searchplugins")); michael@0: michael@0: bool exists; michael@0: rv = searchPlugins->Exists(&exists); michael@0: if (NS_FAILED(rv) || !exists) michael@0: return; michael@0: michael@0: nsCOMPtr commonPlugins; michael@0: rv = searchPlugins->Clone(getter_AddRefs(commonPlugins)); michael@0: if (NS_SUCCEEDED(rv)) { michael@0: commonPlugins->AppendNative(NS_LITERAL_CSTRING("common")); michael@0: rv = commonPlugins->Exists(&exists); michael@0: if (NS_SUCCEEDED(rv) && exists) michael@0: array.AppendObject(commonPlugins); michael@0: } michael@0: michael@0: nsCOMPtr prefs(do_GetService(NS_PREFSERVICE_CONTRACTID)); michael@0: if (prefs) { michael@0: michael@0: nsCOMPtr localePlugins; michael@0: rv = searchPlugins->Clone(getter_AddRefs(localePlugins)); michael@0: if (NS_FAILED(rv)) michael@0: return; michael@0: michael@0: localePlugins->AppendNative(NS_LITERAL_CSTRING("locale")); michael@0: michael@0: nsCString locale; michael@0: nsCOMPtr prefString; michael@0: rv = prefs->GetComplexValue("general.useragent.locale", michael@0: NS_GET_IID(nsIPrefLocalizedString), michael@0: getter_AddRefs(prefString)); michael@0: if (NS_SUCCEEDED(rv)) { michael@0: nsAutoString wLocale; michael@0: prefString->GetData(getter_Copies(wLocale)); michael@0: CopyUTF16toUTF8(wLocale, locale); michael@0: } else { michael@0: rv = prefs->GetCharPref("general.useragent.locale", getter_Copies(locale)); michael@0: } michael@0: michael@0: if (NS_SUCCEEDED(rv)) { michael@0: michael@0: nsCOMPtr curLocalePlugins; michael@0: rv = localePlugins->Clone(getter_AddRefs(curLocalePlugins)); michael@0: if (NS_SUCCEEDED(rv)) { michael@0: michael@0: curLocalePlugins->AppendNative(locale); michael@0: rv = curLocalePlugins->Exists(&exists); michael@0: if (NS_SUCCEEDED(rv) && exists) { michael@0: array.AppendObject(curLocalePlugins); michael@0: return; // all done michael@0: } michael@0: } michael@0: } michael@0: michael@0: // we didn't append the locale dir - try the default one michael@0: nsCString defLocale; michael@0: rv = prefs->GetCharPref("distribution.searchplugins.defaultLocale", michael@0: getter_Copies(defLocale)); michael@0: if (NS_SUCCEEDED(rv)) { michael@0: michael@0: nsCOMPtr defLocalePlugins; michael@0: rv = localePlugins->Clone(getter_AddRefs(defLocalePlugins)); michael@0: if (NS_SUCCEEDED(rv)) { michael@0: michael@0: defLocalePlugins->AppendNative(defLocale); michael@0: rv = defLocalePlugins->Exists(&exists); michael@0: if (NS_SUCCEEDED(rv) && exists) michael@0: array.AppendObject(defLocalePlugins); michael@0: } michael@0: } michael@0: } michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: DirectoryProvider::GetFiles(const char *aKey, nsISimpleEnumerator* *aResult) michael@0: { michael@0: nsresult rv; michael@0: michael@0: if (!strcmp(aKey, NS_APP_SEARCH_DIR_LIST)) { michael@0: nsCOMPtr dirSvc michael@0: (do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID)); michael@0: if (!dirSvc) michael@0: return NS_ERROR_FAILURE; michael@0: michael@0: nsCOMArray baseFiles; michael@0: michael@0: /** michael@0: * We want to preserve the following order, since the search service loads michael@0: * engines in first-loaded-wins order. michael@0: * - extension search plugin locations (prepended below using michael@0: * NS_NewUnionEnumerator) michael@0: * - distro search plugin locations michael@0: * - user search plugin locations (profile) michael@0: * - app search plugin location (shipped engines) michael@0: */ michael@0: AppendDistroSearchDirs(dirSvc, baseFiles); michael@0: AppendFileKey(NS_APP_USER_SEARCH_DIR, dirSvc, baseFiles); michael@0: AppendFileKey(NS_APP_SEARCH_DIR, dirSvc, baseFiles); michael@0: michael@0: nsCOMPtr baseEnum; michael@0: rv = NS_NewArrayEnumerator(getter_AddRefs(baseEnum), baseFiles); michael@0: if (NS_FAILED(rv)) michael@0: return rv; michael@0: michael@0: nsCOMPtr list; michael@0: rv = dirSvc->Get(XRE_EXTENSIONS_DIR_LIST, michael@0: NS_GET_IID(nsISimpleEnumerator), getter_AddRefs(list)); michael@0: if (NS_FAILED(rv)) michael@0: return rv; michael@0: michael@0: static char const *const kAppendSPlugins[] = {"searchplugins", nullptr}; michael@0: michael@0: nsCOMPtr extEnum = michael@0: new AppendingEnumerator(list, kAppendSPlugins); michael@0: if (!extEnum) michael@0: return NS_ERROR_OUT_OF_MEMORY; michael@0: michael@0: return NS_NewUnionEnumerator(aResult, extEnum, baseEnum); michael@0: } michael@0: michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: NS_IMPL_ISUPPORTS(DirectoryProvider::AppendingEnumerator, nsISimpleEnumerator) michael@0: michael@0: NS_IMETHODIMP michael@0: DirectoryProvider::AppendingEnumerator::HasMoreElements(bool *aResult) michael@0: { michael@0: *aResult = mNext ? true : false; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: DirectoryProvider::AppendingEnumerator::GetNext(nsISupports* *aResult) michael@0: { michael@0: if (aResult) michael@0: NS_ADDREF(*aResult = mNext); michael@0: michael@0: mNext = nullptr; michael@0: michael@0: nsresult rv; michael@0: michael@0: // Ignore all errors michael@0: michael@0: bool more; michael@0: while (NS_SUCCEEDED(mBase->HasMoreElements(&more)) && more) { michael@0: nsCOMPtr nextbasesupp; michael@0: mBase->GetNext(getter_AddRefs(nextbasesupp)); michael@0: michael@0: nsCOMPtr nextbase(do_QueryInterface(nextbasesupp)); michael@0: if (!nextbase) michael@0: continue; michael@0: michael@0: nextbase->Clone(getter_AddRefs(mNext)); michael@0: if (!mNext) michael@0: continue; michael@0: michael@0: char const *const * i = mAppendList; michael@0: while (*i) { michael@0: mNext->AppendNative(nsDependentCString(*i)); michael@0: ++i; michael@0: } michael@0: michael@0: bool exists; michael@0: rv = mNext->Exists(&exists); michael@0: if (NS_SUCCEEDED(rv) && exists) michael@0: break; michael@0: michael@0: mNext = nullptr; michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: DirectoryProvider::AppendingEnumerator::AppendingEnumerator michael@0: (nsISimpleEnumerator* aBase, michael@0: char const *const *aAppendList) : michael@0: mBase(aBase), michael@0: mAppendList(aAppendList) michael@0: { michael@0: // Initialize mNext to begin. michael@0: GetNext(nullptr); michael@0: } michael@0: michael@0: } // namespace browser michael@0: } // namespace mozilla