browser/components/distribution.js

changeset 0
6474c204b198
equal deleted inserted replaced
-1:000000000000 0:b81812602379
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/. */
4
5 this.EXPORTED_SYMBOLS = [ "DistributionCustomizer" ];
6
7 const Ci = Components.interfaces;
8 const Cc = Components.classes;
9 const Cr = Components.results;
10 const Cu = Components.utils;
11
12 const DISTRIBUTION_CUSTOMIZATION_COMPLETE_TOPIC =
13 "distribution-customization-complete";
14
15 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
16 Cu.import("resource://gre/modules/Services.jsm");
17 XPCOMUtils.defineLazyModuleGetter(this, "PlacesUtils",
18 "resource://gre/modules/PlacesUtils.jsm");
19
20 this.DistributionCustomizer = function DistributionCustomizer() {
21 // For parallel xpcshell testing purposes allow loading the distribution.ini
22 // file from the profile folder through an hidden pref.
23 let loadFromProfile = false;
24 try {
25 loadFromProfile = Services.prefs.getBoolPref("distribution.testing.loadFromProfile");
26 } catch(ex) {}
27 let dirSvc = Cc["@mozilla.org/file/directory_service;1"].
28 getService(Ci.nsIProperties);
29 let iniFile = loadFromProfile ? dirSvc.get("ProfD", Ci.nsIFile)
30 : dirSvc.get("XREExeF", Ci.nsIFile);
31 iniFile.leafName = "distribution";
32 iniFile.append("distribution.ini");
33 if (iniFile.exists())
34 this._iniFile = iniFile;
35 }
36
37 DistributionCustomizer.prototype = {
38 _iniFile: null,
39
40 get _ini() {
41 let ini = Cc["@mozilla.org/xpcom/ini-parser-factory;1"].
42 getService(Ci.nsIINIParserFactory).
43 createINIParser(this._iniFile);
44 this.__defineGetter__("_ini", function() ini);
45 return this._ini;
46 },
47
48 get _locale() {
49 let locale;
50 try {
51 locale = this._prefs.getCharPref("general.useragent.locale");
52 }
53 catch (e) {
54 locale = "en-US";
55 }
56 this.__defineGetter__("_locale", function() locale);
57 return this._locale;
58 },
59
60 get _prefSvc() {
61 let svc = Cc["@mozilla.org/preferences-service;1"].
62 getService(Ci.nsIPrefService);
63 this.__defineGetter__("_prefSvc", function() svc);
64 return this._prefSvc;
65 },
66
67 get _prefs() {
68 let branch = this._prefSvc.getBranch(null);
69 this.__defineGetter__("_prefs", function() branch);
70 return this._prefs;
71 },
72
73 get _ioSvc() {
74 let svc = Cc["@mozilla.org/network/io-service;1"].
75 getService(Ci.nsIIOService);
76 this.__defineGetter__("_ioSvc", function() svc);
77 return this._ioSvc;
78 },
79
80 _makeURI: function DIST__makeURI(spec) {
81 return this._ioSvc.newURI(spec, null, null);
82 },
83
84 _parseBookmarksSection:
85 function DIST_parseBookmarksSection(parentId, section) {
86 let keys = [];
87 for (let i in enumerate(this._ini.getKeys(section)))
88 keys.push(i);
89 keys.sort();
90
91 let items = {};
92 let defaultItemId = -1;
93 let maxItemId = -1;
94
95 for (let i = 0; i < keys.length; i++) {
96 let m = /^item\.(\d+)\.(\w+)\.?(\w*)/.exec(keys[i]);
97 if (m) {
98 let [foo, iid, iprop, ilocale] = m;
99 iid = parseInt(iid);
100
101 if (ilocale)
102 continue;
103
104 if (!items[iid])
105 items[iid] = {};
106 if (keys.indexOf(keys[i] + "." + this._locale) >= 0) {
107 items[iid][iprop] = this._ini.getString(section, keys[i] + "." +
108 this._locale);
109 } else {
110 items[iid][iprop] = this._ini.getString(section, keys[i]);
111 }
112
113 if (iprop == "type" && items[iid]["type"] == "default")
114 defaultItemId = iid;
115
116 if (maxItemId < iid)
117 maxItemId = iid;
118 } else {
119 dump("Key did not match: " + keys[i] + "\n");
120 }
121 }
122
123 let prependIndex = 0;
124 for (let iid = 0; iid <= maxItemId; iid++) {
125 if (!items[iid])
126 continue;
127
128 let index = PlacesUtils.bookmarks.DEFAULT_INDEX;
129 let newId;
130
131 switch (items[iid]["type"]) {
132 case "default":
133 break;
134
135 case "folder":
136 if (iid < defaultItemId)
137 index = prependIndex++;
138
139 newId = PlacesUtils.bookmarks.createFolder(parentId,
140 items[iid]["title"],
141 index);
142
143 this._parseBookmarksSection(newId, "BookmarksFolder-" +
144 items[iid]["folderId"]);
145
146 if (items[iid]["description"])
147 PlacesUtils.annotations.setItemAnnotation(newId,
148 "bookmarkProperties/description",
149 items[iid]["description"], 0,
150 PlacesUtils.annotations.EXPIRE_NEVER);
151
152 break;
153
154 case "separator":
155 if (iid < defaultItemId)
156 index = prependIndex++;
157 PlacesUtils.bookmarks.insertSeparator(parentId, index);
158 break;
159
160 case "livemark":
161 if (iid < defaultItemId)
162 index = prependIndex++;
163
164 // Don't bother updating the livemark contents on creation.
165 PlacesUtils.livemarks.addLivemark({ title: items[iid]["title"]
166 , parentId: parentId
167 , index: index
168 , feedURI: this._makeURI(items[iid]["feedLink"])
169 , siteURI: this._makeURI(items[iid]["siteLink"])
170 }).then(null, Cu.reportError);
171 break;
172
173 case "bookmark":
174 default:
175 if (iid < defaultItemId)
176 index = prependIndex++;
177
178 newId = PlacesUtils.bookmarks.insertBookmark(parentId,
179 this._makeURI(items[iid]["link"]),
180 index, items[iid]["title"]);
181
182 if (items[iid]["description"])
183 PlacesUtils.annotations.setItemAnnotation(newId,
184 "bookmarkProperties/description",
185 items[iid]["description"], 0,
186 PlacesUtils.annotations.EXPIRE_NEVER);
187
188 break;
189 }
190 }
191 },
192
193 _customizationsApplied: false,
194 applyCustomizations: function DIST_applyCustomizations() {
195 this._customizationsApplied = true;
196 if (!this._iniFile)
197 return this._checkCustomizationComplete();
198
199 // nsPrefService loads very early. Reload prefs so we can set
200 // distribution defaults during the prefservice:after-app-defaults
201 // notification (see applyPrefDefaults below)
202 this._prefSvc.QueryInterface(Ci.nsIObserver);
203 this._prefSvc.observe(null, "reload-default-prefs", null);
204 },
205
206 _bookmarksApplied: false,
207 applyBookmarks: function DIST_applyBookmarks() {
208 this._bookmarksApplied = true;
209 if (!this._iniFile)
210 return this._checkCustomizationComplete();
211
212 let sections = enumToObject(this._ini.getSections());
213
214 // The global section, and several of its fields, is required
215 // (we also check here to be consistent with applyPrefDefaults below)
216 if (!sections["Global"])
217 return this._checkCustomizationComplete();
218 let globalPrefs = enumToObject(this._ini.getKeys("Global"));
219 if (!(globalPrefs["id"] && globalPrefs["version"] && globalPrefs["about"]))
220 return this._checkCustomizationComplete();
221
222 let bmProcessedPref;
223 try {
224 bmProcessedPref = this._ini.getString("Global",
225 "bookmarks.initialized.pref");
226 }
227 catch (e) {
228 bmProcessedPref = "distribution." +
229 this._ini.getString("Global", "id") + ".bookmarksProcessed";
230 }
231
232 let bmProcessed = false;
233 try {
234 bmProcessed = this._prefs.getBoolPref(bmProcessedPref);
235 }
236 catch (e) {}
237
238 if (!bmProcessed) {
239 if (sections["BookmarksMenu"])
240 this._parseBookmarksSection(PlacesUtils.bookmarksMenuFolderId,
241 "BookmarksMenu");
242 if (sections["BookmarksToolbar"])
243 this._parseBookmarksSection(PlacesUtils.toolbarFolderId,
244 "BookmarksToolbar");
245 this._prefs.setBoolPref(bmProcessedPref, true);
246 }
247 return this._checkCustomizationComplete();
248 },
249
250 _prefDefaultsApplied: false,
251 applyPrefDefaults: function DIST_applyPrefDefaults() {
252 this._prefDefaultsApplied = true;
253 if (!this._iniFile)
254 return this._checkCustomizationComplete();
255
256 let sections = enumToObject(this._ini.getSections());
257
258 // The global section, and several of its fields, is required
259 if (!sections["Global"])
260 return this._checkCustomizationComplete();
261 let globalPrefs = enumToObject(this._ini.getKeys("Global"));
262 if (!(globalPrefs["id"] && globalPrefs["version"] && globalPrefs["about"]))
263 return this._checkCustomizationComplete();
264
265 let defaults = this._prefSvc.getDefaultBranch(null);
266
267 // Global really contains info we set as prefs. They're only
268 // separate because they are "special" (read: required)
269
270 defaults.setCharPref("distribution.id", this._ini.getString("Global", "id"));
271 defaults.setCharPref("distribution.version",
272 this._ini.getString("Global", "version"));
273
274 let partnerAbout = Cc["@mozilla.org/supports-string;1"].
275 createInstance(Ci.nsISupportsString);
276 try {
277 if (globalPrefs["about." + this._locale]) {
278 partnerAbout.data = this._ini.getString("Global", "about." + this._locale);
279 } else {
280 partnerAbout.data = this._ini.getString("Global", "about");
281 }
282 defaults.setComplexValue("distribution.about",
283 Ci.nsISupportsString, partnerAbout);
284 } catch (e) {
285 /* ignore bad prefs due to bug 895473 and move on */
286 Cu.reportError(e);
287 }
288
289 if (sections["Preferences"]) {
290 for (let key in enumerate(this._ini.getKeys("Preferences"))) {
291 try {
292 let value = eval(this._ini.getString("Preferences", key));
293 switch (typeof value) {
294 case "boolean":
295 defaults.setBoolPref(key, value);
296 break;
297 case "number":
298 defaults.setIntPref(key, value);
299 break;
300 case "string":
301 defaults.setCharPref(key, value);
302 break;
303 case "undefined":
304 defaults.setCharPref(key, value);
305 break;
306 }
307 } catch (e) { /* ignore bad prefs and move on */ }
308 }
309 }
310
311 // We eval() the localizable prefs as well (even though they'll
312 // always get set as a string) to keep the INI format consistent:
313 // string prefs always need to be in quotes
314
315 let localizedStr = Cc["@mozilla.org/pref-localizedstring;1"].
316 createInstance(Ci.nsIPrefLocalizedString);
317
318 if (sections["LocalizablePreferences"]) {
319 for (let key in enumerate(this._ini.getKeys("LocalizablePreferences"))) {
320 try {
321 let value = eval(this._ini.getString("LocalizablePreferences", key));
322 value = value.replace("%LOCALE%", this._locale, "g");
323 localizedStr.data = "data:text/plain," + key + "=" + value;
324 defaults.setComplexValue(key, Ci.nsIPrefLocalizedString, localizedStr);
325 } catch (e) { /* ignore bad prefs and move on */ }
326 }
327 }
328
329 if (sections["LocalizablePreferences-" + this._locale]) {
330 for (let key in enumerate(this._ini.getKeys("LocalizablePreferences-" + this._locale))) {
331 try {
332 let value = eval(this._ini.getString("LocalizablePreferences-" + this._locale, key));
333 localizedStr.data = "data:text/plain," + key + "=" + value;
334 defaults.setComplexValue(key, Ci.nsIPrefLocalizedString, localizedStr);
335 } catch (e) { /* ignore bad prefs and move on */ }
336 }
337 }
338
339 return this._checkCustomizationComplete();
340 },
341
342 _checkCustomizationComplete: function DIST__checkCustomizationComplete() {
343 let prefDefaultsApplied = this._prefDefaultsApplied || !this._iniFile;
344 if (this._customizationsApplied && this._bookmarksApplied &&
345 prefDefaultsApplied) {
346 let os = Cc["@mozilla.org/observer-service;1"].
347 getService(Ci.nsIObserverService);
348 os.notifyObservers(null, DISTRIBUTION_CUSTOMIZATION_COMPLETE_TOPIC, null);
349 }
350 }
351 };
352
353 function enumerate(UTF8Enumerator) {
354 while (UTF8Enumerator.hasMore())
355 yield UTF8Enumerator.getNext();
356 }
357
358 function enumToObject(UTF8Enumerator) {
359 let ret = {};
360 for (let i in enumerate(UTF8Enumerator))
361 ret[i] = 1;
362 return ret;
363 }

mercurial