1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129
|
// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <algorithm>
#include <array>
#include <string>
#include "base/functional/bind.h"
#include "base/logging.h"
#include "base/metrics/histogram_functions.h"
#include "base/task/task_traits.h"
#include "base/task/thread_pool.h"
#include "base/version.h"
#include "chrome/browser/ash/printing/printer_info.h"
#include "chromeos/printing/cups_printer_status.h"
#include "chromeos/printing/printer_configuration.h"
#include "printing/backend/cups_jobs.h"
#include "printing/printer_status.h"
namespace {
const char kPdfMimeType[] = "application/pdf";
const char kPwgRasterMimeType[] = "image/pwg-raster";
// Wraps several printing data structures so that we can use
// PostTaskAndReplyWithResult().
struct QueryResult {
printing::PrinterQueryResult result;
printing::PrinterInfo printer_info;
printing::PrinterStatus printer_status;
};
// Returns true if any of the |ipp_versions| are greater than or equal to 2.0.
bool AllowedIpp(const std::vector<base::Version>& ipp_versions) {
return std::ranges::any_of(ipp_versions, [](const base::Version& version) {
return version.IsValid() && version.components()[0] >= 2;
});
}
// Returns true if |mime_type| is one of the supported types.
bool SupportedMime(const std::string& mime_type) {
return mime_type == kPwgRasterMimeType || mime_type == kPdfMimeType;
}
// Returns true if |formats| contains one of the supported printer description
// languages for an autoconf printer identified by MIME type.
bool SupportsRequiredPDLS(const std::vector<std::string>& formats) {
return std::ranges::any_of(formats, &SupportedMime);
}
// Returns true if |info| describes a printer for which we want to attempt
// automatic configuration.
bool IsAutoconf(const ::printing::PrinterInfo& info) {
return info.ipp_everywhere || (AllowedIpp(info.ipp_versions) &&
SupportsRequiredPDLS(info.document_formats));
}
// Dispatches an IPP request to |host| to retrieve printer information. Returns
// a nullptr if the request fails.
QueryResult QueryPrinterImpl(const std::string& host,
const int port,
const std::string& path,
bool encrypted) {
QueryResult result;
result.result =
::printing::GetPrinterInfo(host, port, path, encrypted,
&result.printer_info, &result.printer_status);
if (result.result != ::printing::PrinterQueryResult::kSuccess) {
LOG(ERROR) << "Could not retrieve printer info from "
<< (encrypted ? "ipps://" : "ipp://") << host << ":" << port
<< path << ": " << static_cast<int>(result.result);
}
return result;
}
// Handles the request for |info|. Parses make and model information before
// calling |callback|.
void OnPrinterQueried(ash::PrinterInfoCallback callback,
const QueryResult& query_result) {
const ::printing::PrinterQueryResult& result = query_result.result;
const ::printing::PrinterInfo& printer_info = query_result.printer_info;
const ::printing::PrinterStatus& printer_status = query_result.printer_status;
if (result != ::printing::PrinterQueryResult::kSuccess) {
VLOG(1) << "Could not reach printer";
std::move(callback).Run(result, ::printing::PrinterStatus(),
/*make_and_model=*/std::string(),
/*document_formats=*/{}, /*ipp_everywhere=*/false,
chromeos::PrinterAuthenticationInfo{},
chromeos::IppPrinterInfo{});
return;
}
std::move(callback).Run(
result, printer_status, printer_info.make_and_model,
printer_info.document_formats, IsAutoconf(printer_info),
{.oauth_server = printer_info.oauth_server,
.oauth_scope = printer_info.oauth_scope},
{/*document_formats=*/printer_info.document_formats,
/*document_format_default=*/printer_info.document_format_default,
/*document_format_preferred=*/printer_info.document_format_preferred,
/*urf_supported=*/printer_info.urf_supported,
/*pdf_versions=*/printer_info.pdf_versions,
/*ipp_features=*/printer_info.ipp_features,
/*mopria_certified=*/printer_info.mopria_certified,
/*printer_kind=*/printer_info.printer_kind});
}
} // namespace
namespace ash {
void QueryIppPrinter(const std::string& host,
const int port,
const std::string& path,
bool encrypted,
PrinterInfoCallback callback) {
DCHECK(!host.empty());
// QueryPrinterImpl could block on a network call for a noticable amount of
// time (100s of ms). Also the user is waiting on this result. Thus, run at
// USER_VISIBLE with MayBlock.
base::ThreadPool::PostTaskAndReplyWithResult(
FROM_HERE, {base::TaskPriority::USER_VISIBLE, base::MayBlock()},
base::BindOnce(&QueryPrinterImpl, host, port, path, encrypted),
base::BindOnce(&OnPrinterQueried, std::move(callback)));
}
} // namespace ash
|