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.
5 #include "chromeos/network/network_sms_handler.h"
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"
25 // Not exposed/exported:
26 const char kIndexKey
[] = "index";
28 // Keys from ModemManager1
29 const char kModemManager1NumberKey
[] = "Number";
30 const char kModemManager1TextKey
[] = "Text";
31 const char kModemManager1TimestampKey
[] = "Timestamp";
33 // Maximum number of messages stored for RequestUpdate(true).
34 const size_t kMaxReceivedMessages
= 100;
41 const char NetworkSmsHandler::kNumberKey
[] = "number";
42 const char NetworkSmsHandler::kTextKey
[] = "text";
43 const char NetworkSmsHandler::kTimestampKey
[] = "timestamp";
45 class NetworkSmsHandler::NetworkSmsDeviceHandler
{
47 NetworkSmsDeviceHandler() {}
48 virtual ~NetworkSmsDeviceHandler() {}
50 virtual void RequestUpdate() = 0;
53 class NetworkSmsHandler::ModemManagerNetworkSmsDeviceHandler
54 : public NetworkSmsHandler::NetworkSmsDeviceHandler
{
56 ModemManagerNetworkSmsDeviceHandler(NetworkSmsHandler
* host
,
57 const std::string
& service_name
,
58 const dbus::ObjectPath
& object_path
);
60 void RequestUpdate() override
;
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
);
69 NetworkSmsHandler
* host_
;
70 std::string service_name_
;
71 dbus::ObjectPath object_path_
;
72 bool deleting_messages_
;
73 std::vector
<uint32
> delete_queue_
;
74 base::WeakPtrFactory
<ModemManagerNetworkSmsDeviceHandler
> weak_ptr_factory_
;
76 DISALLOW_COPY_AND_ASSIGN(ModemManagerNetworkSmsDeviceHandler
);
80 ModemManagerNetworkSmsDeviceHandler::ModemManagerNetworkSmsDeviceHandler(
81 NetworkSmsHandler
* host
,
82 const std::string
& service_name
,
83 const dbus::ObjectPath
& object_path
)
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()));
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()));
103 void NetworkSmsHandler::ModemManagerNetworkSmsDeviceHandler::RequestUpdate() {
104 DBusThreadManager::Get()->GetGsmSMSClient()->RequestUpdate(
105 service_name_
, object_path_
);
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
))
117 MessageReceived(*message
);
119 if (message
->GetDoubleWithoutPathExpansion(kIndexKey
, &index
))
120 delete_queue_
.push_back(static_cast<uint32
>(index
));
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;
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()));
143 void NetworkSmsHandler::
144 ModemManagerNetworkSmsDeviceHandler::SmsReceivedCallback(
147 // Only handle complete messages.
150 DBusThreadManager::Get()->GetGsmSMSClient()->Get(
151 service_name_
, object_path_
, index
,
152 base::Bind(&NetworkSmsHandler::
153 ModemManagerNetworkSmsDeviceHandler::GetCallback
,
154 weak_ptr_factory_
.GetWeakPtr(), index
));
157 void NetworkSmsHandler::ModemManagerNetworkSmsDeviceHandler::GetCallback(
159 const base::DictionaryValue
& dictionary
) {
160 MessageReceived(dictionary
);
161 delete_queue_
.push_back(index
);
162 if (!deleting_messages_
)
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
172 host_
->MessageReceived(dictionary
);
175 class NetworkSmsHandler::ModemManager1NetworkSmsDeviceHandler
176 : public NetworkSmsHandler::NetworkSmsDeviceHandler
{
178 ModemManager1NetworkSmsDeviceHandler(NetworkSmsHandler
* host
,
179 const std::string
& service_name
,
180 const dbus::ObjectPath
& object_path
);
182 void RequestUpdate() override
;
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();
190 void MessageReceived(const base::DictionaryValue
& dictionary
);
192 NetworkSmsHandler
* host_
;
193 std::string service_name_
;
194 dbus::ObjectPath object_path_
;
195 bool deleting_messages_
;
196 bool retrieving_messages_
;
197 std::vector
<dbus::ObjectPath
> delete_queue_
;
198 std::deque
<dbus::ObjectPath
> retrieval_queue_
;
199 base::WeakPtrFactory
<ModemManager1NetworkSmsDeviceHandler
> weak_ptr_factory_
;
201 DISALLOW_COPY_AND_ASSIGN(ModemManager1NetworkSmsDeviceHandler
);
205 ModemManager1NetworkSmsDeviceHandler::ModemManager1NetworkSmsDeviceHandler(
206 NetworkSmsHandler
* host
,
207 const std::string
& service_name
,
208 const dbus::ObjectPath
& object_path
)
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_
,
220 ModemManager1NetworkSmsDeviceHandler::SmsReceivedCallback
,
221 weak_ptr_factory_
.GetWeakPtr()));
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()));
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()));
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();
247 retrieval_queue_
.resize(paths
.size());
248 std::copy(paths
.begin(), paths
.end(), retrieval_queue_
.begin());
249 if (!retrieving_messages_
)
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;
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()));
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_
)
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
);
291 void NetworkSmsHandler::
292 ModemManager1NetworkSmsDeviceHandler::SmsReceivedCallback(
293 const dbus::ObjectPath
& sms_path
,
295 // Only handle complete messages.
298 retrieval_queue_
.push_back(sms_path
);
299 if (!retrieving_messages_
)
303 void NetworkSmsHandler::ModemManager1NetworkSmsDeviceHandler::GetCallback(
304 const base::DictionaryValue
& dictionary
) {
305 MessageReceived(dictionary
);
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
315 base::DictionaryValue new_dictionary
;
316 std::string text
, number
, timestamp
;
317 if (dictionary
.GetStringWithoutPathExpansion(kModemManager1NumberKey
,
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
,
325 new_dictionary
.SetString(kTimestampKey
, timestamp
);
326 host_
->MessageReceived(new_dictionary
);
329 ///////////////////////////////////////////////////////////////////////////////
332 NetworkSmsHandler::NetworkSmsHandler()
333 : weak_ptr_factory_(this) {
336 NetworkSmsHandler::~NetworkSmsHandler() {
337 DBusThreadManager::Get()->GetShillManagerClient()->
338 RemovePropertyChangedObserver(this);
341 void NetworkSmsHandler::Init() {
342 // Add as an observer here so that new devices added after this call are
344 DBusThreadManager::Get()->GetShillManagerClient()->AddPropertyChangedObserver(
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()));
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
);
361 // Request updates from each device.
362 for (ScopedVector
<NetworkSmsDeviceHandler
>::iterator iter
=
363 device_handlers_
.begin(); iter
!= device_handlers_
.end(); ++iter
) {
364 (*iter
)->RequestUpdate();
368 void NetworkSmsHandler::AddObserver(Observer
* observer
) {
369 observers_
.AddObserver(observer
);
372 void NetworkSmsHandler::RemoveObserver(Observer
* observer
) {
373 observers_
.RemoveObserver(observer
);
376 void NetworkSmsHandler::OnPropertyChanged(const std::string
& name
,
377 const base::Value
& value
) {
378 if (name
!= shill::kDevicesProperty
)
380 const base::ListValue
* devices
= NULL
;
381 if (!value
.GetAsList(&devices
) || !devices
)
383 UpdateDevices(devices
);
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
);
396 void NetworkSmsHandler::NotifyMessageReceived(
397 const base::DictionaryValue
& message
) {
398 FOR_EACH_OBSERVER(Observer
, observers_
, MessageReceived(message
));
401 void NetworkSmsHandler::MessageReceived(const base::DictionaryValue
& message
) {
402 AddReceivedMessage(message
);
403 NotifyMessageReceived(message
);
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.";
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
;
420 const base::ListValue
* devices
= static_cast<const base::ListValue
*>(value
);
421 UpdateDevices(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(),
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
;
451 std::string device_type
;
452 if (!properties
.GetStringWithoutPathExpansion(
453 shill::kTypeProperty
, &device_type
)) {
454 LOG(ERROR
) << "NetworkSmsHandler: No type for: " << device_path
;
457 if (device_type
!= shill::kTypeCellular
)
460 std::string service_name
;
461 if (!properties
.GetStringWithoutPathExpansion(
462 shill::kDBusServiceProperty
, &service_name
)) {
463 LOG(ERROR
) << "Device has no DBusService Property: " << device_path
;
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
;
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
));
479 device_handlers_
.push_back(
480 new ModemManagerNetworkSmsDeviceHandler(
481 this, service_name
, object_path
));
485 } // namespace chromeos