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/sms_client.h"
5
6#include <map>
7#include <utility>
8
9#include "base/bind.h"
10#include "base/command_line.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 "chromeos/chromeos_switches.h"
18#include "dbus/bus.h"
19#include "dbus/message.h"
20#include "dbus/object_proxy.h"
21#include "dbus/values_util.h"
22#include "third_party/cros_system_api/dbus/service_constants.h"
23
24namespace chromeos {
25
26namespace {
27
28// SMSClient is used to communicate with the
29// org.freedesktop.ModemManager1.SMS service.  All methods should be
30// called from the origin thread (UI thread) which initializes the
31// DBusThreadManager instance.
32class SMSClientImpl : public SMSClient {
33 public:
34  explicit SMSClientImpl(dbus::Bus* bus) : bus_(bus), weak_ptr_factory_(this) {}
35  virtual ~SMSClientImpl() {}
36
37  // Calls GetAll method.  |callback| is called after the method call succeeds.
38  virtual void GetAll(const std::string& service_name,
39                      const dbus::ObjectPath& object_path,
40                      const GetAllCallback& callback) OVERRIDE {
41    dbus::ObjectProxy *proxy = bus_->GetObjectProxy(service_name, object_path);
42    dbus::MethodCall method_call(dbus::kDBusPropertiesInterface,
43                                 dbus::kDBusPropertiesGetAll);
44    dbus::MessageWriter writer(&method_call);
45    writer.AppendString(modemmanager::kModemManager1SmsInterface);
46    proxy->CallMethod(&method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
47                       base::Bind(&SMSClientImpl::OnGetAll,
48                                  weak_ptr_factory_.GetWeakPtr(),
49                                  callback));
50  }
51
52 private:
53  // Handles responses of GetAll method calls.
54  void OnGetAll(const GetAllCallback& callback, dbus::Response* response) {
55    if (!response) {
56      // Must invoke the callback, even if there is no message.
57      base::DictionaryValue empty_dictionary;
58      callback.Run(empty_dictionary);
59      return;
60    }
61    dbus::MessageReader reader(response);
62    scoped_ptr<base::Value> value(dbus::PopDataAsValue(&reader));
63    base::DictionaryValue* dictionary_value = NULL;
64    if (!value.get() || !value->GetAsDictionary(&dictionary_value)) {
65      LOG(WARNING) << "Invalid response: " << response->ToString();
66      base::DictionaryValue empty_dictionary;
67      callback.Run(empty_dictionary);
68      return;
69    }
70    callback.Run(*dictionary_value);
71  }
72
73  dbus::Bus* bus_;
74
75  // Note: This should remain the last member so it'll be destroyed and
76  // invalidate its weak pointers before any other members are destroyed.
77  base::WeakPtrFactory<SMSClientImpl> weak_ptr_factory_;
78
79  DISALLOW_COPY_AND_ASSIGN(SMSClientImpl);
80};
81
82class SMSClientStubImpl : public SMSClient {
83 public:
84  SMSClientStubImpl() : weak_ptr_factory_(this) {}
85  virtual ~SMSClientStubImpl() {}
86
87  virtual void GetAll(const std::string& service_name,
88                      const dbus::ObjectPath& object_path,
89                      const GetAllCallback& callback) OVERRIDE {
90    if (!CommandLine::ForCurrentProcess()->HasSwitch(
91            chromeos::switches::kSmsTestMessages))
92      return;
93
94    // Ownership passed to callback
95    base::DictionaryValue *sms = new base::DictionaryValue();
96    sms->SetString("Number", "000-000-0000");
97    sms->SetString("Text",
98                   "SMSClientStubImpl: Test Message: " + object_path.value());
99    sms->SetString("Timestamp", "Fri Jun  8 13:26:04 EDT 2012");
100
101    // Run callback asynchronously.
102    if (callback.is_null())
103      return;
104    base::MessageLoop::current()->PostTask(
105        FROM_HERE,
106        base::Bind(&SMSClientStubImpl::OnGetAll,
107                   weak_ptr_factory_.GetWeakPtr(),
108                   base::Owned(sms),
109                   callback));
110  }
111
112 private:
113  void OnGetAll(base::DictionaryValue *sms,
114                const GetAllCallback& callback) {
115    callback.Run(*sms);
116  }
117
118  base::WeakPtrFactory<SMSClientStubImpl> weak_ptr_factory_;
119
120  DISALLOW_COPY_AND_ASSIGN(SMSClientStubImpl);
121};
122
123}  // namespace
124
125////////////////////////////////////////////////////////////////////////////////
126// SMSClient
127
128SMSClient::SMSClient() {}
129
130SMSClient::~SMSClient() {}
131
132
133// static
134SMSClient* SMSClient::Create(DBusClientImplementationType type,
135                             dbus::Bus* bus) {
136  if (type == REAL_DBUS_CLIENT_IMPLEMENTATION) {
137    return new SMSClientImpl(bus);
138  }
139  DCHECK_EQ(STUB_DBUS_CLIENT_IMPLEMENTATION, type);
140  return new SMSClientStubImpl();
141}
142
143}  // namespace chromeos
144