15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/service/cloud_print/cloud_print_proxy_backend.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <map>
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <vector>
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/command_line.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/compiler_specific.h"
130f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)#include "base/metrics/histogram.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/rand_util.h"
156e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#include "base/strings/string_util.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/values.h"
172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/common/cloud_print/cloud_print_constants.h"
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/service/cloud_print/cloud_print_auth.h"
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/service/cloud_print/cloud_print_connector.h"
20f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "chrome/service/cloud_print/cloud_print_service_helpers.h"
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/service/cloud_print/cloud_print_token_store.h"
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/service/cloud_print/connector_settings.h"
23116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "chrome/service/net/service_url_request_context_getter.h"
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/service/service_process.h"
250529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch#include "components/cloud_devices/common/cloud_devices_switches.h"
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "google_apis/gaia/gaia_oauth_client.h"
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "google_apis/gaia/gaia_urls.h"
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "jingle/notifier/base/notifier_options.h"
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "jingle/notifier/listener/push_client.h"
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "jingle/notifier/listener/push_client_observer.h"
317dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "url/gurl.h"
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace cloud_print {
342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The real guts of CloudPrintProxyBackend, to keep the public client API clean.
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class CloudPrintProxyBackend::Core
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : public base::RefCountedThreadSafe<CloudPrintProxyBackend::Core>,
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      public CloudPrintAuth::Client,
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      public CloudPrintConnector::Client,
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      public notifier::PushClientObserver {
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // It is OK for print_server_url to be empty. In this case system should
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // use system default (local) print server.
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Core(CloudPrintProxyBackend* backend,
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       const ConnectorSettings& settings,
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       const gaia::OAuthClientInfo& oauth_client_info,
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       bool enable_job_poll);
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Note:
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The Do* methods are the various entry points from CloudPrintProxyBackend
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // It calls us on a dedicated thread to actually perform synchronous
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // (and potentially blocking) operations.
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void DoInitializeWithToken(const std::string& cloud_print_token);
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void DoInitializeWithRobotToken(const std::string& robot_oauth_refresh_token,
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                  const std::string& robot_email);
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void DoInitializeWithRobotAuthCode(const std::string& robot_oauth_auth_code,
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                     const std::string& robot_email);
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Called on the CloudPrintProxyBackend core_thread_ to perform
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // shutdown.
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void DoShutdown();
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void DoRegisterSelectedPrinters(
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      const printing::PrinterList& printer_list);
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void DoUnregisterPrinters();
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // CloudPrintAuth::Client implementation.
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void OnAuthenticationComplete(
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      const std::string& access_token,
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      const std::string& robot_oauth_refresh_token,
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      const std::string& robot_email,
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      const std::string& user_email) OVERRIDE;
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void OnInvalidCredentials() OVERRIDE;
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // CloudPrintConnector::Client implementation.
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void OnAuthFailed() OVERRIDE;
7768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  virtual void OnXmppPingUpdated(int ping_timeout) OVERRIDE;
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // notifier::PushClientObserver implementation.
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void OnNotificationsEnabled() OVERRIDE;
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void OnNotificationsDisabled(
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      notifier::NotificationsDisabledReason reason) OVERRIDE;
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void OnIncomingNotification(
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      const notifier::Notification& notification) OVERRIDE;
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void OnPingResponse() OVERRIDE;
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  friend class base::RefCountedThreadSafe<Core>;
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual ~Core() {}
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void CreateAuthAndConnector();
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void DestroyAuthAndConnector();
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // NotifyXXX is how the Core communicates with the frontend across
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // threads.
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void NotifyPrinterListAvailable(
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      const printing::PrinterList& printer_list);
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void NotifyAuthenticated(
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& robot_oauth_refresh_token,
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& robot_email,
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& user_email);
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void NotifyAuthenticationFailed();
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void NotifyPrintSystemUnavailable();
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void NotifyUnregisterPrinters(const std::string& auth_token,
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                const std::list<std::string>& printer_ids);
10768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  void NotifyXmppPingUpdated(int ping_timeout);
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Init XMPP channel
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void InitNotifications(const std::string& robot_email,
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         const std::string& access_token);
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  void HandlePrinterNotification(const std::string& notification);
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void PollForJobs();
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Schedules a task to poll for jobs. Does nothing if a task is already
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // scheduled.
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void ScheduleJobPoll();
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void PingXmppServer();
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void ScheduleXmppPing();
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void CheckXmppPingStatus();
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CloudPrintTokenStore* GetTokenStore();
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Our parent CloudPrintProxyBackend
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CloudPrintProxyBackend* backend_;
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Cloud Print authenticator.
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_refptr<CloudPrintAuth> auth_;
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Cloud Print connector.
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_refptr<CloudPrintConnector> connector_;
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // OAuth client info.
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gaia::OAuthClientInfo oauth_client_info_;
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Notification (xmpp) handler.
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<notifier::PushClient> push_client_;
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Indicates whether XMPP notifications are currently enabled.
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool notifications_enabled_;
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The time when notifications were enabled. Valid only when
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // notifications_enabled_ is true.
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::TimeTicks notifications_enabled_since_;
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Indicates whether a task to poll for jobs has been scheduled.
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool job_poll_scheduled_;
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Indicates whether we should poll for jobs when we lose XMPP connection.
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool enable_job_poll_;
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Indicates whether a task to ping xmpp server has been scheduled.
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool xmpp_ping_scheduled_;
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Number of XMPP pings pending reply from the server.
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int pending_xmpp_pings_;
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Connector settings.
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ConnectorSettings settings_;
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string robot_email_;
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<CloudPrintTokenStore> token_store_;
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(Core);
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)CloudPrintProxyBackend::CloudPrintProxyBackend(
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CloudPrintProxyFrontend* frontend,
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const ConnectorSettings& settings,
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const gaia::OAuthClientInfo& oauth_client_info,
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool enable_job_poll)
163a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    : core_thread_("Chrome_CloudPrintProxyCoreThread"),
164a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      frontend_loop_(base::MessageLoop::current()),
165a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      frontend_(frontend) {
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(frontend_);
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  core_ = new Core(this, settings, oauth_client_info, enable_job_poll);
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
170868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)CloudPrintProxyBackend::~CloudPrintProxyBackend() { DCHECK(!core_.get()); }
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool CloudPrintProxyBackend::InitializeWithToken(
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& cloud_print_token) {
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!core_thread_.Start())
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  core_thread_.message_loop()->PostTask(
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      FROM_HERE,
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(&CloudPrintProxyBackend::Core::DoInitializeWithToken,
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 core_.get(), cloud_print_token));
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool CloudPrintProxyBackend::InitializeWithRobotToken(
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& robot_oauth_refresh_token,
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& robot_email) {
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!core_thread_.Start())
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  core_thread_.message_loop()->PostTask(
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      FROM_HERE,
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(&CloudPrintProxyBackend::Core::DoInitializeWithRobotToken,
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 core_.get(), robot_oauth_refresh_token, robot_email));
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool CloudPrintProxyBackend::InitializeWithRobotAuthCode(
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& robot_oauth_auth_code,
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& robot_email) {
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!core_thread_.Start())
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  core_thread_.message_loop()->PostTask(
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      FROM_HERE,
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(&CloudPrintProxyBackend::Core::DoInitializeWithRobotAuthCode,
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 core_.get(), robot_oauth_auth_code, robot_email));
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CloudPrintProxyBackend::Shutdown() {
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  core_thread_.message_loop()->PostTask(
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      FROM_HERE,
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(&CloudPrintProxyBackend::Core::DoShutdown, core_.get()));
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  core_thread_.Stop();
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  core_ = NULL;  // Releases reference to core_.
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CloudPrintProxyBackend::UnregisterPrinters() {
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  core_thread_.message_loop()->PostTask(
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      FROM_HERE,
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(&CloudPrintProxyBackend::Core::DoUnregisterPrinters,
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 core_.get()));
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)CloudPrintProxyBackend::Core::Core(
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CloudPrintProxyBackend* backend,
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const ConnectorSettings& settings,
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const gaia::OAuthClientInfo& oauth_client_info,
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool enable_job_poll)
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      : backend_(backend),
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        oauth_client_info_(oauth_client_info),
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        notifications_enabled_(false),
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        job_poll_scheduled_(false),
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        enable_job_poll_(enable_job_poll),
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        xmpp_ping_scheduled_(false),
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        pending_xmpp_pings_(0) {
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  settings_.CopyFrom(settings);
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CloudPrintProxyBackend::Core::CreateAuthAndConnector() {
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!auth_.get()) {
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    auth_ = new CloudPrintAuth(this, settings_.server_url(), oauth_client_info_,
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               settings_.proxy_id());
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!connector_.get()) {
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    connector_ = new CloudPrintConnector(this, settings_);
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CloudPrintProxyBackend::Core::DestroyAuthAndConnector() {
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  auth_ = NULL;
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  connector_ = NULL;
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CloudPrintProxyBackend::Core::DoInitializeWithToken(
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& cloud_print_token) {
255a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  DCHECK(base::MessageLoop::current() == backend_->core_thread_.message_loop());
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CreateAuthAndConnector();
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  auth_->AuthenticateWithToken(cloud_print_token);
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CloudPrintProxyBackend::Core::DoInitializeWithRobotToken(
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& robot_oauth_refresh_token,
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& robot_email) {
263a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  DCHECK(base::MessageLoop::current() == backend_->core_thread_.message_loop());
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CreateAuthAndConnector();
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  auth_->AuthenticateWithRobotToken(robot_oauth_refresh_token, robot_email);
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CloudPrintProxyBackend::Core::DoInitializeWithRobotAuthCode(
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& robot_oauth_auth_code,
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& robot_email) {
271a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  DCHECK(base::MessageLoop::current() == backend_->core_thread_.message_loop());
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CreateAuthAndConnector();
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  auth_->AuthenticateWithRobotAuthCode(robot_oauth_auth_code, robot_email);
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CloudPrintProxyBackend::Core::OnAuthenticationComplete(
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& access_token,
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& robot_oauth_refresh_token,
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& robot_email,
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& user_email) {
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CloudPrintTokenStore* token_store  = GetTokenStore();
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool first_time = token_store->token().empty();
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  token_store->SetToken(access_token);
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  robot_email_ = robot_email;
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Let the frontend know that we have authenticated.
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  backend_->frontend_loop_->PostTask(
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      FROM_HERE,
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(&Core::NotifyAuthenticated, this, robot_oauth_refresh_token,
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 robot_email, user_email));
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (first_time) {
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    InitNotifications(robot_email, access_token);
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // If we are refreshing a token, update the XMPP token too.
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(push_client_.get());
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    push_client_->UpdateCredentials(robot_email, access_token);
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Start cloud print connector if needed.
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!connector_->IsRunning()) {
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!connector_->Start()) {
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Let the frontend know that we do not have a print system.
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      backend_->frontend_loop_->PostTask(
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          FROM_HERE, base::Bind(&Core::NotifyPrintSystemUnavailable, this));
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CloudPrintProxyBackend::Core::OnInvalidCredentials() {
308a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  DCHECK(base::MessageLoop::current() == backend_->core_thread_.message_loop());
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VLOG(1) << "CP_CONNECTOR: Auth Error";
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  backend_->frontend_loop_->PostTask(
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      FROM_HERE, base::Bind(&Core::NotifyAuthenticationFailed, this));
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CloudPrintProxyBackend::Core::OnAuthFailed() {
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VLOG(1) << "CP_CONNECTOR: Authentication failed in connector.";
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Let's stop connecter and refresh token. We'll restart connecter once
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // new token available.
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (connector_->IsRunning())
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    connector_->Stop();
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Refresh Auth token.
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  auth_->RefreshAccessToken();
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
32568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)void CloudPrintProxyBackend::Core::OnXmppPingUpdated(int ping_timeout) {
32668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  settings_.SetXmppPingTimeoutSec(ping_timeout);
32768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  backend_->frontend_loop_->PostTask(
32868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      FROM_HERE,
32968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      base::Bind(&Core::NotifyXmppPingUpdated, this, ping_timeout));
33068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)}
33168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CloudPrintProxyBackend::Core::InitNotifications(
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& robot_email,
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& access_token) {
335a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  DCHECK(base::MessageLoop::current() == backend_->core_thread_.message_loop());
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pending_xmpp_pings_ = 0;
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  notifier::NotifierOptions notifier_options;
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  notifier_options.request_context_getter =
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      g_service_process->GetServiceURLRequestContextGetter();
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  notifier_options.auth_mechanism = "X-OAUTH2";
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  notifier_options.try_ssltcp_first = true;
3430529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  notifier_options.xmpp_host_port = net::HostPortPair::FromString(
3440529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
3450529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch          switches::kCloudPrintXmppEndpoint));
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  push_client_ = notifier::PushClient::CreateDefault(notifier_options);
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  push_client_->AddObserver(this);
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  notifier::Subscription subscription;
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  subscription.channel = kCloudPrintPushNotificationsSource;
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  subscription.from = kCloudPrintPushNotificationsSource;
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  push_client_->UpdateSubscriptions(
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      notifier::SubscriptionList(1, subscription));
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  push_client_->UpdateCredentials(robot_email, access_token);
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CloudPrintProxyBackend::Core::DoShutdown() {
357a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  DCHECK(base::MessageLoop::current() == backend_->core_thread_.message_loop());
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VLOG(1) << "CP_CONNECTOR: Shutdown connector, id: " << settings_.proxy_id();
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (connector_->IsRunning())
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    connector_->Stop();
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Important to delete the PushClient on this thread.
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (push_client_.get()) {
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    push_client_->RemoveObserver(this);
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  push_client_.reset();
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  notifications_enabled_ = false;
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  notifications_enabled_since_ = base::TimeTicks();
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  token_store_.reset();
3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DestroyAuthAndConnector();
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CloudPrintProxyBackend::Core::DoUnregisterPrinters() {
376a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  DCHECK(base::MessageLoop::current() == backend_->core_thread_.message_loop());
3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string access_token = GetTokenStore()->token();
3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::list<std::string> printer_ids;
3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  connector_->GetPrinterIds(&printer_ids);
3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  backend_->frontend_loop_->PostTask(
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      FROM_HERE,
3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(&Core::NotifyUnregisterPrinters,
3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 this, access_token, printer_ids));
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CloudPrintProxyBackend::Core::HandlePrinterNotification(
39068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    const std::string& notification) {
391a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  DCHECK(base::MessageLoop::current() == backend_->core_thread_.message_loop());
39268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
39368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  size_t pos = notification.rfind(kNotificationUpdateSettings);
39468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  if (pos == std::string::npos) {
39568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    VLOG(1) << "CP_CONNECTOR: Handle printer notification, id: "
39668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)            << notification;
39768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    connector_->CheckForJobs(kJobFetchReasonNotified, notification);
39868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  } else {
39968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    DCHECK(pos == notification.length() - strlen(kNotificationUpdateSettings));
40068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    std::string printer_id = notification.substr(0, pos);
40168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    VLOG(1) << "CP_CONNECTOR: Update printer settings, id: " << printer_id;
40268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    connector_->UpdatePrinterSettings(printer_id);
40368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  }
4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CloudPrintProxyBackend::Core::PollForJobs() {
4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VLOG(1) << "CP_CONNECTOR: Polling for jobs.";
408a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  DCHECK(base::MessageLoop::current() == backend_->core_thread_.message_loop());
4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Check all printers for jobs.
4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  connector_->CheckForJobs(kJobFetchReasonPoll, std::string());
4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  job_poll_scheduled_ = false;
4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If we don't have notifications and job polling is enabled, poll again
4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // after a while.
4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!notifications_enabled_ && enable_job_poll_)
4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ScheduleJobPoll();
4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CloudPrintProxyBackend::Core::ScheduleJobPoll() {
4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!job_poll_scheduled_) {
4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::TimeDelta interval = base::TimeDelta::FromSeconds(
4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        base::RandInt(kMinJobPollIntervalSecs, kMaxJobPollIntervalSecs));
423a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    base::MessageLoop::current()->PostDelayedTask(
4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        FROM_HERE,
4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        base::Bind(&CloudPrintProxyBackend::Core::PollForJobs, this),
4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        interval);
4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    job_poll_scheduled_ = true;
4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CloudPrintProxyBackend::Core::PingXmppServer() {
4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  xmpp_ping_scheduled_ = false;
4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!push_client_.get())
4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  push_client_->SendPing();
4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pending_xmpp_pings_++;
4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (pending_xmpp_pings_ >= kMaxFailedXmppPings) {
4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Check ping status when we close to the limit.
442a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    base::MessageLoop::current()->PostDelayedTask(
4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        FROM_HERE,
4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        base::Bind(&CloudPrintProxyBackend::Core::CheckXmppPingStatus, this),
4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        base::TimeDelta::FromSeconds(kXmppPingCheckIntervalSecs));
4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Schedule next ping if needed.
4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (notifications_enabled_)
4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ScheduleXmppPing();
4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CloudPrintProxyBackend::Core::ScheduleXmppPing() {
45468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  // settings_.xmpp_ping_enabled() is obsolete, we are now control
45568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  // XMPP pings from Cloud Print server.
4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!xmpp_ping_scheduled_) {
4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::TimeDelta interval = base::TimeDelta::FromSeconds(
4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::RandInt(settings_.xmpp_ping_timeout_sec() * 0.9,
4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    settings_.xmpp_ping_timeout_sec() * 1.1));
460a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    base::MessageLoop::current()->PostDelayedTask(
4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        FROM_HERE,
4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        base::Bind(&CloudPrintProxyBackend::Core::PingXmppServer, this),
4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        interval);
4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    xmpp_ping_scheduled_ = true;
4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CloudPrintProxyBackend::Core::CheckXmppPingStatus() {
4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (pending_xmpp_pings_ >= kMaxFailedXmppPings) {
4700f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    UMA_HISTOGRAM_COUNTS_100("CloudPrint.XmppPingTry", 99);  // Max on fail.
4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Reconnect to XMPP.
4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pending_xmpp_pings_ = 0;
4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    push_client_.reset();
4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    InitNotifications(robot_email_, GetTokenStore()->token());
4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)CloudPrintTokenStore* CloudPrintProxyBackend::Core::GetTokenStore() {
479a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  DCHECK(base::MessageLoop::current() == backend_->core_thread_.message_loop());
4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!token_store_.get())
4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    token_store_.reset(new CloudPrintTokenStore);
4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return token_store_.get();
4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CloudPrintProxyBackend::Core::NotifyAuthenticated(
4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& robot_oauth_refresh_token,
4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& robot_email,
4885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& user_email) {
489a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  DCHECK(base::MessageLoop::current() == backend_->frontend_loop_);
490a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  backend_->frontend_
491a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      ->OnAuthenticated(robot_oauth_refresh_token, robot_email, user_email);
4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CloudPrintProxyBackend::Core::NotifyAuthenticationFailed() {
495a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  DCHECK(base::MessageLoop::current() == backend_->frontend_loop_);
4965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  backend_->frontend_->OnAuthenticationFailed();
4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CloudPrintProxyBackend::Core::NotifyPrintSystemUnavailable() {
500a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  DCHECK(base::MessageLoop::current() == backend_->frontend_loop_);
5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  backend_->frontend_->OnPrintSystemUnavailable();
5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CloudPrintProxyBackend::Core::NotifyUnregisterPrinters(
5055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& auth_token,
5065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::list<std::string>& printer_ids) {
507a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  DCHECK(base::MessageLoop::current() == backend_->frontend_loop_);
5085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  backend_->frontend_->OnUnregisterPrinters(auth_token, printer_ids);
5095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
51168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)void CloudPrintProxyBackend::Core::NotifyXmppPingUpdated(int ping_timeout) {
51268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  DCHECK(base::MessageLoop::current() == backend_->frontend_loop_);
51368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  backend_->frontend_->OnXmppPingUpdated(ping_timeout);
51468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)}
51568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CloudPrintProxyBackend::Core::OnNotificationsEnabled() {
517a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  DCHECK(base::MessageLoop::current() == backend_->core_thread_.message_loop());
5185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  notifications_enabled_ = true;
5195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  notifications_enabled_since_ = base::TimeTicks::Now();
5205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VLOG(1) << "Notifications for connector " << settings_.proxy_id()
5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          << " were enabled at "
5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          << notifications_enabled_since_.ToInternalValue();
5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Notifications just got re-enabled. In this case we want to schedule
5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // a poll once for jobs we might have missed when we were dark.
5255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Note that ScheduleJobPoll will not schedule again if a job poll task is
5265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // already scheduled.
5275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScheduleJobPoll();
5285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Schedule periodic ping for XMPP notification channel.
5305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScheduleXmppPing();
5315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CloudPrintProxyBackend::Core::OnNotificationsDisabled(
5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    notifier::NotificationsDisabledReason reason) {
535a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  DCHECK(base::MessageLoop::current() == backend_->core_thread_.message_loop());
5365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  notifications_enabled_ = false;
5375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  LOG(ERROR) << "Notifications for connector " << settings_.proxy_id()
5385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)             << " disabled.";
5395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  notifications_enabled_since_ = base::TimeTicks();
5405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We just lost notifications. This this case we want to schedule a
5415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // job poll if enable_job_poll_ is true.
5425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (enable_job_poll_)
5435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ScheduleJobPoll();
5445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CloudPrintProxyBackend::Core::OnIncomingNotification(
5485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const notifier::Notification& notification) {
5495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Since we got some notification from the server,
5505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // reset pending ping counter to 0.
5515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pending_xmpp_pings_ = 0;
5525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
553a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  DCHECK(base::MessageLoop::current() == backend_->core_thread_.message_loop());
5545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VLOG(1) << "CP_CONNECTOR: Incoming notification.";
5555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (0 == base::strcasecmp(kCloudPrintPushNotificationsSource,
5565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            notification.channel.c_str()))
5575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    HandlePrinterNotification(notification.data);
5585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CloudPrintProxyBackend::Core::OnPingResponse() {
5610f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  UMA_HISTOGRAM_COUNTS_100("CloudPrint.XmppPingTry", pending_xmpp_pings_);
5625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pending_xmpp_pings_ = 0;
5635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VLOG(1) << "CP_CONNECTOR: Ping response received.";
5645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}  // namespace cloud_print
567