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 UMA_HISTOGRAM_ENUMERATION("CloudPrint.ServiceEvents", 49 ServiceProcessControl::SERVICE_EVENT_INITIALIZE, 50 ServiceProcessControl::SERVICE_EVENT_MAX); 51 if (profile_->GetPrefs()->HasPrefPath(prefs::kCloudPrintEmail) && 52 (!profile_->GetPrefs()->GetString(prefs::kCloudPrintEmail).empty() || 53 !profile_->GetPrefs()->GetBoolean(prefs::kCloudPrintProxyEnabled))) { 54 // If the cloud print proxy is enabled, or the policy preventing it from 55 // being enabled is set, establish a channel with the service process and 56 // update the status. This will check the policy when the status is sent 57 // back. 58 UMA_HISTOGRAM_ENUMERATION( 59 "CloudPrint.ServiceEvents", 60 ServiceProcessControl::SERVICE_EVENT_ENABLED_ON_LAUNCH, 61 ServiceProcessControl::SERVICE_EVENT_MAX); 62 RefreshStatusFromService(); 63 } 64 65 pref_change_registrar_.Init(profile_->GetPrefs()); 66 pref_change_registrar_.Add( 67 prefs::kCloudPrintProxyEnabled, 68 base::Bind( 69 base::IgnoreResult( 70 &CloudPrintProxyService::ApplyCloudPrintConnectorPolicy), 71 base::Unretained(this))); 72 } 73 74 void CloudPrintProxyService::RefreshStatusFromService() { 75 InvokeServiceTask( 76 base::Bind(&CloudPrintProxyService::RefreshCloudPrintProxyStatus, 77 weak_factory_.GetWeakPtr())); 78 } 79 80 bool CloudPrintProxyService::EnforceCloudPrintConnectorPolicyAndQuit() { 81 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 82 enforcing_connector_policy_ = true; 83 if (ApplyCloudPrintConnectorPolicy()) 84 return true; 85 return false; 86 } 87 88 void CloudPrintProxyService::EnableForUserWithRobot( 89 const std::string& robot_auth_code, 90 const std::string& robot_email, 91 const std::string& user_email, 92 const base::DictionaryValue& user_preferences) { 93 UMA_HISTOGRAM_ENUMERATION("CloudPrint.ServiceEvents", 94 ServiceProcessControl::SERVICE_EVENT_ENABLE, 95 ServiceProcessControl::SERVICE_EVENT_MAX); 96 if (profile_->GetPrefs()->GetBoolean(prefs::kCloudPrintProxyEnabled)) { 97 InvokeServiceTask( 98 base::Bind(&CloudPrintProxyService::EnableCloudPrintProxyWithRobot, 99 weak_factory_.GetWeakPtr(), robot_auth_code, robot_email, 100 user_email, base::Owned(user_preferences.DeepCopy()))); 101 } 102 } 103 104 void CloudPrintProxyService::DisableForUser() { 105 UMA_HISTOGRAM_ENUMERATION("CloudPrint.ServiceEvents", 106 ServiceProcessControl::SERVICE_EVENT_DISABLE, 107 ServiceProcessControl::SERVICE_EVENT_MAX); 108 InvokeServiceTask( 109 base::Bind(&CloudPrintProxyService::DisableCloudPrintProxy, 110 weak_factory_.GetWeakPtr())); 111 } 112 113 bool CloudPrintProxyService::ApplyCloudPrintConnectorPolicy() { 114 if (!profile_->GetPrefs()->GetBoolean(prefs::kCloudPrintProxyEnabled)) { 115 std::string email = 116 profile_->GetPrefs()->GetString(prefs::kCloudPrintEmail); 117 if (!email.empty()) { 118 UMA_HISTOGRAM_ENUMERATION( 119 "CloudPrint.ServiceEvents", 120 ServiceProcessControl::SERVICE_EVENT_DISABLE_BY_POLICY, 121 ServiceProcessControl::SERVICE_EVENT_MAX); 122 DisableForUser(); 123 profile_->GetPrefs()->SetString(prefs::kCloudPrintEmail, std::string()); 124 if (enforcing_connector_policy_) { 125 base::MessageLoop::current()->PostTask( 126 FROM_HERE, 127 base::Bind(&CloudPrintProxyService::RefreshCloudPrintProxyStatus, 128 weak_factory_.GetWeakPtr())); 129 } 130 return false; 131 } else if (enforcing_connector_policy_) { 132 base::MessageLoop::current()->PostTask(FROM_HERE, 133 base::MessageLoop::QuitClosure()); 134 } 135 } 136 return true; 137 } 138 139 void CloudPrintProxyService::GetPrintersAvalibleForRegistration( 140 std::vector<std::string>* printers) { 141 base::FilePath list_path( 142 CommandLine::ForCurrentProcess()->GetSwitchValuePath( 143 switches::kCloudPrintSetupProxy)); 144 if (!list_path.empty()) { 145 std::string printers_json; 146 base::ReadFileToString(list_path, &printers_json); 147 scoped_ptr<Value> value(base::JSONReader::Read(printers_json)); 148 base::ListValue* list = NULL; 149 if (value && value->GetAsList(&list) && list) { 150 for (size_t i = 0; i < list->GetSize(); ++i) { 151 std::string printer; 152 if (list->GetString(i, &printer)) 153 printers->push_back(printer); 154 } 155 } 156 UMA_HISTOGRAM_COUNTS_10000("CloudPrint.AvailablePrintersList", 157 printers->size()); 158 } else { 159 printing::PrinterList printer_list; 160 scoped_refptr<printing::PrintBackend> backend( 161 printing::PrintBackend::CreateInstance(NULL)); 162 if (backend.get()) 163 backend->EnumeratePrinters(&printer_list); 164 for (size_t i = 0; i < printer_list.size(); ++i) 165 printers->push_back(printer_list[i].printer_name); 166 UMA_HISTOGRAM_COUNTS_10000("CloudPrint.AvailablePrinters", 167 printers->size()); 168 } 169 } 170 171 void CloudPrintProxyService::RefreshCloudPrintProxyStatus() { 172 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 173 ServiceProcessControl* process_control = GetServiceProcessControl(); 174 DCHECK(process_control->IsConnected()); 175 ServiceProcessControl::CloudPrintProxyInfoHandler callback = 176 base::Bind(&CloudPrintProxyService::ProxyInfoCallback, 177 base::Unretained(this)); 178 // GetCloudPrintProxyInfo takes ownership of callback. 179 process_control->GetCloudPrintProxyInfo(callback); 180 } 181 182 void CloudPrintProxyService::EnableCloudPrintProxyWithRobot( 183 const std::string& robot_auth_code, 184 const std::string& robot_email, 185 const std::string& user_email, 186 const base::DictionaryValue* user_preferences) { 187 ServiceProcessControl* process_control = GetServiceProcessControl(); 188 DCHECK(process_control->IsConnected()); 189 process_control->Send( 190 new ServiceMsg_EnableCloudPrintProxyWithRobot( 191 robot_auth_code, robot_email, user_email, *user_preferences)); 192 // Assume the IPC worked. 193 profile_->GetPrefs()->SetString(prefs::kCloudPrintEmail, user_email); 194 } 195 196 void CloudPrintProxyService::DisableCloudPrintProxy() { 197 ServiceProcessControl* process_control = GetServiceProcessControl(); 198 DCHECK(process_control->IsConnected()); 199 process_control->Send(new ServiceMsg_DisableCloudPrintProxy); 200 // Assume the IPC worked. 201 profile_->GetPrefs()->SetString(prefs::kCloudPrintEmail, std::string()); 202 } 203 204 void CloudPrintProxyService::ProxyInfoCallback( 205 const cloud_print::CloudPrintProxyInfo& proxy_info) { 206 proxy_id_ = proxy_info.proxy_id; 207 profile_->GetPrefs()->SetString( 208 prefs::kCloudPrintEmail, 209 proxy_info.enabled ? proxy_info.email : std::string()); 210 ApplyCloudPrintConnectorPolicy(); 211 } 212 213 bool CloudPrintProxyService::InvokeServiceTask(const base::Closure& task) { 214 GetServiceProcessControl()->Launch(task, base::Closure()); 215 return true; 216 } 217 218 ServiceProcessControl* CloudPrintProxyService::GetServiceProcessControl() { 219 return ServiceProcessControl::GetInstance(); 220 } 221