dom/voicemail/Voicemail.cpp
author Ted Mielczarek <ted@mielczarek.org>
Fri, 18 Jul 2014 16:33:34 -0400
changeset 196190 a660ebbe6ff97b428c78f5f4e5921b094e57afb1
parent 194892 e8ad29f1166a523e727ff6fd297aa9eaf85e5eed
child 200537 fe06c48beccdd9f1f1cec8db7971c5f51c63c8f9
permissions -rw-r--r--
bug 462159 - Use install manifests to track header files from dist/include back to srcdir in symbolstore.py. r=gps

/* -*- 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 "Voicemail.h"

#include "mozilla/dom/MozVoicemailBinding.h"
#include "mozilla/dom/MozVoicemailEvent.h"
#include "mozilla/dom/MozVoicemailStatusBinding.h"

#include "mozilla/Preferences.h"
#include "mozilla/Services.h"
#include "nsContentUtils.h"
#include "nsDOMClassInfo.h"
#include "nsServiceManagerUtils.h"

#define NS_RILCONTENTHELPER_CONTRACTID "@mozilla.org/ril/content-helper;1"
const char* kPrefRilNumRadioInterfaces = "ril.numRadioInterfaces";

using namespace mozilla::dom;

class Voicemail::Listener MOZ_FINAL : public nsIVoicemailListener
{
  Voicemail* mVoicemail;

public:
  NS_DECL_ISUPPORTS
  NS_FORWARD_SAFE_NSIVOICEMAILLISTENER(mVoicemail)

  Listener(Voicemail* aVoicemail)
    : mVoicemail(aVoicemail)
  {
    MOZ_ASSERT(mVoicemail);
  }

  void Disconnect()
  {
    MOZ_ASSERT(mVoicemail);
    mVoicemail = nullptr;
  }

private:
  ~Listener()
  {
    MOZ_ASSERT(!mVoicemail);
  }
};

NS_IMPL_ISUPPORTS(Voicemail::Listener, nsIVoicemailListener)

Voicemail::Voicemail(nsPIDOMWindow* aWindow,
                     nsIVoicemailProvider* aProvider)
  : DOMEventTargetHelper(aWindow)
  , mProvider(aProvider)
{
  mListener = new Listener(this);
  DebugOnly<nsresult> rv = mProvider->RegisterVoicemailMsg(mListener);
  NS_WARN_IF_FALSE(NS_SUCCEEDED(rv),
                   "Failed registering voicemail messages with provider");
}

Voicemail::~Voicemail()
{
  MOZ_ASSERT(mProvider && mListener);

  mListener->Disconnect();
  mProvider->UnregisterVoicemailMsg(mListener);
}

JSObject*
Voicemail::WrapObject(JSContext* aCx)
{
  return MozVoicemailBinding::Wrap(aCx, this);
}

bool
Voicemail::IsValidServiceId(uint32_t aServiceId) const
{
  uint32_t numClients = mozilla::Preferences::GetUint(kPrefRilNumRadioInterfaces, 1);

  return aServiceId < numClients;
}

bool
Voicemail::PassedOrDefaultServiceId(const Optional<uint32_t>& aServiceId,
                                    uint32_t& aResult) const
{
  if (aServiceId.WasPassed()) {
    if (!IsValidServiceId(aServiceId.Value())) {
      return false;
    }
    aResult = aServiceId.Value();
  } else {
    mProvider->GetVoicemailDefaultServiceId(&aResult);
  }

  return true;
}

// MozVoicemail WebIDL

already_AddRefed<MozVoicemailStatus>
Voicemail::GetStatus(const Optional<uint32_t>& aServiceId,
                     ErrorResult& aRv) const
{
  if (!mProvider) {
    aRv.Throw(NS_ERROR_UNEXPECTED);
    return nullptr;
  }

  uint32_t id = 0;
  if (!PassedOrDefaultServiceId(aServiceId, id)) {
    aRv.Throw(NS_ERROR_INVALID_ARG);
    return nullptr;
  }
  JSContext *cx = nsContentUtils::GetCurrentJSContext();
  JS::Rooted<JS::Value> status(cx);
  nsresult rv = mProvider->GetVoicemailStatus(id, &status);
  if (NS_FAILED(rv)) {
    aRv.Throw(rv);
    return nullptr;
  }
  if (!status.isObject()) {
    aRv.Throw(NS_ERROR_UNEXPECTED);
    return nullptr;
  }
  JS::Rooted<JSObject*> statusObj(cx, &status.toObject());
  nsRefPtr<MozVoicemailStatus> res = new MozVoicemailStatus(statusObj, GetParentObject());
  return res.forget();
}

void
Voicemail::GetNumber(const Optional<uint32_t>& aServiceId, nsString& aNumber,
                     ErrorResult& aRv) const
{
  aNumber.SetIsVoid(true);

  if (!mProvider) {
    aRv.Throw(NS_ERROR_UNEXPECTED);
    return;
  }

  uint32_t id = 0;
  if (!PassedOrDefaultServiceId(aServiceId, id)) {
    aRv.Throw(NS_ERROR_INVALID_ARG);
    return;
  }

  aRv = mProvider->GetVoicemailNumber(id, aNumber);
}

void
Voicemail::GetDisplayName(const Optional<uint32_t>& aServiceId, nsString& aDisplayName,
                          ErrorResult& aRv) const
{
  aDisplayName.SetIsVoid(true);

  if (!mProvider) {
    aRv.Throw(NS_ERROR_UNEXPECTED);
    return;
  }

  uint32_t id = 0;
  if (!PassedOrDefaultServiceId(aServiceId, id)) {
    aRv.Throw(NS_ERROR_INVALID_ARG);
    return;
  }

  aRv = mProvider->GetVoicemailDisplayName(id, aDisplayName);
}

// nsIVoicemailListener

NS_IMETHODIMP
Voicemail::NotifyStatusChanged(JS::HandleValue aStatus)
{
  MozVoicemailEventInit init;
  init.mBubbles = false;
  init.mCancelable = false;
  if (aStatus.isObject()) {
    JSContext *cx = nsContentUtils::GetCurrentJSContext();
    JS::Rooted<JSObject*> statusObj(cx, &aStatus.toObject());
    init.mStatus = new MozVoicemailStatus(statusObj, GetParentObject());
  }

  nsRefPtr<MozVoicemailEvent> event =
    MozVoicemailEvent::Constructor(this, NS_LITERAL_STRING("statuschanged"), init);
  return DispatchTrustedEvent(event);
}

nsresult
NS_NewVoicemail(nsPIDOMWindow* aWindow, Voicemail** aVoicemail)
{
  nsPIDOMWindow* innerWindow = aWindow->IsInnerWindow() ?
    aWindow :
    aWindow->GetCurrentInnerWindow();

  nsCOMPtr<nsIVoicemailProvider> provider =
    do_GetService(NS_RILCONTENTHELPER_CONTRACTID);
  NS_ENSURE_STATE(provider);

  nsRefPtr<Voicemail> voicemail = new Voicemail(innerWindow, provider);
  voicemail.forget(aVoicemail);
  return NS_OK;
}