Bug 867440 - B2G MMS: Add more delivery status in delivery "not-downloaded" and send the dom message with right delivery status. r=vyang
authorChia-hung Tai <ctai@mozilla.com>
Fri, 10 May 2013 11:50:18 -0700
changeset 138449 4d6289816a954b82d7031655b92df7d18a6cb8b0
parent 138448 feabd8f7ae0fbd3361d0bb4a1c85322e4f007ec1
child 138450 b5c76bed5fe3516d6c2d20e40ccbe1dce0c6e692
push idunknown
push userunknown
push dateunknown
reviewersvyang
bugs867440
milestone23.0a1
Bug 867440 - B2G MMS: Add more delivery status in delivery "not-downloaded" and send the dom message with right delivery status. r=vyang
dom/mms/src/ril/MmsService.js
dom/mobilemessage/src/Constants.h
dom/mobilemessage/src/MmsMessage.cpp
dom/mobilemessage/src/MobileMessageThread.cpp
dom/mobilemessage/src/Types.h
--- a/dom/mms/src/ril/MmsService.js
+++ b/dom/mms/src/ril/MmsService.js
@@ -54,19 +54,21 @@ const RETRIEVAL_MODE_NEVER     = "never"
 
 //Internal const values.
 const DELIVERY_RECEIVED       = "received";
 const DELIVERY_NOT_DOWNLOADED = "not-downloaded";
 const DELIVERY_SENDING        = "sending";
 const DELIVERY_SENT           = "sent";
 const DELIVERY_ERROR          = "error";
 
-const DELIVERY_STATUS_SUCCESS = "success";
-const DELIVERY_STATUS_PENDING = "pending";
-const DELIVERY_STATUS_ERROR   = "error";
+const DELIVERY_STATUS_SUCCESS  = "success";
+const DELIVERY_STATUS_PENDING  = "pending";
+const DELIVERY_STATUS_ERROR    = "error";
+const DELIVERY_STATUS_REJECTED = "rejected";
+const DELIVERY_STATUS_MANUAL   = "manual";
 
 const PREF_SEND_RETRY_COUNT =
   Services.prefs.getIntPref("dom.mms.sendRetryCount");
 
 const PREF_SEND_RETRY_INTERVAL =
   Services.prefs.getIntPref("dom.mms.sendRetryInterval");
 
 const PREF_RETRIEVAL_RETRY_COUNT =
@@ -960,23 +962,45 @@ MmsService.prototype = {
       }
     }
     return config >= CONFIG_SEND_REPORT_DEFAULT_YES;
   },
 
   /**
    * Convert intermediate message to indexedDB savable object.
    *
+   * @param retrievalMode
+   *        Retrieval mode for MMS receiving setting.
    * @param intermediate
    *        Intermediate MMS message parsed from PDU.
    */
-  convertIntermediateToSavable: function convertIntermediateToSavable(intermediate) {
+  convertIntermediateToSavable: function convertIntermediateToSavable(intermediate,
+                                                                      retrievalMode) {
     intermediate.type = "mms";
     intermediate.delivery = DELIVERY_NOT_DOWNLOADED;
-    intermediate.deliveryStatus = [DELIVERY_STATUS_PENDING];
+
+    switch(retrievalMode) {
+      case RETRIEVAL_MODE_MANUAL:
+        intermediate.deliveryStatus = [DELIVERY_STATUS_MANUAL];
+        break;
+      case RETRIEVAL_MODE_NEVER:
+        intermediate.deliveryStatus = [DELIVERY_STATUS_REJECTED];
+        break;
+      case RETRIEVAL_MODE_AUTOMATIC:
+        intermediate.deliveryStatus = [DELIVERY_STATUS_PENDING];
+        break;
+      case RETRIEVAL_MODE_AUTOMATIC_HOME:
+        if (gMmsConnection.isVoiceRoaming()) {
+          intermediate.deliveryStatus = [DELIVERY_STATUS_MANUAL];
+        } else {
+          intermediate.deliveryStatus = [DELIVERY_STATUS_PENDING];
+        }
+        break;
+    }
+
     intermediate.timestamp = Date.now();
     intermediate.sender = null;
     intermediate.transactionId = intermediate.headers["x-mms-transaction-id"];
     if (intermediate.headers.from) {
       intermediate.sender = intermediate.headers.from.address;
     } else {
       intermediate.sender = "anonymous";
     }
@@ -1128,16 +1152,25 @@ MmsService.prototype = {
     // something must be wrong with MMSC, so stop updating the DB record.
     // We could send a message to content to notify the user the MMS
     // retrieving failed. The end user has to retrieve the MMS again.
     if (MMS.MMS_PDU_STATUS_RETRIEVED !== mmsStatus) {
       let transaction = new NotifyResponseTransaction(transactionId,
                                                       mmsStatus,
                                                       reportAllowed);
       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) {
+        this.broadcastReceivedMessageEvent(domMessage);
+      }).bind(this));
       return;
     }
 
     savableMessage = this.mergeRetrievalConfirmation(retrievedMessage,
                                                      savableMessage);
 
     gMobileMessageDatabaseService.saveReceivedMessage(savableMessage,
         (function (rv, domMessage) {
@@ -1155,28 +1188,29 @@ MmsService.prototype = {
                                       reportAllowed);
       transaction.run();
 
       if (!success) {
         // At this point we could send a message to content to notify the user
         // that storing an incoming MMS failed, most likely due to a full disk.
         // The end user has to retrieve the MMS again.
         if (DEBUG) debug("Could not store MMS " + domMessage.id +
-              ", error code " + rv);
+                         ", error code " + rv);
         return;
       }
 
       this.broadcastReceivedMessageEvent(domMessage);
     }).bind(this));
   },
 
   /**
    * Callback for saveReceivedMessage.
    */
