/* 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 "mozilla/dom/mobileconnection/MobileConnectionParent.h" #include "mozilla/AppProcessChecker.h" #include "mozilla/dom/BindingUtils.h" #include "mozilla/dom/mobileconnection/MobileConnectionIPCSerializer.h" #include "mozilla/dom/MozMobileConnectionBinding.h" #include "mozilla/dom/ToJSValue.h" #include "nsIVariant.h" #include "nsJSUtils.h" using namespace mozilla; using namespace mozilla::dom; using namespace mozilla::dom::mobileconnection; MobileConnectionParent::MobileConnectionParent(uint32_t aClientId) : mLive(true) { MOZ_COUNT_CTOR(MobileConnectionParent); nsCOMPtr service = do_GetService(NS_MOBILE_CONNECTION_SERVICE_CONTRACTID); NS_ASSERTION(service, "This shouldn't fail!"); nsresult rv = service->GetItemByServiceId(aClientId, getter_AddRefs(mMobileConnection)); if (NS_SUCCEEDED(rv) && mMobileConnection) { mMobileConnection->RegisterListener(this); } } void MobileConnectionParent::ActorDestroy(ActorDestroyReason why) { mLive = false; if (mMobileConnection) { mMobileConnection->UnregisterListener(this); mMobileConnection = nullptr; } } bool MobileConnectionParent::RecvPMobileConnectionRequestConstructor(PMobileConnectionRequestParent* aActor, const MobileConnectionRequest& aRequest) { MobileConnectionRequestParent* actor = static_cast(aActor); switch (aRequest.type()) { case MobileConnectionRequest::TGetNetworksRequest: return actor->DoRequest(aRequest.get_GetNetworksRequest()); case MobileConnectionRequest::TSelectNetworkRequest: return actor->DoRequest(aRequest.get_SelectNetworkRequest()); case MobileConnectionRequest::TSelectNetworkAutoRequest: return actor->DoRequest(aRequest.get_SelectNetworkAutoRequest()); case MobileConnectionRequest::TSetPreferredNetworkTypeRequest: return actor->DoRequest(aRequest.get_SetPreferredNetworkTypeRequest()); case MobileConnectionRequest::TGetPreferredNetworkTypeRequest: return actor->DoRequest(aRequest.get_GetPreferredNetworkTypeRequest()); case MobileConnectionRequest::TSetRoamingPreferenceRequest: return actor->DoRequest(aRequest.get_SetRoamingPreferenceRequest()); case MobileConnectionRequest::TGetRoamingPreferenceRequest: return actor->DoRequest(aRequest.get_GetRoamingPreferenceRequest()); case MobileConnectionRequest::TSetVoicePrivacyModeRequest: return actor->DoRequest(aRequest.get_SetVoicePrivacyModeRequest()); case MobileConnectionRequest::TGetVoicePrivacyModeRequest: return actor->DoRequest(aRequest.get_GetVoicePrivacyModeRequest()); case MobileConnectionRequest::TSendMmiRequest: return actor->DoRequest(aRequest.get_SendMmiRequest()); case MobileConnectionRequest::TCancelMmiRequest: return actor->DoRequest(aRequest.get_CancelMmiRequest()); case MobileConnectionRequest::TSetCallForwardingRequest: return actor->DoRequest(aRequest.get_SetCallForwardingRequest()); case MobileConnectionRequest::TGetCallForwardingRequest: return actor->DoRequest(aRequest.get_GetCallForwardingRequest()); case MobileConnectionRequest::TSetCallBarringRequest: return actor->DoRequest(aRequest.get_SetCallBarringRequest()); case MobileConnectionRequest::TGetCallBarringRequest: return actor->DoRequest(aRequest.get_GetCallBarringRequest()); case MobileConnectionRequest::TChangeCallBarringPasswordRequest: return actor->DoRequest(aRequest.get_ChangeCallBarringPasswordRequest()); case MobileConnectionRequest::TSetCallWaitingRequest: return actor->DoRequest(aRequest.get_SetCallWaitingRequest()); case MobileConnectionRequest::TGetCallWaitingRequest: return actor->DoRequest(aRequest.get_GetCallWaitingRequest()); case MobileConnectionRequest::TSetCallingLineIdRestrictionRequest: return actor->DoRequest(aRequest.get_SetCallingLineIdRestrictionRequest()); case MobileConnectionRequest::TGetCallingLineIdRestrictionRequest: return actor->DoRequest(aRequest.get_GetCallingLineIdRestrictionRequest()); case MobileConnectionRequest::TExitEmergencyCbModeRequest: return actor->DoRequest(aRequest.get_ExitEmergencyCbModeRequest()); case MobileConnectionRequest::TSetRadioEnabledRequest: return actor->DoRequest(aRequest.get_SetRadioEnabledRequest()); default: MOZ_CRASH("Received invalid request type!"); } return false; } PMobileConnectionRequestParent* MobileConnectionParent::AllocPMobileConnectionRequestParent(const MobileConnectionRequest& request) { if (!AssertAppProcessPermission(Manager(), "mobileconnection")) { return nullptr; } MobileConnectionRequestParent* actor = new MobileConnectionRequestParent(mMobileConnection); // Add an extra ref for IPDL. Will be released in // MobileConnectionParent::DeallocPMobileConnectionRequestParent(). actor->AddRef(); return actor; } bool MobileConnectionParent::DeallocPMobileConnectionRequestParent(PMobileConnectionRequestParent* aActor) { // MobileConnectionRequestParent is refcounted, must not be freed manually. static_cast(aActor)->Release(); return true; } bool MobileConnectionParent::RecvInit(nsMobileConnectionInfo* aVoice, nsMobileConnectionInfo* aData, nsString* aLastKnownNetwork, nsString* aLastKnownHomeNetwork, nsString* aIccId, nsString* aNetworkSelectionMode, nsString* aRadioState, nsTArray* aSupportedNetworkTypes) { NS_ENSURE_TRUE(mMobileConnection, false); NS_ENSURE_SUCCESS(mMobileConnection->GetVoice(aVoice), false); NS_ENSURE_SUCCESS(mMobileConnection->GetData(aData), false); NS_ENSURE_SUCCESS(mMobileConnection->GetLastKnownNetwork(*aLastKnownNetwork), false); NS_ENSURE_SUCCESS(mMobileConnection->GetLastKnownHomeNetwork(*aLastKnownHomeNetwork), false); NS_ENSURE_SUCCESS(mMobileConnection->GetIccId(*aIccId), false); NS_ENSURE_SUCCESS(mMobileConnection->GetNetworkSelectionMode(*aNetworkSelectionMode), false); NS_ENSURE_SUCCESS(mMobileConnection->GetRadioState(*aRadioState), false); char16_t** types = nullptr; uint32_t length = 0; nsresult rv = mMobileConnection->GetSupportedNetworkTypes(&types, &length); NS_ENSURE_SUCCESS(rv, false); for (uint32_t i = 0; i < length; ++i) { nsDependentString type(types[i]); aSupportedNetworkTypes->AppendElement(type); } NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(length, types); return true; } // nsIMobileConnectionListener NS_IMPL_ISUPPORTS(MobileConnectionParent, nsIMobileConnectionListener) NS_IMETHODIMP MobileConnectionParent::NotifyVoiceChanged() { NS_ENSURE_TRUE(mLive, NS_ERROR_FAILURE); nsresult rv; nsCOMPtr info; rv = mMobileConnection->GetVoice(getter_AddRefs(info)); NS_ENSURE_SUCCESS(rv, rv); // We release the ref after serializing process is finished in // MobileConnectionIPCSerializer. return SendNotifyVoiceInfoChanged(info.forget().take()) ? NS_OK : NS_ERROR_FAILURE; } NS_IMETHODIMP MobileConnectionParent::NotifyDataChanged() { NS_ENSURE_TRUE(mLive, NS_ERROR_FAILURE); nsresult rv; nsCOMPtr info; rv = mMobileConnection->GetData(getter_AddRefs(info)); NS_ENSURE_SUCCESS(rv, rv); // We release the ref after serializing process is finished in // MobileConnectionIPCSerializer. return SendNotifyDataInfoChanged(info.forget().take()) ? NS_OK : NS_ERROR_FAILURE; } NS_IMETHODIMP MobileConnectionParent::NotifyUssdReceived(const nsAString& aMessage, bool aSessionEnded) { NS_ENSURE_TRUE(mLive, NS_ERROR_FAILURE); return SendNotifyUssdReceived(nsAutoString(aMessage), aSessionEnded) ? NS_OK : NS_ERROR_FAILURE; } NS_IMETHODIMP MobileConnectionParent::NotifyDataError(const nsAString& aMessage) { NS_ENSURE_TRUE(mLive, NS_ERROR_FAILURE); return SendNotifyDataError(nsAutoString(aMessage)) ? NS_OK : NS_ERROR_FAILURE; } NS_IMETHODIMP MobileConnectionParent::NotifyCFStateChanged(bool aSuccess, uint16_t aAction, uint16_t aReason, const nsAString &aNumber, uint16_t aTimeSeconds, uint16_t aServiceClass) { NS_ENSURE_TRUE(mLive, NS_ERROR_FAILURE); return SendNotifyCFStateChanged(aSuccess, aAction, aReason, nsAutoString(aNumber), aTimeSeconds, aServiceClass) ? NS_OK : NS_ERROR_FAILURE; } NS_IMETHODIMP MobileConnectionParent::NotifyEmergencyCbModeChanged(bool aActive, uint32_t aTimeoutMs) { NS_ENSURE_TRUE(mLive, NS_ERROR_FAILURE); return SendNotifyEmergencyCbModeChanged(aActive, aTimeoutMs) ? NS_OK : NS_ERROR_FAILURE; } NS_IMETHODIMP MobileConnectionParent::NotifyOtaStatusChanged(const nsAString& aStatus) { NS_ENSURE_TRUE(mLive, NS_ERROR_FAILURE); return SendNotifyOtaStatusChanged(nsAutoString(aStatus)) ? NS_OK : NS_ERROR_FAILURE; } NS_IMETHODIMP MobileConnectionParent::NotifyIccChanged() { NS_ENSURE_TRUE(mLive, NS_ERROR_FAILURE); nsAutoString iccId; mMobileConnection->GetIccId(iccId); return SendNotifyIccChanged(iccId) ? NS_OK : NS_ERROR_FAILURE; } NS_IMETHODIMP MobileConnectionParent::NotifyRadioStateChanged() { NS_ENSURE_TRUE(mLive, NS_ERROR_FAILURE); nsresult rv; nsAutoString radioState; rv = mMobileConnection->GetRadioState(radioState); NS_ENSURE_SUCCESS(rv, rv); return SendNotifyRadioStateChanged(radioState) ? NS_OK : NS_ERROR_FAILURE; } NS_IMETHODIMP MobileConnectionParent::NotifyClirModeChanged(uint32_t aMode) { NS_ENSURE_TRUE(mLive, NS_ERROR_FAILURE); return SendNotifyClirModeChanged(aMode) ? NS_OK : NS_ERROR_FAILURE; } NS_IMETHODIMP MobileConnectionParent::NotifyLastKnownNetworkChanged() { NS_ENSURE_TRUE(mLive, NS_ERROR_FAILURE); nsresult rv; nsAutoString network; rv = mMobileConnection->GetLastKnownNetwork(network); NS_ENSURE_SUCCESS(rv, rv); return SendNotifyLastNetworkChanged(network) ? NS_OK : NS_ERROR_FAILURE; } NS_IMETHODIMP MobileConnectionParent::NotifyLastKnownHomeNetworkChanged() { NS_ENSURE_TRUE(mLive, NS_ERROR_FAILURE); nsresult rv; nsAutoString network; rv = mMobileConnection->GetLastKnownHomeNetwork(network); NS_ENSURE_SUCCESS(rv, rv); return SendNotifyLastHomeNetworkChanged(network) ? NS_OK : NS_ERROR_FAILURE; } NS_IMETHODIMP MobileConnectionParent::NotifyNetworkSelectionModeChanged() { NS_ENSURE_TRUE(mLive, NS_ERROR_FAILURE); nsresult rv; nsAutoString mode; rv = mMobileConnection->GetNetworkSelectionMode(mode); NS_ENSURE_SUCCESS(rv, rv); return SendNotifyNetworkSelectionModeChanged(mode) ? NS_OK : NS_ERROR_FAILURE; } /****************************************************************************** * PMobileConnectionRequestParent ******************************************************************************/ void MobileConnectionRequestParent::ActorDestroy(ActorDestroyReason why) { mLive = false; mMobileConnection = nullptr; } bool MobileConnectionRequestParent::DoRequest(const GetNetworksRequest& aRequest) { NS_ENSURE_TRUE(mMobileConnection, false); return NS_SUCCEEDED(mMobileConnection->GetNetworks(this)); } bool MobileConnectionRequestParent::DoRequest(const SelectNetworkRequest& aRequest) { NS_ENSURE_TRUE(mMobileConnection, false); // Use dont_AddRef here because this instances is already AddRef-ed in // MobileConnectionIPCSerializer.h nsCOMPtr network = dont_AddRef(aRequest.network()); return NS_SUCCEEDED(mMobileConnection->SelectNetwork(network, this)); } bool MobileConnectionRequestParent::DoRequest(const SelectNetworkAutoRequest& aRequest) { NS_ENSURE_TRUE(mMobileConnection, false); return NS_SUCCEEDED(mMobileConnection->SelectNetworkAutomatically(this)); } bool MobileConnectionRequestParent::DoRequest(const SetPreferredNetworkTypeRequest& aRequest) { NS_ENSURE_TRUE(mMobileConnection, false); return NS_SUCCEEDED(mMobileConnection->SetPreferredNetworkType(aRequest.type(), this)); } bool MobileConnectionRequestParent::DoRequest(const GetPreferredNetworkTypeRequest& aRequest) { NS_ENSURE_TRUE(mMobileConnection, false); return NS_SUCCEEDED(mMobileConnection->GetPreferredNetworkType(this)); } bool MobileConnectionRequestParent::DoRequest(const SetRoamingPreferenceRequest& aRequest) { NS_ENSURE_TRUE(mMobileConnection, false); return NS_SUCCEEDED(mMobileConnection->SetRoamingPreference(aRequest.mode(), this)); } bool MobileConnectionRequestParent::DoRequest(const GetRoamingPreferenceRequest& aRequest) { NS_ENSURE_TRUE(mMobileConnection, false); return NS_SUCCEEDED(mMobileConnection->GetRoamingPreference(this)); } bool MobileConnectionRequestParent::DoRequest(const SetVoicePrivacyModeRequest& aRequest) { NS_ENSURE_TRUE(mMobileConnection, false); return NS_SUCCEEDED(mMobileConnection->SetVoicePrivacyMode(aRequest.enabled(), this)); } bool MobileConnectionRequestParent::DoRequest(const GetVoicePrivacyModeRequest& aRequest) { NS_ENSURE_TRUE(mMobileConnection, false); return NS_SUCCEEDED(mMobileConnection->GetVoicePrivacyMode(this)); } bool MobileConnectionRequestParent::DoRequest(const SendMmiRequest& aRequest) { NS_ENSURE_TRUE(mMobileConnection, false); return NS_SUCCEEDED(mMobileConnection->SendMMI(aRequest.mmi(), this)); } bool MobileConnectionRequestParent::DoRequest(const CancelMmiRequest& aRequest) { NS_ENSURE_TRUE(mMobileConnection, false); return NS_SUCCEEDED(mMobileConnection->CancelMMI(this)); } bool MobileConnectionRequestParent::DoRequest(const SetCallForwardingRequest& aRequest) { NS_ENSURE_TRUE(mMobileConnection, false); // There are cases (bug 1070083) where this is called with no JS on the stack. // And since mobileConnectionService might be JS-Implemented, so we just // create it in the System-Principaled Junk Scope. We are going to get rid of // the "jsval" used in MobileConnection's interface in bug 1047196, after that // we don't need these things. // Note that using xpc::PrivilegedJunkScope requires explicit case-by-case // approval from the XPConnect module owner (bholley). AutoJSAPI jsapi; if (NS_WARN_IF(!jsapi.Init(xpc::PrivilegedJunkScope()))) { return false; } JSContext* cx = jsapi.cx(); JS::Rooted options(cx); if (!ToJSValue(cx, aRequest.options(), &options)) { JS_ClearPendingException(cx); return false; } return NS_SUCCEEDED(mMobileConnection->SetCallForwarding(options, this)); } bool MobileConnectionRequestParent::DoRequest(const GetCallForwardingRequest& aRequest) { NS_ENSURE_TRUE(mMobileConnection, false); return NS_SUCCEEDED(mMobileConnection->GetCallForwarding(aRequest.reason(), this)); } bool MobileConnectionRequestParent::DoRequest(const SetCallBarringRequest& aRequest) { NS_ENSURE_TRUE(mMobileConnection, false); // There are cases (bug 1070083) where this is called with no JS on the stack. // And since mobileConnectionService might be JS-Implemented, so we just // create it in the System-Principaled Junk Scope. We are going to get rid of // the "jsval" used in MobileConnection's interface in bug 1047196, after that // we don't need these things. // Note that using xpc::PrivilegedJunkScope requires explicit case-by-case // approval from the XPConnect module owner (bholley). AutoJSAPI jsapi; if (NS_WARN_IF(!jsapi.Init(xpc::PrivilegedJunkScope()))) { return false; } JSContext* cx = jsapi.cx(); JS::Rooted options(cx); if (!ToJSValue(cx, aRequest.options(), &options)) { JS_ClearPendingException(cx); return false; } return NS_SUCCEEDED(mMobileConnection->SetCallBarring(options, this)); } bool MobileConnectionRequestParent::DoRequest(const GetCallBarringRequest& aRequest) { NS_ENSURE_TRUE(mMobileConnection, false); // There are cases (bug 1070083) where this is called with no JS on the stack. // And since mobileConnectionService might be JS-Implemented, so we just // create it in the System-Principaled Junk Scope. We are going to get rid of // the "jsval" used in MobileConnection's interface in bug 1047196, after that // we don't need these things. // Note that using xpc::PrivilegedJunkScope requires explicit case-by-case // approval from the XPConnect module owner (bholley). AutoJSAPI jsapi; if (NS_WARN_IF(!jsapi.Init(xpc::PrivilegedJunkScope()))) { return false; } JSContext* cx = jsapi.cx(); JS::Rooted options(cx); if (!ToJSValue(cx, aRequest.options(), &options)) { JS_ClearPendingException(cx); return false; } return NS_SUCCEEDED(mMobileConnection->GetCallBarring(options, this)); } bool MobileConnectionRequestParent::DoRequest(const ChangeCallBarringPasswordRequest& aRequest) { NS_ENSURE_TRUE(mMobileConnection, false); // There are cases (bug 1070083) where this is called with no JS on the stack. // And since mobileConnectionService might be JS-Implemented, so we just // create it in the System-Principaled Junk Scope. We are going to get rid of // the "jsval" used in MobileConnection's interface in bug 1047196, after that // we don't need these things. // Note that using xpc::PrivilegedJunkScope requires explicit case-by-case // approval from the XPConnect module owner (bholley). AutoJSAPI jsapi; if (NS_WARN_IF(!jsapi.Init(xpc::PrivilegedJunkScope()))) { return false; } JSContext* cx = jsapi.cx(); JS::Rooted options(cx); if (!ToJSValue(cx, aRequest.options(), &options)) { JS_ClearPendingException(cx); return false; } return NS_SUCCEEDED(mMobileConnection->ChangeCallBarringPassword(options, this)); } bool MobileConnectionRequestParent::DoRequest(const SetCallWaitingRequest& aRequest) { NS_ENSURE_TRUE(mMobileConnection, false); return NS_SUCCEEDED(mMobileConnection->SetCallWaiting(aRequest.enabled(), this)); } bool MobileConnectionRequestParent::DoRequest(const GetCallWaitingRequest& aRequest) { NS_ENSURE_TRUE(mMobileConnection, false); return NS_SUCCEEDED(mMobileConnection->GetCallWaiting(this)); } bool MobileConnectionRequestParent::DoRequest(const SetCallingLineIdRestrictionRequest& aRequest) { NS_ENSURE_TRUE(mMobileConnection, false); return NS_SUCCEEDED(mMobileConnection->SetCallingLineIdRestriction(aRequest.mode(), this)); } bool MobileConnectionRequestParent::DoRequest(const GetCallingLineIdRestrictionRequest& aRequest) { NS_ENSURE_TRUE(mMobileConnection, false); return NS_SUCCEEDED(mMobileConnection->GetCallingLineIdRestriction(this)); } bool MobileConnectionRequestParent::DoRequest(const ExitEmergencyCbModeRequest& aRequest) { NS_ENSURE_TRUE(mMobileConnection, false); return NS_SUCCEEDED(mMobileConnection->ExitEmergencyCbMode(this)); } bool MobileConnectionRequestParent::DoRequest(const SetRadioEnabledRequest& aRequest) { NS_ENSURE_TRUE(mMobileConnection, false); return NS_SUCCEEDED(mMobileConnection->SetRadioEnabled(aRequest.enabled(), this)); } nsresult MobileConnectionRequestParent::SendReply(const MobileConnectionReply& aReply) { NS_ENSURE_TRUE(mLive, NS_ERROR_FAILURE); return Send__delete__(this, aReply) ? NS_OK : NS_ERROR_FAILURE; } // nsIMobileConnectionListener NS_IMPL_ISUPPORTS(MobileConnectionRequestParent, nsIMobileConnectionCallback); NS_IMETHODIMP MobileConnectionRequestParent::NotifySuccess() { return SendReply(MobileConnectionReplySuccess()); } NS_IMETHODIMP MobileConnectionRequestParent::NotifySuccessWithString(const nsAString& aResult) { return SendReply(MobileConnectionReplySuccessString(nsAutoString(aResult))); } NS_IMETHODIMP MobileConnectionRequestParent::NotifySuccessWithBoolean(bool aResult) { return SendReply(MobileConnectionReplySuccessBoolean(aResult)); } NS_IMETHODIMP MobileConnectionRequestParent::NotifyGetNetworksSuccess(uint32_t aCount, nsIMobileNetworkInfo** aNetworks) { nsTArray networks; for (uint32_t i = 0; i < aCount; i++) { nsCOMPtr network = aNetworks[i]; // We release the ref after serializing process is finished in // MobileConnectionIPCSerializer. networks.AppendElement(network.forget().take()); } return SendReply(MobileConnectionReplySuccessNetworks(networks)); } NS_IMETHODIMP MobileConnectionRequestParent::NotifySendCancelMmiSuccess(JS::Handle aResult, JSContext* aCx) { RootedDictionary result(aCx); if (!result.Init(aCx, aResult)) { return NS_ERROR_TYPE_ERR; } // No additionInformation passed if (!result.mAdditionalInformation.WasPassed()) { return SendReply(MobileConnectionReplySuccessMmi(result.mServiceCode, result.mStatusMessage, AdditionalInformation(mozilla::void_t()))); } OwningUnsignedShortOrObject& additionInformation = result.mAdditionalInformation.Value(); if (additionInformation.IsUnsignedShort()) { return SendReply(MobileConnectionReplySuccessMmi(result.mServiceCode, result.mStatusMessage, AdditionalInformation(uint16_t(additionInformation.GetAsUnsignedShort())))); } if (additionInformation.IsObject()) { uint32_t length; JS::Rooted value(aCx); JS::Rooted object(aCx, additionInformation.GetAsObject()); if (!JS_IsArrayObject(aCx, object) || !JS_GetArrayLength(aCx, object, &length) || length <= 0 || // Check first element to decide the format of array. !JS_GetElement(aCx, object, 0, &value)) { return NS_ERROR_TYPE_ERR; } // Check first element to decide the format of array. if (value.isString()) { // String[] nsTArray infos; for (uint32_t i = 0; i < length; i++) { if (!JS_GetElement(aCx, object, i, &value) || !value.isString()) { return NS_ERROR_TYPE_ERR; } nsAutoJSString str; if (!str.init(aCx, value.toString())) { return NS_ERROR_FAILURE; } infos.AppendElement(str); } return SendReply(MobileConnectionReplySuccessMmi(result.mServiceCode, result.mStatusMessage, AdditionalInformation(infos))); } else { // IPC::MozCallForwardingOptions[] nsTArray infos; for (uint32_t i = 0; i < length; i++) { IPC::MozCallForwardingOptions info; if (!JS_GetElement(aCx, object, i, &value) || !info.Init(aCx, value)) { return NS_ERROR_TYPE_ERR; } infos.AppendElement(info); } return SendReply(MobileConnectionReplySuccessMmi(result.mServiceCode, result.mStatusMessage, AdditionalInformation(infos))); } } return NS_ERROR_TYPE_ERR; } NS_IMETHODIMP MobileConnectionRequestParent::NotifyGetCallForwardingSuccess(JS::Handle aResults, JSContext* aCx) { uint32_t length; JS::Rooted object(aCx, &aResults.toObject()); nsTArray results; if (!JS_IsArrayObject(aCx, object) || !JS_GetArrayLength(aCx, object, &length)) { return NS_ERROR_TYPE_ERR; } for (uint32_t i = 0; i < length; i++) { JS::Rooted entry(aCx); IPC::MozCallForwardingOptions info; if (!JS_GetElement(aCx, object, i, &entry) || !info.Init(aCx, entry)) { return NS_ERROR_TYPE_ERR; } results.AppendElement(info); } return SendReply(MobileConnectionReplySuccessCallForwarding(results)); } NS_IMETHODIMP MobileConnectionRequestParent::NotifyGetCallBarringSuccess(uint16_t aProgram, bool aEnabled, uint16_t aServiceClass) { return SendReply(MobileConnectionReplySuccessCallBarring(aProgram, aEnabled, aServiceClass)); } NS_IMETHODIMP MobileConnectionRequestParent::NotifyGetClirStatusSuccess(uint16_t aN, uint16_t aM) { return SendReply(MobileConnectionReplySuccessClirStatus(aN, aM)); } NS_IMETHODIMP MobileConnectionRequestParent::NotifyError(const nsAString& aName, const nsAString& aMessage, const nsAString& aServiceCode, uint16_t aInfo, uint8_t aArgc) { if (aArgc == 0) { nsAutoString error(aName); return SendReply(MobileConnectionReplyError(error)); } nsAutoString name(aName); nsAutoString message(aMessage); nsAutoString serviceCode(aServiceCode); if (aArgc < 3) { return SendReply(MobileConnectionReplyErrorMmi(name, message, serviceCode, AdditionalInformation(mozilla::void_t()))); } return SendReply(MobileConnectionReplyErrorMmi(name, message, serviceCode, AdditionalInformation(aInfo))); }