cloud_print_proxy_backend.cc revision f2477e01787aa58f445919b809d89e252beef54f
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"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/values.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/chrome_switches.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"
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/service/net/service_url_request_context.h"
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/service/service_process.h"
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "google_apis/gaia/gaia_oauth_client.h"
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "google_apis/gaia/gaia_urls.h"
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "grit/generated_resources.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"
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/l10n/l10n_util.h"
327dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "url/gurl.h"
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace cloud_print {
352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The real guts of CloudPrintProxyBackend, to keep the public client API clean.
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class CloudPrintProxyBackend::Core
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : public base::RefCountedThreadSafe<CloudPrintProxyBackend::Core>,
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      public CloudPrintAuth::Client,
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      public CloudPrintConnector::Client,
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      public notifier::PushClientObserver {
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // It is OK for print_server_url to be empty. In this case system should
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // use system default (local) print server.
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Core(CloudPrintProxyBackend* backend,
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       const ConnectorSettings& settings,
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       const gaia::OAuthClientInfo& oauth_client_info,
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       bool enable_job_poll);
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Note:
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The Do* methods are the various entry points from CloudPrintProxyBackend
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // It calls us on a dedicated thread to actually perform synchronous
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // (and potentially blocking) operations.
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void DoInitializeWithToken(const std::string& cloud_print_token);
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void DoInitializeWithRobotToken(const std::string& robot_oauth_refresh_token,
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                  const std::string& robot_email);
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void DoInitializeWithRobotAuthCode(const std::string& robot_oauth_auth_code,
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                     const std::string& robot_email);
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Called on the CloudPrintProxyBackend core_thread_ to perform
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // shutdown.
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void DoShutdown();
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void DoRegisterSelectedPrinters(
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      const printing::PrinterList& printer_list);
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void DoUnregisterPrinters();
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // CloudPrintAuth::Client implementation.
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void OnAuthenticationComplete(
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      const std::string& access_token,
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      const std::string& robot_oauth_refresh_token,
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      const std::string& robot_email,
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      const std::string& user_email) OVERRIDE;
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void OnInvalidCredentials() OVERRIDE;
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // CloudPrintConnector::Client implementation.
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void OnAuthFailed() OVERRIDE;
7868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  virtual void OnXmppPingUpdated(int ping_timeout) OVERRIDE;
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // notifier::PushClientObserver implementation.
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void OnNotificationsEnabled() OVERRIDE;
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void OnNotificationsDisabled(
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      notifier::NotificationsDisabledReason reason) OVERRIDE;
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void OnIncomingNotification(
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      const notifier::Notification& notification) OVERRIDE;
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void OnPingResponse() OVERRIDE;
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  friend class base::RefCountedThreadSafe<Core>;
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual ~Core() {}
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void CreateAuthAndConnector();
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void DestroyAuthAndConnector();
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // NotifyXXX is how the Core communicates with the frontend across
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // threads.
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void NotifyPrinterListAvailable(
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      const printing::PrinterList& printer_list);
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void NotifyAuthenticated(
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& robot_oauth_refresh_token,
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& robot_email,
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& user_email);
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void NotifyAuthenticationFailed();
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void NotifyPrintSystemUnavailable();
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void NotifyUnregisterPrinters(const std::string& auth_token,
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                const std::list<std::string>& printer_ids);
10868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  void NotifyXmppPingUpdated(int ping_timeout);
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Init XMPP channel
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void InitNotifications(const std::string& robot_email,
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         const std::string& access_token);
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  void HandlePrinterNotification(const std::string& notification);
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void PollForJobs();
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Schedules a task to poll for jobs. Does nothing if a task is already
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // scheduled.
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void ScheduleJobPoll();
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void PingXmppServer();
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void ScheduleXmppPing();
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void CheckXmppPingStatus();
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CloudPrintTokenStore* GetTokenStore();
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Our parent CloudPrintProxyBackend
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CloudPrintProxyBackend* backend_;
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Cloud Print authenticator.
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_refptr<CloudPrintAuth> auth_;
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Cloud Print connector.
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_refptr<CloudPrintConnector> connector_;
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // OAuth client info.
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gaia::OAuthClientInfo oauth_client_info_;
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Notification (xmpp) handler.
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<notifier::PushClient> push_client_;
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Indicates whether XMPP notifications are currently enabled.
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool notifications_enabled_;
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The time when notifications were enabled. Valid only when
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // notifications_enabled_ is true.
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::TimeTicks notifications_enabled_since_;
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Indicates whether a task to poll for jobs has been scheduled.
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool job_poll_scheduled_;
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Indicates whether we should poll for jobs when we lose XMPP connection.
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool enable_job_poll_;
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Indicates whether a task to ping xmpp server has been scheduled.
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool xmpp_ping_scheduled_;
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Number of XMPP pings pending reply from the server.
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int pending_xmpp_pings_;
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Connector settings.
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ConnectorSettings settings_;
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string robot_email_;
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<CloudPrintTokenStore> token_store_;
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(Core);
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)CloudPrintProxyBackend::CloudPrintProxyBackend(
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CloudPrintProxyFrontend* frontend,
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const ConnectorSettings& settings,
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const gaia::OAuthClientInfo& oauth_client_info,
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool enable_job_poll)
164a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    : core_thread_("Chrome_CloudPrintProxyCoreThread"),
165a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      frontend_loop_(base::MessageLoop::current()),
166a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      frontend_(frontend) {
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(frontend_);
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  core_ = new Core(this, settings, oauth_client_info, enable_job_poll);
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
171868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)CloudPrintProxyBackend::~CloudPrintProxyBackend() { DCHECK(!core_.get()); }
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool CloudPrintProxyBackend::InitializeWithToken(
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& cloud_print_token) {
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!core_thread_.Start())
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  core_thread_.message_loop()->PostTask(
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      FROM_HERE,
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(&CloudPrintProxyBackend::Core::DoInitializeWithToken,
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 core_.get(), cloud_print_token));
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool CloudPrintProxyBackend::InitializeWithRobotToken(
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& robot_oauth_refresh_token,
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& robot_email) {
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!core_thread_.Start())
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  core_thread_.message_loop()->PostTask(
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      FROM_HERE,
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(&CloudPrintProxyBackend::Core::DoInitializeWithRobotToken,
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 core_.get(), robot_oauth_refresh_token, robot_email));
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool CloudPrintProxyBackend::InitializeWithRobotAuthCode(
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& robot_oauth_auth_code,
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& robot_email) {
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!core_thread_.Start())
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  core_thread_.message_loop()->PostTask(
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      FROM_HERE,
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(&CloudPrintProxyBackend::Core::DoInitializeWithRobotAuthCode,
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 core_.get(), robot_oauth_auth_code, robot_email));
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CloudPrintProxyBackend::Shutdown() {
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  core_thread_.message_loop()->PostTask(
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      FROM_HERE,
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(&CloudPrintProxyBackend::Core::DoShutdown, core_.get()));
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  core_thread_.Stop();
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  core_ = NULL;  // Releases reference to core_.
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CloudPrintProxyBackend::UnregisterPrinters() {
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  core_thread_.message_loop()->PostTask(
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      FROM_HERE,
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(&CloudPrintProxyBackend::Core::DoUnregisterPrinters,
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 core_.get()));
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)CloudPrintProxyBackend::Core::Core(
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CloudPrintProxyBackend* backend,
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const ConnectorSettings& settings,
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const gaia::OAuthClientInfo& oauth_client_info,
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool enable_job_poll)
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      : backend_(backend),
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        oauth_client_info_(oauth_client_info),
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        notifications_enabled_(false),
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        job_poll_scheduled_(false),
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        enable_job_poll_(enable_job_poll),
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        xmpp_ping_scheduled_(false),
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        pending_xmpp_pings_(0) {
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  settings_.CopyFrom(settings);
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CloudPrintProxyBackend::Core::CreateAuthAndConnector() {
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!auth_.get()) {
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    auth_ = new CloudPrintAuth(this, settings_.server_url(), oauth_client_info_,
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               settings_.proxy_id());
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!connector_.get()) {
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    connector_ = new CloudPrintConnector(this, settings_);
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CloudPrintProxyBackend::Core::DestroyAuthAndConnector() {
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  auth_ = NULL;
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  connector_ = NULL;
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CloudPrintProxyBackend::Core::DoInitializeWithToken(
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& cloud_print_token) {
256a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  DCHECK(base::MessageLoop::current() == backend_->core_thread_.message_loop());
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CreateAuthAndConnector();
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  auth_->AuthenticateWithToken(cloud_print_token);
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CloudPrintProxyBackend::Core::DoInitializeWithRobotToken(
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& robot_oauth_refresh_token,
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& robot_email) {
264a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  DCHECK(base::MessageLoop::current() == backend_->core_thread_.message_loop());
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CreateAuthAndConnector();
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  auth_->AuthenticateWithRobotToken(robot_oauth_refresh_token, robot_email);
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CloudPrintProxyBackend::Core::DoInitializeWithRobotAuthCode(
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& robot_oauth_auth_code,
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& robot_email) {
272a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  DCHECK(base::MessageLoop::current() == backend_->core_thread_.message_loop());
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CreateAuthAndConnector();
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  auth_->AuthenticateWithRobotAuthCode(robot_oauth_auth_code, robot_email);
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CloudPrintProxyBackend::Core::OnAuthenticationComplete(
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& access_token,
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& robot_oauth_refresh_token,
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& robot_email,
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& user_email) {
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CloudPrintTokenStore* token_store  = GetTokenStore();
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool first_time = token_store->token().empty();
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  token_store->SetToken(access_token);
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  robot_email_ = robot_email;
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Let the frontend know that we have authenticated.
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  backend_->frontend_loop_->PostTask(
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      FROM_HERE,
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(&Core::NotifyAuthenticated, this, robot_oauth_refresh_token,
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 robot_email, user_email));
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (first_time) {
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    InitNotifications(robot_email, access_token);
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // If we are refreshing a token, update the XMPP token too.
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(push_client_.get());
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    push_client_->UpdateCredentials(robot_email, access_token);
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Start cloud print connector if needed.
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!connector_->IsRunning()) {
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!connector_->Start()) {
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Let the frontend know that we do not have a print system.
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      backend_->frontend_loop_->PostTask(
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          FROM_HERE, base::Bind(&Core::NotifyPrintSystemUnavailable, this));
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CloudPrintProxyBackend::Core::OnInvalidCredentials() {
309a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  DCHECK(base::MessageLoop::current() == backend_->core_thread_.message_loop());
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VLOG(1) << "CP_CONNECTOR: Auth Error";
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  backend_->frontend_loop_->PostTask(
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      FROM_HERE, base::Bind(&Core::NotifyAuthenticationFailed, this));
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CloudPrintProxyBackend::Core::OnAuthFailed() {
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VLOG(1) << "CP_CONNECTOR: Authentication failed in connector.";
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Let's stop connecter and refresh token. We'll restart connecter once
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // new token available.
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (connector_->IsRunning())
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    connector_->Stop();
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Refresh Auth token.
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  auth_->RefreshAccessToken();
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
32668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)void CloudPrintProxyBackend::Core::OnXmppPingUpdated(int ping_timeout) {
32768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  settings_.SetXmppPingTimeoutSec(ping_timeout);
32868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  backend_->frontend_loop_->PostTask(
32968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      FROM_HERE,
33068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      base::Bind(&Core::NotifyXmppPingUpdated, this, ping_timeout));
33168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)}
33268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CloudPrintProxyBackend::Core::InitNotifications(
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& robot_email,
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& access_token) {
336a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  DCHECK(base::MessageLoop::current() == backend_->core_thread_.message_loop());
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pending_xmpp_pings_ = 0;
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  notifier::NotifierOptions notifier_options;
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  notifier_options.request_context_getter =
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      g_service_process->GetServiceURLRequestContextGetter();
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  notifier_options.auth_mechanism = "X-OAUTH2";
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  notifier_options.try_ssltcp_first = true;
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  push_client_ = notifier::PushClient::CreateDefault(notifier_options);
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  push_client_->AddObserver(this);
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  notifier::Subscription subscription;
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  subscription.channel = kCloudPrintPushNotificationsSource;
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  subscription.from = kCloudPrintPushNotificationsSource;
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  push_client_->UpdateSubscriptions(
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      notifier::SubscriptionList(1, subscription));
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  push_client_->UpdateCredentials(robot_email, access_token);
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CloudPrintProxyBackend::Core::DoShutdown() {
355a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  DCHECK(base::MessageLoop::current() == backend_->core_thread_.message_loop());
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VLOG(1) << "CP_CONNECTOR: Shutdown connector, id: " << settings_.proxy_id();
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (connector_->IsRunning())
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    connector_->Stop();
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Important to delete the PushClient on this thread.
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (push_client_.get()) {
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    push_client_->RemoveObserver(this);
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  push_client_.reset();
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  notifications_enabled_ = false;
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  notifications_enabled_since_ = base::TimeTicks();
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  token_store_.reset();
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DestroyAuthAndConnector();
3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CloudPrintProxyBackend::Core::DoUnregisterPrinters() {
374a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  DCHECK(base::MessageLoop::current() == backend_->core_thread_.message_loop());
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string access_token = GetTokenStore()->token();
3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::list<std::string> printer_ids;
3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  connector_->GetPrinterIds(&printer_ids);
3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  backend_->frontend_loop_->PostTask(
3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      FROM_HERE,
3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(&Core::NotifyUnregisterPrinters,
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 this, access_token, printer_ids));
3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CloudPrintProxyBackend::Core::HandlePrinterNotification(
38868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    const std::string& notification) {
389a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  DCHECK(base::MessageLoop::current() == backend_->core_thread_.message_loop());
39068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
39168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  size_t pos = notification.rfind(kNotificationUpdateSettings);
39268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  if (pos == std::string::npos) {
39368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    VLOG(1) << "CP_CONNECTOR: Handle printer notification, id: "
39468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)            << notification;
39568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    connector_->CheckForJobs(kJobFetchReasonNotified, notification);
39668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  } else {
39768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    DCHECK(pos == notification.length() - strlen(kNotificationUpdateSettings));
39868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    std::string printer_id = notification.substr(0, pos);
39968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    VLOG(1) << "CP_CONNECTOR: Update printer settings, id: " << printer_id;
40068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    connector_->UpdatePrinterSettings(printer_id);
40168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  }
4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CloudPrintProxyBackend::Core::PollForJobs() {
4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VLOG(1) << "CP_CONNECTOR: Polling for jobs.";
406a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  DCHECK(base::MessageLoop::current() == backend_->core_thread_.message_loop());
4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Check all printers for jobs.
4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  connector_->CheckForJobs(kJobFetchReasonPoll, std::string());
4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  job_poll_scheduled_ = false;
4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If we don't have notifications and job polling is enabled, poll again
4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // after a while.
4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!notifications_enabled_ && enable_job_poll_)
4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ScheduleJobPoll();
4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CloudPrintProxyBackend::Core::ScheduleJobPoll() {
4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!job_poll_scheduled_) {
4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::TimeDelta interval = base::TimeDelta::FromSeconds(
4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        base::RandInt(kMinJobPollIntervalSecs, kMaxJobPollIntervalSecs));
421a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    base::MessageLoop::current()->PostDelayedTask(
4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        FROM_HERE,
4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        base::Bind(&CloudPrintProxyBackend::Core::PollForJobs, this),
4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        interval);
4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    job_poll_scheduled_ = true;
4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CloudPrintProxyBackend::Core::PingXmppServer() {
4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  xmpp_ping_scheduled_ = false;
4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!push_client_.get())
4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  push_client_->SendPing();
4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pending_xmpp_pings_++;
4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (pending_xmpp_pings_ >= kMaxFailedXmppPings) {
4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Check ping status when we close to the limit.
440a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    base::MessageLoop::current()->PostDelayedTask(
4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        FROM_HERE,
4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        base::Bind(&CloudPrintProxyBackend::Core::CheckXmppPingStatus, this),
4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        base::TimeDelta::FromSeconds(kXmppPingCheckIntervalSecs));
4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Schedule next ping if needed.
4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (notifications_enabled_)
4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ScheduleXmppPing();
4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CloudPrintProxyBackend::Core::ScheduleXmppPing() {
45268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  // settings_.xmpp_ping_enabled() is obsolete, we are now control
45368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  // XMPP pings from Cloud Print server.
4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!xmpp_ping_scheduled_) {
4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::TimeDelta interval = base::TimeDelta::FromSeconds(
4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::RandInt(settings_.xmpp_ping_timeout_sec() * 0.9,
4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    settings_.xmpp_ping_timeout_sec() * 1.1));
458a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    base::MessageLoop::current()->PostDelayedTask(
4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        FROM_HERE,
4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        base::Bind(&CloudPrintProxyBackend::Core::PingXmppServer, this),
4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        interval);
4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    xmpp_ping_scheduled_ = true;
4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CloudPrintProxyBackend::Core::CheckXmppPingStatus() {
4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (pending_xmpp_pings_ >= kMaxFailedXmppPings) {
4680f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    UMA_HISTOGRAM_COUNTS_100("CloudPrint.XmppPingTry", 99);  // Max on fail.
4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Reconnect to XMPP.
4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pending_xmpp_pings_ = 0;
4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    push_client_.reset();
4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    InitNotifications(robot_email_, GetTokenStore()->token());
4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)CloudPrintTokenStore* CloudPrintProxyBackend::Core::GetTokenStore() {
477a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  DCHECK(base::MessageLoop::current() == backend_->core_thread_.message_loop());
4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!token_store_.get())
4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    token_store_.reset(new CloudPrintTokenStore);
4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return token_store_.get();
4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CloudPrintProxyBackend::Core::NotifyAuthenticated(
4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& robot_oauth_refresh_token,
4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& robot_email,
4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& user_email) {
487a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  DCHECK(base::MessageLoop::current() == backend_->frontend_loop_);
488a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  backend_->frontend_
489a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      ->OnAuthenticated(robot_oauth_refresh_token, robot_email, user_email);
4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CloudPrintProxyBackend::Core::NotifyAuthenticationFailed() {
493a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  DCHECK(base::MessageLoop::current() == backend_->frontend_loop_);
4945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  backend_->frontend_->OnAuthenticationFailed();
4955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CloudPrintProxyBackend::Core::NotifyPrintSystemUnavailable() {
498a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  DCHECK(base::MessageLoop::current() == backend_->frontend_loop_);
4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  backend_->frontend_->OnPrintSystemUnavailable();
5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CloudPrintProxyBackend::Core::NotifyUnregisterPrinters(
5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& auth_token,
5045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::list<std::string>& printer_ids) {
505a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  DCHECK(base::MessageLoop::current() == backend_->frontend_loop_);
5065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  backend_->frontend_->OnUnregisterPrinters(auth_token, printer_ids);
5075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
50968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)void CloudPrintProxyBackend::Core::NotifyXmppPingUpdated(int ping_timeout) {
51068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  DCHECK(base::MessageLoop::current() == backend_->frontend_loop_);
51168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  backend_->frontend_->OnXmppPingUpdated(ping_timeout);
51268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)}
51368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
5145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CloudPrintProxyBackend::Core::OnNotificationsEnabled() {
515a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  DCHECK(base::MessageLoop::current() == backend_->core_thread_.message_loop());
5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  notifications_enabled_ = true;
5175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  notifications_enabled_since_ = base::TimeTicks::Now();
5185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VLOG(1) << "Notifications for connector " << settings_.proxy_id()
5195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          << " were enabled at "
5205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          << notifications_enabled_since_.ToInternalValue();
5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Notifications just got re-enabled. In this case we want to schedule
5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // a poll once for jobs we might have missed when we were dark.
5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Note that ScheduleJobPoll will not schedule again if a job poll task is
5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // already scheduled.
5255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScheduleJobPoll();
5265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Schedule periodic ping for XMPP notification channel.
5285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScheduleXmppPing();
5295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CloudPrintProxyBackend::Core::OnNotificationsDisabled(
5325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    notifier::NotificationsDisabledReason reason) {
533a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  DCHECK(base::MessageLoop::current() == backend_->core_thread_.message_loop());
5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  notifications_enabled_ = false;
5355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  LOG(ERROR) << "Notifications for connector " << settings_.proxy_id()
5365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)             << " disabled.";
5375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  notifications_enabled_since_ = base::TimeTicks();
5385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We just lost notifications. This this case we want to schedule a
5395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // job poll if enable_job_poll_ is true.
5405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (enable_job_poll_)
5415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ScheduleJobPoll();
5425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CloudPrintProxyBackend::Core::OnIncomingNotification(
5465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const notifier::Notification& notification) {
5475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Since we got some notification from the server,
5485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // reset pending ping counter to 0.
5495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pending_xmpp_pings_ = 0;
5505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
551a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  DCHECK(base::MessageLoop::current() == backend_->core_thread_.message_loop());
5525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VLOG(1) << "CP_CONNECTOR: Incoming notification.";
5535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (0 == base::strcasecmp(kCloudPrintPushNotificationsSource,
5545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            notification.channel.c_str()))
5555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    HandlePrinterNotification(notification.data);
5565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CloudPrintProxyBackend::Core::OnPingResponse() {
5590f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  UMA_HISTOGRAM_COUNTS_100("CloudPrint.XmppPingTry", pending_xmpp_pings_);
5605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pending_xmpp_pings_ = 0;
5615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VLOG(1) << "CP_CONNECTOR: Ping response received.";
5625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}  // namespace cloud_print
565