Wed, 31 Dec 2014 07:22:50 +0100
Correct previous dual key logic pending first delivery installment.
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 #include "nsIDirectoryService.h"
6 #include "DirectoryProvider.h"
8 #include "nsIFile.h"
9 #include "nsISimpleEnumerator.h"
10 #include "nsIPrefService.h"
11 #include "nsIPrefBranch.h"
13 #include "nsArrayEnumerator.h"
14 #include "nsEnumeratorUtils.h"
15 #include "nsAppDirectoryServiceDefs.h"
16 #include "nsDirectoryServiceDefs.h"
17 #include "nsCategoryManagerUtils.h"
18 #include "nsComponentManagerUtils.h"
19 #include "nsCOMArray.h"
20 #include "nsDirectoryServiceUtils.h"
21 #include "mozilla/ModuleUtils.h"
22 #include "nsServiceManagerUtils.h"
23 #include "nsStringAPI.h"
24 #include "nsXULAppAPI.h"
25 #include "nsIPrefLocalizedString.h"
27 namespace mozilla {
28 namespace browser {
30 NS_IMPL_ISUPPORTS(DirectoryProvider,
31 nsIDirectoryServiceProvider,
32 nsIDirectoryServiceProvider2)
34 NS_IMETHODIMP
35 DirectoryProvider::GetFile(const char *aKey, bool *aPersist, nsIFile* *aResult)
36 {
37 nsresult rv;
39 *aResult = nullptr;
41 // NOTE: This function can be reentrant through the NS_GetSpecialDirectory
42 // call, so be careful not to cause infinite recursion.
44 nsCOMPtr<nsIFile> file;
46 char const* leafName = nullptr;
48 if (!strcmp(aKey, NS_APP_BOOKMARKS_50_FILE)) {
49 leafName = "bookmarks.html";
51 nsCOMPtr<nsIPrefBranch> prefs(do_GetService(NS_PREFSERVICE_CONTRACTID));
52 if (prefs) {
53 nsCString path;
54 rv = prefs->GetCharPref("browser.bookmarks.file", getter_Copies(path));
55 if (NS_SUCCEEDED(rv)) {
56 NS_NewNativeLocalFile(path, true, getter_AddRefs(file));
57 }
58 }
59 }
60 else {
61 return NS_ERROR_FAILURE;
62 }
64 nsDependentCString leafstr(leafName);
66 nsCOMPtr<nsIFile> parentDir;
67 if (file) {
68 rv = file->GetParent(getter_AddRefs(parentDir));
69 if (NS_FAILED(rv))
70 return rv;
71 }
72 else {
73 rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR, getter_AddRefs(parentDir));
74 if (NS_FAILED(rv))
75 return rv;
77 rv = parentDir->Clone(getter_AddRefs(file));
78 if (NS_FAILED(rv))
79 return rv;
81 file->AppendNative(leafstr);
82 }
84 *aPersist = true;
85 NS_ADDREF(*aResult = file);
87 return NS_OK;
88 }
90 static void
91 AppendFileKey(const char *key, nsIProperties* aDirSvc,
92 nsCOMArray<nsIFile> &array)
93 {
94 nsCOMPtr<nsIFile> file;
95 nsresult rv = aDirSvc->Get(key, NS_GET_IID(nsIFile), getter_AddRefs(file));
96 if (NS_FAILED(rv))
97 return;
99 bool exists;
100 rv = file->Exists(&exists);
101 if (NS_FAILED(rv) || !exists)
102 return;
104 array.AppendObject(file);
105 }
107 // Appends the distribution-specific search engine directories to the
108 // array. The directory structure is as follows:
110 // appdir/
111 // \- distribution/
112 // \- searchplugins/
113 // |- common/
114 // \- locale/
115 // |- <locale 1>/
116 // ...
117 // \- <locale N>/
119 // common engines are loaded for all locales. If there is no locale
120 // directory for the current locale, there is a pref:
121 // "distribution.searchplugins.defaultLocale"
122 // which specifies a default locale to use.
124 static void
125 AppendDistroSearchDirs(nsIProperties* aDirSvc, nsCOMArray<nsIFile> &array)
126 {
127 nsCOMPtr<nsIFile> searchPlugins;
128 nsresult rv = aDirSvc->Get(XRE_EXECUTABLE_FILE,
129 NS_GET_IID(nsIFile),
130 getter_AddRefs(searchPlugins));
131 if (NS_FAILED(rv))
132 return;
133 searchPlugins->SetNativeLeafName(NS_LITERAL_CSTRING("distribution"));
134 searchPlugins->AppendNative(NS_LITERAL_CSTRING("searchplugins"));
136 bool exists;
137 rv = searchPlugins->Exists(&exists);
138 if (NS_FAILED(rv) || !exists)
139 return;
141 nsCOMPtr<nsIFile> commonPlugins;
142 rv = searchPlugins->Clone(getter_AddRefs(commonPlugins));
143 if (NS_SUCCEEDED(rv)) {
144 commonPlugins->AppendNative(NS_LITERAL_CSTRING("common"));
145 rv = commonPlugins->Exists(&exists);
146 if (NS_SUCCEEDED(rv) && exists)
147 array.AppendObject(commonPlugins);
148 }
150 nsCOMPtr<nsIPrefBranch> prefs(do_GetService(NS_PREFSERVICE_CONTRACTID));
151 if (prefs) {
153 nsCOMPtr<nsIFile> localePlugins;
154 rv = searchPlugins->Clone(getter_AddRefs(localePlugins));
155 if (NS_FAILED(rv))
156 return;
158 localePlugins->AppendNative(NS_LITERAL_CSTRING("locale"));
160 nsCString locale;
161 nsCOMPtr<nsIPrefLocalizedString> prefString;
162 rv = prefs->GetComplexValue("general.useragent.locale",
163 NS_GET_IID(nsIPrefLocalizedString),
164 getter_AddRefs(prefString));
165 if (NS_SUCCEEDED(rv)) {
166 nsAutoString wLocale;
167 prefString->GetData(getter_Copies(wLocale));
168 CopyUTF16toUTF8(wLocale, locale);
169 } else {
170 rv = prefs->GetCharPref("general.useragent.locale", getter_Copies(locale));
171 }
173 if (NS_SUCCEEDED(rv)) {
175 nsCOMPtr<nsIFile> curLocalePlugins;
176 rv = localePlugins->Clone(getter_AddRefs(curLocalePlugins));
177 if (NS_SUCCEEDED(rv)) {
179 curLocalePlugins->AppendNative(locale);
180 rv = curLocalePlugins->Exists(&exists);
181 if (NS_SUCCEEDED(rv) && exists) {
182 array.AppendObject(curLocalePlugins);
183 return; // all done
184 }
185 }
186 }
188 // we didn't append the locale dir - try the default one
189 nsCString defLocale;
190 rv = prefs->GetCharPref("distribution.searchplugins.defaultLocale",
191 getter_Copies(defLocale));
192 if (NS_SUCCEEDED(rv)) {
194 nsCOMPtr<nsIFile> defLocalePlugins;
195 rv = localePlugins->Clone(getter_AddRefs(defLocalePlugins));
196 if (NS_SUCCEEDED(rv)) {
198 defLocalePlugins->AppendNative(defLocale);
199 rv = defLocalePlugins->Exists(&exists);
200 if (NS_SUCCEEDED(rv) && exists)
201 array.AppendObject(defLocalePlugins);
202 }
203 }
204 }
205 }
207 NS_IMETHODIMP
208 DirectoryProvider::GetFiles(const char *aKey, nsISimpleEnumerator* *aResult)
209 {
210 nsresult rv;
212 if (!strcmp(aKey, NS_APP_SEARCH_DIR_LIST)) {
213 nsCOMPtr<nsIProperties> dirSvc
214 (do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID));
215 if (!dirSvc)
216 return NS_ERROR_FAILURE;
218 nsCOMArray<nsIFile> baseFiles;
220 /**
221 * We want to preserve the following order, since the search service loads
222 * engines in first-loaded-wins order.
223 * - extension search plugin locations (prepended below using
224 * NS_NewUnionEnumerator)
225 * - distro search plugin locations
226 * - user search plugin locations (profile)
227 * - app search plugin location (shipped engines)
228 */
229 AppendDistroSearchDirs(dirSvc, baseFiles);
230 AppendFileKey(NS_APP_USER_SEARCH_DIR, dirSvc, baseFiles);
231 AppendFileKey(NS_APP_SEARCH_DIR, dirSvc, baseFiles);
233 nsCOMPtr<nsISimpleEnumerator> baseEnum;
234 rv = NS_NewArrayEnumerator(getter_AddRefs(baseEnum), baseFiles);
235 if (NS_FAILED(rv))
236 return rv;
238 nsCOMPtr<nsISimpleEnumerator> list;
239 rv = dirSvc->Get(XRE_EXTENSIONS_DIR_LIST,
240 NS_GET_IID(nsISimpleEnumerator), getter_AddRefs(list));
241 if (NS_FAILED(rv))
242 return rv;
244 static char const *const kAppendSPlugins[] = {"searchplugins", nullptr};
246 nsCOMPtr<nsISimpleEnumerator> extEnum =
247 new AppendingEnumerator(list, kAppendSPlugins);
248 if (!extEnum)
249 return NS_ERROR_OUT_OF_MEMORY;
251 return NS_NewUnionEnumerator(aResult, extEnum, baseEnum);
252 }
254 return NS_ERROR_FAILURE;
255 }
257 NS_IMPL_ISUPPORTS(DirectoryProvider::AppendingEnumerator, nsISimpleEnumerator)
259 NS_IMETHODIMP
260 DirectoryProvider::AppendingEnumerator::HasMoreElements(bool *aResult)
261 {
262 *aResult = mNext ? true : false;
263 return NS_OK;
264 }
266 NS_IMETHODIMP
267 DirectoryProvider::AppendingEnumerator::GetNext(nsISupports* *aResult)
268 {
269 if (aResult)
270 NS_ADDREF(*aResult = mNext);
272 mNext = nullptr;
274 nsresult rv;
276 // Ignore all errors
278 bool more;
279 while (NS_SUCCEEDED(mBase->HasMoreElements(&more)) && more) {
280 nsCOMPtr<nsISupports> nextbasesupp;
281 mBase->GetNext(getter_AddRefs(nextbasesupp));
283 nsCOMPtr<nsIFile> nextbase(do_QueryInterface(nextbasesupp));
284 if (!nextbase)
285 continue;
287 nextbase->Clone(getter_AddRefs(mNext));
288 if (!mNext)
289 continue;
291 char const *const * i = mAppendList;
292 while (*i) {
293 mNext->AppendNative(nsDependentCString(*i));
294 ++i;
295 }
297 bool exists;
298 rv = mNext->Exists(&exists);
299 if (NS_SUCCEEDED(rv) && exists)
300 break;
302 mNext = nullptr;
303 }
305 return NS_OK;
306 }
308 DirectoryProvider::AppendingEnumerator::AppendingEnumerator
309 (nsISimpleEnumerator* aBase,
310 char const *const *aAppendList) :
311 mBase(aBase),
312 mAppendList(aAppendList)
313 {
314 // Initialize mNext to begin.
315 GetNext(nullptr);
316 }
318 } // namespace browser
319 } // namespace mozilla