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.
5 #include "chrome/service/cloud_print/cloud_print_proxy.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"
27 #if !defined(OS_MACOSX)
28 void LaunchBrowserProcessWithSwitch(const std::string
& switch_string
) {
29 DCHECK(g_service_process
->io_thread()->message_loop_proxy()->
30 BelongsToCurrentThread());
31 base::FilePath exe_path
;
32 PathService::Get(base::FILE_EXE
, &exe_path
);
33 if (exe_path
.empty()) {
34 NOTREACHED() << "Unable to get browser process binary name.";
36 base::CommandLine
cmd_line(exe_path
);
38 // Propagate an explicit --user-data-dir value if one was given. The new
39 // browser process will pick up a policy override during initialization.
40 const base::CommandLine
& process_command_line
=
41 *base::CommandLine::ForCurrentProcess();
42 base::FilePath user_data_dir
=
43 process_command_line
.GetSwitchValuePath(switches::kUserDataDir
);
44 if (!user_data_dir
.empty())
45 cmd_line
.AppendSwitchPath(switches::kUserDataDir
, user_data_dir
);
46 cmd_line
.AppendSwitch(switch_string
);
48 #if defined(OS_POSIX) && !defined(OS_MACOSX)
49 base::Process process
= base::LaunchProcess(cmd_line
, base::LaunchOptions());
50 if (process
.IsValid())
51 base::EnsureProcessGetsReaped(process
.Pid());
53 base::LaunchOptions launch_options
;
55 launch_options
.force_breakaway_from_job_
= true;
57 base::LaunchProcess(cmd_line
, launch_options
);
61 void CheckCloudPrintProxyPolicyInBrowser() {
62 LaunchBrowserProcessWithSwitch(switches::kCheckCloudPrintConnectorPolicy
);
69 namespace cloud_print
{
71 CloudPrintProxy::CloudPrintProxy()
72 : service_prefs_(NULL
),
77 CloudPrintProxy::~CloudPrintProxy() {
78 DCHECK(CalledOnValidThread());
82 void CloudPrintProxy::Initialize(ServiceProcessPrefs
* service_prefs
,
84 DCHECK(CalledOnValidThread());
85 service_prefs_
= service_prefs
;
89 void CloudPrintProxy::EnableForUser() {
90 DCHECK(CalledOnValidThread());
93 DCHECK(backend_
.get());
94 // Read persisted robot credentials because we may decide to reuse it if the
95 // passed in LSID belongs the same user.
96 std::string robot_refresh_token
= service_prefs_
->GetString(
97 prefs::kCloudPrintRobotRefreshToken
, std::string());
98 std::string robot_email
=
99 service_prefs_
->GetString(prefs::kCloudPrintRobotEmail
, std::string());
100 user_email_
= service_prefs_
->GetString(prefs::kCloudPrintEmail
, user_email_
);
102 // See if we have persisted robot credentials.
103 if (!robot_refresh_token
.empty()) {
104 DCHECK(!robot_email
.empty());
105 backend_
->InitializeWithRobotToken(robot_refresh_token
, robot_email
);
107 // Finally see if we have persisted user credentials (legacy case).
108 std::string cloud_print_token
=
109 service_prefs_
->GetString(prefs::kCloudPrintAuthToken
, std::string());
110 DCHECK(!cloud_print_token
.empty());
111 backend_
->InitializeWithToken(cloud_print_token
);
114 client_
->OnCloudPrintProxyEnabled(true);
118 void CloudPrintProxy::EnableForUserWithRobot(
119 const std::string
& robot_auth_code
,
120 const std::string
& robot_email
,
121 const std::string
& user_email
,
122 const base::DictionaryValue
& user_settings
) {
123 DCHECK(CalledOnValidThread());
126 std::string
proxy_id(
127 service_prefs_
->GetString(prefs::kCloudPrintProxyId
, std::string()));
128 service_prefs_
->RemovePref(prefs::kCloudPrintRoot
);
129 if (!proxy_id
.empty()) {
130 // Keep only proxy id;
131 service_prefs_
->SetString(prefs::kCloudPrintProxyId
, proxy_id
);
133 service_prefs_
->SetValue(prefs::kCloudPrintUserSettings
,
134 user_settings
.DeepCopy());
135 service_prefs_
->WritePrefs();
137 if (!CreateBackend())
139 DCHECK(backend_
.get());
140 user_email_
= user_email
;
141 backend_
->InitializeWithRobotAuthCode(robot_auth_code
, robot_email
);
143 client_
->OnCloudPrintProxyEnabled(true);
147 bool CloudPrintProxy::CreateBackend() {
148 DCHECK(CalledOnValidThread());
152 ConnectorSettings settings
;
153 settings
.InitFrom(service_prefs_
);
155 // By default we don't poll for jobs when we lose XMPP connection. But this
156 // behavior can be overridden by a preference.
157 bool enable_job_poll
=
158 service_prefs_
->GetBoolean(prefs::kCloudPrintEnableJobPoll
, false);
160 gaia::OAuthClientInfo oauth_client_info
;
161 oauth_client_info
.client_id
=
162 google_apis::GetOAuth2ClientID(google_apis::CLIENT_CLOUD_PRINT
);
163 oauth_client_info
.client_secret
=
164 google_apis::GetOAuth2ClientSecret(google_apis::CLIENT_CLOUD_PRINT
);
165 oauth_client_info
.redirect_uri
= "oob";
166 backend_
.reset(new CloudPrintProxyBackend(
167 this, settings
, oauth_client_info
, enable_job_poll
));
171 void CloudPrintProxy::UnregisterPrintersAndDisableForUser() {
172 DCHECK(CalledOnValidThread());
173 if (backend_
.get()) {
174 // Try getting auth and printers info from the backend.
175 // We'll get notified in this case.
176 backend_
->UnregisterPrinters();
178 // If no backend avaialble, disable connector immidiately.
183 void CloudPrintProxy::DisableForUser() {
184 DCHECK(CalledOnValidThread());
188 client_
->OnCloudPrintProxyDisabled(true);
193 void CloudPrintProxy::GetProxyInfo(CloudPrintProxyInfo
* info
) {
194 info
->enabled
= enabled_
;
197 info
->email
= user_email();
198 ConnectorSettings settings
;
199 settings
.InitFrom(service_prefs_
);
200 info
->proxy_id
= settings
.proxy_id();
203 void CloudPrintProxy::GetPrinters(std::vector
<std::string
>* printers
) {
204 ConnectorSettings settings
;
205 settings
.InitFrom(service_prefs_
);
206 scoped_refptr
<PrintSystem
> print_system
=
207 PrintSystem::CreateInstance(settings
.print_system_settings());
208 if (!print_system
.get())
210 PrintSystem::PrintSystemResult result
= print_system
->Init();
211 if (!result
.succeeded())
213 printing::PrinterList printer_list
;
214 print_system
->EnumeratePrinters(&printer_list
);
215 for (size_t i
= 0; i
< printer_list
.size(); ++i
)
216 printers
->push_back(printer_list
[i
].printer_name
);
219 void CloudPrintProxy::CheckCloudPrintProxyPolicy() {
220 #if !defined(OS_MACOSX)
221 g_service_process
->io_thread()->message_loop_proxy()->PostTask(
222 FROM_HERE
, base::Bind(&CheckCloudPrintProxyPolicyInBrowser
));
226 void CloudPrintProxy::OnAuthenticated(
227 const std::string
& robot_oauth_refresh_token
,
228 const std::string
& robot_email
,
229 const std::string
& user_email
) {
230 DCHECK(CalledOnValidThread());
231 service_prefs_
->SetString(prefs::kCloudPrintRobotRefreshToken
,
232 robot_oauth_refresh_token
);
233 service_prefs_
->SetString(prefs::kCloudPrintRobotEmail
,
235 // If authenticating from a robot, the user email will be empty.
236 if (!user_email
.empty()) {
237 user_email_
= user_email
;
239 service_prefs_
->SetString(prefs::kCloudPrintEmail
, user_email_
);
241 DCHECK(!user_email_
.empty());
242 service_prefs_
->WritePrefs();
243 // When this switch used we don't want connector continue running, we just
244 // need authentication.
245 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
246 switches::kCloudPrintSetupProxy
)) {
249 client_
->OnCloudPrintProxyDisabled(false);
254 void CloudPrintProxy::OnAuthenticationFailed() {
255 DCHECK(CalledOnValidThread());
256 // Don't disable permanently. Could be just connection issue.
259 client_
->OnCloudPrintProxyDisabled(false);
263 void CloudPrintProxy::OnPrintSystemUnavailable() {
264 // If the print system is unavailable, we want to shutdown the proxy and
265 // disable it non-persistently.
268 client_
->OnCloudPrintProxyDisabled(false);
272 void CloudPrintProxy::OnUnregisterPrinters(
273 const std::string
& auth_token
,
274 const std::list
<std::string
>& printer_ids
) {
275 UMA_HISTOGRAM_COUNTS_10000("CloudPrint.UnregisterPrinters",
278 ConnectorSettings settings
;
279 settings
.InitFrom(service_prefs_
);
280 wipeout_
.reset(new CloudPrintWipeout(this, settings
.server_url()));
281 wipeout_
->UnregisterPrinters(auth_token
, printer_ids
);
284 void CloudPrintProxy::OnXmppPingUpdated(int ping_timeout
) {
285 DCHECK(CalledOnValidThread());
286 service_prefs_
->SetInt(prefs::kCloudPrintXmppPingTimeout
, ping_timeout
);
287 service_prefs_
->WritePrefs();
290 void CloudPrintProxy::OnUnregisterPrintersComplete() {
292 // Finish disabling cloud print for this user.
296 void CloudPrintProxy::ShutdownBackend() {
297 DCHECK(CalledOnValidThread());
299 backend_
->Shutdown();
303 } // namespace cloud_print