| Index: chrome/browser/chromeos/cros/sms_watcher.cc
|
| diff --git a/chrome/browser/chromeos/cros/sms_watcher.cc b/chrome/browser/chromeos/cros/sms_watcher.cc
|
| index 8a81091866e2e3f8d34e30d93ef815aeb682297c..d7327d07a01f3a807720ebc5ab7cb8c3ea7e6875 100644
|
| --- a/chrome/browser/chromeos/cros/sms_watcher.cc
|
| +++ b/chrome/browser/chromeos/cros/sms_watcher.cc
|
| @@ -4,11 +4,18 @@
|
|
|
| #include "chrome/browser/chromeos/cros/sms_watcher.h"
|
|
|
| +#include <algorithm>
|
| +#include <deque>
|
| +#include <string>
|
| +#include <vector>
|
| +
|
| #include "base/bind.h"
|
| #include "base/values.h"
|
| #include "chromeos/dbus/dbus_thread_manager.h"
|
| #include "chromeos/dbus/flimflam_device_client.h"
|
| #include "chromeos/dbus/gsm_sms_client.h"
|
| +#include "chromeos/dbus/modem_messaging_client.h"
|
| +#include "chromeos/dbus/sms_client.h"
|
| #include "third_party/cros_system_api/dbus/service_constants.h"
|
|
|
| namespace chromeos {
|
| @@ -19,6 +26,26 @@ int decode_bcd(const char *s) {
|
| return (s[0] - '0') * 10 + s[1] - '0';
|
| }
|
|
|
| +void decode_timestamp(const std::string& sms_timestamp, SMS *sms) {
|
| + base::Time::Exploded exp;
|
| + exp.year = decode_bcd(&sms_timestamp[0]);
|
| + if (exp.year > 95)
|
| + exp.year += 1900;
|
| + else
|
| + exp.year += 2000;
|
| + exp.month = decode_bcd(&sms_timestamp[2]);
|
| + exp.day_of_month = decode_bcd(&sms_timestamp[4]);
|
| + exp.hour = decode_bcd(&sms_timestamp[6]);
|
| + exp.minute = decode_bcd(&sms_timestamp[8]);
|
| + exp.second = decode_bcd(&sms_timestamp[10]);
|
| + exp.millisecond = 0;
|
| + sms->timestamp = base::Time::FromUTCExploded(exp);
|
| + int hours = decode_bcd(&sms_timestamp[13]);
|
| + if (sms_timestamp[12] == '-')
|
| + hours = -hours;
|
| + sms->timestamp -= base::TimeDelta::FromHours(hours);
|
| +}
|
| +
|
| // Callback for Delete() method. This method does nothing.
|
| void DeleteSMSCallback() {}
|
|
|
| @@ -32,6 +59,335 @@ const char SMSWatcher::kValidityKey[] = "validity";
|
| const char SMSWatcher::kClassKey[] = "class";
|
| const char SMSWatcher::kIndexKey[] = "index";
|
|
|
| +const char SMSWatcher::kModemManager1NumberKey[] = "Number";
|
| +const char SMSWatcher::kModemManager1TextKey[] = "Text";
|
| +const char SMSWatcher::kModemManager1TimestampKey[] = "Timestamp";
|
| +const char SMSWatcher::kModemManager1SmscKey[] = "Smsc";
|
| +const char SMSWatcher::kModemManager1ValidityKey[] = "Validity";
|
| +const char SMSWatcher::kModemManager1ClassKey[] = "Class";
|
| +const char SMSWatcher::kModemManager1IndexKey[] = "Index";
|
| +
|
| +class SMSWatcher::WatcherBase {
|
| + public:
|
| + WatcherBase(const std::string& device_path,
|
| + MonitorSMSCallback callback,
|
| + void* object,
|
| + const std::string& dbus_connection,
|
| + const dbus::ObjectPath& object_path) :
|
| + device_path_(device_path),
|
| + callback_(callback),
|
| + object_(object),
|
| + dbus_connection_(dbus_connection),
|
| + object_path_(object_path) {}
|
| +
|
| + virtual ~WatcherBase() {}
|
| +
|
| + protected:
|
| + const std::string device_path_;
|
| + MonitorSMSCallback callback_;
|
| + void* object_;
|
| + const std::string dbus_connection_;
|
| + const dbus::ObjectPath object_path_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(WatcherBase);
|
| +};
|
| +
|
| +namespace {
|
| +
|
| +class GsmWatcher : public SMSWatcher::WatcherBase {
|
| + public:
|
| + GsmWatcher(const std::string& device_path,
|
| + MonitorSMSCallback callback,
|
| + void* object,
|
| + const std::string& dbus_connection,
|
| + const dbus::ObjectPath& object_path)
|
| + : WatcherBase(device_path, callback, object, dbus_connection,
|
| + object_path),
|
| + weak_ptr_factory_(this) {
|
| + DBusThreadManager::Get()->GetGsmSMSClient()->SetSmsReceivedHandler(
|
| + dbus_connection_,
|
| + object_path_,
|
| + base::Bind(&GsmWatcher::OnSmsReceived, weak_ptr_factory_.GetWeakPtr()));
|
| +
|
| + DBusThreadManager::Get()->GetGsmSMSClient()->List(
|
| + dbus_connection_, object_path_,
|
| + base::Bind(&GsmWatcher::ListSMSCallback,
|
| + weak_ptr_factory_.GetWeakPtr()));
|
| + }
|
| +
|
| + virtual ~GsmWatcher() {
|
| + DBusThreadManager::Get()->GetGsmSMSClient()->ResetSmsReceivedHandler(
|
| + dbus_connection_, object_path_);
|
| + }
|
| +
|
| + private:
|
| + // Callback for SmsReceived signal from ModemManager.Modem.Gsm.SMS
|
| + void OnSmsReceived(uint32 index, bool complete) {
|
| + // Only handle complete messages.
|
| + if (!complete)
|
| + return;
|
| + DBusThreadManager::Get()->GetGsmSMSClient()->Get(
|
| + dbus_connection_, object_path_, index,
|
| + base::Bind(&GsmWatcher::GetSMSCallback,
|
| + weak_ptr_factory_.GetWeakPtr(),
|
| + index));
|
| + }
|
| +
|
| + // Runs |callback_| with a SMS.
|
| + void RunCallbackWithSMS(const base::DictionaryValue& sms_dictionary) {
|
| + SMS sms;
|
| +
|
| + std::string number;
|
| + if (!sms_dictionary.GetStringWithoutPathExpansion(SMSWatcher::kNumberKey,
|
| + &number)) {
|
| + LOG(WARNING) << "SMS did not contain a number";
|
| + }
|
| + sms.number = number.c_str();
|
| +
|
| + std::string text;
|
| + if (!sms_dictionary.GetStringWithoutPathExpansion(SMSWatcher::kTextKey,
|
| + &text)) {
|
| + LOG(WARNING) << "SMS did not contain message text";
|
| + }
|
| + sms.text = text.c_str();
|
| +
|
| + std::string sms_timestamp;
|
| + if (sms_dictionary.GetStringWithoutPathExpansion(SMSWatcher::kTimestampKey,
|
| + &sms_timestamp)) {
|
| + decode_timestamp(sms_timestamp, &sms);
|
| + } else {
|
| + LOG(WARNING) << "SMS did not contain a timestamp";
|
| + sms.timestamp = base::Time();
|
| + }
|
| +
|
| + std::string smsc;
|
| + if (!sms_dictionary.GetStringWithoutPathExpansion(SMSWatcher::kSmscKey,
|
| + &smsc)) {
|
| + sms.smsc = NULL;
|
| + } else {
|
| + sms.smsc = smsc.c_str();
|
| + }
|
| +
|
| + double validity = 0;
|
| + if (!sms_dictionary.GetDoubleWithoutPathExpansion(SMSWatcher::kValidityKey,
|
| + &validity)) {
|
| + validity = -1;
|
| + }
|
| + sms.validity = validity;
|
| +
|
| + double msgclass = 0;
|
| + if (!sms_dictionary.GetDoubleWithoutPathExpansion(SMSWatcher::kClassKey,
|
| + &msgclass)) {
|
| + msgclass = -1;
|
| + }
|
| + sms.msgclass = msgclass;
|
| +
|
| + callback_(object_, device_path_.c_str(), &sms);
|
| + }
|
| +
|
| + // Callback for Get() method from ModemManager.Modem.Gsm.SMS
|
| + void GetSMSCallback(uint32 index,
|
| + const base::DictionaryValue& sms_dictionary) {
|
| + RunCallbackWithSMS(sms_dictionary);
|
| +
|
| + DBusThreadManager::Get()->GetGsmSMSClient()->Delete(
|
| + dbus_connection_, object_path_, index, base::Bind(&DeleteSMSCallback));
|
| + }
|
| +
|
| + // Callback for List() method.
|
| + void ListSMSCallback(const base::ListValue& result) {
|
| + // List() is called only once; no one touches delete_queue_ before List().
|
| + CHECK(delete_queue_.empty());
|
| + for (size_t i = 0; i != result.GetSize(); ++i) {
|
| + base::DictionaryValue* sms_dictionary = NULL;
|
| + if (!result.GetDictionary(i, &sms_dictionary)) {
|
| + LOG(ERROR) << "result[" << i << "] is not a dictionary.";
|
| + continue;
|
| + }
|
| + RunCallbackWithSMS(*sms_dictionary);
|
| + double index = 0;
|
| + if (sms_dictionary->GetDoubleWithoutPathExpansion(SMSWatcher::kIndexKey,
|
| + &index)) {
|
| + delete_queue_.push_back(index);
|
| + }
|
| + }
|
| + DeleteSMSInChain();
|
| + }
|
| +
|
| + // Deletes SMSs in the queue.
|
| + void DeleteSMSInChain() {
|
| + if (!delete_queue_.empty()) {
|
| + DBusThreadManager::Get()->GetGsmSMSClient()->Delete(
|
| + dbus_connection_, object_path_, delete_queue_.back(),
|
| + base::Bind(&GsmWatcher::DeleteSMSInChain,
|
| + weak_ptr_factory_.GetWeakPtr()));
|
| + delete_queue_.pop_back();
|
| + }
|
| + }
|
| +
|
| + base::WeakPtrFactory<GsmWatcher> weak_ptr_factory_;
|
| + std::vector<uint32> delete_queue_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(GsmWatcher);
|
| +};
|
| +
|
| +class ModemManager1Watcher : public SMSWatcher::WatcherBase {
|
| + public:
|
| + ModemManager1Watcher(const std::string& device_path,
|
| + MonitorSMSCallback callback,
|
| + void *object,
|
| + const std::string& dbus_connection,
|
| + const dbus::ObjectPath& object_path)
|
| + : WatcherBase(device_path, callback, object, dbus_connection,
|
| + object_path),
|
| + weak_ptr_factory_(this),
|
| + deleting_messages_(false),
|
| + retrieving_messages_(false) {
|
| + DBusThreadManager::Get()->GetModemMessagingClient()->SetSmsReceivedHandler(
|
| + dbus_connection_,
|
| + object_path_,
|
| + base::Bind(&ModemManager1Watcher::OnSmsReceived,
|
| + weak_ptr_factory_.GetWeakPtr()));
|
| +
|
| + DBusThreadManager::Get()->GetModemMessagingClient()->List(
|
| + dbus_connection_, object_path_,
|
| + base::Bind(&ModemManager1Watcher::ListSMSCallback,
|
| + weak_ptr_factory_.GetWeakPtr()));
|
| + }
|
| +
|
| + virtual ~ModemManager1Watcher() {
|
| + DBusThreadManager::Get()->GetModemMessagingClient()
|
| + ->ResetSmsReceivedHandler(dbus_connection_, object_path_);
|
| + }
|
| +
|
| + private:
|
| + void ListSMSCallback(
|
| + const std::vector<dbus::ObjectPath>& paths) {
|
| + // This receives all messages, so clear any pending gets and deletes.
|
| + retrieval_queue_.clear();
|
| + delete_queue_.clear();
|
| +
|
| + retrieval_queue_.resize(paths.size());
|
| + std::copy(paths.begin(), paths.end(), retrieval_queue_.begin());
|
| + if (!retrieving_messages_)
|
| + GetMessages();
|
| + }
|
| +
|
| + // Messages must be deleted one at a time, since we can not
|
| + // guarantee the order the deletion will be executed in. Delete
|
| + // messages from the back of the list so that the indices are
|
| + // valid.
|
| + void DeleteMessages() {
|
| + if (delete_queue_.empty()) {
|
| + deleting_messages_ = false;
|
| + return;
|
| + }
|
| + deleting_messages_ = true;
|
| + dbus::ObjectPath sms_path = delete_queue_.back();
|
| + delete_queue_.pop_back();
|
| + DBusThreadManager::Get()->GetModemMessagingClient()->Delete(
|
| + dbus_connection_, object_path_, sms_path,
|
| + base::Bind(&ModemManager1Watcher::DeleteMessages,
|
| + weak_ptr_factory_.GetWeakPtr()));
|
| + }
|
| +
|
| + // Messages must be fetched one at a time, so that we do not queue too
|
| + // many requests to a single threaded server.
|
| + void GetMessages() {
|
| + if (retrieval_queue_.empty()) {
|
| + retrieving_messages_ = false;
|
| + if (!deleting_messages_)
|
| + DeleteMessages();
|
| + return;
|
| + }
|
| + retrieving_messages_ = true;
|
| + dbus::ObjectPath sms_path = retrieval_queue_.front();
|
| + retrieval_queue_.pop_front();
|
| + DBusThreadManager::Get()->GetSMSClient()->GetAll(
|
| + dbus_connection_, sms_path,
|
| + base::Bind(&ModemManager1Watcher::GetCallback,
|
| + weak_ptr_factory_.GetWeakPtr()));
|
| + delete_queue_.push_back(sms_path);
|
| + }
|
| +
|
| + // Handles arrival of a new SMS message.
|
| + void OnSmsReceived(const dbus::ObjectPath& sms_path, bool complete) {
|
| + // Only handle complete messages.
|
| + if (!complete)
|
| + return;
|
| + retrieval_queue_.push_back(sms_path);
|
| + if (!retrieving_messages_)
|
| + GetMessages();
|
| + }
|
| +
|
| + // Runs |callback_| with a SMS.
|
| + void RunCallbackWithSMS(const base::DictionaryValue& sms_dictionary) {
|
| + SMS sms;
|
| +
|
| + std::string number;
|
| + if (!sms_dictionary.GetStringWithoutPathExpansion(
|
| + SMSWatcher::kModemManager1NumberKey, &number)) {
|
| + LOG(WARNING) << "SMS did not contain a number";
|
| + }
|
| + sms.number = number.c_str();
|
| +
|
| + std::string text;
|
| + if (!sms_dictionary.GetStringWithoutPathExpansion(
|
| + SMSWatcher::kModemManager1TextKey, &text)) {
|
| + LOG(WARNING) << "SMS did not contain message text";
|
| + }
|
| + sms.text = text.c_str();
|
| +
|
| + std::string sms_timestamp;
|
| + if (sms_dictionary.GetStringWithoutPathExpansion(
|
| + SMSWatcher::kModemManager1TimestampKey, &sms_timestamp)) {
|
| + decode_timestamp(sms_timestamp, &sms);
|
| + } else {
|
| + LOG(WARNING) << "SMS did not contain a timestamp";
|
| + sms.timestamp = base::Time();
|
| + }
|
| +
|
| + std::string smsc;
|
| + if (!sms_dictionary.GetStringWithoutPathExpansion(
|
| + SMSWatcher::kModemManager1SmscKey, &smsc)) {
|
| + sms.smsc = NULL;
|
| + } else {
|
| + sms.smsc = smsc.c_str();
|
| + }
|
| +
|
| + double validity = 0;
|
| + if (!sms_dictionary.GetDoubleWithoutPathExpansion(
|
| + SMSWatcher::kModemManager1ValidityKey, &validity)) {
|
| + validity = -1;
|
| + }
|
| + sms.validity = validity;
|
| +
|
| + double msgclass = 0;
|
| + if (!sms_dictionary.GetDoubleWithoutPathExpansion(
|
| + SMSWatcher::kModemManager1ClassKey, &msgclass)) {
|
| + msgclass = -1;
|
| + }
|
| + sms.msgclass = msgclass;
|
| +
|
| + callback_(object_, device_path_.c_str(), &sms);
|
| + }
|
| +
|
| + void GetCallback(const base::DictionaryValue& dictionary) {
|
| + RunCallbackWithSMS(dictionary);
|
| + GetMessages();
|
| + }
|
| +
|
| + base::WeakPtrFactory<ModemManager1Watcher> weak_ptr_factory_;
|
| + bool deleting_messages_;
|
| + bool retrieving_messages_;
|
| + std::vector<dbus::ObjectPath> delete_queue_;
|
| + std::deque<dbus::ObjectPath> retrieval_queue_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(ModemManager1Watcher);
|
| +};
|
| +
|
| +} // namespace
|
| +
|
| SMSWatcher::SMSWatcher(const std::string& modem_device_path,
|
| MonitorSMSCallback callback,
|
| void* object)
|
| @@ -46,10 +402,6 @@ SMSWatcher::SMSWatcher(const std::string& modem_device_path,
|
| }
|
|
|
| SMSWatcher::~SMSWatcher() {
|
| - if (!dbus_connection_.empty() && !object_path_.value().empty()) {
|
| - DBusThreadManager::Get()->GetGsmSMSClient()->ResetSmsReceivedHandler(
|
| - dbus_connection_, object_path_);
|
| - }
|
| }
|
|
|
| void SMSWatcher::DevicePropertiesCallback(
|
| @@ -58,8 +410,9 @@ void SMSWatcher::DevicePropertiesCallback(
|
| if (call_status != DBUS_METHOD_CALL_SUCCESS)
|
| return;
|
|
|
| + std::string dbus_connection;
|
| if (!properties.GetStringWithoutPathExpansion(
|
| - flimflam::kDBusConnectionProperty, &dbus_connection_)) {
|
| + flimflam::kDBusConnectionProperty, &dbus_connection)) {
|
| LOG(WARNING) << "Modem device properties do not include DBus connection.";
|
| return;
|
| }
|
| @@ -70,121 +423,19 @@ void SMSWatcher::DevicePropertiesCallback(
|
| LOG(WARNING) << "Modem device properties do not include DBus object.";
|
| return;
|
| }
|
| - object_path_ = dbus::ObjectPath(object_path_string);
|
|
|
| - DBusThreadManager::Get()->GetGsmSMSClient()->SetSmsReceivedHandler(
|
| - dbus_connection_,
|
| - object_path_,
|
| - base::Bind(&SMSWatcher::OnSmsReceived, weak_ptr_factory_.GetWeakPtr()));
|
| -
|
| - DBusThreadManager::Get()->GetGsmSMSClient()->List(
|
| - dbus_connection_, object_path_,
|
| - base::Bind(&SMSWatcher::ListSMSCallback,
|
| - weak_ptr_factory_.GetWeakPtr()));
|
| -}
|
| -
|
| -void SMSWatcher::OnSmsReceived(uint32 index, bool complete) {
|
| - // Only handle complete messages.
|
| - if (!complete)
|
| - return;
|
| - DBusThreadManager::Get()->GetGsmSMSClient()->Get(
|
| - dbus_connection_, object_path_, index,
|
| - base::Bind(&SMSWatcher::GetSMSCallback,
|
| - weak_ptr_factory_.GetWeakPtr(),
|
| - index));
|
| -}
|
| -
|
| -void SMSWatcher::RunCallbackWithSMS(
|
| - const base::DictionaryValue& sms_dictionary) {
|
| - SMS sms;
|
| -
|
| - std::string number;
|
| - if (!sms_dictionary.GetStringWithoutPathExpansion(kNumberKey, &number))
|
| - LOG(WARNING) << "SMS did not contain a number";
|
| - sms.number = number.c_str();
|
| -
|
| - std::string text;
|
| - if (!sms_dictionary.GetStringWithoutPathExpansion(kTextKey, &text)) {
|
| - LOG(WARNING) << "SMS did not contain message text";
|
| - }
|
| - sms.text = text.c_str();
|
| -
|
| - std::string sms_timestamp;
|
| - if (sms_dictionary.GetStringWithoutPathExpansion(kTimestampKey,
|
| - &sms_timestamp)) {
|
| - base::Time::Exploded exp;
|
| - exp.year = decode_bcd(&sms_timestamp[0]);
|
| - if (exp.year > 95)
|
| - exp.year += 1900;
|
| - else
|
| - exp.year += 2000;
|
| - exp.month = decode_bcd(&sms_timestamp[2]);
|
| - exp.day_of_month = decode_bcd(&sms_timestamp[4]);
|
| - exp.hour = decode_bcd(&sms_timestamp[6]);
|
| - exp.minute = decode_bcd(&sms_timestamp[8]);
|
| - exp.second = decode_bcd(&sms_timestamp[10]);
|
| - exp.millisecond = 0;
|
| - sms.timestamp = base::Time::FromUTCExploded(exp);
|
| - int hours = decode_bcd(&sms_timestamp[13]);
|
| - if (sms_timestamp[12] == '-')
|
| - hours = -hours;
|
| - sms.timestamp -= base::TimeDelta::FromHours(hours);
|
| + if (object_path_string.compare(
|
| + 0, sizeof(modemmanager::kModemManager1ServicePath) - 1,
|
| + modemmanager::kModemManager1ServicePath) == 0) {
|
| + watcher_.reset(
|
| + new ModemManager1Watcher(device_path_,
|
| + callback_, object_, dbus_connection,
|
| + dbus::ObjectPath(object_path_string)));
|
| } else {
|
| - LOG(WARNING) << "SMS did not contain a timestamp";
|
| - sms.timestamp = base::Time();
|
| - }
|
| -
|
| - std::string smsc;
|
| - if (!sms_dictionary.GetStringWithoutPathExpansion(kSmscKey, &smsc))
|
| - sms.smsc = NULL;
|
| - else
|
| - sms.smsc = smsc.c_str();
|
| -
|
| - double validity = 0;
|
| - if (!sms_dictionary.GetDoubleWithoutPathExpansion(kValidityKey, &validity))
|
| - validity = -1;
|
| - sms.validity = validity;
|
| -
|
| - double msgclass = 0;
|
| - if (!sms_dictionary.GetDoubleWithoutPathExpansion(kClassKey, &msgclass))
|
| - msgclass = -1;
|
| - sms.msgclass = msgclass;
|
| -
|
| - callback_(object_, device_path_.c_str(), &sms);
|
| -}
|
| -
|
| -void SMSWatcher::GetSMSCallback(uint32 index,
|
| - const base::DictionaryValue& sms_dictionary) {
|
| - RunCallbackWithSMS(sms_dictionary);
|
| -
|
| - DBusThreadManager::Get()->GetGsmSMSClient()->Delete(
|
| - dbus_connection_, object_path_, index, base::Bind(&DeleteSMSCallback));
|
| -}
|
| -
|
| -void SMSWatcher::ListSMSCallback(const base::ListValue& result) {
|
| - // List() is called only once and no one touches delete_queue_ before List().
|
| - CHECK(delete_queue_.empty());
|
| - for (size_t i = 0; i != result.GetSize(); ++i) {
|
| - base::DictionaryValue* sms_dictionary = NULL;
|
| - if (!result.GetDictionary(i, &sms_dictionary)) {
|
| - LOG(ERROR) << "result[" << i << "] is not a dictionary.";
|
| - continue;
|
| - }
|
| - RunCallbackWithSMS(*sms_dictionary);
|
| - double index = 0;
|
| - if (sms_dictionary->GetDoubleWithoutPathExpansion(kIndexKey, &index))
|
| - delete_queue_.push_back(index);
|
| - }
|
| - DeleteSMSInChain();
|
| -}
|
| -
|
| -void SMSWatcher::DeleteSMSInChain() {
|
| - if (!delete_queue_.empty()) {
|
| - DBusThreadManager::Get()->GetGsmSMSClient()->Delete(
|
| - dbus_connection_, object_path_, delete_queue_.back(),
|
| - base::Bind(&SMSWatcher::DeleteSMSInChain,
|
| - weak_ptr_factory_.GetWeakPtr()));
|
| - delete_queue_.pop_back();
|
| + watcher_.reset(
|
| + new GsmWatcher(device_path_,
|
| + callback_, object_, dbus_connection,
|
| + dbus::ObjectPath(object_path_string)));
|
| }
|
| }
|
|
|
|
|