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 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.";
35 CommandLine
cmd_line(exe_path
);
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
);
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
);
49 base::LaunchOptions launch_options
;
51 launch_options
.force_breakaway_from_job_
= true;
53 base::LaunchProcess(cmd_line
, launch_options
, NULL
);
57 void CheckCloudPrintProxyPolicyInBrowser() {
58 LaunchBrowserProcessWithSwitch(switches::kCheckCloudPrintConnectorPolicy
);
63 namespace cloud_print
{
65 CloudPrintProxy::CloudPrintProxy()
66 : service_prefs_(NULL
),
71 CloudPrintProxy::~CloudPrintProxy() {
72 DCHECK(CalledOnValidThread());
76 void CloudPrintProxy::Initialize(ServiceProcessPrefs
* service_prefs
,
78 DCHECK(CalledOnValidThread());
79 service_prefs_
= service_prefs
;
83 void CloudPrintProxy::EnableForUser() {
84 DCHECK(CalledOnValidThread());
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_
);
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
);
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
);
108 client_
->OnCloudPrintProxyEnabled(true);
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());
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
);
127 service_prefs_
->SetValue(prefs::kCloudPrintUserSettings
,
128 user_settings
.DeepCopy());
129 service_prefs_
->WritePrefs();
131 if (!CreateBackend())
133 DCHECK(backend_
.get());
134 user_email_
= user_email
;
135 backend_
->InitializeWithRobotAuthCode(robot_auth_code
, robot_email
);
137 client_
->OnCloudPrintProxyEnabled(true);
141 bool CloudPrintProxy::CreateBackend() {
142 DCHECK(CalledOnValidThread());
146 ConnectorSettings settings
;
147 settings
.InitFrom(service_prefs_
);
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);
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
));
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();
172 // If no backend avaialble, disable connector immidiately.
177 void CloudPrintProxy::DisableForUser() {
178 DCHECK(CalledOnValidThread());
182 client_
->OnCloudPrintProxyDisabled(true);
187 void CloudPrintProxy::GetProxyInfo(CloudPrintProxyInfo
* info
) {
188 info
->enabled
= enabled_
;
191 info
->email
= user_email();
192 ConnectorSettings settings
;
193 settings
.InitFrom(service_prefs_
);
194 info
->proxy_id
= settings
.proxy_id();
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
.get())
204 PrintSystem::PrintSystemResult result
= print_system
->Init();
205 if (!result
.succeeded())
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
);
213 void CloudPrintProxy::CheckCloudPrintProxyPolicy() {
214 g_service_process
->io_thread()->message_loop_proxy()->PostTask(
215 FROM_HERE
, base::Bind(&CheckCloudPrintProxyPolicyInBrowser
));
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
,
227 // If authenticating from a robot, the user email will be empty.
228 if (!user_email
.empty()) {
229 user_email_
= user_email
;
231 service_prefs_
->SetString(prefs::kCloudPrintEmail
, user_email_
);
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
)) {
241 client_
->OnCloudPrintProxyDisabled(false);
246 void CloudPrintProxy::OnAuthenticationFailed() {
247 DCHECK(CalledOnValidThread());
248 // Don't disable permanently. Could be just connection issue.
251 client_
->OnCloudPrintProxyDisabled(false);
255 void CloudPrintProxy::OnPrintSystemUnavailable() {
256 // If the print system is unavailable, we want to shutdown the proxy and
257 // disable it non-persistently.
260 client_
->OnCloudPrintProxyDisabled(false);
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",
270 ConnectorSettings settings
;
271 settings
.InitFrom(service_prefs_
);
272 wipeout_
.reset(new CloudPrintWipeout(this, settings
.server_url()));
273 wipeout_
->UnregisterPrinters(auth_token
, printer_ids
);
276 void CloudPrintProxy::OnXmppPingUpdated(int ping_timeout
) {
277 DCHECK(CalledOnValidThread());
278 service_prefs_
->SetInt(prefs::kCloudPrintXmppPingTimeout
, ping_timeout
);
279 service_prefs_
->WritePrefs();
282 void CloudPrintProxy::OnUnregisterPrintersComplete() {
284 // Finish disabling cloud print for this user.
288 void CloudPrintProxy::ShutdownBackend() {
289 DCHECK(CalledOnValidThread());
291 backend_
->Shutdown();
295 } // namespace cloud_print