1 : /* ***** BEGIN LICENSE BLOCK *****
2 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
3 : *
4 : * The contents of this file are subject to the Mozilla Public License Version
5 : * 1.1 (the "License"); you may not use this file except in compliance with
6 : * the License. You may obtain a copy of the License at
7 : * http://www.mozilla.org/MPL/
8 : *
9 : * Software distributed under the License is distributed on an "AS IS" basis,
10 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11 : * for the specific language governing rights and limitations under the
12 : * License.
13 : *
14 : * The Original Code is the Mozilla Firefox browser.
15 : *
16 : * The Initial Developer of the Original Code is
17 : * Benjamin Smedberg <benjamin@smedbergs.us>
18 : *
19 : * Portions created by the Initial Developer are Copyright (C) 2005
20 : * the Initial Developer. All Rights Reserved.
21 : *
22 : * Contributor(s):
23 : *
24 : * Alternatively, the contents of this file may be used under the terms of
25 : * either the GNU General Public License Version 2 or later (the "GPL"), or
26 : * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 : * in which case the provisions of the GPL or the LGPL are applicable instead
28 : * of those above. If you wish to allow use of your version of this file only
29 : * under the terms of either the GPL or the LGPL, and not to allow others to
30 : * use your version of this file under the terms of the MPL, indicate your
31 : * decision by deleting the provisions above and replace them with the notice
32 : * and other provisions required by the GPL or the LGPL. If you do not delete
33 : * the provisions above, a recipient may use your version of this file under
34 : * the terms of any one of the MPL, the GPL or the LGPL.
35 : *
36 : * ***** END LICENSE BLOCK ***** */
37 :
38 : #include "nsIDirectoryService.h"
39 : #include "DirectoryProvider.h"
40 :
41 : #include "nsIFile.h"
42 : #include "nsISimpleEnumerator.h"
43 : #include "nsIPrefService.h"
44 : #include "nsIPrefBranch.h"
45 :
46 : #include "nsArrayEnumerator.h"
47 : #include "nsEnumeratorUtils.h"
48 : #include "nsBrowserDirectoryServiceDefs.h"
49 : #include "nsAppDirectoryServiceDefs.h"
50 : #include "nsDirectoryServiceDefs.h"
51 : #include "nsCategoryManagerUtils.h"
52 : #include "nsComponentManagerUtils.h"
53 : #include "nsCOMArray.h"
54 : #include "nsDirectoryServiceUtils.h"
55 : #include "mozilla/ModuleUtils.h"
56 : #include "nsServiceManagerUtils.h"
57 : #include "nsStringAPI.h"
58 : #include "nsXULAppAPI.h"
59 : #include "nsIPrefLocalizedString.h"
60 :
61 : namespace mozilla {
62 : namespace browser {
63 :
64 51189 : NS_IMPL_ISUPPORTS2(DirectoryProvider,
65 : nsIDirectoryServiceProvider,
66 : nsIDirectoryServiceProvider2)
67 :
68 : NS_IMETHODIMP
69 9787 : DirectoryProvider::GetFile(const char *aKey, bool *aPersist, nsIFile* *aResult)
70 : {
71 : nsresult rv;
72 :
73 9787 : *aResult = nsnull;
74 :
75 : // NOTE: This function can be reentrant through the NS_GetSpecialDirectory
76 : // call, so be careful not to cause infinite recursion.
77 :
78 19574 : nsCOMPtr<nsIFile> file;
79 :
80 9787 : char const* leafName = nsnull;
81 :
82 9787 : if (!strcmp(aKey, NS_APP_BOOKMARKS_50_FILE)) {
83 9 : leafName = "bookmarks.html";
84 :
85 18 : nsCOMPtr<nsIPrefBranch> prefs(do_GetService(NS_PREFSERVICE_CONTRACTID));
86 9 : if (prefs) {
87 18 : nsCString path;
88 9 : rv = prefs->GetCharPref("browser.bookmarks.file", getter_Copies(path));
89 9 : if (NS_SUCCEEDED(rv)) {
90 1 : NS_NewNativeLocalFile(path, true, (nsILocalFile**)(nsIFile**) getter_AddRefs(file));
91 : }
92 : }
93 : }
94 9778 : else if (!strcmp(aKey, NS_APP_EXISTING_PREF_OVERRIDE)) {
95 : rv = NS_GetSpecialDirectory(NS_APP_DEFAULTS_50_DIR,
96 1 : getter_AddRefs(file));
97 1 : NS_ENSURE_SUCCESS(rv, rv);
98 :
99 1 : file->AppendNative(NS_LITERAL_CSTRING("existing-profile-defaults.js"));
100 1 : file.swap(*aResult);
101 1 : return NS_OK;
102 : }
103 : else {
104 9777 : return NS_ERROR_FAILURE;
105 : }
106 :
107 18 : nsDependentCString leafstr(leafName);
108 :
109 18 : nsCOMPtr<nsIFile> parentDir;
110 9 : if (file) {
111 1 : rv = file->GetParent(getter_AddRefs(parentDir));
112 1 : if (NS_FAILED(rv))
113 0 : return rv;
114 : }
115 : else {
116 8 : rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR, getter_AddRefs(parentDir));
117 8 : if (NS_FAILED(rv))
118 0 : return rv;
119 :
120 8 : rv = parentDir->Clone(getter_AddRefs(file));
121 8 : if (NS_FAILED(rv))
122 0 : return rv;
123 :
124 8 : file->AppendNative(leafstr);
125 : }
126 :
127 9 : *aPersist = true;
128 9 : NS_ADDREF(*aResult = file);
129 :
130 9 : return NS_OK;
131 : }
132 :
133 : static void
134 2 : AppendFileKey(const char *key, nsIProperties* aDirSvc,
135 : nsCOMArray<nsIFile> &array)
136 : {
137 4 : nsCOMPtr<nsIFile> file;
138 2 : nsresult rv = aDirSvc->Get(key, NS_GET_IID(nsIFile), getter_AddRefs(file));
139 2 : if (NS_FAILED(rv))
140 : return;
141 :
142 : bool exists;
143 2 : rv = file->Exists(&exists);
144 2 : if (NS_FAILED(rv) || !exists)
145 : return;
146 :
147 1 : array.AppendObject(file);
148 : }
149 :
150 : // Appends the distribution-specific search engine directories to the
151 : // array. The directory structure is as follows:
152 :
153 : // appdir/
154 : // \- distribution/
155 : // \- searchplugins/
156 : // |- common/
157 : // \- locale/
158 : // |- <locale 1>/
159 : // ...
160 : // \- <locale N>/
161 :
162 : // common engines are loaded for all locales. If there is no locale
163 : // directory for the current locale, there is a pref:
164 : // "distribution.searchplugins.defaultLocale"
165 : // which specifies a default locale to use.
166 :
167 : static void
168 1 : AppendDistroSearchDirs(nsIProperties* aDirSvc, nsCOMArray<nsIFile> &array)
169 : {
170 2 : nsCOMPtr<nsIFile> searchPlugins;
171 : nsresult rv = aDirSvc->Get(NS_XPCOM_CURRENT_PROCESS_DIR,
172 : NS_GET_IID(nsIFile),
173 1 : getter_AddRefs(searchPlugins));
174 1 : if (NS_FAILED(rv))
175 : return;
176 1 : searchPlugins->AppendNative(NS_LITERAL_CSTRING("distribution"));
177 1 : searchPlugins->AppendNative(NS_LITERAL_CSTRING("searchplugins"));
178 :
179 : bool exists;
180 1 : rv = searchPlugins->Exists(&exists);
181 1 : if (NS_FAILED(rv) || !exists)
182 : return;
183 :
184 0 : nsCOMPtr<nsIFile> commonPlugins;
185 0 : rv = searchPlugins->Clone(getter_AddRefs(commonPlugins));
186 0 : if (NS_SUCCEEDED(rv)) {
187 0 : commonPlugins->AppendNative(NS_LITERAL_CSTRING("common"));
188 0 : rv = commonPlugins->Exists(&exists);
189 0 : if (NS_SUCCEEDED(rv) && exists)
190 0 : array.AppendObject(commonPlugins);
191 : }
192 :
193 0 : nsCOMPtr<nsIPrefBranch> prefs(do_GetService(NS_PREFSERVICE_CONTRACTID));
194 0 : if (prefs) {
195 :
196 0 : nsCOMPtr<nsIFile> localePlugins;
197 0 : rv = searchPlugins->Clone(getter_AddRefs(localePlugins));
198 0 : if (NS_FAILED(rv))
199 : return;
200 :
201 0 : localePlugins->AppendNative(NS_LITERAL_CSTRING("locale"));
202 :
203 0 : nsCString locale;
204 0 : nsCOMPtr<nsIPrefLocalizedString> prefString;
205 0 : rv = prefs->GetComplexValue("general.useragent.locale",
206 : NS_GET_IID(nsIPrefLocalizedString),
207 0 : getter_AddRefs(prefString));
208 0 : if (NS_SUCCEEDED(rv)) {
209 0 : nsAutoString wLocale;
210 0 : prefString->GetData(getter_Copies(wLocale));
211 0 : CopyUTF16toUTF8(wLocale, locale);
212 : } else {
213 0 : rv = prefs->GetCharPref("general.useragent.locale", getter_Copies(locale));
214 : }
215 :
216 0 : if (NS_SUCCEEDED(rv)) {
217 :
218 0 : nsCOMPtr<nsIFile> curLocalePlugins;
219 0 : rv = localePlugins->Clone(getter_AddRefs(curLocalePlugins));
220 0 : if (NS_SUCCEEDED(rv)) {
221 :
222 0 : curLocalePlugins->AppendNative(locale);
223 0 : rv = curLocalePlugins->Exists(&exists);
224 0 : if (NS_SUCCEEDED(rv) && exists) {
225 0 : array.AppendObject(curLocalePlugins);
226 : return; // all done
227 : }
228 : }
229 : }
230 :
231 : // we didn't append the locale dir - try the default one
232 0 : nsCString defLocale;
233 0 : rv = prefs->GetCharPref("distribution.searchplugins.defaultLocale",
234 0 : getter_Copies(defLocale));
235 0 : if (NS_SUCCEEDED(rv)) {
236 :
237 0 : nsCOMPtr<nsIFile> defLocalePlugins;
238 0 : rv = localePlugins->Clone(getter_AddRefs(defLocalePlugins));
239 0 : if (NS_SUCCEEDED(rv)) {
240 :
241 0 : defLocalePlugins->AppendNative(defLocale);
242 0 : rv = defLocalePlugins->Exists(&exists);
243 0 : if (NS_SUCCEEDED(rv) && exists)
244 0 : array.AppendObject(defLocalePlugins);
245 : }
246 : }
247 : }
248 : }
249 :
250 : NS_IMETHODIMP
251 181 : DirectoryProvider::GetFiles(const char *aKey, nsISimpleEnumerator* *aResult)
252 : {
253 : nsresult rv;
254 :
255 181 : if (!strcmp(aKey, NS_APP_SEARCH_DIR_LIST)) {
256 : nsCOMPtr<nsIProperties> dirSvc
257 2 : (do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID));
258 1 : if (!dirSvc)
259 0 : return NS_ERROR_FAILURE;
260 :
261 2 : nsCOMArray<nsIFile> baseFiles;
262 :
263 : /**
264 : * We want to preserve the following order, since the search service loads
265 : * engines in first-loaded-wins order.
266 : * - extension search plugin locations (prepended below using
267 : * NS_NewUnionEnumerator)
268 : * - distro search plugin locations
269 : * - user search plugin locations (profile)
270 : * - app search plugin location (shipped engines)
271 : */
272 1 : AppendDistroSearchDirs(dirSvc, baseFiles);
273 1 : AppendFileKey(NS_APP_USER_SEARCH_DIR, dirSvc, baseFiles);
274 1 : AppendFileKey(NS_APP_SEARCH_DIR, dirSvc, baseFiles);
275 :
276 2 : nsCOMPtr<nsISimpleEnumerator> baseEnum;
277 1 : rv = NS_NewArrayEnumerator(getter_AddRefs(baseEnum), baseFiles);
278 1 : if (NS_FAILED(rv))
279 0 : return rv;
280 :
281 2 : nsCOMPtr<nsISimpleEnumerator> list;
282 1 : rv = dirSvc->Get(XRE_EXTENSIONS_DIR_LIST,
283 1 : NS_GET_IID(nsISimpleEnumerator), getter_AddRefs(list));
284 1 : if (NS_FAILED(rv))
285 1 : return rv;
286 :
287 : static char const *const kAppendSPlugins[] = {"searchplugins", nsnull};
288 :
289 : nsCOMPtr<nsISimpleEnumerator> extEnum =
290 0 : new AppendingEnumerator(list, kAppendSPlugins);
291 0 : if (!extEnum)
292 0 : return NS_ERROR_OUT_OF_MEMORY;
293 :
294 0 : return NS_NewUnionEnumerator(aResult, extEnum, baseEnum);
295 : }
296 :
297 180 : return NS_ERROR_FAILURE;
298 : }
299 :
300 0 : NS_IMPL_ISUPPORTS1(DirectoryProvider::AppendingEnumerator, nsISimpleEnumerator)
301 :
302 : NS_IMETHODIMP
303 0 : DirectoryProvider::AppendingEnumerator::HasMoreElements(bool *aResult)
304 : {
305 0 : *aResult = mNext ? true : false;
306 0 : return NS_OK;
307 : }
308 :
309 : NS_IMETHODIMP
310 0 : DirectoryProvider::AppendingEnumerator::GetNext(nsISupports* *aResult)
311 : {
312 0 : if (aResult)
313 0 : NS_ADDREF(*aResult = mNext);
314 :
315 0 : mNext = nsnull;
316 :
317 : nsresult rv;
318 :
319 : // Ignore all errors
320 :
321 : bool more;
322 0 : while (NS_SUCCEEDED(mBase->HasMoreElements(&more)) && more) {
323 0 : nsCOMPtr<nsISupports> nextbasesupp;
324 0 : mBase->GetNext(getter_AddRefs(nextbasesupp));
325 :
326 0 : nsCOMPtr<nsIFile> nextbase(do_QueryInterface(nextbasesupp));
327 0 : if (!nextbase)
328 0 : continue;
329 :
330 0 : nextbase->Clone(getter_AddRefs(mNext));
331 0 : if (!mNext)
332 0 : continue;
333 :
334 0 : char const *const * i = mAppendList;
335 0 : while (*i) {
336 0 : mNext->AppendNative(nsDependentCString(*i));
337 0 : ++i;
338 : }
339 :
340 : bool exists;
341 0 : rv = mNext->Exists(&exists);
342 0 : if (NS_SUCCEEDED(rv) && exists)
343 : break;
344 :
345 0 : mNext = nsnull;
346 : }
347 :
348 0 : return NS_OK;
349 : }
350 :
351 0 : DirectoryProvider::AppendingEnumerator::AppendingEnumerator
352 : (nsISimpleEnumerator* aBase,
353 : char const *const *aAppendList) :
354 : mBase(aBase),
355 0 : mAppendList(aAppendList)
356 : {
357 : // Initialize mNext to begin.
358 0 : GetNext(nsnull);
359 0 : }
360 :
361 : } // namespace browser
362 : } // namespace mozilla
|