/services/sync/modules/engines/prefs.js

http://github.com/zpao/v8monkey · JavaScript · 285 lines · 197 code · 40 blank · 48 comment · 29 complexity · d71599c90905b3e9d2308a9635fbb11e MD5 · raw file

  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 Bookmarks Sync.
  15. *
  16. * The Initial Developer of the Original Code is Mozilla.
  17. * Portions created by the Initial Developer are Copyright (C) 2008
  18. * the Initial Developer. All Rights Reserved.
  19. *
  20. * Contributor(s):
  21. * Anant Narayanan <anant@kix.in>
  22. * Philipp von Weitershausen <philipp@weitershausen.de>
  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. const EXPORTED_SYMBOLS = ['PrefsEngine', 'PrefRec'];
  38. const Cc = Components.classes;
  39. const Ci = Components.interfaces;
  40. const Cu = Components.utils;
  41. const WEAVE_SYNC_PREFS = "services.sync.prefs.sync.";
  42. Cu.import("resource://services-sync/engines.js");
  43. Cu.import("resource://services-sync/record.js");
  44. Cu.import("resource://services-sync/util.js");
  45. Cu.import("resource://services-sync/constants.js");
  46. Cu.import("resource://services-sync/ext/Preferences.js");
  47. Cu.import("resource://gre/modules/LightweightThemeManager.jsm");
  48. const PREFS_GUID = Utils.encodeBase64url(Services.appinfo.ID);
  49. function PrefRec(collection, id) {
  50. CryptoWrapper.call(this, collection, id);
  51. }
  52. PrefRec.prototype = {
  53. __proto__: CryptoWrapper.prototype,
  54. _logName: "Sync.Record.Pref",
  55. };
  56. Utils.deferGetSet(PrefRec, "cleartext", ["value"]);
  57. function PrefsEngine() {
  58. SyncEngine.call(this, "Prefs");
  59. }
  60. PrefsEngine.prototype = {
  61. __proto__: SyncEngine.prototype,
  62. _storeObj: PrefStore,
  63. _trackerObj: PrefTracker,
  64. _recordObj: PrefRec,
  65. version: 2,
  66. getChangedIDs: function getChangedIDs() {
  67. // No need for a proper timestamp (no conflict resolution needed).
  68. let changedIDs = {};
  69. if (this._tracker.modified)
  70. changedIDs[PREFS_GUID] = 0;
  71. return changedIDs;
  72. },
  73. _wipeClient: function _wipeClient() {
  74. SyncEngine.prototype._wipeClient.call(this);
  75. this.justWiped = true;
  76. },
  77. _reconcile: function _reconcile(item) {
  78. // Apply the incoming item if we don't care about the local data
  79. if (this.justWiped) {
  80. this.justWiped = false;
  81. return true;
  82. }
  83. return SyncEngine.prototype._reconcile.call(this, item);
  84. }
  85. };
  86. function PrefStore(name) {
  87. Store.call(this, name);
  88. Svc.Obs.add("profile-before-change", function() {
  89. this.__prefs = null;
  90. }, this);
  91. }
  92. PrefStore.prototype = {
  93. __proto__: Store.prototype,
  94. __prefs: null,
  95. get _prefs() {
  96. if (!this.__prefs)
  97. this.__prefs = new Preferences();
  98. return this.__prefs;
  99. },
  100. _getSyncPrefs: function _getSyncPrefs() {
  101. let syncPrefs = Cc["@mozilla.org/preferences-service;1"]
  102. .getService(Ci.nsIPrefService)
  103. .getBranch(WEAVE_SYNC_PREFS)
  104. .getChildList("", {});
  105. // Also sync preferences that determine which prefs get synced.
  106. return syncPrefs.concat(
  107. syncPrefs.map(function (pref) { return WEAVE_SYNC_PREFS + pref; }));
  108. },
  109. _isSynced: function _isSyncedPref(pref) {
  110. return (pref.indexOf(WEAVE_SYNC_PREFS) == 0)
  111. || this._prefs.get(WEAVE_SYNC_PREFS + pref, false);
  112. },
  113. _getAllPrefs: function () {
  114. let values = {};
  115. for each (let pref in this._getSyncPrefs()) {
  116. if (this._isSynced(pref)) {
  117. // Missing prefs get the null value.
  118. values[pref] = this._prefs.get(pref, null);
  119. }
  120. }
  121. return values;
  122. },
  123. _setAllPrefs: function PrefStore__setAllPrefs(values) {
  124. let enabledPref = "lightweightThemes.isThemeSelected";
  125. let enabledBefore = this._prefs.get(enabledPref, false);
  126. let prevTheme = LightweightThemeManager.currentTheme;
  127. for (let [pref, value] in Iterator(values)) {
  128. if (!this._isSynced(pref))
  129. continue;
  130. // Pref has gone missing, best we can do is reset it.
  131. if (value == null) {
  132. this._prefs.reset(pref);
  133. continue;
  134. }
  135. try {
  136. this._prefs.set(pref, value);
  137. } catch(ex) {
  138. this._log.trace("Failed to set pref: " + pref + ": " + ex);
  139. }
  140. }
  141. // Notify the lightweight theme manager of all the new values
  142. let enabledNow = this._prefs.get(enabledPref, false);
  143. if (enabledBefore && !enabledNow) {
  144. LightweightThemeManager.currentTheme = null;
  145. } else if (enabledNow && LightweightThemeManager.usedThemes[0] != prevTheme) {
  146. LightweightThemeManager.currentTheme = null;
  147. LightweightThemeManager.currentTheme = LightweightThemeManager.usedThemes[0];
  148. }
  149. },
  150. getAllIDs: function PrefStore_getAllIDs() {
  151. /* We store all prefs in just one WBO, with just one GUID */
  152. let allprefs = {};
  153. allprefs[PREFS_GUID] = true;
  154. return allprefs;
  155. },
  156. changeItemID: function PrefStore_changeItemID(oldID, newID) {
  157. this._log.trace("PrefStore GUID is constant!");
  158. },
  159. itemExists: function FormStore_itemExists(id) {
  160. return (id === PREFS_GUID);
  161. },
  162. createRecord: function createRecord(id, collection) {
  163. let record = new PrefRec(collection, id);
  164. if (id == PREFS_GUID) {
  165. record.value = this._getAllPrefs();
  166. } else {
  167. record.deleted = true;
  168. }
  169. return record;
  170. },
  171. create: function PrefStore_create(record) {
  172. this._log.trace("Ignoring create request");
  173. },
  174. remove: function PrefStore_remove(record) {
  175. this._log.trace("Ignoring remove request");
  176. },
  177. update: function PrefStore_update(record) {
  178. // Silently ignore pref updates that are for other apps.
  179. if (record.id != PREFS_GUID)
  180. return;
  181. this._log.trace("Received pref updates, applying...");
  182. this._setAllPrefs(record.value);
  183. },
  184. wipe: function PrefStore_wipe() {
  185. this._log.trace("Ignoring wipe request");
  186. }
  187. };
  188. function PrefTracker(name) {
  189. Tracker.call(this, name);
  190. Svc.Obs.add("profile-before-change", this);
  191. Svc.Obs.add("weave:engine:start-tracking", this);
  192. Svc.Obs.add("weave:engine:stop-tracking", this);
  193. }
  194. PrefTracker.prototype = {
  195. __proto__: Tracker.prototype,
  196. get modified() {
  197. return Svc.Prefs.get("engine.prefs.modified", false);
  198. },
  199. set modified(value) {
  200. Svc.Prefs.set("engine.prefs.modified", value);
  201. },
  202. loadChangedIDs: function loadChangedIDs() {
  203. // Don't read changed IDs from disk at start up.
  204. },
  205. clearChangedIDs: function clearChangedIDs() {
  206. this.modified = false;
  207. },
  208. __prefs: null,
  209. get _prefs() {
  210. if (!this.__prefs)
  211. this.__prefs = new Preferences();
  212. return this.__prefs;
  213. },
  214. _enabled: false,
  215. observe: function(aSubject, aTopic, aData) {
  216. switch (aTopic) {
  217. case "weave:engine:start-tracking":
  218. if (!this._enabled) {
  219. Cc["@mozilla.org/preferences-service;1"]
  220. .getService(Ci.nsIPrefBranch).addObserver("", this, false);
  221. this._enabled = true;
  222. }
  223. break;
  224. case "weave:engine:stop-tracking":
  225. if (this._enabled)
  226. this._enabled = false;
  227. // Fall through to clean up.
  228. case "profile-before-change":
  229. this.__prefs = null;
  230. Cc["@mozilla.org/preferences-service;1"]
  231. .getService(Ci.nsIPrefBranch).removeObserver("", this);
  232. break;
  233. case "nsPref:changed":
  234. // Trigger a sync for MULTI-DEVICE for a change that determines
  235. // which prefs are synced or a regular pref change.
  236. if (aData.indexOf(WEAVE_SYNC_PREFS) == 0 ||
  237. this._prefs.get(WEAVE_SYNC_PREFS + aData, false)) {
  238. this.score += SCORE_INCREMENT_XLARGE;
  239. this.modified = true;
  240. this._log.trace("Preference " + aData + " changed");
  241. }
  242. break;
  243. }
  244. }
  245. };