// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/ash/crosapi/local_printer_ash.h"
#include <memory>
#include <optional>
#include <string>
#include <utility>
#include <vector>
#include "ash/constants/ash_features.h"
#include "ash/webui/settings/public/constants/routes.mojom.h"
#include "base/check.h"
#include "base/functional/bind.h"
#include "base/functional/callback.h"
#include "base/functional/callback_helpers.h"
#include "base/logging.h"
#include "base/memory/scoped_refptr.h"
#include "base/memory/weak_ptr.h"
#include "base/metrics/histogram_functions.h"
#include "base/values.h"
#include "chrome/browser/ash/printing/cups_print_job.h"
#include "chrome/browser/ash/printing/cups_print_job_manager.h"
#include "chrome/browser/ash/printing/cups_print_job_manager_factory.h"
#include "chrome/browser/ash/printing/cups_printers_manager.h"
#include "chrome/browser/ash/printing/cups_printers_manager_factory.h"
#include "chrome/browser/ash/printing/history/print_job_info.pb.h"
#include "chrome/browser/ash/printing/ipp_client_info_calculator.h"
#include "chrome/browser/ash/printing/oauth2/authorization_zones_manager.h"
#include "chrome/browser/ash/printing/oauth2/authorization_zones_manager_factory.h"
#include "chrome/browser/ash/printing/oauth2/status_code.h"
#include "chrome/browser/ash/printing/ppd_provider_factory.h"
#include "chrome/browser/ash/printing/print_management/printing_manager.h"
#include "chrome/browser/ash/printing/print_management/printing_manager_factory.h"
#include "chrome/browser/ash/printing/print_server.h"
#include "chrome/browser/ash/printing/print_servers_manager.h"
#include "chrome/browser/ash/printing/printer_authenticator.h"
#include "chrome/browser/ash/printing/printer_setup_util.h"
#include "chrome/browser/ash/profiles/profile_helper.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/printing/local_printer_utils_chromeos.h"
#include "chrome/browser/printing/prefs_util.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/ui/settings_window_manager_chromeos.h"
#include "chrome/common/pref_names.h"
#include "chromeos/crosapi/mojom/local_printer.mojom.h"
#include "chromeos/printing/ppd_provider.h"
#include "chromeos/printing/printer_configuration.h"
#include "components/prefs/pref_service.h"
#include "components/user_manager/user.h"
#include "components/user_manager/user_manager.h"
#include "mojo/public/cpp/bindings/receiver_set.h"
#include "mojo/public/cpp/bindings/remote_set.h"
#include "printing/backend/print_backend.h"
#include "printing/mojom/print.mojom.h"
#include "printing/print_job_constants.h"
#include "printing/print_settings.h"
#include "printing/printing_features.h"
#include "printing/printing_utils.h"
#include "url/gurl.h"
namespace crosapi {
namespace {
// Generates and returns a url for a PPD license which is empty if
// an error occurs e.g. the ppd provider callback failed.
// When bound to a ppd provider scoped refptr, the reference count
// will be decremented once the callback is done executing and the
// ppd provider destroyed if it hits zero.
GURL GenerateEulaUrl(scoped_refptr<chromeos::PpdProvider>,
chromeos::PpdProvider::CallbackResultCode result,
const std::string& license) {
if (result != chromeos::PpdProvider::CallbackResultCode::SUCCESS ||
license.empty()) {
return GURL();
}
return ash::PrinterConfigurer::GeneratePrinterEulaUrl(license);
}
mojom::CapabilitiesResponsePtr OnSetUpPrinter(
const chromeos::Printer& printer,
const std::optional<printing::PrinterSemanticCapsAndDefaults>& caps) {
return printing::PrinterWithCapabilitiesToMojom(printer, caps);
}
void SetUpPrinter(ash::CupsPrintersManager* printers_manager,
const chromeos::Printer& printer,
mojom::LocalPrinter::GetCapabilityCallback callback) {
ash::printing::SetUpPrinter(
printers_manager, printer,
base::BindOnce(OnSetUpPrinter, printer).Then(std::move(callback)));
}
// Mark if a not yet installed printer is autoconf then continue with setup.
void OnPrinterQueriedForAutoConf(
ash::CupsPrintersManager* printers_manager,
mojom::LocalPrinter::GetCapabilityCallback callback,
chromeos::Printer printer,
bool is_printer_autoconf) {
if (!is_printer_autoconf) {
std::move(callback).Run(nullptr);
return;
}
printer.mutable_ppd_reference()->autoconf = true;
SetUpPrinter(printers_manager, printer, std::move(callback));
}
// This function is called when user's rights to access the printer were
// verified. The user can use the printer <=> `status` == StatusCode::kOK.
// Other values of `status` mean that the access was denied or an error
// occurred. The function is supposed to set-up the printer <=> the access was
// granted. The first parameter is used only for keep the pointer alive until
// this callback is executed.
void OnPrinterAuthenticated(
std::unique_ptr<ash::printing::PrinterAuthenticator> /* authenticator */,
ash::CupsPrintersManager* printers_manager,
const chromeos::Printer& printer,
mojom::LocalPrinter::GetCapabilityCallback callback,
ash::printing::oauth2::StatusCode status,
std::string /* access_token */) {
if (status != ash::printing::oauth2::StatusCode::kOK) {
// An error occurred.
std::move(callback).Run(nullptr);
return;
}
// In order for an IPP printer to be valid for set up, it needs to either be
// previously installed, be autoconf compatible, or have a valid PPD
// reference. If necessary, the printer is queried to determine its autoconf
// compatibility.
if (!printers_manager->IsPrinterInstalled(printer)) {
if (!printer.HasUri()) {
std::move(callback).Run(nullptr);
return;
}
// If the printer is autoconf compatible or has a valid PPD reference then
// continue with normal setup.
if (printer.ppd_reference().IsFilled()) {
SetUpPrinter(printers_manager, printer, std::move(callback));
return;
}
// CupsPrintersManager should have marked compatible USB printers as having
// a valid PPD reference or autoconf, so this USB printer is incompatible.
if (printer.IsUsbProtocol()) {
std::move(callback).Run(nullptr);
return;
}
printers_manager->QueryPrinterForAutoConf(
printer, base::BindOnce(OnPrinterQueriedForAutoConf, printers_manager,
std::move(callback), printer));
return;
}
SetUpPrinter(printers_manager, printer, std::move(callback));
}
void OnOAuthAccessTokenObtained(
std::unique_ptr<ash::printing::PrinterAuthenticator> /* authenticator */,
mojom::LocalPrinter::GetOAuthAccessTokenCallback callback,
ash::printing::oauth2::StatusCode status,
std::string access_token) {
if (status != ash::printing::oauth2::StatusCode::kOK) {
// An error occurred.
std::move(callback).Run(
mojom::GetOAuthAccessTokenResult::NewError(mojom::OAuthError::New()));
return;
}
if (access_token.empty()) {
std::move(callback).Run(mojom::GetOAuthAccessTokenResult::NewNone(
mojom::OAuthNotNeeded::New()));
} else {
std::move(callback).Run(mojom::GetOAuthAccessTokenResult::NewToken(
mojom::OAuthAccessToken::New(std::move(access_token))));
}
}
bool IsActiveUserAffiliated() {
// TODO(b/265832837): Figure out if we can rely on `UserManager` always being
// initialized at this point. Currently it is initialized before
// `LocalPrinterAsh` so `UserManager::IsInitialized()` may be unnecessary.
// Also figure out if `GetActiveUser()` can return nullptr. This could happen
// if this function is called before login.
const user_manager::User* user =
user_manager::UserManager::IsInitialized()
? user_manager::UserManager::Get()->GetActiveUser()
: nullptr;
return user ? user->IsAffiliated() : false;
}
bool IsManagedPrinter(const chromeos::Printer& printer) {
return printer.source() == chromeos::Printer::SRC_POLICY;
}
bool IsSecureIppPrinter(const chromeos::Printer& printer) {
return printer.GetProtocol() == chromeos::Printer::PrinterProtocol::kIpps ||
printer.GetProtocol() == chromeos::Printer::PrinterProtocol::kIppUsb;
}
std::vector<chromeos::Printer> GetLocalPrinters(Profile* profile) {
CHECK(profile);
std::vector<chromeos::PrinterClass> printer_classes_to_fetch = {
chromeos::PrinterClass::kSaved, chromeos::PrinterClass::kEnterprise,
chromeos::PrinterClass::kAutomatic, chromeos::PrinterClass::kDiscovered};
// Printing is not allowed during OOBE.
DCHECK(!ash::ProfileHelper::IsSigninProfile(profile));
ash::CupsPrintersManager* printers_manager =
ash::CupsPrintersManagerFactory::GetForBrowserContext(profile);
std::vector<chromeos::Printer> printers;
for (chromeos::PrinterClass pc : printer_classes_to_fetch) {
for (const chromeos::Printer& p : printers_manager->GetPrinters(pc)) {
VLOG(1) << "Found printer " << p.display_name() << " with device name "
<< p.id();
printers.push_back(p);
}
}
return printers;
}
std::vector<mojom::LocalDestinationInfoPtr> ConvertPrintersToMojom(
const std::vector<chromeos::Printer>& printers) {
std::vector<mojom::LocalDestinationInfoPtr> mojom_printers;
for (const auto& printer : printers) {
mojom_printers.push_back(printing::PrinterToMojom(printer));
}
return mojom_printers;
}
} // namespace
LocalPrinterAsh::LocalPrinterAsh() {
auto* profile_manager = g_browser_process->profile_manager();
if (profile_manager) {
profile_manager_observer_.Observe(profile_manager);
}
}
LocalPrinterAsh::~LocalPrinterAsh() = default;
// static
mojom::PrintServersConfigPtr LocalPrinterAsh::ConfigToMojom(
const ash::PrintServersConfig& config) {
mojom::PrintServersConfigPtr ptr = mojom::PrintServersConfig::New();
ptr->fetching_mode = config.fetching_mode;
for (const ash::PrintServer& server : config.print_servers) {
ptr->print_servers.push_back(mojom::PrintServer::New(
server.GetId(), server.GetUrl(), server.GetName()));
}
return ptr;
}
void LocalPrinterAsh::BindReceiver(
mojo::PendingReceiver<mojom::LocalPrinter> pending_receiver) {
receivers_.Add(this, std::move(pending_receiver));
}
void LocalPrinterAsh::OnProfileAdded(Profile* profile) {
if (observers_registered_ || !ash::ProfileHelper::IsPrimaryProfile(profile)) {
return;
}
auto* printers_manager_factory =
ash::CupsPrintersManagerFactory::GetForBrowserContext(profile);
// In unit tests, `printers_manager_factory` can be null.
if (!printers_manager_factory) {
LOG(ERROR) << "CupsPrintersManagerFactory object not found";
return;
}
observers_registered_ = true;
// RemoveObserver() is not called since this object outlasts the
// BrowserContextKeyedServices it's observing -
// BrowserContextKeyedServices are destroyed in
// ChromeBrowserMainParts::PostMainMessageLoopRun() while this object is
// destroyed in ~ChromeBrowserMainParts().
auto* print_servers_manager =
printers_manager_factory->GetPrintServersManager();
if (print_servers_manager) {
print_servers_manager->AddObserver(this);
} else {
// This can occur during browser tests.
LOG(ERROR) << "PrintServersManager object not found";
}
auto* print_job_manager =
ash::CupsPrintJobManagerFactory::GetForBrowserContext(profile);
print_job_manager->AddObserver(this);
}
void LocalPrinterAsh::OnProfileManagerDestroying() {
profile_manager_observer_.Reset();
}
void LocalPrinterAsh::OnPrintJobCreated(base::WeakPtr<ash::CupsPrintJob> job) {
NotifyPrintJobUpdate(job, mojom::PrintJobStatus::kCreated);
}
void LocalPrinterAsh::OnPrintJobStarted(base::WeakPtr<ash::CupsPrintJob> job) {
NotifyPrintJobUpdate(job, mojom::PrintJobStatus::kStarted);
}
void LocalPrinterAsh::OnPrintJobUpdated(base::WeakPtr<ash::CupsPrintJob> job) {
NotifyPrintJobUpdate(job, mojom::PrintJobStatus::kUpdated);
}
void LocalPrinterAsh::OnPrintJobSuspended(
base::WeakPtr<ash::CupsPrintJob> job) {
NotifyPrintJobUpdate(job, mojom::PrintJobStatus::kSuspended);
}
void LocalPrinterAsh::OnPrintJobResumed(base::WeakPtr<ash::CupsPrintJob> job) {
NotifyPrintJobUpdate(job, mojom::PrintJobStatus::kResumed);
}
void LocalPrinterAsh::OnPrintJobDone(base::WeakPtr<ash::CupsPrintJob> job) {
NotifyPrintJobUpdate(job, mojom::PrintJobStatus::kDone);
}
void LocalPrinterAsh::OnPrintJobError(base::WeakPtr<ash::CupsPrintJob> job) {
NotifyPrintJobUpdate(job, mojom::PrintJobStatus::kError);
}
void LocalPrinterAsh::OnPrintJobCancelled(
base::WeakPtr<ash::CupsPrintJob> job) {
NotifyPrintJobUpdate(job, mojom::PrintJobStatus::kCancelled);
}
void LocalPrinterAsh::NotifyPrintJobUpdate(base::WeakPtr<ash::CupsPrintJob> job,
mojom::PrintJobStatus status) {
if (!job) {
LOG(WARNING) << "Ignoring invalid print job";
return;
}
const auto& printer_id = job->printer().id();
const auto& job_id = job->job_id();
auto update = mojom::PrintJobUpdate::New();
update->status = status;
update->pages_printed = job->printed_page_number();
for (auto& remote : print_job_remotes_) {
remote->OnPrintJobUpdate(printer_id, job_id, update.Clone());
}
switch (job->source()) {
case mojom::PrintJob::Source::kExtension:
for (auto& remote : extension_print_job_remotes_) {
remote->OnPrintJobUpdate(printer_id, job_id, update.Clone());
}
break;
case mojom::PrintJob::Source::kIsolatedWebApp:
for (auto& remote : iwa_print_job_remotes_) {
remote->OnPrintJobUpdate(printer_id, job_id, update.Clone());
}
break;
default:
break;
}
}
void LocalPrinterAsh::OnPrintServersChanged(
const ash::PrintServersConfig& config) {
for (auto& remote : print_server_remotes_) {
remote->OnPrintServersChanged(LocalPrinterAsh::ConfigToMojom(config));
}
}
void LocalPrinterAsh::OnServerPrintersChanged(
const std::vector<ash::PrinterDetector::DetectedPrinter>&) {
for (auto& remote : print_server_remotes_) {
remote->OnServerPrintersChanged();
}
}
void LocalPrinterAsh::OnLocalPrintersUpdated() {
Profile* profile = GetProfile();
DCHECK(profile);
const std::vector<mojom::LocalDestinationInfoPtr> printers =
ConvertPrintersToMojom(GetLocalPrinters(profile));
for (const auto& remote : local_printers_observer_remotes_) {
remote->OnLocalPrintersUpdated(mojo::Clone(printers));
}
}
void LocalPrinterAsh::GetPrinters(GetPrintersCallback callback) {
std::move(callback).Run(
ConvertPrintersToMojom(GetLocalPrinters(GetProfile())));
}
void LocalPrinterAsh::GetCapability(const std::string& printer_id,
GetCapabilityCallback callback) {
Profile* profile = GetProfile();
DCHECK(profile);
ash::CupsPrintersManager* printers_manager =
ash::CupsPrintersManagerFactory::GetForBrowserContext(profile);
DCHECK(printers_manager);
std::optional<chromeos::Printer> printer =
printers_manager->GetPrinter(printer_id);
if (!printer) {
// If the printer was removed, the lookup will fail.
std::move(callback).Run(nullptr);
return;
}
if (ash::features::IsOAuthIppEnabled()) {
ash::printing::oauth2::AuthorizationZonesManager* auth_manager =
ash::printing::oauth2::AuthorizationZonesManagerFactory::
GetForBrowserContext(profile);
DCHECK(auth_manager);
auto authenticator = std::make_unique<ash::printing::PrinterAuthenticator>(
printers_manager, auth_manager, *printer);
ash::printing::PrinterAuthenticator* authenticator_ptr =
authenticator.get();
authenticator_ptr->ObtainAccessTokenIfNeeded(
base::BindOnce(OnPrinterAuthenticated, std::move(authenticator),
printers_manager, *printer, std::move(callback)));
} else {
OnPrinterAuthenticated(nullptr, printers_manager, *printer,
std::move(callback),
ash::printing::oauth2::StatusCode::kOK, "");
}
}
void LocalPrinterAsh::GetEulaUrl(const std::string& printer_id,
GetEulaUrlCallback callback) {
Profile* profile = GetProfile();
DCHECK(profile);
ash::CupsPrintersManager* printers_manager =
ash::CupsPrintersManagerFactory::GetForBrowserContext(profile);
std::optional<chromeos::Printer> printer =
printers_manager->GetPrinter(printer_id);
if (!printer) {
// If the printer does not exist, fetching for the license will fail.
std::move(callback).Run(GURL());
return;
}
scoped_refptr<chromeos::PpdProvider> ppd_provider =
CreatePpdProvider(profile);
ppd_provider->ResolvePpdLicense(
printer->ppd_reference().effective_make_and_model,
base::BindOnce(GenerateEulaUrl, ppd_provider).Then(std::move(callback)));
}
void LocalPrinterAsh::GetStatus(const std::string& printer_id,
GetStatusCallback callback) {
Profile* profile = GetProfile();
DCHECK(profile);
ash::CupsPrintersManager* printers_manager =
ash::CupsPrintersManagerFactory::GetForBrowserContext(profile);
printers_manager->FetchPrinterStatus(
printer_id,
base::BindOnce(printing::StatusToMojom).Then(std::move(callback)));
}
void LocalPrinterAsh::ShowSystemPrintSettings(
ShowSystemPrintSettingsCallback callback) {
Profile* profile = GetProfile();
DCHECK(profile);
chrome::SettingsWindowManager::GetInstance()->ShowOSSettings(
profile, chromeos::settings::mojom::kPrintingDetailsSubpagePath);
std::move(callback).Run();
}
void LocalPrinterAsh::CreatePrintJob(mojom::PrintJobPtr job,
CreatePrintJobCallback callback) {
Profile* profile = GetProfile();
DCHECK(profile);
ash::CupsPrintJobManager* print_job_manager =
ash::CupsPrintJobManagerFactory::GetForBrowserContext(profile);
ash::printing::proto::PrintSettings settings;
settings.set_color(
printing::IsColorModelSelected(job->color_mode).value()
? ash::printing::proto::PrintSettings_ColorMode_COLOR
: ash::printing::proto::PrintSettings_ColorMode_BLACK_AND_WHITE);
settings.set_duplex(
static_cast<ash::printing::proto::PrintSettings_DuplexMode>(
job->duplex_mode));
settings.set_copies(job->copies);
ash::printing::proto::MediaSize media_size;
media_size.set_width(job->media_size.width());
media_size.set_height(job->media_size.height());
media_size.set_vendor_id(job->media_vendor_id);
*settings.mutable_media_size() = media_size;
print_job_manager->CreatePrintJob(job->device_name, job->title, job->job_id,
job->page_count, job->source,
job->source_id, std::move(settings));
std::move(callback).Run();
}
void LocalPrinterAsh::CancelPrintJob(const std::string& printer_id,
unsigned int job_id,
CancelPrintJobCallback callback) {
Profile* profile = GetProfile();
DCHECK(profile);
ash::printing::print_management::PrintingManagerFactory::GetForProfile(
profile)
->CancelPrintJob(ash::CupsPrintJob::CreateUniqueId(printer_id, job_id),
std::move(callback));
}
void LocalPrinterAsh::GetPrintServersConfig(
GetPrintServersConfigCallback callback) {
Profile* profile = GetProfile();
DCHECK(profile);
ash::PrintServersManager* print_servers_manager =
ash::CupsPrintersManagerFactory::GetForBrowserContext(profile)
->GetPrintServersManager();
std::move(callback).Run(
ConfigToMojom(print_servers_manager->GetPrintServersConfig()));
}
void LocalPrinterAsh::ChoosePrintServers(
const std::vector<std::string>& print_server_ids,
ChoosePrintServersCallback callback) {
Profile* profile = GetProfile();
DCHECK(profile);
ash::PrintServersManager* print_servers_manager =
ash::CupsPrintersManagerFactory::GetForBrowserContext(profile)
->GetPrintServersManager();
print_servers_manager->ChoosePrintServer(print_server_ids);
std::move(callback).Run();
}
void LocalPrinterAsh::AddPrintServerObserver(
mojo::PendingRemote<mojom::PrintServerObserver> remote,
AddPrintServerObserverCallback callback) {
print_server_remotes_.Add(std::move(remote));
std::move(callback).Run();
}
void LocalPrinterAsh::GetPolicies(GetPoliciesCallback callback) {
Profile* profile = GetProfile();
PrefService* prefs = profile->GetPrefs();
mojom::PoliciesPtr policies = mojom::Policies::New();
if (prefs->HasPrefPath(prefs::kPrintHeaderFooter)) {
(prefs->IsManagedPreference(prefs::kPrintHeaderFooter)
? policies->print_header_footer_allowed
: policies->print_header_footer_default) =
prefs->GetBoolean(prefs::kPrintHeaderFooter)
? mojom::Policies::OptionalBool::kTrue
: mojom::Policies::OptionalBool::kFalse;
}
if (prefs->HasPrefPath(prefs::kPrintingAllowedBackgroundGraphicsModes)) {
policies->allowed_background_graphics_modes =
static_cast<mojom::Policies::BackgroundGraphicsModeRestriction>(
prefs->GetInteger(prefs::kPrintingAllowedBackgroundGraphicsModes));
}
if (prefs->HasPrefPath(prefs::kPrintingBackgroundGraphicsDefault)) {
policies->background_graphics_default =
static_cast<mojom::Policies::BackgroundGraphicsModeRestriction>(
prefs->GetInteger(prefs::kPrintingBackgroundGraphicsDefault));
}
policies->paper_size_default = printing::ParsePaperSizeDefault(*prefs);
if (prefs->HasPrefPath(prefs::kPrintingMaxSheetsAllowed)) {
int max_sheets = prefs->GetInteger(prefs::kPrintingMaxSheetsAllowed);
if (max_sheets >= 0) {
policies->max_sheets_allowed = max_sheets;
policies->max_sheets_allowed_has_value = true;
}
}
if (prefs->HasPrefPath(prefs::kPrintingAllowedColorModes)) {
policies->allowed_color_modes =
prefs->GetInteger(prefs::kPrintingAllowedColorModes);
}
if (prefs->HasPrefPath(prefs::kPrintingAllowedDuplexModes)) {
policies->allowed_duplex_modes =
prefs->GetInteger(prefs::kPrintingAllowedDuplexModes);
}
if (prefs->HasPrefPath(prefs::kPrintingAllowedPinModes)) {
policies->allowed_pin_modes =
static_cast<printing::mojom::PinModeRestriction>(
prefs->GetInteger(prefs::kPrintingAllowedPinModes));
}
if (prefs->HasPrefPath(prefs::kPrintingColorDefault)) {
policies->default_color_mode =
static_cast<printing::mojom::ColorModeRestriction>(
prefs->GetInteger(prefs::kPrintingColorDefault));
}
if (prefs->HasPrefPath(prefs::kPrintingDuplexDefault)) {
policies->default_duplex_mode =
static_cast<printing::mojom::DuplexModeRestriction>(
prefs->GetInteger(prefs::kPrintingDuplexDefault));
}
if (prefs->HasPrefPath(prefs::kPrintingPinDefault)) {
policies->default_pin_mode =
static_cast<printing::mojom::PinModeRestriction>(
prefs->GetInteger(prefs::kPrintingPinDefault));
}
if (prefs->HasPrefPath(prefs::kPrintPdfAsImageDefault)) {
policies->default_print_pdf_as_image =
prefs->GetBoolean(prefs::kPrintPdfAsImageDefault)
? mojom::Policies::OptionalBool::kTrue
: mojom::Policies::OptionalBool::kFalse;
}
std::move(callback).Run(std::move(policies));
}
void LocalPrinterAsh::GetUsernamePerPolicy(
GetUsernamePerPolicyCallback callback) {
Profile* profile = GetProfile();
const std::string username =
ash::ProfileHelper::Get()->GetUserByProfile(profile)->display_email();
std::move(callback).Run(profile->GetPrefs()->GetBoolean(
prefs::kPrintingSendUsernameAndFilenameEnabled)
? std::make_optional(username)
: std::nullopt);
}
void LocalPrinterAsh::GetPrinterTypeDenyList(
GetPrinterTypeDenyListCallback callback) {
Profile* profile = GetProfile();
PrefService* prefs = profile->GetPrefs();
std::vector<printing::mojom::PrinterType> deny_list;
if (!prefs->HasPrefPath(prefs::kPrinterTypeDenyList)) {
std::move(callback).Run(deny_list);
return;
}
const base::Value& deny_list_from_prefs =
prefs->GetValue(prefs::kPrinterTypeDenyList);
deny_list.reserve(deny_list_from_prefs.GetList().size());
for (const base::Value& deny_list_value : deny_list_from_prefs.GetList()) {
const std::string& deny_list_str = deny_list_value.GetString();
printing::mojom::PrinterType printer_type;
if (deny_list_str == "extension") {
printer_type = printing::mojom::PrinterType::kExtension;
} else if (deny_list_str == "pdf") {
printer_type = printing::mojom::PrinterType::kPdf;
} else if (deny_list_str == "local") {
printer_type = printing::mojom::PrinterType::kLocal;
} else {
continue;
}
deny_list.push_back(printer_type);
}
std::move(callback).Run(deny_list);
}
Profile* LocalPrinterAsh::GetProfile() {
if (!user_manager::UserManager::IsInitialized() ||
!user_manager::UserManager::Get()->IsUserLoggedIn()) {
return nullptr;
}
return ProfileManager::GetPrimaryUserProfile();
}
void LocalPrinterAsh::AddPrintJobObserver(
mojo::PendingRemote<mojom::PrintJobObserver> remote,
mojom::PrintJobSource source,
AddPrintJobObserverCallback callback) {
switch (source) {
case mojom::PrintJobSource::kExtension:
extension_print_job_remotes_.Add(std::move(remote));
break;
case mojom::PrintJobSource::kIsolatedWebApp:
iwa_print_job_remotes_.Add(std::move(remote));
break;
case mojom::PrintJobSource::kAny:
print_job_remotes_.Add(std::move(remote));
break;
}
std::move(callback).Run();
}
void LocalPrinterAsh::AddLocalPrintersObserver(
mojo::PendingRemote<mojom::LocalPrintersObserver> remote,
AddLocalPrintersObserverCallback callback) {
Profile* profile = GetProfile();
DCHECK(profile);
ash::CupsPrintersManager* printers_manager =
ash::CupsPrintersManagerFactory::GetForBrowserContext(profile);
printers_manager->AddLocalPrintersObserver(this);
local_printers_observer_remotes_.Add(std::move(remote));
std::move(callback).Run(ConvertPrintersToMojom(GetLocalPrinters(profile)));
}
void LocalPrinterAsh::GetOAuthAccessToken(
const std::string& printer_id,
GetOAuthAccessTokenCallback callback) {
if (!ash::features::IsOAuthIppEnabled()) {
std::move(callback).Run(mojom::GetOAuthAccessTokenResult::NewNone(
mojom::OAuthNotNeeded::New()));
return;
}
Profile* profile = GetProfile();
DCHECK(profile);
ash::CupsPrintersManager* printers_manager =
ash::CupsPrintersManagerFactory::GetForBrowserContext(profile);
DCHECK(printers_manager);
std::optional<chromeos::Printer> printer =
printers_manager->GetPrinter(printer_id);
if (!printer) {
// If the printer was removed, the lookup will fail.
std::move(callback).Run(
mojom::GetOAuthAccessTokenResult::NewError(mojom::OAuthError::New()));
return;
}
ash::printing::oauth2::AuthorizationZonesManager* auth_manager =
ash::printing::oauth2::AuthorizationZonesManagerFactory::
GetForBrowserContext(profile);
DCHECK(auth_manager);
auto authenticator = std::make_unique<ash::printing::PrinterAuthenticator>(
printers_manager, auth_manager, *printer);
ash::printing::PrinterAuthenticator* authenticator_ptr = authenticator.get();
authenticator_ptr->ObtainAccessTokenIfNeeded(
base::BindOnce(OnOAuthAccessTokenObtained, std::move(authenticator),
std::move(callback)));
}
void LocalPrinterAsh::GetIppClientInfo(const std::string& printer_id,
GetIppClientInfoCallback callback) {
if (!ash::features::IsIppClientInfoEnabled()) {
std::move(callback).Run({});
return;
}
Profile* profile = GetProfile();
DCHECK(profile);
ash::CupsPrintersManager* printers_manager =
ash::CupsPrintersManagerFactory::GetForBrowserContext(profile);
DCHECK(printers_manager);
std::optional<chromeos::Printer> printer =
printers_manager->GetPrinter(printer_id);
if (!printer) {
std::move(callback).Run({});
return;
}
std::vector<printing::mojom::IppClientInfoPtr> result;
result.emplace_back(GetIppClientInfoCalculator()->GetOsInfo());
if (IsManagedPrinter(*printer) && IsSecureIppPrinter(*printer) &&
IsActiveUserAffiliated()) {
printing::mojom::IppClientInfoPtr device_info =
GetIppClientInfoCalculator()->GetDeviceInfo();
if (device_info) {
result.push_back(std::move(device_info));
}
}
std::move(callback).Run(std::move(result));
}
scoped_refptr<chromeos::PpdProvider> LocalPrinterAsh::CreatePpdProvider(
Profile* profile) {
return ash::CreatePpdProvider(profile);
}
ash::printing::IppClientInfoCalculator*
LocalPrinterAsh::GetIppClientInfoCalculator() {
if (!ipp_client_info_calculator_) {
ipp_client_info_calculator_ =
ash::printing::IppClientInfoCalculator::Create();
}
return ipp_client_info_calculator_.get();
}
} // namespace crosapi