2012-02-28 22:01:48 +00: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/. */
|
|
|
|
|
2012-07-03 18:00:53 +00:00
|
|
|
"use strict";
|
2012-02-28 22:01:48 +00:00
|
|
|
|
2013-07-02 06:14:32 +00:00
|
|
|
const DEBUG = false;
|
2012-08-22 21:34:57 +00:00
|
|
|
function debug(s) { dump("-*- Fallback ContactService component: " + s + "\n"); }
|
2012-02-28 22:01:48 +00:00
|
|
|
|
2013-02-03 12:05:51 +00:00
|
|
|
const Cu = Components.utils;
|
2012-02-28 22:01:48 +00:00
|
|
|
const Cc = Components.classes;
|
|
|
|
const Ci = Components.interfaces;
|
|
|
|
|
2013-03-29 07:52:48 +00:00
|
|
|
this.EXPORTED_SYMBOLS = [];
|
|
|
|
|
2012-02-28 22:01:48 +00:00
|
|
|
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
|
|
|
Cu.import("resource://gre/modules/Services.jsm");
|
|
|
|
Cu.import("resource://gre/modules/ContactDB.jsm");
|
2013-06-13 22:00:23 +00:00
|
|
|
Cu.import("resource://gre/modules/PhoneNumberUtils.jsm");
|
2012-02-28 22:01:48 +00:00
|
|
|
|
2012-08-27 14:13:02 +00:00
|
|
|
XPCOMUtils.defineLazyServiceGetter(this, "ppmm",
|
|
|
|
"@mozilla.org/parentprocessmessagemanager;1",
|
|
|
|
"nsIMessageListenerManager");
|
2012-03-07 21:45:24 +00:00
|
|
|
|
2012-02-28 22:01:48 +00:00
|
|
|
let myGlobal = this;
|
|
|
|
|
2013-03-29 07:04:45 +00:00
|
|
|
let ContactService = {
|
2012-02-28 22:01:48 +00:00
|
|
|
init: function() {
|
2012-08-22 21:34:57 +00:00
|
|
|
if (DEBUG) debug("Init");
|
2013-03-27 22:24:15 +00:00
|
|
|
this._messages = ["Contacts:Find", "Contacts:GetAll", "Contacts:GetAll:SendNow",
|
|
|
|
"Contacts:Clear", "Contact:Save",
|
2013-03-06 02:45:07 +00:00
|
|
|
"Contact:Remove", "Contacts:RegisterForMessages",
|
2013-06-04 03:45:10 +00:00
|
|
|
"child-process-shutdown", "Contacts:GetRevision",
|
|
|
|
"Contacts:GetCount"];
|
2013-02-01 20:44:55 +00:00
|
|
|
this._children = [];
|
2013-05-21 18:19:06 +00:00
|
|
|
this._cursors = {};
|
2013-02-03 12:05:51 +00:00
|
|
|
this._messages.forEach(function(msgName) {
|
2012-03-07 21:45:24 +00:00
|
|
|
ppmm.addMessageListener(msgName, this);
|
2013-02-03 12:05:51 +00:00
|
|
|
}.bind(this));
|
2012-02-28 22:01:48 +00:00
|
|
|
|
|
|
|
var idbManager = Components.classes["@mozilla.org/dom/indexeddb/manager;1"].getService(Ci.nsIIndexedDatabaseManager);
|
|
|
|
idbManager.initWindowless(myGlobal);
|
|
|
|
this._db = new ContactDB(myGlobal);
|
2012-04-26 22:10:04 +00:00
|
|
|
this._db.init(myGlobal);
|
2012-02-28 22:01:48 +00:00
|
|
|
|
2013-06-13 22:00:23 +00:00
|
|
|
let countryName = PhoneNumberUtils.getCountryName();
|
|
|
|
if (Services.prefs.getPrefType("dom.phonenumber.substringmatching." + countryName) == Ci.nsIPrefBranch.PREF_INT) {
|
|
|
|
if (DEBUG) debug("Enable Substring Matching for Phone Numbers: " + countryName);
|
|
|
|
let val = Services.prefs.getIntPref("dom.phonenumber.substringmatching." + countryName);
|
|
|
|
if (val && val > 0) {
|
|
|
|
this._db.enableSubstringMatching(val);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-02-28 22:01:48 +00:00
|
|
|
Services.obs.addObserver(this, "profile-before-change", false);
|
2013-06-13 22:00:23 +00:00
|
|
|
Services.prefs.addObserver("dom.phonenumber.substringmatching", this, false);
|
2012-02-28 22:01:48 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
observe: function(aSubject, aTopic, aData) {
|
2013-07-02 06:14:32 +00:00
|
|
|
if (aTopic === 'profile-before-change') {
|
2013-06-13 22:00:23 +00:00
|
|
|
myGlobal = null;
|
|
|
|
this._messages.forEach(function(msgName) {
|
|
|
|
ppmm.removeMessageListener(msgName, this);
|
|
|
|
}.bind(this));
|
|
|
|
Services.obs.removeObserver(this, "profile-before-change");
|
|
|
|
Services.prefs.removeObserver("dom.phonenumber.substringmatching", this);
|
|
|
|
ppmm = null;
|
|
|
|
this._messages = null;
|
|
|
|
if (this._db)
|
|
|
|
this._db.close();
|
|
|
|
this._db = null;
|
|
|
|
this._children = null;
|
|
|
|
this._cursors = null;
|
2013-07-02 06:14:32 +00:00
|
|
|
} else if (aTopic === 'nsPref:changed' && aData.contains("dom.phonenumber.substringmatching")) {
|
2013-06-13 22:00:23 +00:00
|
|
|
// We don't fully support changing substringMatching during runtime. This is mostly for testing.
|
|
|
|
let countryName = PhoneNumberUtils.getCountryName();
|
|
|
|
if (Services.prefs.getPrefType("dom.phonenumber.substringmatching." + countryName) == Ci.nsIPrefBranch.PREF_INT) {
|
|
|
|
let val = Services.prefs.getIntPref("dom.phonenumber.substringmatching." + countryName);
|
|
|
|
if (val && val > 0) {
|
|
|
|
this._db.enableSubstringMatching(val);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2012-02-28 22:01:48 +00:00
|
|
|
},
|
|
|
|
|
2012-11-01 00:26:05 +00:00
|
|
|
assertPermission: function(aMessage, aPerm) {
|
|
|
|
if (!aMessage.target.assertPermission(aPerm)) {
|
2013-02-03 12:05:51 +00:00
|
|
|
Cu.reportError("Contacts message " + aMessage.name +
|
2012-11-01 00:26:05 +00:00
|
|
|
" from a content process with no" + aPerm + " privileges.");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
},
|
|
|
|
|
2013-02-01 20:44:55 +00:00
|
|
|
broadcastMessage: function broadcastMessage(aMsgName, aContent) {
|
|
|
|
this._children.forEach(function(msgMgr) {
|
|
|
|
msgMgr.sendAsyncMessage(aMsgName, aContent);
|
|
|
|
});
|
|
|
|
},
|
|
|
|
|
2012-02-28 22:01:48 +00:00
|
|
|
receiveMessage: function(aMessage) {
|
2013-02-03 12:05:51 +00:00
|
|
|
if (DEBUG) debug("receiveMessage " + aMessage.name);
|
2012-08-27 14:13:02 +00:00
|
|
|
let mm = aMessage.target;
|
2012-08-09 18:34:57 +00:00
|
|
|
let msg = aMessage.data;
|
2012-05-23 23:58:47 +00:00
|
|
|
|
2012-02-28 22:01:48 +00:00
|
|
|
switch (aMessage.name) {
|
|
|
|
case "Contacts:Find":
|
2012-11-01 00:26:05 +00:00
|
|
|
if (!this.assertPermission(aMessage, "contacts-read")) {
|
|
|
|
return null;
|
|
|
|
}
|
2013-02-03 12:05:51 +00:00
|
|
|
let result = [];
|
2012-02-28 22:01:48 +00:00
|
|
|
this._db.find(
|
|
|
|
function(contacts) {
|
2013-02-03 12:05:51 +00:00
|
|
|
for (let i in contacts) {
|
2012-02-28 22:01:48 +00:00
|
|
|
result.push(contacts[i]);
|
2012-04-02 23:39:57 +00:00
|
|
|
}
|
|
|
|
|
2012-08-22 21:34:57 +00:00
|
|
|
if (DEBUG) debug("result:" + JSON.stringify(result));
|
2012-07-25 17:27:27 +00:00
|
|
|
mm.sendAsyncMessage("Contacts:Find:Return:OK", {requestID: msg.requestID, contacts: result});
|
2012-02-28 22:01:48 +00:00
|
|
|
}.bind(this),
|
2013-02-03 12:05:51 +00:00
|
|
|
function(aErrorMsg) { mm.sendAsyncMessage("Contacts:Find:Return:KO", { requestID: msg.requestID, errorMsg: aErrorMsg }); }.bind(this),
|
2012-08-09 18:34:57 +00:00
|
|
|
msg.options.findOptions);
|
2012-02-28 22:01:48 +00:00
|
|
|
break;
|
2013-02-03 12:05:51 +00:00
|
|
|
case "Contacts:GetAll":
|
|
|
|
if (!this.assertPermission(aMessage, "contacts-read")) {
|
|
|
|
return null;
|
|
|
|
}
|
2013-05-21 18:19:06 +00:00
|
|
|
if (!this._cursors[mm]) {
|
|
|
|
this._cursors[mm] = [];
|
|
|
|
}
|
|
|
|
this._cursors[mm].push(msg.cursorId);
|
|
|
|
|
2013-02-03 12:05:51 +00:00
|
|
|
this._db.getAll(
|
2013-02-23 11:41:41 +00:00
|
|
|
function(aContacts) {
|
2013-04-23 12:06:40 +00:00
|
|
|
try {
|
|
|
|
mm.sendAsyncMessage("Contacts:GetAll:Next", {cursorId: msg.cursorId, contacts: aContacts});
|
2013-05-21 18:19:06 +00:00
|
|
|
if (aContacts === null) {
|
|
|
|
let index = this._cursors[mm].indexOf(msg.cursorId);
|
|
|
|
this._cursors[mm].splice(index, 1);
|
|
|
|
}
|
2013-04-23 12:06:40 +00:00
|
|
|
} catch (e) {
|
|
|
|
if (DEBUG) debug("Child is dead, DB should stop sending contacts");
|
|
|
|
throw e;
|
|
|
|
}
|
2013-05-21 18:19:06 +00:00
|
|
|
}.bind(this),
|
2013-06-04 21:23:19 +00:00
|
|
|
function(aErrorMsg) { mm.sendAsyncMessage("Contacts:Find:Return:KO", { requestID: msg.cursorId, errorMsg: aErrorMsg }); },
|
2013-03-27 22:24:15 +00:00
|
|
|
msg.findOptions, msg.cursorId);
|
|
|
|
break;
|
|
|
|
case "Contacts:GetAll:SendNow":
|
|
|
|
// sendNow is a no op if there isn't an existing cursor in the DB, so we
|
|
|
|
// don't need to assert the permission again.
|
|
|
|
this._db.sendNow(msg.cursorId);
|
2013-02-03 12:05:51 +00:00
|
|
|
break;
|
2012-02-28 22:01:48 +00:00
|
|
|
case "Contact:Save":
|
2012-11-01 00:26:05 +00:00
|
|
|
if (msg.options.reason === "create") {
|
|
|
|
if (!this.assertPermission(aMessage, "contacts-create")) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (!this.assertPermission(aMessage, "contacts-write")) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
}
|
2012-05-08 18:42:41 +00:00
|
|
|
this._db.saveContact(
|
2012-08-09 18:34:57 +00:00
|
|
|
msg.options.contact,
|
2013-02-01 20:44:55 +00:00
|
|
|
function() {
|
|
|
|
mm.sendAsyncMessage("Contact:Save:Return:OK", { requestID: msg.requestID, contactID: msg.options.contact.id });
|
|
|
|
this.broadcastMessage("Contact:Changed", { contactID: msg.options.contact.id, reason: msg.options.reason });
|
|
|
|
}.bind(this),
|
2012-07-25 17:27:27 +00:00
|
|
|
function(aErrorMsg) { mm.sendAsyncMessage("Contact:Save:Return:KO", { requestID: msg.requestID, errorMsg: aErrorMsg }); }.bind(this)
|
2012-05-08 18:42:41 +00:00
|
|
|
);
|
2012-02-28 22:01:48 +00:00
|
|
|
break;
|
|
|
|
case "Contact:Remove":
|
2012-11-01 00:26:05 +00:00
|
|
|
if (!this.assertPermission(aMessage, "contacts-write")) {
|
|
|
|
return null;
|
|
|
|
}
|
2012-05-08 18:42:41 +00:00
|
|
|
this._db.removeContact(
|
2012-08-09 18:34:57 +00:00
|
|
|
msg.options.id,
|
2013-02-01 20:44:55 +00:00
|
|
|
function() {
|
|
|
|
mm.sendAsyncMessage("Contact:Remove:Return:OK", { requestID: msg.requestID, contactID: msg.options.id });
|
|
|
|
this.broadcastMessage("Contact:Changed", { contactID: msg.options.id, reason: "remove" });
|
|
|
|
}.bind(this),
|
2012-07-25 17:27:27 +00:00
|
|
|
function(aErrorMsg) { mm.sendAsyncMessage("Contact:Remove:Return:KO", { requestID: msg.requestID, errorMsg: aErrorMsg }); }.bind(this)
|
2012-05-08 18:42:41 +00:00
|
|
|
);
|
2012-02-28 22:01:48 +00:00
|
|
|
break;
|
|
|
|
case "Contacts:Clear":
|
2012-11-01 00:26:05 +00:00
|
|
|
if (!this.assertPermission(aMessage, "contacts-write")) {
|
|
|
|
return null;
|
|
|
|
}
|
2012-05-08 18:42:41 +00:00
|
|
|
this._db.clear(
|
2013-02-01 20:44:55 +00:00
|
|
|
function() {
|
|
|
|
mm.sendAsyncMessage("Contacts:Clear:Return:OK", { requestID: msg.requestID });
|
|
|
|
this.broadcastMessage("Contact:Changed", { reason: "remove" });
|
|
|
|
}.bind(this),
|
2012-07-25 17:27:27 +00:00
|
|
|
function(aErrorMsg) { mm.sendAsyncMessage("Contacts:Clear:Return:KO", { requestID: msg.requestID, errorMsg: aErrorMsg }); }.bind(this)
|
2012-05-08 18:42:41 +00:00
|
|
|
);
|
2012-08-31 13:54:48 +00:00
|
|
|
break;
|
2013-04-25 17:15:47 +00:00
|
|
|
case "Contacts:GetRevision":
|
|
|
|
if (!this.assertPermission(aMessage, "contacts-read")) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
this._db.getRevision(
|
|
|
|
function(revision) {
|
|
|
|
mm.sendAsyncMessage("Contacts:Revision", {
|
|
|
|
requestID: msg.requestID,
|
|
|
|
revision: revision
|
|
|
|
});
|
|
|
|
}
|
|
|
|
);
|
|
|
|
break;
|
2013-06-04 03:45:10 +00:00
|
|
|
case "Contacts:GetCount":
|
|
|
|
if (!this.assertPermission(aMessage, "contacts-read")) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
this._db.getCount(
|
|
|
|
function(count) {
|
|
|
|
mm.sendAsyncMessage("Contacts:Count", {
|
|
|
|
requestID: msg.requestID,
|
|
|
|
count: count
|
|
|
|
});
|
|
|
|
}
|
|
|
|
);
|
|
|
|
break;
|
2013-02-01 20:44:55 +00:00
|
|
|
case "Contacts:RegisterForMessages":
|
|
|
|
if (!aMessage.target.assertPermission("contacts-read")) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
if (DEBUG) debug("Register!");
|
|
|
|
if (this._children.indexOf(mm) == -1) {
|
|
|
|
this._children.push(mm);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case "child-process-shutdown":
|
|
|
|
if (DEBUG) debug("Unregister");
|
|
|
|
let index = this._children.indexOf(mm);
|
|
|
|
if (index != -1) {
|
|
|
|
if (DEBUG) debug("Unregister index: " + index);
|
|
|
|
this._children.splice(index, 1);
|
|
|
|
}
|
2013-05-21 18:19:06 +00:00
|
|
|
if (this._cursors[mm]) {
|
|
|
|
for (let id of this._cursors[mm]) {
|
|
|
|
this._db.clearDispatcher(id);
|
|
|
|
}
|
|
|
|
delete this._cursors[mm];
|
|
|
|
}
|
2013-02-01 20:44:55 +00:00
|
|
|
break;
|
2012-08-09 18:34:57 +00:00
|
|
|
default:
|
2012-08-22 21:34:57 +00:00
|
|
|
if (DEBUG) debug("WRONG MESSAGE NAME: " + aMessage.name);
|
2012-02-28 22:01:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-03-29 07:04:45 +00:00
|
|
|
ContactService.init();
|