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 "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"
22 // Not exposed/exported.
24 const char kSmscKey
[] = "smsc";
25 const char kValidityKey
[] = "validity";
26 const char kClassKey
[] = "class";
27 const char kIndexKey
[] = "index";
29 // Keys from ModemManager1
30 const char kModemManager1NumberKey
[] = "Number";
31 const char kModemManager1TextKey
[] = "Text";
32 const char kModemManager1TimestampKey
[] = "Timestamp";
38 const char NetworkSmsHandler::kNumberKey
[] = "number";
39 const char NetworkSmsHandler::kTextKey
[] = "text";
40 const char NetworkSmsHandler::kTimestampKey
[] = "timestamp";
42 class NetworkSmsHandler::NetworkSmsDeviceHandler
{
44 NetworkSmsDeviceHandler() {}
45 virtual ~NetworkSmsDeviceHandler() {}
47 virtual void RequestUpdate() = 0;
50 class NetworkSmsHandler::ModemManagerNetworkSmsDeviceHandler
51 : public NetworkSmsHandler::NetworkSmsDeviceHandler
{
53 ModemManagerNetworkSmsDeviceHandler(NetworkSmsHandler
* host
,
54 std::string dbus_connection
,
55 dbus::ObjectPath object_path
);
57 virtual void RequestUpdate() OVERRIDE
;
60 void ListCallback(const base::ListValue
& message_list
);
61 void SmsReceivedCallback(uint32 index
, bool complete
);
62 void GetCallback(uint32 index
, const base::DictionaryValue
& dictionary
);
63 void DeleteMessages();
64 void NotifyMessageReceived(const base::DictionaryValue
& dictionary
);
66 NetworkSmsHandler
* host_
;
67 std::string dbus_connection_
;
68 dbus::ObjectPath object_path_
;
69 bool deleting_messages_
;
70 base::WeakPtrFactory
<ModemManagerNetworkSmsDeviceHandler
> weak_ptr_factory_
;
71 std::vector
<uint32
> delete_queue_
;
73 DISALLOW_COPY_AND_ASSIGN(ModemManagerNetworkSmsDeviceHandler
);
77 ModemManagerNetworkSmsDeviceHandler::ModemManagerNetworkSmsDeviceHandler(
78 NetworkSmsHandler
* host
,
79 std::string dbus_connection
,
80 dbus::ObjectPath object_path
)
82 dbus_connection_(dbus_connection
),
83 object_path_(object_path
),
84 deleting_messages_(false),
85 weak_ptr_factory_(this) {
86 // Set the handler for received Sms messaages.
87 DBusThreadManager::Get()->GetGsmSMSClient()->SetSmsReceivedHandler(
88 dbus_connection_
, object_path_
,
89 base::Bind(&ModemManagerNetworkSmsDeviceHandler::SmsReceivedCallback
,
90 weak_ptr_factory_
.GetWeakPtr()));
92 // List the existing messages.
93 DBusThreadManager::Get()->GetGsmSMSClient()->List(
94 dbus_connection_
, object_path_
,
95 base::Bind(&NetworkSmsHandler::
96 ModemManagerNetworkSmsDeviceHandler::ListCallback
,
97 weak_ptr_factory_
.GetWeakPtr()));
100 void NetworkSmsHandler::ModemManagerNetworkSmsDeviceHandler::RequestUpdate() {
101 DBusThreadManager::Get()->GetGsmSMSClient()->RequestUpdate(
102 dbus_connection_
, object_path_
);
105 void NetworkSmsHandler::ModemManagerNetworkSmsDeviceHandler::ListCallback(
106 const base::ListValue
& message_list
) {
107 // This receives all messages, so clear any pending deletes.
108 delete_queue_
.clear();
109 for (base::ListValue::const_iterator iter
= message_list
.begin();
110 iter
!= message_list
.end(); ++iter
) {
111 base::DictionaryValue
* message
= NULL
;
112 if (!(*iter
)->GetAsDictionary(&message
))
114 NotifyMessageReceived(*message
);
116 if (message
->GetDoubleWithoutPathExpansion(kIndexKey
, &index
))
117 delete_queue_
.push_back(static_cast<uint32
>(index
));
122 // Messages must be deleted one at a time, since we can not guarantee
123 // the order the deletion will be executed in. Delete messages from
124 // the back of the list so that the indices are valid.
125 void NetworkSmsHandler::ModemManagerNetworkSmsDeviceHandler::DeleteMessages() {
126 if (delete_queue_
.empty()) {
127 deleting_messages_
= false;
130 deleting_messages_
= true;
131 uint32 index
= delete_queue_
.back();
132 delete_queue_
.pop_back();
133 DBusThreadManager::Get()->GetGsmSMSClient()->Delete(
134 dbus_connection_
, object_path_
, index
,
135 base::Bind(&NetworkSmsHandler::
136 ModemManagerNetworkSmsDeviceHandler::DeleteMessages
,
137 weak_ptr_factory_
.GetWeakPtr()));
140 void NetworkSmsHandler::
141 ModemManagerNetworkSmsDeviceHandler::SmsReceivedCallback(
144 // Only handle complete messages.
147 DBusThreadManager::Get()->GetGsmSMSClient()->Get(
148 dbus_connection_
, object_path_
, index
,
149 base::Bind(&NetworkSmsHandler::
150 ModemManagerNetworkSmsDeviceHandler::GetCallback
,
151 weak_ptr_factory_
.GetWeakPtr(), index
));
154 void NetworkSmsHandler::ModemManagerNetworkSmsDeviceHandler::GetCallback(
156 const base::DictionaryValue
& dictionary
) {
157 NotifyMessageReceived(dictionary
);
158 delete_queue_
.push_back(index
);
159 if (!deleting_messages_
)
163 void NetworkSmsHandler::
164 ModemManagerNetworkSmsDeviceHandler::NotifyMessageReceived(
165 const base::DictionaryValue
& dictionary
) {
166 // The keys of the ModemManager.Modem.Gsm.SMS interface match the
167 // exported keys, so the dictionary used as a notification argument
169 host_
->NotifyMessageReceived(dictionary
);
172 class NetworkSmsHandler::ModemManager1NetworkSmsDeviceHandler
173 : public NetworkSmsHandler::NetworkSmsDeviceHandler
{
175 ModemManager1NetworkSmsDeviceHandler(NetworkSmsHandler
* host
,
176 std::string dbus_connection
,
177 dbus::ObjectPath object_path
);
179 virtual void RequestUpdate() OVERRIDE
;
182 void ListCallback(const std::vector
<dbus::ObjectPath
>& paths
);
183 void SmsReceivedCallback(const dbus::ObjectPath
& path
, bool complete
);
184 void GetCallback(const base::DictionaryValue
& dictionary
);
185 void DeleteMessages();
187 void NotifyMessageReceived(const base::DictionaryValue
& dictionary
);
189 NetworkSmsHandler
* host_
;
190 std::string dbus_connection_
;
191 dbus::ObjectPath object_path_
;
192 bool deleting_messages_
;
193 bool retrieving_messages_
;
194 base::WeakPtrFactory
<ModemManager1NetworkSmsDeviceHandler
> weak_ptr_factory_
;
195 std::vector
<dbus::ObjectPath
> delete_queue_
;
196 std::deque
<dbus::ObjectPath
> retrieval_queue_
;
198 DISALLOW_COPY_AND_ASSIGN(ModemManager1NetworkSmsDeviceHandler
);
202 ModemManager1NetworkSmsDeviceHandler::ModemManager1NetworkSmsDeviceHandler(
203 NetworkSmsHandler
* host
,
204 std::string dbus_connection
,
205 dbus::ObjectPath object_path
)
207 dbus_connection_(dbus_connection
),
208 object_path_(object_path
),
209 deleting_messages_(false),
210 retrieving_messages_(false),
211 weak_ptr_factory_(this) {
212 // Set the handler for received Sms messaages.
213 DBusThreadManager::Get()->GetModemMessagingClient()->SetSmsReceivedHandler(
214 dbus_connection_
, object_path_
,
217 ModemManager1NetworkSmsDeviceHandler::SmsReceivedCallback
,
218 weak_ptr_factory_
.GetWeakPtr()));
220 // List the existing messages.
221 DBusThreadManager::Get()->GetModemMessagingClient()->List(
222 dbus_connection_
, object_path_
,
223 base::Bind(&NetworkSmsHandler::
224 ModemManager1NetworkSmsDeviceHandler::ListCallback
,
225 weak_ptr_factory_
.GetWeakPtr()));
228 void NetworkSmsHandler::ModemManager1NetworkSmsDeviceHandler::RequestUpdate() {
229 // Calling List using the service "AddSMS" causes the stub
230 // implementation to deliver new sms messages.
231 DBusThreadManager::Get()->GetModemMessagingClient()->List(
232 std::string("AddSMS"), dbus::ObjectPath("/"),
233 base::Bind(&NetworkSmsHandler::
234 ModemManager1NetworkSmsDeviceHandler::ListCallback
,
235 weak_ptr_factory_
.GetWeakPtr()));
238 void NetworkSmsHandler::ModemManager1NetworkSmsDeviceHandler::ListCallback(
239 const std::vector
<dbus::ObjectPath
>& paths
) {
240 // This receives all messages, so clear any pending gets and deletes.
241 retrieval_queue_
.clear();
242 delete_queue_
.clear();
244 retrieval_queue_
.resize(paths
.size());
245 std::copy(paths
.begin(), paths
.end(), retrieval_queue_
.begin());
246 if (!retrieving_messages_
)
250 // Messages must be deleted one at a time, since we can not guarantee
251 // the order the deletion will be executed in. Delete messages from
252 // the back of the list so that the indices are valid.
253 void NetworkSmsHandler::ModemManager1NetworkSmsDeviceHandler::DeleteMessages() {
254 if (delete_queue_
.empty()) {
255 deleting_messages_
= false;
258 deleting_messages_
= true;
259 dbus::ObjectPath sms_path
= delete_queue_
.back();
260 delete_queue_
.pop_back();
261 DBusThreadManager::Get()->GetModemMessagingClient()->Delete(
262 dbus_connection_
, object_path_
, sms_path
,
263 base::Bind(&NetworkSmsHandler::
264 ModemManager1NetworkSmsDeviceHandler::DeleteMessages
,
265 weak_ptr_factory_
.GetWeakPtr()));
268 // Messages must be fetched one at a time, so that we do not queue too
269 // many requests to a single threaded server.
270 void NetworkSmsHandler::ModemManager1NetworkSmsDeviceHandler::GetMessages() {
271 if (retrieval_queue_
.empty()) {
272 retrieving_messages_
= false;
273 if (!deleting_messages_
)
277 retrieving_messages_
= true;
278 dbus::ObjectPath sms_path
= retrieval_queue_
.front();
279 retrieval_queue_
.pop_front();
280 DBusThreadManager::Get()->GetSMSClient()->GetAll(
281 dbus_connection_
, sms_path
,
282 base::Bind(&NetworkSmsHandler::
283 ModemManager1NetworkSmsDeviceHandler::GetCallback
,
284 weak_ptr_factory_
.GetWeakPtr()));
285 delete_queue_
.push_back(sms_path
);
288 void NetworkSmsHandler::
289 ModemManager1NetworkSmsDeviceHandler::SmsReceivedCallback(
290 const dbus::ObjectPath
& sms_path
,
292 // Only handle complete messages.
295 retrieval_queue_
.push_back(sms_path
);
296 if (!retrieving_messages_
)
300 void NetworkSmsHandler::ModemManager1NetworkSmsDeviceHandler::GetCallback(
301 const base::DictionaryValue
& dictionary
) {
302 NotifyMessageReceived(dictionary
);
306 void NetworkSmsHandler::
307 ModemManager1NetworkSmsDeviceHandler::NotifyMessageReceived(
308 const base::DictionaryValue
& dictionary
) {
309 // The keys of the ModemManager1.SMS interface do not match the
310 // exported keys, so a new dictionary is created with the expected
312 base::DictionaryValue new_dictionary
;
313 std::string text
, number
, timestamp
;
314 if (dictionary
.GetStringWithoutPathExpansion(kModemManager1NumberKey
,
316 new_dictionary
.SetString(kNumberKey
, number
);
317 if (dictionary
.GetStringWithoutPathExpansion(kModemManager1TextKey
, &text
))
318 new_dictionary
.SetString(kTextKey
, text
);
319 // TODO(jglasgow): consider normalizing timestamp.
320 if (dictionary
.GetStringWithoutPathExpansion(kModemManager1TimestampKey
,
322 new_dictionary
.SetString(kTimestampKey
, timestamp
);
323 host_
->NotifyMessageReceived(new_dictionary
);
326 ///////////////////////////////////////////////////////////////////////////////
329 NetworkSmsHandler::NetworkSmsHandler()
330 : weak_ptr_factory_(this) {
333 NetworkSmsHandler::~NetworkSmsHandler() {
336 void NetworkSmsHandler::Init() {
337 // TODO(stevenjb): This code needs to monitor changes to Manager.Network
338 // so that devices added after Init() is called get added to device_handlers_.
339 // See: crbug.com/133416.
341 // Request network manager properties so that we can get the list of devices.
342 DBusThreadManager::Get()->GetShillManagerClient()->GetProperties(
343 base::Bind(&NetworkSmsHandler::ManagerPropertiesCallback
,
344 weak_ptr_factory_
.GetWeakPtr()));
347 void NetworkSmsHandler::RequestUpdate() {
348 for (ScopedVector
<NetworkSmsDeviceHandler
>::iterator iter
=
349 device_handlers_
.begin(); iter
!= device_handlers_
.end(); ++iter
) {
350 (*iter
)->RequestUpdate();
354 void NetworkSmsHandler::AddObserver(Observer
* observer
) {
355 observers_
.AddObserver(observer
);
358 void NetworkSmsHandler::RemoveObserver(Observer
* observer
) {
359 observers_
.RemoveObserver(observer
);
362 void NetworkSmsHandler::NotifyMessageReceived(
363 const base::DictionaryValue
& message
) {
364 FOR_EACH_OBSERVER(Observer
, observers_
, MessageReceived(message
));
367 void NetworkSmsHandler::ManagerPropertiesCallback(
368 DBusMethodCallStatus call_status
,
369 const base::DictionaryValue
& properties
) {
370 if (call_status
!= DBUS_METHOD_CALL_SUCCESS
) {
371 LOG(ERROR
) << "NetworkSmsHandler: Failed to get manager properties.";
374 const base::Value
* value
;
375 if (!properties
.GetWithoutPathExpansion(flimflam::kDevicesProperty
, &value
) ||
376 value
->GetType() != base::Value::TYPE_LIST
) {
377 LOG(ERROR
) << "NetworkSmsHandler: No list value for: "
378 << flimflam::kDevicesProperty
;
381 const base::ListValue
* devices
= static_cast<const base::ListValue
*>(value
);
382 for (base::ListValue::const_iterator iter
= devices
->begin();
383 iter
!= devices
->end(); ++iter
) {
384 std::string device_path
;
385 (*iter
)->GetAsString(&device_path
);
386 if (!device_path
.empty()) {
387 // Request device properties.
388 VLOG(1) << "GetDeviceProperties: " << device_path
;
389 DBusThreadManager::Get()->GetShillDeviceClient()->GetProperties(
390 dbus::ObjectPath(device_path
),
391 base::Bind(&NetworkSmsHandler::DevicePropertiesCallback
,
392 weak_ptr_factory_
.GetWeakPtr(),
398 void NetworkSmsHandler::DevicePropertiesCallback(
399 const std::string
& device_path
,
400 DBusMethodCallStatus call_status
,
401 const base::DictionaryValue
& properties
) {
402 if (call_status
!= DBUS_METHOD_CALL_SUCCESS
) {
403 LOG(ERROR
) << "NetworkSmsHandler: ERROR: " << call_status
404 << " For: " << device_path
;
408 std::string device_type
;
409 if (!properties
.GetStringWithoutPathExpansion(
410 flimflam::kTypeProperty
, &device_type
)) {
411 LOG(ERROR
) << "NetworkSmsHandler: No type for: " << device_path
;
414 if (device_type
!= flimflam::kTypeCellular
)
417 std::string dbus_connection
;
418 if (!properties
.GetStringWithoutPathExpansion(
419 flimflam::kDBusConnectionProperty
, &dbus_connection
)) {
420 LOG(ERROR
) << "Device has no DBusConnection Property: " << device_path
;
424 std::string object_path_string
;
425 if (!properties
.GetStringWithoutPathExpansion(
426 flimflam::kDBusObjectProperty
, &object_path_string
)) {
427 LOG(ERROR
) << "Device has no DBusObject Property: " << device_path
;
430 dbus::ObjectPath
object_path(object_path_string
);
431 if (object_path_string
.compare(
432 0, sizeof(modemmanager::kModemManager1ServicePath
) - 1,
433 modemmanager::kModemManager1ServicePath
) == 0) {
434 device_handlers_
.push_back(
435 new ModemManager1NetworkSmsDeviceHandler(
436 this, dbus_connection
, object_path
));
438 device_handlers_
.push_back(
439 new ModemManagerNetworkSmsDeviceHandler(
440 this, dbus_connection
, object_path
));
445 } // namespace chromeos