Chromium Code Reviews| Index: printing/backend/cups_jobs.cc |
| diff --git a/printing/backend/cups_jobs.cc b/printing/backend/cups_jobs.cc |
| index e73ae8fb331041aaa5754074a924856980eca18d..f2a9b5b01f183a776011adb857fbc6ae96c0e4d0 100644 |
| --- a/printing/backend/cups_jobs.cc |
| +++ b/printing/backend/cups_jobs.cc |
| @@ -11,8 +11,14 @@ |
| #include <memory> |
| #include "base/logging.h" |
| +#include "base/stl_util.h" |
| +#include "base/strings/string_number_conversions.h" |
|
Lei Zhang
2017/05/31 23:00:03
Probably don't need this and string_split.h anymor
skau
2017/06/01 22:50:45
Done.
|
| #include "base/strings/string_piece.h" |
| +#include "base/strings/string_split.h" |
| #include "base/strings/stringprintf.h" |
| +#include "base/threading/thread_restrictions.h" |
| +#include "base/version.h" |
| +#include "printing/backend/cups_deleters.h" |
| namespace printing { |
| namespace { |
| @@ -26,6 +32,11 @@ const char kPrinterState[] = "printer-state"; |
| const char kPrinterStateReasons[] = "printer-state-reasons"; |
| const char kPrinterStateMessage[] = "printer-state-message"; |
| +const char kPrinterMakeAndModel[] = "printer-make-and-model"; |
| +const char kIppVersionsSupported[] = "ipp-versions-supported"; |
| +const char kIppFeaturesSupported[] = "ipp-features-supported"; |
| +const char kDocumentFormatSupported[] = "document-format-supported"; |
| + |
| // job attributes |
| const char kJobUri[] = "job-uri"; |
| const char kJobId[] = "job-id"; |
| @@ -44,6 +55,9 @@ const char kLimit[] = "limit"; |
| const char kCompleted[] = "completed"; |
| const char kNotCompleted[] = "not-completed"; |
| +// ipp features |
| +const char kIppEverywhere[] = "ipp-everywhere"; |
| + |
| // printer state severities |
| const char kSeverityReport[] = "report"; |
| const char kSeverityWarn[] = "warning"; |
| @@ -88,10 +102,18 @@ const char kInterpreterResourceUnavailable[] = |
| constexpr std::array<const char* const, 3> kPrinterAttributes{ |
| {kPrinterState, kPrinterStateReasons, kPrinterStateMessage}}; |
| -std::unique_ptr<ipp_t, void (*)(ipp_t*)> WrapIpp(ipp_t* ipp) { |
| - return std::unique_ptr<ipp_t, void (*)(ipp_t*)>(ipp, &ippDelete); |
| +constexpr std::array<const char* const, 4> kPrinterInfo{ |
| + {kPrinterMakeAndModel, kIppVersionsSupported, kIppFeaturesSupported, |
| + kDocumentFormatSupported}}; |
| + |
| +using ScopedIppPtr = std::unique_ptr<ipp_t, void (*)(ipp_t*)>; |
| + |
| +ScopedIppPtr WrapIpp(ipp_t* ipp) { |
| + return ScopedIppPtr(ipp, &ippDelete); |
| } |
| +using ScopedHttpPtr = std::unique_ptr<http_t, HttpDeleter>; |
| + |
| // Converts an IPP attribute |attr| to the appropriate JobState enum. |
| CupsJob::JobState ToJobState(ipp_attribute_t* attr) { |
| DCHECK_EQ(IPP_TAG_ENUM, ippGetValueTag(attr)); |
| @@ -281,6 +303,40 @@ std::string PrinterUriFromName(const std::string& id) { |
| return base::StringPrintf("ipp://localhost/printers/%s", id.c_str()); |
| } |
| +// Extracts PrinterInfo fields from |response| and populates |printer_info|. |
| +// Returns true if at least printer-make-and-model and ipp-versions-supported |
| +// were read. |
| +bool ParsePrinterInfo(ipp_t* response, PrinterInfo* printer_info) { |
| + for (ipp_attribute_t* attr = ippFirstAttribute(response); attr != nullptr; |
| + attr = ippNextAttribute(response)) { |
| + base::StringPiece name = ippGetName(attr); |
| + |
| + if (name == base::StringPiece(kPrinterMakeAndModel)) { |
| + DCHECK_EQ(IPP_TAG_TEXT, ippGetValueTag(attr)); |
| + printer_info->make_and_model = ippGetString(attr, 0, nullptr); |
| + } else if (name == base::StringPiece(kIppVersionsSupported)) { |
| + std::vector<std::string> ipp_versions; |
| + ParseCollection(attr, &ipp_versions); |
| + for (const std::string& version : ipp_versions) { |
| + base::Version major_minor(version); |
| + if (major_minor.IsValid()) { |
| + printer_info->ipp_versions.push_back(major_minor); |
| + } |
| + } |
| + } else if (name == base::StringPiece(kIppFeaturesSupported)) { |
| + std::vector<std::string> features; |
| + ParseCollection(attr, &features); |
| + printer_info->ipp_everywhere = |
| + base::ContainsValue(features, kIppEverywhere); |
| + } else if (name == base::StringPiece(kDocumentFormatSupported)) { |
| + ParseCollection(attr, &printer_info->document_formats); |
| + } |
| + } |
| + |
| + return !printer_info->make_and_model.empty() && |
| + !printer_info->ipp_versions.empty(); |
| +} |
| + |
| } // namespace |
| CupsJob::CupsJob() = default; |
| @@ -295,6 +351,10 @@ PrinterStatus::PrinterStatus(const PrinterStatus& other) = default; |
| PrinterStatus::~PrinterStatus() = default; |
| +PrinterInfo::PrinterInfo() = default; |
| + |
| +PrinterInfo::~PrinterInfo() = default; |
| + |
| void ParseJobsResponse(ipp_t* response, |
| const std::string& printer_id, |
| std::vector<CupsJob>* jobs) { |
| @@ -309,6 +369,29 @@ void ParseJobsResponse(ipp_t* response, |
| } |
| } |
| +ScopedIppPtr GetPrinterAttributes(http_t* http, |
| + const std::string& printer_uri, |
| + int num_attributes, |
| + const char* const* attributes, |
| + ipp_status_t* status) { |
| + base::ThreadRestrictions::AssertIOAllowed(); |
| + DCHECK(http); |
| + |
| + auto request = WrapIpp(ippNewRequest(IPP_OP_GET_PRINTER_ATTRIBUTES)); |
| + |
| + ippAddString(request.get(), IPP_TAG_OPERATION, IPP_TAG_URI, kPrinterUri, |
| + nullptr, printer_uri.data()); |
| + |
| + ippAddStrings(request.get(), IPP_TAG_OPERATION, IPP_TAG_KEYWORD, |
| + kRequestedAttributes, num_attributes, nullptr, attributes); |
| + |
| + auto response = |
| + WrapIpp(cupsDoRequest(http, request.release(), printer_uri.c_str())); |
| + *status = ippGetStatusCode(response.get()); |
| + |
| + return response; |
| +} |
| + |
| void ParsePrinterStatus(ipp_t* response, PrinterStatus* printer_status) { |
| for (ipp_attribute_t* attr = ippFirstAttribute(response); attr != nullptr; |
| attr = ippNextAttribute(response)) { |
| @@ -332,25 +415,38 @@ void ParsePrinterStatus(ipp_t* response, PrinterStatus* printer_status) { |
| } |
| } |
| +bool GetPrinterInfo(const std::string& address, |
| + const int port, |
| + const std::string& resource, |
| + PrinterInfo* printer_info) { |
| + base::ThreadRestrictions::AssertIOAllowed(); |
| + |
| + ScopedHttpPtr http = ScopedHttpPtr( |
| + httpConnect2(address.data(), port, nullptr, AF_INET, |
| + HTTP_ENCRYPTION_IF_REQUESTED, 0, 200, nullptr)); |
| + if (!http) |
| + return false; |
| + |
| + ipp_status_t status; |
| + ScopedIppPtr response = GetPrinterAttributes( |
| + http.get(), resource, kPrinterInfo.size(), kPrinterInfo.data(), &status); |
| + return status == IPP_STATUS_OK && |
| + ParsePrinterInfo(response.get(), printer_info); |
| +} |
| + |
| bool GetPrinterStatus(http_t* http, |
| const std::string& printer_id, |
| PrinterStatus* printer_status) { |
| - DCHECK(http); |
| - |
| - auto request = WrapIpp(ippNewRequest(IPP_OP_GET_PRINTER_ATTRIBUTES)); |
| + base::ThreadRestrictions::AssertIOAllowed(); |
| + ipp_status_t status; |
| const std::string printer_uri = PrinterUriFromName(printer_id); |
| - ippAddString(request.get(), IPP_TAG_OPERATION, IPP_TAG_URI, kPrinterUri, |
| - nullptr, printer_uri.data()); |
| - |
| - ippAddStrings(request.get(), IPP_TAG_OPERATION, IPP_TAG_KEYWORD, |
| - kRequestedAttributes, kPrinterAttributes.size(), nullptr, |
| - kPrinterAttributes.data()); |
| - auto response = |
| - WrapIpp(cupsDoRequest(http, request.release(), printer_uri.c_str())); |
| + ScopedIppPtr response = |
| + GetPrinterAttributes(http, printer_uri, kPrinterAttributes.size(), |
| + kPrinterAttributes.data(), &status); |
| - if (ippGetStatusCode(response.get()) != IPP_STATUS_OK) |
| + if (status != IPP_STATUS_OK) |
| return false; |
| ParsePrinterStatus(response.get(), printer_status); |
| @@ -363,6 +459,7 @@ bool GetCupsJobs(http_t* http, |
| int limit, |
| JobCompletionState which, |
| std::vector<CupsJob>* jobs) { |
| + base::ThreadRestrictions::AssertIOAllowed(); |
| DCHECK(http); |
| auto request = WrapIpp(ippNewRequest(IPP_OP_GET_JOBS)); |