From e620d61236f2b46f418c2af9704ac82e11a85590 Mon Sep 17 00:00:00 2001 From: Gene Lian Date: Wed, 31 Jul 2013 15:23:37 +0800 Subject: [PATCH] Bug 850140 - B2G MMS: implement MmsService.handleDeliveryIndication() to handle delivery report (part 1, provide and correct DB functions). r=vicamo a=koi+ --- .../nsIRilMobileMessageDatabaseService.idl | 39 ++- dom/mobilemessage/src/gonk/MmsService.js | 50 +-- .../src/gonk/MobileMessageDatabaseService.js | 314 ++++++++++++------ dom/system/gonk/RadioInterfaceLayer.js | 47 +-- 4 files changed, 292 insertions(+), 158 deletions(-) diff --git a/dom/mobilemessage/interfaces/nsIRilMobileMessageDatabaseService.idl b/dom/mobilemessage/interfaces/nsIRilMobileMessageDatabaseService.idl index 78272317eeba..948380a47af4 100644 --- a/dom/mobilemessage/interfaces/nsIRilMobileMessageDatabaseService.idl +++ b/dom/mobilemessage/interfaces/nsIRilMobileMessageDatabaseService.idl @@ -25,7 +25,7 @@ interface nsIRilMobileMessageDatabaseRecordCallback : nsISupports void notify(in nsresult aRv, in jsval aMessageRecord, in nsISupports aDomMessage); }; -[scriptable, uuid(0ead3154-542d-4e2c-a624-9e3cec504758)] +[scriptable, uuid(f6cd671e-f9af-11e2-b64b-1fb87e9c217c)] interface nsIRilMobileMessageDatabaseService : nsIMobileMessageDatabaseService { /** @@ -43,7 +43,7 @@ interface nsIRilMobileMessageDatabaseService : nsIMobileMessageDatabaseService * - |deliveryStatus| DOMString Array: the delivery status of received message * - |receivers| DOMString Array: the phone numbers of receivers * - |msisdn| DOMString: [optional] my own phone number. - * - |transactionId| DOMString: the transaction ID from MMS pdu header. + * - |transactionId| DOMString: the transaction ID from MMS PDU header. * * Note: |deliveryStatus| should only contain single string to specify * the delivery status of MMS message for the phone owner self. @@ -72,26 +72,41 @@ interface nsIRilMobileMessageDatabaseService : nsIMobileMessageDatabaseService * |aReceiver| DOMString: the phone number of receiver (for MMS; can be null). * |aDelivery| DOMString: the new delivery value to update (can be null). * |aDeliveryStatus| DOMString: the new delivery status to update (can be null). + * |aEnvelopeId| DOMString: the "message-id" specified in the MMS PDU headers. * |aCallback| nsIRilMobileMessageDatabaseCallback: an optional callback. */ - void setMessageDelivery(in long aMessageId, - in DOMString aReceiver, - in DOMString aDelivery, - in DOMString aDeliveryStatus, - [optional] in nsIRilMobileMessageDatabaseCallback aCallback); + void setMessageDeliveryByMessageId(in long aMessageId, + in DOMString aReceiver, + in DOMString aDelivery, + in DOMString aDeliveryStatus, + in DOMString aEnvelopeId, + [optional] in nsIRilMobileMessageDatabaseCallback aCallback); + + /** + * |aEnvelopeId| DOMString: the "message-id" specified in the MMS PDU headers. + * |aReceiver| DOMString: the phone number of receiver (for MMS; can be null). + * |aDelivery| DOMString: the new delivery value to update (can be null). + * |aDeliveryStatus| DOMString: the new delivery status to update (can be null). + * |aCallback| nsIRilMobileMessageDatabaseCallback: an optional callback. + */ + void setMessageDeliveryByEnvelopeId(in DOMString aEnvelopeId, + in DOMString aReceiver, + in DOMString aDelivery, + in DOMString aDeliveryStatus, + [optional] in nsIRilMobileMessageDatabaseCallback aCallback); /** * |aMessageId| Number: the message's DB record ID. - * |aCallback| nsIRilMobileMessageDatabaseCallback: a callback which takes - * result flag, message record and domMessage as parameters. + * |aCallback| nsIRilMobileMessageDatabaseRecordCallback: a callback which + * takes result flag, message record and domMessage as parameters. */ void getMessageRecordById(in long aMessageId, in nsIRilMobileMessageDatabaseRecordCallback aCallback); /** - * |aTransactionId| DOMString: the transaction ID of MMS pdu. - * |aCallback| nsIRilMobileMessageDatabaseCallback: a callback which takes - * result flag and message record as parameters. + * |aTransactionId| DOMString: the transaction ID of MMS PDU. + * |aCallback| nsIRilMobileMessageDatabaseRecordCallback: a callback which + * takes result flag and message record as parameters. */ void getMessageRecordByTransactionId(in DOMString aTransactionId, in nsIRilMobileMessageDatabaseRecordCallback aCallback); diff --git a/dom/mobilemessage/src/gonk/MmsService.js b/dom/mobilemessage/src/gonk/MmsService.js index 137e7a305fdf..d740dca9a1c4 100644 --- a/dom/mobilemessage/src/gonk/MmsService.js +++ b/dom/mobilemessage/src/gonk/MmsService.js @@ -1396,11 +1396,13 @@ MmsService.prototype = { transaction.run(); // Retrieved fail after retry, so we update the delivery status in DB and // notify this domMessage that error happen. - gMobileMessageDatabaseService.setMessageDelivery(id, - null, - null, - DELIVERY_STATUS_ERROR, - (function (rv, domMessage) { + gMobileMessageDatabaseService + .setMessageDeliveryByMessageId(id, + null, + null, + DELIVERY_STATUS_ERROR, + null, + (function (rv, domMessage) { this.broadcastReceivedMessageEvent(domMessage); }).bind(this)); return; @@ -1728,11 +1730,12 @@ MmsService.prototype = { let isSentSuccess = (aErrorCode == Ci.nsIMobileMessageCallback.SUCCESS_NO_ERROR); gMobileMessageDatabaseService - .setMessageDelivery(aDomMessage.id, - null, - isSentSuccess ? DELIVERY_SENT : DELIVERY_ERROR, - isSentSuccess ? null : DELIVERY_STATUS_ERROR, - function notifySetDeliveryResult(aRv, aDomMessage) { + .setMessageDeliveryByMessageId(aDomMessage.id, + null, + isSentSuccess ? DELIVERY_SENT : DELIVERY_ERROR, + isSentSuccess ? null : DELIVERY_STATUS_ERROR, + null, + function notifySetDeliveryResult(aRv, aDomMessage) { if (DEBUG) debug("Marking the delivery state/staus is done. Notify sent or failed."); // TODO bug 832140 handle !Components.isSuccessCode(aRv) if (!isSentSuccess) { @@ -1874,11 +1877,13 @@ MmsService.prototype = { // status to 'error'. if (MMS.MMS_PDU_STATUS_RETRIEVED !== mmsStatus) { if (DEBUG) debug("RetrieveMessage fail after retry."); - gMobileMessageDatabaseService.setMessageDelivery(aMessageId, - null, - null, - DELIVERY_STATUS_ERROR, - function () { + gMobileMessageDatabaseService + .setMessageDeliveryByMessageId(aMessageId, + null, + null, + DELIVERY_STATUS_ERROR, + null, + function () { aRequest.notifyGetMessageFailed(Ci.nsIMobileMessageCallback.INTERNAL_ERROR); }); return; @@ -1932,13 +1937,14 @@ MmsService.prototype = { }; // Update the delivery status to pending in DB. gMobileMessageDatabaseService - .setMessageDelivery(aMessageId, - null, - null, - DELIVERY_STATUS_PENDING, - this.retrieveMessage(url, - responseNotify.bind(this), - aDomMessage)); + .setMessageDeliveryByMessageId(aMessageId, + null, + null, + DELIVERY_STATUS_PENDING, + null, + this.retrieveMessage(url, + responseNotify.bind(this), + aDomMessage)); }).bind(this)); }, diff --git a/dom/mobilemessage/src/gonk/MobileMessageDatabaseService.js b/dom/mobilemessage/src/gonk/MobileMessageDatabaseService.js index 5f53d34c80c3..c4acb68da885 100644 --- a/dom/mobilemessage/src/gonk/MobileMessageDatabaseService.js +++ b/dom/mobilemessage/src/gonk/MobileMessageDatabaseService.js @@ -24,7 +24,7 @@ const DISABLE_MMS_GROUPING_FOR_RECEIVING = true; const DB_NAME = "sms"; -const DB_VERSION = 11; +const DB_VERSION = 12; const MESSAGE_STORE_NAME = "sms"; const THREAD_STORE_NAME = "thread"; const PARTICIPANT_STORE_NAME = "participant"; @@ -221,10 +221,14 @@ MobileMessageDatabaseService.prototype = { if (DEBUG) debug("Upgrade to version 11. Add last message type into threadRecord."); self.upgradeSchema10(event.target.transaction, next); break; - case 11: - // This will need to be moved for each new version - if (DEBUG) debug("Upgrade finished."); - break; + case 11: + if (DEBUG) debug("Upgrade to version 12. Add envelopeId index for outgoing MMS."); + self.upgradeSchema11(event.target.transaction, next); + break; + case 12: + // This will need to be moved for each new version + if (DEBUG) debug("Upgrade finished."); + break; default: event.target.transaction.abort(); callback("Old database version: " + event.oldVersion, null); @@ -765,6 +769,38 @@ MobileMessageDatabaseService.prototype = { }; }, + /** + * Add envelopeId index for MMS. + */ + upgradeSchema11: function upgradeSchema11(transaction, next) { + let messageStore = transaction.objectStore(MESSAGE_STORE_NAME); + + // Delete "envelopeId" index. + if (messageStore.indexNames.contains("envelopeId")) { + messageStore.deleteIndex("envelopeId"); + } + + // Create new "envelopeId" indexes. + messageStore.createIndex("envelopeId", "envelopeIdIndex", { unique: true }); + + // Populate new "envelopeIdIndex" attributes. + messageStore.openCursor().onsuccess = function(event) { + let cursor = event.target.result; + if (!cursor) { + next(); + return; + } + + let messageRecord = cursor.value; + if (messageRecord.type == "mms" && + messageRecord.delivery == DELIVERY_SENT) { + messageRecord.envelopeIdIndex = messageRecord.headers["message-id"]; + cursor.update(messageRecord); + } + cursor.continue(); + }; + }, + createDomMessageFromRecord: function createDomMessageFromRecord(aMessageRecord) { if (DEBUG) { debug("createDomMessageFromRecord: " + JSON.stringify(aMessageRecord)); @@ -1152,6 +1188,162 @@ MobileMessageDatabaseService.prototype = { return aMessageRecord.id; }, + updateMessageDeliveryById: function updateMessageDeliveryById( + id, type, receiver, delivery, deliveryStatus, envelopeId, callback) { + if (DEBUG) { + debug("Setting message's delivery by " + type + " = "+ id + + " receiver: " + receiver + + " delivery: " + delivery + + " deliveryStatus: " + deliveryStatus + + " envelopeId: " + envelopeId); + } + + let self = this; + let messageRecord; + function notifyResult(rv) { + if (!callback) { + return; + } + let domMessage = self.createDomMessageFromRecord(messageRecord); + callback.notify(rv, domMessage); + } + + this.newTxn(READ_WRITE, function (error, txn, messageStore) { + if (error) { + // TODO bug 832140 check event.target.errorCode + notifyResult(Cr.NS_ERROR_FAILURE); + return; + } + txn.oncomplete = function oncomplete(event) { + notifyResult(Cr.NS_OK); + }; + txn.onabort = function onabort(event) { + // TODO bug 832140 check event.target.errorCode + notifyResult(Cr.NS_ERROR_FAILURE); + }; + + let getRequest; + if (type === "messageId") { + getRequest = messageStore.get(id); + } else if (type === "envelopeId") { + getRequest = messageStore.index("envelopeId").get(id); + } + + getRequest.onsuccess = function onsuccess(event) { + messageRecord = event.target.result; + if (!messageRecord) { + if (DEBUG) debug("type = " + id + " is not found"); + return; + } + + let isRecordUpdated = false; + + // Update |messageRecord.delivery| if needed. + if (delivery && messageRecord.delivery != delivery) { + messageRecord.delivery = delivery; + messageRecord.deliveryIndex = [delivery, messageRecord.timestamp]; + isRecordUpdated = true; + } + + // Update |messageRecord.deliveryStatus| if needed. + if (deliveryStatus) { + if (messageRecord.type == "sms") { + if (messageRecord.deliveryStatus != deliveryStatus) { + messageRecord.deliveryStatus = deliveryStatus; + isRecordUpdated = true; + } + } else if (messageRecord.type == "mms") { + if (!receiver) { + for (let i = 0; i < messageRecord.deliveryStatus.length; i++) { + if (messageRecord.deliveryStatus[i] != deliveryStatus) { + messageRecord.deliveryStatus[i] = deliveryStatus; + isRecordUpdated = true; + } + } + } else { + let normReceiver = PhoneNumberUtils.normalize(receiver, false); + if (!normReceiver) { + if (DEBUG) { + debug("Normalized receiver is not valid. Fail to update."); + } + return; + } + + let parsedReveiver = PhoneNumberUtils.parseWithMCC(normReceiver, null); + + let found = false; + for (let i = 0; i < messageRecord.receivers.length; i++) { + let storedReceiver = messageRecord.receivers[i]; + let normStoreReceiver = + PhoneNumberUtils.normalize(storedReceiver, false); + if (!normStoreReceiver) { + if (DEBUG) { + debug("Normalized stored receiver is not valid. Skipping."); + } + continue; + } + + let match = (normReceiver === normStoreReceiver); + if (!match) { + if (parsedReveiver) { + if (normStoreReceiver.endsWith(parsedReveiver.nationalNumber)) { + match = true; + } + } else { + let parsedStoreReceiver = + PhoneNumberUtils.parseWithMCC(normStoreReceiver, null); + if (parsedStoreReceiver && + normReceiver.endsWith(parsedStoreReceiver.nationalNumber)) { + match = true; + } + } + } + if (!match) { + if (DEBUG) debug("Stored receiver is not matched. Skipping."); + continue; + } + + found = true; + if (messageRecord.deliveryStatus[i] != deliveryStatus) { + messageRecord.deliveryStatus[i] = deliveryStatus; + isRecordUpdated = true; + } + } + + if (!found) { + if (DEBUG) { + debug("Cannot find the receiver. Fail to set delivery status."); + } + return; + } + } + } + } + + // Update |messageRecord.envelopeIdIndex| if needed. + if (envelopeId) { + if (messageRecord.envelopeIdIndex != envelopeId) { + messageRecord.envelopeIdIndex = envelopeId; + isRecordUpdated = true; + } + } + + if (!isRecordUpdated) { + if (DEBUG) { + debug("The values of delivery, deliveryStatus and envelopeId " + + "don't need to be updated."); + } + return; + } + + if (DEBUG) { + debug("The delivery, deliveryStatus or envelopeId are updated."); + } + messageStore.put(messageRecord); + }; + }); + }, + /** * nsIRilMobileMessageDatabaseService API */ @@ -1283,107 +1475,20 @@ MobileMessageDatabaseService.prototype = { return this.saveRecord(aMessage, addresses, aCallback); }, - setMessageDelivery: function setMessageDelivery( - messageId, receiver, delivery, deliveryStatus, callback) { - if (DEBUG) { - debug("Setting message " + messageId + " delivery to " + delivery - + ", and deliveryStatus to " + deliveryStatus); - } + setMessageDeliveryByMessageId: function setMessageDeliveryByMessageId( + messageId, receiver, delivery, deliveryStatus, envelopeId, callback) { + this.updateMessageDeliveryById(messageId, "messageId", + receiver, delivery, deliveryStatus, + envelopeId, callback); - let self = this; - let messageRecord; - function notifyResult(rv) { - if (!callback) { - return; - } - let domMessage = self.createDomMessageFromRecord(messageRecord); - callback.notify(rv, domMessage); - } + }, - this.newTxn(READ_WRITE, function (error, txn, messageStore) { - if (error) { - // TODO bug 832140 check event.target.errorCode - notifyResult(Cr.NS_ERROR_FAILURE); - return; - } - txn.oncomplete = function oncomplete(event) { - notifyResult(Cr.NS_OK); - }; - txn.onabort = function onabort(event) { - // TODO bug 832140 check event.target.errorCode - notifyResult(Cr.NS_ERROR_FAILURE); - }; + setMessageDeliveryByEnvelopeId: function setMessageDeliveryByEnvelopeId( + envelopeId, receiver, delivery, deliveryStatus, callback) { + this.updateMessageDeliveryById(envelopeId, "envelopeId", + receiver, delivery, deliveryStatus, + null, callback); - let getRequest = messageStore.get(messageId); - getRequest.onsuccess = function onsuccess(event) { - messageRecord = event.target.result; - if (!messageRecord) { - if (DEBUG) debug("Message ID " + messageId + " not found"); - return; - } - if (messageRecord.id != messageId) { - if (DEBUG) { - debug("Retrieve message ID (" + messageId + ") is " + - "different from the one we got"); - } - return; - } - - let isRecordUpdated = false; - - // Update |messageRecord.delivery| if needed. - if (delivery && messageRecord.delivery != delivery) { - messageRecord.delivery = delivery; - messageRecord.deliveryIndex = [delivery, messageRecord.timestamp]; - isRecordUpdated = true; - } - - // Update |messageRecord.deliveryStatus| if needed. - if (deliveryStatus) { - if (messageRecord.type == "sms") { - if (messageRecord.deliveryStatus != deliveryStatus) { - messageRecord.deliveryStatus = deliveryStatus; - isRecordUpdated = true; - } - } else if (messageRecord.type == "mms") { - if (!receiver) { - for (let i = 0; i < messageRecord.deliveryStatus.length; i++) { - if (messageRecord.deliveryStatus[i] != deliveryStatus) { - messageRecord.deliveryStatus[i] = deliveryStatus; - isRecordUpdated = true; - } - } - } else { - let index = messageRecord.receivers.indexOf(receiver); - if (index == -1) { - if (DEBUG) { - debug("Cannot find the receiver. Fail to set delivery status."); - } - return; - } - if (messageRecord.deliveryStatus[index] != deliveryStatus) { - messageRecord.deliveryStatus[index] = deliveryStatus; - isRecordUpdated = true; - } - } - } - } - - // Only updates messages that have different delivery or deliveryStatus. - if (!isRecordUpdated) { - if (DEBUG) { - debug("The values of attribute delivery and deliveryStatus are the" - + " the same with given parameters."); - } - return; - } - - if (DEBUG) { - debug("The record's delivery and/or deliveryStatus are updated."); - } - messageStore.put(messageRecord); - }; - }); }, getMessageRecordByTransactionId: function getMessageRecordByTransactionId(aTransactionId, aCallback) { @@ -1413,8 +1518,9 @@ MobileMessageDatabaseService.prototype = { txn.onerror = function onerror(event) { if (DEBUG) { - if (event.target) + if (event.target) { debug("Caught error on transaction", event.target.errorCode); + } } aCallback.notify(Ci.nsIMobileMessageCallback.INTERNAL_ERROR, null, null); }; diff --git a/dom/system/gonk/RadioInterfaceLayer.js b/dom/system/gonk/RadioInterfaceLayer.js index 462032f5c663..bbabb6770cf4 100644 --- a/dom/system/gonk/RadioInterfaceLayer.js +++ b/dom/system/gonk/RadioInterfaceLayer.js @@ -2032,11 +2032,13 @@ RadioInterface.prototype = { return; } - gMobileMessageDatabaseService.setMessageDelivery(options.sms.id, - null, - DOM_MOBILE_MESSAGE_DELIVERY_SENT, - options.sms.deliveryStatus, - function notifyResult(rv, domMessage) { + gMobileMessageDatabaseService + .setMessageDeliveryByMessageId(options.sms.id, + null, + DOM_MOBILE_MESSAGE_DELIVERY_SENT, + options.sms.deliveryStatus, + null, + function notifyResult(rv, domMessage) { // TODO bug 832140 handle !Components.isSuccessCode(rv) this.broadcastSmsSystemMessage("sms-sent", domMessage); @@ -2065,11 +2067,13 @@ RadioInterface.prototype = { return; } - gMobileMessageDatabaseService.setMessageDelivery(options.sms.id, - null, - options.sms.delivery, - message.deliveryStatus, - function notifyResult(rv, domMessage) { + gMobileMessageDatabaseService + .setMessageDeliveryByMessageId(options.sms.id, + null, + options.sms.delivery, + message.deliveryStatus, + null, + function notifyResult(rv, domMessage) { // TODO bug 832140 handle !Components.isSuccessCode(rv) let topic = (message.deliveryStatus == RIL.GECKO_SMS_DELIVERY_STATUS_SUCCESS) ? kSmsDeliverySuccessObserverTopic @@ -2099,11 +2103,13 @@ RadioInterface.prototype = { return; } - gMobileMessageDatabaseService.setMessageDelivery(options.sms.id, - null, - DOM_MOBILE_MESSAGE_DELIVERY_ERROR, - RIL.GECKO_SMS_DELIVERY_STATUS_ERROR, - function notifyResult(rv, domMessage) { + gMobileMessageDatabaseService + .setMessageDeliveryByMessageId(options.sms.id, + null, + DOM_MOBILE_MESSAGE_DELIVERY_ERROR, + RIL.GECKO_SMS_DELIVERY_STATUS_ERROR, + null, + function notifyResult(rv, domMessage) { // TODO bug 832140 handle !Components.isSuccessCode(rv) options.request.notifySendMessageFailed(error); Services.obs.notifyObservers(domMessage, kSmsFailedObserverTopic, null); @@ -3275,11 +3281,12 @@ RadioInterface.prototype = { } gMobileMessageDatabaseService - .setMessageDelivery(domMessage.id, - null, - DOM_MOBILE_MESSAGE_DELIVERY_ERROR, - RIL.GECKO_SMS_DELIVERY_STATUS_ERROR, - function notifyResult(rv, domMessage) { + .setMessageDeliveryByMessageId(domMessage.id, + null, + DOM_MOBILE_MESSAGE_DELIVERY_ERROR, + RIL.GECKO_SMS_DELIVERY_STATUS_ERROR, + null, + function notifyResult(rv, domMessage) { // TODO bug 832140 handle !Components.isSuccessCode(rv) request.notifySendMessageFailed(errorCode); Services.obs.notifyObservers(domMessage, kSmsFailedObserverTopic, null);