Use Persistent::Reset.
[chromium-blink-merge.git] / chromeos / network / network_sms_handler.cc
blobf70314b08f8251242794c8231e31b8b5fecc0c88
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"
7 #include <algorithm>
8 #include <deque>
9 #include <string>
10 #include <vector>
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.
23 namespace {
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";
33 } // namespace
35 namespace chromeos {
37 // static
38 const char NetworkSmsHandler::kNumberKey[] = "number";
39 const char NetworkSmsHandler::kTextKey[] = "text";
40 const char NetworkSmsHandler::kTimestampKey[] = "timestamp";
42 class NetworkSmsHandler::NetworkSmsDeviceHandler {
43 public:
44 NetworkSmsDeviceHandler() {}
45 virtual ~NetworkSmsDeviceHandler() {}
47 virtual void RequestUpdate() = 0;
50 class NetworkSmsHandler::ModemManagerNetworkSmsDeviceHandler
51 : public NetworkSmsHandler::NetworkSmsDeviceHandler {
52 public:
53 ModemManagerNetworkSmsDeviceHandler(NetworkSmsHandler* host,
54 std::string dbus_connection,
55 dbus::ObjectPath object_path);
57 virtual void RequestUpdate() OVERRIDE;
59 private:
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);
76 NetworkSmsHandler::
77 ModemManagerNetworkSmsDeviceHandler::ModemManagerNetworkSmsDeviceHandler(
78 NetworkSmsHandler* host,
79 std::string dbus_connection,
80 dbus::ObjectPath object_path)
81 : host_(host),
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))
113 continue;
114 NotifyMessageReceived(*message);
115 double index = 0;
116 if (message->GetDoubleWithoutPathExpansion(kIndexKey, &index))
117 delete_queue_.push_back(static_cast<uint32>(index));
119 DeleteMessages();
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;
128 return;
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(
142 uint32 index,
143 bool complete) {
144 // Only handle complete messages.
145 if (!complete)
146 return;
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(
155 uint32 index,
156 const base::DictionaryValue& dictionary) {
157 NotifyMessageReceived(dictionary);
158 delete_queue_.push_back(index);
159 if (!deleting_messages_)
160 DeleteMessages();
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
168 // unchanged.
169 host_->NotifyMessageReceived(dictionary);
172 class NetworkSmsHandler::ModemManager1NetworkSmsDeviceHandler
173 : public NetworkSmsHandler::NetworkSmsDeviceHandler {
174 public:
175 ModemManager1NetworkSmsDeviceHandler(NetworkSmsHandler* host,
176 std::string dbus_connection,
177 dbus::ObjectPath object_path);
179 virtual void RequestUpdate() OVERRIDE;
181 private:
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();
186 void GetMessages();
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);
201 NetworkSmsHandler::
202 ModemManager1NetworkSmsDeviceHandler::ModemManager1NetworkSmsDeviceHandler(
203 NetworkSmsHandler* host,
204 std::string dbus_connection,
205 dbus::ObjectPath object_path)
206 : host_(host),
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_,
215 base::Bind(
216 &NetworkSmsHandler::
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_)
247 GetMessages();
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;
256 return;
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_)
274 DeleteMessages();
275 return;
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,
291 bool complete) {
292 // Only handle complete messages.
293 if (!complete)
294 return;
295 retrieval_queue_.push_back(sms_path);
296 if (!retrieving_messages_)
297 GetMessages();
300 void NetworkSmsHandler::ModemManager1NetworkSmsDeviceHandler::GetCallback(
301 const base::DictionaryValue& dictionary) {
302 NotifyMessageReceived(dictionary);
303 GetMessages();
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
311 // key namaes.
312 base::DictionaryValue new_dictionary;
313 std::string text, number, timestamp;
314 if (dictionary.GetStringWithoutPathExpansion(kModemManager1NumberKey,
315 &number))
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,
321 &timestamp))
322 new_dictionary.SetString(kTimestampKey, timestamp);
323 host_->NotifyMessageReceived(new_dictionary);
326 ///////////////////////////////////////////////////////////////////////////////
327 // NetworkSmsHandler
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.";
372 return;
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;
379 return;
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(),
393 device_path));
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;
405 return;
408 std::string device_type;
409 if (!properties.GetStringWithoutPathExpansion(
410 flimflam::kTypeProperty, &device_type)) {
411 LOG(ERROR) << "NetworkSmsHandler: No type for: " << device_path;
412 return;
414 if (device_type != flimflam::kTypeCellular)
415 return;
417 std::string dbus_connection;
418 if (!properties.GetStringWithoutPathExpansion(
419 flimflam::kDBusConnectionProperty, &dbus_connection)) {
420 LOG(ERROR) << "Device has no DBusConnection Property: " << device_path;
421 return;
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;
428 return;
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));
437 } else {
438 device_handlers_.push_back(
439 new ModemManagerNetworkSmsDeviceHandler(
440 this, dbus_connection, object_path));
445 } // namespace chromeos