michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this file, michael@0: * You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "SmsParent.h" michael@0: #include "nsISmsService.h" michael@0: #include "nsIMmsService.h" michael@0: #include "nsIObserverService.h" michael@0: #include "mozilla/Services.h" michael@0: #include "nsIDOMMozSmsMessage.h" michael@0: #include "nsIDOMMozMmsMessage.h" michael@0: #include "mozilla/unused.h" michael@0: #include "SmsMessage.h" michael@0: #include "MmsMessage.h" michael@0: #include "nsIMobileMessageDatabaseService.h" michael@0: #include "SmsFilter.h" michael@0: #include "SmsSegmentInfo.h" michael@0: #include "MobileMessageThread.h" michael@0: #include "nsIDOMFile.h" michael@0: #include "mozilla/dom/ipc/Blob.h" michael@0: #include "mozilla/dom/ContentParent.h" michael@0: #include "mozilla/dom/mobilemessage/Constants.h" // For MessageType michael@0: #include "nsContentUtils.h" michael@0: #include "nsTArrayHelpers.h" michael@0: #include "nsCxPusher.h" michael@0: #include "xpcpublic.h" michael@0: #include "nsServiceManagerUtils.h" michael@0: michael@0: namespace mozilla { michael@0: namespace dom { michael@0: namespace mobilemessage { michael@0: michael@0: static JSObject* michael@0: MmsAttachmentDataToJSObject(JSContext* aContext, michael@0: const MmsAttachmentData& aAttachment) michael@0: { michael@0: JS::Rooted obj(aContext, JS_NewObject(aContext, nullptr, JS::NullPtr(), michael@0: JS::NullPtr())); michael@0: NS_ENSURE_TRUE(obj, nullptr); michael@0: michael@0: JS::Rooted idStr(aContext, JS_NewUCStringCopyN(aContext, michael@0: aAttachment.id().get(), michael@0: aAttachment.id().Length())); michael@0: NS_ENSURE_TRUE(idStr, nullptr); michael@0: if (!JS_DefineProperty(aContext, obj, "id", idStr, 0)) { michael@0: return nullptr; michael@0: } michael@0: michael@0: JS::Rooted locStr(aContext, JS_NewUCStringCopyN(aContext, michael@0: aAttachment.location().get(), michael@0: aAttachment.location().Length())); michael@0: NS_ENSURE_TRUE(locStr, nullptr); michael@0: if (!JS_DefineProperty(aContext, obj, "location", locStr, 0)) { michael@0: return nullptr; michael@0: } michael@0: michael@0: nsCOMPtr blob = static_cast(aAttachment.contentParent())->GetBlob(); michael@0: JS::Rooted content(aContext); michael@0: nsresult rv = nsContentUtils::WrapNative(aContext, michael@0: blob, michael@0: &NS_GET_IID(nsIDOMBlob), michael@0: &content); michael@0: NS_ENSURE_SUCCESS(rv, nullptr); michael@0: if (!JS_DefineProperty(aContext, obj, "content", content, 0)) { michael@0: return nullptr; michael@0: } michael@0: michael@0: return obj; michael@0: } michael@0: michael@0: static bool michael@0: GetParamsFromSendMmsMessageRequest(JSContext* aCx, michael@0: const SendMmsMessageRequest& aRequest, michael@0: JS::Value* aParam) michael@0: { michael@0: JS::Rooted paramsObj(aCx, JS_NewObject(aCx, nullptr, JS::NullPtr(), JS::NullPtr())); michael@0: NS_ENSURE_TRUE(paramsObj, false); michael@0: michael@0: // smil michael@0: JS::Rooted smilStr(aCx, JS_NewUCStringCopyN(aCx, michael@0: aRequest.smil().get(), michael@0: aRequest.smil().Length())); michael@0: NS_ENSURE_TRUE(smilStr, false); michael@0: if(!JS_DefineProperty(aCx, paramsObj, "smil", smilStr, 0)) { michael@0: return false; michael@0: } michael@0: michael@0: // subject michael@0: JS::Rooted subjectStr(aCx, JS_NewUCStringCopyN(aCx, michael@0: aRequest.subject().get(), michael@0: aRequest.subject().Length())); michael@0: NS_ENSURE_TRUE(subjectStr, false); michael@0: if(!JS_DefineProperty(aCx, paramsObj, "subject", subjectStr, 0)) { michael@0: return false; michael@0: } michael@0: michael@0: // receivers michael@0: JS::Rooted receiverArray(aCx); michael@0: if (NS_FAILED(nsTArrayToJSArray(aCx, michael@0: aRequest.receivers(), michael@0: receiverArray.address()))) { michael@0: return false; michael@0: } michael@0: if (!JS_DefineProperty(aCx, paramsObj, "receivers", receiverArray, 0)) { michael@0: return false; michael@0: } michael@0: michael@0: // attachments michael@0: JS::Rooted attachmentArray(aCx, JS_NewArrayObject(aCx, michael@0: aRequest.attachments().Length())); michael@0: for (uint32_t i = 0; i < aRequest.attachments().Length(); i++) { michael@0: JS::Rooted obj(aCx, michael@0: MmsAttachmentDataToJSObject(aCx, aRequest.attachments().ElementAt(i))); michael@0: NS_ENSURE_TRUE(obj, false); michael@0: if (!JS_SetElement(aCx, attachmentArray, i, obj)) { michael@0: return false; michael@0: } michael@0: } michael@0: michael@0: if (!JS_DefineProperty(aCx, paramsObj, "attachments", attachmentArray, 0)) { michael@0: return false; michael@0: } michael@0: michael@0: aParam->setObject(*paramsObj); michael@0: return true; michael@0: } michael@0: michael@0: NS_IMPL_ISUPPORTS(SmsParent, nsIObserver) michael@0: michael@0: SmsParent::SmsParent() michael@0: { michael@0: MOZ_COUNT_CTOR(SmsParent); michael@0: nsCOMPtr obs = services::GetObserverService(); michael@0: if (!obs) { michael@0: return; michael@0: } michael@0: michael@0: obs->AddObserver(this, kSmsReceivedObserverTopic, false); michael@0: obs->AddObserver(this, kSmsRetrievingObserverTopic, false); michael@0: obs->AddObserver(this, kSmsSendingObserverTopic, false); michael@0: obs->AddObserver(this, kSmsSentObserverTopic, false); michael@0: obs->AddObserver(this, kSmsFailedObserverTopic, false); michael@0: obs->AddObserver(this, kSmsDeliverySuccessObserverTopic, false); michael@0: obs->AddObserver(this, kSmsDeliveryErrorObserverTopic, false); michael@0: obs->AddObserver(this, kSilentSmsReceivedObserverTopic, false); michael@0: obs->AddObserver(this, kSmsReadSuccessObserverTopic, false); michael@0: obs->AddObserver(this, kSmsReadErrorObserverTopic, false); michael@0: } michael@0: michael@0: void michael@0: SmsParent::ActorDestroy(ActorDestroyReason why) michael@0: { michael@0: nsCOMPtr obs = services::GetObserverService(); michael@0: if (!obs) { michael@0: return; michael@0: } michael@0: michael@0: obs->RemoveObserver(this, kSmsReceivedObserverTopic); michael@0: obs->RemoveObserver(this, kSmsRetrievingObserverTopic); michael@0: obs->RemoveObserver(this, kSmsSendingObserverTopic); michael@0: obs->RemoveObserver(this, kSmsSentObserverTopic); michael@0: obs->RemoveObserver(this, kSmsFailedObserverTopic); michael@0: obs->RemoveObserver(this, kSmsDeliverySuccessObserverTopic); michael@0: obs->RemoveObserver(this, kSmsDeliveryErrorObserverTopic); michael@0: obs->RemoveObserver(this, kSilentSmsReceivedObserverTopic); michael@0: obs->RemoveObserver(this, kSmsReadSuccessObserverTopic); michael@0: obs->RemoveObserver(this, kSmsReadErrorObserverTopic); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: SmsParent::Observe(nsISupports* aSubject, const char* aTopic, michael@0: const char16_t* aData) michael@0: { michael@0: if (!strcmp(aTopic, kSmsReceivedObserverTopic)) { michael@0: MobileMessageData msgData; michael@0: if (!GetMobileMessageDataFromMessage(aSubject, msgData)) { michael@0: NS_ERROR("Got a 'sms-received' topic without a valid message!"); michael@0: return NS_OK; michael@0: } michael@0: michael@0: unused << SendNotifyReceivedMessage(msgData); michael@0: return NS_OK; michael@0: } michael@0: michael@0: if (!strcmp(aTopic, kSmsRetrievingObserverTopic)) { michael@0: MobileMessageData msgData; michael@0: if (!GetMobileMessageDataFromMessage(aSubject, msgData)) { michael@0: NS_ERROR("Got a 'sms-retrieving' topic without a valid message!"); michael@0: return NS_OK; michael@0: } michael@0: michael@0: unused << SendNotifyRetrievingMessage(msgData); michael@0: return NS_OK; michael@0: } michael@0: michael@0: if (!strcmp(aTopic, kSmsSendingObserverTopic)) { michael@0: MobileMessageData msgData; michael@0: if (!GetMobileMessageDataFromMessage(aSubject, msgData)) { michael@0: NS_ERROR("Got a 'sms-sending' topic without a valid message!"); michael@0: return NS_OK; michael@0: } michael@0: michael@0: unused << SendNotifySendingMessage(msgData); michael@0: return NS_OK; michael@0: } michael@0: michael@0: if (!strcmp(aTopic, kSmsSentObserverTopic)) { michael@0: MobileMessageData msgData; michael@0: if (!GetMobileMessageDataFromMessage(aSubject, msgData)) { michael@0: NS_ERROR("Got a 'sms-sent' topic without a valid message!"); michael@0: return NS_OK; michael@0: } michael@0: michael@0: unused << SendNotifySentMessage(msgData); michael@0: return NS_OK; michael@0: } michael@0: michael@0: if (!strcmp(aTopic, kSmsFailedObserverTopic)) { michael@0: MobileMessageData msgData; michael@0: if (!GetMobileMessageDataFromMessage(aSubject, msgData)) { michael@0: NS_ERROR("Got a 'sms-failed' topic without a valid message!"); michael@0: return NS_OK; michael@0: } michael@0: michael@0: unused << SendNotifyFailedMessage(msgData); michael@0: return NS_OK; michael@0: } michael@0: michael@0: if (!strcmp(aTopic, kSmsDeliverySuccessObserverTopic)) { michael@0: MobileMessageData msgData; michael@0: if (!GetMobileMessageDataFromMessage(aSubject, msgData)) { michael@0: NS_ERROR("Got a 'sms-sending' topic without a valid message!"); michael@0: return NS_OK; michael@0: } michael@0: michael@0: unused << SendNotifyDeliverySuccessMessage(msgData); michael@0: return NS_OK; michael@0: } michael@0: michael@0: if (!strcmp(aTopic, kSmsDeliveryErrorObserverTopic)) { michael@0: MobileMessageData msgData; michael@0: if (!GetMobileMessageDataFromMessage(aSubject, msgData)) { michael@0: NS_ERROR("Got a 'sms-delivery-error' topic without a valid message!"); michael@0: return NS_OK; michael@0: } michael@0: michael@0: unused << SendNotifyDeliveryErrorMessage(msgData); michael@0: return NS_OK; michael@0: } michael@0: michael@0: if (!strcmp(aTopic, kSilentSmsReceivedObserverTopic)) { michael@0: nsCOMPtr smsMsg = do_QueryInterface(aSubject); michael@0: if (!smsMsg) { michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsString sender; michael@0: if (NS_FAILED(smsMsg->GetSender(sender)) || michael@0: !mSilentNumbers.Contains(sender)) { michael@0: return NS_OK; michael@0: } michael@0: michael@0: MobileMessageData msgData = michael@0: static_cast(smsMsg.get())->GetData(); michael@0: unused << SendNotifyReceivedSilentMessage(msgData); michael@0: return NS_OK; michael@0: } michael@0: michael@0: michael@0: if (!strcmp(aTopic, kSmsReadSuccessObserverTopic)) { michael@0: MobileMessageData msgData; michael@0: if (!GetMobileMessageDataFromMessage(aSubject, msgData)) { michael@0: NS_ERROR("Got a 'sms-read-success' topic without a valid message!"); michael@0: return NS_OK; michael@0: } michael@0: michael@0: unused << SendNotifyReadSuccessMessage(msgData); michael@0: return NS_OK; michael@0: } michael@0: michael@0: if (!strcmp(aTopic, kSmsReadErrorObserverTopic)) { michael@0: MobileMessageData msgData; michael@0: if (!GetMobileMessageDataFromMessage(aSubject, msgData)) { michael@0: NS_ERROR("Got a 'sms-read-error' topic without a valid message!"); michael@0: return NS_OK; michael@0: } michael@0: michael@0: unused << SendNotifyReadErrorMessage(msgData); michael@0: return NS_OK; michael@0: } michael@0: michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: bool michael@0: SmsParent::GetMobileMessageDataFromMessage(nsISupports *aMsg, michael@0: MobileMessageData &aData) michael@0: { michael@0: nsCOMPtr mmsMsg = do_QueryInterface(aMsg); michael@0: if (mmsMsg) { michael@0: MmsMessageData data; michael@0: ContentParent *parent = static_cast(Manager()); michael@0: if (!static_cast(mmsMsg.get())->GetData(parent, data)) { michael@0: return false; michael@0: } michael@0: aData = data; michael@0: return true; michael@0: } michael@0: michael@0: nsCOMPtr smsMsg = do_QueryInterface(aMsg); michael@0: if (smsMsg) { michael@0: aData = static_cast(smsMsg.get())->GetData(); michael@0: return true; michael@0: } michael@0: michael@0: NS_WARNING("Cannot get MobileMessageData"); michael@0: return false; michael@0: } michael@0: michael@0: bool michael@0: SmsParent::RecvAddSilentNumber(const nsString& aNumber) michael@0: { michael@0: if (mSilentNumbers.Contains(aNumber)) { michael@0: return true; michael@0: } michael@0: michael@0: nsCOMPtr smsService = do_GetService(SMS_SERVICE_CONTRACTID); michael@0: NS_ENSURE_TRUE(smsService, true); michael@0: michael@0: nsresult rv = smsService->AddSilentNumber(aNumber); michael@0: if (NS_SUCCEEDED(rv)) { michael@0: mSilentNumbers.AppendElement(aNumber); michael@0: } michael@0: michael@0: return true; michael@0: } michael@0: michael@0: bool michael@0: SmsParent::RecvRemoveSilentNumber(const nsString& aNumber) michael@0: { michael@0: if (!mSilentNumbers.Contains(aNumber)) { michael@0: return true; michael@0: } michael@0: michael@0: nsCOMPtr smsService = do_GetService(SMS_SERVICE_CONTRACTID); michael@0: NS_ENSURE_TRUE(smsService, true); michael@0: michael@0: nsresult rv = smsService->RemoveSilentNumber(aNumber); michael@0: if (NS_SUCCEEDED(rv)) { michael@0: mSilentNumbers.RemoveElement(aNumber); michael@0: } michael@0: michael@0: return true; michael@0: } michael@0: michael@0: bool michael@0: SmsParent::RecvPSmsRequestConstructor(PSmsRequestParent* aActor, michael@0: const IPCSmsRequest& aRequest) michael@0: { michael@0: SmsRequestParent* actor = static_cast(aActor); michael@0: michael@0: switch (aRequest.type()) { michael@0: case IPCSmsRequest::TSendMessageRequest: michael@0: return actor->DoRequest(aRequest.get_SendMessageRequest()); michael@0: case IPCSmsRequest::TRetrieveMessageRequest: michael@0: return actor->DoRequest(aRequest.get_RetrieveMessageRequest()); michael@0: case IPCSmsRequest::TGetMessageRequest: michael@0: return actor->DoRequest(aRequest.get_GetMessageRequest()); michael@0: case IPCSmsRequest::TDeleteMessageRequest: michael@0: return actor->DoRequest(aRequest.get_DeleteMessageRequest()); michael@0: case IPCSmsRequest::TMarkMessageReadRequest: michael@0: return actor->DoRequest(aRequest.get_MarkMessageReadRequest()); michael@0: case IPCSmsRequest::TGetSegmentInfoForTextRequest: michael@0: return actor->DoRequest(aRequest.get_GetSegmentInfoForTextRequest()); michael@0: case IPCSmsRequest::TGetSmscAddressRequest: michael@0: return actor->DoRequest(aRequest.get_GetSmscAddressRequest()); michael@0: default: michael@0: MOZ_CRASH("Unknown type!"); michael@0: } michael@0: michael@0: return false; michael@0: } michael@0: michael@0: PSmsRequestParent* michael@0: SmsParent::AllocPSmsRequestParent(const IPCSmsRequest& aRequest) michael@0: { michael@0: SmsRequestParent* actor = new SmsRequestParent(); michael@0: // Add an extra ref for IPDL. Will be released in michael@0: // SmsParent::DeallocPSmsRequestParent(). michael@0: actor->AddRef(); michael@0: michael@0: return actor; michael@0: } michael@0: michael@0: bool michael@0: SmsParent::DeallocPSmsRequestParent(PSmsRequestParent* aActor) michael@0: { michael@0: // SmsRequestParent is refcounted, must not be freed manually. michael@0: static_cast(aActor)->Release(); michael@0: return true; michael@0: } michael@0: michael@0: bool michael@0: SmsParent::RecvPMobileMessageCursorConstructor(PMobileMessageCursorParent* aActor, michael@0: const IPCMobileMessageCursor& aRequest) michael@0: { michael@0: MobileMessageCursorParent* actor = michael@0: static_cast(aActor); michael@0: michael@0: switch (aRequest.type()) { michael@0: case IPCMobileMessageCursor::TCreateMessageCursorRequest: michael@0: return actor->DoRequest(aRequest.get_CreateMessageCursorRequest()); michael@0: case IPCMobileMessageCursor::TCreateThreadCursorRequest: michael@0: return actor->DoRequest(aRequest.get_CreateThreadCursorRequest()); michael@0: default: michael@0: MOZ_CRASH("Unknown type!"); michael@0: } michael@0: michael@0: return false; michael@0: } michael@0: michael@0: PMobileMessageCursorParent* michael@0: SmsParent::AllocPMobileMessageCursorParent(const IPCMobileMessageCursor& aRequest) michael@0: { michael@0: MobileMessageCursorParent* actor = new MobileMessageCursorParent(); michael@0: // Add an extra ref for IPDL. Will be released in michael@0: // SmsParent::DeallocPMobileMessageCursorParent(). michael@0: actor->AddRef(); michael@0: michael@0: return actor; michael@0: } michael@0: michael@0: bool michael@0: SmsParent::DeallocPMobileMessageCursorParent(PMobileMessageCursorParent* aActor) michael@0: { michael@0: // MobileMessageCursorParent is refcounted, must not be freed manually. michael@0: static_cast(aActor)->Release(); michael@0: return true; michael@0: } michael@0: michael@0: /******************************************************************************* michael@0: * SmsRequestParent michael@0: ******************************************************************************/ michael@0: michael@0: NS_IMPL_ISUPPORTS(SmsRequestParent, nsIMobileMessageCallback) michael@0: michael@0: void michael@0: SmsRequestParent::ActorDestroy(ActorDestroyReason aWhy) michael@0: { michael@0: mActorDestroyed = true; michael@0: } michael@0: michael@0: bool michael@0: SmsRequestParent::DoRequest(const SendMessageRequest& aRequest) michael@0: { michael@0: switch(aRequest.type()) { michael@0: case SendMessageRequest::TSendSmsMessageRequest: { michael@0: nsCOMPtr smsService = do_GetService(SMS_SERVICE_CONTRACTID); michael@0: NS_ENSURE_TRUE(smsService, true); michael@0: michael@0: const SendSmsMessageRequest &req = aRequest.get_SendSmsMessageRequest(); michael@0: smsService->Send(req.serviceId(), req.number(), req.message(), michael@0: req.silent(), this); michael@0: } michael@0: break; michael@0: case SendMessageRequest::TSendMmsMessageRequest: { michael@0: nsCOMPtr mmsService = do_GetService(MMS_SERVICE_CONTRACTID); michael@0: NS_ENSURE_TRUE(mmsService, true); michael@0: michael@0: // There are cases (see bug 981202) where this is called with no JS on the michael@0: // stack. And since mmsService might be JS-Implemented, we need to pass a michael@0: // jsval to ::Send. Only system code should be looking at the result here, michael@0: // so we just create it in the System-Principaled Junk Scope. michael@0: AutoJSContext cx; michael@0: JSAutoCompartment ac(cx, xpc::GetJunkScope()); michael@0: JS::Rooted params(cx); michael@0: const SendMmsMessageRequest &req = aRequest.get_SendMmsMessageRequest(); michael@0: if (!GetParamsFromSendMmsMessageRequest(cx, michael@0: req, michael@0: params.address())) { michael@0: NS_WARNING("SmsRequestParent: Fail to build MMS params."); michael@0: return true; michael@0: } michael@0: mmsService->Send(req.serviceId(), params, this); michael@0: } michael@0: break; michael@0: default: michael@0: MOZ_CRASH("Unknown type of SendMessageRequest!"); michael@0: } michael@0: return true; michael@0: } michael@0: michael@0: bool michael@0: SmsRequestParent::DoRequest(const RetrieveMessageRequest& aRequest) michael@0: { michael@0: nsresult rv = NS_ERROR_FAILURE; michael@0: michael@0: nsCOMPtr mmsService = do_GetService(MMS_SERVICE_CONTRACTID); michael@0: if (mmsService) { michael@0: rv = mmsService->Retrieve(aRequest.messageId(), this); michael@0: } michael@0: michael@0: if (NS_FAILED(rv)) { michael@0: return NS_SUCCEEDED(NotifyGetMessageFailed(nsIMobileMessageCallback::INTERNAL_ERROR)); michael@0: } michael@0: michael@0: return true; michael@0: } michael@0: michael@0: bool michael@0: SmsRequestParent::DoRequest(const GetMessageRequest& aRequest) michael@0: { michael@0: nsresult rv = NS_ERROR_FAILURE; michael@0: michael@0: nsCOMPtr dbService = michael@0: do_GetService(MOBILE_MESSAGE_DATABASE_SERVICE_CONTRACTID); michael@0: if (dbService) { michael@0: rv = dbService->GetMessageMoz(aRequest.messageId(), this); michael@0: } michael@0: michael@0: if (NS_FAILED(rv)) { michael@0: return NS_SUCCEEDED(NotifyGetMessageFailed(nsIMobileMessageCallback::INTERNAL_ERROR)); michael@0: } michael@0: michael@0: return true; michael@0: } michael@0: michael@0: bool michael@0: SmsRequestParent::DoRequest(const GetSmscAddressRequest& aRequest) michael@0: { michael@0: nsresult rv = NS_ERROR_FAILURE; michael@0: michael@0: nsCOMPtr smsService = do_GetService(SMS_SERVICE_CONTRACTID); michael@0: if (smsService) { michael@0: rv = smsService->GetSmscAddress(aRequest.serviceId(), this); michael@0: } michael@0: michael@0: if (NS_FAILED(rv)) { michael@0: return NS_SUCCEEDED(NotifyGetSmscAddressFailed(nsIMobileMessageCallback::INTERNAL_ERROR)); michael@0: } michael@0: michael@0: return true; michael@0: } michael@0: michael@0: bool michael@0: SmsRequestParent::DoRequest(const DeleteMessageRequest& aRequest) michael@0: { michael@0: nsresult rv = NS_ERROR_FAILURE; michael@0: michael@0: nsCOMPtr dbService = michael@0: do_GetService(MOBILE_MESSAGE_DATABASE_SERVICE_CONTRACTID); michael@0: if (dbService) { michael@0: const InfallibleTArray& messageIds = aRequest.messageIds(); michael@0: rv = dbService->DeleteMessage(const_cast(messageIds.Elements()), michael@0: messageIds.Length(), this); michael@0: } michael@0: michael@0: if (NS_FAILED(rv)) { michael@0: return NS_SUCCEEDED(NotifyDeleteMessageFailed(nsIMobileMessageCallback::INTERNAL_ERROR)); michael@0: } michael@0: michael@0: return true; michael@0: } michael@0: michael@0: bool michael@0: SmsRequestParent::DoRequest(const MarkMessageReadRequest& aRequest) michael@0: { michael@0: nsresult rv = NS_ERROR_FAILURE; michael@0: michael@0: nsCOMPtr dbService = michael@0: do_GetService(MOBILE_MESSAGE_DATABASE_SERVICE_CONTRACTID); michael@0: if (dbService) { michael@0: rv = dbService->MarkMessageRead(aRequest.messageId(), aRequest.value(), michael@0: aRequest.sendReadReport(), this); michael@0: } michael@0: michael@0: if (NS_FAILED(rv)) { michael@0: return NS_SUCCEEDED(NotifyMarkMessageReadFailed(nsIMobileMessageCallback::INTERNAL_ERROR)); michael@0: } michael@0: michael@0: return true; michael@0: } michael@0: michael@0: bool michael@0: SmsRequestParent::DoRequest(const GetSegmentInfoForTextRequest& aRequest) michael@0: { michael@0: nsresult rv = NS_ERROR_FAILURE; michael@0: michael@0: nsCOMPtr smsService = do_GetService(SMS_SERVICE_CONTRACTID); michael@0: if (smsService) { michael@0: rv = smsService->GetSegmentInfoForText(aRequest.text(), this); michael@0: } michael@0: michael@0: if (NS_FAILED(rv)) { michael@0: return NS_SUCCEEDED(NotifyGetSegmentInfoForTextFailed( michael@0: nsIMobileMessageCallback::INTERNAL_ERROR)); michael@0: } michael@0: michael@0: return true; michael@0: } michael@0: michael@0: nsresult michael@0: SmsRequestParent::SendReply(const MessageReply& aReply) michael@0: { michael@0: // The child process could die before this asynchronous notification, in which michael@0: // case ActorDestroy() was called and mActorDestroyed is set to true. Return michael@0: // an error here to avoid sending a message to the dead process. michael@0: NS_ENSURE_TRUE(!mActorDestroyed, NS_ERROR_FAILURE); michael@0: michael@0: return Send__delete__(this, aReply) ? NS_OK : NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: // nsIMobileMessageCallback michael@0: michael@0: NS_IMETHODIMP michael@0: SmsRequestParent::NotifyMessageSent(nsISupports *aMessage) michael@0: { michael@0: NS_ENSURE_TRUE(!mActorDestroyed, NS_ERROR_FAILURE); michael@0: michael@0: nsCOMPtr mms = do_QueryInterface(aMessage); michael@0: if (mms) { michael@0: MmsMessage *msg = static_cast(mms.get()); michael@0: ContentParent *parent = static_cast(Manager()->Manager()); michael@0: MmsMessageData data; michael@0: if (!msg->GetData(parent, data)) { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: return SendReply(ReplyMessageSend(MobileMessageData(data))); michael@0: } michael@0: michael@0: nsCOMPtr sms = do_QueryInterface(aMessage); michael@0: if (sms) { michael@0: SmsMessage* msg = static_cast(sms.get()); michael@0: return SendReply(ReplyMessageSend(MobileMessageData(msg->GetData()))); michael@0: } michael@0: michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: SmsRequestParent::NotifySendMessageFailed(int32_t aError) michael@0: { michael@0: return SendReply(ReplyMessageSendFail(aError)); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: SmsRequestParent::NotifyMessageGot(nsISupports *aMessage) michael@0: { michael@0: NS_ENSURE_TRUE(!mActorDestroyed, NS_ERROR_FAILURE); michael@0: michael@0: nsCOMPtr mms = do_QueryInterface(aMessage); michael@0: if (mms) { michael@0: MmsMessage *msg = static_cast(mms.get()); michael@0: ContentParent *parent = static_cast(Manager()->Manager()); michael@0: MmsMessageData data; michael@0: if (!msg->GetData(parent, data)) { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: return SendReply(ReplyGetMessage(MobileMessageData(data))); michael@0: } michael@0: michael@0: nsCOMPtr sms = do_QueryInterface(aMessage); michael@0: if (sms) { michael@0: SmsMessage* msg = static_cast(sms.get()); michael@0: return SendReply(ReplyGetMessage(MobileMessageData(msg->GetData()))); michael@0: } michael@0: michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: SmsRequestParent::NotifyGetMessageFailed(int32_t aError) michael@0: { michael@0: return SendReply(ReplyGetMessageFail(aError)); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: SmsRequestParent::NotifyMessageDeleted(bool *aDeleted, uint32_t aSize) michael@0: { michael@0: ReplyMessageDelete data; michael@0: data.deleted().AppendElements(aDeleted, aSize); michael@0: return SendReply(data); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: SmsRequestParent::NotifyDeleteMessageFailed(int32_t aError) michael@0: { michael@0: return SendReply(ReplyMessageDeleteFail(aError)); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: SmsRequestParent::NotifyMessageMarkedRead(bool aRead) michael@0: { michael@0: return SendReply(ReplyMarkeMessageRead(aRead)); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: SmsRequestParent::NotifyMarkMessageReadFailed(int32_t aError) michael@0: { michael@0: return SendReply(ReplyMarkeMessageReadFail(aError)); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: SmsRequestParent::NotifySegmentInfoForTextGot(nsIDOMMozSmsSegmentInfo *aInfo) michael@0: { michael@0: SmsSegmentInfo* info = static_cast(aInfo); michael@0: return SendReply(ReplyGetSegmentInfoForText(info->GetData())); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: SmsRequestParent::NotifyGetSegmentInfoForTextFailed(int32_t aError) michael@0: { michael@0: return SendReply(ReplyGetSegmentInfoForTextFail(aError)); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: SmsRequestParent::NotifyGetSmscAddress(const nsAString& aSmscAddress) michael@0: { michael@0: return SendReply(ReplyGetSmscAddress(nsString(aSmscAddress))); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: SmsRequestParent::NotifyGetSmscAddressFailed(int32_t aError) michael@0: { michael@0: return SendReply(ReplyGetSmscAddressFail(aError)); michael@0: } michael@0: michael@0: /******************************************************************************* michael@0: * MobileMessageCursorParent michael@0: ******************************************************************************/ michael@0: michael@0: NS_IMPL_ISUPPORTS(MobileMessageCursorParent, nsIMobileMessageCursorCallback) michael@0: michael@0: void michael@0: MobileMessageCursorParent::ActorDestroy(ActorDestroyReason aWhy) michael@0: { michael@0: // Two possible scenarios here: michael@0: // 1) When parent fails to SendNotifyResult() in NotifyCursorResult(), it's michael@0: // destroyed without nulling out mContinueCallback. michael@0: // 2) When parent dies normally, mContinueCallback should have been cleared in michael@0: // NotifyCursorError(), but just ensure this again. michael@0: mContinueCallback = nullptr; michael@0: } michael@0: michael@0: bool michael@0: MobileMessageCursorParent::RecvContinue() michael@0: { michael@0: MOZ_ASSERT(mContinueCallback); michael@0: michael@0: if (NS_FAILED(mContinueCallback->HandleContinue())) { michael@0: return NS_SUCCEEDED(NotifyCursorError(nsIMobileMessageCallback::INTERNAL_ERROR)); michael@0: } michael@0: michael@0: return true; michael@0: } michael@0: michael@0: bool michael@0: MobileMessageCursorParent::DoRequest(const CreateMessageCursorRequest& aRequest) michael@0: { michael@0: nsresult rv = NS_ERROR_FAILURE; michael@0: michael@0: nsCOMPtr dbService = michael@0: do_GetService(MOBILE_MESSAGE_DATABASE_SERVICE_CONTRACTID); michael@0: if (dbService) { michael@0: nsCOMPtr filter = new SmsFilter(aRequest.filter()); michael@0: bool reverse = aRequest.reverse(); michael@0: michael@0: rv = dbService->CreateMessageCursor(filter, reverse, this, michael@0: getter_AddRefs(mContinueCallback)); michael@0: } michael@0: michael@0: if (NS_FAILED(rv)) { michael@0: return NS_SUCCEEDED(NotifyCursorError(nsIMobileMessageCallback::INTERNAL_ERROR)); michael@0: } michael@0: michael@0: return true; michael@0: } michael@0: michael@0: bool michael@0: MobileMessageCursorParent::DoRequest(const CreateThreadCursorRequest& aRequest) michael@0: { michael@0: nsresult rv = NS_ERROR_FAILURE; michael@0: michael@0: nsCOMPtr dbService = michael@0: do_GetService(MOBILE_MESSAGE_DATABASE_SERVICE_CONTRACTID); michael@0: if (dbService) { michael@0: rv = dbService->CreateThreadCursor(this, michael@0: getter_AddRefs(mContinueCallback)); michael@0: } michael@0: michael@0: if (NS_FAILED(rv)) { michael@0: return NS_SUCCEEDED(NotifyCursorError(nsIMobileMessageCallback::INTERNAL_ERROR)); michael@0: } michael@0: michael@0: return true; michael@0: } michael@0: michael@0: // nsIMobileMessageCursorCallback michael@0: michael@0: NS_IMETHODIMP michael@0: MobileMessageCursorParent::NotifyCursorError(int32_t aError) michael@0: { michael@0: // The child process could die before this asynchronous notification, in which michael@0: // case ActorDestroy() was called and mContinueCallback is now null. Return an michael@0: // error here to avoid sending a message to the dead process. michael@0: NS_ENSURE_TRUE(mContinueCallback, NS_ERROR_FAILURE); michael@0: michael@0: mContinueCallback = nullptr; michael@0: michael@0: return Send__delete__(this, aError) ? NS_OK : NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: MobileMessageCursorParent::NotifyCursorResult(nsISupports* aResult) michael@0: { michael@0: // The child process could die before this asynchronous notification, in which michael@0: // case ActorDestroy() was called and mContinueCallback is now null. Return an michael@0: // error here to avoid sending a message to the dead process. michael@0: NS_ENSURE_TRUE(mContinueCallback, NS_ERROR_FAILURE); michael@0: michael@0: nsCOMPtr iSms = do_QueryInterface(aResult); michael@0: if (iSms) { michael@0: SmsMessage* message = static_cast(aResult); michael@0: return SendNotifyResult(MobileMessageCursorData(message->GetData())) michael@0: ? NS_OK : NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: nsCOMPtr iMms = do_QueryInterface(aResult); michael@0: if (iMms) { michael@0: MmsMessage* message = static_cast(aResult); michael@0: ContentParent* parent = static_cast(Manager()->Manager()); michael@0: MmsMessageData data; michael@0: if (!message->GetData(parent, data)) { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: return SendNotifyResult(MobileMessageCursorData(data)) michael@0: ? NS_OK : NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: nsCOMPtr iThread = do_QueryInterface(aResult); michael@0: if (iThread) { michael@0: MobileMessageThread* thread = static_cast(aResult); michael@0: return SendNotifyResult(MobileMessageCursorData(thread->GetData())) michael@0: ? NS_OK : NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: MOZ_CRASH("Received invalid response parameters!"); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: MobileMessageCursorParent::NotifyCursorDone() michael@0: { michael@0: return NotifyCursorError(nsIMobileMessageCallback::SUCCESS_NO_ERROR); michael@0: } michael@0: michael@0: } // namespace mobilemessage michael@0: } // namespace dom michael@0: } // namespace mozilla