Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / extensions / api / gcd_private / gcd_private_api.cc
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
33 namespace extensions {
34
35 namespace gcd_private = api::gcd_private;
36
37 namespace {
38
39 const int kNumRequestsNeeded = 2;
40
41 const char kIDPrefixCloudPrinter[] = "cloudprint:";
42 const char kIDPrefixGcd[] = "gcd:";
43 const char kIDPrefixMdns[] = "mdns:";
44
45 const char kPrivatAPISetup[] = "/privet/v3/setup/start";
46 const char kPrivetKeyWifi[] = "wifi";
47 const char kPrivetKeyPassphrase[] = "passphrase";
48 const char kPrivetKeySSID[] = "ssid";
49 const char kPrivetKeyPassphraseDotted[] = "wifi.passphrase";
50
51 scoped_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
60 scoped_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
68 GcdPrivateAPI::GCDApiFlowFactoryForTests* g_gcd_api_flow_factory = NULL;
69
70 base::LazyInstance<BrowserContextKeyedAPIFactory<GcdPrivateAPI> > g_factory =
71     LAZY_INSTANCE_INITIALIZER;
72
73 scoped_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
94 class GcdPrivateSessionHolder;
95
96 class 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
193 class 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
216 class 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
257 GcdPrivateAPIImpl::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
268 GcdPrivateAPIImpl::~GcdPrivateAPIImpl() {
269   if (EventRouter::Get(browser_context_)) {
270     EventRouter::Get(browser_context_)->UnregisterObserver(this);
271   }
272 }
273
274 void 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
296 void 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
308 void 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
327 void 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
336 void 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
348 GcdPrivateAPIImpl* 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
354 bool GcdPrivateAPIImpl::QueryForDevices() {
355   if (!privet_device_lister_)
356     return false;
357
358   privet_device_lister_->DiscoverNewDevices(true);
359
360   return true;
361 }
362
363 void 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
374 void 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
387 void 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
435 void 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)
450 void 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
461 void GcdPrivateAPIImpl::StartWifiIfNotStarted() {
462   if (!wifi_manager_) {
463     wifi_manager_ = local_discovery::wifi::WifiManager::Create();
464     wifi_manager_->Start();
465   }
466 }
467
468 #endif
469
470 void GcdPrivateAPIImpl::RemoveSession(int session_id) {
471   sessions_.erase(session_id);
472 }
473
474 scoped_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
488 GcdPrivateRequest::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
499 GcdPrivateRequest::~GcdPrivateRequest() {
500 }
501
502 std::string GcdPrivateRequest::GetName() {
503   return api_;
504 }
505
506 const base::DictionaryValue& GcdPrivateRequest::GetInput() {
507   return *input_;
508 }
509
510 void 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
517 void 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
524 GcdPrivateSessionHolder::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
542 GcdPrivateSessionHolder::~GcdPrivateSessionHolder() {
543 }
544
545 void 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
553 void GcdPrivateSessionHolder::ConfirmCode(
554     const std::string& code,
555     const GcdPrivateAPIImpl::SessionEstablishedCallback& callback) {
556   session_established_callback_ = callback;
557   privet_session_->ConfirmCode(code);
558 }
559
560 void 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
570 void 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
581 void 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
590 void GcdPrivateSessionHolder::OnSessionStatus(gcd_private::Status status) {
591   session_established_callback_.Run(status);
592
593   session_established_callback_.Reset();
594 }
595
596 GcdPrivateAPI::GcdPrivateAPI(content::BrowserContext* context)
597     : impl_(new GcdPrivateAPIImpl(context)) {
598 }
599
600 GcdPrivateAPI::~GcdPrivateAPI() {
601 }
602
603 // static
604 BrowserContextKeyedAPIFactory<GcdPrivateAPI>*
605 GcdPrivateAPI::GetFactoryInstance() {
606   return g_factory.Pointer();
607 }
608
609 // static
610 void GcdPrivateAPI::SetGCDApiFlowFactoryForTests(
611     GCDApiFlowFactoryForTests* factory) {
612   g_gcd_api_flow_factory = factory;
613 }
614
615 GcdPrivateGetCloudDeviceListFunction::GcdPrivateGetCloudDeviceListFunction() {
616 }
617
618 GcdPrivateGetCloudDeviceListFunction::~GcdPrivateGetCloudDeviceListFunction() {
619 }
620
621 bool 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
642 void GcdPrivateGetCloudDeviceListFunction::OnDeviceListReady(
643     const DeviceList& devices) {
644   requests_succeeded_++;
645
646   devices_.insert(devices_.end(), devices.begin(), devices.end());
647
648   CheckListingDone();
649 }
650
651 void GcdPrivateGetCloudDeviceListFunction::OnDeviceListUnavailable() {
652   requests_failed_++;
653
654   CheckListingDone();
655 }
656
657 void 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
691 GcdPrivateQueryForNewLocalDevicesFunction::
692     GcdPrivateQueryForNewLocalDevicesFunction() {
693 }
694
695 GcdPrivateQueryForNewLocalDevicesFunction::
696     ~GcdPrivateQueryForNewLocalDevicesFunction() {
697 }
698
699 bool 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
712 GcdPrivatePrefetchWifiPasswordFunction::
713     GcdPrivatePrefetchWifiPasswordFunction() {
714 }
715
716 GcdPrivatePrefetchWifiPasswordFunction::
717     ~GcdPrivatePrefetchWifiPasswordFunction() {
718 }
719
720 bool 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
736 void 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
743 GcdPrivateEstablishSessionFunction::GcdPrivateEstablishSessionFunction() {
744 }
745
746 GcdPrivateEstablishSessionFunction::~GcdPrivateEstablishSessionFunction() {
747 }
748
749 bool 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
767 void 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
784 GcdPrivateConfirmCodeFunction::GcdPrivateConfirmCodeFunction() {
785 }
786
787 GcdPrivateConfirmCodeFunction::~GcdPrivateConfirmCodeFunction() {
788 }
789
790 bool 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
808 void GcdPrivateConfirmCodeFunction::OnSessionEstablishedCallback(
809     api::gcd_private::Status status) {
810   results_ = gcd_private::ConfirmCode::Results::Create(status);
811   SendResponse(true);
812 }
813
814 GcdPrivateSendMessageFunction::GcdPrivateSendMessageFunction() {
815 }
816
817 GcdPrivateSendMessageFunction::~GcdPrivateSendMessageFunction() {
818 }
819
820 bool 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
839 void 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
849 GcdPrivateTerminateSessionFunction::GcdPrivateTerminateSessionFunction() {
850 }
851
852 GcdPrivateTerminateSessionFunction::~GcdPrivateTerminateSessionFunction() {
853 }
854
855 bool 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
870 GcdPrivateGetCommandDefinitionsFunction::
871     GcdPrivateGetCommandDefinitionsFunction() {
872 }
873
874 GcdPrivateGetCommandDefinitionsFunction::
875     ~GcdPrivateGetCommandDefinitionsFunction() {
876 }
877
878 GcdPrivateGetPrefetchedWifiNameListFunction::
879     GcdPrivateGetPrefetchedWifiNameListFunction() {
880 }
881
882 GcdPrivateGetPrefetchedWifiNameListFunction::
883     ~GcdPrivateGetPrefetchedWifiNameListFunction() {
884 }
885
886 bool 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
896 bool GcdPrivateGetCommandDefinitionsFunction::RunAsync() {
897   return false;
898 }
899
900 GcdPrivateInsertCommandFunction::GcdPrivateInsertCommandFunction() {
901 }
902
903 GcdPrivateInsertCommandFunction::~GcdPrivateInsertCommandFunction() {
904 }
905
906 bool GcdPrivateInsertCommandFunction::RunAsync() {
907   return false;
908 }
909
910 GcdPrivateGetCommandFunction::GcdPrivateGetCommandFunction() {
911 }
912
913 GcdPrivateGetCommandFunction::~GcdPrivateGetCommandFunction() {
914 }
915
916 bool GcdPrivateGetCommandFunction::RunAsync() {
917   return false;
918 }
919
920 GcdPrivateCancelCommandFunction::GcdPrivateCancelCommandFunction() {
921 }
922
923 GcdPrivateCancelCommandFunction::~GcdPrivateCancelCommandFunction() {
924 }
925
926 bool GcdPrivateCancelCommandFunction::RunAsync() {
927   return false;
928 }
929
930 GcdPrivateGetCommandsListFunction::GcdPrivateGetCommandsListFunction() {
931 }
932
933 GcdPrivateGetCommandsListFunction::~GcdPrivateGetCommandsListFunction() {
934 }
935
936 bool GcdPrivateGetCommandsListFunction::RunAsync() {
937   return false;
938 }
939
940 }  // namespace extensions