/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* 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/Icc.h" #include "IccCallback.h" #include "IccContact.h" #include "mozilla/dom/ContactsBinding.h" #include "mozilla/dom/DOMRequest.h" #include "mozilla/dom/IccInfo.h" #include "mozilla/dom/MozStkCommandEvent.h" #include "mozilla/dom/Promise.h" #include "mozilla/dom/ScriptSettings.h" #include "nsIIccInfo.h" #include "nsIIccService.h" #include "nsIStkCmdFactory.h" #include "nsIStkProactiveCmd.h" #include "nsServiceManagerUtils.h" using mozilla::dom::icc::IccCallback; using mozilla::dom::icc::IccContact; namespace mozilla { namespace dom { namespace { bool IsPukCardLockType(IccLockType aLockType) { switch(aLockType) { case IccLockType::Puk: case IccLockType::Puk2: case IccLockType::NckPuk: case IccLockType::Nck1Puk: case IccLockType::Nck2Puk: case IccLockType::HnckPuk: case IccLockType::CckPuk: case IccLockType::SpckPuk: case IccLockType::RcckPuk: case IccLockType::RspckPuk: case IccLockType::NsckPuk: case IccLockType::PckPuk: return true; default: return false; } } } // namespace NS_IMPL_CYCLE_COLLECTION_INHERITED(Icc, DOMEventTargetHelper, mIccInfo) NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(Icc) NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper) NS_IMPL_ADDREF_INHERITED(Icc, DOMEventTargetHelper) NS_IMPL_RELEASE_INHERITED(Icc, DOMEventTargetHelper) Icc::Icc(nsPIDOMWindow* aWindow, nsIIcc* aHandler, nsIIccInfo* aIccInfo) : mLive(true) , mHandler(aHandler) { BindToOwner(aWindow); if (aIccInfo) { aIccInfo->GetIccid(mIccId); UpdateIccInfo(aIccInfo); } } Icc::~Icc() { } void Icc::Shutdown() { mIccInfo.SetNull(); mHandler = nullptr; mLive = false; } nsresult Icc::NotifyEvent(const nsAString& aName) { return DispatchTrustedEvent(aName); } nsresult Icc::NotifyStkEvent(const nsAString& aName, nsIStkProactiveCmd* aStkProactiveCmd) { AutoJSAPI jsapi; if (NS_WARN_IF(!jsapi.InitWithLegacyErrorReporting(GetOwner()))) { return NS_ERROR_UNEXPECTED; } JSContext* cx = jsapi.cx(); JS::Rooted value(cx); nsCOMPtr cmdFactory = do_GetService(ICC_STK_CMD_FACTORY_CONTRACTID); NS_ENSURE_TRUE(cmdFactory, NS_ERROR_UNEXPECTED); cmdFactory->CreateCommandMessage(aStkProactiveCmd, &value); NS_ENSURE_TRUE(value.isObject(), NS_ERROR_UNEXPECTED); MozStkCommandEventInit init; init.mBubbles = false; init.mCancelable = false; init.mCommand = value; nsRefPtr event = MozStkCommandEvent::Constructor(this, aName, init); return DispatchTrustedEvent(event); } void Icc::UpdateIccInfo(nsIIccInfo* aIccInfo) { if (!aIccInfo) { mIccInfo.SetNull(); return; } nsCOMPtr gsmIccInfo(do_QueryInterface(aIccInfo)); if (gsmIccInfo) { if (mIccInfo.IsNull() || !mIccInfo.Value().IsMozGsmIccInfo()) { mIccInfo.SetValue().SetAsMozGsmIccInfo() = new GsmIccInfo(GetOwner()); } mIccInfo.Value().GetAsMozGsmIccInfo().get()->Update(gsmIccInfo); return; } nsCOMPtr cdmaIccInfo(do_QueryInterface(aIccInfo)); if (cdmaIccInfo) { if (mIccInfo.IsNull() || !mIccInfo.Value().IsMozCdmaIccInfo()) { mIccInfo.SetValue().SetAsMozCdmaIccInfo() = new CdmaIccInfo(GetOwner()); } mIccInfo.Value().GetAsMozCdmaIccInfo().get()->Update(cdmaIccInfo); return; } if (mIccInfo.IsNull() || !mIccInfo.Value().IsMozIccInfo()) { mIccInfo.SetValue().SetAsMozIccInfo() = new IccInfo(GetOwner()); } mIccInfo.Value().GetAsMozIccInfo().get()->Update(aIccInfo); } // WrapperCache JSObject* Icc::WrapObject(JSContext* aCx, JS::Handle aGivenProto) { return MozIccBinding::Wrap(aCx, this, aGivenProto); } // MozIcc WebIDL void Icc::GetIccInfo(Nullable& aIccInfo) const { aIccInfo = mIccInfo; } Nullable Icc::GetCardState() const { Nullable result; uint32_t cardState = nsIIcc::CARD_STATE_UNDETECTED; if (mHandler && NS_SUCCEEDED(mHandler->GetCardState(&cardState)) && cardState != nsIIcc::CARD_STATE_UNDETECTED) { MOZ_ASSERT(cardState < static_cast(IccCardState::EndGuard_)); result.SetValue(static_cast(cardState)); } return result; } void Icc::SendStkResponse(const JSContext* aCx, JS::Handle aCommand, JS::Handle aResponse, ErrorResult& aRv) { if (!mHandler) { aRv.Throw(NS_ERROR_FAILURE); return; } nsCOMPtr cmdFactory = do_GetService(ICC_STK_CMD_FACTORY_CONTRACTID); if (!cmdFactory) { aRv.Throw(NS_ERROR_FAILURE); return; } nsCOMPtr command; cmdFactory->CreateCommand(aCommand, getter_AddRefs(command)); if (!command) { aRv.Throw(NS_ERROR_FAILURE); return; } nsCOMPtr response; cmdFactory->CreateResponse(aResponse, getter_AddRefs(response)); if (!response) { aRv.Throw(NS_ERROR_FAILURE); return; } nsresult rv = mHandler->SendStkResponse(command, response); if (NS_FAILED(rv)) { aRv.Throw(rv); } } void Icc::SendStkMenuSelection(uint16_t aItemIdentifier, bool aHelpRequested, ErrorResult& aRv) { if (!mHandler) { aRv.Throw(NS_ERROR_FAILURE); return; } nsresult rv = mHandler->SendStkMenuSelection(aItemIdentifier, aHelpRequested); if (NS_FAILED(rv)) { aRv.Throw(rv); } } void Icc::SendStkTimerExpiration(const JSContext* aCx, JS::Handle aTimer, ErrorResult& aRv) { if (!mHandler) { aRv.Throw(NS_ERROR_FAILURE); return; } nsCOMPtr cmdFactory = do_GetService(ICC_STK_CMD_FACTORY_CONTRACTID); if (!cmdFactory) { aRv.Throw(NS_ERROR_FAILURE); return; } nsCOMPtr timer; cmdFactory->CreateTimer(aTimer, getter_AddRefs(timer)); if (!timer) { aRv.Throw(NS_ERROR_FAILURE); return; } uint16_t timerId; nsresult rv = timer->GetTimerId(&timerId); if (NS_FAILED(rv)) { aRv.Throw(rv); } uint32_t timerValue; rv = timer->GetTimerValue(&timerValue); if (NS_FAILED(rv)) { aRv.Throw(rv); } rv = mHandler->SendStkTimerExpiration(timerId, timerValue); if (NS_FAILED(rv)) { aRv.Throw(rv); } } void Icc::SendStkEventDownload(const JSContext* aCx, JS::Handle aEvent, ErrorResult& aRv) { if (!mHandler) { aRv.Throw(NS_ERROR_FAILURE); return; } nsCOMPtr cmdFactory = do_GetService(ICC_STK_CMD_FACTORY_CONTRACTID); if (!cmdFactory) { aRv.Throw(NS_ERROR_FAILURE); return; } nsCOMPtr event; cmdFactory->CreateEvent(aEvent, getter_AddRefs(event)); if (!event) { aRv.Throw(NS_ERROR_FAILURE); return; } nsresult rv = mHandler->SendStkEventDownload(event); if (NS_FAILED(rv)) { aRv.Throw(rv); } } already_AddRefed Icc::GetCardLock(IccLockType aLockType, ErrorResult& aRv) { if (!mHandler) { aRv.Throw(NS_ERROR_FAILURE); return nullptr; } nsRefPtr request = new DOMRequest(GetOwner()); // TODO: Bug 1125018 - Simplify The Result of GetCardLock and // getCardLockRetryCount in MozIcc.webidl without a wrapper object. nsRefPtr requestCallback = new IccCallback(GetOwner(), request, true); nsresult rv = mHandler->GetCardLockEnabled(static_cast(aLockType), requestCallback); if (NS_FAILED(rv)) { aRv.Throw(rv); return nullptr; } return request.forget(); } already_AddRefed Icc::UnlockCardLock(const IccUnlockCardLockOptions& aOptions, ErrorResult& aRv) { if (!mHandler) { aRv.Throw(NS_ERROR_FAILURE); return nullptr; } nsRefPtr request = new DOMRequest(GetOwner()); nsRefPtr requestCallback = new IccCallback(GetOwner(), request); const nsString& password = IsPukCardLockType(aOptions.mLockType) ? aOptions.mPuk : aOptions.mPin; nsresult rv = mHandler->UnlockCardLock(static_cast(aOptions.mLockType), password, aOptions.mNewPin, requestCallback); if (NS_FAILED(rv)) { aRv.Throw(rv); return nullptr; } return request.forget(); } already_AddRefed Icc::SetCardLock(const IccSetCardLockOptions& aOptions, ErrorResult& aRv) { if (!mHandler) { aRv.Throw(NS_ERROR_FAILURE); return nullptr; } nsresult rv; nsRefPtr request = new DOMRequest(GetOwner()); nsRefPtr requestCallback = new IccCallback(GetOwner(), request); if (aOptions.mEnabled.WasPassed()) { // Enable card lock. const nsString& password = (aOptions.mLockType == IccLockType::Fdn) ? aOptions.mPin2 : aOptions.mPin; rv = mHandler->SetCardLockEnabled(static_cast(aOptions.mLockType), password, aOptions.mEnabled.Value(), requestCallback); } else { // Change card lock password. rv = mHandler->ChangeCardLockPassword(static_cast(aOptions.mLockType), aOptions.mPin, aOptions.mNewPin, requestCallback); } if (NS_FAILED(rv)) { aRv.Throw(rv); return nullptr; } return request.forget(); } already_AddRefed Icc::GetCardLockRetryCount(IccLockType aLockType, ErrorResult& aRv) { if (!mHandler) { aRv.Throw(NS_ERROR_FAILURE); return nullptr; } nsRefPtr request = new DOMRequest(GetOwner()); nsRefPtr requestCallback = new IccCallback(GetOwner(), request); nsresult rv = mHandler->GetCardLockRetryCount(static_cast(aLockType), requestCallback); if (NS_FAILED(rv)) { aRv.Throw(rv); return nullptr; } return request.forget(); } already_AddRefed Icc::ReadContacts(IccContactType aContactType, ErrorResult& aRv) { if (!mHandler) { aRv.Throw(NS_ERROR_FAILURE); return nullptr; } nsRefPtr request = new DOMRequest(GetOwner()); nsRefPtr requestCallback = new IccCallback(GetOwner(), request); nsresult rv = mHandler->ReadContacts(static_cast(aContactType), requestCallback); if (NS_FAILED(rv)) { aRv.Throw(rv); return nullptr; } return request.forget(); } already_AddRefed Icc::UpdateContact(IccContactType aContactType, mozContact& aContact, const nsAString& aPin2, ErrorResult& aRv) { if (!mHandler) { aRv.Throw(NS_ERROR_FAILURE); return nullptr; } nsRefPtr request = new DOMRequest(GetOwner()); nsRefPtr requestCallback = new IccCallback(GetOwner(), request); nsCOMPtr iccContact; nsresult rv = IccContact::Create(aContact, getter_AddRefs(iccContact)); if (NS_FAILED(rv)) { aRv.Throw(rv); return nullptr; } rv = mHandler->UpdateContact(static_cast(aContactType), iccContact, aPin2, requestCallback); if (NS_FAILED(rv)) { aRv.Throw(rv); return nullptr; } return request.forget(); } already_AddRefed Icc::MatchMvno(IccMvnoType aMvnoType, const nsAString& aMvnoData, ErrorResult& aRv) { if (!mHandler) { aRv.Throw(NS_ERROR_FAILURE); return nullptr; } nsRefPtr request = new DOMRequest(GetOwner()); nsRefPtr requestCallback = new IccCallback(GetOwner(), request); nsresult rv = mHandler->MatchMvno(static_cast(aMvnoType), aMvnoData, requestCallback); if (NS_FAILED(rv)) { aRv.Throw(rv); return nullptr; } return request.forget(); } already_AddRefed Icc::GetServiceState(IccService aService, ErrorResult& aRv) { if (!mHandler) { aRv.Throw(NS_ERROR_FAILURE); return nullptr; } nsCOMPtr global = do_QueryInterface(GetOwner()); if (!global) { return nullptr; } nsRefPtr promise = Promise::Create(global, aRv); if (aRv.Failed()) { return nullptr; } nsRefPtr requestCallback = new IccCallback(GetOwner(), promise); nsresult rv = mHandler->GetServiceStateEnabled(static_cast(aService), requestCallback); if (NS_FAILED(rv)) { promise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR); // fall-through to return promise. } return promise.forget(); } } // namespace dom } // namespace mozilla