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

Side by Side Diff: chrome/service/cloud_print/printer_info_cups.cc

Issue 1933006: CL for linux proxy for cloud printing (Closed) Base URL: http://src.chromium.org/svn/trunk/src/
Patch Set: '' Created 10 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 | Annotate | Revision Log
« no previous file with comments | « chrome/chrome.gyp ('k') | chrome/service/cloud_print/printer_info_dummy.cc » ('j') | 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) 2010 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2010 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 "chrome/service/cloud_print/printer_info.h" 5 #include "chrome/service/cloud_print/printer_info.h"
6 6
7 #include <cups/cups.h>
8 #include <list>
9 #include <map>
10
11 #include "base/json/json_reader.h"
12 #include "base/file_path.h"
13 #include "base/file_util.h"
7 #include "base/logging.h" 14 #include "base/logging.h"
8 15 #include "base/lock.h"
9 // TODO(sanjeevr): Implement the Linux interfaces. 16 #include "base/message_loop.h"
17 #include "base/rand_util.h"
18 #include "base/string_util.h"
19 #include "base/task.h"
20 #include "base/values.h"
21 #include "base/utf_string_conversions.h"
22
10 namespace cloud_print { 23 namespace cloud_print {
11 24
25 static const char kCUPSPrinterInfoOpt[] = "printer-info";
26 static const char kCUPSPrinterStateOpt[] = "printer-state";
27
12 void EnumeratePrinters(PrinterList* printer_list) { 28 void EnumeratePrinters(PrinterList* printer_list) {
13 DCHECK(printer_list); 29 DCHECK(printer_list);
14 NOTIMPLEMENTED(); 30 printer_list->clear();
31
32 cups_dest_t* destinations = NULL;
33 int num_dests = cupsGetDests(&destinations);
34
35 for (int i = 0; i < num_dests; i++) {
36 PrinterBasicInfo printer_info;
37 printer_info.printer_name = destinations[i].name;
38
39 const char* info = cupsGetOption(kCUPSPrinterInfoOpt,
40 destinations[i].num_options, destinations[i].options);
41 if (info != NULL)
42 printer_info.printer_description = info;
43
44 const char* state = cupsGetOption(kCUPSPrinterStateOpt,
45 destinations[i].num_options, destinations[i].options);
46 if (state != NULL)
47 StringToInt(state, &printer_info.printer_status);
48
49 printer_list->push_back(printer_info);
50 }
51
52 cupsFreeDests(num_dests, destinations);
15 } 53 }
16 54
17 bool GetPrinterCapsAndDefaults(const std::string& printer_name, 55 bool GetPrinterCapsAndDefaults(const std::string& printer_name,
18 PrinterCapsAndDefaults* printer_info) { 56 PrinterCapsAndDefaults* printer_info) {
19 NOTIMPLEMENTED(); 57 DCHECK(printer_info);
20 return false; 58
59 static Lock ppd_lock;
60 // cupsGetPPD returns a filename stored in a static buffer in CUPS.
61 // Protect this code with lock.
62 ppd_lock.Acquire();
63 FilePath ppd_path(cupsGetPPD(printer_name.c_str()));
64 ppd_lock.Release();
65
66 std::string content;
67 bool res = file_util::ReadFileToString(ppd_path, &content);
68
69 file_util::Delete(ppd_path, false);
70
71 if (res) {
72 printer_info->printer_capabilities.swap(content);
73 printer_info->caps_mime_type = "application/pagemaker";
74 // In CUPS, printer defaults is a part of PPD file. Nothing to upload here.
75 printer_info->printer_defaults.clear();
76 printer_info->defaults_mime_type.clear();
77 }
78
79 return res;
21 } 80 }
22 81
23 bool ValidatePrintTicket(const std::string& printer_name, 82 bool ValidatePrintTicket(const std::string& printer_name,
24 const std::string& print_ticket_data) { 83 const std::string& print_ticket_data) {
25 NOTIMPLEMENTED(); 84 scoped_ptr<Value> ticket_value(base::JSONReader::Read(print_ticket_data,
26 return false; 85 false));
86 return ticket_value != NULL && ticket_value->IsType(Value::TYPE_DICTIONARY);
27 } 87 }
28 88
29 std::string GenerateProxyId() { 89 std::string GenerateProxyId() {
30 NOTIMPLEMENTED(); 90 // TODO(gene): This code should generate a unique id for proxy. ID should be
31 return std::string(); 91 // unique for this user. Rand may return the same number. We'll need to change
92 // this in the future.
93 std::string id("CP_PROXY_");
94 id += Uint64ToString(base::RandUint64());
95 return id;
96 }
97
98 // Print ticket on linux is a JSON string containing only one dictionary.
99 bool ParsePrintTicket(const std::string& print_ticket,
100 std::map<std::string, std::string>* options) {
101 DCHECK(options);
102 scoped_ptr<Value> ticket_value(base::JSONReader::Read(print_ticket, false));
103 if (ticket_value == NULL || !ticket_value->IsType(Value::TYPE_DICTIONARY))
104 return false;
105
106 options->clear();
107 DictionaryValue* ticket_dict =
108 static_cast<DictionaryValue*>(ticket_value.get());
109 DictionaryValue::key_iterator it(ticket_dict->begin_keys());
110 for (; it != ticket_dict->end_keys(); ++it) {
111 std::wstring key = *it;
112 std::string value;
113 if (ticket_dict->GetString(key, &value)) {
114 (*options)[WideToUTF8(key.c_str())] = value;
115 }
116 }
117
118 return true;
32 } 119 }
33 120
34 bool SpoolPrintJob(const std::string& print_ticket, 121 bool SpoolPrintJob(const std::string& print_ticket,
35 const FilePath& print_data_file_path, 122 const FilePath& print_data_file_path,
36 const std::string& print_data_mime_type, 123 const std::string& print_data_mime_type,
37 const std::string& printer_name, 124 const std::string& printer_name,
38 const std::string& job_title, 125 const std::string& job_title,
39 PlatformJobId* job_id_ret) { 126 PlatformJobId* job_id_ret) {
40 NOTIMPLEMENTED(); 127 DCHECK(job_id_ret);
41 return false; 128
129 // We need to store options as char* string for the duration of the
130 // cupsPrintFile call. We'll use map here to store options, since
131 // Dictionary value from JSON parser returns wchat_t.
132 std::map<std::string, std::string> options;
133 bool res = ParsePrintTicket(print_ticket, &options);
134 DCHECK(res); // If print ticket is invalid we still print using defaults.
135
136 std::vector<cups_option_t> cups_options;
137 std::map<std::string, std::string>::iterator it;
138 for (it = options.begin(); it != options.end(); ++it) {
139 cups_option_t opt;
140 opt.name = const_cast<char*>(it->first.c_str());
141 opt.value = const_cast<char*>(it->second.c_str());
142 cups_options.push_back(opt);
143 }
144
145 int job_id = cupsPrintFile(printer_name.c_str(),
146 print_data_file_path.value().c_str(),
147 job_title.c_str(),
148 cups_options.size(),
149 &(cups_options[0]));
150
151 if (job_id == 0)
152 return false;
153
154 *job_id_ret = job_id;
155 return true;
42 } 156 }
43 157
44 bool GetJobDetails(const std::string& printer_name, 158 bool GetJobDetails(const std::string& printer_name,
45 PlatformJobId job_id, 159 PlatformJobId job_id,
46 PrintJobDetails *job_details) { 160 PrintJobDetails *job_details) {
47 NOTIMPLEMENTED(); 161 DCHECK(job_details);
162 cups_job_t* jobs = NULL;
163 int num_jobs = cupsGetJobs(&jobs, printer_name.c_str(), 1, -1);
164
165 bool found = false;
166 for (int i = 0; i < num_jobs; i++) {
167 if (jobs[i].id == job_id) {
168 found = true;
169 switch (jobs[i].state) {
170 case IPP_JOB_PENDING :
171 case IPP_JOB_HELD :
172 case IPP_JOB_PROCESSING :
173 job_details->status = PRINT_JOB_STATUS_IN_PROGRESS;
174 break;
175 case IPP_JOB_STOPPED :
176 case IPP_JOB_CANCELLED :
177 case IPP_JOB_ABORTED :
178 job_details->status = PRINT_JOB_STATUS_ERROR;
179 break;
180 case IPP_JOB_COMPLETED :
181 job_details->status = PRINT_JOB_STATUS_COMPLETED;
182 break;
183 default:
184 job_details->status = PRINT_JOB_STATUS_INVALID;
185 }
186 job_details->platform_status_flags = jobs[i].state;
187
188 // We don't have any details on the number of processed pages here.
189 break;
190 }
191 }
192
193 cupsFreeJobs(num_jobs, jobs);
194 return found;
195 }
196
197 bool GetPrinterInfo(const std::string& printer_name, PrinterBasicInfo* info) {
198 DCHECK(info);
199
200 // This is not very efficient way to get specific printer info. CUPS 1.4
201 // supports cupsGetNamedDest() function. However, CUPS 1.4 is not available
202 // everywhere (for example, it supported from Mac OS 10.6 only).
203 PrinterList printer_list;
204 EnumeratePrinters(&printer_list);
205
206 PrinterList::iterator it;
207 for (it = printer_list.begin(); it != printer_list.end(); ++it) {
208 if (it->printer_name == printer_name) {
209 *info = *it;
210 return true;
211 }
212 }
48 return false; 213 return false;
49 } 214 }
50 215
51 bool IsValidPrinter(const std::string& printer_name) { 216 bool IsValidPrinter(const std::string& printer_name) {
52 NOTIMPLEMENTED(); 217 PrinterBasicInfo info;
53 return false; 218 return GetPrinterInfo(printer_name, &info);
54 } 219 }
220
221 class PrinterChangeNotifier::NotificationState
222 : public base::RefCountedThreadSafe<
223 PrinterChangeNotifier::NotificationState> {
224 public:
225 NotificationState() : delegate_(NULL) {}
226 bool Start(const std::string& printer_name,
227 PrinterChangeNotifier::Delegate* delegate) {
228 if (delegate_ != NULL)
229 Stop();
230
231 printer_name_ = printer_name;
232 delegate_ = delegate;
233
234 MessageLoop::current()->PostDelayedTask(FROM_HERE,
235 NewRunnableMethod(this,
236 &PrinterChangeNotifier::NotificationState::Update), 5000);
237 return true;
238 }
239 bool Stop() {
240 delegate_ = NULL;
241 return true;
242 }
243 void Update() {
244 if (delegate_ == NULL)
245 return; // Orphan call. We have been stopped already.
246 // For CUPS proxy, we are going to fire OnJobChanged notification
247 // periodically. Higher level will check if there are any outstanding
248 // jobs for this printer and check their status. If printer has no
249 // outstanding jobs, OnJobChanged() will do nothing.
250 delegate_->OnJobChanged();
251 MessageLoop::current()->PostDelayedTask(FROM_HERE,
252 NewRunnableMethod(this,
253 &PrinterChangeNotifier::NotificationState::Update),
254 kNotificationTimeout);
255 }
256 std::string printer_name() const {
257 return printer_name_;
258 }
259 private:
260 friend class base::RefCountedThreadSafe<
261 PrinterChangeNotifier::NotificationState>;
262 ~NotificationState() {
263 Stop();
264 }
265 static const int kNotificationTimeout = 5000; // in ms
266 std::string printer_name_; // The printer being watched
267 PrinterChangeNotifier::Delegate* delegate_; // Delegate to notify
268 };
55 269
56 PrinterChangeNotifier::PrinterChangeNotifier() : state_(NULL) { 270 PrinterChangeNotifier::PrinterChangeNotifier() : state_(NULL) {
57 } 271 }
58 272
59 PrinterChangeNotifier::~PrinterChangeNotifier() { 273 PrinterChangeNotifier::~PrinterChangeNotifier() {
60 StopWatching(); 274 StopWatching();
61 } 275 }
62 276
63 bool PrinterChangeNotifier::StartWatching(const std::string& printer_name, 277 bool PrinterChangeNotifier::StartWatching(const std::string& printer_name,
64 Delegate* delegate) { 278 Delegate* delegate) {
65 NOTIMPLEMENTED(); 279 if (state_) {
66 return false; 280 NOTREACHED();
281 return false;
282 }
283 state_ = new NotificationState;
284 state_->AddRef();
285 if (!state_->Start(printer_name, delegate)) {
286 StopWatching();
287 return false;
288 }
289 return true;
67 } 290 }
68 291
69 bool PrinterChangeNotifier::StopWatching() { 292 bool PrinterChangeNotifier::StopWatching() {
70 NOTIMPLEMENTED(); 293 if (!state_) {
71 return false; 294 return false;
295 }
296 state_->Stop();
297 state_->Release();
298 state_ = NULL;
299 return true;
72 } 300 }
73 301
74 bool PrinterChangeNotifier::GetCurrentPrinterInfo( 302 bool PrinterChangeNotifier::GetCurrentPrinterInfo(
75 PrinterBasicInfo* printer_info) { 303 PrinterBasicInfo* printer_info) {
76 NOTIMPLEMENTED(); 304 if (!state_) {
77 return false; 305 return false;
306 }
307 DCHECK(printer_info);
308 return GetPrinterInfo(state_->printer_name(), printer_info);
78 } 309 }
79 } // namespace cloud_print 310 } // namespace cloud_print
80 311
OLDNEW
« no previous file with comments | « chrome/chrome.gyp ('k') | chrome/service/cloud_print/printer_info_dummy.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698