Bug 847744: Part 4 - IPC implementation for MMS send(). r=jdm,vicamo,mrbkap, a=leo+
authorVicamo Yang <vyang@mozilla.com>
Thu, 18 Apr 2013 09:09:52 +0800
changeset 119108 d10ff6cda618be03a5e1522919d512f60cb16a17
parent 119107 898d1ece6313bf26076a5bf8d7444bafffdb48e0
child 119109 37f11e04ebf520e6d6799e1425dd09bdb640d382
push id680
push uservyang@mozilla.com
push dateThu, 18 Apr 2013 01:11:41 +0000
reviewersjdm, vicamo, mrbkap, leo
bugs847744
milestone18.0
Bug 847744: Part 4 - IPC implementation for MMS send(). r=jdm,vicamo,mrbkap, a=leo+
dom/mobilemessage/src/MmsMessage.cpp
dom/mobilemessage/src/MmsMessage.h
dom/mobilemessage/src/ipc/SmsChild.cpp
dom/mobilemessage/src/ipc/SmsChild.h
dom/mobilemessage/src/ipc/SmsIPCService.cpp
dom/mobilemessage/src/ipc/SmsParent.cpp
dom/mobilemessage/src/ipc/SmsParent.h
--- a/dom/mobilemessage/src/MmsMessage.cpp
+++ b/dom/mobilemessage/src/MmsMessage.cpp
@@ -7,16 +7,18 @@
 #include "nsIDOMClassInfo.h"
 #include "jsapi.h" // For OBJECT_TO_JSVAL and JS_NewDateObjectMsec
 #include "jsfriendapi.h" // For js_DateGetMsecSinceEpoch
 #include "nsJSUtils.h"
 #include "Constants.h"
 #include "nsContentUtils.h"
 #include "nsIDOMFile.h"
 #include "nsTArrayHelpers.h"
