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/browser/printing/cloud_print/cloud_print_proxy_service.h" 6 7 #include <stack> 8 #include <vector> 9 10 #include "base/bind.h" 11 #include "base/bind_helpers.h" 12 #include "base/command_line.h" 13 #include "base/file_util.h" 14 #include "base/json/json_reader.h" 15 #include "base/message_loop/message_loop.h" 16 #include "base/metrics/histogram.h" 17 #include "base/prefs/pref_service.h" 18 #include "base/strings/utf_string_conversions.h" 19 #include "chrome/browser/browser_process.h" 20 #include "chrome/browser/chrome_notification_types.h" 21 #include "chrome/browser/lifetime/application_lifetime.h" 22 #include "chrome/browser/notifications/desktop_notification_service.h" 23 #include "chrome/browser/notifications/notification.h" 24 #include "chrome/browser/notifications/notification_ui_manager.h" 25 #include "chrome/browser/profiles/profile.h" 26 #include "chrome/browser/service_process/service_process_control.h" 27 #include "chrome/common/chrome_switches.h" 28 #include "chrome/common/cloud_print/cloud_print_proxy_info.h" 29 #include "chrome/common/pref_names.h" 30 #include "chrome/common/service_messages.h" 31 #include "content/public/browser/browser_thread.h" 32 #include "grit/generated_resources.h" 33 #include "printing/backend/print_backend.h" 34 #include "ui/base/l10n/l10n_util.h" 35 36 using content::BrowserThread; 37 38 CloudPrintProxyService::CloudPrintProxyService(Profile* profile) 39 : profile_(profile), 40 weak_factory_(this), 41 enforcing_connector_policy_(false) { 42 } 43 44 CloudPrintProxyService::~CloudPrintProxyService() { 45 } 46 47 void CloudPrintProxyService::Initialize() { 48 DCHECK_CURRENTLY_ON(BrowserThread::UI); 49 UMA_HISTOGRAM_ENUMERATION("CloudPrint.ServiceEvents", 50 ServiceProcessControl::SERVICE_EVENT_INITIALIZE, 51 ServiceProcessControl::SERVICE_EVENT_MAX); 52 if (profile_->GetPrefs()->HasPrefPath(prefs::kCloudPrintEmail) && 53 (!profile_->GetPrefs()->GetString(prefs::kCloudPrintEmail).empty() || 54 !profile_->GetPrefs()->GetBoolean(prefs::kCloudPrintProxyEnabled))) { 55 // If the cloud print proxy is enabled, or the policy preventing it from 56 // being enabled is set, establish a channel with the service process and 57 // update the status. This will check the policy when the status is sent 58 // back. 59 UMA_HISTOGRAM_ENUMERATION( 60 "CloudPrint.ServiceEvents", 61 ServiceProcessControl::SERVICE_EVENT_ENABLED_ON_LAUNCH, 62 ServiceProcessControl::SERVICE_EVENT_MAX); 63 RefreshStatusFromService(); 64 } 65 66 pref_change_registrar_.Init(profile_->GetPrefs()); 67 pref_change_registrar_.Add( 68 prefs::kCloudPrintProxyEnabled, 69 base::Bind( 70 base::IgnoreResult( 71 &CloudPrintProxyService::ApplyCloudPrintConnectorPolicy), 72 base::Unretained(this))); 73 } 74 75 void CloudPrintProxyService::RefreshStatusFromService() { 76 DCHECK_CURRENTLY_ON(BrowserThread::UI); 77 InvokeServiceTask( 78 base::Bind(&CloudPrintProxyService::RefreshCloudPrintProxyStatus, 79 weak_factory_.GetWeakPtr())); 80 } 81 82 bool CloudPrintProxyService::EnforceCloudPrintConnectorPolicyAndQuit() { 83 DCHECK_CURRENTLY_ON(BrowserThread::UI); 84 enforcing_connector_policy_ = true; 85 if (ApplyCloudPrintConnectorPolicy()) 86 return true; 87 return false; 88 } 89 90 void CloudPrintProxyService::EnableForUserWithRobot( 91 const std::string& robot_auth_code, 92 const std::string& robot_email, 93 const std::string& user_email, 94 const base::DictionaryValue& user_preferences) { 95 DCHECK_CURRENTLY_ON(BrowserThread::UI); 96 UMA_HISTOGRAM_ENUMERATION("CloudPrint.ServiceEvents", 97 ServiceProcessControl::SERVICE_EVENT_ENABLE, 98 ServiceProcessControl::SERVICE_EVENT_MAX); 99 if (profile_->GetPrefs()->GetBoolean(prefs::kCloudPrintProxyEnabled)) { 100 InvokeServiceTask( 101 base::Bind(&CloudPrintProxyService::EnableCloudPrintProxyWithRobot, 102 weak_factory_.GetWeakPtr(), robot_auth_code, robot_email, 103 user_email, base::Owned(user_preferences.DeepCopy()))); 104 } 105 } 106 107 void CloudPrintProxyService::DisableForUser() { 108 DCHECK_CURRENTLY_ON(BrowserThread::UI); 109 UMA_HISTOGRAM_ENUMERATION("CloudPrint.ServiceEvents", 110 ServiceProcessControl::SERVICE_EVENT_DISABLE, 111 ServiceProcessControl::SERVICE_EVENT_MAX); 112 InvokeServiceTask( 113 base::Bind(&CloudPrintProxyService::DisableCloudPrintProxy, 114 weak_factory_.GetWeakPtr())); 115 } 116 117 bool CloudPrintProxyService::ApplyCloudPrintConnectorPolicy() { 118 DCHECK_CURRENTLY_ON(BrowserThread::UI); 119 if (!profile_->GetPrefs()->GetBoolean(prefs::kCloudPrintProxyEnabled)) { 120 std::string email = 121 profile_->GetPrefs()->GetString(prefs::kCloudPrintEmail); 122 if (!email.empty()) { 123 UMA_HISTOGRAM_ENUMERATION( 124 "CloudPrint.ServiceEvents", 125 ServiceProcessControl::SERVICE_EVENT_DISABLE_BY_POLICY, 126 ServiceProcessControl::SERVICE_EVENT_MAX); 127 DisableForUser(); 128 profile_->GetPrefs()->SetString(prefs::kCloudPrintEmail, std::string()); 129 if (enforcing_connector_policy_) { 130 base::MessageLoop::current()->PostTask( 131 FROM_HERE, 132 base::Bind(&CloudPrintProxyService::RefreshCloudPrintProxyStatus, 133 weak_factory_.GetWeakPtr())); 134 } 135 return false; 136 } else if (enforcing_connector_policy_) { 137 base::MessageLoop::current()->PostTask(FROM_HERE, 138 base::MessageLoop::QuitClosure()); 139 } 140 } 141 return true; 142 } 143 144 void CloudPrintProxyService::GetPrinters(const PrintersCallback& callback) { 145 DCHECK_CURRENTLY_ON(BrowserThread::UI); 146 if (!profile_->GetPrefs()->GetBoolean(prefs::kCloudPrintProxyEnabled)) 147 return; 148 149 base::FilePath list_path( 150 CommandLine::ForCurrentProcess()->GetSwitchValuePath( 151 switches::kCloudPrintSetupProxy)); 152 if (!list_path.empty()) { 153 std::string printers_json; 154 base::ReadFileToString(list_path, &printers_json); 155 scoped_ptr<base::Value> value(base::JSONReader::Read(printers_json)); 156 base::ListValue* list = NULL; 157 std::vector<std::string> printers; 158 if (value && value->GetAsList(&list) && list) { 159 for (size_t i = 0; i < list->GetSize(); ++i) { 160 std::string printer; 161 if (list->GetString(i, &printer)) 162 printers.push_back(printer); 163 } 164 } 165 UMA_HISTOGRAM_COUNTS_10000("CloudPrint.AvailablePrintersList", 166 printers.size()); 167 base::MessageLoop::current()->PostTask(FROM_HERE, 168 base::Bind(callback, printers)); 169 } else { 170 InvokeServiceTask( 171 base::Bind(&CloudPrintProxyService::GetCloudPrintProxyPrinters, 172 weak_factory_.GetWeakPtr(), 173 callback)); 174 } 175 } 176 177 void CloudPrintProxyService::GetCloudPrintProxyPrinters( 178 const PrintersCallback& callback) { 179 DCHECK_CURRENTLY_ON(BrowserThread::UI); 180 ServiceProcessControl* process_control = GetServiceProcessControl(); 181 DCHECK(process_control->IsConnected()); 182 process_control->GetPrinters(callback); 183 } 184 185 void CloudPrintProxyService::RefreshCloudPrintProxyStatus() { 186 DCHECK_CURRENTLY_ON(BrowserThread::UI); 187 ServiceProcessControl* process_control = GetServiceProcessControl(); 188 DCHECK(process_control->IsConnected()); 189 ServiceProcessControl::CloudPrintProxyInfoCallback callback = base::Bind( 190 &CloudPrintProxyService::ProxyInfoCallback, base::Unretained(this)); 191 process_control->GetCloudPrintProxyInfo(callback); 192 } 193 194 void CloudPrintProxyService::EnableCloudPrintProxyWithRobot( 195 const std::string& robot_auth_code, 196 const std::string& robot_email, 197 const std::string& user_email, 198 const base::DictionaryValue* user_preferences) { 199 ServiceProcessControl* process_control = GetServiceProcessControl(); 200 DCHECK(process_control->IsConnected()); 201 process_control->Send( 202 new ServiceMsg_EnableCloudPrintProxyWithRobot( 203 robot_auth_code, robot_email, user_email, *user_preferences)); 204 // Assume the IPC worked. 205 profile_->GetPrefs()->SetString(prefs::kCloudPrintEmail, user_email); 206 } 207 208 void CloudPrintProxyService::DisableCloudPrintProxy() { 209 ServiceProcessControl* process_control = GetServiceProcessControl(); 210 DCHECK(process_control->IsConnected()); 211 process_control->Send(new ServiceMsg_DisableCloudPrintProxy); 212 // Assume the IPC worked. 213 profile_->GetPrefs()->SetString(prefs::kCloudPrintEmail, std::string()); 214 } 215 216 void CloudPrintProxyService::ProxyInfoCallback( 217 const cloud_print::CloudPrintProxyInfo& proxy_info) { 218 proxy_id_ = proxy_info.proxy_id; 219 profile_->GetPrefs()->SetString( 220 prefs::kCloudPrintEmail, 221 proxy_info.enabled ? proxy_info.email : std::string()); 222 ApplyCloudPrintConnectorPolicy(); 223 } 224 225 bool CloudPrintProxyService::InvokeServiceTask(const base::Closure& task) { 226 GetServiceProcessControl()->Launch(task, base::Closure()); 227 return true; 228 } 229 230 ServiceProcessControl* CloudPrintProxyService::GetServiceProcessControl() { 231 return ServiceProcessControl::GetInstance(); 232 } 233