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

Side by Side Diff: printing/backend/print_backend_cups.cc

Issue 1976683005: Use cupsGetNamedDest() in PrintBackendCUPS. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 4 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 unified diff | Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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/print_backend.h" 5 #include "printing/backend/print_backend.h"
6 6
7 #include <dlfcn.h> 7 #include <dlfcn.h>
8 #include <errno.h> 8 #include <errno.h>
9 #include <pthread.h> 9 #include <pthread.h>
10 10
(...skipping 13 matching lines...) Expand all
24 static const char kCUPSPrinterInfoOpt[] = "printer-info"; 24 static const char kCUPSPrinterInfoOpt[] = "printer-info";
25 static const char kCUPSPrinterStateOpt[] = "printer-state"; 25 static const char kCUPSPrinterStateOpt[] = "printer-state";
26 static const char kCUPSPrinterTypeOpt[] = "printer-type"; 26 static const char kCUPSPrinterTypeOpt[] = "printer-type";
27 static const char kCUPSPrinterMakeModelOpt[] = "printer-make-and-model"; 27 static const char kCUPSPrinterMakeModelOpt[] = "printer-make-and-model";
28 28
29 class PrintBackendCUPS : public PrintBackend { 29 class PrintBackendCUPS : public PrintBackend {
30 public: 30 public:
31 PrintBackendCUPS(const GURL& print_server_url, 31 PrintBackendCUPS(const GURL& print_server_url,
32 http_encryption_t encryption, bool blocking); 32 http_encryption_t encryption, bool blocking);
33 33
34 private:
35 ~PrintBackendCUPS() override {}
36
34 // PrintBackend implementation. 37 // PrintBackend implementation.
35 bool EnumeratePrinters(PrinterList* printer_list) override; 38 bool EnumeratePrinters(PrinterList* printer_list) override;
36 std::string GetDefaultPrinterName() override; 39 std::string GetDefaultPrinterName() override;
37 bool GetPrinterSemanticCapsAndDefaults( 40 bool GetPrinterSemanticCapsAndDefaults(
38 const std::string& printer_name, 41 const std::string& printer_name,
39 PrinterSemanticCapsAndDefaults* printer_info) override; 42 PrinterSemanticCapsAndDefaults* printer_info) override;
40 bool GetPrinterCapsAndDefaults(const std::string& printer_name, 43 bool GetPrinterCapsAndDefaults(const std::string& printer_name,
41 PrinterCapsAndDefaults* printer_info) override; 44 PrinterCapsAndDefaults* printer_info) override;
42 std::string GetPrinterDriverInfo(const std::string& printer_name) override; 45 std::string GetPrinterDriverInfo(const std::string& printer_name) override;
43 bool IsValidPrinter(const std::string& printer_name) override; 46 bool IsValidPrinter(const std::string& printer_name) override;
44 47
45 protected: 48 // The following functions are wrappers around corresponding CUPS functions.
Lei Zhang 2016/05/16 18:43:18 Despite being "wrappers", these two methods are no
46 ~PrintBackendCUPS() override {} 49 // <functions>2() are called when print server is specified, and plain version
47 50 // in another case. There is an issue specifying CUPS_HTTP_DEFAULT in the
48 private: 51 // functions>2(), it does not work in CUPS prior to 1.4.
49 // Following functions are wrappers around corresponding CUPS functions.
50 // <functions>2() are called when print server is specified, and plain
51 // version in another case. There is an issue specifing CUPS_HTTP_DEFAULT
52 // in the <functions>2(), it does not work in CUPS prior to 1.4.
53 int GetDests(cups_dest_t** dests); 52 int GetDests(cups_dest_t** dests);
54 base::FilePath GetPPD(const char* name); 53 base::FilePath GetPPD(const char* name);
55 54
55 // Wrapper around cupsGetNamedDest(). Returned result should be freed with
56 // cupsFreeDests().
57 cups_dest_t* GetNamedDest(const std::string& printer_name);
58
56 GURL print_server_url_; 59 GURL print_server_url_;
57 http_encryption_t cups_encryption_; 60 http_encryption_t cups_encryption_;
58 bool blocking_; 61 bool blocking_;
59 }; 62 };
60 63
61 PrintBackendCUPS::PrintBackendCUPS(const GURL& print_server_url, 64 PrintBackendCUPS::PrintBackendCUPS(const GURL& print_server_url,
62 http_encryption_t encryption, 65 http_encryption_t encryption,
63 bool blocking) 66 bool blocking)
64 : print_server_url_(print_server_url), 67 : print_server_url_(print_server_url),
65 cups_encryption_(encryption), 68 cups_encryption_(encryption),
66 blocking_(blocking) { 69 blocking_(blocking) {
67 } 70 }
68 71
69 bool PrintBackendCUPS::EnumeratePrinters(PrinterList* printer_list) { 72 bool PrintBackendCUPS::EnumeratePrinters(PrinterList* printer_list) {
70 DCHECK(printer_list); 73 DCHECK(printer_list);
71 printer_list->clear(); 74 printer_list->clear();
72 75
73 cups_dest_t* destinations = NULL; 76 cups_dest_t* destinations = nullptr;
74 int num_dests = GetDests(&destinations); 77 int num_dests = GetDests(&destinations);
75 if ((num_dests == 0) && (cupsLastError() > IPP_OK_EVENTS_COMPLETE)) { 78 if (!num_dests && cupsLastError() > IPP_OK_EVENTS_COMPLETE) {
76 VLOG(1) << "CUPS: Error getting printers from CUPS server" 79 VLOG(1) << "CUPS: Error getting printers from CUPS server"
77 << ", server: " << print_server_url_ 80 << ", server: " << print_server_url_
78 << ", error: " << static_cast<int>(cupsLastError()); 81 << ", error: " << static_cast<int>(cupsLastError());
79 return false; 82 return false;
80 } 83 }
81 84
82 for (int printer_index = 0; printer_index < num_dests; ++printer_index) { 85 for (int printer_index = 0; printer_index < num_dests; ++printer_index) {
83 const cups_dest_t& printer = destinations[printer_index]; 86 const cups_dest_t& printer = destinations[printer_index];
84 87
85 // CUPS can have 'printers' that are actually scanners. (not MFC) 88 // CUPS can have 'printers' that are actually scanners. (not MFC)
86 // At least on Mac. Check for scanners and skip them. 89 // At least on Mac. Check for scanners and skip them.
87 const char* type_str = cupsGetOption(kCUPSPrinterTypeOpt, 90 const char* type_str = cupsGetOption(kCUPSPrinterTypeOpt,
88 printer.num_options, printer.options); 91 printer.num_options, printer.options);
89 if (type_str != NULL) { 92 if (type_str) {
90 int type; 93 int type;
91 if (base::StringToInt(type_str, &type) && (type & CUPS_PRINTER_SCANNER)) 94 if (base::StringToInt(type_str, &type) && (type & CUPS_PRINTER_SCANNER))
92 continue; 95 continue;
93 } 96 }
94 97
95 PrinterBasicInfo printer_info; 98 PrinterBasicInfo printer_info;
96 printer_info.printer_name = printer.name; 99 printer_info.printer_name = printer.name;
97 printer_info.is_default = printer.is_default; 100 printer_info.is_default = printer.is_default;
98 101
99 const char* info = cupsGetOption(kCUPSPrinterInfoOpt, 102 const char* info = cupsGetOption(kCUPSPrinterInfoOpt,
100 printer.num_options, printer.options); 103 printer.num_options, printer.options);
101 if (info != NULL) 104 if (info)
102 printer_info.printer_description = info; 105 printer_info.printer_description = info;
103 106
104 const char* state = cupsGetOption(kCUPSPrinterStateOpt, 107 const char* state = cupsGetOption(kCUPSPrinterStateOpt,
105 printer.num_options, printer.options); 108 printer.num_options, printer.options);
106 if (state != NULL) 109 if (state)
107 base::StringToInt(state, &printer_info.printer_status); 110 base::StringToInt(state, &printer_info.printer_status);
108 111
109 const char* drv_info = cupsGetOption(kCUPSPrinterMakeModelOpt, 112 const char* drv_info = cupsGetOption(kCUPSPrinterMakeModelOpt,
110 printer.num_options, 113 printer.num_options,
111 printer.options); 114 printer.options);
112 if (drv_info) 115 if (drv_info)
113 printer_info.options[kDriverInfoTagName] = *drv_info; 116 printer_info.options[kDriverInfoTagName] = *drv_info;
114 117
115 // Store printer options. 118 // Store printer options.
116 for (int opt_index = 0; opt_index < printer.num_options; ++opt_index) { 119 for (int opt_index = 0; opt_index < printer.num_options; ++opt_index) {
117 printer_info.options[printer.options[opt_index].name] = 120 printer_info.options[printer.options[opt_index].name] =
118 printer.options[opt_index].value; 121 printer.options[opt_index].value;
119 } 122 }
120 123
121 printer_list->push_back(printer_info); 124 printer_list->push_back(printer_info);
122 } 125 }
123 126
124 cupsFreeDests(num_dests, destinations); 127 cupsFreeDests(num_dests, destinations);
125 128
126 VLOG(1) << "CUPS: Enumerated printers" 129 VLOG(1) << "CUPS: Enumerated printers, server: " << print_server_url_
127 << ", server: " << print_server_url_
128 << ", # of printers: " << printer_list->size(); 130 << ", # of printers: " << printer_list->size();
129 return true; 131 return true;
130 } 132 }
131 133
132 std::string PrintBackendCUPS::GetDefaultPrinterName() { 134 std::string PrintBackendCUPS::GetDefaultPrinterName() {
133 // Not using cupsGetDefault() because it lies about the default printer. 135 // Not using cupsGetDefault() because it lies about the default printer.
134 cups_dest_t* dests; 136 cups_dest_t* dests;
135 int num_dests = GetDests(&dests); 137 int num_dests = GetDests(&dests);
136 cups_dest_t* dest = cupsGetDest(NULL, NULL, num_dests, dests); 138 cups_dest_t* dest = cupsGetDest(nullptr, nullptr, num_dests, dests);
137 std::string name = dest ? std::string(dest->name) : std::string(); 139 std::string name = dest ? std::string(dest->name) : std::string();
138 cupsFreeDests(num_dests, dests); 140 cupsFreeDests(num_dests, dests);
139 return name; 141 return name;
140 } 142 }
141 143
142 bool PrintBackendCUPS::GetPrinterSemanticCapsAndDefaults( 144 bool PrintBackendCUPS::GetPrinterSemanticCapsAndDefaults(
143 const std::string& printer_name, 145 const std::string& printer_name,
144 PrinterSemanticCapsAndDefaults* printer_info) { 146 PrinterSemanticCapsAndDefaults* printer_info) {
145 PrinterCapsAndDefaults info; 147 PrinterCapsAndDefaults info;
146 if (!GetPrinterCapsAndDefaults(printer_name, &info) ) 148 if (!GetPrinterCapsAndDefaults(printer_name, &info) )
147 return false; 149 return false;
148 150
149 return ParsePpdCapabilities( 151 return ParsePpdCapabilities(
150 printer_name, info.printer_capabilities, printer_info); 152 printer_name, info.printer_capabilities, printer_info);
151 } 153 }
152 154
153 bool PrintBackendCUPS::GetPrinterCapsAndDefaults( 155 bool PrintBackendCUPS::GetPrinterCapsAndDefaults(
154 const std::string& printer_name, 156 const std::string& printer_name,
155 PrinterCapsAndDefaults* printer_info) { 157 PrinterCapsAndDefaults* printer_info) {
156 DCHECK(printer_info); 158 DCHECK(printer_info);
157 159
158 VLOG(1) << "CUPS: Getting caps and defaults" 160 VLOG(1) << "CUPS: Getting caps and defaults, printer name: " << printer_name;
159 << ", printer name: " << printer_name;
160 161
161 base::FilePath ppd_path(GetPPD(printer_name.c_str())); 162 base::FilePath ppd_path(GetPPD(printer_name.c_str()));
162 // In some cases CUPS failed to get ppd file. 163 // In some cases CUPS failed to get ppd file.
163 if (ppd_path.empty()) { 164 if (ppd_path.empty()) {
164 LOG(ERROR) << "CUPS: Failed to get PPD, printer name: " << printer_name; 165 LOG(ERROR) << "CUPS: Failed to get PPD, printer name: " << printer_name;
165 return false; 166 return false;
166 } 167 }
167 168
168 std::string content; 169 std::string content;
169 bool res = base::ReadFileToString(ppd_path, &content); 170 bool res = base::ReadFileToString(ppd_path, &content);
170 171
171 base::DeleteFile(ppd_path, false); 172 base::DeleteFile(ppd_path, false);
172 173
173 if (res) { 174 if (res) {
174 printer_info->printer_capabilities.swap(content); 175 printer_info->printer_capabilities.swap(content);
175 printer_info->caps_mime_type = "application/pagemaker"; 176 printer_info->caps_mime_type = "application/pagemaker";
176 // In CUPS, printer defaults is a part of PPD file. Nothing to upload here. 177 // In CUPS, printer defaults is a part of PPD file. Nothing to upload here.
177 printer_info->printer_defaults.clear(); 178 printer_info->printer_defaults.clear();
178 printer_info->defaults_mime_type.clear(); 179 printer_info->defaults_mime_type.clear();
179 } 180 }
180 181
181 return res; 182 return res;
182 } 183 }
183 184
184 std::string PrintBackendCUPS::GetPrinterDriverInfo( 185 std::string PrintBackendCUPS::GetPrinterDriverInfo(
185 const std::string& printer_name) { 186 const std::string& printer_name) {
186 cups_dest_t* destinations = NULL;
187 int num_dests = GetDests(&destinations);
188 std::string result; 187 std::string result;
189 for (int printer_index = 0; printer_index < num_dests; ++printer_index) {
190 const cups_dest_t& printer = destinations[printer_index];
191 if (printer_name == printer.name) {
192 const char* info = cupsGetOption(kCUPSPrinterMakeModelOpt,
193 printer.num_options,
194 printer.options);
195 if (info)
196 result = *info;
197 }
198 }
199 188
200 cupsFreeDests(num_dests, destinations); 189 cups_dest_t* dest = GetNamedDest(printer_name);
190 if (!dest)
191 return result;
192
193 DCHECK_EQ(printer_name, dest->name);
194 const char* info =
195 cupsGetOption(kCUPSPrinterMakeModelOpt, dest->num_options, dest->options);
196 if (info)
197 result = *info;
198 cupsFreeDests(1, dest);
201 return result; 199 return result;
202 } 200 }
203 201
204 bool PrintBackendCUPS::IsValidPrinter(const std::string& printer_name) { 202 bool PrintBackendCUPS::IsValidPrinter(const std::string& printer_name) {
205 // This is not very efficient way to get specific printer info. CUPS 1.4 203 cups_dest_t* dest = GetNamedDest(printer_name);
206 // supports cupsGetNamedDest() function. However, CUPS 1.4 is not available 204 if (!dest)
207 // everywhere (for example, it supported from Mac OS 10.6 only). 205 return false;
208 PrinterList printer_list;
209 EnumeratePrinters(&printer_list);
210 206
211 PrinterList::iterator it; 207 cupsFreeDests(1, dest);
212 for (it = printer_list.begin(); it != printer_list.end(); ++it) 208 return true;
213 if (it->printer_name == printer_name)
214 return true;
215 return false;
216 } 209 }
217 210
218 scoped_refptr<PrintBackend> PrintBackend::CreateInstance( 211 scoped_refptr<PrintBackend> PrintBackend::CreateInstance(
219 const base::DictionaryValue* print_backend_settings) { 212 const base::DictionaryValue* print_backend_settings) {
220 std::string print_server_url_str, cups_blocking; 213 std::string print_server_url_str, cups_blocking;
221 int encryption = HTTP_ENCRYPT_NEVER; 214 int encryption = HTTP_ENCRYPT_NEVER;
222 if (print_backend_settings) { 215 if (print_backend_settings) {
223 print_backend_settings->GetString(kCUPSPrintServerURL, 216 print_backend_settings->GetString(kCUPSPrintServerURL,
224 &print_server_url_str); 217 &print_server_url_str);
225 218
(...skipping 23 matching lines...) Expand all
249 return cupsGetDests2(http.http(), dests); 242 return cupsGetDests2(http.http(), dests);
250 } 243 }
251 } 244 }
252 245
253 base::FilePath PrintBackendCUPS::GetPPD(const char* name) { 246 base::FilePath PrintBackendCUPS::GetPPD(const char* name) {
254 // cupsGetPPD returns a filename stored in a static buffer in CUPS. 247 // cupsGetPPD returns a filename stored in a static buffer in CUPS.
255 // Protect this code with lock. 248 // Protect this code with lock.
256 CR_DEFINE_STATIC_LOCAL(base::Lock, ppd_lock, ()); 249 CR_DEFINE_STATIC_LOCAL(base::Lock, ppd_lock, ());
257 base::AutoLock ppd_autolock(ppd_lock); 250 base::AutoLock ppd_autolock(ppd_lock);
258 base::FilePath ppd_path; 251 base::FilePath ppd_path;
259 const char* ppd_file_path = NULL; 252 const char* ppd_file_path = nullptr;
260 if (print_server_url_.is_empty()) { // Use default (local) print server. 253 if (print_server_url_.is_empty()) { // Use default (local) print server.
261 ppd_file_path = cupsGetPPD(name); 254 ppd_file_path = cupsGetPPD(name);
262 if (ppd_file_path) 255 if (ppd_file_path)
263 ppd_path = base::FilePath(ppd_file_path); 256 ppd_path = base::FilePath(ppd_file_path);
264 } else { 257 } else {
265 // cupsGetPPD2 gets stuck sometimes in an infinite time due to network 258 // cupsGetPPD2 gets stuck sometimes in an infinite time due to network
266 // configuration/issues. To prevent that, use non-blocking http connection 259 // configuration/issues. To prevent that, use non-blocking http connection
267 // here. 260 // here.
268 // Note: After looking at CUPS sources, it looks like non-blocking 261 // Note: After looking at CUPS sources, it looks like non-blocking
269 // connection will timeout after 10 seconds of no data period. And it will 262 // connection will timeout after 10 seconds of no data period. And it will
(...skipping 11 matching lines...) Expand all
281 // http->data_remaining or http->_data_remaining, unfortunately http_t 274 // http->data_remaining or http->_data_remaining, unfortunately http_t
282 // is an internal structure and fields are not exposed in CUPS headers. 275 // is an internal structure and fields are not exposed in CUPS headers.
283 // httpGetLength or httpGetLength2 returning the full content size. 276 // httpGetLength or httpGetLength2 returning the full content size.
284 // Comparing file size against that content length might be unreliable 277 // Comparing file size against that content length might be unreliable
285 // since some http reponses are encoded and content_length > file size. 278 // since some http reponses are encoded and content_length > file size.
286 // Let's just check for the obvious CUPS and http errors here. 279 // Let's just check for the obvious CUPS and http errors here.
287 ppd_path = base::FilePath(ppd_file_path); 280 ppd_path = base::FilePath(ppd_file_path);
288 ipp_status_t error_code = cupsLastError(); 281 ipp_status_t error_code = cupsLastError();
289 int http_error = httpError(http.http()); 282 int http_error = httpError(http.http());
290 if (error_code > IPP_OK_EVENTS_COMPLETE || http_error != 0) { 283 if (error_code > IPP_OK_EVENTS_COMPLETE || http_error != 0) {
291 LOG(ERROR) << "Error downloading PPD file" 284 LOG(ERROR) << "Error downloading PPD file, name: " << name
292 << ", name: " << name
293 << ", CUPS error: " << static_cast<int>(error_code) 285 << ", CUPS error: " << static_cast<int>(error_code)
294 << ", HTTP error: " << http_error; 286 << ", HTTP error: " << http_error;
295 base::DeleteFile(ppd_path, false); 287 base::DeleteFile(ppd_path, false);
296 ppd_path.clear(); 288 ppd_path.clear();
297 } 289 }
298 } 290 }
299 } 291 }
300 return ppd_path; 292 return ppd_path;
301 } 293 }
302 294
295 cups_dest_t* PrintBackendCUPS::GetNamedDest(const std::string& printer_name) {
296 // Use default (local) print server.
297 if (print_server_url_.is_empty())
298 return cupsGetNamedDest(CUPS_HTTP_DEFAULT, printer_name.c_str(), nullptr);
299
300 HttpConnectionCUPS http(print_server_url_, cups_encryption_);
301 http.SetBlocking(blocking_);
302 return cupsGetNamedDest(http.http(), printer_name.c_str(), nullptr);
303 }
304
303 } // namespace printing 305 } // namespace printing
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698