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