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

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: Fix comment. 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(base::WeakPtr<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_(std::move(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_.get(), destination_.get(),
55 dest_info_.get(),
56 option_name.as_string().c_str());
57 }
58
59 std::vector<base::StringPiece> CupsPrinter::GetSupportedOptionValueStrings(
60 base::StringPiece option_name) const {
61 ipp_attribute_t* attr = GetSupportedOptionValues(option_name);
62 std::vector<base::StringPiece> values;
63 if (!attr) {
64 return values;
65 }
66
67 base::StringPiece value;
68 int num_options = ippGetCount(attr);
69 for (int i = 0; i < num_options; ++i) {
70 value.set(ippGetString(attr, i, nullptr));
71 values.push_back(value);
72 }
73
74 return values;
75 }
76
77 ipp_attribute_t* CupsPrinter::GetDefaultOptionValue(
78 base::StringPiece option_name) const {
79 if (!InitializeDestInfo())
80 return nullptr;
81
82 return cupsFindDestDefault(cups_http_.get(), destination_.get(),
83 dest_info_.get(), option_name.as_string().c_str());
84 }
85
86 bool CupsPrinter::CheckOptionSupported(base::StringPiece name,
87 base::StringPiece value) const {
88 int supported = cupsCheckDestSupported(
89 cups_http_.get(), destination_.get(), dest_info_.get(),
90 name.as_string().c_str(), value.as_string().c_str());
91 return supported == 1;
92 }
93
94 bool CupsPrinter::ToPrinterInfo(PrinterBasicInfo* printer_info) const {
95 const cups_dest_t* printer = destination_.get();
96
97 printer_info->printer_name = printer->name;
98 printer_info->is_default = printer->is_default;
99
100 const char* info = cupsGetOption(kCUPSPrinterInfoOpt, printer->num_options,
101 printer->options);
102 if (info)
103 printer_info->printer_description = info;
104
105 const char* state = cupsGetOption(kCUPSPrinterStateOpt, printer->num_options,
106 printer->options);
107 if (state)
108 base::StringToInt(state, &printer_info->printer_status);
109
110 const char* drv_info = cupsGetOption(kCUPSPrinterMakeModelOpt,
111 printer->num_options, printer->options);
112 if (drv_info)
113 printer_info->options[kDriverInfoTagName] = *drv_info;
114
115 // Store printer options.
116 for (int opt_index = 0; opt_index < printer->num_options; ++opt_index) {
117 printer_info->options[printer->options[opt_index].name] =
118 printer->options[opt_index].value;
119 }
120
121 return true;
122 }
123
124 base::FilePath CupsPrinter::GetPPD() const {
125 base::StringPiece printer_name = destination_->name;
126 const char* ppd_path =
127 cupsGetPPD2(cups_http_.get(), printer_name.as_string().c_str());
128 base::FilePath path(ppd_path);
129
130 if (ppd_path) {
131 // There is no reliable way right now to detect full and complete PPD
132 // get downloaded. If we reach http timeout, it may simply return
133 // downloaded part as a full response. It might be good enough to check
134 // http->data_remaining or http->_data_remaining, unfortunately http_t
135 // is an internal structure and fields are not exposed in CUPS headers.
136 // httpGetLength or httpGetLength2 returning the full content size.
137 // Comparing file size against that content length might be unreliable
138 // since some http reponses are encoded and content_length > file size.
139 // Let's just check for the obvious CUPS and http errors here.
140 ipp_status_t error_code = cupsLastError();
141 int http_error = httpError(cups_http_.get());
142 if (error_code > IPP_OK_EVENTS_COMPLETE || http_error != 0) {
143 LOG(ERROR) << "Error downloading PPD file, name: " << destination_->name
144 << ", CUPS error: " << static_cast<int>(error_code)
145 << ", HTTP error: " << http_error;
146 base::DeleteFile(path, false);
147 path.clear();
148 }
149 }
150
151 return path;
152 }
153
154 const std::string CupsPrinter::GetName() const {
155 return std::string(destination_->name);
156 }
157
158 const std::string CupsPrinter::GetMakeAndModel() const {
159 const char* make_and_model =
160 cupsGetOption(kCUPSPrinterMakeModelOpt, destination_->num_options,
161 destination_->options);
162
163 return make_and_model ? std::string(make_and_model) : std::string();
164 }
165
166 bool CupsPrinter::IsAvailable() const {
167 return cups_http_ && destination_ && InitializeDestInfo();
168 }
169
170 bool CupsPrinter::InitializeDestInfo() const {
171 if (dest_info_)
172 return true;
173
174 cups_dinfo_t* info = cupsCopyDestInfo(cups_http_.get(), destination_.get());
175
176 if (!info)
177 return false;
178
179 dest_info_.reset(info);
180 return true;
181 }
182
183 ipp_status_t CupsPrinter::CreateJob(int* job_id,
184 base::StringPiece title,
185 const std::vector<cups_option_t>& options) {
186 cups_option_t* data = const_cast<cups_option_t*>(
187 options.data()); // createDestJob will not modify the data
188 ipp_status_t create_status = cupsCreateDestJob(
189 cups_http_.get(), destination_.get(), dest_info_.get(), job_id,
190 title.as_string().c_str(), options.size(), data);
191
192 return create_status;
193 }
194
195 bool CupsPrinter::StartDocument(int job_id,
196 base::StringPiece document_name,
197 bool last_document,
198 const std::vector<cups_option_t>& options) {
199 cups_option_t* data = const_cast<cups_option_t*>(
200 options.data()); // createStartDestDocument will not modify the data
201 http_status_t start_doc_status = cupsStartDestDocument(
202 cups_http_.get(), destination_.get(), dest_info_.get(), job_id,
203 document_name.as_string().c_str(), CUPS_FORMAT_PDF, options.size(), data,
204 last_document ? 0 : 1);
205
206 return start_doc_status == HTTP_CONTINUE;
207 }
208
209 bool CupsPrinter::StreamData(const std::vector<char>& buffer) {
210 http_status_t status =
211 cupsWriteRequestData(cups_http_.get(), buffer.data(), buffer.size());
212 return status == HTTP_STATUS_CONTINUE;
213 }
214
215 bool CupsPrinter::FinishDocument() {
216 DCHECK(cups_http_);
217 DCHECK(destination_);
218 DCHECK(dest_info_);
219
220 ipp_status_t status = cupsFinishDestDocument(
221 cups_http_.get(), destination_.get(), dest_info_.get());
222
223 return status == IPP_STATUS_OK;
224 }
225
226 ipp_status_t CupsPrinter::CloseJob(int job_id) {
227 return cupsCloseDestJob(cups_http_.get(), destination_.get(),
228 dest_info_.get(), job_id);
229 }
230
231 } // namespace printing
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698