Home | History | Annotate | Download | only in network
      1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "chromeos/network/network_sms_handler.h"
      6 
      7 #include <algorithm>
      8 #include <deque>
      9 #include <string>
     10 #include <vector>
     11 
     12 #include "base/bind.h"
     13 #include "base/values.h"
     14 #include "chromeos/dbus/dbus_thread_manager.h"
     15 #include "chromeos/dbus/shill_device_client.h"
     16 #include "chromeos/dbus/shill_manager_client.h"
     17 #include "chromeos/dbus/gsm_sms_client.h"
     18 #include "chromeos/dbus/modem_messaging_client.h"
     19 #include "chromeos/dbus/sms_client.h"
     20 #include "dbus/object_path.h"
     21 #include "third_party/cros_system_api/dbus/service_constants.h"
     22 
     23 namespace {
     24 
     25 // Not exposed/exported:
     26 const char kIndexKey[] = "index";
     27 
     28 // Keys from ModemManager1
     29 const char kModemManager1NumberKey[] = "Number";
     30 const char kModemManager1TextKey[] = "Text";
     31 const char kModemManager1TimestampKey[] = "Timestamp";
     32 
     33 // Maximum number of messages stored for RequestUpdate(true).
     34 const size_t kMaxReceivedMessages = 100;
     35 
     36 }  // namespace
     37 
     38 namespace chromeos {
     39 
     40 // static
     41 const char NetworkSmsHandler::kNumberKey[] = "number";
     42 const char NetworkSmsHandler::kTextKey[] = "text";
     43 const char NetworkSmsHandler::kTimestampKey[] = "timestamp";
     44 
     45 class NetworkSmsHandler::NetworkSmsDeviceHandler {
     46  public:
     47   NetworkSmsDeviceHandler() {}
     48   virtual ~NetworkSmsDeviceHandler() {}
     49 
     50   virtual void RequestUpdate() = 0;
     51 };
     52 
     53 class NetworkSmsHandler::ModemManagerNetworkSmsDeviceHandler
     54     : public NetworkSmsHandler::NetworkSmsDeviceHandler {
     55  public:
     56   ModemManagerNetworkSmsDeviceHandler(NetworkSmsHandler* host,
     57                                       const std::string& service_name,
     58                                       const dbus::ObjectPath& object_path);
     59 
     60   virtual void RequestUpdate() OVERRIDE;
     61 
     62  private:
     63   void ListCallback(const base::ListValue& message_list);
     64   void SmsReceivedCallback(uint32 index, bool complete);
     65   void GetCallback(uint32 index, const base::DictionaryValue& dictionary);
     66   void DeleteMessages();
     67   void MessageReceived(const base::DictionaryValue& dictionary);
     68 
     69   NetworkSmsHandler* host_;
     70   std::string service_name_;
     71   dbus::ObjectPath object_path_;
     72   bool deleting_messages_;
     73   base::WeakPtrFactory<ModemManagerNetworkSmsDeviceHandler> weak_ptr_factory_;
     74   std::vector<uint32> delete_queue_;
     75 
     76   DISALLOW_COPY_AND_ASSIGN(ModemManagerNetworkSmsDeviceHandler);
     77 };
     78 
     79 NetworkSmsHandler::
     80 ModemManagerNetworkSmsDeviceHandler::ModemManagerNetworkSmsDeviceHandler(
     81     NetworkSmsHandler* host,
     82     const std::string& service_name,
     83     const dbus::ObjectPath& object_path)
     84     : host_(host),
     85       service_name_(service_name),
     86       object_path_(object_path),
     87       deleting_messages_(false),
     88       weak_ptr_factory_(this) {
     89   // Set the handler for received Sms messaages.
     90   DBusThreadManager::Get()->GetGsmSMSClient()->SetSmsReceivedHandler(
     91       service_name_, object_path_,
     92       base::Bind(&ModemManagerNetworkSmsDeviceHandler::SmsReceivedCallback,
     93                  weak_ptr_factory_.GetWeakPtr()));
     94 
     95   // List the existing messages.
     96   DBusThreadManager::Get()->GetGsmSMSClient()->List(
     97       service_name_, object_path_,
     98       base::Bind(&NetworkSmsHandler::
     99                  ModemManagerNetworkSmsDeviceHandler::ListCallback,
    100                  weak_ptr_factory_.GetWeakPtr()));
    101 }
    102 
    103 void NetworkSmsHandler::ModemManagerNetworkSmsDeviceHandler::RequestUpdate() {
    104   DBusThreadManager::Get()->GetGsmSMSClient()->RequestUpdate(
    105       service_name_, object_path_);
    106 }
    107 
    108 void NetworkSmsHandler::ModemManagerNetworkSmsDeviceHandler::ListCallback(
    109     const base::ListValue& message_list) {
    110   // This receives all messages, so clear any pending deletes.
    111   delete_queue_.clear();
    112   for (base::ListValue::const_iterator iter = message_list.begin();
    113        iter != message_list.end(); ++iter) {
    114     base::DictionaryValue* message = NULL;
    115     if (!(*iter)->GetAsDictionary(&message))
    116       continue;
    117     MessageReceived(*message);
    118     double index = 0;
    119     if (message->GetDoubleWithoutPathExpansion(kIndexKey, &index))
    120       delete_queue_.push_back(static_cast<uint32>(index));
    121   }
    122   DeleteMessages();
    123 }
    124 
    125 // Messages must be deleted one at a time, since we can not guarantee
    126 // the order the deletion will be executed in. Delete messages from
    127 // the back of the list so that the indices are valid.
    128 void NetworkSmsHandler::ModemManagerNetworkSmsDeviceHandler::DeleteMessages() {
    129   if (delete_queue_.empty()) {
    130     deleting_messages_ = false;
    131     return;
    132   }
    133   deleting_messages_ = true;
    134   uint32 index = delete_queue_.back();
    135   delete_queue_.pop_back();
    136   DBusThreadManager::Get()->GetGsmSMSClient()->Delete(
    137       service_name_, object_path_, index,
    138       base::Bind(&NetworkSmsHandler::
    139                  ModemManagerNetworkSmsDeviceHandler::DeleteMessages,
    140                  weak_ptr_factory_.GetWeakPtr()));
    141 }
    142 
    143 void NetworkSmsHandler::
    144 ModemManagerNetworkSmsDeviceHandler::SmsReceivedCallback(
    145     uint32 index,
    146     bool complete) {
    147   // Only handle complete messages.
    148   if (!complete)
    149     return;
    150   DBusThreadManager::Get()->GetGsmSMSClient()->Get(
    151       service_name_, object_path_, index,
    152       base::Bind(&NetworkSmsHandler::
    153                  ModemManagerNetworkSmsDeviceHandler::GetCallback,
    154                  weak_ptr_factory_.GetWeakPtr(), index));
    155 }
    156 
    157 void NetworkSmsHandler::ModemManagerNetworkSmsDeviceHandler::GetCallback(
    158     uint32 index,
    159     const base::DictionaryValue& dictionary) {
    160   MessageReceived(dictionary);
    161   delete_queue_.push_back(index);
    162   if (!deleting_messages_)
    163     DeleteMessages();
    164 }
    165 
    166 void NetworkSmsHandler::
    167 ModemManagerNetworkSmsDeviceHandler::MessageReceived(
    168     const base::DictionaryValue& dictionary) {
    169   // The keys of the ModemManager.Modem.Gsm.SMS interface match the
    170   // exported keys, so the dictionary used as a notification argument
    171   // unchanged.
    172   host_->MessageReceived(dictionary);
    173 }
    174 
    175 class NetworkSmsHandler::ModemManager1NetworkSmsDeviceHandler
    176     : public NetworkSmsHandler::NetworkSmsDeviceHandler {
    177  public:
    178   ModemManager1NetworkSmsDeviceHandler(NetworkSmsHandler* host,
    179                                        const std::string& service_name,
    180                                        const dbus::ObjectPath& object_path);
    181 
    182   virtual void RequestUpdate() OVERRIDE;
    183 
    184  private:
    185   void ListCallback(const std::vector<dbus::ObjectPath>& paths);
    186   void SmsReceivedCallback(const dbus::ObjectPath& path, bool complete);
    187   void GetCallback(const base::DictionaryValue& dictionary);
    188   void DeleteMessages();
    189   void GetMessages();
    190   void MessageReceived(const base::DictionaryValue& dictionary);
    191 
    192   NetworkSmsHandler* host_;
    193   std::string service_name_;
    194   dbus::ObjectPath object_path_;
    195   bool deleting_messages_;
    196   bool retrieving_messages_;
    197   base::WeakPtrFactory<ModemManager1NetworkSmsDeviceHandler> weak_ptr_factory_;
    198   std::vector<dbus::ObjectPath> delete_queue_;
    199   std::deque<dbus::ObjectPath> retrieval_queue_;
    200 
    201   DISALLOW_COPY_AND_ASSIGN(ModemManager1NetworkSmsDeviceHandler);
    202 };
    203 
    204 NetworkSmsHandler::
    205 ModemManager1NetworkSmsDeviceHandler::ModemManager1NetworkSmsDeviceHandler(
    206     NetworkSmsHandler* host,
    207     const std::string& service_name,
    208     const dbus::ObjectPath& object_path)
    209     : host_(host),
    210       service_name_(service_name),
    211       object_path_(object_path),
    212       deleting_messages_(false),
    213       retrieving_messages_(false),
    214       weak_ptr_factory_(this) {
    215   // Set the handler for received Sms messaages.
    216   DBusThreadManager::Get()->GetModemMessagingClient()->SetSmsReceivedHandler(
    217       service_name_, object_path_,
    218       base::Bind(
    219           &NetworkSmsHandler::
    220           ModemManager1NetworkSmsDeviceHandler::SmsReceivedCallback,
    221           weak_ptr_factory_.GetWeakPtr()));
    222 
    223   // List the existing messages.
    224   DBusThreadManager::Get()->GetModemMessagingClient()->List(
    225       service_name_, object_path_,
    226       base::Bind(&NetworkSmsHandler::
    227                  ModemManager1NetworkSmsDeviceHandler::ListCallback,
    228                  weak_ptr_factory_.GetWeakPtr()));
    229 }
    230 
    231 void NetworkSmsHandler::ModemManager1NetworkSmsDeviceHandler::RequestUpdate() {
    232   // Calling List using the service "AddSMS" causes the stub
    233   // implementation to deliver new sms messages.
    234   DBusThreadManager::Get()->GetModemMessagingClient()->List(
    235       std::string("AddSMS"), dbus::ObjectPath("/"),
    236       base::Bind(&NetworkSmsHandler::
    237                  ModemManager1NetworkSmsDeviceHandler::ListCallback,
    238                  weak_ptr_factory_.GetWeakPtr()));
    239 }
    240 
    241 void NetworkSmsHandler::ModemManager1NetworkSmsDeviceHandler::ListCallback(
    242     const std::vector<dbus::ObjectPath>& paths) {
    243   // This receives all messages, so clear any pending gets and deletes.
    244   retrieval_queue_.clear();
    245   delete_queue_.clear();
    246 
    247   retrieval_queue_.resize(paths.size());
    248   std::copy(paths.begin(), paths.end(), retrieval_queue_.begin());
    249   if (!retrieving_messages_)
    250     GetMessages();
    251 }
    252 
    253 // Messages must be deleted one at a time, since we can not guarantee
    254 // the order the deletion will be executed in. Delete messages from
    255 // the back of the list so that the indices are valid.
    256 void NetworkSmsHandler::ModemManager1NetworkSmsDeviceHandler::DeleteMessages() {
    257   if (delete_queue_.empty()) {
    258     deleting_messages_ = false;
    259     return;
    260   }
    261   deleting_messages_ = true;
    262   dbus::ObjectPath sms_path = delete_queue_.back();
    263   delete_queue_.pop_back();
    264   DBusThreadManager::Get()->GetModemMessagingClient()->Delete(
    265       service_name_, object_path_, sms_path,
    266       base::Bind(&NetworkSmsHandler::
    267                  ModemManager1NetworkSmsDeviceHandler::DeleteMessages,
    268                  weak_ptr_factory_.GetWeakPtr()));
    269 }
    270 
    271 // Messages must be fetched one at a time, so that we do not queue too
    272 // many requests to a single threaded server.
    273 void NetworkSmsHandler::ModemManager1NetworkSmsDeviceHandler::GetMessages() {
    274   if (retrieval_queue_.empty()) {
    275     retrieving_messages_ = false;
    276     if (!deleting_messages_)
    277       DeleteMessages();
    278     return;
    279   }
    280   retrieving_messages_ = true;
    281   dbus::ObjectPath sms_path = retrieval_queue_.front();
    282   retrieval_queue_.pop_front();
    283   DBusThreadManager::Get()->GetSMSClient()->GetAll(
    284       service_name_, sms_path,
    285       base::Bind(&NetworkSmsHandler::
    286                  ModemManager1NetworkSmsDeviceHandler::GetCallback,
    287                  weak_ptr_factory_.GetWeakPtr()));
    288   delete_queue_.push_back(sms_path);
    289 }
    290 
    291 void NetworkSmsHandler::
    292 ModemManager1NetworkSmsDeviceHandler::SmsReceivedCallback(
    293     const dbus::ObjectPath& sms_path,
    294     bool complete) {
    295   // Only handle complete messages.
    296   if (!complete)
    297     return;
    298   retrieval_queue_.push_back(sms_path);
    299   if (!retrieving_messages_)
    300     GetMessages();
    301 }
    302 
    303 void NetworkSmsHandler::ModemManager1NetworkSmsDeviceHandler::GetCallback(
    304     const base::DictionaryValue& dictionary) {
    305   MessageReceived(dictionary);
    306   GetMessages();
    307 }
    308 
    309 void NetworkSmsHandler::
    310 ModemManager1NetworkSmsDeviceHandler::MessageReceived(
    311     const base::DictionaryValue& dictionary) {
    312   // The keys of the ModemManager1.SMS interface do not match the
    313   // exported keys, so a new dictionary is created with the expected
    314   // key namaes.
    315   base::DictionaryValue new_dictionary;
    316   std::string text, number, timestamp;
    317   if (dictionary.GetStringWithoutPathExpansion(kModemManager1NumberKey,
    318                                                &number))
    319     new_dictionary.SetString(kNumberKey, number);
    320   if (dictionary.GetStringWithoutPathExpansion(kModemManager1TextKey, &text))
    321     new_dictionary.SetString(kTextKey, text);
    322   // TODO(jglasgow): consider normalizing timestamp.
    323   if (dictionary.GetStringWithoutPathExpansion(kModemManager1TimestampKey,
    324                                                &timestamp))
    325     new_dictionary.SetString(kTimestampKey, timestamp);
    326   host_->MessageReceived(new_dictionary);
    327 }
    328 
    329 ///////////////////////////////////////////////////////////////////////////////
    330 // NetworkSmsHandler
    331 
    332 NetworkSmsHandler::NetworkSmsHandler()
    333     : weak_ptr_factory_(this) {
    334 }
    335 
    336 NetworkSmsHandler::~NetworkSmsHandler() {
    337   DBusThreadManager::Get()->GetShillManagerClient()->
    338       RemovePropertyChangedObserver(this);
    339 }
    340 
    341 void NetworkSmsHandler::Init() {
    342   // Add as an observer here so that new devices added after this call are
    343   // recognized.
    344   DBusThreadManager::Get()->GetShillManagerClient()->AddPropertyChangedObserver(
    345       this);
    346   // Request network manager properties so that we can get the list of devices.
    347   DBusThreadManager::Get()->GetShillManagerClient()->GetProperties(
    348       base::Bind(&NetworkSmsHandler::ManagerPropertiesCallback,
    349                  weak_ptr_factory_.GetWeakPtr()));
    350 }
    351 
    352 void NetworkSmsHandler::RequestUpdate(bool request_existing) {
    353   // If we already received messages and |request_existing| is true, send
    354   // updates for existing messages.
    355   for (ScopedVector<base::DictionaryValue>::iterator iter =
    356            received_messages_.begin();
    357        iter != received_messages_.end(); ++iter) {
    358     base::DictionaryValue* message = *iter;
    359     NotifyMessageReceived(*message);
    360   }
    361   // Request updates from each device.
    362   for (ScopedVector<NetworkSmsDeviceHandler>::iterator iter =
    363            device_handlers_.begin(); iter != device_handlers_.end(); ++iter) {
    364     (*iter)->RequestUpdate();
    365   }
    366 }
    367 
    368 void NetworkSmsHandler::AddObserver(Observer* observer) {
    369   observers_.AddObserver(observer);
    370 }
    371 
    372 void NetworkSmsHandler::RemoveObserver(Observer* observer) {
    373   observers_.RemoveObserver(observer);
    374 }
    375 
    376 void NetworkSmsHandler::OnPropertyChanged(const std::string& name,
    377                                           const base::Value& value) {
    378   if (name != shill::kDevicesProperty)
    379     return;
    380   const base::ListValue* devices = NULL;
    381   if (!value.GetAsList(&devices) || !devices)
    382     return;
    383   UpdateDevices(devices);
    384 }
    385 
    386 // Private methods
    387 
    388 void NetworkSmsHandler::AddReceivedMessage(
    389     const base::DictionaryValue& message) {
    390   base::DictionaryValue* new_message = message.DeepCopy();
    391   if (received_messages_.size() >= kMaxReceivedMessages)
    392     received_messages_.erase(received_messages_.begin());
    393   received_messages_.push_back(new_message);
    394 }
    395 
    396 void NetworkSmsHandler::NotifyMessageReceived(
    397     const base::DictionaryValue& message) {
    398   FOR_EACH_OBSERVER(Observer, observers_, MessageReceived(message));
    399 }
    400 
    401 void NetworkSmsHandler::MessageReceived(const base::DictionaryValue& message) {
    402   AddReceivedMessage(message);
    403   NotifyMessageReceived(message);
    404 }
    405 
    406 void NetworkSmsHandler::ManagerPropertiesCallback(
    407     DBusMethodCallStatus call_status,
    408     const base::DictionaryValue& properties) {
    409   if (call_status != DBUS_METHOD_CALL_SUCCESS) {
    410     LOG(ERROR) << "NetworkSmsHandler: Failed to get manager properties.";
    411     return;
    412   }
    413   const base::Value* value;
    414   if (!properties.GetWithoutPathExpansion(shill::kDevicesProperty, &value) ||
    415       value->GetType() != base::Value::TYPE_LIST) {
    416     LOG(ERROR) << "NetworkSmsHandler: No list value for: "
    417                << shill::kDevicesProperty;
    418     return;
    419   }
    420   const base::ListValue* devices = static_cast<const base::ListValue*>(value);
    421   UpdateDevices(devices);
    422 }
    423 
    424 void NetworkSmsHandler::UpdateDevices(const base::ListValue* devices) {
    425   for (base::ListValue::const_iterator iter = devices->begin();
    426        iter != devices->end(); ++iter) {
    427     std::string device_path;
    428     (*iter)->GetAsString(&device_path);
    429     if (!device_path.empty()) {
    430       // Request device properties.
    431       VLOG(1) << "GetDeviceProperties: " << device_path;
    432       DBusThreadManager::Get()->GetShillDeviceClient()->GetProperties(
    433           dbus::ObjectPath(device_path),
    434           base::Bind(&NetworkSmsHandler::DevicePropertiesCallback,
    435                      weak_ptr_factory_.GetWeakPtr(),
    436                      device_path));
    437     }
    438   }
    439 }
    440 
    441 void NetworkSmsHandler::DevicePropertiesCallback(
    442     const std::string& device_path,
    443     DBusMethodCallStatus call_status,
    444     const base::DictionaryValue& properties) {
    445   if (call_status != DBUS_METHOD_CALL_SUCCESS) {
    446     LOG(ERROR) << "NetworkSmsHandler: ERROR: " << call_status
    447                << " For: " << device_path;
    448     return;
    449   }
    450 
    451   std::string device_type;
    452   if (!properties.GetStringWithoutPathExpansion(
    453           shill::kTypeProperty, &device_type)) {
    454     LOG(ERROR) << "NetworkSmsHandler: No type for: " << device_path;
    455     return;
    456   }
    457   if (device_type != shill::kTypeCellular)
    458     return;
    459 
    460   std::string service_name;
    461   if (!properties.GetStringWithoutPathExpansion(
    462           shill::kDBusServiceProperty, &service_name)) {
    463     LOG(ERROR) << "Device has no DBusService Property: " << device_path;
    464     return;
    465   }
    466 
    467   std::string object_path_string;
    468   if (!properties.GetStringWithoutPathExpansion(
    469           shill::kDBusObjectProperty, &object_path_string)) {
    470     LOG(ERROR) << "Device has no DBusObject Property: " << device_path;
    471     return;
    472   }
    473   dbus::ObjectPath object_path(object_path_string);
    474   if (service_name == modemmanager::kModemManager1ServiceName) {
    475     device_handlers_.push_back(
    476         new ModemManager1NetworkSmsDeviceHandler(
    477             this, service_name, object_path));
    478   } else {
    479     device_handlers_.push_back(
    480         new ModemManagerNetworkSmsDeviceHandler(
    481             this, service_name, object_path));
    482   }
    483 }
    484 
    485 }  // namespace chromeos
    486