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