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

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

Issue 2105463002: Create a new print backend for the updated CUPS APIs (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: update gyp Created 4 years, 5 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
OLDNEW
(Empty)
1 // Copyright 2016 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.
4
5 #include "printing/backend/cups_printer.h"
6
7 #include <cups/cups.h>
8
9 #include <string>
10 #include <utility>
11
12 #include "base/files/file.h"
13 #include "base/files/file_path.h"
14 #include "base/files/file_util.h"
15 #include "base/strings/string_number_conversions.h"
16 #include "printing/backend/cups_connection.h"
17 #include "printing/backend/print_backend.h"
18
19 namespace {
20
21 const char kDriverInfoTagName[] = "system_driverinfo";
22
23 const char kCUPSPrinterInfoOpt[] = "printer-info";
24 const char kCUPSPrinterStateOpt[] = "printer-state";
25 const char kCUPSPrinterMakeModelOpt[] = "printer-make-and-model";
26
27 } // namespace
28
29 namespace printing {
30
31 CupsPrinter::CupsPrinter(http_t* http,
32 std::unique_ptr<cups_dest_t, DestinationDeleter> dest,
33 std::unique_ptr<cups_dinfo_t, DestInfoDeleter> info)
34 : cups_http_(http),
35 destination_(std::move(dest)),
36 dest_info_(std::move(info)) {}
37
38 CupsPrinter::CupsPrinter(CupsPrinter&& printer)
39 : cups_http_(printer.cups_http_),
40 destination_(std::move(printer.destination_)),
41 dest_info_(std::move(printer.dest_info_)) {}
42
43 CupsPrinter::~CupsPrinter() {}
44
45 bool CupsPrinter::is_default() const {
46 return destination_->is_default;
47 }
48
49 ipp_attribute_t* CupsPrinter::GetSupportedOptionValues(
50 base::StringPiece option_name) const {
51 if (!InitializeDestInfo())
52 return nullptr;
53
54 return cupsFindDestSupported(cups_http_, destination_.get(), dest_info_.get(),
55 option_name.as_string().c_str());
56 }
57
58 std::vector<base::StringPiece> CupsPrinter::GetSupportedOptionValueStrings(
59 base::StringPiece option_name) const {
60 ipp_attribute_t* attr = GetSupportedOptionValues(option_name);
61 std::vector<base::StringPiece> values;
62 if (!attr) {
63 return values;
64 }
65
66 base::StringPiece value;
67 int num_options = ippGetCount(attr);
68 for (int i = 0; i < num_options; ++i) {
69 value.set(ippGetString(attr, i, nullptr));
70 values.push_back(value);
71 }
72
73 return values;
74 }
75
76 ipp_attribute_t* CupsPrinter::GetDefaultOptionValue(
77 base::StringPiece option_name) const {
78 if (!InitializeDestInfo())
79 return nullptr;
80
81 return cupsFindDestDefault(cups_http_, destination_.get(), dest_info_.get(),
82 option_name.as_string().c_str());
83 }
84
85 bool CupsPrinter::CheckOptionSupported(base::StringPiece name,
86 base::StringPiece value) const {
87 int supported = cupsCheckDestSupported(
88 cups_http_, destination_.get(), dest_info_.get(),
89 name.as_string().c_str(), value.as_string().c_str());
90 return supported == 1;
91 }
92
93 bool CupsPrinter::ToPrinterInfo(PrinterBasicInfo* printer_info) const {
94 const cups_dest_t* printer = destination_.get();
95
96 printer_info->printer_name = printer->name;
97 printer_info->is_default = printer->is_default;
98
99 const char* info = cupsGetOption(kCUPSPrinterInfoOpt, printer->num_options,
100 printer->options);
101 if (info)
102 printer_info->printer_description = info;
103
104 const char* state = cupsGetOption(kCUPSPrinterStateOpt, printer->num_options,
105 printer->options);
106 if (state)
107 base::StringToInt(state, &printer_info->printer_status);
108
109 const char* drv_info = cupsGetOption(kCUPSPrinterMakeModelOpt,
110 printer->num_options, printer->options);
111 if (drv_info)
112 printer_info->options[kDriverInfoTagName] = *drv_info;
113
114 // Store printer options.
115 for (int opt_index = 0; opt_index < printer->num_options; ++opt_index) {
116 printer_info->options[printer->options[opt_index].name] =
117 printer->options[opt_index].value;
118 }
119
120 return true;
121 }
122
123 base::FilePath CupsPrinter::GetPPD() const {
124 base::StringPiece printer_name = destination_->name;
125 const char* ppd_path =
126 cupsGetPPD2(cups_http_, printer_name.as_string().c_str());
127 base::FilePath path(ppd_path);
128
129 if (ppd_path) {
130 // There is no reliable way right now to detect full and complete PPD
131 // get downloaded. If we reach http timeout, it may simply return
132 // downloaded part as a full response. It might be good enough to check
133 // http->data_remaining or http->_data_remaining, unfortunately http_t
134 // is an internal structure and fields are not exposed in CUPS headers.
135 // httpGetLength or httpGetLength2 returning the full content size.
136 // Comparing file size against that content length might be unreliable
137 // since some http reponses are encoded and content_length > file size.
138 // Let's just check for the obvious CUPS and http errors here.
139 ipp_status_t error_code = cupsLastError();
140 int http_error = httpError(cups_http_);
141 if (error_code > IPP_OK_EVENTS_COMPLETE || http_error != 0) {
142 LOG(ERROR) << "Error downloading PPD file, name: " << destination_->name
143 << ", CUPS error: " << static_cast<int>(error_code)
144 << ", HTTP error: " << http_error;
145 base::DeleteFile(path, false);
146 path.clear();
147 }
148 }
149
150 return path;
151 }
152
153 const std::string CupsPrinter::GetName() const {
154 return std::string(destination_->name);
155 }
156
157 const std::string CupsPrinter::GetMakeAndModel() const {
158 const char* make_and_model =
159 cupsGetOption(kCUPSPrinterMakeModelOpt, destination_->num_options,
160 destination_->options);
161
162 return make_and_model ? std::string(make_and_model) : std::string();
163 }
164
165 bool CupsPrinter::IsAvailable() const {
166 return cups_http_ && destination_ && InitializeDestInfo();
167 }
168
169 bool CupsPrinter::InitializeDestInfo() const {
170 if (dest_info_)
171 return true;
172
173 cups_dinfo_t* info = cupsCopyDestInfo(cups_http_, destination_.get());
Lei Zhang 2016/07/21 00:46:20 Same pattern, dest_info_.reset(cupsFoo()); return
skau 2016/07/21 20:07:32 Done.
174
175 if (!info)
176 return false;
177
178 dest_info_.reset(info);
179 return true;
180 }
181
182 ipp_status_t CupsPrinter::CreateJob(int* job_id,
183 base::StringPiece title,
184 const std::vector<cups_option_t>& options) {
185 cups_option_t* data = const_cast<cups_option_t*>(
186 options.data()); // createDestJob will not modify the data
187 ipp_status_t create_status = cupsCreateDestJob(
188 cups_http_, destination_.get(), dest_info_.get(), job_id,
189 title.as_string().c_str(), options.size(), data);
190
191 return create_status;
192 }
193
194 bool CupsPrinter::StartDocument(int job_id,
195 base::StringPiece document_name,
196 bool last_document,
197 const std::vector<cups_option_t>& options) {
198 cups_option_t* data = const_cast<cups_option_t*>(
199 options.data()); // createStartDestDocument will not modify the data
200 http_status_t start_doc_status = cupsStartDestDocument(
201 cups_http_, destination_.get(), dest_info_.get(), job_id,
202 document_name.as_string().c_str(), CUPS_FORMAT_PDF, options.size(), data,
203 last_document ? 0 : 1);
204
205 return start_doc_status == HTTP_CONTINUE;
206 }
207
208 bool CupsPrinter::StreamData(const std::vector<char>& buffer) {
209 http_status_t status =
210 cupsWriteRequestData(cups_http_, buffer.data(), buffer.size());
211 return status == HTTP_STATUS_CONTINUE;
212 }
213
214 bool CupsPrinter::FinishDocument() {
215 DCHECK(cups_http_);
Lei Zhang 2016/07/21 00:46:20 Given cups_http_ can be "http_t* const", if you wa
skau 2016/07/21 20:07:33 Done.
216 DCHECK(destination_);
Lei Zhang 2016/07/21 00:46:20 BTW, we use |destination_| and |dest_info_| all ov
skau 2016/07/21 20:07:32 The code was moved from where there were different
217 DCHECK(dest_info_);
218
219 ipp_status_t status =
220 cupsFinishDestDocument(cups_http_, destination_.get(), dest_info_.get());
221
222 return status == IPP_STATUS_OK;
223 }
224
225 ipp_status_t CupsPrinter::CloseJob(int job_id) {
226 return cupsCloseDestJob(cups_http_, destination_.get(), dest_info_.get(),
227 job_id);
228 }
229
230 } // namespace printing
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698