Avoid double-InitCache() in SimpleDoomBetween test, leak
[chromium-blink-merge.git] / printing / backend / cups_helper.cc
blobfecd18a2d729f2d80503ed649b1f3a387b9e164d
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/string_number_conversions.h"
12 #include "base/string_util.h"
13 #include "base/strings/string_split.h"
14 #include "base/values.h"
15 #include "googleurl/src/gurl.h"
16 #include "printing/backend/print_backend.h"
17 #include "printing/backend/print_backend_consts.h"
19 // This section contains helper code for PPD parsing for semantic capabilities.
20 namespace {
22 const char kColorDevice[] = "ColorDevice";
23 const char kColorModel[] = "ColorModel";
24 const char kColorMode[] = "ColorMode";
25 const char kProcessColorModel[] = "ProcessColorModel";
26 const char kPrintoutMode[] = "PrintoutMode";
27 const char kDraftGray[] = "Draft.Gray";
28 const char kHighGray[] = "High.Gray";
30 const char kDuplex[] = "Duplex";
31 const char kDuplexNone[] = "None";
33 #if !defined(OS_MACOSX)
34 void ParseLpOptions(const base::FilePath& filepath,
35 const std::string& printer_name,
36 int* num_options, cups_option_t** options) {
37 std::string content;
38 if (!file_util::ReadFileToString(filepath, &content))
39 return;
41 const char kDest[] = "dest";
42 const char kDefault[] = "default";
43 const size_t kDestLen = sizeof(kDest) - 1;
44 const size_t kDefaultLen = sizeof(kDefault) - 1;
45 std::vector<std::string> lines;
46 base::SplitString(content, '\n', &lines);
48 for (size_t i = 0; i < lines.size(); ++i) {
49 std::string line = lines[i];
50 if (line.empty())
51 continue;
53 if (base::strncasecmp (line.c_str(), kDefault, kDefaultLen) == 0 &&
54 isspace(line[kDefaultLen])) {
55 line = line.substr(kDefaultLen);
56 } else if (base::strncasecmp (line.c_str(), kDest, kDestLen) == 0 &&
57 isspace(line[kDestLen])) {
58 line = line.substr(kDestLen);
59 } else {
60 continue;
63 TrimWhitespaceASCII(line, TRIM_ALL, &line);
64 if (line.empty())
65 continue;
67 size_t space_found = line.find(' ');
68 if (space_found == std::string::npos)
69 continue;
71 std::string name = line.substr(0, space_found);
72 if (name.empty())
73 continue;
75 if (base::strncasecmp(printer_name.c_str(), name.c_str(),
76 name.length()) != 0) {
77 continue; // This is not the required printer.
80 line = line.substr(space_found + 1);
81 TrimWhitespaceASCII(line, TRIM_ALL, &line); // Remove extra spaces.
82 if (line.empty())
83 continue;
84 // Parse the selected printer custom options.
85 *num_options = cupsParseOptions(line.c_str(), 0, options);
89 void MarkLpOptions(const std::string& printer_name, ppd_file_t** ppd) {
90 cups_option_t* options = NULL;
91 int num_options = 0;
92 ppdMarkDefaults(*ppd);
94 const char kSystemLpOptionPath[] = "/etc/cups/lpoptions";
95 const char kUserLpOptionPath[] = ".cups/lpoptions";
97 std::vector<base::FilePath> file_locations;
98 file_locations.push_back(base::FilePath(kSystemLpOptionPath));
99 file_locations.push_back(base::FilePath(
100 file_util::GetHomeDir().Append(kUserLpOptionPath)));
102 for (std::vector<base::FilePath>::const_iterator it = file_locations.begin();
103 it != file_locations.end(); ++it) {
104 num_options = 0;
105 options = NULL;
106 ParseLpOptions(*it, printer_name, &num_options, &options);
107 if (num_options > 0 && options) {
108 cupsMarkOptions(*ppd, num_options, options);
109 cupsFreeOptions(num_options, options);
113 #endif // !defined(OS_MACOSX)
115 bool GetBasicColorModelSettings(ppd_file_t* ppd,
116 int* color_model_for_black,
117 int* color_model_for_color,
118 bool* color_is_default) {
119 ppd_option_t* color_model = ppdFindOption(ppd, kColorModel);
120 if (!color_model)
121 return false;
123 if (ppdFindChoice(color_model, printing::kBlack))
124 *color_model_for_black = printing::BLACK;
125 else if (ppdFindChoice(color_model, printing::kGray))
126 *color_model_for_black = printing::GRAY;
127 else if (ppdFindChoice(color_model, printing::kGrayscale))
128 *color_model_for_black = printing::GRAYSCALE;
130 if (ppdFindChoice(color_model, printing::kColor))
131 *color_model_for_color = printing::COLOR;
132 else if (ppdFindChoice(color_model, printing::kCMYK))
133 *color_model_for_color = printing::CMYK;
134 else if (ppdFindChoice(color_model, printing::kRGB))
135 *color_model_for_color = printing::RGB;
136 else if (ppdFindChoice(color_model, printing::kRGBA))
137 *color_model_for_color = printing::RGBA;
138 else if (ppdFindChoice(color_model, printing::kRGB16))
139 *color_model_for_color = printing::RGB16;
140 else if (ppdFindChoice(color_model, printing::kCMY))
141 *color_model_for_color = printing::CMY;
142 else if (ppdFindChoice(color_model, printing::kKCMY))
143 *color_model_for_color = printing::KCMY;
144 else if (ppdFindChoice(color_model, printing::kCMY_K))
145 *color_model_for_color = printing::CMY_K;
147 ppd_choice_t* marked_choice = ppdFindMarkedChoice(ppd, kColorModel);
148 if (!marked_choice)
149 marked_choice = ppdFindChoice(color_model, color_model->defchoice);
151 if (marked_choice) {
152 *color_is_default =
153 (base::strcasecmp(marked_choice->choice, printing::kBlack) != 0) &&
154 (base::strcasecmp(marked_choice->choice, printing::kGray) != 0) &&
155 (base::strcasecmp(marked_choice->choice, printing::kGrayscale) != 0);
157 return true;
160 bool GetPrintOutModeColorSettings(ppd_file_t* ppd,
161 int* color_model_for_black,
162 int* color_model_for_color,
163 bool* color_is_default) {
164 ppd_option_t* printout_mode = ppdFindOption(ppd, kPrintoutMode);
165 if (!printout_mode)
166 return false;
168 *color_model_for_color = printing::PRINTOUTMODE_NORMAL;
169 *color_model_for_black = printing::PRINTOUTMODE_NORMAL;
171 // Check to see if NORMAL_GRAY value is supported by PrintoutMode.
172 // If NORMAL_GRAY is not supported, NORMAL value is used to
173 // represent grayscale. If NORMAL_GRAY is supported, NORMAL is used to
174 // represent color.
175 if (ppdFindChoice(printout_mode, printing::kNormalGray))
176 *color_model_for_black = printing::PRINTOUTMODE_NORMAL_GRAY;
178 // Get the default marked choice to identify the default color setting
179 // value.
180 ppd_choice_t* printout_mode_choice = ppdFindMarkedChoice(ppd, kPrintoutMode);
181 if (!printout_mode_choice) {
182 printout_mode_choice = ppdFindChoice(printout_mode,
183 printout_mode->defchoice);
185 if (printout_mode_choice) {
186 if ((base::strcasecmp(printout_mode_choice->choice,
187 printing::kNormalGray) == 0) ||
188 (base::strcasecmp(printout_mode_choice->choice, kHighGray) == 0) ||
189 (base::strcasecmp(printout_mode_choice->choice, kDraftGray) == 0)) {
190 *color_model_for_black = printing::PRINTOUTMODE_NORMAL_GRAY;
191 *color_is_default = false;
194 return true;
197 bool GetColorModeSettings(ppd_file_t* ppd,
198 int* color_model_for_black,
199 int* color_model_for_color,
200 bool* color_is_default) {
201 // Samsung printers use "ColorMode" attribute in their ppds.
202 ppd_option_t* color_mode_option = ppdFindOption(ppd, kColorMode);
203 if (!color_mode_option)
204 return false;
206 if (ppdFindChoice(color_mode_option, printing::kColor))
207 *color_model_for_color = printing::COLORMODE_COLOR;
209 if (ppdFindChoice(color_mode_option, printing::kMonochrome))
210 *color_model_for_black = printing::COLORMODE_MONOCHROME;
212 ppd_choice_t* mode_choice = ppdFindMarkedChoice(ppd, kColorMode);
213 if (!mode_choice) {
214 mode_choice = ppdFindChoice(color_mode_option,
215 color_mode_option->defchoice);
218 if (mode_choice) {
219 *color_is_default =
220 (base::strcasecmp(mode_choice->choice, printing::kColor) == 0);
222 return true;
225 bool GetHPColorSettings(ppd_file_t* ppd,
226 int* color_model_for_black,
227 int* color_model_for_color,
228 bool* color_is_default) {
229 // HP printers use "Color/Color Model" attribute in their ppds.
230 ppd_option_t* color_mode_option = ppdFindOption(ppd, printing::kColor);
231 if (!color_mode_option)
232 return false;
234 if (ppdFindChoice(color_mode_option, printing::kColor))
235 *color_model_for_color = printing::HP_COLOR_COLOR;
236 if (ppdFindChoice(color_mode_option, printing::kBlack))
237 *color_model_for_black = printing::HP_COLOR_BLACK;
239 ppd_choice_t* mode_choice = ppdFindMarkedChoice(ppd, kColorMode);
240 if (!mode_choice) {
241 mode_choice = ppdFindChoice(color_mode_option,
242 color_mode_option->defchoice);
244 if (mode_choice) {
245 *color_is_default =
246 (base::strcasecmp(mode_choice->choice, printing::kColor) == 0);
248 return true;
251 bool GetProcessColorModelSettings(ppd_file_t* ppd,
252 int* color_model_for_black,
253 int* color_model_for_color,
254 bool* color_is_default) {
255 // Canon printers use "ProcessColorModel" attribute in their ppds.
256 ppd_option_t* color_mode_option = ppdFindOption(ppd, kProcessColorModel);
257 if (!color_mode_option)
258 return false;
260 if (ppdFindChoice(color_mode_option, printing::kRGB))
261 *color_model_for_color = printing::PROCESSCOLORMODEL_RGB;
262 else if (ppdFindChoice(color_mode_option, printing::kCMYK))
263 *color_model_for_color = printing::PROCESSCOLORMODEL_CMYK;
265 if (ppdFindChoice(color_mode_option, printing::kGreyscale))
266 *color_model_for_black = printing::PROCESSCOLORMODEL_GREYSCALE;
268 ppd_choice_t* mode_choice = ppdFindMarkedChoice(ppd, kProcessColorModel);
269 if (!mode_choice) {
270 mode_choice = ppdFindChoice(color_mode_option,
271 color_mode_option->defchoice);
274 if (mode_choice) {
275 *color_is_default =
276 (base::strcasecmp(mode_choice->choice, printing::kGreyscale) != 0);
278 return true;
281 bool GetColorModelSettings(ppd_file_t* ppd,
282 int* cm_black,
283 int* cm_color,
284 bool* is_color) {
285 bool is_color_device = false;
286 ppd_attr_t* attr = ppdFindAttr(ppd, kColorDevice, NULL);
287 if (attr && attr->value)
288 is_color_device = ppd->color_device;
290 *is_color = is_color_device;
291 return (is_color_device &&
292 GetBasicColorModelSettings(ppd, cm_black, cm_color, is_color)) ||
293 GetPrintOutModeColorSettings(ppd, cm_black, cm_color, is_color) ||
294 GetColorModeSettings(ppd, cm_black, cm_color, is_color) ||
295 GetHPColorSettings(ppd, cm_black, cm_color, is_color) ||
296 GetProcessColorModelSettings(ppd, cm_black, cm_color, is_color);
299 } // namespace
301 namespace printing {
303 // Default port for IPP print servers.
304 static const int kDefaultIPPServerPort = 631;
306 // Helper wrapper around http_t structure, with connection and cleanup
307 // functionality.
308 HttpConnectionCUPS::HttpConnectionCUPS(const GURL& print_server_url,
309 http_encryption_t encryption)
310 : http_(NULL) {
311 // If we have an empty url, use default print server.
312 if (print_server_url.is_empty())
313 return;
315 int port = print_server_url.IntPort();
316 if (port == url_parse::PORT_UNSPECIFIED)
317 port = kDefaultIPPServerPort;
319 http_ = httpConnectEncrypt(print_server_url.host().c_str(), port,
320 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 (!file_util::CreateTemporaryFile(&ppd_file_path))
346 return false;
348 int data_size = printer_capabilities.length();
349 if (data_size != file_util::WriteFile(
350 ppd_file_path,
351 printer_capabilities.data(),
352 data_size)) {
353 file_util::Delete(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 int cm_color = 0, cm_black = 0;
382 if (!GetColorModelSettings(ppd, &cm_black, &cm_color, &is_color)) {
383 VLOG(1) << "Unknown printer color model";
386 caps.color_changeable = (cm_color && cm_black && (cm_color != cm_black));
387 caps.color_default = is_color;
389 ppdClose(ppd);
390 file_util::Delete(ppd_file_path, false);
392 *printer_info = caps;
393 return true;
396 } // namespace printing