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#include "chromeos/dbus/modem_messaging_client.h"
5
6#include <map>
7#include <utility>
8
9#include "base/bind.h"
10#include "base/memory/weak_ptr.h"
11#include "base/message_loop/message_loop.h"
12#include "base/stl_util.h"
13#include "base/values.h"
14#include "dbus/bus.h"
15#include "dbus/message.h"
16#include "dbus/object_proxy.h"
17#include "third_party/cros_system_api/dbus/service_constants.h"
18
19namespace chromeos {
20
21namespace {
22
23// A class which makes method calls for SMS services via the
24// org.freedesktop.ModemManager1.Messaging object.
25class ModemMessagingProxy {
26 public:
27  typedef ModemMessagingClient::SmsReceivedHandler SmsReceivedHandler;
28  typedef ModemMessagingClient::ListCallback ListCallback;
29  typedef ModemMessagingClient::DeleteCallback DeleteCallback;
30
31  ModemMessagingProxy(dbus::Bus* bus,
32           const std::string& service_name,
33           const dbus::ObjectPath& object_path)
34      : bus_(bus),
35        proxy_(bus->GetObjectProxy(service_name, object_path)),
36        service_name_(service_name),
37        weak_ptr_factory_(this) {
38    proxy_->ConnectToSignal(
39        modemmanager::kModemManager1MessagingInterface,
40        modemmanager::kSMSAddedSignal,
41        base::Bind(&ModemMessagingProxy::OnSmsAdded,
42                   weak_ptr_factory_.GetWeakPtr()),
43        base::Bind(&ModemMessagingProxy::OnSignalConnected,
44                   weak_ptr_factory_.GetWeakPtr()));
45  }
46  virtual ~ModemMessagingProxy() {}
47
48  // Sets SmsReceived signal handler.
49  void SetSmsReceivedHandler(const SmsReceivedHandler& handler) {
50    DCHECK(sms_received_handler_.is_null());
51    sms_received_handler_ = handler;
52  }
53
54  // Resets SmsReceived signal handler.
55  void ResetSmsReceivedHandler() {
56    sms_received_handler_.Reset();
57  }
58
59  // Calls Delete method.
60  void Delete(const dbus::ObjectPath& message_path,
61              const DeleteCallback& callback) {
62    dbus::MethodCall method_call(modemmanager::kModemManager1MessagingInterface,
63                                 modemmanager::kSMSDeleteFunction);
64    dbus::MessageWriter writer(&method_call);
65    writer.AppendObjectPath(message_path);
66    proxy_->CallMethod(&method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
67                       base::Bind(&ModemMessagingProxy::OnDelete,
68                                  weak_ptr_factory_.GetWeakPtr(),
69                                  callback));
70  }
71
72  // Calls List method.
73  virtual void List(const ListCallback& callback) {
74    dbus::MethodCall method_call(modemmanager::kModemManager1MessagingInterface,
75                                 modemmanager::kSMSListFunction);
76    proxy_->CallMethod(&method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
77                       base::Bind(&ModemMessagingProxy::OnList,
78                                  weak_ptr_factory_.GetWeakPtr(),
79                                  callback));
80  }
81
82 private:
83  // Handles SmsAdded signal.
84  void OnSmsAdded(dbus::Signal* signal) {
85    dbus::ObjectPath message_path;
86    bool complete = false;
87    dbus::MessageReader reader(signal);
88    if (!reader.PopObjectPath(&message_path) ||
89        !reader.PopBool(&complete)) {
90      LOG(ERROR) << "Invalid signal: " << signal->ToString();
91      return;
92    }
93    if (!sms_received_handler_.is_null()) {
94      sms_received_handler_.Run(message_path, complete);
95    }
96  }
97
98  // Handles responses of Delete method calls.
99  void OnDelete(const DeleteCallback& callback, dbus::Response* response) {
100    if (!response)
101      return;
102    callback.Run();
103  }
104
105  // Handles responses of List method calls.
106  void OnList(const ListCallback& callback, dbus::Response* response) {
107    if (!response)
108      return;
109    dbus::MessageReader reader(response);
110    std::vector<dbus::ObjectPath> sms_paths;
111    if (!reader.PopArrayOfObjectPaths(&sms_paths))
112      LOG(WARNING) << "Invalid response: " << response->ToString();
113    callback.Run(sms_paths);
114  }
115
116  // Handles the result of signal connection setup.
117  void OnSignalConnected(const std::string& interface,
118                         const std::string& signal,
119                         bool succeeded) {
120    LOG_IF(ERROR, !succeeded) << "Connect to " << interface << " "
121                              << signal << " failed.";
122  }
123
124  dbus::Bus* bus_;
125  dbus::ObjectProxy* proxy_;
126  std::string service_name_;
127  SmsReceivedHandler sms_received_handler_;
128
129  // Note: This should remain the last member so it'll be destroyed and
130  // invalidate its weak pointers before any other members are destroyed.
131  base::WeakPtrFactory<ModemMessagingProxy> weak_ptr_factory_;
132
133  DISALLOW_COPY_AND_ASSIGN(ModemMessagingProxy);
134};
135
136class CHROMEOS_EXPORT ModemMessagingClientImpl : public ModemMessagingClient {
137 public:
138  ModemMessagingClientImpl()
139      : bus_(NULL),
140        proxies_deleter_(&proxies_) {
141  }
142
143  virtual void SetSmsReceivedHandler(
144      const std::string& service_name,
145      const dbus::ObjectPath& object_path,
146      const SmsReceivedHandler& handler) OVERRIDE {
147    GetProxy(service_name, object_path)->SetSmsReceivedHandler(handler);
148  }
149
150  virtual void ResetSmsReceivedHandler(
151      const std::string& service_name,
152      const dbus::ObjectPath& object_path) OVERRIDE {
153    GetProxy(service_name, object_path)->ResetSmsReceivedHandler();
154  }
155
156  virtual void Delete(const std::string& service_name,
157                      const dbus::ObjectPath& object_path,
158                      const dbus::ObjectPath& sms_path,
159                      const DeleteCallback& callback) OVERRIDE {
160    GetProxy(service_name, object_path)->Delete(sms_path, callback);
161  }
162
163  virtual void List(const std::string& service_name,
164                    const dbus::ObjectPath& object_path,
165                    const ListCallback& callback) OVERRIDE {
166    GetProxy(service_name, object_path)->List(callback);
167  }
168
169 protected:
170  virtual void Init(dbus::Bus* bus) OVERRIDE {
171    bus_ = bus;
172  };
173
174 private:
175  typedef std::map<std::pair<std::string, std::string>, ModemMessagingProxy*>
176      ProxyMap;
177
178  // Returns a SMSProxy for the given service name and object path.
179  ModemMessagingProxy* GetProxy(const std::string& service_name,
180                                const dbus::ObjectPath& object_path) {
181    const ProxyMap::key_type key(service_name, object_path.value());
182    ProxyMap::iterator it = proxies_.find(key);
183    if (it != proxies_.end())
184      return it->second;
185
186    // There is no proxy for the service_name and object_path, create it.
187    ModemMessagingProxy* proxy
188        = new ModemMessagingProxy(bus_, service_name, object_path);
189    proxies_.insert(ProxyMap::value_type(key, proxy));
190    return proxy;
191  }
192
193  dbus::Bus* bus_;
194  ProxyMap proxies_;
195  STLValueDeleter<ProxyMap> proxies_deleter_;
196
197  DISALLOW_COPY_AND_ASSIGN(ModemMessagingClientImpl);
198};
199
200}  // namespace
201
202////////////////////////////////////////////////////////////////////////////////
203// ModemMessagingClient
204
205ModemMessagingClient::ModemMessagingClient() {}
206
207ModemMessagingClient::~ModemMessagingClient() {}
208
209
210// static
211ModemMessagingClient* ModemMessagingClient::Create() {
212  return new ModemMessagingClientImpl();
213}
214
215
216}  // namespace chromeos
217