Renamed namespaces of url lib.
[chromium-blink-merge.git] / printing / backend / cups_helper.cc
blob296b95eb07a4c15da7bb58efcec8fd86a794b53c
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "printing/backend/cups_helper.h"
7 #include <cups/ppd.h>
9 #include "base/file_util.h"
10 #include "base/logging.h"
11 #include "base/strings/string_number_conversions.h"
12 #include "base/strings/string_split.h"
13 #include "base/strings/string_util.h"
14 #include "base/values.h"
15 #include "printing/backend/print_backend.h"
16 #include "printing/backend/print_backend_consts.h"
17 #include "url/gurl.h"
19 namespace printing {
21 // This section contains helper code for PPD parsing for semantic capabilities.
22 namespace {
24 const char kColorDevice[] = "ColorDevice";
25 const char kColorModel[] = "ColorModel";
26 const char kColorMode[] = "ColorMode";
27 const char kProcessColorModel[] = "ProcessColorModel";
28 const char kPrintoutMode[] = "PrintoutMode";
29 const char kDraftGray[] = "Draft.Gray";
30 const char kHighGray[] = "High.Gray";
32 const char kDuplex[] = "Duplex";
33 const char kDuplexNone[] = "None";
35 #if !defined(OS_MACOSX)
36 void ParseLpOptions(const base::FilePath& filepath,
37 const std::string& printer_name,
38 int* num_options, cups_option_t** options) {
39 std::string content;
40 if (!base::ReadFileToString(filepath, &content))
41 return;
43 const char kDest[] = "dest";
44 const char kDefault[] = "default";
45 const size_t kDestLen = sizeof(kDest) - 1;
46 const size_t kDefaultLen = sizeof(kDefault) - 1;
47 std::vector<std::string> lines;
48 base::SplitString(content, '\n', &lines);
50 for (size_t i = 0; i < lines.size(); ++i) {
51 std::string line = lines[i];
52 if (line.empty())
53 continue;
55 if (base::strncasecmp (line.c_str(), kDefault, kDefaultLen) == 0 &&
56 isspace(line[kDefaultLen])) {
57 line = line.substr(kDefaultLen);
58 } else if (base::strncasecmp (line.c_str(), kDest, kDestLen) == 0 &&
59 isspace(line[kDestLen])) {
60 line = line.substr(kDestLen);
61 } else {
62 continue;
65 base::TrimWhitespaceASCII(line, base::TRIM_ALL, &line);
66 if (line.empty())
67 continue;
69 size_t space_found = line.find(' ');
70 if (space_found == std::string::npos)
71 continue;
73 std::string name = line.substr(0, space_found);
74 if (name.empty())
75 continue;
77 if (base::strncasecmp(printer_name.c_str(), name.c_str(),
78 name.length()) != 0) {
79 continue; // This is not the required printer.
82 line = line.substr(space_found + 1);
83 // Remove extra spaces.
84 base::TrimWhitespaceASCII(line, base::TRIM_ALL, &line);
85 if (line.empty())
86 continue;
87 // Parse the selected printer custom options.
88 *num_options = cupsParseOptions(line.c_str(), 0, options);
92 void MarkLpOptions(const std::string& printer_name, ppd_file_t** ppd) {
93 cups_option_t* options = NULL;
94 int num_options = 0;
95 ppdMarkDefaults(*ppd);
97 const char kSystemLpOptionPath[] = "/etc/cups/lpoptions";
98 const char kUserLpOptionPath[] = ".cups/lpoptions";
100 std::vector<base::FilePath> file_locations;
101 file_locations.push_back(base::FilePath(kSystemLpOptionPath));
102 file_locations.push_back(base::FilePath(
103 base::GetHomeDir().Append(kUserLpOptionPath)));
105 for (std::vector<base::FilePath>::const_iterator it = file_locations.begin();
106 it != file_locations.end(); ++it) {
107 num_options = 0;
108 options = NULL;
109 ParseLpOptions(*it, printer_name, &num_options, &options);
110 if (num_options > 0 && options) {
111 cupsMarkOptions(*ppd, num_options, options);
112 cupsFreeOptions(num_options, options);
116 #endif // !defined(OS_MACOSX)
118 bool GetBasicColorModelSettings(ppd_file_t* ppd,
119 ColorModel* color_model_for_black,
120 ColorModel* color_model_for_color,
121 bool* color_is_default) {
122 ppd_option_t* color_model = ppdFindOption(ppd, kColorModel);
123 if (!color_model)
124 return false;
126 if (ppdFindChoice(color_model, printing::kBlack))
127 *color_model_for_black = printing::BLACK;
128 else if (ppdFindChoice(color_model, printing::kGray))
129 *color_model_for_black = printing::GRAY;
130 else if (ppdFindChoice(color_model, printing::kGrayscale))
131 *color_model_for_black = printing::GRAYSCALE;
133 if (ppdFindChoice(color_model, printing::kColor))
134 *color_model_for_color = printing::COLOR;
135 else if (ppdFindChoice(color_model, printing::kCMYK))
136 *color_model_for_color = printing::CMYK;
137 else if (ppdFindChoice(color_model, printing::kRGB))
138 *color_model_for_color = printing::RGB;
139 else if (ppdFindChoice(color_model, printing::kRGBA))
140 *color_model_for_color = printing::RGBA;
141 else if (ppdFindChoice(color_model, printing::kRGB16))
142 *color_model_for_color = printing::RGB16;
143 else if (ppdFindChoice(color_model, printing::kCMY))
144 *color_model_for_color = printing::CMY;
145 else if (ppdFindChoice(color_model, printing::kKCMY))
146 *color_model_for_color = printing::KCMY;
147 else if (ppdFindChoice(color_model, printing::kCMY_K))
148 *color_model_for_color = printing::CMY_K;
150 ppd_choice_t* marked_choice = ppdFindMarkedChoice(ppd, kColorModel);
151 if (!marked_choice)
152 marked_choice = ppdFindChoice(color_model, color_model->defchoice);
154 if (marked_choice) {
155 *color_is_default =
156 (base::strcasecmp(marked_choice->choice, printing::kBlack) != 0) &&
157 (base::strcasecmp(marked_choice->choice, printing::kGray) != 0) &&
158 (base::strcasecmp(marked_choice->choice, printing::kGrayscale) != 0);
160 return true;
163 bool GetPrintOutModeColorSettings(ppd_file_t* ppd,
164 ColorModel* color_model_for_black,
165 ColorModel* color_model_for_color,
166 bool* color_is_default) {
167 ppd_option_t* printout_mode = ppdFindOption(ppd, kPrintoutMode);
168 if (!printout_mode)
169 return false;
171 *color_model_for_color = printing::PRINTOUTMODE_NORMAL;
172 *color_model_for_black = printing::PRINTOUTMODE_NORMAL;
174 // Check to see if NORMAL_GRAY value is supported by PrintoutMode.
175 // If NORMAL_GRAY is not supported, NORMAL value is used to
176 // represent grayscale. If NORMAL_GRAY is supported, NORMAL is used to
177 // represent color.
178 if (ppdFindChoice(printout_mode, printing::kNormalGray))
179 *color_model_for_black = printing::PRINTOUTMODE_NORMAL_GRAY;
181 // Get the default marked choice to identify the default color setting
182 // value.
183 ppd_choice_t* printout_mode_choice = ppdFindMarkedChoice(ppd, kPrintoutMode);
184 if (!printout_mode_choice) {
185 printout_mode_choice = ppdFindChoice(printout_mode,
186 printout_mode->defchoice);
188 if (printout_mode_choice) {
189 if ((base::strcasecmp(printout_mode_choice->choice,
190 printing::kNormalGray) == 0) ||
191 (base::strcasecmp(printout_mode_choice->choice, kHighGray) == 0) ||
192 (base::strcasecmp(printout_mode_choice->choice, kDraftGray) == 0)) {
193 *color_model_for_black = printing::PRINTOUTMODE_NORMAL_GRAY;
194 *color_is_default = false;
197 return true;
200 bool GetColorModeSettings(ppd_file_t* ppd,
201 ColorModel* color_model_for_black,
202 ColorModel* color_model_for_color,
203 bool* color_is_default) {
204 // Samsung printers use "ColorMode" attribute in their ppds.
205 ppd_option_t* color_mode_option = ppdFindOption(ppd, kColorMode);
206 if (!color_mode_option)
207 return false;
209 if (ppdFindChoice(color_mode_option, printing::kColor))
210 *color_model_for_color = printing::COLORMODE_COLOR;
212 if (ppdFindChoice(color_mode_option, printing::kMonochrome))
213 *color_model_for_black = printing::COLORMODE_MONOCHROME;
215 ppd_choice_t* mode_choice = ppdFindMarkedChoice(ppd, kColorMode);
216 if (!mode_choice) {
217 mode_choice = ppdFindChoice(color_mode_option,
218 color_mode_option->defchoice);
221 if (mode_choice) {
222 *color_is_default =
223 (base::strcasecmp(mode_choice->choice, printing::kColor) == 0);
225 return true;
228 bool GetHPColorSettings(ppd_file_t* ppd,
229 ColorModel* color_model_for_black,
230 ColorModel* color_model_for_color,
231 bool* color_is_default) {
232 // HP printers use "Color/Color Model" attribute in their ppds.
233 ppd_option_t* color_mode_option = ppdFindOption(ppd, printing::kColor);
234 if (!color_mode_option)
235 return false;
237 if (ppdFindChoice(color_mode_option, printing::kColor))
238 *color_model_for_color = printing::HP_COLOR_COLOR;
239 if (ppdFindChoice(color_mode_option, printing::kBlack))
240 *color_model_for_black = printing::HP_COLOR_BLACK;
242 ppd_choice_t* mode_choice = ppdFindMarkedChoice(ppd, kColorMode);
243 if (!mode_choice) {
244 mode_choice = ppdFindChoice(color_mode_option,
245 color_mode_option->defchoice);
247 if (mode_choice) {
248 *color_is_default =
249 (base::strcasecmp(mode_choice->choice, printing::kColor) == 0);
251 return true;
254 bool GetProcessColorModelSettings(ppd_file_t* ppd,
255 ColorModel* color_model_for_black,
256 ColorModel* color_model_for_color,
257 bool* color_is_default) {
258 // Canon printers use "ProcessColorModel" attribute in their ppds.
259 ppd_option_t* color_mode_option = ppdFindOption(ppd, kProcessColorModel);
260 if (!color_mode_option)
261 return false;
263 if (ppdFindChoice(color_mode_option, printing::kRGB))
264 *color_model_for_color = printing::PROCESSCOLORMODEL_RGB;
265 else if (ppdFindChoice(color_mode_option, printing::kCMYK))
266 *color_model_for_color = printing::PROCESSCOLORMODEL_CMYK;
268 if (ppdFindChoice(color_mode_option, printing::kGreyscale))
269 *color_model_for_black = printing::PROCESSCOLORMODEL_GREYSCALE;
271 ppd_choice_t* mode_choice = ppdFindMarkedChoice(ppd, kProcessColorModel);
272 if (!mode_choice) {
273 mode_choice = ppdFindChoice(color_mode_option,
274 color_mode_option->defchoice);
277 if (mode_choice) {
278 *color_is_default =
279 (base::strcasecmp(mode_choice->choice, printing::kGreyscale) != 0);
281 return true;
284 bool GetColorModelSettings(ppd_file_t* ppd,
285 ColorModel* cm_black,
286 ColorModel* cm_color,
287 bool* is_color) {
288 bool is_color_device = false;
289 ppd_attr_t* attr = ppdFindAttr(ppd, kColorDevice, NULL);
290 if (attr && attr->value)
291 is_color_device = ppd->color_device;
293 *is_color = is_color_device;
294 return (is_color_device &&
295 GetBasicColorModelSettings(ppd, cm_black, cm_color, is_color)) ||
296 GetPrintOutModeColorSettings(ppd, cm_black, cm_color, is_color) ||
297 GetColorModeSettings(ppd, cm_black, cm_color, is_color) ||
298 GetHPColorSettings(ppd, cm_black, cm_color, is_color) ||
299 GetProcessColorModelSettings(ppd, cm_black, cm_color, is_color);
302 // Default port for IPP print servers.
303 const int kDefaultIPPServerPort = 631;
305 } // namespace
307 // Helper wrapper around http_t structure, with connection and cleanup
308 // functionality.
309 HttpConnectionCUPS::HttpConnectionCUPS(const GURL& print_server_url,
310 http_encryption_t encryption)
311 : http_(NULL) {
312 // If we have an empty url, use default print server.
313 if (print_server_url.is_empty())
314 return;
316 int port = print_server_url.IntPort();
317 if (port == url::PORT_UNSPECIFIED)
318 port = kDefaultIPPServerPort;
320 http_ = httpConnectEncrypt(print_server_url.host().c_str(), port, encryption);
321 if (http_ == NULL) {
322 LOG(ERROR) << "CP_CUPS: Failed connecting to print server: "
323 << print_server_url;
327 HttpConnectionCUPS::~HttpConnectionCUPS() {
328 if (http_ != NULL)
329 httpClose(http_);
332 void HttpConnectionCUPS::SetBlocking(bool blocking) {
333 httpBlocking(http_, blocking ? 1 : 0);
336 http_t* HttpConnectionCUPS::http() {
337 return http_;
340 bool ParsePpdCapabilities(
341 const std::string& printer_name,
342 const std::string& printer_capabilities,
343 PrinterSemanticCapsAndDefaults* printer_info) {
344 base::FilePath ppd_file_path;
345 if (!base::CreateTemporaryFile(&ppd_file_path))
346 return false;
348 int data_size = printer_capabilities.length();
349 if (data_size != base::WriteFile(
350 ppd_file_path,
351 printer_capabilities.data(),
352 data_size)) {
353 base::DeleteFile(ppd_file_path, false);
354 return false;
357 ppd_file_t* ppd = ppdOpenFile(ppd_file_path.value().c_str());
358 if (!ppd)
359 return false;
361 printing::PrinterSemanticCapsAndDefaults caps;
362 #if !defined(OS_MACOSX)
363 MarkLpOptions(printer_name, &ppd);
364 #endif
365 ppd_choice_t* duplex_choice = ppdFindMarkedChoice(ppd, kDuplex);
366 if (!duplex_choice) {
367 ppd_option_t* option = ppdFindOption(ppd, kDuplex);
368 if (option)
369 duplex_choice = ppdFindChoice(option, option->defchoice);
372 if (duplex_choice) {
373 caps.duplex_capable = true;
374 if (base::strcasecmp(duplex_choice->choice, kDuplexNone) != 0)
375 caps.duplex_default = printing::LONG_EDGE;
376 else
377 caps.duplex_default = printing::SIMPLEX;
380 bool is_color = false;
381 ColorModel cm_color = UNKNOWN_COLOR_MODEL, cm_black = UNKNOWN_COLOR_MODEL;
382 if (!GetColorModelSettings(ppd, &cm_black, &cm_color, &is_color)) {
383 VLOG(1) << "Unknown printer color model";
386 caps.color_changeable = ((cm_color != UNKNOWN_COLOR_MODEL) &&
387 (cm_black != UNKNOWN_COLOR_MODEL) &&
388 (cm_color != cm_black));
389 caps.color_default = is_color;
390 caps.color_model = cm_color;
391 caps.bw_model = cm_black;
393 ppdClose(ppd);
394 base::DeleteFile(ppd_file_path, false);
396 *printer_info = caps;
397 return true;
400 } // namespace printing