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 "mozilla/dom/ContentChild.h" michael@0: #include "SmsIPCService.h" michael@0: #include "nsXULAppAPI.h" michael@0: #include "mozilla/dom/mobilemessage/SmsChild.h" michael@0: #include "SmsMessage.h" michael@0: #include "SmsFilter.h" michael@0: #include "SmsSegmentInfo.h" michael@0: #include "nsJSUtils.h" michael@0: #include "nsCxPusher.h" michael@0: #include "mozilla/dom/MobileMessageManagerBinding.h" michael@0: #include "mozilla/dom/MozMmsMessageBinding.h" michael@0: #include "mozilla/dom/BindingUtils.h" michael@0: #include "mozilla/Preferences.h" michael@0: #include "nsString.h" michael@0: michael@0: using namespace mozilla::dom; michael@0: using namespace mozilla::dom::mobilemessage; michael@0: michael@0: namespace { michael@0: michael@0: const char* kPrefRilNumRadioInterfaces = "ril.numRadioInterfaces"; michael@0: #define kPrefMmsDefaultServiceId "dom.mms.defaultServiceId" michael@0: #define kPrefSmsDefaultServiceId "dom.sms.defaultServiceId" michael@0: const char* kObservedPrefs[] = { michael@0: kPrefMmsDefaultServiceId, michael@0: kPrefSmsDefaultServiceId, michael@0: nullptr michael@0: }; michael@0: michael@0: // TODO: Bug 767082 - WebSMS: sSmsChild leaks at shutdown michael@0: PSmsChild* gSmsChild; michael@0: michael@0: PSmsChild* michael@0: GetSmsChild() michael@0: { michael@0: MOZ_ASSERT(NS_IsMainThread()); michael@0: michael@0: if (!gSmsChild) { michael@0: gSmsChild = ContentChild::GetSingleton()->SendPSmsConstructor(); michael@0: michael@0: NS_WARN_IF_FALSE(gSmsChild, michael@0: "Calling methods on SmsIPCService during shutdown!"); michael@0: } michael@0: michael@0: return gSmsChild; michael@0: } michael@0: michael@0: nsresult michael@0: SendRequest(const IPCSmsRequest& aRequest, michael@0: nsIMobileMessageCallback* aRequestReply) michael@0: { michael@0: PSmsChild* smsChild = GetSmsChild(); michael@0: NS_ENSURE_TRUE(smsChild, NS_ERROR_FAILURE); michael@0: michael@0: SmsRequestChild* actor = new SmsRequestChild(aRequestReply); michael@0: smsChild->SendPSmsRequestConstructor(actor, aRequest); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsresult michael@0: SendCursorRequest(const IPCMobileMessageCursor& aRequest, michael@0: nsIMobileMessageCursorCallback* aRequestReply, michael@0: nsICursorContinueCallback** aResult) michael@0: { michael@0: PSmsChild* smsChild = GetSmsChild(); michael@0: NS_ENSURE_TRUE(smsChild, NS_ERROR_FAILURE); michael@0: michael@0: nsRefPtr actor = michael@0: new MobileMessageCursorChild(aRequestReply); michael@0: michael@0: // Add an extra ref for IPDL. Will be released in michael@0: // SmsChild::DeallocPMobileMessageCursor(). michael@0: actor->AddRef(); michael@0: michael@0: smsChild->SendPMobileMessageCursorConstructor(actor, aRequest); michael@0: michael@0: actor.forget(aResult); michael@0: return NS_OK; michael@0: } michael@0: michael@0: uint32_t michael@0: getDefaultServiceId(const char* aPrefKey) michael@0: { michael@0: int32_t id = mozilla::Preferences::GetInt(aPrefKey, 0); michael@0: int32_t numRil = mozilla::Preferences::GetInt(kPrefRilNumRadioInterfaces, 1); michael@0: michael@0: if (id >= numRil || id < 0) { michael@0: id = 0; michael@0: } michael@0: michael@0: return id; michael@0: } michael@0: michael@0: } // anonymous namespace michael@0: michael@0: NS_IMPL_ISUPPORTS(SmsIPCService, michael@0: nsISmsService, michael@0: nsIMmsService, michael@0: nsIMobileMessageDatabaseService, michael@0: nsIObserver) michael@0: michael@0: SmsIPCService::SmsIPCService() michael@0: { michael@0: Preferences::AddStrongObservers(this, kObservedPrefs); michael@0: mMmsDefaultServiceId = getDefaultServiceId(kPrefMmsDefaultServiceId); michael@0: mSmsDefaultServiceId = getDefaultServiceId(kPrefSmsDefaultServiceId); michael@0: } michael@0: michael@0: /* michael@0: * Implementation of nsIObserver. michael@0: */ michael@0: michael@0: NS_IMETHODIMP michael@0: SmsIPCService::Observe(nsISupports* aSubject, michael@0: const char* aTopic, michael@0: const char16_t* aData) michael@0: { michael@0: if (!strcmp(aTopic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID)) { michael@0: nsDependentString data(aData); michael@0: if (data.EqualsLiteral(kPrefMmsDefaultServiceId)) { michael@0: mMmsDefaultServiceId = getDefaultServiceId(kPrefMmsDefaultServiceId); michael@0: } else if (data.EqualsLiteral(kPrefSmsDefaultServiceId)) { michael@0: mSmsDefaultServiceId = getDefaultServiceId(kPrefSmsDefaultServiceId); michael@0: } michael@0: return NS_OK; michael@0: } michael@0: michael@0: MOZ_ASSERT(false, "SmsIPCService got unexpected topic!"); michael@0: return NS_ERROR_UNEXPECTED; michael@0: } michael@0: michael@0: /* michael@0: * Implementation of nsISmsService. michael@0: */ michael@0: michael@0: NS_IMETHODIMP michael@0: SmsIPCService::GetSmsDefaultServiceId(uint32_t* aServiceId) michael@0: { michael@0: *aServiceId = mSmsDefaultServiceId; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: SmsIPCService::GetSegmentInfoForText(const nsAString& aText, michael@0: nsIMobileMessageCallback* aRequest) michael@0: { michael@0: return SendRequest(GetSegmentInfoForTextRequest(nsString(aText)), michael@0: aRequest); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: SmsIPCService::GetSmscAddress(uint32_t aServiceId, michael@0: nsIMobileMessageCallback* aRequest) michael@0: { michael@0: return SendRequest(GetSmscAddressRequest(aServiceId), aRequest); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: SmsIPCService::Send(uint32_t aServiceId, michael@0: const nsAString& aNumber, michael@0: const nsAString& aMessage, michael@0: bool aSilent, michael@0: nsIMobileMessageCallback* aRequest) michael@0: { michael@0: return SendRequest(SendMessageRequest(SendSmsMessageRequest(aServiceId, michael@0: nsString(aNumber), michael@0: nsString(aMessage), michael@0: aSilent)), michael@0: aRequest); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: SmsIPCService::IsSilentNumber(const nsAString& aNumber, michael@0: bool* aIsSilent) michael@0: { michael@0: NS_ERROR("We should not be here!"); michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: SmsIPCService::AddSilentNumber(const nsAString& aNumber) michael@0: { michael@0: PSmsChild* smsChild = GetSmsChild(); michael@0: NS_ENSURE_TRUE(smsChild, NS_ERROR_FAILURE); michael@0: michael@0: smsChild->SendAddSilentNumber(nsString(aNumber)); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: SmsIPCService::RemoveSilentNumber(const nsAString& aNumber) michael@0: { michael@0: PSmsChild* smsChild = GetSmsChild(); michael@0: NS_ENSURE_TRUE(smsChild, NS_ERROR_FAILURE); michael@0: michael@0: smsChild->SendRemoveSilentNumber(nsString(aNumber)); michael@0: return NS_OK; michael@0: } michael@0: michael@0: /* michael@0: * Implementation of nsIMobileMessageDatabaseService. michael@0: */ michael@0: NS_IMETHODIMP michael@0: SmsIPCService::GetMessageMoz(int32_t aMessageId, michael@0: nsIMobileMessageCallback* aRequest) michael@0: { michael@0: return SendRequest(GetMessageRequest(aMessageId), aRequest); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: SmsIPCService::DeleteMessage(int32_t *aMessageIds, uint32_t aSize, michael@0: nsIMobileMessageCallback* aRequest) michael@0: { michael@0: DeleteMessageRequest data; michael@0: data.messageIds().AppendElements(aMessageIds, aSize); michael@0: return SendRequest(data, aRequest); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: SmsIPCService::CreateMessageCursor(nsIDOMMozSmsFilter* aFilter, michael@0: bool aReverse, michael@0: nsIMobileMessageCursorCallback* aCursorCallback, michael@0: nsICursorContinueCallback** aResult) michael@0: { michael@0: const SmsFilterData& data = michael@0: SmsFilterData(static_cast(aFilter)->GetData()); michael@0: michael@0: return SendCursorRequest(CreateMessageCursorRequest(data, aReverse), michael@0: aCursorCallback, aResult); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: SmsIPCService::MarkMessageRead(int32_t aMessageId, michael@0: bool aValue, michael@0: bool aSendReadReport, michael@0: nsIMobileMessageCallback* aRequest) michael@0: { michael@0: return SendRequest(MarkMessageReadRequest(aMessageId, aValue, aSendReadReport), aRequest); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: SmsIPCService::CreateThreadCursor(nsIMobileMessageCursorCallback* aCursorCallback, michael@0: nsICursorContinueCallback** aResult) michael@0: { michael@0: return SendCursorRequest(CreateThreadCursorRequest(), aCursorCallback, michael@0: aResult); michael@0: } michael@0: michael@0: bool michael@0: GetSendMmsMessageRequestFromParams(uint32_t aServiceId, michael@0: const JS::Value& aParam, michael@0: SendMmsMessageRequest& request) { michael@0: if (aParam.isUndefined() || aParam.isNull() || !aParam.isObject()) { michael@0: return false; michael@0: } michael@0: michael@0: mozilla::AutoJSContext cx; michael@0: JS::Rooted param(cx, aParam); michael@0: RootedDictionary params(cx); michael@0: if (!params.Init(cx, param)) { michael@0: return false; michael@0: } michael@0: michael@0: // SendMobileMessageRequest.receivers michael@0: if (!params.mReceivers.WasPassed()) { michael@0: return false; michael@0: } michael@0: request.receivers().AppendElements(params.mReceivers.Value()); michael@0: michael@0: // SendMobileMessageRequest.attachments michael@0: mozilla::dom::ContentChild* cc = mozilla::dom::ContentChild::GetSingleton(); michael@0: michael@0: if (!params.mAttachments.WasPassed()) { michael@0: return false; michael@0: } michael@0: michael@0: for (uint32_t i = 0; i < params.mAttachments.Value().Length(); i++) { michael@0: mozilla::dom::MmsAttachment& attachment = params.mAttachments.Value()[i]; michael@0: MmsAttachmentData mmsAttachment; michael@0: mmsAttachment.id().Assign(attachment.mId); michael@0: mmsAttachment.location().Assign(attachment.mLocation); michael@0: mmsAttachment.contentChild() = cc->GetOrCreateActorForBlob(attachment.mContent); michael@0: if (!mmsAttachment.contentChild()) { michael@0: return false; michael@0: } michael@0: request.attachments().AppendElement(mmsAttachment); michael@0: } michael@0: michael@0: request.smil() = params.mSmil; michael@0: request.subject() = params.mSubject; michael@0: michael@0: // Set service ID. michael@0: request.serviceId() = aServiceId; michael@0: michael@0: return true; michael@0: } michael@0: michael@0: /* michael@0: * Implementation of nsIMmsService. michael@0: */ michael@0: michael@0: NS_IMETHODIMP michael@0: SmsIPCService::GetMmsDefaultServiceId(uint32_t* aServiceId) michael@0: { michael@0: *aServiceId = mMmsDefaultServiceId; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: SmsIPCService::Send(uint32_t aServiceId, michael@0: JS::Handle aParameters, michael@0: nsIMobileMessageCallback *aRequest) michael@0: { michael@0: SendMmsMessageRequest req; michael@0: if (!GetSendMmsMessageRequestFromParams(aServiceId, aParameters, req)) { michael@0: return NS_ERROR_INVALID_ARG; michael@0: } michael@0: return SendRequest(SendMessageRequest(req), aRequest); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: SmsIPCService::Retrieve(int32_t aId, nsIMobileMessageCallback *aRequest) michael@0: { michael@0: return SendRequest(RetrieveMessageRequest(aId), aRequest); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: SmsIPCService::SendReadReport(const nsAString & messageID, michael@0: const nsAString & toAddress, michael@0: const nsAString & iccId) michael@0: { michael@0: NS_ERROR("We should not be here!"); michael@0: return NS_OK; michael@0: }