Bumping manifests a=b2g-bump
[gecko.git] / dom / mobilemessage / MmsMessage.cpp
blobcd726f95dbedf46fb664caa6f8b9608d71fbfc62
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;
24 namespace mozilla {
25 namespace dom {
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)
31 NS_INTERFACE_MAP_END
33 NS_IMPL_ADDREF(MmsMessage)
34 NS_IMPL_RELEASE(MmsMessage)
36 MmsMessage::MmsMessage(int32_t aId,
37 uint64_t aThreadId,
38 const nsAString& aIccId,
39 DeliveryState aDelivery,
40 const nsTArray<MmsDeliveryInfo>& aDeliveryInfo,
41 const nsAString& aSender,
42 const nsTArray<nsString>& aReceivers,
43 uint64_t aTimestamp,
44 uint64_t aSentTimestamp,
45 bool aRead,
46 const nsAString& aSubject,
47 const nsAString& aSmil,
48 const nsTArray<Attachment>& aAttachments,
49 uint64_t aExpiryDate,
50 bool aReadReportRequested)
51 : mId(aId),
52 mThreadId(aThreadId),
53 mIccId(aIccId),
54 mDelivery(aDelivery),
55 mDeliveryInfo(aDeliveryInfo),
56 mSender(aSender),
57 mReceivers(aReceivers),
58 mTimestamp(aTimestamp),
59 mSentTimestamp(aSentTimestamp),
60 mRead(aRead),
61 mSubject(aSubject),
62 mSmil(aSmil),
63 mAttachments(aAttachments),
64 mExpiryDate(aExpiryDate),
65 mReadReportRequested(aReadReportRequested)
69 MmsMessage::MmsMessage(const mobilemessage::MmsMessageData& aData)
70 : mId(aData.id())
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())
78 , mRead(aData.read())
79 , mSubject(aData.subject())
80 , mSmil(aData.smil())
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++) {
87 MmsAttachment att;
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
93 // nullptr as parent.
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);
100 } else {
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|.
116 nsString statusStr;
117 switch (infoData.deliveryStatus()) {
118 case eDeliveryStatus_NotApplicable:
119 statusStr = DELIVERY_STATUS_NOT_APPLICABLE;
120 break;
121 case eDeliveryStatus_Success:
122 statusStr = DELIVERY_STATUS_SUCCESS;
123 break;
124 case eDeliveryStatus_Pending:
125 statusStr = DELIVERY_STATUS_PENDING;
126 break;
127 case eDeliveryStatus_Error:
128 statusStr = DELIVERY_STATUS_ERROR;
129 break;
130 case eDeliveryStatus_Reject:
131 statusStr = DELIVERY_STATUS_REJECTED;
132 break;
133 case eDeliveryStatus_Manual:
134 statusStr = DELIVERY_STATUS_MANUAL;
135 break;
136 case eDeliveryStatus_EndGuard:
137 default:
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;
150 break;
151 case eReadStatus_Success:
152 statusReadString = READ_STATUS_SUCCESS;
153 break;
154 case eReadStatus_Pending:
155 statusReadString = READ_STATUS_PENDING;
156 break;
157 case eReadStatus_Error:
158 statusReadString = READ_STATUS_ERROR;
159 break;
160 case eReadStatus_EndGuard:
161 default:
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,
175 uint64_t aThreadId,
176 const nsAString& aIccId,
177 const nsAString& aDelivery,
178 const JS::Value& aDeliveryInfo,
179 const nsAString& aSender,
180 const JS::Value& aReceivers,
181 uint64_t aTimestamp,
182 uint64_t aSentTimestamp,
183 bool aRead,
184 const nsAString& aSubject,
185 const nsAString& aSmil,
186 const JS::Value& aAttachments,
187 uint64_t aExpiryDate,
188 bool aIsReadReportRequested,
189 JSContext* aCx,
190 nsIDOMMozMmsMessage** aMessage)
192 *aMessage = nullptr;
194 // Set |delivery|.
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;
206 } else {
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;
219 uint32_t length;
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);
238 // Set |receivers|.
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,
292 aThreadId,
293 aIccId,
294 delivery,
295 deliveryInfo,
296 aSender,
297 receivers,
298 aTimestamp,
299 aSentTimestamp,
300 aRead,
301 aSubject,
302 aSmil,
303 attachments,
304 aExpiryDate,
305 aIsReadReportRequested);
306 message.forget(aMessage);
307 return NS_OK;
310 bool
311 MmsMessage::GetData(ContentParent* aParent,
312 mobilemessage::MmsMessageData& aData)
314 NS_ASSERTION(aParent, "aParent is null");
316 aData.id() = mId;
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;
352 } else {
353 return false;
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;
370 } else {
371 return false;
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()) {
393 uint64_t date;
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()) {
401 return false;
403 aData.attachments().AppendElement(mma);
406 return true;
409 NS_IMETHODIMP
410 MmsMessage::GetType(nsAString& aType)
412 aType = NS_LITERAL_STRING("mms");
413 return NS_OK;
416 NS_IMETHODIMP
417 MmsMessage::GetId(int32_t* aId)
419 *aId = mId;
420 return NS_OK;
423 NS_IMETHODIMP
424 MmsMessage::GetThreadId(uint64_t* aThreadId)
426 *aThreadId = mThreadId;
427 return NS_OK;
430 NS_IMETHODIMP
431 MmsMessage::GetIccId(nsAString& aIccId)
433 aIccId = mIccId;
434 return NS_OK;
437 NS_IMETHODIMP
438 MmsMessage::GetDelivery(nsAString& aDelivery)
440 switch (mDelivery) {
441 case eDeliveryState_Received:
442 aDelivery = DELIVERY_RECEIVED;
443 break;
444 case eDeliveryState_Sending:
445 aDelivery = DELIVERY_SENDING;
446 break;
447 case eDeliveryState_Sent:
448 aDelivery = DELIVERY_SENT;
449 break;
450 case eDeliveryState_Error:
451 aDelivery = DELIVERY_ERROR;
452 break;
453 case eDeliveryState_NotDownloaded:
454 aDelivery = DELIVERY_NOT_DOWNLOADED;
455 break;
456 case eDeliveryState_Unknown:
457 case eDeliveryState_EndGuard:
458 default:
459 MOZ_CRASH("We shouldn't get any other delivery state!");
462 return NS_OK;
465 NS_IMETHODIMP
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();
472 if (length == 0) {
473 aDeliveryInfo.setNull();
474 return NS_OK;
477 if (!ToJSValue(aCx, mDeliveryInfo, aDeliveryInfo)) {
478 return NS_ERROR_OUT_OF_MEMORY;
481 return NS_OK;
484 NS_IMETHODIMP
485 MmsMessage::GetSender(nsAString& aSender)
487 aSender = mSender;
488 return NS_OK;
491 NS_IMETHODIMP
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);
499 return NS_OK;
502 NS_IMETHODIMP
503 MmsMessage::GetTimestamp(DOMTimeStamp* aTimestamp)
505 *aTimestamp = mTimestamp;
506 return NS_OK;
509 NS_IMETHODIMP
510 MmsMessage::GetSentTimestamp(DOMTimeStamp* aSentTimestamp)
512 *aSentTimestamp = mSentTimestamp;
513 return NS_OK;
516 NS_IMETHODIMP
517 MmsMessage::GetRead(bool* aRead)
519 *aRead = mRead;
520 return NS_OK;
523 NS_IMETHODIMP
524 MmsMessage::GetSubject(nsAString& aSubject)
526 aSubject = mSubject;
527 return NS_OK;
530 NS_IMETHODIMP
531 MmsMessage::GetSmil(nsAString& aSmil)
533 aSmil = mSmil;
534 return NS_OK;
537 NS_IMETHODIMP
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,
557 attachment.id.get(),
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));
579 MOZ_ASSERT(global);
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);
597 return NS_OK;
600 NS_IMETHODIMP
601 MmsMessage::GetExpiryDate(DOMTimeStamp* aExpiryDate)
603 *aExpiryDate = mExpiryDate;
604 return NS_OK;
607 NS_IMETHODIMP
608 MmsMessage::GetReadReportRequested(bool* aReadReportRequested)
610 *aReadReportRequested = mReadReportRequested;
611 return NS_OK;
615 } // namespace dom
616 } // namespace mozilla