blob: cfe4219cd4b603cdf50146883ff2b782aacb53a6 [file] [log] [blame]
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chromeos/network/network_sms_handler.h"
#include <string>
#include "base/bind.h"
#include "chromeos/dbus/dbus_thread_manager.h"
#include "chromeos/dbus/flimflam_device_client.h"
#include "chromeos/dbus/flimflam_manager_client.h"
#include "chromeos/dbus/gsm_sms_client.h"
#include "dbus/object_path.h"
#include "third_party/cros_system_api/dbus/service_constants.h"
// Not exposed/exported.
namespace {
const char kSmscKey[] = "smsc";
const char kValidityKey[] = "validity";
const char kClassKey[] = "class";
const char kIndexKey[] = "index";
} // namespace
namespace chromeos {
// static
const char NetworkSmsHandler::kNumberKey[] = "number";
const char NetworkSmsHandler::kTextKey[] = "text";
const char NetworkSmsHandler::kTimestampKey[] = "timestamp";
class NetworkSmsHandler::NetworkSmsDeviceHandler {
public:
NetworkSmsDeviceHandler(NetworkSmsHandler* host,
std::string dbus_connection,
dbus::ObjectPath object_path);
void RequestUpdate();
private:
void ListCallback(const base::ListValue& message_list);
void SmsReceivedCallback(uint32 index, bool complete);
void GetCallback(uint32 index, const base::DictionaryValue& dictionary);
void DeleteMessages();
void NotifyMessageReceived(const base::DictionaryValue& dictionary);
NetworkSmsHandler* host_;
std::string dbus_connection_;
dbus::ObjectPath object_path_;
bool deleting_messages_;
base::WeakPtrFactory<NetworkSmsDeviceHandler> weak_ptr_factory_;
std::vector<uint32> delete_queue_;
DISALLOW_COPY_AND_ASSIGN(NetworkSmsDeviceHandler);
};
NetworkSmsHandler::NetworkSmsDeviceHandler::NetworkSmsDeviceHandler(
NetworkSmsHandler* host,
std::string dbus_connection,
dbus::ObjectPath object_path)
: host_(host),
dbus_connection_(dbus_connection),
object_path_(object_path),
deleting_messages_(false),
weak_ptr_factory_(this) {
// Set the handler for received Sms messaages.
DBusThreadManager::Get()->GetGsmSMSClient()->SetSmsReceivedHandler(
dbus_connection_, object_path_,
base::Bind(&NetworkSmsDeviceHandler::SmsReceivedCallback,
weak_ptr_factory_.GetWeakPtr()));
// List the existing messages.
DBusThreadManager::Get()->GetGsmSMSClient()->List(
dbus_connection_, object_path_,
base::Bind(&NetworkSmsDeviceHandler::ListCallback,
weak_ptr_factory_.GetWeakPtr()));
}
void NetworkSmsHandler::NetworkSmsDeviceHandler::RequestUpdate() {
DBusThreadManager::Get()->GetGsmSMSClient()->RequestUpdate(
dbus_connection_, object_path_);
}
void NetworkSmsHandler::NetworkSmsDeviceHandler::ListCallback(
const base::ListValue& message_list) {
// This receives all messages, so clear any pending deletes.
delete_queue_.clear();
for (base::ListValue::const_iterator iter = message_list.begin();
iter != message_list.end(); ++iter) {
base::DictionaryValue* message = NULL;
if (!(*iter)->GetAsDictionary(&message))
continue;
NotifyMessageReceived(*message);
double index = 0;
if (message->GetDoubleWithoutPathExpansion(kIndexKey, &index))
delete_queue_.push_back(static_cast<uint32>(index));
}
DeleteMessages();
}
// Messages must be deleted one at a time, since we can not gaurantee the order
// the deletion will be executed in. Delete messages from the back of the list
// so that the indices are valid.
void NetworkSmsHandler::NetworkSmsDeviceHandler::DeleteMessages() {
if (delete_queue_.empty()) {
deleting_messages_ = false;
return;
}
deleting_messages_ = true;
uint32 index = delete_queue_.back();
delete_queue_.pop_back();
DBusThreadManager::Get()->GetGsmSMSClient()->Delete(
dbus_connection_, object_path_, index,
base::Bind(&NetworkSmsDeviceHandler::DeleteMessages,
weak_ptr_factory_.GetWeakPtr()));
}
void NetworkSmsHandler::NetworkSmsDeviceHandler::SmsReceivedCallback(
uint32 index,
bool complete) {
// Only handle complete messages.
if (!complete)
return;
DBusThreadManager::Get()->GetGsmSMSClient()->Get(
dbus_connection_, object_path_, index,
base::Bind(&NetworkSmsDeviceHandler::GetCallback,
weak_ptr_factory_.GetWeakPtr(), index));
}
void NetworkSmsHandler::NetworkSmsDeviceHandler::GetCallback(
uint32 index,
const base::DictionaryValue& dictionary) {
NotifyMessageReceived(dictionary);
delete_queue_.push_back(index);
if (!deleting_messages_)
DeleteMessages();
}
void NetworkSmsHandler::NetworkSmsDeviceHandler::NotifyMessageReceived(
const base::DictionaryValue& dictionary) {
host_->NotifyMessageReceived(dictionary);
}
///////////////////////////////////////////////////////////////////////////////
// NetworkSmsHandler
NetworkSmsHandler::NetworkSmsHandler()
: weak_ptr_factory_(this) {
}
NetworkSmsHandler::~NetworkSmsHandler() {
}
void NetworkSmsHandler::Init() {
// Request network manager properties so that we can get the list of devices.
DBusThreadManager::Get()->GetFlimflamManagerClient()->GetProperties(
base::Bind(&NetworkSmsHandler::ManagerPropertiesCallback,
weak_ptr_factory_.GetWeakPtr()));
}
void NetworkSmsHandler::RequestUpdate() {
for (ScopedVector<NetworkSmsDeviceHandler>::iterator iter =
device_handlers_.begin(); iter != device_handlers_.end(); ++iter) {
(*iter)->RequestUpdate();
}
}
void NetworkSmsHandler::AddObserver(Observer* observer) {
observers_.AddObserver(observer);
}
void NetworkSmsHandler::RemoveObserver(Observer* observer) {
observers_.RemoveObserver(observer);
}
void NetworkSmsHandler::NotifyMessageReceived(
const base::DictionaryValue& message) {
FOR_EACH_OBSERVER(Observer, observers_, MessageReceived(message));
}
void NetworkSmsHandler::ManagerPropertiesCallback(
DBusMethodCallStatus call_status,
const base::DictionaryValue& properties) {
if (call_status != DBUS_METHOD_CALL_SUCCESS) {
LOG(ERROR) << "NetworkSmsHandler: Failed to get manager properties.";
return;
}
base::Value* value;
if (!properties.GetWithoutPathExpansion(flimflam::kDevicesProperty, &value) ||
value->GetType() != base::Value::TYPE_LIST) {
LOG(ERROR) << "NetworkSmsDeviceHandler: No list value for: "
<< flimflam::kDevicesProperty;
return;
}
const base::ListValue* devices = static_cast<const base::ListValue*>(value);
for (base::ListValue::const_iterator iter = devices->begin();
iter != devices->end(); ++iter) {
std::string device_path;
(*iter)->GetAsString(&device_path);
if (!device_path.empty()) {
// Request device properties.
DBusThreadManager::Get()->GetFlimflamDeviceClient()->GetProperties(
dbus::ObjectPath(device_path),
base::Bind(&NetworkSmsHandler::DevicePropertiesCallback,
weak_ptr_factory_.GetWeakPtr(),
device_path));
}
}
}
void NetworkSmsHandler::DevicePropertiesCallback(
const std::string& device_path,
DBusMethodCallStatus call_status,
const base::DictionaryValue& properties) {
if (call_status != DBUS_METHOD_CALL_SUCCESS)
return;
std::string device_type;
if (!properties.GetStringWithoutPathExpansion(
flimflam::kTypeProperty, &device_type)) {
LOG(ERROR) << "NetworkSmsDeviceHandler: No type for: " << device_path;
return;
}
if (device_type != flimflam::kTypeCellular)
return;
std::string dbus_connection;
if (!properties.GetStringWithoutPathExpansion(
flimflam::kDBusConnectionProperty, &dbus_connection)) {
LOG(ERROR) << "Device has no DBusConnection Property: " << device_path;
return;
}
std::string object_path_string;
if (!properties.GetStringWithoutPathExpansion(
flimflam::kDBusObjectProperty, &object_path_string)) {
LOG(ERROR) << "Device has no DBusObject Property: " << device_path;
return;
}
dbus::ObjectPath object_path(object_path_string);
device_handlers_.push_back(
new NetworkSmsDeviceHandler(this, dbus_connection, object_path));
}
} // namespace chromeos