2012-05-21 15:12:37 +04:00
|
|
|
/* 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/. */
|
2007-06-19 22:51:09 +04:00
|
|
|
|
|
|
|
const Ci = Components.interfaces;
|
|
|
|
const Cc = Components.classes;
|
|
|
|
const Cr = Components.results;
|
|
|
|
const Cu = Components.utils;
|
|
|
|
|
2010-12-28 23:45:04 +03:00
|
|
|
const CACHE_MAX_GROUP_ENTRIES = 100;
|
|
|
|
|
2013-08-01 23:27:30 +04:00
|
|
|
|
|
|
|
// We have a whitelist for getting/setting. This is because
|
|
|
|
// there are potential privacy issues with a compromised
|
|
|
|
// content process checking the user's content preferences
|
|
|
|
// and using that to discover all the websites visited, etc.
|
|
|
|
// Also there are both potential race conditions (if two processes
|
|
|
|
// set more than one value in succession, and the values
|
|
|
|
// only make sense together), as well as security issues, if
|
|
|
|
// a compromised content process can send arbitrary setPref
|
|
|
|
// messages. The whitelist contains only those settings that
|
|
|
|
// are not at risk for either.
|
|
|
|
// We currently whitelist saving/reading the last directory of file
|
|
|
|
// uploads, and the last current spellchecker dictionary which are so far
|
|
|
|
// the only need we have identified.
|
|
|
|
const REMOTE_WHITELIST = [
|
|
|
|
"browser.upload.lastDir",
|
|
|
|
"spellcheck.lang",
|
|
|
|
];
|
|
|
|
|
2007-11-13 09:36:18 +03:00
|
|
|
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
2007-07-11 23:04:04 +04:00
|
|
|
|
2010-09-07 23:16:43 +04:00
|
|
|
/**
|
|
|
|
* Remotes the service. All the remoting/electrolysis code is in here,
|
|
|
|
* so the regular service code below remains uncluttered and maintainable.
|
|
|
|
*/
|
|
|
|
function electrolify(service) {
|
|
|
|
// FIXME: For now, use the wrappedJSObject hack, until bug
|
|
|
|
// 593407 which will clean that up.
|
|
|
|
// Note that we also use this in the xpcshell tests, separately.
|
|
|
|
service.wrappedJSObject = service;
|
|
|
|
|
|
|
|
var appInfo = Cc["@mozilla.org/xre/app-info;1"];
|
2013-08-01 23:27:30 +04:00
|
|
|
if (!appInfo || appInfo.getService(Ci.nsIXULRuntime).processType ==
|
|
|
|
Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT) {
|
|
|
|
// Parent process
|
|
|
|
|
|
|
|
service.messageManager = Cc["@mozilla.org/parentprocessmessagemanager;1"].
|
|
|
|
getService(Ci.nsIMessageBroadcaster);
|
|
|
|
|
|
|
|
// Setup listener for child messages. We don't need to call
|
|
|
|
// addMessageListener as the wakeup service will do that for us.
|
|
|
|
service.receiveMessage = function(aMessage) {
|
|
|
|
var json = aMessage.json;
|
|
|
|
|
|
|
|
if (REMOTE_WHITELIST.indexOf(json.name) == -1)
|
|
|
|
return { succeeded: false };
|
|
|
|
|
|
|
|
switch (aMessage.name) {
|
|
|
|
case "ContentPref:getPref":
|
|
|
|
return { succeeded: true,
|
|
|
|
value: service.getPref(json.group, json.name, json.value) };
|
|
|
|
|
|
|
|
case "ContentPref:setPref":
|
|
|
|
service.setPref(json.group, json.name, json.value);
|
|
|
|
return { succeeded: true };
|
|
|
|
}
|
|
|
|
};
|
|
|
|
} else {
|
2010-09-07 23:16:43 +04:00
|
|
|
// Child process
|
2013-08-01 23:27:30 +04:00
|
|
|
|
2010-09-07 23:16:43 +04:00
|
|
|
service._dbInit = function(){}; // No local DB
|
2013-08-01 23:27:30 +04:00
|
|
|
|
|
|
|
service.messageManager = Cc["@mozilla.org/childprocessmessagemanager;1"].
|
|
|
|
getService(Ci.nsISyncMessageSender);
|
|
|
|
|
|
|
|
// Child method remoting
|
|
|
|
[
|
|
|
|
['getPref', ['group', 'name'], ['_parseGroupParam']],
|
|
|
|
['setPref', ['group', 'name', 'value'], ['_parseGroupParam']],
|
|
|
|
].forEach(function(data) {
|
|
|
|
var method = data[0];
|
|
|
|
var params = data[1];
|
|
|
|
var parsers = data[2];
|
|
|
|
service[method] = function __remoted__() {
|
|
|
|
var json = {};
|
|
|
|
for (var i = 0; i < params.length; i++) {
|
|
|
|
if (params[i]) {
|
|
|
|
json[params[i]] = arguments[i];
|
|
|
|
if (parsers[i])
|
|
|
|
json[params[i]] = this[parsers[i]](json[params[i]]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
var ret = service.messageManager.sendSyncMessage('ContentPref:' + method, json)[0];
|
|
|
|
if (!ret.succeeded)
|
|
|
|
throw "ContentPrefs remoting failed to pass whitelist";
|
|
|
|
return ret.value;
|
|
|
|
};
|
|
|
|
});
|
|
|
|
|
|
|
|
// Listen to preference change notifications from the parent and notify
|
|
|
|
// observers in the child process according to the change
|
|
|
|
service.messageManager.addMessageListener("ContentPref:notifyPrefSet",
|
|
|
|
function(aMessage) {
|
|
|
|
var json = aMessage.json;
|
|
|
|
service._notifyPrefSet(json.group, json.name, json.value);
|
|
|
|
});
|
|
|
|
service.messageManager.addMessageListener("ContentPref:notifyPrefRemoved",
|
|
|
|
function(aMessage) {
|
|
|
|
var json = aMessage.json;
|
|
|
|
service._notifyPrefRemoved(json.group, json.name);
|
|
|
|
});
|
2010-09-07 23:16:43 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-07-11 23:04:04 +04:00
|
|
|
function ContentPrefService() {
|
2010-09-07 23:16:43 +04:00
|
|
|
electrolify(this);
|
|
|
|
|
2007-11-13 09:36:18 +03:00
|
|
|
// If this throws an exception, it causes the getService call to fail,
|
|
|
|
// but the next time a consumer tries to retrieve the service, we'll try
|
|
|
|
// to initialize the database again, which might work if the failure
|
|
|
|
// was due to a temporary condition (like being out of disk space).
|
|
|
|
this._dbInit();
|
|
|
|
|
2012-06-30 18:50:07 +04:00
|
|
|
this._observerSvc.addObserver(this, "last-pb-context-exited", false);
|
bug 679784: let nsIContentPrefService handle private browsing mode; r=ehsan
Manage private browsing mode in content pref service. CPS should be available
in private browsing mode, but should not store informations on disk, and should
clear all informations once the private session ends.
When setting a pref in private mode, it is stored in an in-memory hash table.
When getting a pref, it is retrieved from that hash table if available.
Otherwise, it is retrieved using the standard mechanism. When removing a pref,
it is retrieved from the hash table. The rationale is that in private mode,
it's ok to read a pref from normal database, but not ok to set it.
The in-memory hash table is cleared when leaving the private browsing mode.
When removing a set of preferences (with removeGroupedPrefs or
removePrefsByName), preferences are removed from the in-memory hashtable, *and*
from normal mode database. The rationale is that visiting a website may trigger
setting/getting/removing for a specific preference only. But removing many
prefs at once is the result of an action not associated with a website. For
example, user may wish to delete all its informations. In that case, user
probably expects to not have those informations restored once it leaves private
browsing mode.
2011-09-01 22:13:03 +04:00
|
|
|
|
2007-11-13 09:36:18 +03:00
|
|
|
// Observe shutdown so we can shut down the database connection.
|
|
|
|
this._observerSvc.addObserver(this, "xpcom-shutdown", false);
|
2007-07-11 23:04:04 +04:00
|
|
|
}
|
2007-06-19 22:51:09 +04:00
|
|
|
|
2012-12-21 05:37:56 +04:00
|
|
|
Cu.import("resource://gre/modules/ContentPrefStore.jsm");
|
|
|
|
const cache = new ContentPrefStore();
|
|
|
|
cache.set = function CPS_cache_set(group, name, val) {
|
|
|
|
Object.getPrototypeOf(this).set.apply(this, arguments);
|
|
|
|
let groupCount = Object.keys(this._groups).length;
|
|
|
|
if (groupCount >= CACHE_MAX_GROUP_ENTRIES) {
|
|
|
|
// Clean half of the entries
|
|
|
|
for (let [group, name, ] in this) {
|
|
|
|
this.remove(group, name);
|
|
|
|
groupCount--;
|
|
|
|
if (groupCount < CACHE_MAX_GROUP_ENTRIES / 2)
|
|
|
|
break;
|
bug 679784: let nsIContentPrefService handle private browsing mode; r=ehsan
Manage private browsing mode in content pref service. CPS should be available
in private browsing mode, but should not store informations on disk, and should
clear all informations once the private session ends.
When setting a pref in private mode, it is stored in an in-memory hash table.
When getting a pref, it is retrieved from that hash table if available.
Otherwise, it is retrieved using the standard mechanism. When removing a pref,
it is retrieved from the hash table. The rationale is that in private mode,
it's ok to read a pref from normal database, but not ok to set it.
The in-memory hash table is cleared when leaving the private browsing mode.
When removing a set of preferences (with removeGroupedPrefs or
removePrefsByName), preferences are removed from the in-memory hashtable, *and*
from normal mode database. The rationale is that visiting a website may trigger
setting/getting/removing for a specific preference only. But removing many
prefs at once is the result of an action not associated with a website. For
example, user may wish to delete all its informations. In that case, user
probably expects to not have those informations restored once it leaves private
browsing mode.
2011-09-01 22:13:03 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2012-12-21 05:37:56 +04:00
|
|
|
const privModeStorage = new ContentPrefStore();
|
|
|
|
|
2007-06-19 22:51:09 +04:00
|
|
|
ContentPrefService.prototype = {
|
2007-07-11 23:04:04 +04:00
|
|
|
//**************************************************************************//
|
|
|
|
// XPCOM Plumbing
|
|
|
|
|
2012-12-21 05:37:56 +04:00
|
|
|
classID: Components.ID("{e3f772f3-023f-4b32-b074-36cf0fd5d414}"),
|
|
|
|
|
|
|
|
QueryInterface: function CPS_QueryInterface(iid) {
|
|
|
|
let supportedIIDs = [
|
|
|
|
Ci.nsIContentPrefService,
|
|
|
|
Ci.nsIFrameMessageListener,
|
|
|
|
Ci.nsISupports,
|
|
|
|
];
|
|
|
|
if (supportedIIDs.some(function (i) iid.equals(i)))
|
|
|
|
return this;
|
|
|
|
if (iid.equals(Ci.nsIContentPrefService2)) {
|
|
|
|
if (!this._contentPrefService2) {
|
|
|
|
let s = {};
|
|
|
|
Cu.import("resource://gre/modules/ContentPrefService2.jsm", s);
|
|
|
|
this._contentPrefService2 = new s.ContentPrefService2(this);
|
|
|
|
}
|
|
|
|
return this._contentPrefService2;
|
|
|
|
}
|
|
|
|
throw Cr.NS_ERROR_NO_INTERFACE;
|
|
|
|
},
|
2007-07-11 23:04:04 +04:00
|
|
|
|
2007-06-19 22:51:09 +04:00
|
|
|
//**************************************************************************//
|
|
|
|
// Convenience Getters
|
|
|
|
|
|
|
|
// Observer Service
|
|
|
|
__observerSvc: null,
|
2010-04-17 14:19:33 +04:00
|
|
|
get _observerSvc() {
|
2007-06-19 22:51:09 +04:00
|
|
|
if (!this.__observerSvc)
|
|
|
|
this.__observerSvc = Cc["@mozilla.org/observer-service;1"].
|
|
|
|
getService(Ci.nsIObserverService);
|
|
|
|
return this.__observerSvc;
|
|
|
|
},
|
|
|
|
|
|
|
|
// Console Service
|
|
|
|
__consoleSvc: null,
|
2010-04-17 14:19:33 +04:00
|
|
|
get _consoleSvc() {
|
2007-06-19 22:51:09 +04:00
|
|
|
if (!this.__consoleSvc)
|
|
|
|
this.__consoleSvc = Cc["@mozilla.org/consoleservice;1"].
|
|
|
|
getService(Ci.nsIConsoleService);
|
|
|
|
return this.__consoleSvc;
|
|
|
|
},
|
|
|
|
|
2008-05-26 05:05:00 +04:00
|
|
|
// Preferences Service
|
|
|
|
__prefSvc: null,
|
2010-04-17 14:19:33 +04:00
|
|
|
get _prefSvc() {
|
2008-05-26 05:05:00 +04:00
|
|
|
if (!this.__prefSvc)
|
|
|
|
this.__prefSvc = Cc["@mozilla.org/preferences-service;1"].
|
2012-01-17 05:18:29 +04:00
|
|
|
getService(Ci.nsIPrefBranch);
|
2008-05-26 05:05:00 +04:00
|
|
|
return this.__prefSvc;
|
|
|
|
},
|
|
|
|
|
2007-06-19 22:51:09 +04:00
|
|
|
|
|
|
|
//**************************************************************************//
|
2007-11-13 09:36:18 +03:00
|
|
|
// Destruction
|
2007-06-19 22:51:09 +04:00
|
|
|
|
|
|
|
_destroy: function ContentPrefService__destroy() {
|
|
|
|
this._observerSvc.removeObserver(this, "xpcom-shutdown");
|
2012-06-30 18:50:07 +04:00
|
|
|
this._observerSvc.removeObserver(this, "last-pb-context-exited");
|
2007-06-19 22:51:09 +04:00
|
|
|
|
2010-02-23 20:19:36 +03:00
|
|
|
// Finalize statements which may have been used asynchronously.
|
2011-10-28 18:55:20 +04:00
|
|
|
// FIXME(696499): put them in an object cache like other components.
|
|
|
|
if (this.__stmtSelectPrefID) {
|
|
|
|
this.__stmtSelectPrefID.finalize();
|
|
|
|
this.__stmtSelectPrefID = null;
|
|
|
|
}
|
|
|
|
if (this.__stmtSelectGlobalPrefID) {
|
|
|
|
this.__stmtSelectGlobalPrefID.finalize();
|
|
|
|
this.__stmtSelectGlobalPrefID = null;
|
|
|
|
}
|
|
|
|
if (this.__stmtInsertPref) {
|
|
|
|
this.__stmtInsertPref.finalize();
|
|
|
|
this.__stmtInsertPref = null;
|
|
|
|
}
|
|
|
|
if (this.__stmtInsertGroup) {
|
|
|
|
this.__stmtInsertGroup.finalize();
|
|
|
|
this.__stmtInsertGroup = null;
|
|
|
|
}
|
|
|
|
if (this.__stmtInsertSetting) {
|
|
|
|
this.__stmtInsertSetting.finalize();
|
|
|
|
this.__stmtInsertSetting = null;
|
|
|
|
}
|
|
|
|
if (this.__stmtSelectGroupID) {
|
|
|
|
this.__stmtSelectGroupID.finalize();
|
|
|
|
this.__stmtSelectGroupID = null;
|
|
|
|
}
|
|
|
|
if (this.__stmtSelectSettingID) {
|
|
|
|
this.__stmtSelectSettingID.finalize();
|
|
|
|
this.__stmtSelectSettingID = null;
|
|
|
|
}
|
|
|
|
if (this.__stmtSelectPref) {
|
2010-02-23 20:19:36 +03:00
|
|
|
this.__stmtSelectPref.finalize();
|
2011-10-28 18:55:20 +04:00
|
|
|
this.__stmtSelectPref = null;
|
|
|
|
}
|
|
|
|
if (this.__stmtSelectGlobalPref) {
|
2010-02-23 20:19:36 +03:00
|
|
|
this.__stmtSelectGlobalPref.finalize();
|
2011-10-28 18:55:20 +04:00
|
|
|
this.__stmtSelectGlobalPref = null;
|
|
|
|
}
|
|
|
|
if (this.__stmtSelectPrefsByName) {
|
|
|
|
this.__stmtSelectPrefsByName.finalize();
|
|
|
|
this.__stmtSelectPrefsByName = null;
|
|
|
|
}
|
|
|
|
if (this.__stmtDeleteSettingIfUnused) {
|
|
|
|
this.__stmtDeleteSettingIfUnused.finalize();
|
|
|
|
this.__stmtDeleteSettingIfUnused = null;
|
|
|
|
}
|
|
|
|
if(this.__stmtSelectPrefs) {
|
|
|
|
this.__stmtSelectPrefs.finalize();
|
|
|
|
this.__stmtSelectPrefs = null;
|
|
|
|
}
|
|
|
|
if(this.__stmtDeleteGroupIfUnused) {
|
|
|
|
this.__stmtDeleteGroupIfUnused.finalize();
|
|
|
|
this.__stmtDeleteGroupIfUnused = null;
|
|
|
|
}
|
|
|
|
if (this.__stmtDeletePref) {
|
|
|
|
this.__stmtDeletePref.finalize();
|
|
|
|
this.__stmtDeletePref = null;
|
|
|
|
}
|
|
|
|
if (this.__stmtUpdatePref) {
|
|
|
|
this.__stmtUpdatePref.finalize();
|
|
|
|
this.__stmtUpdatePref = null;
|
|
|
|
}
|
2010-02-23 20:19:36 +03:00
|
|
|
|
2012-12-21 05:37:56 +04:00
|
|
|
if (this._contentPrefService2)
|
|
|
|
this._contentPrefService2.destroy();
|
|
|
|
|
2011-12-19 22:10:18 +04:00
|
|
|
this._dbConnection.asyncClose();
|
|
|
|
|
2007-06-21 22:52:35 +04:00
|
|
|
// Delete references to XPCOM components to make sure we don't leak them
|
2007-06-22 01:19:15 +04:00
|
|
|
// (although we haven't observed leakage in tests). Also delete references
|
|
|
|
// in _observers and _genericObservers to avoid cycles with those that
|
|
|
|
// refer to us and don't remove themselves from those observer pools.
|
|
|
|
for (var i in this) {
|
|
|
|
try { this[i] = null }
|
|
|
|
// Ignore "setting a property that has only a getter" exceptions.
|
|
|
|
catch(ex) {}
|
|
|
|
}
|
2007-06-19 22:51:09 +04:00
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
//**************************************************************************//
|
|
|
|
// nsIObserver
|
|
|
|
|
|
|
|
observe: function ContentPrefService_observe(subject, topic, data) {
|
|
|
|
switch (topic) {
|
2007-06-26 01:19:40 +04:00
|
|
|
case "xpcom-shutdown":
|
|
|
|
this._destroy();
|
|
|
|
break;
|
2012-06-30 18:50:07 +04:00
|
|
|
case "last-pb-context-exited":
|
2012-12-21 05:37:56 +04:00
|
|
|
this._privModeStorage.removeAll();
|
bug 679784: let nsIContentPrefService handle private browsing mode; r=ehsan
Manage private browsing mode in content pref service. CPS should be available
in private browsing mode, but should not store informations on disk, and should
clear all informations once the private session ends.
When setting a pref in private mode, it is stored in an in-memory hash table.
When getting a pref, it is retrieved from that hash table if available.
Otherwise, it is retrieved using the standard mechanism. When removing a pref,
it is retrieved from the hash table. The rationale is that in private mode,
it's ok to read a pref from normal database, but not ok to set it.
The in-memory hash table is cleared when leaving the private browsing mode.
When removing a set of preferences (with removeGroupedPrefs or
removePrefsByName), preferences are removed from the in-memory hashtable, *and*
from normal mode database. The rationale is that visiting a website may trigger
setting/getting/removing for a specific preference only. But removing many
prefs at once is the result of an action not associated with a website. For
example, user may wish to delete all its informations. In that case, user
probably expects to not have those informations restored once it leaves private
browsing mode.
2011-09-01 22:13:03 +04:00
|
|
|
break;
|
2007-06-19 22:51:09 +04:00
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
|
2010-12-28 23:45:04 +03:00
|
|
|
//**************************************************************************//
|
2012-12-21 05:37:56 +04:00
|
|
|
// in-memory cache and private-browsing stores
|
bug 679784: let nsIContentPrefService handle private browsing mode; r=ehsan
Manage private browsing mode in content pref service. CPS should be available
in private browsing mode, but should not store informations on disk, and should
clear all informations once the private session ends.
When setting a pref in private mode, it is stored in an in-memory hash table.
When getting a pref, it is retrieved from that hash table if available.
Otherwise, it is retrieved using the standard mechanism. When removing a pref,
it is retrieved from the hash table. The rationale is that in private mode,
it's ok to read a pref from normal database, but not ok to set it.
The in-memory hash table is cleared when leaving the private browsing mode.
When removing a set of preferences (with removeGroupedPrefs or
removePrefsByName), preferences are removed from the in-memory hashtable, *and*
from normal mode database. The rationale is that visiting a website may trigger
setting/getting/removing for a specific preference only. But removing many
prefs at once is the result of an action not associated with a website. For
example, user may wish to delete all its informations. In that case, user
probably expects to not have those informations restored once it leaves private
browsing mode.
2011-09-01 22:13:03 +04:00
|
|
|
|
2012-12-21 05:37:56 +04:00
|
|
|
_cache: cache,
|
|
|
|
_privModeStorage: privModeStorage,
|
2010-12-28 23:45:04 +03:00
|
|
|
|
2007-06-19 22:51:09 +04:00
|
|
|
//**************************************************************************//
|
|
|
|
// nsIContentPrefService
|
|
|
|
|
2012-06-30 18:50:07 +04:00
|
|
|
getPref: function ContentPrefService_getPref(aGroup, aName, aContext, aCallback) {
|
2009-08-24 21:12:04 +04:00
|
|
|
if (!aName)
|
|
|
|
throw Components.Exception("aName cannot be null or an empty string",
|
|
|
|
Cr.NS_ERROR_ILLEGAL_VALUE);
|
|
|
|
|
2010-09-07 23:16:43 +04:00
|
|
|
var group = this._parseGroupParam(aGroup);
|
bug 679784: let nsIContentPrefService handle private browsing mode; r=ehsan
Manage private browsing mode in content pref service. CPS should be available
in private browsing mode, but should not store informations on disk, and should
clear all informations once the private session ends.
When setting a pref in private mode, it is stored in an in-memory hash table.
When getting a pref, it is retrieved from that hash table if available.
Otherwise, it is retrieved using the standard mechanism. When removing a pref,
it is retrieved from the hash table. The rationale is that in private mode,
it's ok to read a pref from normal database, but not ok to set it.
The in-memory hash table is cleared when leaving the private browsing mode.
When removing a set of preferences (with removeGroupedPrefs or
removePrefsByName), preferences are removed from the in-memory hashtable, *and*
from normal mode database. The rationale is that visiting a website may trigger
setting/getting/removing for a specific preference only. But removing many
prefs at once is the result of an action not associated with a website. For
example, user may wish to delete all its informations. In that case, user
probably expects to not have those informations restored once it leaves private
browsing mode.
2011-09-01 22:13:03 +04:00
|
|
|
|
2012-06-30 18:50:07 +04:00
|
|
|
if (aContext && aContext.usePrivateBrowsing) {
|
2012-12-21 05:37:56 +04:00
|
|
|
if (this._privModeStorage.has(group, aName)) {
|
|
|
|
let value = this._privModeStorage.get(group, aName);
|
bug 679784: let nsIContentPrefService handle private browsing mode; r=ehsan
Manage private browsing mode in content pref service. CPS should be available
in private browsing mode, but should not store informations on disk, and should
clear all informations once the private session ends.
When setting a pref in private mode, it is stored in an in-memory hash table.
When getting a pref, it is retrieved from that hash table if available.
Otherwise, it is retrieved using the standard mechanism. When removing a pref,
it is retrieved from the hash table. The rationale is that in private mode,
it's ok to read a pref from normal database, but not ok to set it.
The in-memory hash table is cleared when leaving the private browsing mode.
When removing a set of preferences (with removeGroupedPrefs or
removePrefsByName), preferences are removed from the in-memory hashtable, *and*
from normal mode database. The rationale is that visiting a website may trigger
setting/getting/removing for a specific preference only. But removing many
prefs at once is the result of an action not associated with a website. For
example, user may wish to delete all its informations. In that case, user
probably expects to not have those informations restored once it leaves private
browsing mode.
2011-09-01 22:13:03 +04:00
|
|
|
if (aCallback) {
|
|
|
|
this._scheduleCallback(function(){aCallback.onResult(value);});
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
// if we don't have a pref specific to this private mode browsing
|
|
|
|
// session, to try to get one from normal mode
|
|
|
|
}
|
|
|
|
|
2010-09-07 23:16:43 +04:00
|
|
|
if (group == null)
|
2010-02-09 13:28:39 +03:00
|
|
|
return this._selectGlobalPref(aName, aCallback);
|
2010-09-07 23:16:43 +04:00
|
|
|
return this._selectPref(group, aName, aCallback);
|
2007-06-19 22:51:09 +04:00
|
|
|
},
|
|
|
|
|
2012-06-30 18:50:07 +04:00
|
|
|
setPref: function ContentPrefService_setPref(aGroup, aName, aValue, aContext) {
|
2007-06-19 22:51:09 +04:00
|
|
|
// If the pref is already set to the value, there's nothing more to do.
|
2012-06-30 18:50:07 +04:00
|
|
|
var currentValue = this.getPref(aGroup, aName, aContext);
|
2008-10-20 01:16:22 +04:00
|
|
|
if (typeof currentValue != "undefined") {
|
|
|
|
if (currentValue == aValue)
|
|
|
|
return;
|
|
|
|
}
|
bug 679784: let nsIContentPrefService handle private browsing mode; r=ehsan
Manage private browsing mode in content pref service. CPS should be available
in private browsing mode, but should not store informations on disk, and should
clear all informations once the private session ends.
When setting a pref in private mode, it is stored in an in-memory hash table.
When getting a pref, it is retrieved from that hash table if available.
Otherwise, it is retrieved using the standard mechanism. When removing a pref,
it is retrieved from the hash table. The rationale is that in private mode,
it's ok to read a pref from normal database, but not ok to set it.
The in-memory hash table is cleared when leaving the private browsing mode.
When removing a set of preferences (with removeGroupedPrefs or
removePrefsByName), preferences are removed from the in-memory hashtable, *and*
from normal mode database. The rationale is that visiting a website may trigger
setting/getting/removing for a specific preference only. But removing many
prefs at once is the result of an action not associated with a website. For
example, user may wish to delete all its informations. In that case, user
probably expects to not have those informations restored once it leaves private
browsing mode.
2011-09-01 22:13:03 +04:00
|
|
|
|
|
|
|
var group = this._parseGroupParam(aGroup);
|
|
|
|
|
2012-06-30 18:50:07 +04:00
|
|
|
if (aContext && aContext.usePrivateBrowsing) {
|
2012-12-21 05:37:56 +04:00
|
|
|
this._privModeStorage.setWithCast(group, aName, aValue);
|
2013-08-01 23:27:30 +04:00
|
|
|
this._broadcastPrefSet(group, aName, aValue);
|
bug 679784: let nsIContentPrefService handle private browsing mode; r=ehsan
Manage private browsing mode in content pref service. CPS should be available
in private browsing mode, but should not store informations on disk, and should
clear all informations once the private session ends.
When setting a pref in private mode, it is stored in an in-memory hash table.
When getting a pref, it is retrieved from that hash table if available.
Otherwise, it is retrieved using the standard mechanism. When removing a pref,
it is retrieved from the hash table. The rationale is that in private mode,
it's ok to read a pref from normal database, but not ok to set it.
The in-memory hash table is cleared when leaving the private browsing mode.
When removing a set of preferences (with removeGroupedPrefs or
removePrefsByName), preferences are removed from the in-memory hashtable, *and*
from normal mode database. The rationale is that visiting a website may trigger
setting/getting/removing for a specific preference only. But removing many
prefs at once is the result of an action not associated with a website. For
example, user may wish to delete all its informations. In that case, user
probably expects to not have those informations restored once it leaves private
browsing mode.
2011-09-01 22:13:03 +04:00
|
|
|
return;
|
2008-10-20 01:16:22 +04:00
|
|
|
}
|
2007-06-19 22:51:09 +04:00
|
|
|
|
|
|
|
var settingID = this._selectSettingID(aName) || this._insertSetting(aName);
|
2010-09-07 23:16:43 +04:00
|
|
|
var groupID, prefID;
|
|
|
|
if (group == null) {
|
2009-09-05 06:22:19 +04:00
|
|
|
groupID = null;
|
|
|
|
prefID = this._selectGlobalPrefID(settingID);
|
|
|
|
}
|
2010-09-07 23:16:43 +04:00
|
|
|
else {
|
2007-06-19 22:51:09 +04:00
|
|
|
groupID = this._selectGroupID(group) || this._insertGroup(group);
|
|
|
|
prefID = this._selectPrefID(groupID, settingID);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Update the existing record, if any, or create a new one.
|
|
|
|
if (prefID)
|
|
|
|
this._updatePref(prefID, aValue);
|
|
|
|
else
|
|
|
|
this._insertPref(groupID, settingID, aValue);
|
|
|
|
|
2012-12-21 05:37:56 +04:00
|
|
|
this._cache.setWithCast(group, aName, aValue);
|
2013-08-01 23:27:30 +04:00
|
|
|
this._broadcastPrefSet(group, aName, aValue);
|
2007-06-19 22:51:09 +04:00
|
|
|
},
|
|
|
|
|
2012-06-30 18:50:07 +04:00
|
|
|
hasPref: function ContentPrefService_hasPref(aGroup, aName, aContext) {
|
2007-06-19 22:51:09 +04:00
|
|
|
// XXX If consumers end up calling this method regularly, then we should
|
|
|
|
// optimize this to query the database directly.
|
2012-06-30 18:50:07 +04:00
|
|
|
return (typeof this.getPref(aGroup, aName, aContext) != "undefined");
|
2007-06-19 22:51:09 +04:00
|
|
|
},
|
|
|
|
|
2012-06-30 18:50:07 +04:00
|
|
|
hasCachedPref: function ContentPrefService_hasCachedPref(aGroup, aName, aContext) {
|
2010-12-28 23:45:04 +03:00
|
|
|
if (!aName)
|
|
|
|
throw Components.Exception("aName cannot be null or an empty string",
|
|
|
|
Cr.NS_ERROR_ILLEGAL_VALUE);
|
|
|
|
|
|
|
|
let group = this._parseGroupParam(aGroup);
|
2012-06-30 18:50:07 +04:00
|
|
|
let storage = aContext && aContext.usePrivateBrowsing ? this._privModeStorage: this._cache;
|
2012-12-21 05:37:56 +04:00
|
|
|
return storage.has(group, aName);
|
2010-12-28 23:45:04 +03:00
|
|
|
},
|
|
|
|
|
2012-06-30 18:50:07 +04:00
|
|
|
removePref: function ContentPrefService_removePref(aGroup, aName, aContext) {
|
2007-06-19 22:51:09 +04:00
|
|
|
// If there's no old value, then there's nothing to remove.
|
2012-06-30 18:50:07 +04:00
|
|
|
if (!this.hasPref(aGroup, aName, aContext))
|
2007-06-19 22:51:09 +04:00
|
|
|
return;
|
|
|
|
|
bug 679784: let nsIContentPrefService handle private browsing mode; r=ehsan
Manage private browsing mode in content pref service. CPS should be available
in private browsing mode, but should not store informations on disk, and should
clear all informations once the private session ends.
When setting a pref in private mode, it is stored in an in-memory hash table.
When getting a pref, it is retrieved from that hash table if available.
Otherwise, it is retrieved using the standard mechanism. When removing a pref,
it is retrieved from the hash table. The rationale is that in private mode,
it's ok to read a pref from normal database, but not ok to set it.
The in-memory hash table is cleared when leaving the private browsing mode.
When removing a set of preferences (with removeGroupedPrefs or
removePrefsByName), preferences are removed from the in-memory hashtable, *and*
from normal mode database. The rationale is that visiting a website may trigger
setting/getting/removing for a specific preference only. But removing many
prefs at once is the result of an action not associated with a website. For
example, user may wish to delete all its informations. In that case, user
probably expects to not have those informations restored once it leaves private
browsing mode.
2011-09-01 22:13:03 +04:00
|
|
|
var group = this._parseGroupParam(aGroup);
|
|
|
|
|
2012-06-30 18:50:07 +04:00
|
|
|
if (aContext && aContext.usePrivateBrowsing) {
|
2012-12-21 05:37:56 +04:00
|
|
|
this._privModeStorage.remove(group, aName);
|
2013-08-01 23:27:30 +04:00
|
|
|
this._broadcastPrefRemoved(group, aName);
|
bug 679784: let nsIContentPrefService handle private browsing mode; r=ehsan
Manage private browsing mode in content pref service. CPS should be available
in private browsing mode, but should not store informations on disk, and should
clear all informations once the private session ends.
When setting a pref in private mode, it is stored in an in-memory hash table.
When getting a pref, it is retrieved from that hash table if available.
Otherwise, it is retrieved using the standard mechanism. When removing a pref,
it is retrieved from the hash table. The rationale is that in private mode,
it's ok to read a pref from normal database, but not ok to set it.
The in-memory hash table is cleared when leaving the private browsing mode.
When removing a set of preferences (with removeGroupedPrefs or
removePrefsByName), preferences are removed from the in-memory hashtable, *and*
from normal mode database. The rationale is that visiting a website may trigger
setting/getting/removing for a specific preference only. But removing many
prefs at once is the result of an action not associated with a website. For
example, user may wish to delete all its informations. In that case, user
probably expects to not have those informations restored once it leaves private
browsing mode.
2011-09-01 22:13:03 +04:00
|
|
|
return;
|
|
|
|
}
|
2010-09-07 23:16:43 +04:00
|
|
|
|
2007-06-19 22:51:09 +04:00
|
|
|
var settingID = this._selectSettingID(aName);
|
2010-09-07 23:16:43 +04:00
|
|
|
var groupID, prefID;
|
|
|
|
if (group == null) {
|
2009-09-05 06:22:19 +04:00
|
|
|
groupID = null;
|
|
|
|
prefID = this._selectGlobalPrefID(settingID);
|
|
|
|
}
|
2010-09-07 23:16:43 +04:00
|
|
|
else {
|
2010-09-04 09:56:49 +04:00
|
|
|
groupID = this._selectGroupID(group);
|
|
|
|
prefID = this._selectPrefID(groupID, settingID);
|
|
|
|
}
|
2007-06-19 22:51:09 +04:00
|
|
|
|
|
|
|
this._deletePref(prefID);
|
|
|
|
|
|
|
|
// Get rid of extraneous records that are no longer being used.
|
|
|
|
this._deleteSettingIfUnused(settingID);
|
|
|
|
if (groupID)
|
|
|
|
this._deleteGroupIfUnused(groupID);
|
|
|
|
|
2012-12-21 05:37:56 +04:00
|
|
|
this._cache.remove(group, aName);
|
2013-08-01 23:27:30 +04:00
|
|
|
this._broadcastPrefRemoved(group, aName);
|
2007-06-19 22:51:09 +04:00
|
|
|
},
|
|
|
|
|
2012-06-30 18:50:07 +04:00
|
|
|
removeGroupedPrefs: function ContentPrefService_removeGroupedPrefs(aContext) {
|
bug 679784: let nsIContentPrefService handle private browsing mode; r=ehsan
Manage private browsing mode in content pref service. CPS should be available
in private browsing mode, but should not store informations on disk, and should
clear all informations once the private session ends.
When setting a pref in private mode, it is stored in an in-memory hash table.
When getting a pref, it is retrieved from that hash table if available.
Otherwise, it is retrieved using the standard mechanism. When removing a pref,
it is retrieved from the hash table. The rationale is that in private mode,
it's ok to read a pref from normal database, but not ok to set it.
The in-memory hash table is cleared when leaving the private browsing mode.
When removing a set of preferences (with removeGroupedPrefs or
removePrefsByName), preferences are removed from the in-memory hashtable, *and*
from normal mode database. The rationale is that visiting a website may trigger
setting/getting/removing for a specific preference only. But removing many
prefs at once is the result of an action not associated with a website. For
example, user may wish to delete all its informations. In that case, user
probably expects to not have those informations restored once it leaves private
browsing mode.
2011-09-01 22:13:03 +04:00
|
|
|
// will not delete global preferences
|
2012-06-30 18:50:07 +04:00
|
|
|
if (aContext && aContext.usePrivateBrowsing) {
|
bug 679784: let nsIContentPrefService handle private browsing mode; r=ehsan
Manage private browsing mode in content pref service. CPS should be available
in private browsing mode, but should not store informations on disk, and should
clear all informations once the private session ends.
When setting a pref in private mode, it is stored in an in-memory hash table.
When getting a pref, it is retrieved from that hash table if available.
Otherwise, it is retrieved using the standard mechanism. When removing a pref,
it is retrieved from the hash table. The rationale is that in private mode,
it's ok to read a pref from normal database, but not ok to set it.
The in-memory hash table is cleared when leaving the private browsing mode.
When removing a set of preferences (with removeGroupedPrefs or
removePrefsByName), preferences are removed from the in-memory hashtable, *and*
from normal mode database. The rationale is that visiting a website may trigger
setting/getting/removing for a specific preference only. But removing many
prefs at once is the result of an action not associated with a website. For
example, user may wish to delete all its informations. In that case, user
probably expects to not have those informations restored once it leaves private
browsing mode.
2011-09-01 22:13:03 +04:00
|
|
|
// keep only global prefs
|
2013-06-06 04:05:36 +04:00
|
|
|
this._privModeStorage.removeAllGroups();
|
bug 679784: let nsIContentPrefService handle private browsing mode; r=ehsan
Manage private browsing mode in content pref service. CPS should be available
in private browsing mode, but should not store informations on disk, and should
clear all informations once the private session ends.
When setting a pref in private mode, it is stored in an in-memory hash table.
When getting a pref, it is retrieved from that hash table if available.
Otherwise, it is retrieved using the standard mechanism. When removing a pref,
it is retrieved from the hash table. The rationale is that in private mode,
it's ok to read a pref from normal database, but not ok to set it.
The in-memory hash table is cleared when leaving the private browsing mode.
When removing a set of preferences (with removeGroupedPrefs or
removePrefsByName), preferences are removed from the in-memory hashtable, *and*
from normal mode database. The rationale is that visiting a website may trigger
setting/getting/removing for a specific preference only. But removing many
prefs at once is the result of an action not associated with a website. For
example, user may wish to delete all its informations. In that case, user
probably expects to not have those informations restored once it leaves private
browsing mode.
2011-09-01 22:13:03 +04:00
|
|
|
}
|
2013-06-06 04:05:36 +04:00
|
|
|
this._cache.removeAllGroups();
|
2009-01-20 18:59:49 +03:00
|
|
|
this._dbConnection.beginTransaction();
|
|
|
|
try {
|
|
|
|
this._dbConnection.executeSimpleSQL("DELETE FROM prefs WHERE groupID IS NOT NULL");
|
|
|
|
this._dbConnection.executeSimpleSQL("DELETE FROM groups");
|
2010-01-06 02:38:06 +03:00
|
|
|
this._dbConnection.executeSimpleSQL(
|
|
|
|
"DELETE FROM settings " +
|
|
|
|
"WHERE id NOT IN (SELECT DISTINCT settingID FROM prefs)"
|
|
|
|
);
|
2009-01-20 18:59:49 +03:00
|
|
|
this._dbConnection.commitTransaction();
|
|
|
|
}
|
|
|
|
catch(ex) {
|
|
|
|
this._dbConnection.rollbackTransaction();
|
|
|
|
throw ex;
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2012-06-30 18:50:07 +04:00
|
|
|
removePrefsByName: function ContentPrefService_removePrefsByName(aName, aContext) {
|
2009-08-24 21:12:04 +04:00
|
|
|
if (!aName)
|
|
|
|
throw Components.Exception("aName cannot be null or an empty string",
|
|
|
|
Cr.NS_ERROR_ILLEGAL_VALUE);
|
|
|
|
|
2012-06-30 18:50:07 +04:00
|
|
|
if (aContext && aContext.usePrivateBrowsing) {
|
2012-12-21 05:37:56 +04:00
|
|
|
for (let [group, name, ] in this._privModeStorage) {
|
|
|
|
if (name === aName) {
|
|
|
|
this._privModeStorage.remove(group, aName);
|
2013-08-01 23:27:30 +04:00
|
|
|
this._broadcastPrefRemoved(group, aName);
|
2012-12-21 05:37:56 +04:00
|
|
|
}
|
bug 679784: let nsIContentPrefService handle private browsing mode; r=ehsan
Manage private browsing mode in content pref service. CPS should be available
in private browsing mode, but should not store informations on disk, and should
clear all informations once the private session ends.
When setting a pref in private mode, it is stored in an in-memory hash table.
When getting a pref, it is retrieved from that hash table if available.
Otherwise, it is retrieved using the standard mechanism. When removing a pref,
it is retrieved from the hash table. The rationale is that in private mode,
it's ok to read a pref from normal database, but not ok to set it.
The in-memory hash table is cleared when leaving the private browsing mode.
When removing a set of preferences (with removeGroupedPrefs or
removePrefsByName), preferences are removed from the in-memory hashtable, *and*
from normal mode database. The rationale is that visiting a website may trigger
setting/getting/removing for a specific preference only. But removing many
prefs at once is the result of an action not associated with a website. For
example, user may wish to delete all its informations. In that case, user
probably expects to not have those informations restored once it leaves private
browsing mode.
2011-09-01 22:13:03 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-07-27 20:13:15 +04:00
|
|
|
var settingID = this._selectSettingID(aName);
|
2009-09-05 06:22:19 +04:00
|
|
|
if (!settingID)
|
2009-07-27 20:13:15 +04:00
|
|
|
return;
|
|
|
|
|
|
|
|
var selectGroupsStmt = this._dbCreateStatement(
|
2010-01-06 02:38:06 +03:00
|
|
|
"SELECT groups.id AS groupID, groups.name AS groupName " +
|
2009-07-27 20:13:15 +04:00
|
|
|
"FROM prefs " +
|
|
|
|
"JOIN groups ON prefs.groupID = groups.id " +
|
|
|
|
"WHERE prefs.settingID = :setting "
|
|
|
|
);
|
|
|
|
|
2010-01-06 02:38:06 +03:00
|
|
|
var groupNames = [];
|
|
|
|
var groupIDs = [];
|
2009-07-27 20:13:15 +04:00
|
|
|
try {
|
|
|
|
selectGroupsStmt.params.setting = settingID;
|
|
|
|
|
2009-09-26 02:32:21 +04:00
|
|
|
while (selectGroupsStmt.executeStep()) {
|
2010-01-06 02:38:06 +03:00
|
|
|
groupIDs.push(selectGroupsStmt.row["groupID"]);
|
|
|
|
groupNames.push(selectGroupsStmt.row["groupName"]);
|
2009-07-27 20:13:15 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
finally {
|
|
|
|
selectGroupsStmt.reset();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (this.hasPref(null, aName)) {
|
2010-01-06 02:38:06 +03:00
|
|
|
groupNames.push(null);
|
2009-07-27 20:13:15 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
this._dbConnection.executeSimpleSQL("DELETE FROM prefs WHERE settingID = " + settingID);
|
|
|
|
this._dbConnection.executeSimpleSQL("DELETE FROM settings WHERE id = " + settingID);
|
|
|
|
|
2010-01-06 02:38:06 +03:00
|
|
|
for (var i = 0; i < groupNames.length; i++) {
|
2012-12-21 05:37:56 +04:00
|
|
|
this._cache.remove(groupNames[i], aName);
|
2010-01-06 02:38:06 +03:00
|
|
|
if (groupNames[i]) // ie. not null, which will be last (and i == groupIDs.length)
|
|
|
|
this._deleteGroupIfUnused(groupIDs[i]);
|
2012-06-30 18:50:07 +04:00
|
|
|
if (!aContext || !aContext.usePrivateBrowsing) {
|
2013-08-01 23:27:30 +04:00
|
|
|
this._broadcastPrefRemoved(groupNames[i], aName);
|
bug 679784: let nsIContentPrefService handle private browsing mode; r=ehsan
Manage private browsing mode in content pref service. CPS should be available
in private browsing mode, but should not store informations on disk, and should
clear all informations once the private session ends.
When setting a pref in private mode, it is stored in an in-memory hash table.
When getting a pref, it is retrieved from that hash table if available.
Otherwise, it is retrieved using the standard mechanism. When removing a pref,
it is retrieved from the hash table. The rationale is that in private mode,
it's ok to read a pref from normal database, but not ok to set it.
The in-memory hash table is cleared when leaving the private browsing mode.
When removing a set of preferences (with removeGroupedPrefs or
removePrefsByName), preferences are removed from the in-memory hashtable, *and*
from normal mode database. The rationale is that visiting a website may trigger
setting/getting/removing for a specific preference only. But removing many
prefs at once is the result of an action not associated with a website. For
example, user may wish to delete all its informations. In that case, user
probably expects to not have those informations restored once it leaves private
browsing mode.
2011-09-01 22:13:03 +04:00
|
|
|
}
|
2009-07-27 20:13:15 +04:00
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2012-06-30 18:50:07 +04:00
|
|
|
getPrefs: function ContentPrefService_getPrefs(aGroup, aContext) {
|
2010-09-07 23:16:43 +04:00
|
|
|
var group = this._parseGroupParam(aGroup);
|
2012-06-30 18:50:07 +04:00
|
|
|
if (aContext && aContext.usePrivateBrowsing) {
|
bug 679784: let nsIContentPrefService handle private browsing mode; r=ehsan
Manage private browsing mode in content pref service. CPS should be available
in private browsing mode, but should not store informations on disk, and should
clear all informations once the private session ends.
When setting a pref in private mode, it is stored in an in-memory hash table.
When getting a pref, it is retrieved from that hash table if available.
Otherwise, it is retrieved using the standard mechanism. When removing a pref,
it is retrieved from the hash table. The rationale is that in private mode,
it's ok to read a pref from normal database, but not ok to set it.
The in-memory hash table is cleared when leaving the private browsing mode.
When removing a set of preferences (with removeGroupedPrefs or
removePrefsByName), preferences are removed from the in-memory hashtable, *and*
from normal mode database. The rationale is that visiting a website may trigger
setting/getting/removing for a specific preference only. But removing many
prefs at once is the result of an action not associated with a website. For
example, user may wish to delete all its informations. In that case, user
probably expects to not have those informations restored once it leaves private
browsing mode.
2011-09-01 22:13:03 +04:00
|
|
|
let prefs = Cc["@mozilla.org/hash-property-bag;1"].
|
|
|
|
createInstance(Ci.nsIWritablePropertyBag);
|
2012-12-21 05:37:56 +04:00
|
|
|
for (let [sgroup, sname, sval] in this._privModeStorage) {
|
|
|
|
if (sgroup === group)
|
|
|
|
prefs.setProperty(sname, sval);
|
bug 679784: let nsIContentPrefService handle private browsing mode; r=ehsan
Manage private browsing mode in content pref service. CPS should be available
in private browsing mode, but should not store informations on disk, and should
clear all informations once the private session ends.
When setting a pref in private mode, it is stored in an in-memory hash table.
When getting a pref, it is retrieved from that hash table if available.
Otherwise, it is retrieved using the standard mechanism. When removing a pref,
it is retrieved from the hash table. The rationale is that in private mode,
it's ok to read a pref from normal database, but not ok to set it.
The in-memory hash table is cleared when leaving the private browsing mode.
When removing a set of preferences (with removeGroupedPrefs or
removePrefsByName), preferences are removed from the in-memory hashtable, *and*
from normal mode database. The rationale is that visiting a website may trigger
setting/getting/removing for a specific preference only. But removing many
prefs at once is the result of an action not associated with a website. For
example, user may wish to delete all its informations. In that case, user
probably expects to not have those informations restored once it leaves private
browsing mode.
2011-09-01 22:13:03 +04:00
|
|
|
}
|
|
|
|
return prefs;
|
|
|
|
}
|
|
|
|
|
2010-09-07 23:16:43 +04:00
|
|
|
if (group == null)
|
2009-09-05 06:22:19 +04:00
|
|
|
return this._selectGlobalPrefs();
|
2010-09-07 23:16:43 +04:00
|
|
|
return this._selectPrefs(group);
|
2007-06-19 22:51:09 +04:00
|
|
|
},
|
|
|
|
|
2012-06-30 18:50:07 +04:00
|
|
|
getPrefsByName: function ContentPrefService_getPrefsByName(aName, aContext) {
|
2009-08-24 21:12:04 +04:00
|
|
|
if (!aName)
|
|
|
|
throw Components.Exception("aName cannot be null or an empty string",
|
|
|
|
Cr.NS_ERROR_ILLEGAL_VALUE);
|
|
|
|
|
2012-06-30 18:50:07 +04:00
|
|
|
if (aContext && aContext.usePrivateBrowsing) {
|
bug 679784: let nsIContentPrefService handle private browsing mode; r=ehsan
Manage private browsing mode in content pref service. CPS should be available
in private browsing mode, but should not store informations on disk, and should
clear all informations once the private session ends.
When setting a pref in private mode, it is stored in an in-memory hash table.
When getting a pref, it is retrieved from that hash table if available.
Otherwise, it is retrieved using the standard mechanism. When removing a pref,
it is retrieved from the hash table. The rationale is that in private mode,
it's ok to read a pref from normal database, but not ok to set it.
The in-memory hash table is cleared when leaving the private browsing mode.
When removing a set of preferences (with removeGroupedPrefs or
removePrefsByName), preferences are removed from the in-memory hashtable, *and*
from normal mode database. The rationale is that visiting a website may trigger
setting/getting/removing for a specific preference only. But removing many
prefs at once is the result of an action not associated with a website. For
example, user may wish to delete all its informations. In that case, user
probably expects to not have those informations restored once it leaves private
browsing mode.
2011-09-01 22:13:03 +04:00
|
|
|
let prefs = Cc["@mozilla.org/hash-property-bag;1"].
|
|
|
|
createInstance(Ci.nsIWritablePropertyBag);
|
2012-12-21 05:37:56 +04:00
|
|
|
for (let [sgroup, sname, sval] in this._privModeStorage) {
|
|
|
|
if (sname === aName)
|
|
|
|
prefs.setProperty(sgroup, sval);
|
bug 679784: let nsIContentPrefService handle private browsing mode; r=ehsan
Manage private browsing mode in content pref service. CPS should be available
in private browsing mode, but should not store informations on disk, and should
clear all informations once the private session ends.
When setting a pref in private mode, it is stored in an in-memory hash table.
When getting a pref, it is retrieved from that hash table if available.
Otherwise, it is retrieved using the standard mechanism. When removing a pref,
it is retrieved from the hash table. The rationale is that in private mode,
it's ok to read a pref from normal database, but not ok to set it.
The in-memory hash table is cleared when leaving the private browsing mode.
When removing a set of preferences (with removeGroupedPrefs or
removePrefsByName), preferences are removed from the in-memory hashtable, *and*
from normal mode database. The rationale is that visiting a website may trigger
setting/getting/removing for a specific preference only. But removing many
prefs at once is the result of an action not associated with a website. For
example, user may wish to delete all its informations. In that case, user
probably expects to not have those informations restored once it leaves private
browsing mode.
2011-09-01 22:13:03 +04:00
|
|
|
}
|
|
|
|
return prefs;
|
|
|
|
}
|
|
|
|
|
2009-07-27 20:13:15 +04:00
|
|
|
return this._selectPrefsByName(aName);
|
|
|
|
},
|
|
|
|
|
2007-06-19 22:51:09 +04:00
|
|
|
// A hash of arrays of observers, indexed by setting name.
|
|
|
|
_observers: {},
|
|
|
|
|
|
|
|
// An array of generic observers, which observe all settings.
|
|
|
|
_genericObservers: [],
|
|
|
|
|
|
|
|
addObserver: function ContentPrefService_addObserver(aName, aObserver) {
|
|
|
|
var observers;
|
|
|
|
if (aName) {
|
|
|
|
if (!this._observers[aName])
|
|
|
|
this._observers[aName] = [];
|
|
|
|
observers = this._observers[aName];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
observers = this._genericObservers;
|
|
|
|
|
|
|
|
if (observers.indexOf(aObserver) == -1)
|
|
|
|
observers.push(aObserver);
|
|
|
|
},
|
|
|
|
|
|
|
|
removeObserver: function ContentPrefService_removeObserver(aName, aObserver) {
|
|
|
|
var observers;
|
|
|
|
if (aName) {
|
|
|
|
if (!this._observers[aName])
|
|
|
|
return;
|
|
|
|
observers = this._observers[aName];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
observers = this._genericObservers;
|
|
|
|
|
|
|
|
if (observers.indexOf(aObserver) != -1)
|
|
|
|
observers.splice(observers.indexOf(aObserver), 1);
|
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Construct a list of observers to notify about a change to some setting,
|
|
|
|
* putting setting-specific observers before before generic ones, so observers
|
|
|
|
* that initialize individual settings (like the page style controller)
|
|
|
|
* execute before observers that display multiple settings and depend on them
|
|
|
|
* being initialized first (like the content prefs sidebar).
|
|
|
|
*/
|
|
|
|
_getObservers: function ContentPrefService__getObservers(aName) {
|
|
|
|
var observers = [];
|
|
|
|
|
|
|
|
if (aName && this._observers[aName])
|
|
|
|
observers = observers.concat(this._observers[aName]);
|
|
|
|
observers = observers.concat(this._genericObservers);
|
|
|
|
|
|
|
|
return observers;
|
|
|
|
},
|
2013-01-31 21:43:56 +04:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Notify all observers about the removal of a preference.
|
|
|
|
*/
|
2009-07-27 20:13:15 +04:00
|
|
|
_notifyPrefRemoved: function ContentPrefService__notifyPrefRemoved(aGroup, aName) {
|
|
|
|
for each (var observer in this._getObservers(aName)) {
|
|
|
|
try {
|
|
|
|
observer.onContentPrefRemoved(aGroup, aName);
|
|
|
|
}
|
|
|
|
catch(ex) {
|
|
|
|
Cu.reportError(ex);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
2007-06-19 22:51:09 +04:00
|
|
|
|
2013-01-31 21:43:56 +04:00
|
|
|
/**
|
|
|
|
* Notify all observers about a preference change.
|
|
|
|
*/
|
bug 679784: let nsIContentPrefService handle private browsing mode; r=ehsan
Manage private browsing mode in content pref service. CPS should be available
in private browsing mode, but should not store informations on disk, and should
clear all informations once the private session ends.
When setting a pref in private mode, it is stored in an in-memory hash table.
When getting a pref, it is retrieved from that hash table if available.
Otherwise, it is retrieved using the standard mechanism. When removing a pref,
it is retrieved from the hash table. The rationale is that in private mode,
it's ok to read a pref from normal database, but not ok to set it.
The in-memory hash table is cleared when leaving the private browsing mode.
When removing a set of preferences (with removeGroupedPrefs or
removePrefsByName), preferences are removed from the in-memory hashtable, *and*
from normal mode database. The rationale is that visiting a website may trigger
setting/getting/removing for a specific preference only. But removing many
prefs at once is the result of an action not associated with a website. For
example, user may wish to delete all its informations. In that case, user
probably expects to not have those informations restored once it leaves private
browsing mode.
2011-09-01 22:13:03 +04:00
|
|
|
_notifyPrefSet: function ContentPrefService__notifyPrefSet(aGroup, aName, aValue) {
|
|
|
|
for each (var observer in this._getObservers(aName)) {
|
|
|
|
try {
|
|
|
|
observer.onContentPrefSet(aGroup, aName, aValue);
|
|
|
|
}
|
|
|
|
catch(ex) {
|
|
|
|
Cu.reportError(ex);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2013-08-01 23:27:30 +04:00
|
|
|
/**
|
|
|
|
* Notify all observers in the current process about the removal of a
|
|
|
|
* preference and send a message to all other processes so that they can in
|
|
|
|
* turn notify their observers about the change. This is meant to be called
|
|
|
|
* only in the parent process. Only whitelisted preferences are broadcast to
|
|
|
|
* the child processes.
|
|
|
|
*/
|
|
|
|
_broadcastPrefRemoved: function ContentPrefService__broadcastPrefRemoved(aGroup, aName) {
|
|
|
|
this._notifyPrefRemoved(aGroup, aName);
|
|
|
|
|
|
|
|
if (REMOTE_WHITELIST.indexOf(aName) != -1) {
|
|
|
|
this.messageManager.broadcastAsyncMessage('ContentPref:notifyPrefRemoved',
|
|
|
|
{ "group": aGroup, "name": aName } );
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Notify all observers in the current process about a preference change and
|
|
|
|
* send a message to all other processes so that they can in turn notify
|
|
|
|
* their observers about the change. This is meant to be called only in the
|
|
|
|
* parent process. Only whitelisted preferences are broadcast to the child
|
|
|
|
* processes.
|
|
|
|
*/
|
|
|
|
_broadcastPrefSet: function ContentPrefService__broadcastPrefSet(aGroup, aName, aValue) {
|
|
|
|
this._notifyPrefSet(aGroup, aName, aValue);
|
|
|
|
|
|
|
|
if (REMOTE_WHITELIST.indexOf(aName) != -1) {
|
|
|
|
this.messageManager.broadcastAsyncMessage('ContentPref:notifyPrefSet',
|
|
|
|
{ "group": aGroup, "name": aName, "value": aValue } );
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2007-06-19 22:51:09 +04:00
|
|
|
_grouper: null,
|
2010-04-17 14:19:33 +04:00
|
|
|
get grouper() {
|
2007-06-19 22:51:09 +04:00
|
|
|
if (!this._grouper)
|
|
|
|
this._grouper = Cc["@mozilla.org/content-pref/hostname-grouper;1"].
|
|
|
|
getService(Ci.nsIContentURIGrouper);
|
|
|
|
return this._grouper;
|
|
|
|
},
|
|
|
|
|
2010-04-17 14:19:33 +04:00
|
|
|
get DBConnection() {
|
2008-02-26 01:07:52 +03:00
|
|
|
return this._dbConnection;
|
|
|
|
},
|
|
|
|
|
2007-06-19 22:51:09 +04:00
|
|
|
|
|
|
|
//**************************************************************************//
|
|
|
|
// Data Retrieval & Modification
|
|
|
|
|
|
|
|
__stmtSelectPref: null,
|
2010-04-17 14:19:33 +04:00
|
|
|
get _stmtSelectPref() {
|
2007-06-19 22:51:09 +04:00
|
|
|
if (!this.__stmtSelectPref)
|
|
|
|
this.__stmtSelectPref = this._dbCreateStatement(
|
|
|
|
"SELECT prefs.value AS value " +
|
|
|
|
"FROM prefs " +
|
|
|
|
"JOIN groups ON prefs.groupID = groups.id " +
|
|
|
|
"JOIN settings ON prefs.settingID = settings.id " +
|
|
|
|
"WHERE groups.name = :group " +
|
|
|
|
"AND settings.name = :setting"
|
|
|
|
);
|
|
|
|
|
|
|
|
return this.__stmtSelectPref;
|
|
|
|
},
|
|
|
|
|
2010-12-28 23:45:04 +03:00
|
|
|
_scheduleCallback: function(func) {
|
|
|
|
let tm = Cc["@mozilla.org/thread-manager;1"].getService(Ci.nsIThreadManager);
|
|
|
|
tm.mainThread.dispatch(func, Ci.nsIThread.DISPATCH_NORMAL);
|
|
|
|
},
|
|
|
|
|
2010-02-09 13:28:39 +03:00
|
|
|
_selectPref: function ContentPrefService__selectPref(aGroup, aSetting, aCallback) {
|
2012-12-21 05:37:56 +04:00
|
|
|
let value = undefined;
|
|
|
|
if (this._cache.has(aGroup, aSetting)) {
|
|
|
|
value = this._cache.get(aGroup, aSetting);
|
2010-12-28 23:45:04 +03:00
|
|
|
if (aCallback) {
|
|
|
|
this._scheduleCallback(function(){aCallback.onResult(value);});
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
return value;
|
|
|
|
}
|
2007-06-19 22:51:09 +04:00
|
|
|
|
|
|
|
try {
|
|
|
|
this._stmtSelectPref.params.group = aGroup;
|
|
|
|
this._stmtSelectPref.params.setting = aSetting;
|
|
|
|
|
2010-12-28 23:45:04 +03:00
|
|
|
if (aCallback) {
|
|
|
|
let cache = this._cache;
|
|
|
|
new AsyncStatement(this._stmtSelectPref).execute({onResult: function(aResult) {
|
2012-12-21 05:37:56 +04:00
|
|
|
cache.set(aGroup, aSetting, aResult);
|
2010-12-28 23:45:04 +03:00
|
|
|
aCallback.onResult(aResult);
|
|
|
|
}});
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
if (this._stmtSelectPref.executeStep()) {
|
|
|
|
value = this._stmtSelectPref.row["value"];
|
|
|
|
}
|
2012-12-21 05:37:56 +04:00
|
|
|
this._cache.set(aGroup, aSetting, value);
|
2010-12-28 23:45:04 +03:00
|
|
|
}
|
2007-06-19 22:51:09 +04:00
|
|
|
}
|
|
|
|
finally {
|
|
|
|
this._stmtSelectPref.reset();
|
|
|
|
}
|
|
|
|
|
|
|
|
return value;
|
|
|
|
},
|
|
|
|
|
|
|
|
__stmtSelectGlobalPref: null,
|
2010-04-17 14:19:33 +04:00
|
|
|
get _stmtSelectGlobalPref() {
|
2007-06-19 22:51:09 +04:00
|
|
|
if (!this.__stmtSelectGlobalPref)
|
|
|
|
this.__stmtSelectGlobalPref = this._dbCreateStatement(
|
|
|
|
"SELECT prefs.value AS value " +
|
|
|
|
"FROM prefs " +
|
|
|
|
"JOIN settings ON prefs.settingID = settings.id " +
|
|
|
|
"WHERE prefs.groupID IS NULL " +
|
|
|
|
"AND settings.name = :name"
|
|
|
|
);
|
|
|
|
|
|
|
|
return this.__stmtSelectGlobalPref;
|
|
|
|
},
|
|
|
|
|
2010-02-09 13:28:39 +03:00
|
|
|
_selectGlobalPref: function ContentPrefService__selectGlobalPref(aName, aCallback) {
|
2012-12-21 05:37:56 +04:00
|
|
|
let value = undefined;
|
|
|
|
if (this._cache.has(null, aName)) {
|
|
|
|
value = this._cache.get(null, aName);
|
2010-12-28 23:45:04 +03:00
|
|
|
if (aCallback) {
|
|
|
|
this._scheduleCallback(function(){aCallback.onResult(value);});
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
return value;
|
|
|
|
}
|
2007-06-19 22:51:09 +04:00
|
|
|
|
|
|
|
try {
|
|
|
|
this._stmtSelectGlobalPref.params.name = aName;
|
|
|
|
|
2010-12-28 23:45:04 +03:00
|
|
|
if (aCallback) {
|
|
|
|
let cache = this._cache;
|
|
|
|
new AsyncStatement(this._stmtSelectGlobalPref).execute({onResult: function(aResult) {
|
2012-12-21 05:37:56 +04:00
|
|
|
cache.set(null, aName, aResult);
|
2010-12-28 23:45:04 +03:00
|
|
|
aCallback.onResult(aResult);
|
|
|
|
}});
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
if (this._stmtSelectGlobalPref.executeStep()) {
|
|
|
|
value = this._stmtSelectGlobalPref.row["value"];
|
|
|
|
}
|
2012-12-21 05:37:56 +04:00
|
|
|
this._cache.set(null, aName, value);
|
2010-12-28 23:45:04 +03:00
|
|
|
}
|
2007-06-19 22:51:09 +04:00
|
|
|
}
|
|
|
|
finally {
|
|
|
|
this._stmtSelectGlobalPref.reset();
|
|
|
|
}
|
|
|
|
|
|
|
|
return value;
|
|
|
|
},
|
|
|
|
|
|
|
|
__stmtSelectGroupID: null,
|
2010-04-17 14:19:33 +04:00
|
|
|
get _stmtSelectGroupID() {
|
2007-06-19 22:51:09 +04:00
|
|
|
if (!this.__stmtSelectGroupID)
|
|
|
|
this.__stmtSelectGroupID = this._dbCreateStatement(
|
|
|
|
"SELECT groups.id AS id " +
|
|
|
|
"FROM groups " +
|
|
|
|
"WHERE groups.name = :name "
|
|
|
|
);
|
|
|
|
|
|
|
|
return this.__stmtSelectGroupID;
|
|
|
|
},
|
|
|
|
|
|
|
|
_selectGroupID: function ContentPrefService__selectGroupID(aName) {
|
|
|
|
var id;
|
|
|
|
|
|
|
|
try {
|
|
|
|
this._stmtSelectGroupID.params.name = aName;
|
|
|
|
|
2009-09-26 02:32:21 +04:00
|
|
|
if (this._stmtSelectGroupID.executeStep())
|
2007-06-19 22:51:09 +04:00
|
|
|
id = this._stmtSelectGroupID.row["id"];
|
|
|
|
}
|
|
|
|
finally {
|
|
|
|
this._stmtSelectGroupID.reset();
|
|
|
|
}
|
|
|
|
|
|
|
|
return id;
|
|
|
|
},
|
|
|
|
|
|
|
|
__stmtInsertGroup: null,
|
2010-04-17 14:19:33 +04:00
|
|
|
get _stmtInsertGroup() {
|
2007-06-19 22:51:09 +04:00
|
|
|
if (!this.__stmtInsertGroup)
|
|
|
|
this.__stmtInsertGroup = this._dbCreateStatement(
|
|
|
|
"INSERT INTO groups (name) VALUES (:name)"
|
|
|
|
);
|
|
|
|
|
|
|
|
return this.__stmtInsertGroup;
|
|
|
|
},
|
|
|
|
|
|
|
|
_insertGroup: function ContentPrefService__insertGroup(aName) {
|
|
|
|
this._stmtInsertGroup.params.name = aName;
|
|
|
|
this._stmtInsertGroup.execute();
|
|
|
|
return this._dbConnection.lastInsertRowID;
|
|
|
|
},
|
|
|
|
|
|
|
|
__stmtSelectSettingID: null,
|
2010-04-17 14:19:33 +04:00
|
|
|
get _stmtSelectSettingID() {
|
2007-06-19 22:51:09 +04:00
|
|
|
if (!this.__stmtSelectSettingID)
|
|
|
|
this.__stmtSelectSettingID = this._dbCreateStatement(
|
|
|
|
"SELECT id FROM settings WHERE name = :name"
|
|
|
|
);
|
|
|
|
|
|
|
|
return this.__stmtSelectSettingID;
|
|
|
|
},
|
|
|
|
|
|
|
|
_selectSettingID: function ContentPrefService__selectSettingID(aName) {
|
|
|
|
var id;
|
|
|
|
|
|
|
|
try {
|
|
|
|
this._stmtSelectSettingID.params.name = aName;
|
|
|
|
|
2009-09-26 02:32:21 +04:00
|
|
|
if (this._stmtSelectSettingID.executeStep())
|
2007-06-19 22:51:09 +04:00
|
|
|
id = this._stmtSelectSettingID.row["id"];
|
|
|
|
}
|
|
|
|
finally {
|
|
|
|
this._stmtSelectSettingID.reset();
|
|
|
|
}
|
|
|
|
|
|
|
|
return id;
|
|
|
|
},
|
|
|
|
|
|
|
|
__stmtInsertSetting: null,
|
2010-04-17 14:19:33 +04:00
|
|
|
get _stmtInsertSetting() {
|
2007-06-19 22:51:09 +04:00
|
|
|
if (!this.__stmtInsertSetting)
|
|
|
|
this.__stmtInsertSetting = this._dbCreateStatement(
|
|
|
|
"INSERT INTO settings (name) VALUES (:name)"
|
|
|
|
);
|
|
|
|
|
|
|
|
return this.__stmtInsertSetting;
|
|
|
|
},
|
|
|
|
|
|
|
|
_insertSetting: function ContentPrefService__insertSetting(aName) {
|
|
|
|
this._stmtInsertSetting.params.name = aName;
|
|
|
|
this._stmtInsertSetting.execute();
|
|
|
|
return this._dbConnection.lastInsertRowID;
|
|
|
|
},
|
|
|
|
|
|
|
|
__stmtSelectPrefID: null,
|
2010-04-17 14:19:33 +04:00
|
|
|
get _stmtSelectPrefID() {
|
2007-06-19 22:51:09 +04:00
|
|
|
if (!this.__stmtSelectPrefID)
|
|
|
|
this.__stmtSelectPrefID = this._dbCreateStatement(
|
|
|
|
"SELECT id FROM prefs WHERE groupID = :groupID AND settingID = :settingID"
|
|
|
|
);
|
|
|
|
|
|
|
|
return this.__stmtSelectPrefID;
|
|
|
|
},
|
|
|
|
|
|
|
|
_selectPrefID: function ContentPrefService__selectPrefID(aGroupID, aSettingID) {
|
|
|
|
var id;
|
|
|
|
|
|
|
|
try {
|
|
|
|
this._stmtSelectPrefID.params.groupID = aGroupID;
|
|
|
|
this._stmtSelectPrefID.params.settingID = aSettingID;
|
|
|
|
|
2009-09-26 02:32:21 +04:00
|
|
|
if (this._stmtSelectPrefID.executeStep())
|
2007-06-19 22:51:09 +04:00
|
|
|
id = this._stmtSelectPrefID.row["id"];
|
|
|
|
}
|
|
|
|
finally {
|
|
|
|
this._stmtSelectPrefID.reset();
|
|
|
|
}
|
|
|
|
|
|
|
|
return id;
|
|
|
|
},
|
|
|
|
|
|
|
|
__stmtSelectGlobalPrefID: null,
|
2010-04-17 14:19:33 +04:00
|
|
|
get _stmtSelectGlobalPrefID() {
|
2007-06-19 22:51:09 +04:00
|
|
|
if (!this.__stmtSelectGlobalPrefID)
|
|
|
|
this.__stmtSelectGlobalPrefID = this._dbCreateStatement(
|
|
|
|
"SELECT id FROM prefs WHERE groupID IS NULL AND settingID = :settingID"
|
|
|
|
);
|
|
|
|
|
|
|
|
return this.__stmtSelectGlobalPrefID;
|
|
|
|
},
|
|
|
|
|
|
|
|
_selectGlobalPrefID: function ContentPrefService__selectGlobalPrefID(aSettingID) {
|
|
|
|
var id;
|
|
|
|
|
|
|
|
try {
|
|
|
|
this._stmtSelectGlobalPrefID.params.settingID = aSettingID;
|
|
|
|
|
2009-09-26 02:32:21 +04:00
|
|
|
if (this._stmtSelectGlobalPrefID.executeStep())
|
2007-06-19 22:51:09 +04:00
|
|
|
id = this._stmtSelectGlobalPrefID.row["id"];
|
|
|
|
}
|
|
|
|
finally {
|
|
|
|
this._stmtSelectGlobalPrefID.reset();
|
|
|
|
}
|
|
|
|
|
|
|
|
return id;
|
|
|
|
},
|
|
|
|
|
|
|
|
__stmtInsertPref: null,
|
2010-04-17 14:19:33 +04:00
|
|
|
get _stmtInsertPref() {
|
2007-06-19 22:51:09 +04:00
|
|
|
if (!this.__stmtInsertPref)
|
|
|
|
this.__stmtInsertPref = this._dbCreateStatement(
|
|
|
|
"INSERT INTO prefs (groupID, settingID, value) " +
|
|
|
|
"VALUES (:groupID, :settingID, :value)"
|
|
|
|
);
|
|
|
|
|
|
|
|
return this.__stmtInsertPref;
|
|
|
|
},
|
|
|
|
|
|
|
|
_insertPref: function ContentPrefService__insertPref(aGroupID, aSettingID, aValue) {
|
|
|
|
this._stmtInsertPref.params.groupID = aGroupID;
|
|
|
|
this._stmtInsertPref.params.settingID = aSettingID;
|
|
|
|
this._stmtInsertPref.params.value = aValue;
|
|
|
|
this._stmtInsertPref.execute();
|
|
|
|
return this._dbConnection.lastInsertRowID;
|
|
|
|
},
|
|
|
|
|
|
|
|
__stmtUpdatePref: null,
|
2010-04-17 14:19:33 +04:00
|
|
|
get _stmtUpdatePref() {
|
2007-06-19 22:51:09 +04:00
|
|
|
if (!this.__stmtUpdatePref)
|
|
|
|
this.__stmtUpdatePref = this._dbCreateStatement(
|
|
|
|
"UPDATE prefs SET value = :value WHERE id = :id"
|
|
|
|
);
|
|
|
|
|
|
|
|
return this.__stmtUpdatePref;
|
|
|
|
},
|
|
|
|
|
|
|
|
_updatePref: function ContentPrefService__updatePref(aPrefID, aValue) {
|
|
|
|
this._stmtUpdatePref.params.id = aPrefID;
|
|
|
|
this._stmtUpdatePref.params.value = aValue;
|
|
|
|
this._stmtUpdatePref.execute();
|
|
|
|
},
|
|
|
|
|
|
|
|
__stmtDeletePref: null,
|
2010-04-17 14:19:33 +04:00
|
|
|
get _stmtDeletePref() {
|
2007-06-19 22:51:09 +04:00
|
|
|
if (!this.__stmtDeletePref)
|
|
|
|
this.__stmtDeletePref = this._dbCreateStatement(
|
|
|
|
"DELETE FROM prefs WHERE id = :id"
|
|
|
|
);
|
|
|
|
|
|
|
|
return this.__stmtDeletePref;
|
|
|
|
},
|
|
|
|
|
|
|
|
_deletePref: function ContentPrefService__deletePref(aPrefID) {
|
|
|
|
this._stmtDeletePref.params.id = aPrefID;
|
|
|
|
this._stmtDeletePref.execute();
|
|
|
|
},
|
|
|
|
|
|
|
|
__stmtDeleteSettingIfUnused: null,
|
2010-04-17 14:19:33 +04:00
|
|
|
get _stmtDeleteSettingIfUnused() {
|
2007-06-19 22:51:09 +04:00
|
|
|
if (!this.__stmtDeleteSettingIfUnused)
|
|
|
|
this.__stmtDeleteSettingIfUnused = this._dbCreateStatement(
|
|
|
|
"DELETE FROM settings WHERE id = :id " +
|
|
|
|
"AND id NOT IN (SELECT DISTINCT settingID FROM prefs)"
|
|
|
|
);
|
|
|
|
|
|
|
|
return this.__stmtDeleteSettingIfUnused;
|
|
|
|
},
|
|
|
|
|
|
|
|
_deleteSettingIfUnused: function ContentPrefService__deleteSettingIfUnused(aSettingID) {
|
|
|
|
this._stmtDeleteSettingIfUnused.params.id = aSettingID;
|
|
|
|
this._stmtDeleteSettingIfUnused.execute();
|
|
|
|
},
|
|
|
|
|
|
|
|
__stmtDeleteGroupIfUnused: null,
|
2010-04-17 14:19:33 +04:00
|
|
|
get _stmtDeleteGroupIfUnused() {
|
2007-06-19 22:51:09 +04:00
|
|
|
if (!this.__stmtDeleteGroupIfUnused)
|
|
|
|
this.__stmtDeleteGroupIfUnused = this._dbCreateStatement(
|
|
|
|
"DELETE FROM groups WHERE id = :id " +
|
|
|
|
"AND id NOT IN (SELECT DISTINCT groupID FROM prefs)"
|
|
|
|
);
|
|
|
|
|
|
|
|
return this.__stmtDeleteGroupIfUnused;
|
|
|
|
},
|
|
|
|
|
|
|
|
_deleteGroupIfUnused: function ContentPrefService__deleteGroupIfUnused(aGroupID) {
|
|
|
|
this._stmtDeleteGroupIfUnused.params.id = aGroupID;
|
|
|
|
this._stmtDeleteGroupIfUnused.execute();
|
|
|
|
},
|
|
|
|
|
|
|
|
__stmtSelectPrefs: null,
|
2010-04-17 14:19:33 +04:00
|
|
|
get _stmtSelectPrefs() {
|
2007-06-19 22:51:09 +04:00
|
|
|
if (!this.__stmtSelectPrefs)
|
|
|
|
this.__stmtSelectPrefs = this._dbCreateStatement(
|
|
|
|
"SELECT settings.name AS name, prefs.value AS value " +
|
|
|
|
"FROM prefs " +
|
|
|
|
"JOIN groups ON prefs.groupID = groups.id " +
|
|
|
|
"JOIN settings ON prefs.settingID = settings.id " +
|
|
|
|
"WHERE groups.name = :group "
|
|
|
|
);
|
|
|
|
|
|
|
|
return this.__stmtSelectPrefs;
|
|
|
|
},
|
|
|
|
|
|
|
|
_selectPrefs: function ContentPrefService__selectPrefs(aGroup) {
|
|
|
|
var prefs = Cc["@mozilla.org/hash-property-bag;1"].
|
|
|
|
createInstance(Ci.nsIWritablePropertyBag);
|
|
|
|
|
|
|
|
try {
|
|
|
|
this._stmtSelectPrefs.params.group = aGroup;
|
|
|
|
|
2009-09-26 02:32:21 +04:00
|
|
|
while (this._stmtSelectPrefs.executeStep())
|
2007-06-19 22:51:09 +04:00
|
|
|
prefs.setProperty(this._stmtSelectPrefs.row["name"],
|
|
|
|
this._stmtSelectPrefs.row["value"]);
|
|
|
|
}
|
|
|
|
finally {
|
|
|
|
this._stmtSelectPrefs.reset();
|
|
|
|
}
|
|
|
|
|
|
|
|
return prefs;
|
|
|
|
},
|
|
|
|
|
|
|
|
__stmtSelectGlobalPrefs: null,
|
2010-04-17 14:19:33 +04:00
|
|
|
get _stmtSelectGlobalPrefs() {
|
2007-06-19 22:51:09 +04:00
|
|
|
if (!this.__stmtSelectGlobalPrefs)
|
|
|
|
this.__stmtSelectGlobalPrefs = this._dbCreateStatement(
|
|
|
|
"SELECT settings.name AS name, prefs.value AS value " +
|
|
|
|
"FROM prefs " +
|
|
|
|
"JOIN settings ON prefs.settingID = settings.id " +
|
|
|
|
"WHERE prefs.groupID IS NULL"
|
|
|
|
);
|
|
|
|
|
|
|
|
return this.__stmtSelectGlobalPrefs;
|
|
|
|
},
|
|
|
|
|
|
|
|
_selectGlobalPrefs: function ContentPrefService__selectGlobalPrefs() {
|
|
|
|
var prefs = Cc["@mozilla.org/hash-property-bag;1"].
|
|
|
|
createInstance(Ci.nsIWritablePropertyBag);
|
|
|
|
|
|
|
|
try {
|
2009-09-26 02:32:21 +04:00
|
|
|
while (this._stmtSelectGlobalPrefs.executeStep())
|
2007-06-19 22:51:09 +04:00
|
|
|
prefs.setProperty(this._stmtSelectGlobalPrefs.row["name"],
|
|
|
|
this._stmtSelectGlobalPrefs.row["value"]);
|
|
|
|
}
|
|
|
|
finally {
|
|
|
|
this._stmtSelectGlobalPrefs.reset();
|
|
|
|
}
|
|
|
|
|
|
|
|
return prefs;
|
|
|
|
},
|
|
|
|
|
2009-07-27 20:13:15 +04:00
|
|
|
__stmtSelectPrefsByName: null,
|
2010-04-17 14:19:33 +04:00
|
|
|
get _stmtSelectPrefsByName() {
|
2009-07-27 20:13:15 +04:00
|
|
|
if (!this.__stmtSelectPrefsByName)
|
|
|
|
this.__stmtSelectPrefsByName = this._dbCreateStatement(
|
|
|
|
"SELECT groups.name AS groupName, prefs.value AS value " +
|
|
|
|
"FROM prefs " +
|
|
|
|
"JOIN groups ON prefs.groupID = groups.id " +
|
|
|
|
"JOIN settings ON prefs.settingID = settings.id " +
|
|
|
|
"WHERE settings.name = :setting "
|
|
|
|
);
|
|
|
|
|
|
|
|
return this.__stmtSelectPrefsByName;
|
|
|
|
},
|
|
|
|
|
|
|
|
_selectPrefsByName: function ContentPrefService__selectPrefsByName(aName) {
|
|
|
|
var prefs = Cc["@mozilla.org/hash-property-bag;1"].
|
|
|
|
createInstance(Ci.nsIWritablePropertyBag);
|
|
|
|
|
|
|
|
try {
|
|
|
|
this._stmtSelectPrefsByName.params.setting = aName;
|
|
|
|
|
2009-09-26 02:32:21 +04:00
|
|
|
while (this._stmtSelectPrefsByName.executeStep())
|
2009-07-27 20:13:15 +04:00
|
|
|
prefs.setProperty(this._stmtSelectPrefsByName.row["groupName"],
|
|
|
|
this._stmtSelectPrefsByName.row["value"]);
|
|
|
|
}
|
|
|
|
finally {
|
|
|
|
this._stmtSelectPrefsByName.reset();
|
|
|
|
}
|
|
|
|
|
|
|
|
var global = this._selectGlobalPref(aName);
|
|
|
|
if (typeof global != "undefined") {
|
|
|
|
prefs.setProperty(null, global);
|
|
|
|
}
|
|
|
|
|
|
|
|
return prefs;
|
|
|
|
},
|
|
|
|
|
2007-06-19 22:51:09 +04:00
|
|
|
|
|
|
|
//**************************************************************************//
|
|
|
|
// Database Creation & Access
|
|
|
|
|
2007-11-27 10:55:59 +03:00
|
|
|
_dbVersion: 3,
|
2007-06-19 22:51:09 +04:00
|
|
|
|
|
|
|
_dbSchema: {
|
2007-11-27 10:55:59 +03:00
|
|
|
tables: {
|
|
|
|
groups: "id INTEGER PRIMARY KEY, \
|
|
|
|
name TEXT NOT NULL",
|
|
|
|
|
|
|
|
settings: "id INTEGER PRIMARY KEY, \
|
|
|
|
name TEXT NOT NULL",
|
|
|
|
|
|
|
|
prefs: "id INTEGER PRIMARY KEY, \
|
|
|
|
groupID INTEGER REFERENCES groups(id), \
|
|
|
|
settingID INTEGER NOT NULL REFERENCES settings(id), \
|
|
|
|
value BLOB"
|
|
|
|
},
|
|
|
|
indices: {
|
|
|
|
groups_idx: {
|
|
|
|
table: "groups",
|
|
|
|
columns: ["name"]
|
|
|
|
},
|
|
|
|
settings_idx: {
|
|
|
|
table: "settings",
|
|
|
|
columns: ["name"]
|
|
|
|
},
|
|
|
|
prefs_idx: {
|
|
|
|
table: "prefs",
|
|
|
|
columns: ["groupID", "settingID"]
|
|
|
|
}
|
|
|
|
}
|
2007-06-19 22:51:09 +04:00
|
|
|
},
|
|
|
|
|
|
|
|
_dbConnection: null,
|
|
|
|
|
2007-11-26 11:35:22 +03:00
|
|
|
_dbCreateStatement: function ContentPrefService__dbCreateStatement(aSQLString) {
|
2007-06-19 22:51:09 +04:00
|
|
|
try {
|
|
|
|
var statement = this._dbConnection.createStatement(aSQLString);
|
|
|
|
}
|
|
|
|
catch(ex) {
|
|
|
|
Cu.reportError("error creating statement " + aSQLString + ": " +
|
|
|
|
this._dbConnection.lastError + " - " +
|
|
|
|
this._dbConnection.lastErrorString);
|
|
|
|
throw ex;
|
|
|
|
}
|
|
|
|
|
2009-09-26 02:32:21 +04:00
|
|
|
return statement;
|
2007-06-19 22:51:09 +04:00
|
|
|
},
|
|
|
|
|
|
|
|
// _dbInit and the methods it calls (_dbCreate, _dbMigrate, and version-
|
|
|
|
// specific migration methods) must be careful not to call any method
|
|
|
|
// of the service that assumes the database connection has already been
|
|
|
|
// initialized, since it won't be initialized until at the end of _dbInit.
|
|
|
|
|
|
|
|
_dbInit: function ContentPrefService__dbInit() {
|
|
|
|
var dirService = Cc["@mozilla.org/file/directory_service;1"].
|
|
|
|
getService(Ci.nsIProperties);
|
|
|
|
var dbFile = dirService.get("ProfD", Ci.nsIFile);
|
|
|
|
dbFile.append("content-prefs.sqlite");
|
|
|
|
|
|
|
|
var dbService = Cc["@mozilla.org/storage/service;1"].
|
|
|
|
getService(Ci.mozIStorageService);
|
|
|
|
|
|
|
|
var dbConnection;
|
|
|
|
|
2007-11-26 11:35:22 +03:00
|
|
|
if (!dbFile.exists())
|
2007-06-19 22:51:09 +04:00
|
|
|
dbConnection = this._dbCreate(dbService, dbFile);
|
|
|
|
else {
|
2008-03-25 01:14:38 +03:00
|
|
|
try {
|
|
|
|
dbConnection = dbService.openDatabase(dbFile);
|
|
|
|
}
|
2008-02-26 01:07:52 +03:00
|
|
|
// If the connection isn't ready after we open the database, that means
|
|
|
|
// the database has been corrupted, so we back it up and then recreate it.
|
2008-03-25 01:14:38 +03:00
|
|
|
catch (e if e.result == Cr.NS_ERROR_FILE_CORRUPTED) {
|
|
|
|
dbConnection = this._dbBackUpAndRecreate(dbService, dbFile,
|
|
|
|
dbConnection);
|
|
|
|
}
|
2007-06-19 22:51:09 +04:00
|
|
|
|
2008-02-26 01:07:52 +03:00
|
|
|
// Get the version of the schema in the file.
|
|
|
|
var version = dbConnection.schemaVersion;
|
|
|
|
|
|
|
|
// Try to migrate the schema in the database to the current schema used by
|
|
|
|
// the service. If migration fails, back up the database and recreate it.
|
|
|
|
if (version != this._dbVersion) {
|
|
|
|
try {
|
2007-06-19 22:51:09 +04:00
|
|
|
this._dbMigrate(dbConnection, version, this._dbVersion);
|
|
|
|
}
|
2008-02-26 01:07:52 +03:00
|
|
|
catch(ex) {
|
|
|
|
Cu.reportError("error migrating DB: " + ex + "; backing up and recreating");
|
|
|
|
dbConnection = this._dbBackUpAndRecreate(dbService, dbFile, dbConnection);
|
|
|
|
}
|
2007-06-19 22:51:09 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-05-26 05:05:00 +04:00
|
|
|
// Turn off disk synchronization checking to reduce disk churn and speed up
|
|
|
|
// operations when prefs are changed rapidly (such as when a user repeatedly
|
|
|
|
// changes the value of the browser zoom setting for a site).
|
|
|
|
//
|
|
|
|
// Note: this could cause database corruption if the OS crashes or machine
|
|
|
|
// loses power before the data gets written to disk, but this is considered
|
|
|
|
// a reasonable risk for the not-so-critical data stored in this database.
|
|
|
|
//
|
|
|
|
// If you really don't want to take this risk, however, just set the
|
|
|
|
// toolkit.storage.synchronous pref to 1 (NORMAL synchronization) or 2
|
|
|
|
// (FULL synchronization), in which case mozStorageConnection::Initialize
|
|
|
|
// will use that value, and we won't override it here.
|
|
|
|
if (!this._prefSvc.prefHasUserValue("toolkit.storage.synchronous"))
|
|
|
|
dbConnection.executeSimpleSQL("PRAGMA synchronous = OFF");
|
|
|
|
|
2007-06-19 22:51:09 +04:00
|
|
|
this._dbConnection = dbConnection;
|
|
|
|
},
|
|
|
|
|
|
|
|
_dbCreate: function ContentPrefService__dbCreate(aDBService, aDBFile) {
|
2007-11-27 10:55:59 +03:00
|
|
|
var dbConnection = aDBService.openDatabase(aDBFile);
|
2008-02-26 01:07:52 +03:00
|
|
|
|
|
|
|
try {
|
|
|
|
this._dbCreateSchema(dbConnection);
|
|
|
|
dbConnection.schemaVersion = this._dbVersion;
|
|
|
|
}
|
|
|
|
catch(ex) {
|
|
|
|
// If we failed to create the database (perhaps because the disk ran out
|
|
|
|
// of space), then remove the database file so we don't leave it in some
|
|
|
|
// half-created state from which we won't know how to recover.
|
|
|
|
dbConnection.close();
|
|
|
|
aDBFile.remove(false);
|
|
|
|
throw ex;
|
|
|
|
}
|
|
|
|
|
2007-11-27 10:55:59 +03:00
|
|
|
return dbConnection;
|
|
|
|
},
|
|
|
|
|
2008-02-26 01:07:52 +03:00
|
|
|
_dbCreateSchema: function ContentPrefService__dbCreateSchema(aDBConnection) {
|
|
|
|
this._dbCreateTables(aDBConnection);
|
|
|
|
this._dbCreateIndices(aDBConnection);
|
|
|
|
},
|
|
|
|
|
|
|
|
_dbCreateTables: function ContentPrefService__dbCreateTables(aDBConnection) {
|
|
|
|
for (let name in this._dbSchema.tables)
|
|
|
|
aDBConnection.createTable(name, this._dbSchema.tables[name]);
|
|
|
|
},
|
|
|
|
|
2007-11-27 10:55:59 +03:00
|
|
|
_dbCreateIndices: function ContentPrefService__dbCreateIndices(aDBConnection) {
|
|
|
|
for (let name in this._dbSchema.indices) {
|
|
|
|
let index = this._dbSchema.indices[name];
|
2007-11-28 23:19:05 +03:00
|
|
|
let statement = "CREATE INDEX IF NOT EXISTS " + name + " ON " + index.table +
|
2007-11-27 10:55:59 +03:00
|
|
|
"(" + index.columns.join(", ") + ")";
|
|
|
|
aDBConnection.executeSimpleSQL(statement);
|
|
|
|
}
|
2007-06-19 22:51:09 +04:00
|
|
|
},
|
|
|
|
|
2008-02-26 01:07:52 +03:00
|
|
|
_dbBackUpAndRecreate: function ContentPrefService__dbBackUpAndRecreate(aDBService,
|
|
|
|
aDBFile,
|
|
|
|
aDBConnection) {
|
2008-03-25 01:14:38 +03:00
|
|
|
aDBService.backupDatabaseFile(aDBFile, "content-prefs.sqlite.corrupt");
|
2008-02-26 01:07:52 +03:00
|
|
|
|
|
|
|
// Close the database, ignoring the "already closed" exception, if any.
|
|
|
|
// It'll be open if we're here because of a migration failure but closed
|
|
|
|
// if we're here because of database corruption.
|
|
|
|
try { aDBConnection.close() } catch(ex) {}
|
|
|
|
|
|
|
|
aDBFile.remove(false);
|
|
|
|
|
|
|
|
let dbConnection = this._dbCreate(aDBService, aDBFile);
|
|
|
|
|
|
|
|
return dbConnection;
|
|
|
|
},
|
|
|
|
|
2007-06-19 22:51:09 +04:00
|
|
|
_dbMigrate: function ContentPrefService__dbMigrate(aDBConnection, aOldVersion, aNewVersion) {
|
|
|
|
if (this["_dbMigrate" + aOldVersion + "To" + aNewVersion]) {
|
|
|
|
aDBConnection.beginTransaction();
|
|
|
|
try {
|
|
|
|
this["_dbMigrate" + aOldVersion + "To" + aNewVersion](aDBConnection);
|
2007-11-28 23:19:05 +03:00
|
|
|
aDBConnection.schemaVersion = aNewVersion;
|
2007-06-19 22:51:09 +04:00
|
|
|
aDBConnection.commitTransaction();
|
|
|
|
}
|
|
|
|
catch(ex) {
|
|
|
|
aDBConnection.rollbackTransaction();
|
|
|
|
throw ex;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
2008-02-26 01:07:52 +03:00
|
|
|
throw("no migrator function from version " + aOldVersion +
|
|
|
|
" to version " + aNewVersion);
|
2007-06-19 22:51:09 +04:00
|
|
|
},
|
|
|
|
|
2008-02-26 01:07:52 +03:00
|
|
|
/**
|
|
|
|
* If the schema version is 0, that means it was never set, which means
|
|
|
|
* the database was somehow created without the schema being applied, perhaps
|
|
|
|
* because the system ran out of disk space (although we check for this
|
|
|
|
* in _createDB) or because some other code created the database file without
|
|
|
|
* applying the schema. In any case, recover by simply reapplying the schema.
|
|
|
|
*/
|
2007-11-27 10:55:59 +03:00
|
|
|
_dbMigrate0To3: function ContentPrefService___dbMigrate0To3(aDBConnection) {
|
2008-02-26 01:07:52 +03:00
|
|
|
this._dbCreateSchema(aDBConnection);
|
2007-06-19 22:51:09 +04:00
|
|
|
},
|
|
|
|
|
2007-11-27 10:55:59 +03:00
|
|
|
_dbMigrate1To3: function ContentPrefService___dbMigrate1To3(aDBConnection) {
|
2007-06-19 22:51:09 +04:00
|
|
|
aDBConnection.executeSimpleSQL("ALTER TABLE groups RENAME TO groupsOld");
|
2007-11-27 10:55:59 +03:00
|
|
|
aDBConnection.createTable("groups", this._dbSchema.tables.groups);
|
2007-06-19 22:51:09 +04:00
|
|
|
aDBConnection.executeSimpleSQL(
|
|
|
|
"INSERT INTO groups (id, name) " +
|
|
|
|
"SELECT id, name FROM groupsOld"
|
|
|
|
);
|
|
|
|
|
|
|
|
aDBConnection.executeSimpleSQL("DROP TABLE groupers");
|
|
|
|
aDBConnection.executeSimpleSQL("DROP TABLE groupsOld");
|
|
|
|
|
2007-11-27 10:55:59 +03:00
|
|
|
this._dbCreateIndices(aDBConnection);
|
|
|
|
},
|
|
|
|
|
|
|
|
_dbMigrate2To3: function ContentPrefService__dbMigrate2To3(aDBConnection) {
|
|
|
|
this._dbCreateIndices(aDBConnection);
|
2010-09-07 23:16:43 +04:00
|
|
|
},
|
|
|
|
|
|
|
|
_parseGroupParam: function ContentPrefService__parseGroupParam(aGroup) {
|
|
|
|
if (aGroup == null)
|
|
|
|
return null;
|
|
|
|
if (aGroup.constructor.name == "String")
|
|
|
|
return aGroup.toString();
|
|
|
|
if (aGroup instanceof Ci.nsIURI)
|
|
|
|
return this.grouper.group(aGroup);
|
2007-11-27 10:55:59 +03:00
|
|
|
|
2010-09-07 23:16:43 +04:00
|
|
|
throw Components.Exception("aGroup is not a string, nsIURI or null",
|
|
|
|
Cr.NS_ERROR_ILLEGAL_VALUE);
|
|
|
|
},
|
2007-06-19 22:51:09 +04:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
function HostnameGrouper() {}
|
|
|
|
|
|
|
|
HostnameGrouper.prototype = {
|
|
|
|
//**************************************************************************//
|
2007-07-11 23:04:04 +04:00
|
|
|
// XPCOM Plumbing
|
|
|
|
|
|
|
|
classID: Components.ID("{8df290ae-dcaa-4c11-98a5-2429a4dc97bb}"),
|
|
|
|
QueryInterface: XPCOMUtils.generateQI([Ci.nsIContentURIGrouper]),
|
2007-06-19 22:51:09 +04:00
|
|
|
|
|
|
|
//**************************************************************************//
|
|
|
|
// nsIContentURIGrouper
|
|
|
|
|
|
|
|
group: function HostnameGrouper_group(aURI) {
|
|
|
|
var group;
|
|
|
|
|
|
|
|
try {
|
|
|
|
// Accessing the host property of the URI will throw an exception
|
|
|
|
// if the URI is of a type that doesn't have a host property.
|
|
|
|
// Otherwise, we manually throw an exception if the host is empty,
|
|
|
|
// since the effect is the same (we can't derive a group from it).
|
|
|
|
|
|
|
|
group = aURI.host;
|
|
|
|
if (!group)
|
|
|
|
throw("can't derive group from host; no host in URI");
|
|
|
|
}
|
|
|
|
catch(ex) {
|
|
|
|
// If we don't have a host, then use the entire URI (minus the query,
|
|
|
|
// reference, and hash, if possible) as the group. This means that URIs
|
|
|
|
// like about:mozilla and about:blank will be considered separate groups,
|
|
|
|
// but at least they'll be grouped somehow.
|
|
|
|
|
|
|
|
// This also means that each individual file: URL will be considered
|
|
|
|
// its own group. This seems suboptimal, but so does treating the entire
|
|
|
|
// file: URL space as a single group (especially if folks start setting
|
|
|
|
// group-specific capabilities prefs).
|
|
|
|
|
|
|
|
// XXX Is there something better we can do here?
|
|
|
|
|
|
|
|
try {
|
|
|
|
var url = aURI.QueryInterface(Ci.nsIURL);
|
|
|
|
group = aURI.prePath + url.filePath;
|
|
|
|
}
|
|
|
|
catch(ex) {
|
|
|
|
group = aURI.spec;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return group;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2010-02-09 13:28:39 +03:00
|
|
|
function AsyncStatement(aStatement) {
|
|
|
|
this.stmt = aStatement;
|
|
|
|
}
|
|
|
|
|
|
|
|
AsyncStatement.prototype = {
|
|
|
|
execute: function AsyncStmt_execute(aCallback) {
|
|
|
|
let stmt = this.stmt;
|
|
|
|
stmt.executeAsync({
|
|
|
|
_callback: aCallback,
|
|
|
|
_hadResult: false,
|
|
|
|
handleResult: function(aResult) {
|
|
|
|
this._hadResult = true;
|
|
|
|
if (this._callback) {
|
|
|
|
let row = aResult.getNextRow();
|
|
|
|
this._callback.onResult(row.getResultByName("value"));
|
|
|
|
}
|
|
|
|
},
|
|
|
|
handleCompletion: function(aReason) {
|
|
|
|
if (!this._hadResult && this._callback &&
|
|
|
|
aReason == Ci.mozIStorageStatementCallback.REASON_FINISHED)
|
|
|
|
this._callback.onResult(undefined);
|
|
|
|
},
|
|
|
|
handleError: function(aError) {}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
};
|
2007-06-19 22:51:09 +04:00
|
|
|
|
2007-07-11 23:04:04 +04:00
|
|
|
//****************************************************************************//
|
|
|
|
// XPCOM Plumbing
|
2007-06-19 22:51:09 +04:00
|
|
|
|
2007-07-11 23:04:04 +04:00
|
|
|
var components = [ContentPrefService, HostnameGrouper];
|
2012-10-31 20:13:28 +04:00
|
|
|
this.NSGetFactory = XPCOMUtils.generateNSGetFactory(components);
|