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