Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(278)

Unified Diff: printing/backend/cups_jobs.cc

Issue 2891643002: Add a method to query IPP printers for attributes. (Closed)
Patch Set: add thread assertions Created 3 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« printing/backend/cups_jobs.h ('K') | « printing/backend/cups_jobs.h ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: printing/backend/cups_jobs.cc
diff --git a/printing/backend/cups_jobs.cc b/printing/backend/cups_jobs.cc
index e73ae8fb331041aaa5754074a924856980eca18d..724bd1326bf4408e5791930d1f69826dd45b79ef 100644
--- a/printing/backend/cups_jobs.cc
+++ b/printing/backend/cups_jobs.cc
@@ -11,8 +11,13 @@
#include <memory>
#include "base/logging.h"
+#include "base/stl_util.h"
+#include "base/strings/string_number_conversions.h"
#include "base/strings/string_piece.h"
+#include "base/strings/string_split.h"
#include "base/strings/stringprintf.h"
+#include "base/threading/thread_restrictions.h"
+#include "printing/backend/cups_deleters.h"
namespace printing {
namespace {
@@ -26,6 +31,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 +54,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 +101,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 IppPtr = std::unique_ptr<ipp_t, void (*)(ipp_t*)>;
Lei Zhang 2017/05/31 00:48:03 How about ScopedIppPtr here and ScopedHttpPtr belo
skau 2017/05/31 18:37:51 Done.
+
+IppPtr WrapIpp(ipp_t* ipp) {
+ return IppPtr(ipp, &ippDelete);
}
+using HttpPtr = 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 +302,58 @@ std::string PrinterUriFromName(const std::string& id) {
return base::StringPrintf("ipp://localhost/printers/%s", id.c_str());
}
+// Parses the |version| string into a <major, minor> pair. Returns false if
+// parsing failed. |major_minor| is only modified if parsing was successful.
+bool ToVersionNumber(const std::string& version,
Lei Zhang 2017/05/31 00:48:03 Do you want to use base::Version and not bother do
skau 2017/05/31 18:37:51 I didn't see that. Thanks!
+ std::pair<int, int>* major_minor) {
+ std::vector<base::StringPiece> pieces = SplitStringPiece(
+ version, ".", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
+ int major;
+ int minor;
+ if (pieces.size() != 2U || !base::StringToInt(pieces[0], &major) ||
+ !base::StringToInt(pieces[1], &minor)) {
+ return false;
+ }
+
+ major_minor->first = major;
+ major_minor->second = minor;
+ return true;
+}
+
+// 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) {
+ std::pair<int, int> major_minor;
+ if (ToVersionNumber(version, &major_minor)) {
+ 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 +368,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 +386,29 @@ void ParseJobsResponse(ipp_t* response,
}
}
+IppPtr GetPrinterAttributes(http_t* http,
+ const std::string& printer_uri,
+ int num_attributes,
+ const char* const* attributes,
+ ipp_status_t* status) {
+ DCHECK(http);
+ base::ThreadRestrictions::AssertIOAllowed();
Lei Zhang 2017/05/31 00:48:03 Check this first. Ditto on line 480. If you look
skau 2017/05/31 18:37:51 Done.
+
+ 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 +432,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();
+
+ HttpPtr http =
+ HttpPtr(httpConnect2(address.data(), port, nullptr, AF_INET,
+ HTTP_ENCRYPTION_IF_REQUESTED, 0, 200, nullptr));
+ if (!http)
+ return false;
+
+ ipp_status_t status;
+ auto 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 =
Lei Zhang 2017/05/31 00:48:03 Can we put the actual type here, since it's not im
skau 2017/05/31 18:37:51 Done.
- WrapIpp(cupsDoRequest(http, request.release(), printer_uri.c_str()));
+ 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);
@@ -364,6 +477,7 @@ bool GetCupsJobs(http_t* http,
JobCompletionState which,
std::vector<CupsJob>* jobs) {
DCHECK(http);
+ base::ThreadRestrictions::AssertIOAllowed();
auto request = WrapIpp(ippNewRequest(IPP_OP_GET_JOBS));
const std::string printer_uri = PrinterUriFromName(printer_id);
« printing/backend/cups_jobs.h ('K') | « printing/backend/cups_jobs.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698