123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703 |
- // Copyright (c) 2012 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #include "printing/backend/cups_helper.h"
- #include <cups/ppd.h>
- #include <stddef.h>
- #include <stdio.h>
- #include <unistd.h>
- #include <vector>
- #include "base/files/file_path.h"
- #include "base/files/file_util.h"
- #include "base/files/scoped_file.h"
- #include "base/logging.h"
- #include "base/strings/string_number_conversions.h"
- #include "base/strings/string_util.h"
- #include "base/time/time.h"
- #include "build/build_config.h"
- #include "printing/backend/print_backend.h"
- #include "printing/backend/print_backend_consts.h"
- #include "printing/mojom/print.mojom.h"
- #include "printing/print_job_constants.h"
- #include "printing/printing_utils.h"
- #include "printing/units.h"
- #include "url/gurl.h"
- using base::EqualsCaseInsensitiveASCII;
- namespace printing {
- // This section contains helper code for PPD parsing for semantic capabilities.
- namespace {
- // Function availability can be tested by checking whether its address is not
- // nullptr. Weak symbols remove the need for platform specific build flags and
- // allow for appropriate CUPS usage on platforms with non-uniform version
- // support, namely Linux.
- #define WEAK_CUPS_FN(x) extern "C" __attribute__((weak)) decltype(x) x
- WEAK_CUPS_FN(httpConnect2);
- // Timeout for establishing a CUPS connection. It is expected that cupsd is
- // able to start and respond on all systems within this duration.
- constexpr base::TimeDelta kCupsTimeout = base::Seconds(5);
- // CUPS default max copies value (parsed from kCupsMaxCopies PPD attribute).
- constexpr int32_t kDefaultMaxCopies = 9999;
- constexpr char kCupsMaxCopies[] = "cupsMaxCopies";
- constexpr char kColorDevice[] = "ColorDevice";
- constexpr char kColorModel[] = "ColorModel";
- constexpr char kColorMode[] = "ColorMode";
- constexpr char kProcessColorModel[] = "ProcessColorModel";
- constexpr char kPrintoutMode[] = "PrintoutMode";
- constexpr char kDraftGray[] = "Draft.Gray";
- constexpr char kHighGray[] = "High.Gray";
- constexpr char kDuplex[] = "Duplex";
- constexpr char kDuplexNone[] = "None";
- constexpr char kDuplexNoTumble[] = "DuplexNoTumble";
- constexpr char kDuplexTumble[] = "DuplexTumble";
- constexpr char kPageSize[] = "PageSize";
- // Brother printer specific options.
- constexpr char kBrotherDuplex[] = "BRDuplex";
- constexpr char kBrotherMonoColor[] = "BRMonoColor";
- constexpr char kBrotherPrintQuality[] = "BRPrintQuality";
- // Epson printer specific options.
- constexpr char kEpsonInk[] = "Ink";
- constexpr char kEpsonColor[] = "COLOR";
- constexpr char kEpsonMono[] = "MONO";
- // HP printer specific options.
- constexpr char kHpColorMode[] = "HPColorMode";
- constexpr char kHpColorPrint[] = "ColorPrint";
- constexpr char kHpGrayscalePrint[] = "GrayscalePrint";
- // Samsung printer specific options.
- constexpr char kSamsungColorTrue[] = "True";
- constexpr char kSamsungColorFalse[] = "False";
- // Sharp printer specific options.
- constexpr char kSharpARCMode[] = "ARCMode";
- constexpr char kSharpCMColor[] = "CMColor";
- constexpr char kSharpCMBW[] = "CMBW";
- // Xerox printer specific options.
- constexpr char kXeroxXRXColor[] = "XRXColor";
- constexpr char kXeroxAutomatic[] = "Automatic";
- constexpr char kXeroxBW[] = "BW";
- int32_t GetCopiesMax(ppd_file_t* ppd) {
- ppd_attr_t* attr = ppdFindAttr(ppd, kCupsMaxCopies, nullptr);
- if (!attr || !attr->value) {
- return kDefaultMaxCopies;
- }
- int32_t ret;
- return base::StringToInt(attr->value, &ret) ? ret : kDefaultMaxCopies;
- }
- void GetDuplexSettings(ppd_file_t* ppd,
- std::vector<mojom::DuplexMode>* duplex_modes,
- mojom::DuplexMode* duplex_default) {
- ppd_choice_t* duplex_choice = ppdFindMarkedChoice(ppd, kDuplex);
- ppd_option_t* option = ppdFindOption(ppd, kDuplex);
- if (!option)
- option = ppdFindOption(ppd, kBrotherDuplex);
- if (!option)
- return;
- if (!duplex_choice)
- duplex_choice = ppdFindChoice(option, option->defchoice);
- if (ppdFindChoice(option, kDuplexNone))
- duplex_modes->push_back(mojom::DuplexMode::kSimplex);
- if (ppdFindChoice(option, kDuplexNoTumble))
- duplex_modes->push_back(mojom::DuplexMode::kLongEdge);
- if (ppdFindChoice(option, kDuplexTumble))
- duplex_modes->push_back(mojom::DuplexMode::kShortEdge);
- if (!duplex_choice)
- return;
- const char* choice = duplex_choice->choice;
- if (EqualsCaseInsensitiveASCII(choice, kDuplexNone)) {
- *duplex_default = mojom::DuplexMode::kSimplex;
- } else if (EqualsCaseInsensitiveASCII(choice, kDuplexTumble)) {
- *duplex_default = mojom::DuplexMode::kShortEdge;
- } else {
- *duplex_default = mojom::DuplexMode::kLongEdge;
- }
- }
- void GetResolutionSettings(ppd_file_t* ppd,
- std::vector<gfx::Size>* dpis,
- gfx::Size* default_dpi) {
- static constexpr const char* kResolutions[] = {
- "Resolution", "JCLResolution", "SetResolution",
- "CNRes_PGP", "HPPrintQuality", "LXResolution"};
- ppd_option_t* res;
- for (const char* res_name : kResolutions) {
- res = ppdFindOption(ppd, res_name);
- if (res)
- break;
- }
- if (!res)
- return;
- for (int i = 0; i < res->num_choices; i++) {
- char* choice = res->choices[i].choice;
- DCHECK(choice);
- int len = strlen(choice);
- if (len == 0) {
- VLOG(1) << "Bad PPD resolution choice: null string";
- continue;
- }
- int n = 0; // number of chars successfully parsed by sscanf()
- int dpi_x;
- int dpi_y;
- sscanf(choice, "%ddpi%n", &dpi_x, &n);
- if (n == len) {
- dpi_y = dpi_x;
- } else {
- sscanf(choice, "%dx%ddpi%n", &dpi_x, &dpi_y, &n);
- if (n != len) {
- VLOG(1) << "Bad PPD resolution choice: " << choice;
- continue;
- }
- }
- if (dpi_x <= 0 || dpi_y <= 0) {
- VLOG(1) << "Invalid PPD resolution dimensions: " << dpi_x << " " << dpi_y;
- continue;
- }
- dpis->push_back({dpi_x, dpi_y});
- if (!strcmp(choice, res->defchoice))
- *default_dpi = dpis->back();
- }
- }
- bool GetBasicColorModelSettings(ppd_file_t* ppd,
- mojom::ColorModel* color_model_for_black,
- mojom::ColorModel* color_model_for_color,
- bool* color_is_default) {
- ppd_option_t* color_model = ppdFindOption(ppd, kColorModel);
- if (!color_model)
- return false;
- if (ppdFindChoice(color_model, kBlack))
- *color_model_for_black = mojom::ColorModel::kBlack;
- else if (ppdFindChoice(color_model, kGray))
- *color_model_for_black = mojom::ColorModel::kGray;
- else if (ppdFindChoice(color_model, kGrayscale))
- *color_model_for_black = mojom::ColorModel::kGrayscale;
- if (ppdFindChoice(color_model, kColor))
- *color_model_for_color = mojom::ColorModel::kColor;
- else if (ppdFindChoice(color_model, kCMYK))
- *color_model_for_color = mojom::ColorModel::kCMYK;
- else if (ppdFindChoice(color_model, kRGB))
- *color_model_for_color = mojom::ColorModel::kRGB;
- else if (ppdFindChoice(color_model, kRGBA))
- *color_model_for_color = mojom::ColorModel::kRGBA;
- else if (ppdFindChoice(color_model, kRGB16))
- *color_model_for_color = mojom::ColorModel::kRGB16;
- else if (ppdFindChoice(color_model, kCMY))
- *color_model_for_color = mojom::ColorModel::kCMY;
- else if (ppdFindChoice(color_model, kKCMY))
- *color_model_for_color = mojom::ColorModel::kKCMY;
- else if (ppdFindChoice(color_model, kCMY_K))
- *color_model_for_color = mojom::ColorModel::kCMYPlusK;
- ppd_choice_t* marked_choice = ppdFindMarkedChoice(ppd, kColorModel);
- if (!marked_choice)
- marked_choice = ppdFindChoice(color_model, color_model->defchoice);
- if (marked_choice) {
- *color_is_default =
- !EqualsCaseInsensitiveASCII(marked_choice->choice, kBlack) &&
- !EqualsCaseInsensitiveASCII(marked_choice->choice, kGray) &&
- !EqualsCaseInsensitiveASCII(marked_choice->choice, kGrayscale);
- }
- return true;
- }
- bool GetPrintOutModeColorSettings(ppd_file_t* ppd,
- mojom::ColorModel* color_model_for_black,
- mojom::ColorModel* color_model_for_color,
- bool* color_is_default) {
- ppd_option_t* printout_mode = ppdFindOption(ppd, kPrintoutMode);
- if (!printout_mode)
- return false;
- *color_model_for_color = mojom::ColorModel::kPrintoutModeNormal;
- *color_model_for_black = mojom::ColorModel::kPrintoutModeNormal;
- // Check to see if NORMAL_GRAY value is supported by PrintoutMode.
- // If NORMAL_GRAY is not supported, NORMAL value is used to
- // represent grayscale. If NORMAL_GRAY is supported, NORMAL is used to
- // represent color.
- if (ppdFindChoice(printout_mode, kNormalGray))
- *color_model_for_black = mojom::ColorModel::kPrintoutModeNormalGray;
- // Get the default marked choice to identify the default color setting
- // value.
- ppd_choice_t* printout_mode_choice = ppdFindMarkedChoice(ppd, kPrintoutMode);
- if (!printout_mode_choice) {
- printout_mode_choice =
- ppdFindChoice(printout_mode, printout_mode->defchoice);
- }
- if (printout_mode_choice) {
- if (EqualsCaseInsensitiveASCII(printout_mode_choice->choice, kNormalGray) ||
- EqualsCaseInsensitiveASCII(printout_mode_choice->choice, kHighGray) ||
- EqualsCaseInsensitiveASCII(printout_mode_choice->choice, kDraftGray)) {
- *color_model_for_black = mojom::ColorModel::kPrintoutModeNormalGray;
- *color_is_default = false;
- }
- }
- return true;
- }
- bool GetColorModeSettings(ppd_file_t* ppd,
- mojom::ColorModel* color_model_for_black,
- mojom::ColorModel* color_model_for_color,
- bool* color_is_default) {
- // Samsung printers use "ColorMode" attribute in their PPDs.
- ppd_option_t* color_mode_option = ppdFindOption(ppd, kColorMode);
- if (!color_mode_option)
- return false;
- if (ppdFindChoice(color_mode_option, kColor) ||
- ppdFindChoice(color_mode_option, kSamsungColorTrue)) {
- *color_model_for_color = mojom::ColorModel::kColorModeColor;
- }
- if (ppdFindChoice(color_mode_option, kMonochrome) ||
- ppdFindChoice(color_mode_option, kSamsungColorFalse)) {
- *color_model_for_black = mojom::ColorModel::kColorModeMonochrome;
- }
- ppd_choice_t* mode_choice = ppdFindMarkedChoice(ppd, kColorMode);
- if (!mode_choice) {
- mode_choice =
- ppdFindChoice(color_mode_option, color_mode_option->defchoice);
- }
- if (mode_choice) {
- *color_is_default =
- EqualsCaseInsensitiveASCII(mode_choice->choice, kColor) ||
- EqualsCaseInsensitiveASCII(mode_choice->choice, kSamsungColorTrue);
- }
- return true;
- }
- bool GetBrotherColorSettings(ppd_file_t* ppd,
- mojom::ColorModel* color_model_for_black,
- mojom::ColorModel* color_model_for_color,
- bool* color_is_default) {
- // Some Brother printers use "BRMonoColor" attribute in their PPDs.
- // Some Brother printers use "BRPrintQuality" attribute in their PPDs.
- ppd_option_t* color_mode_option = ppdFindOption(ppd, kBrotherMonoColor);
- if (!color_mode_option)
- color_mode_option = ppdFindOption(ppd, kBrotherPrintQuality);
- if (!color_mode_option)
- return false;
- if (ppdFindChoice(color_mode_option, kFullColor))
- *color_model_for_color = mojom::ColorModel::kBrotherCUPSColor;
- else if (ppdFindChoice(color_mode_option, kColor))
- *color_model_for_color = mojom::ColorModel::kBrotherBRScript3Color;
- if (ppdFindChoice(color_mode_option, kMono))
- *color_model_for_black = mojom::ColorModel::kBrotherCUPSMono;
- else if (ppdFindChoice(color_mode_option, kBlack))
- *color_model_for_black = mojom::ColorModel::kBrotherBRScript3Black;
- ppd_choice_t* marked_choice = ppdFindMarkedChoice(ppd, kColorMode);
- if (!marked_choice) {
- marked_choice =
- ppdFindChoice(color_mode_option, color_mode_option->defchoice);
- }
- if (marked_choice) {
- *color_is_default =
- !EqualsCaseInsensitiveASCII(marked_choice->choice, kBlack) &&
- !EqualsCaseInsensitiveASCII(marked_choice->choice, kMono);
- }
- return true;
- }
- bool GetHPColorSettings(ppd_file_t* ppd,
- mojom::ColorModel* color_model_for_black,
- mojom::ColorModel* color_model_for_color,
- bool* color_is_default) {
- // Some HP printers use "Color/Color Model" attribute in their PPDs.
- ppd_option_t* color_mode_option = ppdFindOption(ppd, kColor);
- if (!color_mode_option)
- return false;
- if (ppdFindChoice(color_mode_option, kColor))
- *color_model_for_color = mojom::ColorModel::kHPColorColor;
- if (ppdFindChoice(color_mode_option, kBlack))
- *color_model_for_black = mojom::ColorModel::kHPColorBlack;
- ppd_choice_t* mode_choice = ppdFindMarkedChoice(ppd, kColorMode);
- if (!mode_choice) {
- mode_choice =
- ppdFindChoice(color_mode_option, color_mode_option->defchoice);
- }
- if (mode_choice) {
- *color_is_default = EqualsCaseInsensitiveASCII(mode_choice->choice, kColor);
- }
- return true;
- }
- bool GetHPColorModeSettings(ppd_file_t* ppd,
- mojom::ColorModel* color_model_for_black,
- mojom::ColorModel* color_model_for_color,
- bool* color_is_default) {
- // Some HP printers use "HPColorMode/Mode" attribute in their PPDs.
- ppd_option_t* color_mode_option = ppdFindOption(ppd, kHpColorMode);
- if (!color_mode_option)
- return false;
- if (ppdFindChoice(color_mode_option, kHpColorPrint))
- *color_model_for_color = mojom::ColorModel::kHPColorColor;
- if (ppdFindChoice(color_mode_option, kHpGrayscalePrint))
- *color_model_for_black = mojom::ColorModel::kHPColorBlack;
- ppd_choice_t* mode_choice = ppdFindMarkedChoice(ppd, kHpColorMode);
- if (!mode_choice) {
- mode_choice =
- ppdFindChoice(color_mode_option, color_mode_option->defchoice);
- }
- if (mode_choice) {
- *color_is_default =
- EqualsCaseInsensitiveASCII(mode_choice->choice, kHpColorPrint);
- }
- return true;
- }
- bool GetEpsonInkSettings(ppd_file_t* ppd,
- mojom::ColorModel* color_model_for_black,
- mojom::ColorModel* color_model_for_color,
- bool* color_is_default) {
- // Epson printers use "Ink" attribute in their PPDs.
- ppd_option_t* color_mode_option = ppdFindOption(ppd, kEpsonInk);
- if (!color_mode_option)
- return false;
- if (ppdFindChoice(color_mode_option, kEpsonColor))
- *color_model_for_color = mojom::ColorModel::kEpsonInkColor;
- if (ppdFindChoice(color_mode_option, kEpsonMono))
- *color_model_for_black = mojom::ColorModel::kEpsonInkMono;
- ppd_choice_t* mode_choice = ppdFindMarkedChoice(ppd, kEpsonInk);
- if (!mode_choice) {
- mode_choice =
- ppdFindChoice(color_mode_option, color_mode_option->defchoice);
- }
- if (mode_choice) {
- *color_is_default = EqualsCaseInsensitiveASCII(mode_choice->choice, kColor);
- }
- return true;
- }
- bool GetSharpARCModeSettings(ppd_file_t* ppd,
- mojom::ColorModel* color_model_for_black,
- mojom::ColorModel* color_model_for_color,
- bool* color_is_default) {
- // Sharp printers use "ARCMode" attribute in their PPDs.
- ppd_option_t* color_mode_option = ppdFindOption(ppd, kSharpARCMode);
- if (!color_mode_option)
- return false;
- if (ppdFindChoice(color_mode_option, kSharpCMColor))
- *color_model_for_color = mojom::ColorModel::kSharpARCModeCMColor;
- if (ppdFindChoice(color_mode_option, kSharpCMBW))
- *color_model_for_black = mojom::ColorModel::kSharpARCModeCMBW;
- ppd_choice_t* mode_choice = ppdFindMarkedChoice(ppd, kSharpARCMode);
- if (!mode_choice) {
- mode_choice =
- ppdFindChoice(color_mode_option, color_mode_option->defchoice);
- }
- if (mode_choice) {
- // Many Sharp printers use "CMAuto" as the default color mode.
- *color_is_default =
- !EqualsCaseInsensitiveASCII(mode_choice->choice, kSharpCMBW);
- }
- return true;
- }
- bool GetXeroxColorSettings(ppd_file_t* ppd,
- mojom::ColorModel* color_model_for_black,
- mojom::ColorModel* color_model_for_color,
- bool* color_is_default) {
- // Some Xerox printers use "XRXColor" attribute in their PPDs.
- ppd_option_t* color_mode_option = ppdFindOption(ppd, kXeroxXRXColor);
- if (!color_mode_option)
- return false;
- if (ppdFindChoice(color_mode_option, kXeroxAutomatic))
- *color_model_for_color = mojom::ColorModel::kXeroxXRXColorAutomatic;
- if (ppdFindChoice(color_mode_option, kXeroxBW))
- *color_model_for_black = mojom::ColorModel::kXeroxXRXColorBW;
- ppd_choice_t* mode_choice = ppdFindMarkedChoice(ppd, kXeroxXRXColor);
- if (!mode_choice) {
- mode_choice =
- ppdFindChoice(color_mode_option, color_mode_option->defchoice);
- }
- if (mode_choice) {
- // Many Xerox printers use "Automatic" as the default color mode.
- *color_is_default =
- !EqualsCaseInsensitiveASCII(mode_choice->choice, kXeroxBW);
- }
- return true;
- }
- bool GetProcessColorModelSettings(ppd_file_t* ppd,
- mojom::ColorModel* color_model_for_black,
- mojom::ColorModel* color_model_for_color,
- bool* color_is_default) {
- // Canon printers use "ProcessColorModel" attribute in their PPDs.
- ppd_option_t* color_mode_option = ppdFindOption(ppd, kProcessColorModel);
- if (!color_mode_option)
- return false;
- if (ppdFindChoice(color_mode_option, kRGB))
- *color_model_for_color = mojom::ColorModel::kProcessColorModelRGB;
- else if (ppdFindChoice(color_mode_option, kCMYK))
- *color_model_for_color = mojom::ColorModel::kProcessColorModelCMYK;
- if (ppdFindChoice(color_mode_option, kGreyscale))
- *color_model_for_black = mojom::ColorModel::kProcessColorModelGreyscale;
- ppd_choice_t* mode_choice = ppdFindMarkedChoice(ppd, kProcessColorModel);
- if (!mode_choice) {
- mode_choice =
- ppdFindChoice(color_mode_option, color_mode_option->defchoice);
- }
- if (mode_choice) {
- *color_is_default =
- !EqualsCaseInsensitiveASCII(mode_choice->choice, kGreyscale);
- }
- return true;
- }
- bool GetColorModelSettings(ppd_file_t* ppd,
- mojom::ColorModel* cm_black,
- mojom::ColorModel* cm_color,
- bool* is_color) {
- bool is_color_device = false;
- ppd_attr_t* attr = ppdFindAttr(ppd, kColorDevice, nullptr);
- if (attr && attr->value)
- is_color_device = ppd->color_device;
- *is_color = is_color_device;
- return (is_color_device &&
- GetBasicColorModelSettings(ppd, cm_black, cm_color, is_color)) ||
- GetPrintOutModeColorSettings(ppd, cm_black, cm_color, is_color) ||
- GetColorModeSettings(ppd, cm_black, cm_color, is_color) ||
- GetHPColorSettings(ppd, cm_black, cm_color, is_color) ||
- GetHPColorModeSettings(ppd, cm_black, cm_color, is_color) ||
- GetBrotherColorSettings(ppd, cm_black, cm_color, is_color) ||
- GetEpsonInkSettings(ppd, cm_black, cm_color, is_color) ||
- GetSharpARCModeSettings(ppd, cm_black, cm_color, is_color) ||
- GetXeroxColorSettings(ppd, cm_black, cm_color, is_color) ||
- GetProcessColorModelSettings(ppd, cm_black, cm_color, is_color);
- }
- // Default port for IPP print servers.
- const int kDefaultIPPServerPort = 631;
- } // namespace
- // Helper wrapper around http_t structure, with connection and cleanup
- // functionality.
- HttpConnectionCUPS::HttpConnectionCUPS(const GURL& print_server_url,
- http_encryption_t encryption,
- bool blocking)
- : http_(nullptr) {
- // If we have an empty url, use default print server.
- if (print_server_url.is_empty())
- return;
- int port = print_server_url.IntPort();
- if (port == url::PORT_UNSPECIFIED)
- port = kDefaultIPPServerPort;
- if (httpConnect2) {
- http_ = httpConnect2(print_server_url.host().c_str(), port,
- /*addrlist=*/nullptr, AF_UNSPEC, encryption,
- blocking ? 1 : 0, kCupsTimeout.InMilliseconds(),
- /*cancel=*/nullptr);
- } else {
- // Continue to use deprecated CUPS calls because because older Linux
- // distribution such as RHEL/CentOS 7 are shipped with CUPS 1.6.
- http_ =
- httpConnectEncrypt(print_server_url.host().c_str(), port, encryption);
- }
- if (!http_) {
- LOG(ERROR) << "CP_CUPS: Failed connecting to print server: "
- << print_server_url;
- return;
- }
- if (!httpConnect2)
- httpBlocking(http_, blocking ? 1 : 0);
- }
- HttpConnectionCUPS::~HttpConnectionCUPS() {
- if (http_)
- httpClose(http_);
- }
- http_t* HttpConnectionCUPS::http() {
- return http_;
- }
- bool ParsePpdCapabilities(cups_dest_t* dest,
- base::StringPiece locale,
- base::StringPiece printer_capabilities,
- PrinterSemanticCapsAndDefaults* printer_info) {
- // A file created while in a sandbox will be automatically deleted once all
- // handles to it have been closed. This precludes the use of multiple
- // operations against a file path.
- //
- // Underlying CUPS libraries process the PPD using standard I/O file
- // descriptors, so `FILE` stream APIs that don't support that are not an
- // option (e.g., can't use fmemopen()).
- //
- // Previous attempts to just read & write with a single disk `FILE` stream
- // demonstrated occasional data corruption in the wild, so resort to working
- // directly with lower-level file descriptors.
- base::FilePath temp_dir;
- if (!base::GetTempDir(&temp_dir))
- return false;
- base::FilePath ppd_file_path;
- base::ScopedFD ppd_fd =
- base::CreateAndOpenFdForTemporaryFileInDir(temp_dir, &ppd_file_path);
- if (!ppd_fd.is_valid() ||
- !base::WriteFileDescriptor(ppd_fd.get(), printer_capabilities) ||
- lseek(ppd_fd.get(), 0, SEEK_SET) == -1) {
- return false;
- }
- // We release ownership of `ppd_fd` here because ppdOpenFd() assumes ownership
- // of it in all but one case (see below).
- int unowned_ppd_fd = ppd_fd.release();
- ppd_file_t* ppd = ppdOpenFd(unowned_ppd_fd);
- if (!ppd) {
- int line = 0;
- ppd_status_t ppd_status = ppdLastError(&line);
- LOG(ERROR) << "Failed to open PDD file: error " << ppd_status << " at line "
- << line << ", " << ppdErrorString(ppd_status);
- if (ppd_status == PPD_FILE_OPEN_ERROR) {
- // Normally ppdOpenFd assumes ownership of the file descriptor we give it,
- // regardless of success or failure. The one exception is when it fails
- // with PPD_FILE_OPEN_ERROR. In that case ownership is retained by the
- // caller, so we must explicitly close it.
- close(unowned_ppd_fd);
- }
- return false;
- }
- ppdMarkDefaults(ppd);
- if (dest)
- cupsMarkOptions(ppd, dest->num_options, dest->options);
- PrinterSemanticCapsAndDefaults caps;
- caps.collate_capable = true;
- caps.collate_default = true;
- caps.copies_max = GetCopiesMax(ppd);
- GetDuplexSettings(ppd, &caps.duplex_modes, &caps.duplex_default);
- GetResolutionSettings(ppd, &caps.dpis, &caps.default_dpi);
- mojom::ColorModel cm_black = mojom::ColorModel::kUnknownColorModel;
- mojom::ColorModel cm_color = mojom::ColorModel::kUnknownColorModel;
- bool is_color = false;
- if (!GetColorModelSettings(ppd, &cm_black, &cm_color, &is_color)) {
- VLOG(1) << "Unknown printer color model";
- }
- caps.color_changeable =
- ((cm_color != mojom::ColorModel::kUnknownColorModel) &&
- (cm_black != mojom::ColorModel::kUnknownColorModel) &&
- (cm_color != cm_black));
- caps.color_default = is_color;
- caps.color_model = cm_color;
- caps.bw_model = cm_black;
- if (ppd->num_sizes > 0 && ppd->sizes) {
- VLOG(1) << "Paper list size - " << ppd->num_sizes;
- ppd_option_t* paper_option = ppdFindOption(ppd, kPageSize);
- bool is_default_found = false;
- for (int i = 0; i < ppd->num_sizes; ++i) {
- gfx::Size paper_size_microns(
- ConvertUnit(ppd->sizes[i].width, kPointsPerInch, kMicronsPerInch),
- ConvertUnit(ppd->sizes[i].length, kPointsPerInch, kMicronsPerInch));
- if (!paper_size_microns.IsEmpty()) {
- PrinterSemanticCapsAndDefaults::Paper paper;
- paper.size_um = paper_size_microns;
- paper.vendor_id = ppd->sizes[i].name;
- if (paper_option) {
- ppd_choice_t* paper_choice =
- ppdFindChoice(paper_option, ppd->sizes[i].name);
- // Human readable paper name should be UTF-8 encoded, but some PPDs
- // do not follow this standard.
- if (paper_choice && base::IsStringUTF8(paper_choice->text)) {
- paper.display_name = paper_choice->text;
- }
- }
- caps.papers.push_back(paper);
- if (ppd->sizes[i].marked) {
- caps.default_paper = paper;
- is_default_found = true;
- }
- }
- }
- if (!is_default_found) {
- gfx::Size locale_paper_microns =
- GetDefaultPaperSizeFromLocaleMicrons(locale);
- for (const PrinterSemanticCapsAndDefaults::Paper& paper : caps.papers) {
- // Set epsilon to 500 microns to allow tolerance of rounded paper sizes.
- // While the above utility function returns paper sizes in microns, they
- // are still rounded to the nearest millimeter (1000 microns).
- constexpr int kSizeEpsilon = 500;
- if (SizesEqualWithinEpsilon(paper.size_um, locale_paper_microns,
- kSizeEpsilon)) {
- caps.default_paper = paper;
- is_default_found = true;
- break;
- }
- }
- // If no default was set in the PPD or if the locale default is not within
- // the printer's capabilities, select the first on the list.
- if (!is_default_found)
- caps.default_paper = caps.papers[0];
- }
- }
- ppdClose(ppd);
- *printer_info = caps;
- return true;
- }
- } // namespace printing
|