+#include "mozilla/dom/ContentParent.h"
+#include "mozilla/dom/mobilemessage/SmsTypes.h"
 
 using namespace mozilla::dom::mobilemessage;
 
 DOMCI_DATA(MozMmsMessage, mozilla::dom::MmsMessage)
 
 namespace mozilla {
 namespace dom {
 
@@ -49,16 +51,45 @@ MmsMessage::MmsMessage(int32_t          
     mTimestamp(aTimestamp),
     mRead(aRead),
     mSubject(aSubject),
     mSmil(aSmil),
     mAttachments(aAttachments)
 {
 }
 
+MmsMessage::MmsMessage(const mobilemessage::MmsMessageData& aData)
+  : mId(aData.id())
+  , mDelivery(aData.delivery())
+  , mDeliveryStatus(aData.deliveryStatus())
+  , mSender(aData.sender())
+  , mReceivers(aData.receivers())
+  , mTimestamp(aData.timestamp())
+  , mRead(aData.read())
+  , mSubject(aData.subject())
+  , mSmil(aData.smil())
+{
+  uint32_t len = aData.attachments().Length();
+  mAttachments.SetCapacity(len);
+  for (uint32_t i = 0; i < len; i++) {
+    MmsAttachment att;
+    const MmsAttachmentData &element = aData.attachments()[i];
+    att.id = element.id();
+    att.location = element.location();
+    if (element.contentParent()) {
+      att.content = static_cast<BlobParent*>(element.contentParent())->GetBlob();
+    } else if (element.contentChild()) {
+      att.content = static_cast<BlobChild*>(element.contentChild())->GetBlob();
+    } else {
+      NS_WARNING("MmsMessage: Unable to get attachment content.");
+    }
+    mAttachments.AppendElement(att);
+  }
+}
+
 /* static */ nsresult
 MmsMessage::Create(int32_t               aId,
                    const uint64_t        aThreadId,
                    const nsAString&      aDelivery,
                    const JS::Value&      aDeliveryStatus,
                    const nsAString&      aSender,
                    const JS::Value&      aReceivers,
                    const JS::Value&      aTimestamp,
@@ -204,16 +235,58 @@ MmsMessage::Create(int32_t              
                                                          aRead,
                                                          aSubject,
                                                          aSmil,
                                                          attachments);
   message.forget(aMessage);
   return NS_OK;
 }
 
+bool
+MmsMessage::GetData(ContentParent* aParent,
+                    mobilemessage::MmsMessageData& aData)
+{
+  NS_ASSERTION(aParent, "aParent is null");
+
+  aData.id() = mId;
+  aData.delivery() = mDelivery;
+  aData.sender().Assign(mSender);
+  aData.timestamp() = mTimestamp;
+  aData.read() = mRead;
+  aData.subject() = mSubject;
+  aData.smil() = mSmil;
+
+  // Bug 819791 is not uplifted in b2g18 branch.
+  aData.deliveryStatus().SetCapacity(mDeliveryStatus.Length());
+  for (uint32_t i = 0; i < mDeliveryStatus.Length(); i++) {
+    aData.deliveryStatus().AppendElement(mDeliveryStatus[i]);
+  }
+
+  // Bug 819791 is not uplifted in b2g18 branch.
+  aData.receivers().SetCapacity(mReceivers.Length());
+  for (uint32_t i = 0; i < mReceivers.Length(); i++) {
+    aData.receivers().AppendElement(mReceivers[i]);
+  }
+
+  aData.attachments().SetCapacity(mAttachments.Length());
+  for (uint32_t i = 0; i < mAttachments.Length(); i++) {
+    MmsAttachmentData mma;
+    const MmsAttachment &element = mAttachments[i];
+    mma.id().Assign(element.id);
+    mma.location().Assign(element.location);
+    mma.contentParent() = aParent->GetOrCreateActorForBlob(element.content);
+    if (!mma.contentParent()) {
+      return false;
+    }
+    aData.attachments().AppendElement(mma);
+  }
+
+  return true;
+}
+
 NS_IMETHODIMP
 MmsMessage::GetType(nsAString& aType)
 {
   aType = NS_LITERAL_STRING("mms");
   return NS_OK;
 }
 
 NS_IMETHODIMP
--- a/dom/mobilemessage/src/MmsMessage.h
+++ b/dom/mobilemessage/src/MmsMessage.h
@@ -11,16 +11,22 @@
 #include "jspubtd.h"
 #include "mozilla/dom/mobilemessage/Types.h"
 #include "mozilla/Attributes.h"
 #include "DictionaryHelpers.h"
 
 namespace mozilla {
 namespace dom {
 
+namespace mobilemessage {
+class MmsMessageData;
+} // namespace mobilemessage
+
+class ContentParent;
+
 class MmsMessage MOZ_FINAL : public nsIDOMMozMmsMessage
 {
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSIDOMMOZMMSMESSAGE
 
   MmsMessage(int32_t                                        aId,
              const uint64_t                                 aThreadId,
@@ -29,30 +35,35 @@ public:
              const nsAString&                               aSender,
              const nsTArray<nsString>&                      aReceivers,
              uint64_t                                       aTimestamp,
              bool                                           aRead,
              const nsAString&                               aSubject,
              const nsAString&                               aSmil,
              const nsTArray<MmsAttachment>&                 aAttachments);
 
+  MmsMessage(const mobilemessage::MmsMessageData& aData);
+
   static nsresult Create(int32_t               aId,
                          const uint64_t        aThreadId,
                          const nsAString&      aDelivery,
                          const JS::Value&      aDeliveryStatus,
                          const nsAString&      aSender,
                          const JS::Value&      aReceivers,
                          const JS::Value&      aTimestamp,
                          bool                  aRead,
                          const nsAString&      aSubject,
                          const nsAString&      aSmil,
                          const JS::Value&      aAttachments,
                          JSContext*            aCx,
                          nsIDOMMozMmsMessage** aMessage);
 
+  bool GetData(ContentParent* aParent,
+               mobilemessage::MmsMessageData& aData);
+
 private:
 
   int32_t                                 mId;
   uint64_t                                mThreadId;
   mobilemessage::DeliveryState            mDelivery;
   nsTArray<mobilemessage::DeliveryStatus> mDeliveryStatus;
   nsString                                mSender;
   nsTArray<nsString>                      mReceivers;
--- a/dom/mobilemessage/src/ipc/SmsChild.cpp
+++ b/dom/mobilemessage/src/ipc/SmsChild.cpp
@@ -1,89 +1,110 @@
 /* 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/. */
 
 #include "SmsChild.h"
 #include "SmsMessage.h"
+#include "MmsMessage.h"
 #include "Constants.h"
 #include "nsIObserverService.h"
 #include "mozilla/Services.h"
 #include "mozilla/dom/ContentChild.h"
 #include "MobileMessageThread.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 using namespace mozilla::dom::mobilemessage;
 
 namespace {
 
+already_AddRefed<nsISupports>
+CreateMessageFromMessageData(const MobileMessageData& aData)
+{
+  nsCOMPtr<nsISupports> message;
+
+  switch(aData. type()) {
+    case MobileMessageData::TMmsMessageData:
+      message = new MmsMessage(aData.get_MmsMessageData());
+      break;
+    case MobileMessageData::TSmsMessageData:
+      message = new SmsMessage(aData.get_SmsMessageData());
+      break;
+    default:
+      MOZ_NOT_REACHED("Unexpected type of MobileMessageData");
+      return nullptr;
+  }
+
+  return message.forget();
+}
+
 void
-NotifyObserversWithSmsMessage(const char* aEventName,
-                              const SmsMessageData& aMessageData)
+NotifyObserversWithMobileMessage(const char* aEventName,
+                                 const MobileMessageData& aData)
 {
   nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
   if (!obs) {
     return;
   }
 
-  nsCOMPtr<SmsMessage> message = new SmsMessage(aMessageData);
-  obs->NotifyObservers(message, aEventName, nullptr);
+  nsCOMPtr<nsISupports> msg = CreateMessageFromMessageData(aData);
+  obs->NotifyObservers(msg, aEventName, nullptr);
 }
 
 } // anonymous namespace
 
 namespace mozilla {
 namespace dom {
 namespace mobilemessage {
 
 void
 SmsChild::ActorDestroy(ActorDestroyReason aWhy)
 {
 }
 
 bool
-SmsChild::RecvNotifyReceivedMessage(const SmsMessageData& aMessageData)
+SmsChild::RecvNotifyReceivedMessage(const MobileMessageData& aData)
 {
-  NotifyObserversWithSmsMessage(kSmsReceivedObserverTopic, aMessageData);
+  NotifyObserversWithMobileMessage(kSmsReceivedObserverTopic, aData);
   return true;
 }
 
 bool
-SmsChild::RecvNotifySendingMessage(const SmsMessageData& aMessageData)
+SmsChild::RecvNotifySendingMessage(const MobileMessageData& aData)
 {
-  NotifyObserversWithSmsMessage(kSmsSendingObserverTopic, aMessageData);
+  NotifyObserversWithMobileMessage(kSmsSendingObserverTopic, aData);
   return true;
 }
 
 bool
-SmsChild::RecvNotifySentMessage(const SmsMessageData& aMessageData)
+SmsChild::RecvNotifySentMessage(const MobileMessageData& aData)
 {
-  NotifyObserversWithSmsMessage(kSmsSentObserverTopic, aMessageData);
+  NotifyObserversWithMobileMessage(kSmsSentObserverTopic, aData);
   return true;
 }
 
 bool
-SmsChild::RecvNotifyFailedMessage(const SmsMessageData& aMessageData)
+SmsChild::RecvNotifyFailedMessage(const MobileMessageData& aData)
 {
-  NotifyObserversWithSmsMessage(kSmsFailedObserverTopic, aMessageData);
+  NotifyObserversWithMobileMessage(kSmsFailedObserverTopic, aData);
   return true;
 }
 
 bool
-SmsChild::RecvNotifyDeliverySuccessMessage(const SmsMessageData& aMessageData)
+SmsChild::RecvNotifyDeliverySuccessMessage(const MobileMessageData& aData)
 {
-  NotifyObserversWithSmsMessage(kSmsDeliverySuccessObserverTopic, aMessageData);
+  NotifyObserversWithMobileMessage(kSmsDeliverySuccessObserverTopic, aData);
   return true;
 }
 
 bool
-SmsChild::RecvNotifyDeliveryErrorMessage(const SmsMessageData& aMessageData)
+SmsChild::RecvNotifyDeliveryErrorMessage(const MobileMessageData& aData)
 {
-  NotifyObserversWithSmsMessage(kSmsDeliveryErrorObserverTopic, aMessageData);
+  NotifyObserversWithMobileMessage(kSmsDeliveryErrorObserverTopic, aData);
   return true;
 }
 
 PSmsRequestChild*
 SmsChild::AllocPSmsRequest(const IPCSmsRequest& aRequest)
 {
   MOZ_NOT_REACHED("Caller is supposed to manually construct a request!");
   return nullptr;
@@ -131,26 +152,32 @@ SmsRequestChild::ActorDestroy(ActorDestr
 
 bool
 SmsRequestChild::Recv__delete__(const MessageReply& aReply)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(mReplyRequest);
   nsCOMPtr<SmsMessage> message;
   switch(aReply.type()) {
-    case MessageReply::TReplyMessageSend:
-      message = new SmsMessage(aReply.get_ReplyMessageSend().messageData());
-      mReplyRequest->NotifyMessageSent(message);
+    case MessageReply::TReplyMessageSend: {
+        const MobileMessageData& data =
+          aReply.get_ReplyMessageSend().messageData();
+        nsCOMPtr<nsISupports> msg = CreateMessageFromMessageData(data);
+        mReplyRequest->NotifyMessageSent(msg);
+      }
       break;
     case MessageReply::TReplyMessageSendFail:
       mReplyRequest->NotifySendMessageFailed(aReply.get_ReplyMessageSendFail().error());
       break;
-    case MessageReply::TReplyGetMessage:
-      message = new SmsMessage(aReply.get_ReplyGetMessage().messageData());
-      mReplyRequest->NotifyMessageGot(message);
+    case MessageReply::TReplyGetMessage: {
+        const MobileMessageData& data =
+          aReply.get_ReplyGetMessage().messageData();
+        nsCOMPtr<nsISupports> msg = CreateMessageFromMessageData(data);
+        mReplyRequest->NotifyMessageGot(msg);
+      }
       break;
     case MessageReply::TReplyGetMessageFail:
       mReplyRequest->NotifyGetMessageFailed(aReply.get_ReplyGetMessageFail().error());
       break;
     case MessageReply::TReplyMessageDelete:
       mReplyRequest->NotifyMessageDeleted(aReply.get_ReplyMessageDelete().deleted());
       break;
     case MessageReply::TReplyMessageDeleteFail:
@@ -191,16 +218,19 @@ MobileMessageCursorChild::ActorDestroy(A
 
 bool
 MobileMessageCursorChild::RecvNotifyResult(const MobileMessageCursorData& aData)
 {
   MOZ_ASSERT(mCursorCallback);
 
   nsCOMPtr<nsISupports> result;
   switch(aData.type()) {
+    case MobileMessageCursorData::TMmsMessageData:
+      result = new MmsMessage(aData.get_MmsMessageData());
+      break;
     case MobileMessageCursorData::TSmsMessageData:
       result = new SmsMessage(aData.get_SmsMessageData());
       break;
     case MobileMessageCursorData::TThreadData:
       result = new MobileMessageThread(aData.get_ThreadData());
       break;
     default:
       MOZ_NOT_REACHED("Received invalid response parameters!");
--- a/dom/mobilemessage/src/ipc/SmsChild.h
+++ b/dom/mobilemessage/src/ipc/SmsChild.h
@@ -30,32 +30,32 @@ protected:
   {
     MOZ_COUNT_DTOR(SmsChild);
   }
 
   virtual void
   ActorDestroy(ActorDestroyReason aWhy) MOZ_OVERRIDE;
 
   virtual bool
-  RecvNotifyReceivedMessage(const SmsMessageData& aMessage) MOZ_OVERRIDE;
+  RecvNotifyReceivedMessage(const MobileMessageData& aMessage) MOZ_OVERRIDE;
 
   virtual bool
-  RecvNotifySendingMessage(const SmsMessageData& aMessage) MOZ_OVERRIDE;
+  RecvNotifySendingMessage(const MobileMessageData& aMessage) MOZ_OVERRIDE;
 
   virtual bool
-  RecvNotifySentMessage(const SmsMessageData& aMessage) MOZ_OVERRIDE;
+  RecvNotifySentMessage(const MobileMessageData& aMessage) MOZ_OVERRIDE;
 
   virtual bool
-  RecvNotifyFailedMessage(const SmsMessageData& aMessage) MOZ_OVERRIDE;
+  RecvNotifyFailedMessage(const MobileMessageData& aMessage) MOZ_OVERRIDE;
 
   virtual bool
-  RecvNotifyDeliverySuccessMessage(const SmsMessageData& aMessage) MOZ_OVERRIDE;
+  RecvNotifyDeliverySuccessMessage(const MobileMessageData& aMessage) MOZ_OVERRIDE;
 
   virtual bool
-  RecvNotifyDeliveryErrorMessage(const SmsMessageData& aMessage) MOZ_OVERRIDE;
+  RecvNotifyDeliveryErrorMessage(const MobileMessageData& aMessage) MOZ_OVERRIDE;
 
   virtual PSmsRequestChild*
   AllocPSmsRequest(const IPCSmsRequest& aRequest) MOZ_OVERRIDE;
 
   virtual bool
   DeallocPSmsRequest(PSmsRequestChild* aActor) MOZ_OVERRIDE;
 
   virtual PMobileMessageCursorChild*
--- a/dom/mobilemessage/src/ipc/SmsIPCService.cpp
+++ b/dom/mobilemessage/src/ipc/SmsIPCService.cpp
@@ -6,16 +6,19 @@
 #include "mozilla/dom/ContentChild.h"
 #include "SmsIPCService.h"
 #include "nsXULAppAPI.h"
 #include "jsapi.h"
 #include "mozilla/dom/mobilemessage/SmsChild.h"
 #include "SmsMessage.h"
 #include "SmsFilter.h"
 #include "SmsSegmentInfo.h"
+#include "DictionaryHelpers.h"
+#include "nsJSUtils.h"
+#include "nsContentUtils.h"
 
 using namespace mozilla::dom;
 using namespace mozilla::dom::mobilemessage;
 
 namespace {
 
 // TODO: Bug 767082 - WebSMS: sSmsChild leaks at shutdown
 PSmsChild* gSmsChild;
@@ -106,18 +109,19 @@ SmsIPCService::GetSegmentInfoForText(con
   return NS_OK;
 }
 
 NS_IMETHODIMP
 SmsIPCService::Send(const nsAString& aNumber,
                     const nsAString& aMessage,
                     nsIMobileMessageCallback* aRequest)
 {
-  return SendRequest(SendMessageRequest(nsString(aNumber), nsString(aMessage)),
-                     aRequest);
+  return SendRequest(SendMessageRequest(SendSmsMessageRequest(nsString(aNumber),
+                                                              nsString(aMessage))),
+                     aRequest) ? NS_OK : NS_ERROR_FAILURE;
 }
 
 /*
  * Implementation of nsIMobileMessageDatabaseService.
  */
 NS_IMETHODIMP
 SmsIPCService::GetMessageMoz(int32_t aMessageId,
                              nsIMobileMessageCallback* aRequest)
@@ -156,15 +160,101 @@ SmsIPCService::MarkMessageRead(int32_t a
 NS_IMETHODIMP
 SmsIPCService::CreateThreadCursor(nsIMobileMessageCursorCallback* aCursorCallback,
                                   nsICursorContinueCallback** aResult)
 {
   return SendCursorRequest(CreateThreadCursorRequest(), aCursorCallback,
                            aResult);
 }
 
+bool
+GetSendMmsMessageRequestFromParams(const JS::Value& aParam,
+                                   SendMmsMessageRequest& request)
+{
+  if (aParam.isUndefined() || aParam.isNull() || !aParam.isObject()) {
+    return false;
+  }
+
+  JSContext* cx = nsContentUtils::GetSafeJSContext();
+  MmsParameters params;
+  nsresult rv = params.Init(cx, &aParam);
+  NS_ENSURE_SUCCESS(rv, false);
+
+  uint32_t len;
+
+  // SendMobileMessageRequest.receivers
+  if (!params.receivers.isObject()) {
+    return false;
+  }
+  JSObject &receiversObj = params.receivers.toObject();
+  if (!JS_GetArrayLength(cx, &receiversObj, &len)) {
+    return false;
+  }
+
+  request.receivers().SetCapacity(len);
+
+  for (uint32_t i = 0; i < len; i++) {
+    JS::Value val;
+    if (!JS_GetElement(cx, &receiversObj, i, &val)) {
+      return false;
+    }
+
+    if (!val.isString()) {
+      return false;
+    }
+
+    nsDependentJSString str;
+    if (!str.init(cx, val.toString())) {
+      return false;
+    }
+
+    request.receivers().AppendElement(str);
+  }
+
+  // SendMobileMessageRequest.attachments
+  mozilla::dom::ContentChild* cc = mozilla::dom::ContentChild::GetSingleton();
+
+  if (!params.attachments.isObject()) {
+    return false;
+  }
+  JSObject &attachmentsObj = params.attachments.toObject();
+  if (!JS_GetArrayLength(cx, &attachmentsObj, &len)) {
+    return false;
+  }
+  request.attachments().SetCapacity(len);
+
+  for (uint32_t i = 0; i < len; i++) {
+    JS::Value val;
+    if (!JS_GetElement(cx, &attachmentsObj, i, &val)) {
+      return false;
+    }
+
+    MmsAttachment attachment;
+    rv = attachment.Init(cx, &val);
+    NS_ENSURE_SUCCESS(rv, false);
+
+    MmsAttachmentData mmsAttachment;
+    mmsAttachment.id().Assign(attachment.id);
+    mmsAttachment.location().Assign(attachment.location);
+    mmsAttachment.contentChild() = cc->GetOrCreateActorForBlob(attachment.content);
+    if (!mmsAttachment.contentChild()) {
+      return false;
+    }
+    request.attachments().AppendElement(mmsAttachment);
+  }
+
+  request.smil() = params.smil;
+  request.subject() = params.subject;
+
+  return true;
+}
+
 NS_IMETHODIMP
 SmsIPCService::Send(const JS::Value& aParameters,
                     nsIMobileMessageCallback *aRequest)
 {
-  return NS_ERROR_NOT_IMPLEMENTED;
+  SendMmsMessageRequest req;
+  if (!GetSendMmsMessageRequestFromParams(aParameters, req)) {
+    return NS_ERROR_UNEXPECTED;
+  }
+  return SendRequest(SendMessageRequest(req), aRequest);
 }
 
--- a/dom/mobilemessage/src/ipc/SmsParent.cpp
+++ b/dom/mobilemessage/src/ipc/SmsParent.cpp
@@ -1,30 +1,191 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* 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/. */
 
 #include "SmsParent.h"
 #include "nsISmsService.h"
+#include "nsIMmsService.h"
 #include "nsIObserverService.h"
 #include "mozilla/Services.h"
 #include "Constants.h"
 #include "nsIDOMSmsMessage.h"
+#include "nsIDOMMozMmsMessage.h"
 #include "mozilla/unused.h"
 #include "SmsMessage.h"
+#include "MmsMessage.h"
 #include "nsIMobileMessageDatabaseService.h"
 #include "SmsFilter.h"
 #include "SmsSegmentInfo.h"
 #include "MobileMessageThread.h"
+#include "nsIDOMFile.h"
+#include "mozilla/dom/ipc/Blob.h"
+#include "mozilla/dom/ContentParent.h"
+#include "nsContentUtils.h"
+#include "nsTArrayHelpers.h"
+
+namespace {
+
+// Bug 819791 is not uplifted in b2g18 branch.
+inline nsresult
+InfallibleTArrayToJSArray(JSContext* aCx,
+                          const InfallibleTArray<nsString>& aSourceArray,
+                          JSObject** aResultArray)
+{
+  MOZ_ASSERT(aCx);
+  JSAutoRequest ar(aCx);
+
+  JSObject* arrayObj = JS_NewArrayObject(aCx, aSourceArray.Length(), nullptr);
+  if (!arrayObj) {
+    NS_WARNING("JS_NewArrayObject failed!");
+    return NS_ERROR_OUT_OF_MEMORY;
+  }
+
+  for (uint32_t index = 0; index < aSourceArray.Length(); index++) {
+    JSString* s = JS_NewUCStringCopyN(aCx, aSourceArray[index].BeginReading(),
+                                      aSourceArray[index].Length());
+
+    if(!s) {
+      NS_WARNING("Memory allocation error!");
+      return NS_ERROR_OUT_OF_MEMORY;
+    }
+
+    jsval wrappedVal = STRING_TO_JSVAL(s);
+
+    if (!JS_SetElement(aCx, arrayObj, index, &wrappedVal)) {
+      NS_WARNING("JS_SetElement failed!");
+      return NS_ERROR_FAILURE;
+    }
+  }
+
+  if (!JS_FreezeObject(aCx, arrayObj)) {
+    NS_WARNING("JS_FreezeObject failed!");
+    return NS_ERROR_FAILURE;
+  }
+
+  *aResultArray = arrayObj;
+  return NS_OK;
+}
+
+} // anonymous namespace
 
 namespace mozilla {
 namespace dom {
 namespace mobilemessage {
 
+static JSObject*
+MmsAttachmentDataToJSObject(JSContext* aContext,
+                            const MmsAttachmentData& aAttachment)
+{
+  JSAutoRequest ar(aContext);
+
+  JSObject* obj = JS_NewObject(aContext, nullptr, nullptr, nullptr);
+  NS_ENSURE_TRUE(obj, nullptr);
+
+  JSString* idStr = JS_NewUCStringCopyN(aContext,
+                                        aAttachment.id().get(),
+                                        aAttachment.id().Length());
+  NS_ENSURE_TRUE(idStr, nullptr);
+  if (!JS_DefineProperty(aContext, obj, "id", JS::StringValue(idStr),
+                         nullptr, nullptr, 0)) {
+    return nullptr;
+  }
+
+  JSString* locStr = JS_NewUCStringCopyN(aContext,
+                                         aAttachment.location().get(),
+                                         aAttachment.location().Length());
+  NS_ENSURE_TRUE(locStr, nullptr);
+  if (!JS_DefineProperty(aContext, obj, "location", JS::StringValue(locStr),
+                         nullptr, nullptr, 0)) {
+    return nullptr;
+  }
+
+  nsCOMPtr<nsIDOMBlob> blob = static_cast<BlobParent*>(aAttachment.contentParent())->GetBlob();
+  JS::Value content;
+  nsresult rv = nsContentUtils::WrapNative(aContext,
+                                           JS_GetGlobalForScopeChain(aContext),
+                                           blob,
+                                           &NS_GET_IID(nsIDOMBlob),
+                                           &content);
+  NS_ENSURE_SUCCESS(rv, nullptr);
+  if (!JS_DefineProperty(aContext, obj, "content", content,
+                         nullptr, nullptr, 0)) {
+    return nullptr;
+  }
+
+  return obj;
+}
+
+static bool
+GetParamsFromSendMmsMessageRequest(JSContext* aCx,
+                                   const SendMmsMessageRequest& aRequest,
+                                   JS::Value* aParam)
+{
+  JSAutoRequest ar(aCx);
+
+  JSObject* paramsObj = JS_NewObject(aCx, nullptr, nullptr, nullptr);
+  NS_ENSURE_TRUE(paramsObj, false);
+
+  // smil
+  JSString* smilStr = JS_NewUCStringCopyN(aCx,
+                                          aRequest.smil().get(),
+                                          aRequest.smil().Length());
+  NS_ENSURE_TRUE(smilStr, false);
+  if(!JS_DefineProperty(aCx, paramsObj, "smil", JS::StringValue(smilStr),
+                        nullptr, nullptr, 0)) {
+    return false;
+  }
+
+  // subject
+  JSString* subjectStr = JS_NewUCStringCopyN(aCx,
+                                             aRequest.subject().get(),
+                                             aRequest.subject().Length());
+  NS_ENSURE_TRUE(subjectStr, false);
+  if(!JS_DefineProperty(aCx, paramsObj, "subject",
+                        JS::StringValue(subjectStr), nullptr, nullptr, 0)) {
+    return false;
+  }
+
+  // receivers
+  JSObject* receiverArray;
+  if (NS_FAILED(InfallibleTArrayToJSArray(aCx,
+                                          aRequest.receivers(),
+                                          &receiverArray))) {
+    return false;
+  }
+  if (!JS_DefineProperty(aCx, paramsObj, "receivers",
+                         JS::ObjectValue(*receiverArray), nullptr, nullptr, 0)) {
+    return false;
+  }
+
+  // attachments
+  JSObject* attachmentArray = JS_NewArrayObject(aCx,
+                                                aRequest.attachments().Length(),
+                                                nullptr);
+  for (uint32_t i = 0; i < aRequest.attachments().Length(); i++) {
+    JSObject *obj = MmsAttachmentDataToJSObject(aCx,
+                                                aRequest.attachments().ElementAt(i));
+    NS_ENSURE_TRUE(obj, false);
+    jsval val = JS::ObjectValue(*obj);
+    if (!JS_SetElement(aCx, attachmentArray, i, &val)) {
+      return false;
+    }
+  }
+
+  if (!JS_DefineProperty(aCx, paramsObj, "attachments",
+                         JS::ObjectValue(*attachmentArray), nullptr, nullptr, 0)) {
+    return false;
+  }
+
+  aParam->setObject(*paramsObj);
+  return true;
+}
+
 NS_IMPL_ISUPPORTS1(SmsParent, nsIObserver)
 
 SmsParent::SmsParent()
 {
   MOZ_COUNT_CTOR(SmsParent);
   nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
   if (!obs) {
     return;
@@ -54,85 +215,110 @@ SmsParent::ActorDestroy(ActorDestroyReas
   obs->RemoveObserver(this, kSmsDeliveryErrorObserverTopic);
 }
 
 NS_IMETHODIMP
 SmsParent::Observe(nsISupports* aSubject, const char* aTopic,
                    const PRUnichar* aData)
 {
   if (!strcmp(aTopic, kSmsReceivedObserverTopic)) {
-    nsCOMPtr<nsIDOMMozSmsMessage> message = do_QueryInterface(aSubject);
-    if (!message) {
+    MobileMessageData msgData;
+    if (!GetMobileMessageDataFromMessage(aSubject, msgData)) {
       NS_ERROR("Got a 'sms-received' topic without a valid message!");
       return NS_OK;
     }
 
-    unused << SendNotifyReceivedMessage(static_cast<SmsMessage*>(message.get())->GetData());
+    unused << SendNotifyReceivedMessage(msgData);
     return NS_OK;
   }
 
   if (!strcmp(aTopic, kSmsSendingObserverTopic)) {
-    nsCOMPtr<nsIDOMMozSmsMessage> message = do_QueryInterface(aSubject);
-    if (!message) {
+    MobileMessageData msgData;
+    if (!GetMobileMessageDataFromMessage(aSubject, msgData)) {
       NS_ERROR("Got a 'sms-sending' topic without a valid message!");
       return NS_OK;
     }
 
-    unused << SendNotifySendingMessage(static_cast<SmsMessage*>(message.get())->GetData());
+    unused << SendNotifySendingMessage(msgData);
     return NS_OK;
   }
 
   if (!strcmp(aTopic, kSmsSentObserverTopic)) {
-    nsCOMPtr<nsIDOMMozSmsMessage> message = do_QueryInterface(aSubject);
-    if (!message) {
+    MobileMessageData msgData;
+    if (!GetMobileMessageDataFromMessage(aSubject, msgData)) {
       NS_ERROR("Got a 'sms-sent' topic without a valid message!");
       return NS_OK;
     }
 
-    unused << SendNotifySentMessage(static_cast<SmsMessage*>(message.get())->GetData());
+    unused << SendNotifySentMessage(msgData);
     return NS_OK;
   }
 
   if (!strcmp(aTopic, kSmsFailedObserverTopic)) {
-    nsCOMPtr<nsIDOMMozSmsMessage> message = do_QueryInterface(aSubject);
-    if (!message) {
+    MobileMessageData msgData;
+    if (!GetMobileMessageDataFromMessage(aSubject, msgData)) {
       NS_ERROR("Got a 'sms-failed' topic without a valid message!");
       return NS_OK;
     }
 
-    unused << SendNotifyFailedMessage(static_cast<SmsMessage*>(message.get())->GetData());
+    unused << SendNotifyFailedMessage(msgData);
     return NS_OK;
   }
 
   if (!strcmp(aTopic, kSmsDeliverySuccessObserverTopic)) {
-    nsCOMPtr<nsIDOMMozSmsMessage> message = do_QueryInterface(aSubject);
-    if (!message) {
-      NS_ERROR("Got a 'sms-delivery-success' topic without a valid message!");
+    MobileMessageData msgData;
+    if (!GetMobileMessageDataFromMessage(aSubject, msgData)) {
+      NS_ERROR("Got a 'sms-sending' topic without a valid message!");
       return NS_OK;
     }
 
-    unused << SendNotifyDeliverySuccessMessage(static_cast<SmsMessage*>(message.get())->GetData());
+    unused << SendNotifyDeliverySuccessMessage(msgData);
     return NS_OK;
   }
 
   if (!strcmp(aTopic, kSmsDeliveryErrorObserverTopic)) {
-    nsCOMPtr<nsIDOMMozSmsMessage> message = do_QueryInterface(aSubject);
-    if (!message) {
+    MobileMessageData msgData;
+    if (!GetMobileMessageDataFromMessage(aSubject, msgData)) {
       NS_ERROR("Got a 'sms-delivery-error' topic without a valid message!");
       return NS_OK;
     }
 
-    unused << SendNotifyDeliveryErrorMessage(static_cast<SmsMessage*>(message.get())->GetData());
+    unused << SendNotifyDeliveryErrorMessage(msgData);
     return NS_OK;
   }
 
   return NS_OK;
 }
 
 bool
+SmsParent::GetMobileMessageDataFromMessage(nsISupports *aMsg,
+                                           MobileMessageData &aData)
+{
+  nsCOMPtr<nsIDOMMozMmsMessage> mmsMsg = do_QueryInterface(aMsg);
+  if (mmsMsg) {
+    MmsMessageData data;
+    ContentParent *parent = static_cast<ContentParent*>(Manager());
+    if (!static_cast<MmsMessage*>(mmsMsg.get())->GetData(parent, data)) {
+      return false;
+    }
+    aData = data;
+    return true;
+  }
+
+  nsCOMPtr<nsIDOMMozSmsMessage> smsMsg = do_QueryInterface(aMsg);
+  if (smsMsg) {
+    aData = static_cast<SmsMessage*>(smsMsg.get())->GetData();
+    return true;
+  }
+
+  NS_WARNING("Cannot get MobileMessageData");
+  return false;
+}
+
+bool
 SmsParent::RecvHasSupport(bool* aHasSupport)
 {
   *aHasSupport = false;
 
   nsCOMPtr<nsISmsService> smsService = do_GetService(SMS_SERVICE_CONTRACTID);
   NS_ENSURE_TRUE(smsService, true);
 
   smsService->HasSupport(aHasSupport);
@@ -259,27 +445,45 @@ void
 SmsRequestParent::ActorDestroy(ActorDestroyReason aWhy)
 {
   mActorDestroyed = true;
 }
 
 bool
 SmsRequestParent::DoRequest(const SendMessageRequest& aRequest)
 {
-  nsresult rv = NS_ERROR_FAILURE;
+  switch(aRequest.type()) {
+  case SendMessageRequest::TSendSmsMessageRequest: {
+      nsCOMPtr<nsISmsService> smsService = do_GetService(SMS_SERVICE_CONTRACTID);
+      NS_ENSURE_TRUE(smsService, true);
+
+      const SendSmsMessageRequest &data = aRequest.get_SendSmsMessageRequest();
+      smsService->Send(data.number(), data.message(), this);
+    }
+    break;
+  case SendMessageRequest::TSendMmsMessageRequest: {
+      nsCOMPtr<nsIMmsService> mmsService = do_GetService(MMS_SERVICE_CONTRACTID);
+      NS_ENSURE_TRUE(mmsService, true);
 
-  nsCOMPtr<nsISmsService> smsService = do_GetService(SMS_SERVICE_CONTRACTID);
-  if (smsService) {
-    rv = smsService->Send(aRequest.number(), aRequest.message(), this);
+      JS::Value params;
+      JSContext* cx = nsContentUtils::GetSafeJSContext();
+      if (!GetParamsFromSendMmsMessageRequest(
+              cx,
+              aRequest.get_SendMmsMessageRequest(),
+              &params)) {
+        NS_WARNING("SmsRequestParent: Fail to build MMS params.");
+        return true;
+      }
+      mmsService->Send(params, this);
+    }
+    break;
+  default:
+    MOZ_NOT_REACHED("Unknown type of SendMessageRequest!");
+    return false;
   }
-
-  if (NS_FAILED(rv)) {
-    return NS_SUCCEEDED(NotifySendMessageFailed(nsIMobileMessageCallback::INTERNAL_ERROR));
-  }
-
   return true;
 }
 
 bool
 SmsRequestParent::DoRequest(const GetMessageRequest& aRequest)
 {
   nsresult rv = NS_ERROR_FAILURE;
 
@@ -344,31 +548,63 @@ SmsRequestParent::SendReply(const Messag
   return Send__delete__(this, aReply) ? NS_OK : NS_ERROR_FAILURE;
 }
 
 // nsIMobileMessageCallback
 
 NS_IMETHODIMP
 SmsRequestParent::NotifyMessageSent(nsISupports *aMessage)
 {
-  SmsMessage* message = static_cast<SmsMessage*>(aMessage);
-  return SendReply(ReplyMessageSend(message->GetData()));
+  nsCOMPtr<nsIDOMMozMmsMessage> mms = do_QueryInterface(aMessage);
+  if (mms) {
+    MmsMessage *msg = static_cast<MmsMessage*>(mms.get());
+    ContentParent *parent = static_cast<ContentParent*>(Manager()->Manager());
+    MmsMessageData data;
+    if (!msg->GetData(parent, data)) {
+      return NS_ERROR_FAILURE;
+    }
+    return SendReply(MessageReply(ReplyMessageSend(MobileMessageData(data))));
+  }
+
+  nsCOMPtr<nsIDOMMozSmsMessage> sms = do_QueryInterface(aMessage);
+  if (sms) {
+    SmsMessage* msg = static_cast<SmsMessage*>(sms.get());
+    return SendReply(MessageReply(ReplyMessageSend(MobileMessageData(msg->GetData()))));
+  }
+
+  return NS_ERROR_FAILURE;
 }
 
 NS_IMETHODIMP
 SmsRequestParent::NotifySendMessageFailed(int32_t aError)
 {
   return SendReply(ReplyMessageSendFail(aError));
 }
 
 NS_IMETHODIMP
 SmsRequestParent::NotifyMessageGot(nsISupports *aMessage)
 {
-  SmsMessage* message = static_cast<SmsMessage*>(aMessage);
-  return SendReply(ReplyGetMessage(message->GetData()));
+  nsCOMPtr<nsIDOMMozMmsMessage> mms = do_QueryInterface(aMessage);
+  if (mms) {
+    MmsMessage *msg = static_cast<MmsMessage*>(mms.get());
+    ContentParent *parent = static_cast<ContentParent*>(Manager()->Manager());
+    MmsMessageData data;
+    if (!msg->GetData(parent, data)) {
+      return NS_ERROR_FAILURE;
+    }
+    return SendReply(MessageReply(ReplyGetMessage(MobileMessageData(data))));
+  }
+
+  nsCOMPtr<nsIDOMMozSmsMessage> sms = do_QueryInterface(aMessage);
+  if (sms) {
+    SmsMessage* msg = static_cast<SmsMessage*>(sms.get());
+    return SendReply(MessageReply(ReplyGetMessage(MobileMessageData(msg->GetData()))));
+  }
+
+  return NS_ERROR_FAILURE;
 }
 
 NS_IMETHODIMP
 SmsRequestParent::NotifyGetMessageFailed(int32_t aError)
 {
   return SendReply(ReplyGetMessageFail(aError));
 }
 
--- a/dom/mobilemessage/src/ipc/SmsParent.h
+++ b/dom/mobilemessage/src/ipc/SmsParent.h
@@ -60,16 +60,19 @@ protected:
   RecvPMobileMessageCursorConstructor(PMobileMessageCursorParent* aActor,
                                       const IPCMobileMessageCursor& aCursor) MOZ_OVERRIDE;
 
   virtual PMobileMessageCursorParent*
   AllocPMobileMessageCursor(const IPCMobileMessageCursor& aCursor) MOZ_OVERRIDE;
 
   virtual bool
   DeallocPMobileMessageCursor(PMobileMessageCursorParent* aActor) MOZ_OVERRIDE;
+
+  bool
+  GetMobileMessageDataFromMessage(nsISupports* aMsg, MobileMessageData& aData);
 };
 
 class SmsRequestParent : public PSmsRequestParent
                        , public nsIMobileMessageCallback
 {
   friend class SmsParent;
 
   bool mActorDestroyed;