OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "printing/backend/cups_helper.h" | 5 #include "printing/backend/cups_helper.h" |
6 | 6 |
| 7 #include "base/file_util.h" |
7 #include "base/logging.h" | 8 #include "base/logging.h" |
| 9 #include "base/string_number_conversions.h" |
| 10 #include "base/string_split.h" |
| 11 #include "base/string_util.h" |
| 12 #include "base/values.h" |
8 #include "googleurl/src/gurl.h" | 13 #include "googleurl/src/gurl.h" |
| 14 #include "printing/backend/print_backend.h" |
| 15 #include "printing/backend/print_backend_consts.h" |
| 16 |
| 17 // This section contains helper code for PPD parsing for semantic capabilities. |
| 18 namespace { |
| 19 |
| 20 const char kColorDevice[] = "ColorDevice"; |
| 21 const char kColorModel[] = "ColorModel"; |
| 22 const char kColorMode[] = "ColorMode"; |
| 23 const char kProcessColorModel[] = "ProcessColorModel"; |
| 24 const char kPrintoutMode[] = "PrintoutMode"; |
| 25 const char kDraftGray[] = "Draft.Gray"; |
| 26 const char kHighGray[] = "High.Gray"; |
| 27 |
| 28 const char kDuplex[] = "Duplex"; |
| 29 const char kDuplexNone[] = "None"; |
| 30 |
| 31 #if !defined(OS_MACOSX) |
| 32 void ParseLpOptions(const FilePath& filepath, const std::string& printer_name, |
| 33 int* num_options, cups_option_t** options) { |
| 34 std::string content; |
| 35 if (!file_util::ReadFileToString(filepath, &content)) |
| 36 return; |
| 37 |
| 38 const char kDest[] = "dest"; |
| 39 const char kDefault[] = "default"; |
| 40 const size_t kDestLen = sizeof(kDest) - 1; |
| 41 const size_t kDefaultLen = sizeof(kDefault) - 1; |
| 42 std::vector<std::string> lines; |
| 43 base::SplitString(content, '\n', &lines); |
| 44 |
| 45 for (size_t i = 0; i < lines.size(); ++i) { |
| 46 std::string line = lines[i]; |
| 47 if (line.empty()) |
| 48 continue; |
| 49 |
| 50 if (base::strncasecmp (line.c_str(), kDefault, kDefaultLen) == 0 && |
| 51 isspace(line[kDefaultLen])) { |
| 52 line = line.substr(kDefaultLen); |
| 53 } else if (base::strncasecmp (line.c_str(), kDest, kDestLen) == 0 && |
| 54 isspace(line[kDestLen])) { |
| 55 line = line.substr(kDestLen); |
| 56 } else { |
| 57 continue; |
| 58 } |
| 59 |
| 60 TrimWhitespaceASCII(line, TRIM_ALL, &line); |
| 61 if (line.empty()) |
| 62 continue; |
| 63 |
| 64 size_t space_found = line.find(' '); |
| 65 if (space_found == std::string::npos) |
| 66 continue; |
| 67 |
| 68 std::string name = line.substr(0, space_found); |
| 69 if (name.empty()) |
| 70 continue; |
| 71 |
| 72 if (base::strncasecmp(printer_name.c_str(), name.c_str(), |
| 73 name.length()) != 0) { |
| 74 continue; // This is not the required printer. |
| 75 } |
| 76 |
| 77 line = line.substr(space_found + 1); |
| 78 TrimWhitespaceASCII(line, TRIM_ALL, &line); // Remove extra spaces. |
| 79 if (line.empty()) |
| 80 continue; |
| 81 // Parse the selected printer custom options. |
| 82 *num_options = cupsParseOptions(line.c_str(), 0, options); |
| 83 } |
| 84 } |
| 85 |
| 86 void MarkLpOptions(const std::string& printer_name, ppd_file_t** ppd) { |
| 87 cups_option_t* options = NULL; |
| 88 int num_options = 0; |
| 89 ppdMarkDefaults(*ppd); |
| 90 |
| 91 const char kSystemLpOptionPath[] = "/etc/cups/lpoptions"; |
| 92 const char kUserLpOptionPath[] = ".cups/lpoptions"; |
| 93 |
| 94 std::vector<FilePath> file_locations; |
| 95 file_locations.push_back(FilePath(kSystemLpOptionPath)); |
| 96 file_locations.push_back(FilePath( |
| 97 file_util::GetHomeDir().Append(kUserLpOptionPath))); |
| 98 |
| 99 for (std::vector<FilePath>::const_iterator it = file_locations.begin(); |
| 100 it != file_locations.end(); ++it) { |
| 101 num_options = 0; |
| 102 options = NULL; |
| 103 ParseLpOptions(*it, printer_name, &num_options, &options); |
| 104 if (num_options > 0 && options) { |
| 105 cupsMarkOptions(*ppd, num_options, options); |
| 106 cupsFreeOptions(num_options, options); |
| 107 } |
| 108 } |
| 109 } |
| 110 #endif // !defined(OS_MACOSX) |
| 111 |
| 112 bool GetBasicColorModelSettings(ppd_file_t* ppd, |
| 113 int* color_model_for_black, |
| 114 int* color_model_for_color, |
| 115 bool* color_is_default) { |
| 116 ppd_option_t* color_model = ppdFindOption(ppd, kColorModel); |
| 117 if (!color_model) |
| 118 return false; |
| 119 |
| 120 if (ppdFindChoice(color_model, printing::kBlack)) |
| 121 *color_model_for_black = printing::BLACK; |
| 122 else if (ppdFindChoice(color_model, printing::kGray)) |
| 123 *color_model_for_black = printing::GRAY; |
| 124 else if (ppdFindChoice(color_model, printing::kGrayscale)) |
| 125 *color_model_for_black = printing::GRAYSCALE; |
| 126 |
| 127 if (ppdFindChoice(color_model, printing::kColor)) |
| 128 *color_model_for_color = printing::COLOR; |
| 129 else if (ppdFindChoice(color_model, printing::kCMYK)) |
| 130 *color_model_for_color = printing::CMYK; |
| 131 else if (ppdFindChoice(color_model, printing::kRGB)) |
| 132 *color_model_for_color = printing::RGB; |
| 133 else if (ppdFindChoice(color_model, printing::kRGBA)) |
| 134 *color_model_for_color = printing::RGBA; |
| 135 else if (ppdFindChoice(color_model, printing::kRGB16)) |
| 136 *color_model_for_color = printing::RGB16; |
| 137 else if (ppdFindChoice(color_model, printing::kCMY)) |
| 138 *color_model_for_color = printing::CMY; |
| 139 else if (ppdFindChoice(color_model, printing::kKCMY)) |
| 140 *color_model_for_color = printing::KCMY; |
| 141 else if (ppdFindChoice(color_model, printing::kCMY_K)) |
| 142 *color_model_for_color = printing::CMY_K; |
| 143 |
| 144 ppd_choice_t* marked_choice = ppdFindMarkedChoice(ppd, kColorModel); |
| 145 if (!marked_choice) |
| 146 marked_choice = ppdFindChoice(color_model, color_model->defchoice); |
| 147 |
| 148 if (marked_choice) { |
| 149 *color_is_default = |
| 150 (base::strcasecmp(marked_choice->choice, printing::kBlack) != 0) && |
| 151 (base::strcasecmp(marked_choice->choice, printing::kGray) != 0) && |
| 152 (base::strcasecmp(marked_choice->choice, printing::kGrayscale) != 0); |
| 153 } |
| 154 return true; |
| 155 } |
| 156 |
| 157 bool GetPrintOutModeColorSettings(ppd_file_t* ppd, |
| 158 int* color_model_for_black, |
| 159 int* color_model_for_color, |
| 160 bool* color_is_default) { |
| 161 ppd_option_t* printout_mode = ppdFindOption(ppd, kPrintoutMode); |
| 162 if (!printout_mode) |
| 163 return false; |
| 164 |
| 165 *color_model_for_color = printing::PRINTOUTMODE_NORMAL; |
| 166 *color_model_for_black = printing::PRINTOUTMODE_NORMAL; |
| 167 |
| 168 // Check to see if NORMAL_GRAY value is supported by PrintoutMode. |
| 169 // If NORMAL_GRAY is not supported, NORMAL value is used to |
| 170 // represent grayscale. If NORMAL_GRAY is supported, NORMAL is used to |
| 171 // represent color. |
| 172 if (ppdFindChoice(printout_mode, printing::kNormalGray)) |
| 173 *color_model_for_black = printing::PRINTOUTMODE_NORMAL_GRAY; |
| 174 |
| 175 // Get the default marked choice to identify the default color setting |
| 176 // value. |
| 177 ppd_choice_t* printout_mode_choice = ppdFindMarkedChoice(ppd, kPrintoutMode); |
| 178 if (!printout_mode_choice) { |
| 179 printout_mode_choice = ppdFindChoice(printout_mode, |
| 180 printout_mode->defchoice); |
| 181 } |
| 182 if (printout_mode_choice) { |
| 183 if ((base::strcasecmp(printout_mode_choice->choice, |
| 184 printing::kNormalGray) == 0) || |
| 185 (base::strcasecmp(printout_mode_choice->choice, kHighGray) == 0) || |
| 186 (base::strcasecmp(printout_mode_choice->choice, kDraftGray) == 0)) { |
| 187 *color_model_for_black = printing::PRINTOUTMODE_NORMAL_GRAY; |
| 188 *color_is_default = false; |
| 189 } |
| 190 } |
| 191 return true; |
| 192 } |
| 193 |
| 194 bool GetColorModeSettings(ppd_file_t* ppd, |
| 195 int* color_model_for_black, |
| 196 int* color_model_for_color, |
| 197 bool* color_is_default) { |
| 198 // Samsung printers use "ColorMode" attribute in their ppds. |
| 199 ppd_option_t* color_mode_option = ppdFindOption(ppd, kColorMode); |
| 200 if (!color_mode_option) |
| 201 return false; |
| 202 |
| 203 if (ppdFindChoice(color_mode_option, printing::kColor)) |
| 204 *color_model_for_color = printing::COLORMODE_COLOR; |
| 205 |
| 206 if (ppdFindChoice(color_mode_option, printing::kMonochrome)) |
| 207 *color_model_for_black = printing::COLORMODE_MONOCHROME; |
| 208 |
| 209 ppd_choice_t* mode_choice = ppdFindMarkedChoice(ppd, kColorMode); |
| 210 if (!mode_choice) { |
| 211 mode_choice = ppdFindChoice(color_mode_option, |
| 212 color_mode_option->defchoice); |
| 213 } |
| 214 |
| 215 if (mode_choice) { |
| 216 *color_is_default = |
| 217 (base::strcasecmp(mode_choice->choice, printing::kColor) == 0); |
| 218 } |
| 219 return true; |
| 220 } |
| 221 |
| 222 bool GetHPColorSettings(ppd_file_t* ppd, |
| 223 int* color_model_for_black, |
| 224 int* color_model_for_color, |
| 225 bool* color_is_default) { |
| 226 // HP printers use "Color/Color Model" attribute in their ppds. |
| 227 ppd_option_t* color_mode_option = ppdFindOption(ppd, printing::kColor); |
| 228 if (!color_mode_option) |
| 229 return false; |
| 230 |
| 231 if (ppdFindChoice(color_mode_option, printing::kColor)) |
| 232 *color_model_for_color = printing::HP_COLOR_COLOR; |
| 233 if (ppdFindChoice(color_mode_option, printing::kBlack)) |
| 234 *color_model_for_black = printing::HP_COLOR_BLACK; |
| 235 |
| 236 ppd_choice_t* mode_choice = ppdFindMarkedChoice(ppd, kColorMode); |
| 237 if (!mode_choice) { |
| 238 mode_choice = ppdFindChoice(color_mode_option, |
| 239 color_mode_option->defchoice); |
| 240 } |
| 241 if (mode_choice) { |
| 242 *color_is_default = |
| 243 (base::strcasecmp(mode_choice->choice, printing::kColor) == 0); |
| 244 } |
| 245 return true; |
| 246 } |
| 247 |
| 248 bool GetProcessColorModelSettings(ppd_file_t* ppd, |
| 249 int* color_model_for_black, |
| 250 int* color_model_for_color, |
| 251 bool* color_is_default) { |
| 252 // Canon printers use "ProcessColorModel" attribute in their ppds. |
| 253 ppd_option_t* color_mode_option = ppdFindOption(ppd, kProcessColorModel); |
| 254 if (!color_mode_option) |
| 255 return false; |
| 256 |
| 257 if (ppdFindChoice(color_mode_option, printing::kRGB)) |
| 258 *color_model_for_color = printing::PROCESSCOLORMODEL_RGB; |
| 259 else if (ppdFindChoice(color_mode_option, printing::kCMYK)) |
| 260 *color_model_for_color = printing::PROCESSCOLORMODEL_CMYK; |
| 261 |
| 262 if (ppdFindChoice(color_mode_option, printing::kGreyscale)) |
| 263 *color_model_for_black = printing::PROCESSCOLORMODEL_GREYSCALE; |
| 264 |
| 265 ppd_choice_t* mode_choice = ppdFindMarkedChoice(ppd, kProcessColorModel); |
| 266 if (!mode_choice) { |
| 267 mode_choice = ppdFindChoice(color_mode_option, |
| 268 color_mode_option->defchoice); |
| 269 } |
| 270 |
| 271 if (mode_choice) { |
| 272 *color_is_default = |
| 273 (base::strcasecmp(mode_choice->choice, printing::kGreyscale) != 0); |
| 274 } |
| 275 return true; |
| 276 } |
| 277 |
| 278 bool GetColorModelSettings(ppd_file_t* ppd, |
| 279 int* cm_black, |
| 280 int* cm_color, |
| 281 bool* is_color) { |
| 282 bool is_color_device = false; |
| 283 ppd_attr_t* attr = ppdFindAttr(ppd, kColorDevice, NULL); |
| 284 if (attr && attr->value) |
| 285 is_color_device = ppd->color_device; |
| 286 |
| 287 *is_color = is_color_device; |
| 288 return (is_color_device && |
| 289 GetBasicColorModelSettings(ppd, cm_black, cm_color, is_color)) || |
| 290 GetPrintOutModeColorSettings(ppd, cm_black, cm_color, is_color) || |
| 291 GetColorModeSettings(ppd, cm_black, cm_color, is_color) || |
| 292 GetHPColorSettings(ppd, cm_black, cm_color, is_color) || |
| 293 GetProcessColorModelSettings(ppd, cm_black, cm_color, is_color); |
| 294 } |
| 295 |
| 296 } // namespace |
9 | 297 |
10 namespace printing { | 298 namespace printing { |
11 | 299 |
12 // Default port for IPP print servers. | 300 // Default port for IPP print servers. |
13 static const int kDefaultIPPServerPort = 631; | 301 static const int kDefaultIPPServerPort = 631; |
14 | 302 |
15 // Helper wrapper around http_t structure, with connection and cleanup | 303 // Helper wrapper around http_t structure, with connection and cleanup |
16 // functionality. | 304 // functionality. |
17 HttpConnectionCUPS::HttpConnectionCUPS(const GURL& print_server_url, | 305 HttpConnectionCUPS::HttpConnectionCUPS(const GURL& print_server_url, |
18 http_encryption_t encryption) | 306 http_encryption_t encryption) |
(...skipping 20 matching lines...) Expand all Loading... |
39 } | 327 } |
40 | 328 |
41 void HttpConnectionCUPS::SetBlocking(bool blocking) { | 329 void HttpConnectionCUPS::SetBlocking(bool blocking) { |
42 httpBlocking(http_, blocking ? 1 : 0); | 330 httpBlocking(http_, blocking ? 1 : 0); |
43 } | 331 } |
44 | 332 |
45 http_t* HttpConnectionCUPS::http() { | 333 http_t* HttpConnectionCUPS::http() { |
46 return http_; | 334 return http_; |
47 } | 335 } |
48 | 336 |
| 337 bool parsePpdCapabilities( |
| 338 const std::string& printer_name, |
| 339 const std::string& printer_capabilities, |
| 340 PrinterSemanticCapsAndDefaults* printer_info) { |
| 341 FilePath ppd_file_path; |
| 342 if (!file_util::CreateTemporaryFile(&ppd_file_path)) |
| 343 return false; |
| 344 |
| 345 int data_size = printer_capabilities.length(); |
| 346 if (data_size != file_util::WriteFile( |
| 347 ppd_file_path, |
| 348 printer_capabilities.data(), |
| 349 data_size)) { |
| 350 file_util::Delete(ppd_file_path, false); |
| 351 return false; |
| 352 } |
| 353 |
| 354 ppd_file_t* ppd = ppdOpenFile(ppd_file_path.value().c_str()); |
| 355 if (!ppd) |
| 356 return false; |
| 357 |
| 358 printing::PrinterSemanticCapsAndDefaults caps; |
| 359 #if !defined(OS_MACOSX) |
| 360 MarkLpOptions(printer_name, &ppd); |
| 361 #endif |
| 362 ppd_choice_t* duplex_choice = ppdFindMarkedChoice(ppd, kDuplex); |
| 363 if (!duplex_choice) { |
| 364 ppd_option_t* option = ppdFindOption(ppd, kDuplex); |
| 365 if (option) |
| 366 duplex_choice = ppdFindChoice(option, option->defchoice); |
| 367 } |
| 368 |
| 369 if (duplex_choice) { |
| 370 caps.duplex_capable = true; |
| 371 if (base::strcasecmp(duplex_choice->choice, kDuplexNone) != 0) |
| 372 caps.duplex_default = printing::LONG_EDGE; |
| 373 else |
| 374 caps.duplex_default = printing::SIMPLEX; |
| 375 } |
| 376 |
| 377 bool is_color = false; |
| 378 int cm_color = 0, cm_black = 0; |
| 379 if (!GetColorModelSettings(ppd, &cm_black, &cm_color, &is_color)) { |
| 380 VLOG(1) << "Unknown printer color model"; |
| 381 } |
| 382 |
| 383 caps.color_capable = (cm_color && cm_black && (cm_color != cm_black)); |
| 384 caps.color_default = is_color; |
| 385 |
| 386 ppdClose(ppd); |
| 387 file_util::Delete(ppd_file_path, false); |
| 388 |
| 389 *printer_info = caps; |
| 390 return true; |
| 391 } |
| 392 |
49 } // namespace printing | 393 } // namespace printing |
OLD | NEW |