• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "chrome/service/cloud_print/cloud_print_proxy.h"
6 
7 #include "base/bind.h"
8 #include "base/command_line.h"
9 #include "base/metrics/histogram.h"
10 #include "base/path_service.h"
11 #include "base/process/kill.h"
12 #include "base/process/launch.h"
13 #include "base/values.h"
14 #include "chrome/common/chrome_switches.h"
15 #include "chrome/common/cloud_print/cloud_print_constants.h"
16 #include "chrome/common/cloud_print/cloud_print_proxy_info.h"
17 #include "chrome/common/pref_names.h"
18 #include "chrome/service/cloud_print/print_system.h"
19 #include "chrome/service/service_process.h"
20 #include "chrome/service/service_process_prefs.h"
21 #include "google_apis/gaia/gaia_oauth_client.h"
22 #include "google_apis/google_api_keys.h"
23 #include "url/gurl.h"
24 
25 namespace {
26 
LaunchBrowserProcessWithSwitch(const std::string & switch_string)27 void LaunchBrowserProcessWithSwitch(const std::string& switch_string) {
28   DCHECK(g_service_process->io_thread()->message_loop_proxy()->
29       BelongsToCurrentThread());
30   base::FilePath exe_path;
31   PathService::Get(base::FILE_EXE, &exe_path);
32   if (exe_path.empty()) {
33     NOTREACHED() << "Unable to get browser process binary name.";
34   }
35   CommandLine cmd_line(exe_path);
36 
37   const CommandLine& process_command_line = *CommandLine::ForCurrentProcess();
38   base::FilePath user_data_dir =
39       process_command_line.GetSwitchValuePath(switches::kUserDataDir);
40   if (!user_data_dir.empty())
41     cmd_line.AppendSwitchPath(switches::kUserDataDir, user_data_dir);
42   cmd_line.AppendSwitch(switch_string);
43 
44 #if defined(OS_POSIX) && !defined(OS_MACOSX)
45   base::ProcessHandle pid = 0;
46   base::LaunchProcess(cmd_line, base::LaunchOptions(), &pid);
47   base::EnsureProcessGetsReaped(pid);
48 #else
49   base::LaunchOptions launch_options;
50 #if defined(OS_WIN)
51   launch_options.force_breakaway_from_job_ = true;
52 #endif  // OS_WIN
53   base::LaunchProcess(cmd_line, launch_options, NULL);
54 #endif
55 }
56 
CheckCloudPrintProxyPolicyInBrowser()57 void CheckCloudPrintProxyPolicyInBrowser() {
58   LaunchBrowserProcessWithSwitch(switches::kCheckCloudPrintConnectorPolicy);
59 }
60 
61 }  // namespace
62 
63 namespace cloud_print {
64 
CloudPrintProxy()65 CloudPrintProxy::CloudPrintProxy()
66     : service_prefs_(NULL),
67       client_(NULL),
68       enabled_(false) {
69 }
70 
~CloudPrintProxy()71 CloudPrintProxy::~CloudPrintProxy() {
72   DCHECK(CalledOnValidThread());
73   ShutdownBackend();
74 }
75 
Initialize(ServiceProcessPrefs * service_prefs,Client * client)76 void CloudPrintProxy::Initialize(ServiceProcessPrefs* service_prefs,
77                                  Client* client) {
78   DCHECK(CalledOnValidThread());
79   service_prefs_ = service_prefs;
80   client_ = client;
81 }
82 
EnableForUser()83 void CloudPrintProxy::EnableForUser() {
84   DCHECK(CalledOnValidThread());
85   if (!CreateBackend())
86     return;
87   DCHECK(backend_.get());
88   // Read persisted robot credentials because we may decide to reuse it if the
89   // passed in LSID belongs the same user.
90   std::string robot_refresh_token = service_prefs_->GetString(
91       prefs::kCloudPrintRobotRefreshToken, std::string());
92   std::string robot_email =
93       service_prefs_->GetString(prefs::kCloudPrintRobotEmail, std::string());
94   user_email_ = service_prefs_->GetString(prefs::kCloudPrintEmail, user_email_);
95 
96   // See if we have persisted robot credentials.
97   if (!robot_refresh_token.empty()) {
98     DCHECK(!robot_email.empty());
99     backend_->InitializeWithRobotToken(robot_refresh_token, robot_email);
100   } else {
101     // Finally see if we have persisted user credentials (legacy case).
102     std::string cloud_print_token =
103         service_prefs_->GetString(prefs::kCloudPrintAuthToken, std::string());
104     DCHECK(!cloud_print_token.empty());
105     backend_->InitializeWithToken(cloud_print_token);
106   }
107   if (client_) {
108     client_->OnCloudPrintProxyEnabled(true);
109   }
110 }
111 
EnableForUserWithRobot(const std::string & robot_auth_code,const std::string & robot_email,const std::string & user_email,const base::DictionaryValue & user_settings)112 void CloudPrintProxy::EnableForUserWithRobot(
113     const std::string& robot_auth_code,
114     const std::string& robot_email,
115     const std::string& user_email,
116     const base::DictionaryValue& user_settings) {
117   DCHECK(CalledOnValidThread());
118 
119   ShutdownBackend();
120   std::string proxy_id(
121       service_prefs_->GetString(prefs::kCloudPrintProxyId, std::string()));
122   service_prefs_->RemovePref(prefs::kCloudPrintRoot);
123   if (!proxy_id.empty()) {
124     // Keep only proxy id;
125     service_prefs_->SetString(prefs::kCloudPrintProxyId, proxy_id);
126   }
127   service_prefs_->SetValue(prefs::kCloudPrintUserSettings,
128                            user_settings.DeepCopy());
129   service_prefs_->WritePrefs();
130 
131   if (!CreateBackend())
132     return;
133   DCHECK(backend_.get());
134   user_email_ = user_email;
135   backend_->InitializeWithRobotAuthCode(robot_auth_code, robot_email);
136   if (client_) {
137     client_->OnCloudPrintProxyEnabled(true);
138   }
139 }
140 
CreateBackend()141 bool CloudPrintProxy::CreateBackend() {
142   DCHECK(CalledOnValidThread());
143   if (backend_.get())
144     return false;
145 
146   ConnectorSettings settings;
147   settings.InitFrom(service_prefs_);
148 
149   // By default we don't poll for jobs when we lose XMPP connection. But this
150   // behavior can be overridden by a preference.
151   bool enable_job_poll =
152     service_prefs_->GetBoolean(prefs::kCloudPrintEnableJobPoll, false);
153 
154   gaia::OAuthClientInfo oauth_client_info;
155   oauth_client_info.client_id =
156     google_apis::GetOAuth2ClientID(google_apis::CLIENT_CLOUD_PRINT);
157   oauth_client_info.client_secret =
158     google_apis::GetOAuth2ClientSecret(google_apis::CLIENT_CLOUD_PRINT);
159   oauth_client_info.redirect_uri = "oob";
160   backend_.reset(new CloudPrintProxyBackend(
161       this, settings, oauth_client_info, enable_job_poll));
162   return true;
163 }
164 
UnregisterPrintersAndDisableForUser()165 void CloudPrintProxy::UnregisterPrintersAndDisableForUser() {
166   DCHECK(CalledOnValidThread());
167   if (backend_.get()) {
168     // Try getting auth and printers info from the backend.
169     // We'll get notified in this case.
170     backend_->UnregisterPrinters();
171   } else {
172     // If no backend avaialble, disable connector immidiately.
173     DisableForUser();
174   }
175 }
176 
DisableForUser()177 void CloudPrintProxy::DisableForUser() {
178   DCHECK(CalledOnValidThread());
179   user_email_.clear();
180   enabled_ = false;
181   if (client_) {
182     client_->OnCloudPrintProxyDisabled(true);
183   }
184   ShutdownBackend();
185 }
186 
GetProxyInfo(CloudPrintProxyInfo * info)187 void CloudPrintProxy::GetProxyInfo(CloudPrintProxyInfo* info) {
188   info->enabled = enabled_;
189   info->email.clear();
190   if (enabled_)
191     info->email = user_email();
192   ConnectorSettings settings;
193   settings.InitFrom(service_prefs_);
194   info->proxy_id = settings.proxy_id();
195 }
196 
GetPrinters(std::vector<std::string> * printers)197 void CloudPrintProxy::GetPrinters(std::vector<std::string>* printers) {
198   ConnectorSettings settings;
199   settings.InitFrom(service_prefs_);
200   scoped_refptr<PrintSystem> print_system =
201       PrintSystem::CreateInstance(settings.print_system_settings());
202   if (!print_system)
203     return;
204   PrintSystem::PrintSystemResult result = print_system->Init();
205   if (!result.succeeded())
206     return;
207   printing::PrinterList printer_list;
208   print_system->EnumeratePrinters(&printer_list);
209   for (size_t i = 0; i < printer_list.size(); ++i)
210     printers->push_back(printer_list[i].printer_name);
211 }
212 
CheckCloudPrintProxyPolicy()213 void CloudPrintProxy::CheckCloudPrintProxyPolicy() {
214   g_service_process->io_thread()->message_loop_proxy()->PostTask(
215       FROM_HERE, base::Bind(&CheckCloudPrintProxyPolicyInBrowser));
216 }
217 
OnAuthenticated(const std::string & robot_oauth_refresh_token,const std::string & robot_email,const std::string & user_email)218 void CloudPrintProxy::OnAuthenticated(
219     const std::string& robot_oauth_refresh_token,
220     const std::string& robot_email,
221     const std::string& user_email) {
222   DCHECK(CalledOnValidThread());
223   service_prefs_->SetString(prefs::kCloudPrintRobotRefreshToken,
224                             robot_oauth_refresh_token);
225   service_prefs_->SetString(prefs::kCloudPrintRobotEmail,
226                             robot_email);
227   // If authenticating from a robot, the user email will be empty.
228   if (!user_email.empty()) {
229     user_email_ = user_email;
230   }
231   service_prefs_->SetString(prefs::kCloudPrintEmail, user_email_);
232   enabled_ = true;
233   DCHECK(!user_email_.empty());
234   service_prefs_->WritePrefs();
235   // When this switch used we don't want connector continue running, we just
236   // need authentication.
237   if (CommandLine::ForCurrentProcess()->HasSwitch(
238           switches::kCloudPrintSetupProxy)) {
239     ShutdownBackend();
240     if (client_) {
241       client_->OnCloudPrintProxyDisabled(false);
242     }
243   }
244 }
245 
OnAuthenticationFailed()246 void CloudPrintProxy::OnAuthenticationFailed() {
247   DCHECK(CalledOnValidThread());
248   // Don't disable permanently. Could be just connection issue.
249   ShutdownBackend();
250   if (client_) {
251     client_->OnCloudPrintProxyDisabled(false);
252   }
253 }
254 
OnPrintSystemUnavailable()255 void CloudPrintProxy::OnPrintSystemUnavailable() {
256   // If the print system is unavailable, we want to shutdown the proxy and
257   // disable it non-persistently.
258   ShutdownBackend();
259   if (client_) {
260     client_->OnCloudPrintProxyDisabled(false);
261   }
262 }
263 
OnUnregisterPrinters(const std::string & auth_token,const std::list<std::string> & printer_ids)264 void CloudPrintProxy::OnUnregisterPrinters(
265     const std::string& auth_token,
266     const std::list<std::string>& printer_ids) {
267   UMA_HISTOGRAM_COUNTS_10000("CloudPrint.UnregisterPrinters",
268                              printer_ids.size());
269   ShutdownBackend();
270   ConnectorSettings settings;
271   settings.InitFrom(service_prefs_);
272   wipeout_.reset(new CloudPrintWipeout(this, settings.server_url()));
273   wipeout_->UnregisterPrinters(auth_token, printer_ids);
274 }
275 
OnXmppPingUpdated(int ping_timeout)276 void CloudPrintProxy::OnXmppPingUpdated(int ping_timeout) {
277   DCHECK(CalledOnValidThread());
278   service_prefs_->SetInt(prefs::kCloudPrintXmppPingTimeout, ping_timeout);
279   service_prefs_->WritePrefs();
280 }
281 
OnUnregisterPrintersComplete()282 void CloudPrintProxy::OnUnregisterPrintersComplete() {
283   wipeout_.reset();
284   // Finish disabling cloud print for this user.
285   DisableForUser();
286 }
287 
ShutdownBackend()288 void CloudPrintProxy::ShutdownBackend() {
289   DCHECK(CalledOnValidThread());
290   if (backend_.get())
291     backend_->Shutdown();
292   backend_.reset();
293 }
294 
295 }  // namespace cloud_print
296