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"
11 #include "base/bind.h"
12 #include "base/values.h"
13 #include "chromeos/dbus/dbus_thread_manager.h"
14 #include "chromeos/dbus/shill_device_client.h"
15 #include "chromeos/dbus/shill_manager_client.h"
16 #include "chromeos/dbus/gsm_sms_client.h"
17 #include "chromeos/dbus/modem_messaging_client.h"
18 #include "chromeos/dbus/sms_client.h"
19 #include "dbus/object_path.h"
20 #include "third_party/cros_system_api/dbus/service_constants.h"
24 // Not exposed/exported:
25 const char kIndexKey
[] = "index";
27 // Keys from ModemManager1
28 const char kModemManager1NumberKey
[] = "Number";
29 const char kModemManager1TextKey
[] = "Text";
30 const char kModemManager1TimestampKey
[] = "Timestamp";
32 // Maximum number of messages stored for RequestUpdate(true).
33 const size_t kMaxReceivedMessages
= 100;
40 const char NetworkSmsHandler::kNumberKey
[] = "number";
41 const char NetworkSmsHandler::kTextKey
[] = "text";
42 const char NetworkSmsHandler::kTimestampKey
[] = "timestamp";
44 class NetworkSmsHandler::NetworkSmsDeviceHandler
{
46 NetworkSmsDeviceHandler() {}
47 virtual ~NetworkSmsDeviceHandler() {}
49 virtual void RequestUpdate() = 0;
52 class NetworkSmsHandler::ModemManagerNetworkSmsDeviceHandler
53 : public NetworkSmsHandler::NetworkSmsDeviceHandler
{
55 ModemManagerNetworkSmsDeviceHandler(NetworkSmsHandler
* host
,
56 const std::string
& service_name
,
57 const dbus::ObjectPath
& object_path
);
59 void RequestUpdate() override
;
62 void ListCallback(const base::ListValue
& message_list
);
63 void SmsReceivedCallback(uint32 index
, bool complete
);
64 void GetCallback(uint32 index
, const base::DictionaryValue
& dictionary
);
65 void DeleteMessages();
66 void MessageReceived(const base::DictionaryValue
& dictionary
);
68 NetworkSmsHandler
* host_
;
69 std::string service_name_
;
70 dbus::ObjectPath object_path_
;
71 bool deleting_messages_
;
72 std::vector
<uint32
> delete_queue_
;
73 base::WeakPtrFactory
<ModemManagerNetworkSmsDeviceHandler
> weak_ptr_factory_
;
75 DISALLOW_COPY_AND_ASSIGN(ModemManagerNetworkSmsDeviceHandler
);
79 ModemManagerNetworkSmsDeviceHandler::ModemManagerNetworkSmsDeviceHandler(
80 NetworkSmsHandler
* host
,
81 const std::string
& service_name
,
82 const dbus::ObjectPath
& object_path
)
84 service_name_(service_name
),
85 object_path_(object_path
),
86 deleting_messages_(false),
87 weak_ptr_factory_(this) {
88 // Set the handler for received Sms messaages.
89 DBusThreadManager::Get()->GetGsmSMSClient()->SetSmsReceivedHandler(
90 service_name_
, object_path_
,
91 base::Bind(&ModemManagerNetworkSmsDeviceHandler::SmsReceivedCallback
,
92 weak_ptr_factory_
.GetWeakPtr()));
94 // List the existing messages.
95 DBusThreadManager::Get()->GetGsmSMSClient()->List(
96 service_name_
, object_path_
,
97 base::Bind(&NetworkSmsHandler::
98 ModemManagerNetworkSmsDeviceHandler::ListCallback
,
99 weak_ptr_factory_
.GetWeakPtr()));
102 void NetworkSmsHandler::ModemManagerNetworkSmsDeviceHandler::RequestUpdate() {
103 DBusThreadManager::Get()->GetGsmSMSClient()->RequestUpdate(
104 service_name_
, object_path_
);
107 void NetworkSmsHandler::ModemManagerNetworkSmsDeviceHandler::ListCallback(
108 const base::ListValue
& message_list
) {
109 // This receives all messages, so clear any pending deletes.
110 delete_queue_
.clear();
111 for (base::ListValue::const_iterator iter
= message_list
.begin();
112 iter
!= message_list
.end(); ++iter
) {
113 base::DictionaryValue
* message
= NULL
;
114 if (!(*iter
)->GetAsDictionary(&message
))
116 MessageReceived(*message
);
118 if (message
->GetDoubleWithoutPathExpansion(kIndexKey
, &index
))
119 delete_queue_
.push_back(static_cast<uint32
>(index
));
124 // Messages must be deleted one at a time, since we can not guarantee
125 // the order the deletion will be executed in. Delete messages from
126 // the back of the list so that the indices are valid.
127 void NetworkSmsHandler::ModemManagerNetworkSmsDeviceHandler::DeleteMessages() {
128 if (delete_queue_
.empty()) {
129 deleting_messages_
= false;
132 deleting_messages_
= true;
133 uint32 index
= delete_queue_
.back();
134 delete_queue_
.pop_back();
135 DBusThreadManager::Get()->GetGsmSMSClient()->Delete(
136 service_name_
, object_path_
, index
,
137 base::Bind(&NetworkSmsHandler::
138 ModemManagerNetworkSmsDeviceHandler::DeleteMessages
,
139 weak_ptr_factory_
.GetWeakPtr()));
142 void NetworkSmsHandler::
143 ModemManagerNetworkSmsDeviceHandler::SmsReceivedCallback(
146 // Only handle complete messages.
149 DBusThreadManager::Get()->GetGsmSMSClient()->Get(
150 service_name_
, object_path_
, index
,
151 base::Bind(&NetworkSmsHandler::
152 ModemManagerNetworkSmsDeviceHandler::GetCallback
,
153 weak_ptr_factory_
.GetWeakPtr(), index
));
156 void NetworkSmsHandler::ModemManagerNetworkSmsDeviceHandler::GetCallback(
158 const base::DictionaryValue
& dictionary
) {
159 MessageReceived(dictionary
);
160 delete_queue_
.push_back(index
);
161 if (!deleting_messages_
)
165 void NetworkSmsHandler::
166 ModemManagerNetworkSmsDeviceHandler::MessageReceived(
167 const base::DictionaryValue
& dictionary
) {
168 // The keys of the ModemManager.Modem.Gsm.SMS interface match the
169 // exported keys, so the dictionary used as a notification argument
171 host_
->MessageReceived(dictionary
);
174 class NetworkSmsHandler::ModemManager1NetworkSmsDeviceHandler
175 : public NetworkSmsHandler::NetworkSmsDeviceHandler
{
177 ModemManager1NetworkSmsDeviceHandler(NetworkSmsHandler
* host
,
178 const std::string
& service_name
,
179 const dbus::ObjectPath
& object_path
);
181 void RequestUpdate() override
;
184 void ListCallback(const std::vector
<dbus::ObjectPath
>& paths
);
185 void SmsReceivedCallback(const dbus::ObjectPath
& path
, bool complete
);
186 void GetCallback(const base::DictionaryValue
& dictionary
);
187 void DeleteMessages();
189 void MessageReceived(const base::DictionaryValue
& dictionary
);
191 NetworkSmsHandler
* host_
;
192 std::string service_name_
;
193 dbus::ObjectPath object_path_
;
194 bool deleting_messages_
;
195 bool retrieving_messages_
;
196 std::vector
<dbus::ObjectPath
> delete_queue_
;
197 std::deque
<dbus::ObjectPath
> retrieval_queue_
;
198 base::WeakPtrFactory
<ModemManager1NetworkSmsDeviceHandler
> weak_ptr_factory_
;
200 DISALLOW_COPY_AND_ASSIGN(ModemManager1NetworkSmsDeviceHandler
);
204 ModemManager1NetworkSmsDeviceHandler::ModemManager1NetworkSmsDeviceHandler(
205 NetworkSmsHandler
* host
,
206 const std::string
& service_name
,
207 const dbus::ObjectPath
& object_path
)
209 service_name_(service_name
),
210 object_path_(object_path
),
211 deleting_messages_(false),
212 retrieving_messages_(false),
213 weak_ptr_factory_(this) {
214 // Set the handler for received Sms messaages.
215 DBusThreadManager::Get()->GetModemMessagingClient()->SetSmsReceivedHandler(
216 service_name_
, object_path_
,
219 ModemManager1NetworkSmsDeviceHandler::SmsReceivedCallback
,
220 weak_ptr_factory_
.GetWeakPtr()));
222 // List the existing messages.
223 DBusThreadManager::Get()->GetModemMessagingClient()->List(
224 service_name_
, object_path_
,
225 base::Bind(&NetworkSmsHandler::
226 ModemManager1NetworkSmsDeviceHandler::ListCallback
,
227 weak_ptr_factory_
.GetWeakPtr()));
230 void NetworkSmsHandler::ModemManager1NetworkSmsDeviceHandler::RequestUpdate() {
231 // Calling List using the service "AddSMS" causes the stub
232 // implementation to deliver new sms messages.
233 DBusThreadManager::Get()->GetModemMessagingClient()->List(
234 std::string("AddSMS"), dbus::ObjectPath("/"),
235 base::Bind(&NetworkSmsHandler::
236 ModemManager1NetworkSmsDeviceHandler::ListCallback
,
237 weak_ptr_factory_
.GetWeakPtr()));
240 void NetworkSmsHandler::ModemManager1NetworkSmsDeviceHandler::ListCallback(
241 const std::vector
<dbus::ObjectPath
>& paths
) {
242 // This receives all messages, so clear any pending gets and deletes.
243 retrieval_queue_
.clear();
244 delete_queue_
.clear();
246 retrieval_queue_
.resize(paths
.size());
247 std::copy(paths
.begin(), paths
.end(), retrieval_queue_
.begin());
248 if (!retrieving_messages_
)
252 // Messages must be deleted one at a time, since we can not guarantee
253 // the order the deletion will be executed in. Delete messages from
254 // the back of the list so that the indices are valid.
255 void NetworkSmsHandler::ModemManager1NetworkSmsDeviceHandler::DeleteMessages() {
256 if (delete_queue_
.empty()) {
257 deleting_messages_
= false;
260 deleting_messages_
= true;
261 dbus::ObjectPath sms_path
= delete_queue_
.back();
262 delete_queue_
.pop_back();
263 DBusThreadManager::Get()->GetModemMessagingClient()->Delete(
264 service_name_
, object_path_
, sms_path
,
265 base::Bind(&NetworkSmsHandler::
266 ModemManager1NetworkSmsDeviceHandler::DeleteMessages
,
267 weak_ptr_factory_
.GetWeakPtr()));
270 // Messages must be fetched one at a time, so that we do not queue too
271 // many requests to a single threaded server.
272 void NetworkSmsHandler::ModemManager1NetworkSmsDeviceHandler::GetMessages() {
273 if (retrieval_queue_
.empty()) {
274 retrieving_messages_
= false;
275 if (!deleting_messages_
)
279 retrieving_messages_
= true;
280 dbus::ObjectPath sms_path
= retrieval_queue_
.front();
281 retrieval_queue_
.pop_front();
282 DBusThreadManager::Get()->GetSMSClient()->GetAll(
283 service_name_
, sms_path
,
284 base::Bind(&NetworkSmsHandler::
285 ModemManager1NetworkSmsDeviceHandler::GetCallback
,
286 weak_ptr_factory_
.GetWeakPtr()));
287 delete_queue_
.push_back(sms_path
);
290 void NetworkSmsHandler::
291 ModemManager1NetworkSmsDeviceHandler::SmsReceivedCallback(
292 const dbus::ObjectPath
& sms_path
,
294 // Only handle complete messages.
297 retrieval_queue_
.push_back(sms_path
);
298 if (!retrieving_messages_
)
302 void NetworkSmsHandler::ModemManager1NetworkSmsDeviceHandler::GetCallback(
303 const base::DictionaryValue
& dictionary
) {
304 MessageReceived(dictionary
);
308 void NetworkSmsHandler::
309 ModemManager1NetworkSmsDeviceHandler::MessageReceived(
310 const base::DictionaryValue
& dictionary
) {
311 // The keys of the ModemManager1.SMS interface do not match the
312 // exported keys, so a new dictionary is created with the expected
314 base::DictionaryValue new_dictionary
;
315 std::string text
, number
, timestamp
;
316 if (dictionary
.GetStringWithoutPathExpansion(kModemManager1NumberKey
,
318 new_dictionary
.SetString(kNumberKey
, number
);
319 if (dictionary
.GetStringWithoutPathExpansion(kModemManager1TextKey
, &text
))
320 new_dictionary
.SetString(kTextKey
, text
);
321 // TODO(jglasgow): consider normalizing timestamp.
322 if (dictionary
.GetStringWithoutPathExpansion(kModemManager1TimestampKey
,
324 new_dictionary
.SetString(kTimestampKey
, timestamp
);
325 host_
->MessageReceived(new_dictionary
);
328 ///////////////////////////////////////////////////////////////////////////////
331 NetworkSmsHandler::NetworkSmsHandler()
332 : weak_ptr_factory_(this) {
335 NetworkSmsHandler::~NetworkSmsHandler() {
336 DBusThreadManager::Get()->GetShillManagerClient()->
337 RemovePropertyChangedObserver(this);
340 void NetworkSmsHandler::Init() {
341 // Add as an observer here so that new devices added after this call are
343 DBusThreadManager::Get()->GetShillManagerClient()->AddPropertyChangedObserver(
345 // Request network manager properties so that we can get the list of devices.
346 DBusThreadManager::Get()->GetShillManagerClient()->GetProperties(
347 base::Bind(&NetworkSmsHandler::ManagerPropertiesCallback
,
348 weak_ptr_factory_
.GetWeakPtr()));
351 void NetworkSmsHandler::RequestUpdate(bool request_existing
) {
352 // If we already received messages and |request_existing| is true, send
353 // updates for existing messages.
354 for (ScopedVector
<base::DictionaryValue
>::iterator iter
=
355 received_messages_
.begin();
356 iter
!= received_messages_
.end(); ++iter
) {
357 base::DictionaryValue
* message
= *iter
;
358 NotifyMessageReceived(*message
);
360 // Request updates from each device.
361 for (ScopedVector
<NetworkSmsDeviceHandler
>::iterator iter
=
362 device_handlers_
.begin(); iter
!= device_handlers_
.end(); ++iter
) {
363 (*iter
)->RequestUpdate();
367 void NetworkSmsHandler::AddObserver(Observer
* observer
) {
368 observers_
.AddObserver(observer
);
371 void NetworkSmsHandler::RemoveObserver(Observer
* observer
) {
372 observers_
.RemoveObserver(observer
);
375 void NetworkSmsHandler::OnPropertyChanged(const std::string
& name
,
376 const base::Value
& value
) {
377 if (name
!= shill::kDevicesProperty
)
379 const base::ListValue
* devices
= NULL
;
380 if (!value
.GetAsList(&devices
) || !devices
)
382 UpdateDevices(devices
);
387 void NetworkSmsHandler::AddReceivedMessage(
388 const base::DictionaryValue
& message
) {
389 base::DictionaryValue
* new_message
= message
.DeepCopy();
390 if (received_messages_
.size() >= kMaxReceivedMessages
)
391 received_messages_
.erase(received_messages_
.begin());
392 received_messages_
.push_back(new_message
);
395 void NetworkSmsHandler::NotifyMessageReceived(
396 const base::DictionaryValue
& message
) {
397 FOR_EACH_OBSERVER(Observer
, observers_
, MessageReceived(message
));
400 void NetworkSmsHandler::MessageReceived(const base::DictionaryValue
& message
) {
401 AddReceivedMessage(message
);
402 NotifyMessageReceived(message
);
405 void NetworkSmsHandler::ManagerPropertiesCallback(
406 DBusMethodCallStatus call_status
,
407 const base::DictionaryValue
& properties
) {
408 if (call_status
!= DBUS_METHOD_CALL_SUCCESS
) {
409 LOG(ERROR
) << "NetworkSmsHandler: Failed to get manager properties.";
412 const base::Value
* value
;
413 if (!properties
.GetWithoutPathExpansion(shill::kDevicesProperty
, &value
) ||
414 value
->GetType() != base::Value::TYPE_LIST
) {
415 LOG(ERROR
) << "NetworkSmsHandler: No list value for: "
416 << shill::kDevicesProperty
;
419 const base::ListValue
* devices
= static_cast<const base::ListValue
*>(value
);
420 UpdateDevices(devices
);
423 void NetworkSmsHandler::UpdateDevices(const base::ListValue
* devices
) {
424 for (base::ListValue::const_iterator iter
= devices
->begin();
425 iter
!= devices
->end(); ++iter
) {
426 std::string device_path
;
427 (*iter
)->GetAsString(&device_path
);
428 if (!device_path
.empty()) {
429 // Request device properties.
430 VLOG(1) << "GetDeviceProperties: " << device_path
;
431 DBusThreadManager::Get()->GetShillDeviceClient()->GetProperties(
432 dbus::ObjectPath(device_path
),
433 base::Bind(&NetworkSmsHandler::DevicePropertiesCallback
,
434 weak_ptr_factory_
.GetWeakPtr(),
440 void NetworkSmsHandler::DevicePropertiesCallback(
441 const std::string
& device_path
,
442 DBusMethodCallStatus call_status
,
443 const base::DictionaryValue
& properties
) {
444 if (call_status
!= DBUS_METHOD_CALL_SUCCESS
) {
445 LOG(ERROR
) << "NetworkSmsHandler: ERROR: " << call_status
446 << " For: " << device_path
;
450 std::string device_type
;
451 if (!properties
.GetStringWithoutPathExpansion(
452 shill::kTypeProperty
, &device_type
)) {
453 LOG(ERROR
) << "NetworkSmsHandler: No type for: " << device_path
;
456 if (device_type
!= shill::kTypeCellular
)
459 std::string service_name
;
460 if (!properties
.GetStringWithoutPathExpansion(
461 shill::kDBusServiceProperty
, &service_name
)) {
462 LOG(ERROR
) << "Device has no DBusService Property: " << device_path
;
466 std::string object_path_string
;
467 if (!properties
.GetStringWithoutPathExpansion(
468 shill::kDBusObjectProperty
, &object_path_string
)) {
469 LOG(ERROR
) << "Device has no DBusObject Property: " << device_path
;
472 dbus::ObjectPath
object_path(object_path_string
);
473 if (service_name
== modemmanager::kModemManager1ServiceName
) {
474 device_handlers_
.push_back(
475 new ModemManager1NetworkSmsDeviceHandler(
476 this, service_name
, object_path
));
478 device_handlers_
.push_back(
479 new ModemManagerNetworkSmsDeviceHandler(
480 this, service_name
, object_path
));
484 } // namespace chromeos