-  saveReceivedMessageCallback: function saveReceivedMessageCallback(savableMessage,
+  saveReceivedMessageCallback: function saveReceivedMessageCallback(retrievalMode,
+                                                                    savableMessage,
                                                                     rv,
                                                                     domMessage) {
     let success = Components.isSuccessCode(rv);
     if (!success) {
       // At this point we could send a message to content to notify the
       // user that storing an incoming MMS notification indication failed,
       // ost likely due to a full disk.
       if (DEBUG) debug("Could not store MMS " + JSON.stringify(savableMessage) +
@@ -1188,21 +1222,16 @@ MmsService.prototype = {
     }
 
     // For X-Mms-Report-Allowed and X-Mms-Transaction-Id
     let wish = savableMessage.headers["x-mms-delivery-report"];
     let transactionId = savableMessage.headers["x-mms-transaction-id"];
 
     this.broadcastReceivedMessageEvent(domMessage);
 
-    let retrievalMode = RETRIEVAL_MODE_MANUAL;
-    try {
-      retrievalMode = Services.prefs.getCharPref(PREF_RETRIEVAL_MODE);
-    } catch (e) {}
-
     // In roaming environment, we send notify response only in
     // automatic retrieval mode.
     if ((retrievalMode !== RETRIEVAL_MODE_AUTOMATIC) &&
         gMmsConnection.isVoiceRoaming()) {
       return;
     }
 
     if (RETRIEVAL_MODE_MANUAL === retrievalMode ||
@@ -1243,21 +1272,28 @@ MmsService.prototype = {
         (function (aRv, aMessageRecord) {
       if (Ci.nsIMobileMessageCallback.SUCCESS_NO_ERROR === aRv
           && aMessageRecord) {
         if (DEBUG) debug("We already got the NotificationIndication with transactionId = "
                          + transactionId + " before.");
         return;
       }
 
-      let savableMessage = this.convertIntermediateToSavable(notification);
+      let retrievalMode = RETRIEVAL_MODE_MANUAL;
+      try {
+        retrievalMode = Services.prefs.getCharPref(PREF_RETRIEVAL_MODE);
+      } catch (e) {}
+
+      let savableMessage = this.convertIntermediateToSavable(notification, retrievalMode);
 
       gMobileMessageDatabaseService
         .saveReceivedMessage(savableMessage,
-                             this.saveReceivedMessageCallback.bind(this, savableMessage));
+                             this.saveReceivedMessageCallback.bind(this,
+                                                                   retrievalMode,
+                                                                   savableMessage));
     }).bind(this));
   },
 
   /**
    * Handle incoming M-Delivery.ind PDU.
    *
    * @param msg
    *        The MMS message object.
@@ -1449,16 +1485,26 @@ MmsService.prototype = {
         aRequest.notifyGetMessageFailed(Ci.nsIMobileMessageCallback.INTERNAL_ERROR);
         return;
       }
       if (!aMessageRecord.headers["x-mms-content-location"]) {
         if (DEBUG) debug("Can't find mms content url in database.");
         aRequest.notifyGetMessageFailed(Ci.nsIMobileMessageCallback.INTERNAL_ERROR);
         return;
       }
+      if (DELIVERY_NOT_DOWNLOADED != aMessageRecord.delivery) {
+        if (DEBUG) debug("Delivery of message record is not 'not-downloaded'.");
+        aRequest.notifyGetMessageFailed(Ci.nsIMobileMessageCallback.INTERNAL_ERROR);
+        return;
+      }
+      if (DELIVERY_STATUS_PENDING == aMessageRecord.deliveryStatus) {
+        if (DEBUG) debug("Delivery status of message record is 'pending'.");
+        aRequest.notifyGetMessageFailed(Ci.nsIMobileMessageCallback.INTERNAL_ERROR);
+        return;
+      }
 
       // Cite 6.2 "Multimedia Message Notification" in OMA-TS-MMS_ENC-V1_3-20110913-A:
       // The field has only one format, relative. The recipient client calculates
       // this length of time relative to the time it receives the notification.
       if (aMessageRecord.headers["x-mms-expiry"] != undefined) {
         let expiryDate = aMessageRecord.timestamp +
                          aMessageRecord.headers["x-mms-expiry"] * 1000;
         if (expiryDate < Date.now()) {
@@ -1466,17 +1512,17 @@ MmsService.prototype = {
           aRequest.notifyGetMessageFailed(Ci.nsIMobileMessageCallback.NOT_FOUND_ERROR);
           return;
         }
       }
 
       let url =  aMessageRecord.headers["x-mms-content-location"].uri;
       // For X-Mms-Report-Allowed
       let wish = aMessageRecord.headers["x-mms-delivery-report"];
-      this.retrieveMessage(url, (function responseNotify(mmsStatus, retrievedMsg) {
+      let responseNotify = function responseNotify(mmsStatus, retrievedMsg) {
         // If the mmsStatus is still MMS_PDU_STATUS_DEFERRED after retry,
         // we should not store it into database.
         if (MMS.MMS_PDU_STATUS_RETRIEVED !== mmsStatus) {
           if (DEBUG) debug("RetrieveMessage fail after retry.");
           aRequest.notifyGetMessageFailed(Ci.nsIMobileMessageCallback.INTERNAL_ERROR);
           return;
         }
         // In OMA-TS-MMS_ENC-V1_3, Table 5 in page 25. This header field
@@ -1520,17 +1566,24 @@ MmsService.prototype = {
           // Cite 6.3.1 "Transaction Flow" in OMA-TS-MMS_ENC-V1_3-20110913-A:
           // If an acknowledgement is requested, the MMS Client SHALL respond
           // with an M-Acknowledge.ind PDU to the MMS Proxy-Relay that supports
           // the specific MMS Client. The M-Acknowledge.ind PDU confirms
           // successful message retrieval to the MMS Proxy Relay.
           let transaction = new AcknowledgeTransaction(transactionId, reportAllowed);
           transaction.run();
         }).bind(this));
-      }).bind(this));
+      };
+      // Update the delivery status to pending in DB.
+      gMobileMessageDatabaseService
+        .setMessageDelivery(aMessageId,
+                            null,
+                            null,
+                            DELIVERY_STATUS_PENDING,
+                            this.retrieveMessage(url, responseNotify.bind(this)));
     }).bind(this));
   },
 
   // nsIWapPushApplication
 
   receiveWapPush: function receiveWapPush(array, length, offset, options) {
     let data = {array: array, offset: offset};
     let msg = MMS.PduHelper.parse(data, null);
--- a/dom/mobilemessage/src/Constants.h
+++ b/dom/mobilemessage/src/Constants.h
@@ -28,16 +28,18 @@ extern const char* kMmsReceivedObserverT
 #define DELIVERY_SENT           NS_LITERAL_STRING("sent")
 #define DELIVERY_ERROR          NS_LITERAL_STRING("error")
 #define DELIVERY_NOT_DOWNLOADED NS_LITERAL_STRING("not-downloaded")
 
 #define DELIVERY_STATUS_NOT_APPLICABLE NS_LITERAL_STRING("not-applicable")
 #define DELIVERY_STATUS_SUCCESS        NS_LITERAL_STRING("success")
 #define DELIVERY_STATUS_PENDING        NS_LITERAL_STRING("pending")
 #define DELIVERY_STATUS_ERROR          NS_LITERAL_STRING("error")
+#define DELIVERY_STATUS_REJECTED       NS_LITERAL_STRING("rejected")
+#define DELIVERY_STATUS_MANUAL         NS_LITERAL_STRING("manual")
 
 #define MESSAGE_CLASS_NORMAL  NS_LITERAL_STRING("normal")
 #define MESSAGE_CLASS_CLASS_0 NS_LITERAL_STRING("class-0")
 #define MESSAGE_CLASS_CLASS_1 NS_LITERAL_STRING("class-1")
 #define MESSAGE_CLASS_CLASS_2 NS_LITERAL_STRING("class-2")
 #define MESSAGE_CLASS_CLASS_3 NS_LITERAL_STRING("class-3")
 
 #define MESSAGE_TYPE_SMS NS_LITERAL_STRING("sms")
--- a/dom/mobilemessage/src/MmsMessage.cpp
+++ b/dom/mobilemessage/src/MmsMessage.cpp
@@ -183,16 +183,20 @@ MmsMessage::Create(int32_t              
     if (statusStr.Equals(DELIVERY_STATUS_NOT_APPLICABLE)) {
       status = eDeliveryStatus_NotApplicable;
     } else if (statusStr.Equals(DELIVERY_STATUS_SUCCESS)) {
       status = eDeliveryStatus_Success;
     } else if (statusStr.Equals(DELIVERY_STATUS_PENDING)) {
       status = eDeliveryStatus_Pending;
     } else if (statusStr.Equals(DELIVERY_STATUS_ERROR)) {
       status = eDeliveryStatus_Error;
+    } else if (statusStr.Equals(DELIVERY_STATUS_REJECTED)) {
+      status = eDeliveryStatus_Reject;
+    } else if (statusStr.Equals(DELIVERY_STATUS_MANUAL)) {
+      status = eDeliveryStatus_Manual;
     } else {
       return NS_ERROR_INVALID_ARG;
     }
 
     deliveryStatus.AppendElement(status);
   }
 
   // Set |receivers|.
@@ -376,16 +380,22 @@ MmsMessage::GetDeliveryStatus(JSContext*
         statusStr = DELIVERY_STATUS_SUCCESS;
         break;
       case eDeliveryStatus_Pending:
         statusStr = DELIVERY_STATUS_PENDING;
         break;
       case eDeliveryStatus_Error:
         statusStr = DELIVERY_STATUS_ERROR;
         break;
+      case eDeliveryStatus_Reject:
+        statusStr = DELIVERY_STATUS_REJECTED;
+        break;
+      case eDeliveryStatus_Manual:
+        statusStr = DELIVERY_STATUS_MANUAL;
+        break;
       case eDeliveryStatus_EndGuard:
       default:
         MOZ_NOT_REACHED("We shouldn't get any other delivery status!");
         return NS_ERROR_UNEXPECTED;
     }
     tempStrArray.AppendElement(statusStr);
   }
 
--- a/dom/mobilemessage/src/MobileMessageThread.cpp
+++ b/dom/mobilemessage/src/MobileMessageThread.cpp
@@ -181,17 +181,17 @@ MobileMessageThread::GetLastMessageType(
     case eMessageType_SMS:
       aLastMessageType = MESSAGE_TYPE_SMS;
       break;
     case eMessageType_MMS:
       aLastMessageType = MESSAGE_TYPE_MMS;
       break;
     case eMessageType_EndGuard:
     default:
-      MOZ_NOT_REACHED("We shouldn't get any other delivery state!");
+      MOZ_NOT_REACHED("We shouldn't get any other message type!");
       return NS_ERROR_UNEXPECTED;
   }
 
   return NS_OK;
 }
 
 } // namespace dom
 } // namespace mozilla
--- a/dom/mobilemessage/src/Types.h
+++ b/dom/mobilemessage/src/Types.h
@@ -27,16 +27,18 @@ enum DeliveryState {
 };
 
 // For {Mms,Sms}MessageData.deliveryStatus.
 enum DeliveryStatus {
   eDeliveryStatus_NotApplicable = 0,
   eDeliveryStatus_Success,
   eDeliveryStatus_Pending,
   eDeliveryStatus_Error,
+  eDeliveryStatus_Reject,
+  eDeliveryStatus_Manual,
   // This state should stay at the end.
   eDeliveryStatus_EndGuard
 };
 
 // For {Mms,Sms}FilterData.read.
 enum ReadState {
   eReadState_Unknown = -1,
   eReadState_Unread,