• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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:
NetworkSmsDeviceHandler()47   NetworkSmsDeviceHandler() {}
~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::
ModemManagerNetworkSmsDeviceHandler(NetworkSmsHandler * host,const std::string & service_name,const dbus::ObjectPath & object_path)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 
RequestUpdate()103 void NetworkSmsHandler::ModemManagerNetworkSmsDeviceHandler::RequestUpdate() {
104   DBusThreadManager::Get()->GetGsmSMSClient()->RequestUpdate(
105       service_name_, object_path_);
106 }
107 
ListCallback(const base::ListValue & message_list)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.
DeleteMessages()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::
SmsReceivedCallback(uint32 index,bool complete)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 
GetCallback(uint32 index,const base::DictionaryValue & dictionary)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::
MessageReceived(const base::DictionaryValue & dictionary)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::
ModemManager1NetworkSmsDeviceHandler(NetworkSmsHandler * host,const std::string & service_name,const dbus::ObjectPath & object_path)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 
RequestUpdate()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 
ListCallback(const std::vector<dbus::ObjectPath> & paths)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.
DeleteMessages()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.
GetMessages()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::
SmsReceivedCallback(const dbus::ObjectPath & sms_path,bool complete)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 
GetCallback(const base::DictionaryValue & dictionary)303 void NetworkSmsHandler::ModemManager1NetworkSmsDeviceHandler::GetCallback(
304     const base::DictionaryValue& dictionary) {
305   MessageReceived(dictionary);
306   GetMessages();
307 }
308 
309 void NetworkSmsHandler::
MessageReceived(const base::DictionaryValue & dictionary)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 
NetworkSmsHandler()332 NetworkSmsHandler::NetworkSmsHandler()
333     : weak_ptr_factory_(this) {
334 }
335 
~NetworkSmsHandler()336 NetworkSmsHandler::~NetworkSmsHandler() {
337   DBusThreadManager::Get()->GetShillManagerClient()->
338       RemovePropertyChangedObserver(this);
339 }
340 
Init()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 
RequestUpdate(bool request_existing)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 
AddObserver(Observer * observer)368 void NetworkSmsHandler::AddObserver(Observer* observer) {
369   observers_.AddObserver(observer);
370 }
371 
RemoveObserver(Observer * observer)372 void NetworkSmsHandler::RemoveObserver(Observer* observer) {
373   observers_.RemoveObserver(observer);
374 }
375 
OnPropertyChanged(const std::string & name,const base::Value & value)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 
AddReceivedMessage(const base::DictionaryValue & message)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 
NotifyMessageReceived(const base::DictionaryValue & message)396 void NetworkSmsHandler::NotifyMessageReceived(
397     const base::DictionaryValue& message) {
398   FOR_EACH_OBSERVER(Observer, observers_, MessageReceived(message));
399 }
400 
MessageReceived(const base::DictionaryValue & message)401 void NetworkSmsHandler::MessageReceived(const base::DictionaryValue& message) {
402   AddReceivedMessage(message);
403   NotifyMessageReceived(message);
404 }
405 
ManagerPropertiesCallback(DBusMethodCallStatus call_status,const base::DictionaryValue & properties)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 
UpdateDevices(const base::ListValue * devices)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 
DevicePropertiesCallback(const std::string & device_path,DBusMethodCallStatus call_status,const base::DictionaryValue & properties)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