1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
4 * You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include "MmsMessage.h"
7 #include "nsIDOMClassInfo.h"
8 #include "jsapi.h" // For OBJECT_TO_JSVAL and JS_NewDateObjectMsec
9 #include "jsfriendapi.h" // For js_DateGetMsecSinceEpoch
10 #include "nsJSUtils.h"
11 #include "nsContentUtils.h"
12 #include "nsTArrayHelpers.h"
13 #include "mozilla/dom/ContentParent.h"
14 #include "mozilla/dom/File.h"
15 #include "mozilla/dom/mobilemessage/Constants.h" // For MessageType
16 #include "mozilla/dom/mobilemessage/SmsTypes.h"
17 #include "mozilla/dom/ScriptSettings.h"
18 #include "mozilla/dom/ToJSValue.h"
19 #include "mozilla/dom/ipc/BlobChild.h"
20 #include "mozilla/dom/ipc/BlobParent.h"
22 using namespace mozilla::dom::mobilemessage
;
27 NS_INTERFACE_MAP_BEGIN(MmsMessage
)
28 NS_INTERFACE_MAP_ENTRY(nsIDOMMozMmsMessage
)
29 NS_INTERFACE_MAP_ENTRY(nsISupports
)
30 NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(MozMmsMessage
)
33 NS_IMPL_ADDREF(MmsMessage
)
34 NS_IMPL_RELEASE(MmsMessage
)
36 MmsMessage::MmsMessage(int32_t aId
,
38 const nsAString
& aIccId
,
39 DeliveryState aDelivery
,
40 const nsTArray
<MmsDeliveryInfo
>& aDeliveryInfo
,
41 const nsAString
& aSender
,
42 const nsTArray
<nsString
>& aReceivers
,
44 uint64_t aSentTimestamp
,
46 const nsAString
& aSubject
,
47 const nsAString
& aSmil
,
48 const nsTArray
<Attachment
>& aAttachments
,
50 bool aReadReportRequested
)
55 mDeliveryInfo(aDeliveryInfo
),
57 mReceivers(aReceivers
),
58 mTimestamp(aTimestamp
),
59 mSentTimestamp(aSentTimestamp
),
63 mAttachments(aAttachments
),
64 mExpiryDate(aExpiryDate
),
65 mReadReportRequested(aReadReportRequested
)
69 MmsMessage::MmsMessage(const mobilemessage::MmsMessageData
& aData
)
71 , mThreadId(aData
.threadId())
72 , mIccId(aData
.iccId())
73 , mDelivery(aData
.delivery())
74 , mSender(aData
.sender())
75 , mReceivers(aData
.receivers())
76 , mTimestamp(aData
.timestamp())
77 , mSentTimestamp(aData
.sentTimestamp())
79 , mSubject(aData
.subject())
81 , mExpiryDate(aData
.expiryDate())
82 , mReadReportRequested(aData
.readReportRequested())
84 uint32_t len
= aData
.attachments().Length();
85 mAttachments
.SetCapacity(len
);
86 for (uint32_t i
= 0; i
< len
; i
++) {
88 const MmsAttachmentData
&element
= aData
.attachments()[i
];
89 att
.mId
= element
.id();
90 att
.mLocation
= element
.location();
92 // mContent is not going to be exposed to JS directly so we can use
94 if (element
.contentParent()) {
95 nsRefPtr
<FileImpl
> impl
= static_cast<BlobParent
*>(element
.contentParent())->GetBlobImpl();
96 att
.mContent
= new File(nullptr, impl
);
97 } else if (element
.contentChild()) {
98 nsRefPtr
<FileImpl
> impl
= static_cast<BlobChild
*>(element
.contentChild())->GetBlobImpl();
99 att
.mContent
= new File(nullptr, impl
);
101 NS_WARNING("MmsMessage: Unable to get attachment content.");
103 mAttachments
.AppendElement(att
);
106 len
= aData
.deliveryInfo().Length();
107 mDeliveryInfo
.SetCapacity(len
);
108 for (uint32_t i
= 0; i
< len
; i
++) {
109 MmsDeliveryInfo info
;
110 const MmsDeliveryInfoData
&infoData
= aData
.deliveryInfo()[i
];
112 // Prepare |info.mReceiver|.
113 info
.mReceiver
= infoData
.receiver();
115 // Prepare |info.mDeliveryStatus|.
117 switch (infoData
.deliveryStatus()) {
118 case eDeliveryStatus_NotApplicable
:
119 statusStr
= DELIVERY_STATUS_NOT_APPLICABLE
;
121 case eDeliveryStatus_Success
:
122 statusStr
= DELIVERY_STATUS_SUCCESS
;
124 case eDeliveryStatus_Pending
:
125 statusStr
= DELIVERY_STATUS_PENDING
;
127 case eDeliveryStatus_Error
:
128 statusStr
= DELIVERY_STATUS_ERROR
;
130 case eDeliveryStatus_Reject
:
131 statusStr
= DELIVERY_STATUS_REJECTED
;
133 case eDeliveryStatus_Manual
:
134 statusStr
= DELIVERY_STATUS_MANUAL
;
136 case eDeliveryStatus_EndGuard
:
138 MOZ_CRASH("We shouldn't get any other delivery status!");
140 info
.mDeliveryStatus
= statusStr
;
142 // Prepare |info.mDeliveryTimestamp|.
143 info
.mDeliveryTimestamp
= infoData
.deliveryTimestamp();
145 // Prepare |info.mReadStatus|.
146 nsString statusReadString
;
147 switch(infoData
.readStatus()) {
148 case eReadStatus_NotApplicable
:
149 statusReadString
= READ_STATUS_NOT_APPLICABLE
;
151 case eReadStatus_Success
:
152 statusReadString
= READ_STATUS_SUCCESS
;
154 case eReadStatus_Pending
:
155 statusReadString
= READ_STATUS_PENDING
;
157 case eReadStatus_Error
:
158 statusReadString
= READ_STATUS_ERROR
;
160 case eReadStatus_EndGuard
:
162 MOZ_CRASH("We shouldn't get any other read status!");
164 info
.mReadStatus
= statusReadString
;
166 // Prepare |info.mReadTimestamp|.
167 info
.mReadTimestamp
= infoData
.readTimestamp();
169 mDeliveryInfo
.AppendElement(info
);
173 /* static */ nsresult
174 MmsMessage::Create(int32_t aId
,
176 const nsAString
& aIccId
,
177 const nsAString
& aDelivery
,
178 const JS::Value
& aDeliveryInfo
,
179 const nsAString
& aSender
,
180 const JS::Value
& aReceivers
,
182 uint64_t aSentTimestamp
,
184 const nsAString
& aSubject
,
185 const nsAString
& aSmil
,
186 const JS::Value
& aAttachments
,
187 uint64_t aExpiryDate
,
188 bool aIsReadReportRequested
,
190 nsIDOMMozMmsMessage
** aMessage
)
195 DeliveryState delivery
;
196 if (aDelivery
.Equals(DELIVERY_SENT
)) {
197 delivery
= eDeliveryState_Sent
;
198 } else if (aDelivery
.Equals(DELIVERY_RECEIVED
)) {
199 delivery
= eDeliveryState_Received
;
200 } else if (aDelivery
.Equals(DELIVERY_SENDING
)) {
201 delivery
= eDeliveryState_Sending
;
202 } else if (aDelivery
.Equals(DELIVERY_NOT_DOWNLOADED
)) {
203 delivery
= eDeliveryState_NotDownloaded
;
204 } else if (aDelivery
.Equals(DELIVERY_ERROR
)) {
205 delivery
= eDeliveryState_Error
;
207 return NS_ERROR_INVALID_ARG
;
210 // Set |deliveryInfo|.
211 if (!aDeliveryInfo
.isObject()) {
212 return NS_ERROR_INVALID_ARG
;
214 JS::Rooted
<JSObject
*> deliveryInfoObj(aCx
, &aDeliveryInfo
.toObject());
215 if (!JS_IsArrayObject(aCx
, deliveryInfoObj
)) {
216 return NS_ERROR_INVALID_ARG
;
220 MOZ_ALWAYS_TRUE(JS_GetArrayLength(aCx
, deliveryInfoObj
, &length
));
222 nsTArray
<MmsDeliveryInfo
> deliveryInfo
;
223 JS::Rooted
<JS::Value
> infoJsVal(aCx
);
224 for (uint32_t i
= 0; i
< length
; ++i
) {
225 if (!JS_GetElement(aCx
, deliveryInfoObj
, i
, &infoJsVal
) ||
226 !infoJsVal
.isObject()) {
227 return NS_ERROR_INVALID_ARG
;
230 MmsDeliveryInfo info
;
231 if (!info
.Init(aCx
, infoJsVal
)) {
232 return NS_ERROR_TYPE_ERR
;
235 deliveryInfo
.AppendElement(info
);
239 if (!aReceivers
.isObject()) {
240 return NS_ERROR_INVALID_ARG
;
242 JS::Rooted
<JSObject
*> receiversObj(aCx
, &aReceivers
.toObject());
243 if (!JS_IsArrayObject(aCx
, receiversObj
)) {
244 return NS_ERROR_INVALID_ARG
;
247 MOZ_ALWAYS_TRUE(JS_GetArrayLength(aCx
, receiversObj
, &length
));
249 nsTArray
<nsString
> receivers
;
250 JS::Rooted
<JS::Value
> receiverJsVal(aCx
);
251 for (uint32_t i
= 0; i
< length
; ++i
) {
252 if (!JS_GetElement(aCx
, receiversObj
, i
, &receiverJsVal
) ||
253 !receiverJsVal
.isString()) {
254 return NS_ERROR_INVALID_ARG
;
257 nsAutoJSString receiverStr
;
258 if (!receiverStr
.init(aCx
, receiverJsVal
.toString())) {
259 return NS_ERROR_FAILURE
;
262 receivers
.AppendElement(receiverStr
);
265 // Set |attachments|.
266 if (!aAttachments
.isObject()) {
267 return NS_ERROR_INVALID_ARG
;
269 JS::Rooted
<JSObject
*> attachmentsObj(aCx
, &aAttachments
.toObject());
270 if (!JS_IsArrayObject(aCx
, attachmentsObj
)) {
271 return NS_ERROR_INVALID_ARG
;
274 nsTArray
<Attachment
> attachments
;
275 MOZ_ALWAYS_TRUE(JS_GetArrayLength(aCx
, attachmentsObj
, &length
));
277 JS::Rooted
<JS::Value
> attachmentJsVal(aCx
);
278 for (uint32_t i
= 0; i
< length
; ++i
) {
279 if (!JS_GetElement(aCx
, attachmentsObj
, i
, &attachmentJsVal
)) {
280 return NS_ERROR_INVALID_ARG
;
283 MmsAttachment attachment
;
284 if (!attachment
.Init(aCx
, attachmentJsVal
)) {
285 return NS_ERROR_TYPE_ERR
;
288 attachments
.AppendElement(attachment
);
291 nsCOMPtr
<nsIDOMMozMmsMessage
> message
= new MmsMessage(aId
,
305 aIsReadReportRequested
);
306 message
.forget(aMessage
);
311 MmsMessage::GetData(ContentParent
* aParent
,
312 mobilemessage::MmsMessageData
& aData
)
314 NS_ASSERTION(aParent
, "aParent is null");
317 aData
.threadId() = mThreadId
;
318 aData
.iccId() = mIccId
;
319 aData
.delivery() = mDelivery
;
320 aData
.sender().Assign(mSender
);
321 aData
.receivers() = mReceivers
;
322 aData
.timestamp() = mTimestamp
;
323 aData
.sentTimestamp() = mSentTimestamp
;
324 aData
.read() = mRead
;
325 aData
.subject() = mSubject
;
326 aData
.smil() = mSmil
;
327 aData
.expiryDate() = mExpiryDate
;
328 aData
.readReportRequested() = mReadReportRequested
;
330 aData
.deliveryInfo().SetCapacity(mDeliveryInfo
.Length());
331 for (uint32_t i
= 0; i
< mDeliveryInfo
.Length(); i
++) {
332 MmsDeliveryInfoData infoData
;
333 const MmsDeliveryInfo
&info
= mDeliveryInfo
[i
];
335 // Prepare |infoData.mReceiver|.
336 infoData
.receiver().Assign(info
.mReceiver
);
338 // Prepare |infoData.mDeliveryStatus|.
339 DeliveryStatus status
;
340 if (info
.mDeliveryStatus
.Equals(DELIVERY_STATUS_NOT_APPLICABLE
)) {
341 status
= eDeliveryStatus_NotApplicable
;
342 } else if (info
.mDeliveryStatus
.Equals(DELIVERY_STATUS_SUCCESS
)) {
343 status
= eDeliveryStatus_Success
;
344 } else if (info
.mDeliveryStatus
.Equals(DELIVERY_STATUS_PENDING
)) {
345 status
= eDeliveryStatus_Pending
;
346 } else if (info
.mDeliveryStatus
.Equals(DELIVERY_STATUS_ERROR
)) {
347 status
= eDeliveryStatus_Error
;
348 } else if (info
.mDeliveryStatus
.Equals(DELIVERY_STATUS_REJECTED
)) {
349 status
= eDeliveryStatus_Reject
;
350 } else if (info
.mDeliveryStatus
.Equals(DELIVERY_STATUS_MANUAL
)) {
351 status
= eDeliveryStatus_Manual
;
355 infoData
.deliveryStatus() = status
;
357 // Prepare |infoData.mDeliveryTimestamp|.
358 infoData
.deliveryTimestamp() = info
.mDeliveryTimestamp
;
360 // Prepare |infoData.mReadStatus|.
361 ReadStatus readStatus
;
362 if (info
.mReadStatus
.Equals(READ_STATUS_NOT_APPLICABLE
)) {
363 readStatus
= eReadStatus_NotApplicable
;
364 } else if (info
.mReadStatus
.Equals(READ_STATUS_SUCCESS
)) {
365 readStatus
= eReadStatus_Success
;
366 } else if (info
.mReadStatus
.Equals(READ_STATUS_PENDING
)) {
367 readStatus
= eReadStatus_Pending
;
368 } else if (info
.mReadStatus
.Equals(READ_STATUS_ERROR
)) {
369 readStatus
= eReadStatus_Error
;
373 infoData
.readStatus() = readStatus
;
375 // Prepare |infoData.mReadTimestamp|.
376 infoData
.readTimestamp() = info
.mReadTimestamp
;
378 aData
.deliveryInfo().AppendElement(infoData
);
381 aData
.attachments().SetCapacity(mAttachments
.Length());
382 for (uint32_t i
= 0; i
< mAttachments
.Length(); i
++) {
383 MmsAttachmentData mma
;
384 const Attachment
&element
= mAttachments
[i
];
385 mma
.id().Assign(element
.id
);
386 mma
.location().Assign(element
.location
);
388 // This is a workaround. Sometimes the blob we get from the database
389 // doesn't have a valid last modified date, making the ContentParent
390 // send a "Mystery Blob" to the ContentChild. Attempting to get the
391 // last modified date of blob can force that value to be initialized.
392 if (element
.content
->IsDateUnknown()) {
394 if (NS_FAILED(element
.content
->GetMozLastModifiedDate(&date
))) {
395 NS_WARNING("Failed to get last modified date!");
399 mma
.contentParent() = aParent
->GetOrCreateActorForBlob(element
.content
);
400 if (!mma
.contentParent()) {
403 aData
.attachments().AppendElement(mma
);
410 MmsMessage::GetType(nsAString
& aType
)
412 aType
= NS_LITERAL_STRING("mms");
417 MmsMessage::GetId(int32_t* aId
)
424 MmsMessage::GetThreadId(uint64_t* aThreadId
)
426 *aThreadId
= mThreadId
;
431 MmsMessage::GetIccId(nsAString
& aIccId
)
438 MmsMessage::GetDelivery(nsAString
& aDelivery
)
441 case eDeliveryState_Received
:
442 aDelivery
= DELIVERY_RECEIVED
;
444 case eDeliveryState_Sending
:
445 aDelivery
= DELIVERY_SENDING
;
447 case eDeliveryState_Sent
:
448 aDelivery
= DELIVERY_SENT
;
450 case eDeliveryState_Error
:
451 aDelivery
= DELIVERY_ERROR
;
453 case eDeliveryState_NotDownloaded
:
454 aDelivery
= DELIVERY_NOT_DOWNLOADED
;
456 case eDeliveryState_Unknown
:
457 case eDeliveryState_EndGuard
:
459 MOZ_CRASH("We shouldn't get any other delivery state!");
466 MmsMessage::GetDeliveryInfo(JSContext
* aCx
, JS::MutableHandle
<JS::Value
> aDeliveryInfo
)
468 // TODO Bug 850525 It'd be better to depend on the delivery of MmsMessage
469 // to return a more correct value. Ex, if .delivery = 'received', we should
470 // also make .deliveryInfo = null, since the .deliveryInfo is useless.
471 uint32_t length
= mDeliveryInfo
.Length();
473 aDeliveryInfo
.setNull();
477 if (!ToJSValue(aCx
, mDeliveryInfo
, aDeliveryInfo
)) {
478 return NS_ERROR_OUT_OF_MEMORY
;
485 MmsMessage::GetSender(nsAString
& aSender
)
492 MmsMessage::GetReceivers(JSContext
* aCx
, JS::MutableHandle
<JS::Value
> aReceivers
)
494 JS::Rooted
<JSObject
*> receiversObj(aCx
);
495 nsresult rv
= nsTArrayToJSArray(aCx
, mReceivers
, &receiversObj
);
496 NS_ENSURE_SUCCESS(rv
, rv
);
498 aReceivers
.setObject(*receiversObj
);
503 MmsMessage::GetTimestamp(DOMTimeStamp
* aTimestamp
)
505 *aTimestamp
= mTimestamp
;
510 MmsMessage::GetSentTimestamp(DOMTimeStamp
* aSentTimestamp
)
512 *aSentTimestamp
= mSentTimestamp
;
517 MmsMessage::GetRead(bool* aRead
)
524 MmsMessage::GetSubject(nsAString
& aSubject
)
531 MmsMessage::GetSmil(nsAString
& aSmil
)
538 MmsMessage::GetAttachments(JSContext
* aCx
, JS::MutableHandle
<JS::Value
> aAttachments
)
540 uint32_t length
= mAttachments
.Length();
542 JS::Rooted
<JSObject
*> attachments(
543 aCx
, JS_NewArrayObject(aCx
, length
));
544 NS_ENSURE_TRUE(attachments
, NS_ERROR_OUT_OF_MEMORY
);
546 for (uint32_t i
= 0; i
< length
; ++i
) {
547 const Attachment
&attachment
= mAttachments
[i
];
549 JS::Rooted
<JSObject
*> attachmentObj(
550 aCx
, JS_NewObject(aCx
, nullptr, JS::NullPtr(), JS::NullPtr()));
551 NS_ENSURE_TRUE(attachmentObj
, NS_ERROR_OUT_OF_MEMORY
);
553 JS::Rooted
<JSString
*> tmpJsStr(aCx
);
555 // Get |attachment.mId|.
556 tmpJsStr
= JS_NewUCStringCopyN(aCx
,
558 attachment
.id
.Length());
559 NS_ENSURE_TRUE(tmpJsStr
, NS_ERROR_OUT_OF_MEMORY
);
561 if (!JS_DefineProperty(aCx
, attachmentObj
, "id", tmpJsStr
, JSPROP_ENUMERATE
)) {
562 return NS_ERROR_FAILURE
;
565 // Get |attachment.mLocation|.
566 tmpJsStr
= JS_NewUCStringCopyN(aCx
,
567 attachment
.location
.get(),
568 attachment
.location
.Length());
569 NS_ENSURE_TRUE(tmpJsStr
, NS_ERROR_OUT_OF_MEMORY
);
571 if (!JS_DefineProperty(aCx
, attachmentObj
, "location", tmpJsStr
, JSPROP_ENUMERATE
)) {
572 return NS_ERROR_FAILURE
;
575 // Get |attachment.mContent|.
577 // Duplicating the File with the correct parent object.
578 nsIGlobalObject
*global
= xpc::NativeGlobal(JS::CurrentGlobalOrNull(aCx
));
580 nsRefPtr
<File
> newBlob
= new File(global
, attachment
.content
->Impl());
582 JS::Rooted
<JS::Value
> val(aCx
);
583 if (!GetOrCreateDOMReflector(aCx
, newBlob
, &val
)) {
584 return NS_ERROR_FAILURE
;
587 if (!JS_DefineProperty(aCx
, attachmentObj
, "content", val
, JSPROP_ENUMERATE
)) {
588 return NS_ERROR_FAILURE
;
591 if (!JS_SetElement(aCx
, attachments
, i
, attachmentObj
)) {
592 return NS_ERROR_FAILURE
;
596 aAttachments
.setObject(*attachments
);
601 MmsMessage::GetExpiryDate(DOMTimeStamp
* aExpiryDate
)
603 *aExpiryDate
= mExpiryDate
;
608 MmsMessage::GetReadReportRequested(bool* aReadReportRequested
)
610 *aReadReportRequested
= mReadReportRequested
;
616 } // namespace mozilla