1// Copyright 2014 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
5#include "chrome/browser/extensions/api/gcd_private/gcd_private_api.h"
6
7#include "base/lazy_instance.h"
8#include "base/memory/linked_ptr.h"
9#include "base/memory/scoped_ptr.h"
10#include "base/memory/scoped_vector.h"
11#include "base/strings/stringprintf.h"
12#include "chrome/browser/local_discovery/cloud_device_list.h"
13#include "chrome/browser/local_discovery/cloud_print_printer_list.h"
14#include "chrome/browser/local_discovery/gcd_api_flow.h"
15#include "chrome/browser/local_discovery/gcd_constants.h"
16#include "chrome/browser/local_discovery/privet_device_lister_impl.h"
17#include "chrome/browser/local_discovery/privet_http_impl.h"
18#include "chrome/browser/local_discovery/privetv3_session.h"
19#include "chrome/browser/local_discovery/service_discovery_shared_client.h"
20#include "chrome/browser/profiles/profile.h"
21#include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
22#include "chrome/browser/signin/signin_manager_factory.h"
23#include "components/signin/core/browser/profile_oauth2_token_service.h"
24#include "components/signin/core/browser/signin_manager.h"
25#include "components/signin/core/browser/signin_manager_base.h"
26#include "extensions/browser/event_router.h"
27#include "net/base/net_util.h"
28
29#if defined(ENABLE_WIFI_BOOTSTRAPPING)
30#include "chrome/browser/local_discovery/wifi/wifi_manager.h"
31#endif
32
33namespace extensions {
34
35namespace gcd_private = api::gcd_private;
36
37namespace {
38
39const int kNumRequestsNeeded = 2;
40
41const char kIDPrefixCloudPrinter[] = "cloudprint:";
42const char kIDPrefixGcd[] = "gcd:";
43const char kIDPrefixMdns[] = "mdns:";
44
45const char kPrivatAPISetup[] = "/privet/v3/setup/start";
46const char kPrivetKeyWifi[] = "wifi";
47const char kPrivetKeyPassphrase[] = "passphrase";
48const char kPrivetKeySSID[] = "ssid";
49const char kPrivetKeyPassphraseDotted[] = "wifi.passphrase";
50
51scoped_ptr<Event> MakeDeviceStateChangedEvent(
52    const gcd_private::GCDDevice& device) {
53  scoped_ptr<base::ListValue> params =
54      gcd_private::OnDeviceStateChanged::Create(device);
55  scoped_ptr<Event> event(
56      new Event(gcd_private::OnDeviceStateChanged::kEventName, params.Pass()));
57  return event.Pass();
58}
59
60scoped_ptr<Event> MakeDeviceRemovedEvent(const std::string& device) {
61  scoped_ptr<base::ListValue> params =
62      gcd_private::OnDeviceRemoved::Create(device);
63  scoped_ptr<Event> event(
64      new Event(gcd_private::OnDeviceRemoved::kEventName, params.Pass()));
65  return event.Pass();
66}
67
68GcdPrivateAPI::GCDApiFlowFactoryForTests* g_gcd_api_flow_factory = NULL;
69
70base::LazyInstance<BrowserContextKeyedAPIFactory<GcdPrivateAPI> > g_factory =
71    LAZY_INSTANCE_INITIALIZER;
72
73scoped_ptr<local_discovery::GCDApiFlow> MakeGCDApiFlow(Profile* profile) {
74  if (g_gcd_api_flow_factory) {
75    return g_gcd_api_flow_factory->CreateGCDApiFlow();
76  }
77
78  ProfileOAuth2TokenService* token_service =
79      ProfileOAuth2TokenServiceFactory::GetForProfile(profile);
80  if (!token_service)
81    return scoped_ptr<local_discovery::GCDApiFlow>();
82  SigninManagerBase* signin_manager =
83      SigninManagerFactory::GetInstance()->GetForProfile(profile);
84  if (!signin_manager)
85    return scoped_ptr<local_discovery::GCDApiFlow>();
86  return local_discovery::GCDApiFlow::Create(
87      profile->GetRequestContext(),
88      token_service,
89      signin_manager->GetAuthenticatedAccountId());
90}
91
92}  // namespace
93
94class GcdPrivateSessionHolder;
95
96class GcdPrivateAPIImpl : public EventRouter::Observer,
97                          public local_discovery::PrivetDeviceLister::Delegate {
98 public:
99  typedef base::Callback<void(bool success)> SuccessCallback;
100
101  typedef base::Callback<void(int session_id,
102                              api::gcd_private::Status status,
103                              const std::string& code,
104                              api::gcd_private::ConfirmationType type)>
105      ConfirmationCodeCallback;
106
107  typedef base::Callback<void(api::gcd_private::Status status)>
108      SessionEstablishedCallback;
109
110  typedef base::Callback<void(api::gcd_private::Status status,
111                              const base::DictionaryValue& response)>
112      MessageResponseCallback;
113
114  explicit GcdPrivateAPIImpl(content::BrowserContext* context);
115  virtual ~GcdPrivateAPIImpl();
116
117  static GcdPrivateAPIImpl* Get(content::BrowserContext* context);
118
119  bool QueryForDevices();
120
121  void EstablishSession(const std::string& ip_address,
122                        int port,
123                        ConfirmationCodeCallback callback);
124
125  void ConfirmCode(int session_id,
126                   const std::string& code,
127                   SessionEstablishedCallback callback);
128
129  void SendMessage(int session_id,
130                   const std::string& api,
131                   const base::DictionaryValue& input,
132                   MessageResponseCallback callback);
133
134  void RequestWifiPassword(const std::string& ssid,
135                           const SuccessCallback& callback);
136
137  void RemoveSession(int session_id);
138
139  scoped_ptr<base::ListValue> GetPrefetchedSSIDList();
140
141 private:
142  typedef std::map<std::string /* id_string */,
143                   linked_ptr<api::gcd_private::GCDDevice> > GCDDeviceMap;
144
145  typedef std::map<int /* session id*/, linked_ptr<GcdPrivateSessionHolder> >
146      GCDSessionMap;
147
148  typedef std::map<std::string /* ssid */, std::string /* password */>
149      PasswordMap;
150
151  // EventRouter::Observer implementation.
152  virtual void OnListenerAdded(const EventListenerInfo& details) OVERRIDE;
153  virtual void OnListenerRemoved(const EventListenerInfo& details) OVERRIDE;
154
155  // local_discovery::PrivetDeviceLister implementation.
156  virtual void DeviceChanged(
157      bool added,
158      const std::string& name,
159      const local_discovery::DeviceDescription& description) OVERRIDE;
160  virtual void DeviceRemoved(const std::string& name) OVERRIDE;
161  virtual void DeviceCacheFlushed() OVERRIDE;
162
163  void SendMessageInternal(int session_id,
164                           const std::string& api,
165                           const base::DictionaryValue& input,
166                           const MessageResponseCallback& callback);
167
168#if defined(ENABLE_WIFI_BOOTSTRAPPING)
169  void OnWifiPassword(const SuccessCallback& callback,
170                      bool success,
171                      const std::string& ssid,
172                      const std::string& password);
173  void StartWifiIfNotStarted();
174#endif
175
176  int num_device_listeners_;
177  scoped_refptr<local_discovery::ServiceDiscoverySharedClient>
178      service_discovery_client_;
179  scoped_ptr<local_discovery::PrivetDeviceLister> privet_device_lister_;
180  GCDDeviceMap known_devices_;
181
182  GCDSessionMap sessions_;
183  int last_session_id_;
184
185  content::BrowserContext* const browser_context_;
186
187#if defined(ENABLE_WIFI_BOOTSTRAPPING)
188  scoped_ptr<local_discovery::wifi::WifiManager> wifi_manager_;
189#endif
190  PasswordMap wifi_passwords_;
191};
192
193class GcdPrivateRequest : public local_discovery::PrivetV3Session::Request {
194 public:
195  GcdPrivateRequest(const std::string& api,
196                    const base::DictionaryValue& input,
197                    const GcdPrivateAPIImpl::MessageResponseCallback& callback,
198                    GcdPrivateSessionHolder* session_holder);
199  virtual ~GcdPrivateRequest();
200
201  // local_discovery::PrivetV3Session::Request implementation.
202  virtual std::string GetName() OVERRIDE;
203  virtual const base::DictionaryValue& GetInput() OVERRIDE;
204  virtual void OnError(
205      local_discovery::PrivetURLFetcher::ErrorType error) OVERRIDE;
206  virtual void OnParsedJson(const base::DictionaryValue& value,
207                            bool has_error) OVERRIDE;
208
209 private:
210  std::string api_;
211  scoped_ptr<base::DictionaryValue> input_;
212  GcdPrivateAPIImpl::MessageResponseCallback callback_;
213  GcdPrivateSessionHolder* session_holder_;
214};
215
216class GcdPrivateSessionHolder
217    : public local_discovery::PrivetV3Session::Delegate {
218 public:
219  typedef base::Callback<void(api::gcd_private::Status status,
220                              const std::string& code,
221                              api::gcd_private::ConfirmationType type)>
222      ConfirmationCodeCallback;
223
224  GcdPrivateSessionHolder(const std::string& ip_address,
225                          int port,
226                          net::URLRequestContextGetter* request_context);
227  virtual ~GcdPrivateSessionHolder();
228
229  void Start(const ConfirmationCodeCallback& callback);
230
231  void ConfirmCode(
232      const std::string& code,
233      const GcdPrivateAPIImpl::SessionEstablishedCallback& callback);
234
235  void SendMessage(const std::string& api,
236                   const base::DictionaryValue& input,
237                   GcdPrivateAPIImpl::MessageResponseCallback callback);
238
239  void DeleteRequest(GcdPrivateRequest* request);
240
241 private:
242  // local_discovery::PrivetV3Session::Delegate implementation.
243  virtual void OnSetupConfirmationNeeded(
244      const std::string& confirmation_code,
245      api::gcd_private::ConfirmationType confirmation_type) OVERRIDE;
246  virtual void OnSessionStatus(api::gcd_private::Status status) OVERRIDE;
247
248  scoped_ptr<local_discovery::PrivetHTTPClient> http_client_;
249  scoped_ptr<local_discovery::PrivetV3Session> privet_session_;
250  typedef ScopedVector<GcdPrivateRequest> RequestVector;
251  RequestVector requests_;
252
253  ConfirmationCodeCallback confirm_callback_;
254  GcdPrivateAPIImpl::SessionEstablishedCallback session_established_callback_;
255};
256
257GcdPrivateAPIImpl::GcdPrivateAPIImpl(content::BrowserContext* context)
258    : num_device_listeners_(0), last_session_id_(0), browser_context_(context) {
259  DCHECK(browser_context_);
260  if (EventRouter::Get(context)) {
261    EventRouter::Get(context)
262        ->RegisterObserver(this, gcd_private::OnDeviceStateChanged::kEventName);
263    EventRouter::Get(context)
264        ->RegisterObserver(this, gcd_private::OnDeviceRemoved::kEventName);
265  }
266}
267
268GcdPrivateAPIImpl::~GcdPrivateAPIImpl() {
269  if (EventRouter::Get(browser_context_)) {
270    EventRouter::Get(browser_context_)->UnregisterObserver(this);
271  }
272}
273
274void GcdPrivateAPIImpl::OnListenerAdded(const EventListenerInfo& details) {
275  if (details.event_name == gcd_private::OnDeviceStateChanged::kEventName ||
276      details.event_name == gcd_private::OnDeviceRemoved::kEventName) {
277    num_device_listeners_++;
278
279    if (num_device_listeners_ == 1) {
280      service_discovery_client_ =
281          local_discovery::ServiceDiscoverySharedClient::GetInstance();
282      privet_device_lister_.reset(new local_discovery::PrivetDeviceListerImpl(
283          service_discovery_client_.get(), this));
284      privet_device_lister_->Start();
285    }
286
287    for (GCDDeviceMap::iterator i = known_devices_.begin();
288         i != known_devices_.end();
289         i++) {
290      EventRouter::Get(browser_context_)->DispatchEventToExtension(
291          details.extension_id, MakeDeviceStateChangedEvent(*i->second));
292    }
293  }
294}
295
296void GcdPrivateAPIImpl::OnListenerRemoved(const EventListenerInfo& details) {
297  if (details.event_name == gcd_private::OnDeviceStateChanged::kEventName ||
298      details.event_name == gcd_private::OnDeviceRemoved::kEventName) {
299    num_device_listeners_--;
300
301    if (num_device_listeners_ == 0) {
302      privet_device_lister_.reset();
303      service_discovery_client_ = NULL;
304    }
305  }
306}
307
308void GcdPrivateAPIImpl::DeviceChanged(
309    bool added,
310    const std::string& name,
311    const local_discovery::DeviceDescription& description) {
312  linked_ptr<gcd_private::GCDDevice> device(new gcd_private::GCDDevice);
313  device->setup_type = gcd_private::SETUP_TYPE_MDNS;
314  device->device_id = kIDPrefixMdns + name;
315  device->device_type = description.type;
316  device->device_name = description.name;
317  device->device_description = description.description;
318  if (!description.id.empty())
319    device->cloud_id.reset(new std::string(description.id));
320
321  known_devices_[device->device_id] = device;
322
323  EventRouter::Get(browser_context_)
324      ->BroadcastEvent(MakeDeviceStateChangedEvent(*device));
325}
326
327void GcdPrivateAPIImpl::DeviceRemoved(const std::string& name) {
328  GCDDeviceMap::iterator found = known_devices_.find(kIDPrefixMdns + name);
329  linked_ptr<gcd_private::GCDDevice> device = found->second;
330  known_devices_.erase(found);
331
332  EventRouter::Get(browser_context_)
333      ->BroadcastEvent(MakeDeviceRemovedEvent(device->device_id));
334}
335
336void GcdPrivateAPIImpl::DeviceCacheFlushed() {
337  for (GCDDeviceMap::iterator i = known_devices_.begin();
338       i != known_devices_.end();
339       i++) {
340    EventRouter::Get(browser_context_)
341        ->BroadcastEvent(MakeDeviceRemovedEvent(i->second->device_id));
342  }
343
344  known_devices_.clear();
345}
346
347// static
348GcdPrivateAPIImpl* GcdPrivateAPIImpl::Get(content::BrowserContext* context) {
349  GcdPrivateAPI* gcd_api =
350      BrowserContextKeyedAPIFactory<GcdPrivateAPI>::Get(context);
351  return gcd_api ? gcd_api->impl_.get() : NULL;
352}
353
354bool GcdPrivateAPIImpl::QueryForDevices() {
355  if (!privet_device_lister_)
356    return false;
357
358  privet_device_lister_->DiscoverNewDevices(true);
359
360  return true;
361}
362
363void GcdPrivateAPIImpl::EstablishSession(const std::string& ip_address,
364                                         int port,
365                                         ConfirmationCodeCallback callback) {
366  int session_id = last_session_id_++;
367  linked_ptr<GcdPrivateSessionHolder> session_handler(
368      new GcdPrivateSessionHolder(
369          ip_address, port, browser_context_->GetRequestContext()));
370  sessions_[session_id] = session_handler;
371  session_handler->Start(base::Bind(callback, session_id));
372}
373
374void GcdPrivateAPIImpl::ConfirmCode(int session_id,
375                                    const std::string& code,
376                                    SessionEstablishedCallback callback) {
377  GCDSessionMap::iterator found = sessions_.find(session_id);
378
379  if (found == sessions_.end()) {
380    callback.Run(gcd_private::STATUS_UNKNOWNSESSIONERROR);
381    return;
382  }
383
384  found->second->ConfirmCode(code, callback);
385}
386
387void GcdPrivateAPIImpl::SendMessage(int session_id,
388                                    const std::string& api,
389                                    const base::DictionaryValue& input,
390                                    MessageResponseCallback callback) {
391  const base::DictionaryValue* input_actual = &input;
392  scoped_ptr<base::DictionaryValue> input_cloned;
393
394  if (api == kPrivatAPISetup) {
395    const base::DictionaryValue* wifi = NULL;
396
397    if (input.GetDictionary(kPrivetKeyWifi, &wifi)) {
398      std::string ssid;
399
400      if (!wifi->GetString(kPrivetKeySSID, &ssid)) {
401        callback.Run(gcd_private::STATUS_SETUPPARSEERROR,
402                     base::DictionaryValue());
403        return;
404      }
405
406      if (!wifi->HasKey(kPrivetKeyPassphrase)) {
407        // If the message is a setup message, has a wifi section, try sending
408        // the passphrase.
409
410        PasswordMap::iterator found = wifi_passwords_.find(ssid);
411        if (found == wifi_passwords_.end()) {
412          callback.Run(gcd_private::STATUS_WIFIPASSWORDERROR,
413                       base::DictionaryValue());
414          return;
415        }
416
417        input_cloned.reset(input.DeepCopy());
418        input_cloned->SetString(kPrivetKeyPassphraseDotted, found->second);
419        input_actual = input_cloned.get();
420      }
421    }
422  }
423
424  GCDSessionMap::iterator found = sessions_.find(session_id);
425
426  if (found == sessions_.end()) {
427    callback.Run(gcd_private::STATUS_UNKNOWNSESSIONERROR,
428                 base::DictionaryValue());
429    return;
430  }
431
432  found->second->SendMessage(api, *input_actual, callback);
433}
434
435void GcdPrivateAPIImpl::RequestWifiPassword(const std::string& ssid,
436                                            const SuccessCallback& callback) {
437#if defined(ENABLE_WIFI_BOOTSTRAPPING)
438  StartWifiIfNotStarted();
439  wifi_manager_->RequestNetworkCredentials(
440      ssid,
441      base::Bind(&GcdPrivateAPIImpl::OnWifiPassword,
442                 base::Unretained(this),
443                 callback));
444#else
445  callback.Run(false);
446#endif
447}
448
449#if defined(ENABLE_WIFI_BOOTSTRAPPING)
450void GcdPrivateAPIImpl::OnWifiPassword(const SuccessCallback& callback,
451                                       bool success,
452                                       const std::string& ssid,
453                                       const std::string& password) {
454  if (success) {
455    wifi_passwords_[ssid] = password;
456  }
457
458  callback.Run(success);
459}
460
461void GcdPrivateAPIImpl::StartWifiIfNotStarted() {
462  if (!wifi_manager_) {
463    wifi_manager_ = local_discovery::wifi::WifiManager::Create();
464    wifi_manager_->Start();
465  }
466}
467
468#endif
469
470void GcdPrivateAPIImpl::RemoveSession(int session_id) {
471  sessions_.erase(session_id);
472}
473
474scoped_ptr<base::ListValue> GcdPrivateAPIImpl::GetPrefetchedSSIDList() {
475  scoped_ptr<base::ListValue> retval(new base::ListValue);
476
477#if defined(ENABLE_WIFI_BOOTSTRAPPING)
478  for (PasswordMap::iterator i = wifi_passwords_.begin();
479       i != wifi_passwords_.end();
480       i++) {
481    retval->AppendString(i->first);
482  }
483#endif
484
485  return retval.Pass();
486}
487
488GcdPrivateRequest::GcdPrivateRequest(
489    const std::string& api,
490    const base::DictionaryValue& input,
491    const GcdPrivateAPIImpl::MessageResponseCallback& callback,
492    GcdPrivateSessionHolder* session_holder)
493    : api_(api),
494      input_(input.DeepCopy()),
495      callback_(callback),
496      session_holder_(session_holder) {
497}
498
499GcdPrivateRequest::~GcdPrivateRequest() {
500}
501
502std::string GcdPrivateRequest::GetName() {
503  return api_;
504}
505
506const base::DictionaryValue& GcdPrivateRequest::GetInput() {
507  return *input_;
508}
509
510void GcdPrivateRequest::OnError(
511    local_discovery::PrivetURLFetcher::ErrorType error) {
512  callback_.Run(gcd_private::STATUS_CONNECTIONERROR, base::DictionaryValue());
513
514  session_holder_->DeleteRequest(this);
515}
516
517void GcdPrivateRequest::OnParsedJson(const base::DictionaryValue& value,
518                                     bool has_error) {
519  callback_.Run(gcd_private::STATUS_SUCCESS, value);
520
521  session_holder_->DeleteRequest(this);
522}
523
524GcdPrivateSessionHolder::GcdPrivateSessionHolder(
525    const std::string& ip_address,
526    int port,
527    net::URLRequestContextGetter* request_context) {
528  std::string host_string;
529  net::IPAddressNumber address_number;
530
531  if (net::ParseIPLiteralToNumber(ip_address, &address_number) &&
532      address_number.size() == net::kIPv6AddressSize) {
533    host_string = base::StringPrintf("[%s]", ip_address.c_str());
534  } else {
535    host_string = ip_address;
536  }
537
538  http_client_.reset(new local_discovery::PrivetHTTPClientImpl(
539      "", net::HostPortPair(host_string, port), request_context));
540}
541
542GcdPrivateSessionHolder::~GcdPrivateSessionHolder() {
543}
544
545void GcdPrivateSessionHolder::Start(const ConfirmationCodeCallback& callback) {
546  confirm_callback_ = callback;
547
548  privet_session_.reset(
549      new local_discovery::PrivetV3Session(http_client_.Pass(), this));
550  privet_session_->Start();
551}
552
553void GcdPrivateSessionHolder::ConfirmCode(
554    const std::string& code,
555    const GcdPrivateAPIImpl::SessionEstablishedCallback& callback) {
556  session_established_callback_ = callback;
557  privet_session_->ConfirmCode(code);
558}
559
560void GcdPrivateSessionHolder::SendMessage(
561    const std::string& api,
562    const base::DictionaryValue& input,
563    GcdPrivateAPIImpl::MessageResponseCallback callback) {
564  GcdPrivateRequest* request =
565      new GcdPrivateRequest(api, input, callback, this);
566  requests_.push_back(request);
567  privet_session_->StartRequest(request);
568}
569
570void GcdPrivateSessionHolder::DeleteRequest(GcdPrivateRequest* request) {
571  // TODO(noamsml): Does this need to be optimized?
572  for (RequestVector::iterator i = requests_.begin(); i != requests_.end();
573       i++) {
574    if (*i == request) {
575      requests_.erase(i);
576      break;
577    }
578  }
579}
580
581void GcdPrivateSessionHolder::OnSetupConfirmationNeeded(
582    const std::string& confirmation_code,
583    gcd_private::ConfirmationType confirmation_type) {
584  confirm_callback_.Run(
585      gcd_private::STATUS_SUCCESS, confirmation_code, confirmation_type);
586
587  confirm_callback_.Reset();
588}
589
590void GcdPrivateSessionHolder::OnSessionStatus(gcd_private::Status status) {
591  session_established_callback_.Run(status);
592
593  session_established_callback_.Reset();
594}
595
596GcdPrivateAPI::GcdPrivateAPI(content::BrowserContext* context)
597    : impl_(new GcdPrivateAPIImpl(context)) {
598}
599
600GcdPrivateAPI::~GcdPrivateAPI() {
601}
602
603// static
604BrowserContextKeyedAPIFactory<GcdPrivateAPI>*
605GcdPrivateAPI::GetFactoryInstance() {
606  return g_factory.Pointer();
607}
608
609// static
610void GcdPrivateAPI::SetGCDApiFlowFactoryForTests(
611    GCDApiFlowFactoryForTests* factory) {
612  g_gcd_api_flow_factory = factory;
613}
614
615GcdPrivateGetCloudDeviceListFunction::GcdPrivateGetCloudDeviceListFunction() {
616}
617
618GcdPrivateGetCloudDeviceListFunction::~GcdPrivateGetCloudDeviceListFunction() {
619}
620
621bool GcdPrivateGetCloudDeviceListFunction::RunAsync() {
622  requests_succeeded_ = 0;
623  requests_failed_ = 0;
624
625  printer_list_ = MakeGCDApiFlow(GetProfile());
626  device_list_ = MakeGCDApiFlow(GetProfile());
627
628  if (!printer_list_ || !device_list_)
629    return false;
630
631  // Balanced in CheckListingDone()
632  AddRef();
633
634  printer_list_->Start(make_scoped_ptr<local_discovery::GCDApiFlow::Request>(
635      new local_discovery::CloudPrintPrinterList(this)));
636  device_list_->Start(make_scoped_ptr<local_discovery::GCDApiFlow::Request>(
637      new local_discovery::CloudDeviceList(this)));
638
639  return true;
640}
641
642void GcdPrivateGetCloudDeviceListFunction::OnDeviceListReady(
643    const DeviceList& devices) {
644  requests_succeeded_++;
645
646  devices_.insert(devices_.end(), devices.begin(), devices.end());
647
648  CheckListingDone();
649}
650
651void GcdPrivateGetCloudDeviceListFunction::OnDeviceListUnavailable() {
652  requests_failed_++;
653
654  CheckListingDone();
655}
656
657void GcdPrivateGetCloudDeviceListFunction::CheckListingDone() {
658  if (requests_failed_ + requests_succeeded_ != kNumRequestsNeeded)
659    return;
660
661  if (requests_succeeded_ == 0) {
662    SendResponse(false);
663    return;
664  }
665
666  std::vector<linked_ptr<gcd_private::GCDDevice> > devices;
667
668  for (DeviceList::iterator i = devices_.begin(); i != devices_.end(); i++) {
669    linked_ptr<gcd_private::GCDDevice> device(new gcd_private::GCDDevice);
670    device->setup_type = gcd_private::SETUP_TYPE_CLOUD;
671    if (i->type == local_discovery::kGCDTypePrinter) {
672      device->device_id = kIDPrefixCloudPrinter + i->id;
673    } else {
674      device->device_id = kIDPrefixGcd + i->id;
675    }
676
677    device->cloud_id.reset(new std::string(i->id));
678    device->device_type = i->type;
679    device->device_name = i->display_name;
680    device->device_description = i->description;
681
682    devices.push_back(device);
683  }
684
685  results_ = gcd_private::GetCloudDeviceList::Results::Create(devices);
686
687  SendResponse(true);
688  Release();
689}
690
691GcdPrivateQueryForNewLocalDevicesFunction::
692    GcdPrivateQueryForNewLocalDevicesFunction() {
693}
694
695GcdPrivateQueryForNewLocalDevicesFunction::
696    ~GcdPrivateQueryForNewLocalDevicesFunction() {
697}
698
699bool GcdPrivateQueryForNewLocalDevicesFunction::RunSync() {
700  GcdPrivateAPIImpl* gcd_api = GcdPrivateAPIImpl::Get(GetProfile());
701
702  if (!gcd_api->QueryForDevices()) {
703    error_ =
704        "You must first subscribe to onDeviceStateChanged or onDeviceRemoved "
705        "notifications";
706    return false;
707  }
708
709  return true;
710}
711
712GcdPrivatePrefetchWifiPasswordFunction::
713    GcdPrivatePrefetchWifiPasswordFunction() {
714}
715
716GcdPrivatePrefetchWifiPasswordFunction::
717    ~GcdPrivatePrefetchWifiPasswordFunction() {
718}
719
720bool GcdPrivatePrefetchWifiPasswordFunction::RunAsync() {
721  scoped_ptr<gcd_private::PrefetchWifiPassword::Params> params =
722      gcd_private::PrefetchWifiPassword::Params::Create(*args_);
723
724  if (!params)
725    return false;
726
727  GcdPrivateAPIImpl* gcd_api = GcdPrivateAPIImpl::Get(GetProfile());
728
729  gcd_api->RequestWifiPassword(
730      params->ssid,
731      base::Bind(&GcdPrivatePrefetchWifiPasswordFunction::OnResponse, this));
732
733  return true;
734}
735
736void GcdPrivatePrefetchWifiPasswordFunction::OnResponse(bool response) {
737  scoped_ptr<base::FundamentalValue> response_value(
738      new base::FundamentalValue(response));
739  SetResult(response_value.release());
740  SendResponse(true);
741}
742
743GcdPrivateEstablishSessionFunction::GcdPrivateEstablishSessionFunction() {
744}
745
746GcdPrivateEstablishSessionFunction::~GcdPrivateEstablishSessionFunction() {
747}
748
749bool GcdPrivateEstablishSessionFunction::RunAsync() {
750  scoped_ptr<gcd_private::EstablishSession::Params> params =
751      gcd_private::EstablishSession::Params::Create(*args_);
752
753  if (!params)
754    return false;
755
756  GcdPrivateAPIImpl* gcd_api = GcdPrivateAPIImpl::Get(GetProfile());
757
758  gcd_api->EstablishSession(
759      params->ip_address,
760      params->port,
761      base::Bind(&GcdPrivateEstablishSessionFunction::OnConfirmCodeCallback,
762                 this));
763
764  return true;
765}
766
767void GcdPrivateEstablishSessionFunction::OnConfirmCodeCallback(
768    int session_id,
769    gcd_private::Status status,
770    const std::string& confirm_code,
771    gcd_private::ConfirmationType confirmation_type) {
772  gcd_private::ConfirmationInfo info;
773
774  info.type = confirmation_type;
775  if (!confirm_code.empty()) {
776    info.code.reset(new std::string(confirm_code));
777  }
778
779  results_ =
780      gcd_private::EstablishSession::Results::Create(session_id, status, info);
781  SendResponse(true);
782}
783
784GcdPrivateConfirmCodeFunction::GcdPrivateConfirmCodeFunction() {
785}
786
787GcdPrivateConfirmCodeFunction::~GcdPrivateConfirmCodeFunction() {
788}
789
790bool GcdPrivateConfirmCodeFunction::RunAsync() {
791  scoped_ptr<gcd_private::ConfirmCode::Params> params =
792      gcd_private::ConfirmCode::Params::Create(*args_);
793
794  if (!params)
795    return false;
796
797  GcdPrivateAPIImpl* gcd_api = GcdPrivateAPIImpl::Get(GetProfile());
798
799  gcd_api->ConfirmCode(
800      params->session_id,
801      params->code,
802      base::Bind(&GcdPrivateConfirmCodeFunction::OnSessionEstablishedCallback,
803                 this));
804
805  return true;
806}
807
808void GcdPrivateConfirmCodeFunction::OnSessionEstablishedCallback(
809    api::gcd_private::Status status) {
810  results_ = gcd_private::ConfirmCode::Results::Create(status);
811  SendResponse(true);
812}
813
814GcdPrivateSendMessageFunction::GcdPrivateSendMessageFunction() {
815}
816
817GcdPrivateSendMessageFunction::~GcdPrivateSendMessageFunction() {
818}
819
820bool GcdPrivateSendMessageFunction::RunAsync() {
821  scoped_ptr<gcd_private::PassMessage::Params> params =
822      gcd_private::PassMessage::Params::Create(*args_);
823
824  if (!params)
825    return false;
826
827  GcdPrivateAPIImpl* gcd_api = GcdPrivateAPIImpl::Get(GetProfile());
828
829
830  gcd_api->SendMessage(
831      params->session_id,
832      params->api,
833      params->input.additional_properties,
834      base::Bind(&GcdPrivateSendMessageFunction::OnMessageSentCallback, this));
835
836  return true;
837}
838
839void GcdPrivateSendMessageFunction::OnMessageSentCallback(
840    api::gcd_private::Status status,
841    const base::DictionaryValue& value) {
842  gcd_private::PassMessage::Results::Response response;
843  response.additional_properties.MergeDictionary(&value);
844
845  results_ = gcd_private::PassMessage::Results::Create(status, response);
846  SendResponse(true);
847}
848
849GcdPrivateTerminateSessionFunction::GcdPrivateTerminateSessionFunction() {
850}
851
852GcdPrivateTerminateSessionFunction::~GcdPrivateTerminateSessionFunction() {
853}
854
855bool GcdPrivateTerminateSessionFunction::RunAsync() {
856  scoped_ptr<gcd_private::TerminateSession::Params> params =
857      gcd_private::TerminateSession::Params::Create(*args_);
858
859  if (!params)
860    return false;
861
862  GcdPrivateAPIImpl* gcd_api = GcdPrivateAPIImpl::Get(GetProfile());
863
864  gcd_api->RemoveSession(params->session_id);
865
866  SendResponse(true);
867  return true;
868}
869
870GcdPrivateGetCommandDefinitionsFunction::
871    GcdPrivateGetCommandDefinitionsFunction() {
872}
873
874GcdPrivateGetCommandDefinitionsFunction::
875    ~GcdPrivateGetCommandDefinitionsFunction() {
876}
877
878GcdPrivateGetPrefetchedWifiNameListFunction::
879    GcdPrivateGetPrefetchedWifiNameListFunction() {
880}
881
882GcdPrivateGetPrefetchedWifiNameListFunction::
883    ~GcdPrivateGetPrefetchedWifiNameListFunction() {
884}
885
886bool GcdPrivateGetPrefetchedWifiNameListFunction::RunSync() {
887  GcdPrivateAPIImpl* gcd_api = GcdPrivateAPIImpl::Get(GetProfile());
888
889  scoped_ptr<base::ListValue> ssid_list = gcd_api->GetPrefetchedSSIDList();
890
891  SetResult(ssid_list.release());
892
893  return true;
894}
895
896bool GcdPrivateGetCommandDefinitionsFunction::RunAsync() {
897  return false;
898}
899
900GcdPrivateInsertCommandFunction::GcdPrivateInsertCommandFunction() {
901}
902
903GcdPrivateInsertCommandFunction::~GcdPrivateInsertCommandFunction() {
904}
905
906bool GcdPrivateInsertCommandFunction::RunAsync() {
907  return false;
908}
909
910GcdPrivateGetCommandFunction::GcdPrivateGetCommandFunction() {
911}
912
913GcdPrivateGetCommandFunction::~GcdPrivateGetCommandFunction() {
914}
915
916bool GcdPrivateGetCommandFunction::RunAsync() {
917  return false;
918}
919
920GcdPrivateCancelCommandFunction::GcdPrivateCancelCommandFunction() {
921}
922
923GcdPrivateCancelCommandFunction::~GcdPrivateCancelCommandFunction() {
924}
925
926bool GcdPrivateCancelCommandFunction::RunAsync() {
927  return false;
928}
929
930GcdPrivateGetCommandsListFunction::GcdPrivateGetCommandsListFunction() {
931}
932
933GcdPrivateGetCommandsListFunction::~GcdPrivateGetCommandsListFunction() {
934}
935
936bool GcdPrivateGetCommandsListFunction::RunAsync() {
937  return false;
938}
939
940}  // namespace extensions
941