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/. */
|
2009-01-07 00:54:18 +03:00
|
|
|
|
2011-01-19 03:23:20 +03:00
|
|
|
const EXPORTED_SYMBOLS = ["Clients", "ClientsRec"];
|
2009-01-07 00:54:18 +03:00
|
|
|
|
|
|
|
const Cc = Components.classes;
|
|
|
|
const Ci = Components.interfaces;
|
|
|
|
const Cu = Components.utils;
|
|
|
|
|
2012-04-06 10:26:06 +04:00
|
|
|
Cu.import("resource://services-common/stringbundle.js");
|
2010-06-17 01:30:08 +04:00
|
|
|
Cu.import("resource://services-sync/constants.js");
|
|
|
|
Cu.import("resource://services-sync/engines.js");
|
2011-01-19 03:23:30 +03:00
|
|
|
Cu.import("resource://services-sync/record.js");
|
2011-04-09 01:51:55 +04:00
|
|
|
Cu.import("resource://services-sync/resource.js");
|
2010-06-17 01:30:08 +04:00
|
|
|
Cu.import("resource://services-sync/util.js");
|
2011-08-05 03:19:02 +04:00
|
|
|
Cu.import("resource://services-sync/main.js");
|
2009-01-07 00:54:18 +03:00
|
|
|
|
2011-01-19 03:23:20 +03:00
|
|
|
const CLIENTS_TTL = 1814400; // 21 days
|
2011-01-15 00:22:20 +03:00
|
|
|
const CLIENTS_TTL_REFRESH = 604800; // 7 days
|
|
|
|
|
2011-01-19 03:23:20 +03:00
|
|
|
function ClientsRec(collection, id) {
|
|
|
|
CryptoWrapper.call(this, collection, id);
|
|
|
|
}
|
|
|
|
ClientsRec.prototype = {
|
|
|
|
__proto__: CryptoWrapper.prototype,
|
2011-06-13 22:42:18 +04:00
|
|
|
_logName: "Sync.Record.Clients",
|
2011-01-19 03:23:20 +03:00
|
|
|
ttl: CLIENTS_TTL
|
|
|
|
};
|
|
|
|
|
|
|
|
Utils.deferGetSet(ClientsRec, "cleartext", ["name", "type", "commands"]);
|
|
|
|
|
|
|
|
|
2011-05-20 05:08:35 +04:00
|
|
|
XPCOMUtils.defineLazyGetter(this, "Clients", function () {
|
|
|
|
return new ClientEngine();
|
|
|
|
});
|
2009-01-07 00:54:18 +03:00
|
|
|
|
|
|
|
function ClientEngine() {
|
2010-02-12 02:29:15 +03:00
|
|
|
SyncEngine.call(this, "Clients");
|
2010-02-12 02:25:31 +03:00
|
|
|
|
|
|
|
// Reset the client on every startup so that we fetch recent clients
|
|
|
|
this._resetClient();
|
2009-01-07 00:54:18 +03:00
|
|
|
}
|
|
|
|
ClientEngine.prototype = {
|
|
|
|
__proto__: SyncEngine.prototype,
|
|
|
|
_storeObj: ClientStore,
|
2010-03-17 02:39:08 +03:00
|
|
|
_recordObj: ClientsRec,
|
2011-07-27 08:48:50 +04:00
|
|
|
_trackerObj: ClientsTracker,
|
2010-03-17 02:39:08 +03:00
|
|
|
|
2010-05-06 04:16:17 +04:00
|
|
|
// Always sync client data as it controls other sync behavior
|
|
|
|
get enabled() true,
|
|
|
|
|
2011-01-15 00:22:20 +03:00
|
|
|
get lastRecordUpload() {
|
|
|
|
return Svc.Prefs.get(this.name + ".lastRecordUpload", 0);
|
|
|
|
},
|
|
|
|
set lastRecordUpload(value) {
|
|
|
|
Svc.Prefs.set(this.name + ".lastRecordUpload", Math.floor(value));
|
|
|
|
},
|
|
|
|
|
2010-03-17 02:39:08 +03:00
|
|
|
// Aggregate some stats on the composition of clients on this account
|
|
|
|
get stats() {
|
|
|
|
let stats = {
|
|
|
|
hasMobile: this.localType == "mobile",
|
|
|
|
names: [this.localName],
|
|
|
|
numClients: 1,
|
|
|
|
};
|
|
|
|
|
|
|
|
for each (let {name, type} in this._store._remoteClients) {
|
|
|
|
stats.hasMobile = stats.hasMobile || type == "mobile";
|
|
|
|
stats.names.push(name);
|
|
|
|
stats.numClients++;
|
|
|
|
}
|
2009-01-24 02:09:21 +03:00
|
|
|
|
2010-03-17 02:39:08 +03:00
|
|
|
return stats;
|
2009-01-24 02:09:21 +03:00
|
|
|
},
|
|
|
|
|
2010-03-17 02:39:08 +03:00
|
|
|
get localID() {
|
|
|
|
// Generate a random GUID id we don't have one
|
|
|
|
let localID = Svc.Prefs.get("client.GUID", "");
|
|
|
|
return localID == "" ? this.localID = Utils.makeGUID() : localID;
|
2009-01-24 02:09:21 +03:00
|
|
|
},
|
2010-03-17 02:39:08 +03:00
|
|
|
set localID(value) Svc.Prefs.set("client.GUID", value),
|
2009-01-24 02:09:21 +03:00
|
|
|
|
2010-03-17 02:39:08 +03:00
|
|
|
get localName() {
|
|
|
|
let localName = Svc.Prefs.get("client.name", "");
|
|
|
|
if (localName != "")
|
|
|
|
return localName;
|
2009-11-20 10:31:04 +03:00
|
|
|
|
|
|
|
// Generate a client name if we don't have a useful one yet
|
2011-05-20 05:08:35 +04:00
|
|
|
let env = Cc["@mozilla.org/process/environment;1"]
|
|
|
|
.getService(Ci.nsIEnvironment);
|
|
|
|
let user = env.get("USER") || env.get("USERNAME") ||
|
2010-10-14 12:59:08 +04:00
|
|
|
Svc.Prefs.get("account") || Svc.Prefs.get("username");
|
2010-06-11 22:36:51 +04:00
|
|
|
let brand = new StringBundle("chrome://branding/locale/brand.properties");
|
|
|
|
let app = brand.get("brandShortName");
|
|
|
|
|
2011-05-20 05:08:35 +04:00
|
|
|
let system = Cc["@mozilla.org/system-info;1"]
|
|
|
|
.getService(Ci.nsIPropertyBag2).get("device") ||
|
2010-09-08 22:55:57 +04:00
|
|
|
Cc["@mozilla.org/network/protocol;1?name=http"]
|
|
|
|
.getService(Ci.nsIHttpProtocolHandler).oscpu;
|
|
|
|
|
|
|
|
return this.localName = Str.sync.get("client.name2", [user, app, system]);
|
2009-11-20 10:31:04 +03:00
|
|
|
},
|
2010-03-17 02:39:08 +03:00
|
|
|
set localName(value) Svc.Prefs.set("client.name", value),
|
|
|
|
|
2010-06-17 02:11:40 +04:00
|
|
|
get localType() Svc.Prefs.get("client.type", "desktop"),
|
2010-03-17 02:39:08 +03:00
|
|
|
set localType(value) Svc.Prefs.set("client.type", value),
|
2009-02-27 09:36:14 +03:00
|
|
|
|
2010-03-13 03:14:09 +03:00
|
|
|
isMobile: function isMobile(id) {
|
2010-04-29 06:20:08 +04:00
|
|
|
if (this._store._remoteClients[id])
|
|
|
|
return this._store._remoteClients[id].type == "mobile";
|
|
|
|
return false;
|
2010-03-13 03:14:09 +03:00
|
|
|
},
|
|
|
|
|
2011-01-15 00:22:20 +03:00
|
|
|
_syncStartup: function _syncStartup() {
|
|
|
|
// Reupload new client record periodically.
|
|
|
|
if (Date.now() / 1000 - this.lastRecordUpload > CLIENTS_TTL_REFRESH) {
|
|
|
|
this._tracker.addChangedID(this.localID);
|
|
|
|
this.lastRecordUpload = Date.now() / 1000;
|
|
|
|
}
|
|
|
|
SyncEngine.prototype._syncStartup.call(this);
|
|
|
|
},
|
|
|
|
|
2009-12-11 05:39:51 +03:00
|
|
|
// Always process incoming items because they might have commands
|
|
|
|
_reconcile: function _reconcile() {
|
|
|
|
return true;
|
|
|
|
},
|
|
|
|
|
2010-02-20 00:36:42 +03:00
|
|
|
// Treat reset the same as wiping for locally cached clients
|
|
|
|
_resetClient: function _resetClient() this._wipeClient(),
|
|
|
|
|
|
|
|
_wipeClient: function _wipeClient() {
|
2009-12-03 01:44:17 +03:00
|
|
|
SyncEngine.prototype._resetClient.call(this);
|
2009-02-27 09:36:14 +03:00
|
|
|
this._store.wipe();
|
2011-03-01 22:56:29 +03:00
|
|
|
},
|
2011-04-09 01:51:55 +04:00
|
|
|
|
|
|
|
removeClientData: function removeClientData() {
|
|
|
|
let res = new Resource(this.engineURL + "/" + this.localID);
|
|
|
|
res.delete();
|
|
|
|
},
|
|
|
|
|
2011-03-01 22:56:29 +03:00
|
|
|
// Override the default behavior to delete bad records from the server.
|
2011-03-21 02:10:40 +03:00
|
|
|
handleHMACMismatch: function handleHMACMismatch(item, mayRetry) {
|
2011-03-01 22:56:29 +03:00
|
|
|
this._log.debug("Handling HMAC mismatch for " + item.id);
|
2011-07-27 08:48:50 +04:00
|
|
|
|
2011-03-21 02:10:40 +03:00
|
|
|
let base = SyncEngine.prototype.handleHMACMismatch.call(this, item, mayRetry);
|
|
|
|
if (base != SyncEngine.kRecoveryStrategy.error)
|
|
|
|
return base;
|
2011-03-01 22:56:29 +03:00
|
|
|
|
|
|
|
// It's a bad client record. Save it to be deleted at the end of the sync.
|
|
|
|
this._log.debug("Bad client record detected. Scheduling for deletion.");
|
|
|
|
this._deleteId(item.id);
|
|
|
|
|
2011-03-21 02:10:40 +03:00
|
|
|
// Neither try again nor error; we're going to delete it.
|
|
|
|
return SyncEngine.kRecoveryStrategy.ignore;
|
2011-08-05 03:19:02 +04:00
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* A hash of valid commands that the client knows about. The key is a command
|
|
|
|
* and the value is a hash containing information about the command such as
|
|
|
|
* number of arguments and description.
|
|
|
|
*/
|
|
|
|
_commands: {
|
|
|
|
resetAll: { args: 0, desc: "Clear temporary local data for all engines" },
|
|
|
|
resetEngine: { args: 1, desc: "Clear temporary local data for engine" },
|
|
|
|
wipeAll: { args: 0, desc: "Delete all client data for all engines" },
|
|
|
|
wipeEngine: { args: 1, desc: "Delete all client data for engine" },
|
2011-08-09 20:23:55 +04:00
|
|
|
logout: { args: 0, desc: "Log out client" },
|
2012-03-27 21:13:52 +04:00
|
|
|
displayURI: { args: 3, desc: "Instruct a client to display a URI" },
|
2011-08-05 03:19:02 +04:00
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Remove any commands for the local client and mark it for upload.
|
|
|
|
*/
|
|
|
|
clearCommands: function clearCommands() {
|
|
|
|
delete this.localCommands;
|
|
|
|
this._tracker.addChangedID(this.localID);
|
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Sends a command+args pair to a specific client.
|
|
|
|
*
|
|
|
|
* @param command Command string
|
|
|
|
* @param args Array of arguments/data for command
|
|
|
|
* @param clientId Client to send command to
|
|
|
|
*/
|
|
|
|
_sendCommandToClient: function sendCommandToClient(command, args, clientId) {
|
|
|
|
this._log.trace("Sending " + command + " to " + clientId);
|
|
|
|
|
|
|
|
let client = this._store._remoteClients[clientId];
|
|
|
|
if (!client) {
|
|
|
|
throw new Error("Unknown remote client ID: '" + clientId + "'.");
|
|
|
|
}
|
|
|
|
|
|
|
|
// notDupe compares two commands and returns if they are not equal.
|
|
|
|
let notDupe = function(other) {
|
|
|
|
return other.command != command || !Utils.deepEquals(other.args, args);
|
|
|
|
};
|
|
|
|
|
|
|
|
let action = {
|
|
|
|
command: command,
|
|
|
|
args: args,
|
|
|
|
};
|
|
|
|
|
|
|
|
if (!client.commands) {
|
|
|
|
client.commands = [action];
|
|
|
|
}
|
|
|
|
// Add the new action if there are no duplicates.
|
|
|
|
else if (client.commands.every(notDupe)) {
|
|
|
|
client.commands.push(action);
|
|
|
|
}
|
|
|
|
// It must be a dupe. Skip.
|
|
|
|
else {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
this._log.trace("Client " + clientId + " got a new action: " + [command, args]);
|
|
|
|
this._tracker.addChangedID(clientId);
|
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Check if the local client has any remote commands and perform them.
|
|
|
|
*
|
|
|
|
* @return false to abort sync
|
|
|
|
*/
|
|
|
|
processIncomingCommands: function processIncomingCommands() {
|
2011-08-06 03:01:49 +04:00
|
|
|
return this._notify("clients:process-commands", "", function() {
|
2011-08-05 03:19:02 +04:00
|
|
|
let commands = this.localCommands;
|
|
|
|
|
|
|
|
// Immediately clear out the commands as we've got them locally.
|
|
|
|
this.clearCommands();
|
|
|
|
|
|
|
|
// Process each command in order.
|
|
|
|
for each ({command: command, args: args} in commands) {
|
|
|
|
this._log.debug("Processing command: " + command + "(" + args + ")");
|
|
|
|
|
|
|
|
let engines = [args[0]];
|
|
|
|
switch (command) {
|
|
|
|
case "resetAll":
|
|
|
|
engines = null;
|
|
|
|
// Fallthrough
|
|
|
|
case "resetEngine":
|
|
|
|
Weave.Service.resetClient(engines);
|
|
|
|
break;
|
|
|
|
case "wipeAll":
|
|
|
|
engines = null;
|
|
|
|
// Fallthrough
|
|
|
|
case "wipeEngine":
|
|
|
|
Weave.Service.wipeClient(engines);
|
|
|
|
break;
|
|
|
|
case "logout":
|
|
|
|
Weave.Service.logout();
|
|
|
|
return false;
|
2011-08-09 20:23:55 +04:00
|
|
|
case "displayURI":
|
2012-03-28 23:53:57 +04:00
|
|
|
this._handleDisplayURI.apply(this, args);
|
2011-08-09 20:23:55 +04:00
|
|
|
break;
|
2011-08-05 03:19:02 +04:00
|
|
|
default:
|
|
|
|
this._log.debug("Received an unknown command: " + command);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
})();
|
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Validates and sends a command to a client or all clients.
|
|
|
|
*
|
|
|
|
* Calling this does not actually sync the command data to the server. If the
|
|
|
|
* client already has the command/args pair, it won't receive a duplicate
|
|
|
|
* command.
|
|
|
|
*
|
|
|
|
* @param command
|
|
|
|
* Command to invoke on remote clients
|
|
|
|
* @param args
|
|
|
|
* Array of arguments to give to the command
|
|
|
|
* @param clientId
|
|
|
|
* Client ID to send command to. If undefined, send to all remote
|
|
|
|
* clients.
|
|
|
|
*/
|
|
|
|
sendCommand: function sendCommand(command, args, clientId) {
|
|
|
|
let commandData = this._commands[command];
|
|
|
|
// Don't send commands that we don't know about.
|
|
|
|
if (!commandData) {
|
|
|
|
this._log.error("Unknown command to send: " + command);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
// Don't send a command with the wrong number of arguments.
|
|
|
|
else if (!args || args.length != commandData.args) {
|
|
|
|
this._log.error("Expected " + commandData.args + " args for '" +
|
|
|
|
command + "', but got " + args);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (clientId) {
|
|
|
|
this._sendCommandToClient(command, args, clientId);
|
|
|
|
} else {
|
|
|
|
for (let id in this._store._remoteClients) {
|
|
|
|
this._sendCommandToClient(command, args, id);
|
|
|
|
}
|
|
|
|
}
|
2011-08-09 20:23:55 +04:00
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Send a URI to another client for display.
|
|
|
|
*
|
|
|
|
* A side effect is the score is increased dramatically to incur an
|
|
|
|
* immediate sync.
|
|
|
|
*
|
|
|
|
* If an unknown client ID is specified, sendCommand() will throw an
|
|
|
|
* Error object.
|
|
|
|
*
|
|
|
|
* @param uri
|
|
|
|
* URI (as a string) to send and display on the remote client
|
|
|
|
* @param clientId
|
|
|
|
* ID of client to send the command to. If not defined, will be sent
|
|
|
|
* to all remote clients.
|
2012-03-27 21:13:52 +04:00
|
|
|
* @param title
|
|
|
|
* Title of the page being sent.
|
2011-08-09 20:23:55 +04:00
|
|
|
*/
|
2012-03-27 21:13:52 +04:00
|
|
|
sendURIToClientForDisplay: function sendURIToClientForDisplay(uri, clientId, title) {
|
|
|
|
this._log.info("Sending URI to client: " + uri + " -> " +
|
|
|
|
clientId + " (" + title + ")");
|
|
|
|
this.sendCommand("displayURI", [uri, this.localID, title], clientId);
|
2011-08-09 20:23:55 +04:00
|
|
|
|
|
|
|
Clients._tracker.score += SCORE_INCREMENT_XLARGE;
|
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Handle a single received 'displayURI' command.
|
|
|
|
*
|
|
|
|
* Interested parties should observe the "weave:engine:clients:display-uri"
|
|
|
|
* topic. The callback will receive an object as the subject parameter with
|
|
|
|
* the following keys:
|
|
|
|
*
|
2012-03-28 23:53:57 +04:00
|
|
|
* uri URI (string) that is requested for display.
|
|
|
|
* clientId ID of client that sent the command.
|
|
|
|
* title Title of page that loaded URI (likely) corresponds to.
|
2011-08-09 20:23:55 +04:00
|
|
|
*
|
|
|
|
* The 'data' parameter to the callback will not be defined.
|
|
|
|
*
|
|
|
|
* @param uri
|
|
|
|
* String URI that was received
|
|
|
|
* @param clientId
|
|
|
|
* ID of client that sent URI
|
2012-03-28 23:53:57 +04:00
|
|
|
* @param title
|
|
|
|
* String title of page that URI corresponds to. Older clients may not
|
|
|
|
* send this.
|
2011-08-09 20:23:55 +04:00
|
|
|
*/
|
2012-03-28 23:53:57 +04:00
|
|
|
_handleDisplayURI: function _handleDisplayURI(uri, clientId, title) {
|
|
|
|
this._log.info("Received a URI for display: " + uri + " (" + title +
|
|
|
|
") from " + clientId);
|
2011-08-09 20:23:55 +04:00
|
|
|
|
2012-03-28 23:53:57 +04:00
|
|
|
let subject = {uri: uri, client: clientId, title: title};
|
2011-08-09 20:23:55 +04:00
|
|
|
Svc.Obs.notify("weave:engine:clients:display-uri", subject);
|
2009-02-27 02:06:57 +03:00
|
|
|
}
|
2009-01-07 00:54:18 +03:00
|
|
|
};
|
|
|
|
|
2010-02-12 02:29:15 +03:00
|
|
|
function ClientStore(name) {
|
|
|
|
Store.call(this, name);
|
2009-01-07 00:54:18 +03:00
|
|
|
}
|
|
|
|
ClientStore.prototype = {
|
|
|
|
__proto__: Store.prototype,
|
|
|
|
|
2010-03-17 02:39:08 +03:00
|
|
|
create: function create(record) this.update(record),
|
2009-04-01 10:56:32 +04:00
|
|
|
|
2010-03-17 02:39:08 +03:00
|
|
|
update: function update(record) {
|
2010-05-06 04:16:17 +04:00
|
|
|
// Only grab commands from the server; local name/type always wins
|
|
|
|
if (record.id == Clients.localID)
|
2010-03-17 02:39:08 +03:00
|
|
|
Clients.localCommands = record.commands;
|
|
|
|
else
|
|
|
|
this._remoteClients[record.id] = record.cleartext;
|
2009-01-07 00:54:18 +03:00
|
|
|
},
|
|
|
|
|
2010-11-30 03:41:17 +03:00
|
|
|
createRecord: function createRecord(id, collection) {
|
|
|
|
let record = new ClientsRec(collection, id);
|
2009-02-20 12:52:07 +03:00
|
|
|
|
2010-03-17 02:39:08 +03:00
|
|
|
// Package the individual components into a record for the local client
|
2010-11-30 03:41:17 +03:00
|
|
|
if (id == Clients.localID) {
|
2010-03-17 02:39:08 +03:00
|
|
|
record.name = Clients.localName;
|
|
|
|
record.type = Clients.localType;
|
|
|
|
record.commands = Clients.localCommands;
|
|
|
|
}
|
|
|
|
else
|
2010-11-30 03:41:17 +03:00
|
|
|
record.cleartext = this._remoteClients[id];
|
2009-01-07 00:54:18 +03:00
|
|
|
|
2009-04-01 10:56:32 +04:00
|
|
|
return record;
|
2009-01-07 00:54:18 +03:00
|
|
|
},
|
|
|
|
|
2010-03-17 02:39:08 +03:00
|
|
|
itemExists: function itemExists(id) id in this.getAllIDs(),
|
2009-01-07 00:54:18 +03:00
|
|
|
|
2010-03-17 02:39:08 +03:00
|
|
|
getAllIDs: function getAllIDs() {
|
|
|
|
let ids = {};
|
|
|
|
ids[Clients.localID] = true;
|
|
|
|
for (let id in this._remoteClients)
|
|
|
|
ids[id] = true;
|
|
|
|
return ids;
|
2009-01-07 00:54:18 +03:00
|
|
|
},
|
|
|
|
|
2010-03-17 02:39:08 +03:00
|
|
|
wipe: function wipe() {
|
|
|
|
this._remoteClients = {};
|
2009-04-01 10:56:32 +04:00
|
|
|
},
|
2009-01-07 00:54:18 +03:00
|
|
|
};
|
2011-07-27 08:48:50 +04:00
|
|
|
|
|
|
|
function ClientsTracker(name) {
|
|
|
|
Tracker.call(this, name);
|
|
|
|
Svc.Obs.add("weave:engine:start-tracking", this);
|
|
|
|
Svc.Obs.add("weave:engine:stop-tracking", this);
|
|
|
|
}
|
|
|
|
ClientsTracker.prototype = {
|
|
|
|
__proto__: Tracker.prototype,
|
|
|
|
|
|
|
|
_enabled: false,
|
|
|
|
|
|
|
|
observe: function observe(subject, topic, data) {
|
|
|
|
switch (topic) {
|
|
|
|
case "weave:engine:start-tracking":
|
|
|
|
if (!this._enabled) {
|
|
|
|
Svc.Prefs.observe("client.name", this);
|
|
|
|
this._enabled = true;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case "weave:engine:stop-tracking":
|
|
|
|
if (this._enabled) {
|
|
|
|
Svc.Prefs.ignore("clients.name", this);
|
|
|
|
this._enabled = false;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case "nsPref:changed":
|
|
|
|
this._log.debug("client.name preference changed");
|
|
|
|
this.addChangedID(Svc.Prefs.get("client.GUID"));
|
|
|
|
this.score += SCORE_INCREMENT_XLARGE;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|