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

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

Issue 4233004: Make CUPS cloud print proxy to support multiple print servers.... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 10 years, 1 month 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
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/print_system.h" 5 #include "chrome/service/cloud_print/print_system.h"
6 6
7 #include <cups/cups.h> 7 #include <cups/cups.h>
8 #include <dlfcn.h> 8 #include <dlfcn.h>
9 #include <errno.h> 9 #include <errno.h>
10 #include <pthread.h> 10 #include <pthread.h>
11 11
12 #include <algorithm>
12 #include <list> 13 #include <list>
13 #include <map> 14 #include <map>
14 15
15 #include "base/file_path.h" 16 #include "base/file_path.h"
16 #include "base/json/json_reader.h" 17 #include "base/json/json_reader.h"
17 #include "base/lock.h" 18 #include "base/lock.h"
18 #include "base/logging.h" 19 #include "base/logging.h"
20 #include "base/md5.h"
19 #include "base/message_loop.h" 21 #include "base/message_loop.h"
20 #include "base/rand_util.h" 22 #include "base/rand_util.h"
21 #include "base/string_number_conversions.h" 23 #include "base/string_number_conversions.h"
22 #include "base/string_util.h" 24 #include "base/string_util.h"
23 #include "base/task.h" 25 #include "base/task.h"
24 #include "base/values.h" 26 #include "base/values.h"
25 #include "base/utf_string_conversions.h" 27 #include "base/utf_string_conversions.h"
26 #include "googleurl/src/gurl.h" 28 #include "googleurl/src/gurl.h"
27 #include "printing/backend/cups_helper.h" 29 #include "printing/backend/cups_helper.h"
28 #include "printing/backend/print_backend.h" 30 #include "printing/backend/print_backend.h"
29 31
30 namespace cloud_print { 32 namespace {
31
32 static const char kCUPSPrinterInfoOpt[] = "printer-info"; 33 static const char kCUPSPrinterInfoOpt[] = "printer-info";
33 static const char kCUPSPrinterStateOpt[] = "printer-state"; 34 static const char kCUPSPrinterStateOpt[] = "printer-state";
34 static const char kCUPSPrintServerURL[] = "print_server_url"; 35 static const char kCUPSPrintServerURLs[] = "print_server_urls";
36 static const char kCUPSUpdateTimeoutMs[] = "update_timeout_ms";
37 static const char kCUPSPrintBackendServerURL[] = "print_server_url";
35 38
36 // Default port for IPP print servers. 39 // Default port for IPP print servers.
37 static const int kDefaultIPPServerPort = 631; 40 static const int kDefaultIPPServerPort = 631;
38 41
42 // Time interval to check for printer's updates.
43 const int kCheckForPrinterUpdatesMs = 6*60*60*1000;
44
45 // Job update timeput
46 const int kJobUpdateTimeoutMs = 5000;
47
48 struct PrintServerInfoCUPS {
49 GURL url;
50 scoped_refptr<printing::PrintBackend> backend;
51 printing::PrinterList printers;
52 // CapsMap cache PPD until the next update and give a fast access to it by
53 // printer name. PPD request is relatively expensive and this should minimize
54 // the number of requests.
55 typedef std::map<std::string, printing::PrinterCapsAndDefaults> CapsMap;
56 CapsMap caps_cache;
57 };
58
59 } // namespace
60
61 namespace cloud_print {
62
39 class PrintSystemCUPS : public PrintSystem { 63 class PrintSystemCUPS : public PrintSystem {
40 public: 64 public:
41 PrintSystemCUPS(const GURL& print_server_url, 65 explicit PrintSystemCUPS(const DictionaryValue* print_system_settings);
42 const DictionaryValue* print_system_settings);
43 66
44 // PrintSystem implementation. 67 // PrintSystem implementation.
45 virtual printing::PrintBackend* GetPrintBackend(); 68 virtual void Init();
69
70 virtual void EnumeratePrinters(printing::PrinterList* printer_list);
71
72 virtual bool GetPrinterCapsAndDefaults(
73 const std::string& printer_name,
74 printing::PrinterCapsAndDefaults* printer_info);
75
76 virtual bool IsValidPrinter(const std::string& printer_name);
46 77
47 virtual bool ValidatePrintTicket(const std::string& printer_name, 78 virtual bool ValidatePrintTicket(const std::string& printer_name,
48 const std::string& print_ticket_data); 79 const std::string& print_ticket_data);
49 80
50 virtual bool GetJobDetails(const std::string& printer_name, 81 virtual bool GetJobDetails(const std::string& printer_name,
51 PlatformJobId job_id, 82 PlatformJobId job_id,
52 PrintJobDetails *job_details); 83 PrintJobDetails *job_details);
53 84
54 // TODO(gene): Add implementation for CUPS print server watcher.
55 class PrintServerWatcherCUPS
56 : public PrintSystem::PrintServerWatcher {
57 public:
58 PrintServerWatcherCUPS() {}
59
60 // PrintSystem::PrintServerWatcher interface
61 virtual bool StartWatching(
62 PrintSystem::PrintServerWatcher::Delegate* delegate) {
63 NOTIMPLEMENTED();
64 return true;
65 }
66 virtual bool StopWatching() {
67 NOTIMPLEMENTED();
68 return true;
69 }
70 };
71
72 class PrinterWatcherCUPS
73 : public PrintSystem::PrinterWatcher {
74 public:
75 explicit PrinterWatcherCUPS(PrintSystemCUPS* print_system,
76 const std::string& printer_name)
77 : printer_name_(printer_name),
78 delegate_(NULL),
79 print_system_(print_system) {
80 }
81
82 // PrintSystem::PrinterWatcher interface
83 virtual bool StartWatching(
84 PrintSystem::PrinterWatcher::Delegate* delegate) {
85 if (delegate_ != NULL)
86 StopWatching();
87 delegate_ = delegate;
88 MessageLoop::current()->PostDelayedTask(FROM_HERE,
89 NewRunnableMethod(this,
90 &PrintSystemCUPS::PrinterWatcherCUPS::Update), 5000);
91 return true;
92 }
93 virtual bool StopWatching() {
94 delegate_ = NULL;
95 return true;
96 }
97 bool GetCurrentPrinterInfo(printing::PrinterBasicInfo* printer_info) {
98 DCHECK(printer_info);
99 return print_system_->GetPrinterInfo(printer_name_, printer_info);
100 }
101
102 void Update() {
103 if (delegate_ == NULL)
104 return; // Orphan call. We have been stopped already.
105 // For CUPS proxy, we are going to fire OnJobChanged notification
106 // periodically. Higher level will check if there are any outstanding
107 // jobs for this printer and check their status. If printer has no
108 // outstanding jobs, OnJobChanged() will do nothing.
109 delegate_->OnJobChanged();
110 MessageLoop::current()->PostDelayedTask(FROM_HERE,
111 NewRunnableMethod(this,
112 &PrintSystemCUPS::PrinterWatcherCUPS::Update),
113 kNotificationTimeout);
114 }
115 private:
116 static const int kNotificationTimeout = 5000; // in ms
117 std::string printer_name_;
118 PrintSystem::PrinterWatcher::Delegate* delegate_;
119 scoped_refptr<PrintSystemCUPS> print_system_;
120 DISALLOW_COPY_AND_ASSIGN(PrinterWatcherCUPS);
121 };
122
123 class JobSpoolerCUPS : public PrintSystem::JobSpooler {
124 public:
125 explicit JobSpoolerCUPS(PrintSystemCUPS* print_system)
126 : print_system_(print_system) {
127 DCHECK(print_system_.get());
128 }
129 // PrintSystem::JobSpooler implementation.
130 virtual bool Spool(const std::string& print_ticket,
131 const FilePath& print_data_file_path,
132 const std::string& print_data_mime_type,
133 const std::string& printer_name,
134 const std::string& job_title,
135 JobSpooler::Delegate* delegate) {
136 DCHECK(delegate);
137 int job_id = print_system_->SpoolPrintJob(
138 print_ticket, print_data_file_path, print_data_mime_type,
139 printer_name, job_title);
140 MessageLoop::current()->PostTask(FROM_HERE,
141 NewRunnableFunction(
142 &JobSpoolerCUPS::NotifyDelegate,
143 delegate,
144 job_id));
145 return true;
146 }
147
148 static void NotifyDelegate(JobSpooler::Delegate* delegate, int job_id) {
149 if (job_id)
150 delegate->OnJobSpoolSucceeded(job_id);
151 else
152 delegate->OnJobSpoolFailed();
153 }
154 private:
155 scoped_refptr<PrintSystemCUPS> print_system_;
156 DISALLOW_COPY_AND_ASSIGN(JobSpoolerCUPS);
157 };
158
159 virtual PrintSystem::PrintServerWatcher* CreatePrintServerWatcher(); 85 virtual PrintSystem::PrintServerWatcher* CreatePrintServerWatcher();
160 virtual PrintSystem::PrinterWatcher* CreatePrinterWatcher( 86 virtual PrintSystem::PrinterWatcher* CreatePrinterWatcher(
161 const std::string& printer_name); 87 const std::string& printer_name);
162 virtual PrintSystem::JobSpooler* CreateJobSpooler(); 88 virtual PrintSystem::JobSpooler* CreateJobSpooler();
163 89
164 // Helper functions. 90 // Helper functions.
165 PlatformJobId SpoolPrintJob(const std::string& print_ticket, 91 PlatformJobId SpoolPrintJob(const std::string& print_ticket,
166 const FilePath& print_data_file_path, 92 const FilePath& print_data_file_path,
167 const std::string& print_data_mime_type, 93 const std::string& print_data_mime_type,
168 const std::string& printer_name, 94 const std::string& printer_name,
169 const std::string& job_title); 95 const std::string& job_title);
170 bool GetPrinterInfo(const std::string& printer_name, 96 bool GetPrinterInfo(const std::string& printer_name,
171 printing::PrinterBasicInfo* info); 97 printing::PrinterBasicInfo* info);
172 bool ParsePrintTicket(const std::string& print_ticket, 98 bool ParsePrintTicket(const std::string& print_ticket,
173 std::map<std::string, std::string>* options); 99 std::map<std::string, std::string>* options);
174 100
101 int GetUpdateTimeoutMs() const {
102 return update_timeout_;
103 }
104
175 private: 105 private:
176 // Following functions are wrappers around corresponding CUPS functions. 106 // Following functions are wrappers around corresponding CUPS functions.
177 // <functions>2() are called when print server is specified, and plain 107 // <functions>2() are called when print server is specified, and plain
178 // version in another case. There is an issue specifing CUPS_HTTP_DEFAULT 108 // version in another case. There is an issue specifing CUPS_HTTP_DEFAULT
179 // in the <functions>2(), it does not work in CUPS prior to 1.4. 109 // in the <functions>2(), it does not work in CUPS prior to 1.4.
180 int GetJobs(cups_job_t** jobs, const char* name, 110 int GetJobs(cups_job_t** jobs, const GURL& url, const char* name,
181 int myjobs, int whichjobs); 111 int myjobs, int whichjobs);
182 int PrintFile(const char* name, const char* filename, const char* title, 112 int PrintFile(const GURL& url, const char* name, const char* filename,
183 int num_options, cups_option_t* options); 113 const char* title, int num_options, cups_option_t* options);
184 114
185 void Init(const DictionaryValue* print_system_settings); 115 void InitPrintBackends(const DictionaryValue* print_system_settings);
186 116 void AddPrintServer(const std::string& url);
187 GURL print_server_url_; 117
188 scoped_refptr<printing::PrintBackend> print_backend_; 118 void UpdatePrinters();
119
120 // PrintServerList contains information about all print servers and backends
121 // this proxy is connected to.
122 typedef std::list<PrintServerInfoCUPS> PrintServerList;
123 // PrintersMap provides fast check for printer existence and access to
124 // printer information by printer name. (optimization).
125 typedef std::map<std::string, PrintServerInfoCUPS*> PrintersMap;
126 PrintServerList print_servers_;
127 PrintersMap printer_map_;
128
129 int update_timeout_;
130 bool initialized_;
189 }; 131 };
190 132
191 PrintSystemCUPS::PrintSystemCUPS(const GURL& print_server_url, 133 class PrintServerWatcherCUPS
192 const DictionaryValue* print_system_settings) 134 : public PrintSystem::PrintServerWatcher {
193 : print_server_url_(print_server_url) { 135 public:
194 Init(print_system_settings); 136 explicit PrintServerWatcherCUPS(PrintSystemCUPS* print_system)
195 } 137 : print_system_(print_system) {
196 138 }
197 void PrintSystemCUPS::Init(const DictionaryValue* print_system_settings) { 139 ~PrintServerWatcherCUPS() {
198 print_backend_ = 140 StopWatching();
199 printing::PrintBackend::CreateInstance(print_system_settings); 141 }
200 } 142
201 143 // PrintSystem::PrintServerWatcher interface
202 printing::PrintBackend* PrintSystemCUPS::GetPrintBackend() { 144 virtual bool StartWatching(
203 return print_backend_; 145 PrintSystem::PrintServerWatcher::Delegate* delegate) {
146 delegate_ = delegate;
147 printers_hash_ = GetPrintersHash();
148 MessageLoop::current()->PostDelayedTask(FROM_HERE,
149 NewRunnableMethod(this, &PrintServerWatcherCUPS::CheckForUpdates),
150 print_system_->GetUpdateTimeoutMs());
151 return true;
152 }
153 virtual bool StopWatching() {
154 delegate_ = NULL;
155 return true;
156 }
157
158 void CheckForUpdates() {
159 if (delegate_ == NULL)
160 return; // Orphan call. We have been stopped already.
161 VLOG(1) << "CP_CUPS: Checking for new printers";
162 std::string new_hash = GetPrintersHash();
163 if (printers_hash_ != new_hash) {
164 printers_hash_ = new_hash;
165 delegate_->OnPrinterAdded();
166 }
167 MessageLoop::current()->PostDelayedTask(FROM_HERE,
168 NewRunnableMethod(this, &PrintServerWatcherCUPS::CheckForUpdates),
169 print_system_->GetUpdateTimeoutMs());
170 }
171 private:
172 std::string GetPrintersHash() {
173 printing::PrinterList printer_list;
174 print_system_->EnumeratePrinters(&printer_list);
175
176 // Sort printer names.
177 std::vector<std::string> printers;
178 printing::PrinterList::iterator it;
179 for (it = printer_list.begin(); it != printer_list.end(); ++it)
180 printers.push_back(it->printer_name);
181 std::sort(printers.begin(), printers.end());
182
183 std::string to_hash;
184 for (size_t i = 0; i < printers.size(); i++)
185 to_hash += printers[i];
186
187 return MD5String(to_hash);
188 }
189
190 scoped_refptr<PrintSystemCUPS> print_system_;
191 PrintSystem::PrintServerWatcher::Delegate* delegate_;
192 std::string printers_hash_;
193 DISALLOW_COPY_AND_ASSIGN(PrintServerWatcherCUPS);
194 };
195
196 class PrinterWatcherCUPS
197 : public PrintSystem::PrinterWatcher {
198 public:
199 explicit PrinterWatcherCUPS(PrintSystemCUPS* print_system,
200 const std::string& printer_name)
201 : printer_name_(printer_name),
202 delegate_(NULL),
203 print_system_(print_system) {
204 }
205 ~PrinterWatcherCUPS() {
206 StopWatching();
207 }
208
209 // PrintSystem::PrinterWatcher interface
210 virtual bool StartWatching(
211 PrintSystem::PrinterWatcher::Delegate* delegate) {
212 if (delegate_ != NULL)
213 StopWatching();
214 delegate_ = delegate;
215 settings_hash_ = GetSettingsHash();
216 // Schedule next job status update.
217 MessageLoop::current()->PostDelayedTask(FROM_HERE,
218 NewRunnableMethod(this, &PrinterWatcherCUPS::JobStatusUpdate),
219 kJobUpdateTimeoutMs);
220 // Schedule next printer check.
221 // TODO(gene): Randomize time for the next printer update.
222 MessageLoop::current()->PostDelayedTask(FROM_HERE,
223 NewRunnableMethod(this, &PrinterWatcherCUPS::PrinterUpdate),
224 print_system_->GetUpdateTimeoutMs());
225 return true;
226 }
227 virtual bool StopWatching() {
228 delegate_ = NULL;
229 return true;
230 }
231 bool GetCurrentPrinterInfo(printing::PrinterBasicInfo* printer_info) {
232 DCHECK(printer_info);
233 return print_system_->GetPrinterInfo(printer_name_, printer_info);
234 }
235
236 void JobStatusUpdate() {
237 if (delegate_ == NULL)
238 return; // Orphan call. We have been stopped already.
239 // For CUPS proxy, we are going to fire OnJobChanged notification
240 // periodically. Higher level will check if there are any outstanding
241 // jobs for this printer and check their status. If printer has no
242 // outstanding jobs, OnJobChanged() will do nothing.
243 delegate_->OnJobChanged();
244 MessageLoop::current()->PostDelayedTask(FROM_HERE,
245 NewRunnableMethod(this, &PrinterWatcherCUPS::JobStatusUpdate),
246 kJobUpdateTimeoutMs);
247 }
248
249 void PrinterUpdate() {
250 if (delegate_ == NULL)
251 return; // Orphan call. We have been stopped already.
252 VLOG(1) << "CP_CUPS: Checking for printer updates: " << printer_name_;
253 std::string new_hash = GetSettingsHash();
254 if (settings_hash_ != new_hash) {
255 settings_hash_ = new_hash;
256 delegate_->OnPrinterChanged();
257 VLOG(1) << "CP_CUPS: Printer update detected for: " << printer_name_;
258 }
259 MessageLoop::current()->PostDelayedTask(FROM_HERE,
260 NewRunnableMethod(this, &PrinterWatcherCUPS::PrinterUpdate),
261 print_system_->GetUpdateTimeoutMs());
262 }
263 private:
264 std::string GetSettingsHash() {
265 printing::PrinterBasicInfo info;
266 if (!print_system_->GetPrinterInfo(printer_name_, &info))
267 return std::string();
268
269 printing::PrinterCapsAndDefaults caps;
270 if (!print_system_->GetPrinterCapsAndDefaults(printer_name_, &caps))
271 return std::string();
272
273 std::string to_hash(info.printer_name);
274 to_hash += info.printer_description;
275 std::map<std::string, std::string>::const_iterator it;
276 for (it = info.options.begin(); it != info.options.end(); ++it) {
277 to_hash += it->first;
278 to_hash += it->second;
279 }
280
281 to_hash += caps.printer_capabilities;
282 to_hash += caps.caps_mime_type;
283 to_hash += caps.printer_defaults;
284 to_hash += caps.defaults_mime_type;
285
286 return MD5String(to_hash);
287 }
288
289 std::string printer_name_;
290 PrintSystem::PrinterWatcher::Delegate* delegate_;
291 scoped_refptr<PrintSystemCUPS> print_system_;
292 std::string settings_hash_;
293 DISALLOW_COPY_AND_ASSIGN(PrinterWatcherCUPS);
294 };
295
296 class JobSpoolerCUPS : public PrintSystem::JobSpooler {
297 public:
298 explicit JobSpoolerCUPS(PrintSystemCUPS* print_system)
299 : print_system_(print_system) {
300 DCHECK(print_system_.get());
301 }
302 // PrintSystem::JobSpooler implementation.
303 virtual bool Spool(const std::string& print_ticket,
304 const FilePath& print_data_file_path,
305 const std::string& print_data_mime_type,
306 const std::string& printer_name,
307 const std::string& job_title,
308 JobSpooler::Delegate* delegate) {
309 DCHECK(delegate);
310 int job_id = print_system_->SpoolPrintJob(
311 print_ticket, print_data_file_path, print_data_mime_type,
312 printer_name, job_title);
313 MessageLoop::current()->PostTask(FROM_HERE,
314 NewRunnableFunction(
315 &JobSpoolerCUPS::NotifyDelegate,
316 delegate,
317 job_id));
318 return true;
319 }
320
321 static void NotifyDelegate(JobSpooler::Delegate* delegate, int job_id) {
322 if (job_id)
323 delegate->OnJobSpoolSucceeded(job_id);
324 else
325 delegate->OnJobSpoolFailed();
326 }
327 private:
328 scoped_refptr<PrintSystemCUPS> print_system_;
329 DISALLOW_COPY_AND_ASSIGN(JobSpoolerCUPS);
330 };
331
332 PrintSystemCUPS::PrintSystemCUPS(const DictionaryValue* print_system_settings)
333 : update_timeout_(kCheckForPrinterUpdatesMs), initialized_(false) {
334 if (print_system_settings) {
335 int timeout;
336 if (print_system_settings->GetInteger(kCUPSUpdateTimeoutMs, &timeout))
337 update_timeout_ = timeout;
338 }
339
340 InitPrintBackends(print_system_settings);
341 }
342
343 void PrintSystemCUPS::InitPrintBackends(
344 const DictionaryValue* print_system_settings) {
345 ListValue* url_list;
346 if (print_system_settings &&
347 print_system_settings->GetList(kCUPSPrintServerURLs, &url_list)) {
348 for (size_t i = 0; i < url_list->GetSize(); i++) {
349 std::string print_server_url;
350 if (url_list->GetString(i, &print_server_url))
351 AddPrintServer(print_server_url);
352 }
353 }
354
355 // If server list is empty, use default print server.
356 if (print_servers_.empty())
357 AddPrintServer(std::string());
358 }
359
360 void PrintSystemCUPS::AddPrintServer(const std::string& url) {
361 if (url.empty())
362 LOG(WARNING) << "No print server specified. Using default print server.";
363
364 // Get Print backend for the specific print server.
365 DictionaryValue backend_settings;
366 backend_settings.SetString(kCUPSPrintBackendServerURL, url);
367
368 PrintServerInfoCUPS print_server;
369 print_server.backend =
370 printing::PrintBackend::CreateInstance(&backend_settings);
371 print_server.url = GURL(url.c_str());
372
373 print_servers_.push_back(print_server);
374 }
375
376 void PrintSystemCUPS::Init() {
377 UpdatePrinters();
378 initialized_ = true;
379 }
380
381 void PrintSystemCUPS::UpdatePrinters() {
382 printer_map_.clear();
383 PrintServerList::iterator it;
384 for (it = print_servers_.begin(); it != print_servers_.end(); ++it) {
385 it->backend->EnumeratePrinters(&it->printers);
386 it->caps_cache.clear();
387 printing::PrinterList::const_iterator printer_it;
388 for (printer_it = it->printers.begin();
389 printer_it != it->printers.end(); ++printer_it) {
390 printer_map_[printer_it->printer_name] = &(*it);
391 }
392 VLOG(1) << "CUPS: Updated printer list for url: " << it->url
393 << " Number of printers: " << it->printers.size();
394 }
395
396 // Schedule next update.
397 MessageLoop::current()->PostDelayedTask(FROM_HERE,
398 NewRunnableMethod(this, &PrintSystemCUPS::UpdatePrinters),
399 GetUpdateTimeoutMs());
400 }
401
402 void PrintSystemCUPS::EnumeratePrinters(printing::PrinterList* printer_list) {
403 DCHECK(initialized_);
404 printer_list->clear();
405 PrintServerList::iterator it;
406 for (it = print_servers_.begin(); it != print_servers_.end(); ++it) {
407 printer_list->insert(printer_list->end(),
408 it->printers.begin(), it->printers.end());
409 }
410 VLOG(1) << "CUPS: Total " << printer_list->size() << " printers enumerated.";
411 }
412
413 bool PrintSystemCUPS::GetPrinterCapsAndDefaults(
414 const std::string& printer_name,
415 printing::PrinterCapsAndDefaults* printer_info) {
416 DCHECK(initialized_);
417 PrintersMap::iterator it = printer_map_.find(printer_name);
418 if (it == printer_map_.end())
419 return false;
420
421 PrintServerInfoCUPS::CapsMap::iterator caps_it =
422 it->second->caps_cache.find(printer_name);
423 if (caps_it != it->second->caps_cache.end()) {
424 *printer_info = caps_it->second;
425 return true;
426 }
427
428 // TODO(gene): Retry multiple times in case of error.
429 if (!it->second->backend->GetPrinterCapsAndDefaults(printer_name,
430 printer_info) ) {
431 return false;
432 }
433
434 it->second->caps_cache[printer_name] = *printer_info;
435 return true;
436 }
437
438 bool PrintSystemCUPS::IsValidPrinter(const std::string& printer_name) {
439 DCHECK(initialized_);
440 PrintersMap::iterator it = printer_map_.find(printer_name);
441 return it != printer_map_.end();
204 } 442 }
205 443
206 bool PrintSystemCUPS::ValidatePrintTicket(const std::string& printer_name, 444 bool PrintSystemCUPS::ValidatePrintTicket(const std::string& printer_name,
207 const std::string& print_ticket_data) { 445 const std::string& print_ticket_data) {
446 DCHECK(initialized_);
208 scoped_ptr<Value> ticket_value(base::JSONReader::Read(print_ticket_data, 447 scoped_ptr<Value> ticket_value(base::JSONReader::Read(print_ticket_data,
209 false)); 448 false));
210 return ticket_value != NULL && ticket_value->IsType(Value::TYPE_DICTIONARY); 449 return ticket_value != NULL && ticket_value->IsType(Value::TYPE_DICTIONARY);
211 } 450 }
212 451
213 // Print ticket on linux is a JSON string containing only one dictionary. 452 // Print ticket on linux is a JSON string containing only one dictionary.
214 bool PrintSystemCUPS::ParsePrintTicket(const std::string& print_ticket, 453 bool PrintSystemCUPS::ParsePrintTicket(const std::string& print_ticket,
215 std::map<std::string, std::string>* options) { 454 std::map<std::string, std::string>* options) {
455 DCHECK(initialized_);
216 DCHECK(options); 456 DCHECK(options);
217 scoped_ptr<Value> ticket_value(base::JSONReader::Read(print_ticket, false)); 457 scoped_ptr<Value> ticket_value(base::JSONReader::Read(print_ticket, false));
218 if (ticket_value == NULL || !ticket_value->IsType(Value::TYPE_DICTIONARY)) 458 if (ticket_value == NULL || !ticket_value->IsType(Value::TYPE_DICTIONARY))
219 return false; 459 return false;
220 460
221 options->clear(); 461 options->clear();
222 DictionaryValue* ticket_dict = 462 DictionaryValue* ticket_dict =
223 static_cast<DictionaryValue*>(ticket_value.get()); 463 static_cast<DictionaryValue*>(ticket_value.get());
224 DictionaryValue::key_iterator it(ticket_dict->begin_keys()); 464 DictionaryValue::key_iterator it(ticket_dict->begin_keys());
225 for (; it != ticket_dict->end_keys(); ++it) { 465 for (; it != ticket_dict->end_keys(); ++it) {
226 const std::string& key = *it; 466 const std::string& key = *it;
227 std::string value; 467 std::string value;
228 if (ticket_dict->GetString(key, &value)) { 468 if (ticket_dict->GetString(key, &value)) {
229 (*options)[key] = value; 469 (*options)[key] = value;
230 } 470 }
231 } 471 }
232 472
233 return true; 473 return true;
234 } 474 }
235 475
236 bool PrintSystemCUPS::GetJobDetails(const std::string& printer_name, 476 bool PrintSystemCUPS::GetJobDetails(const std::string& printer_name,
237 PlatformJobId job_id, 477 PlatformJobId job_id,
238 PrintJobDetails *job_details) { 478 PrintJobDetails *job_details) {
479 DCHECK(initialized_);
239 DCHECK(job_details); 480 DCHECK(job_details);
240 481
482 PrintersMap::iterator it = printer_map_.find(printer_name);
483 if (it == printer_map_.end())
484 return false;
485
241 cups_job_t* jobs = NULL; 486 cups_job_t* jobs = NULL;
242 int num_jobs = GetJobs(&jobs, printer_name.c_str(), 1, -1); 487 int num_jobs = GetJobs(&jobs, it->second->url, printer_name.c_str(), 1, -1);
243 488
244 bool found = false; 489 bool found = false;
245 for (int i = 0; i < num_jobs; i++) { 490 for (int i = 0; i < num_jobs; i++) {
246 if (jobs[i].id == job_id) { 491 if (jobs[i].id == job_id) {
247 found = true; 492 found = true;
248 switch (jobs[i].state) { 493 switch (jobs[i].state) {
249 case IPP_JOB_PENDING : 494 case IPP_JOB_PENDING :
250 case IPP_JOB_HELD : 495 case IPP_JOB_HELD :
251 case IPP_JOB_PROCESSING : 496 case IPP_JOB_PROCESSING :
252 job_details->status = PRINT_JOB_STATUS_IN_PROGRESS; 497 job_details->status = PRINT_JOB_STATUS_IN_PROGRESS;
(...skipping 22 matching lines...) Expand all
275 else 520 else
276 LOG(WARNING) << "CP_CUPS: Job not found for: " << printer_name 521 LOG(WARNING) << "CP_CUPS: Job not found for: " << printer_name
277 << " job_id: " << job_id; 522 << " job_id: " << job_id;
278 523
279 cupsFreeJobs(num_jobs, jobs); 524 cupsFreeJobs(num_jobs, jobs);
280 return found; 525 return found;
281 } 526 }
282 527
283 bool PrintSystemCUPS::GetPrinterInfo(const std::string& printer_name, 528 bool PrintSystemCUPS::GetPrinterInfo(const std::string& printer_name,
284 printing::PrinterBasicInfo* info) { 529 printing::PrinterBasicInfo* info) {
530 DCHECK(initialized_);
285 DCHECK(info); 531 DCHECK(info);
286
287 VLOG(1) << "CP_CUPS: Getting printer info for: " << printer_name; 532 VLOG(1) << "CP_CUPS: Getting printer info for: " << printer_name;
288 533
289 // This is not very efficient way to get specific printer info. CUPS 1.4 534 PrintersMap::iterator it = printer_map_.find(printer_name);
290 // supports cupsGetNamedDest() function. However, CUPS 1.4 is not available 535 if (it == printer_map_.end())
291 // everywhere (for example, it supported from Mac OS 10.6 only). 536 return false;
292 printing::PrinterList printer_list;
293 print_backend_->EnumeratePrinters(&printer_list);
294 537
295 printing::PrinterList::iterator it; 538 printing::PrinterList::iterator printer_it;
296 for (it = printer_list.begin(); it != printer_list.end(); ++it) { 539 for (printer_it = it->second->printers.begin();
297 if (it->printer_name == printer_name) { 540 printer_it != it->second->printers.end(); ++printer_it) {
298 *info = *it; 541 if (printer_it->printer_name == printer_name) {
542 *info = *printer_it;
299 return true; 543 return true;
300 } 544 }
301 } 545 }
302 return false; 546 return false;
303 } 547 }
304 548
305 PrintSystem::PrintServerWatcher* 549 PrintSystem::PrintServerWatcher*
306 PrintSystemCUPS::CreatePrintServerWatcher() { 550 PrintSystemCUPS::CreatePrintServerWatcher() {
307 return new PrintServerWatcherCUPS(); 551 DCHECK(initialized_);
552 return new PrintServerWatcherCUPS(this);
308 } 553 }
309 554
310 PrintSystem::PrinterWatcher* PrintSystemCUPS::CreatePrinterWatcher( 555 PrintSystem::PrinterWatcher* PrintSystemCUPS::CreatePrinterWatcher(
311 const std::string& printer_name) { 556 const std::string& printer_name) {
557 DCHECK(initialized_);
312 DCHECK(!printer_name.empty()); 558 DCHECK(!printer_name.empty());
313 return new PrinterWatcherCUPS(this, printer_name); 559 return new PrinterWatcherCUPS(this, printer_name);
314 } 560 }
315 561
316 PrintSystem::JobSpooler* PrintSystemCUPS::CreateJobSpooler() { 562 PrintSystem::JobSpooler* PrintSystemCUPS::CreateJobSpooler() {
563 DCHECK(initialized_);
317 return new JobSpoolerCUPS(this); 564 return new JobSpoolerCUPS(this);
318 } 565 }
319 566
320 std::string PrintSystem::GenerateProxyId() { 567 std::string PrintSystem::GenerateProxyId() {
321 // TODO(gene): This code should generate a unique id for proxy. ID should be 568 // TODO(gene): This code should generate a unique id for proxy. ID should be
322 // unique for this user. Rand may return the same number. We'll need to change 569 // unique for this user. Rand may return the same number. We'll need to change
323 // this in the future. 570 // this in the future.
324 std::string id("CP_PROXY_"); 571 std::string id("CP_PROXY_");
325 id += base::Uint64ToString(base::RandUint64()); 572 id += base::Uint64ToString(base::RandUint64());
326 return id; 573 return id;
327 } 574 }
328 575
329 scoped_refptr<PrintSystem> PrintSystem::CreateInstance( 576 scoped_refptr<PrintSystem> PrintSystem::CreateInstance(
330 const DictionaryValue* print_system_settings) { 577 const DictionaryValue* print_system_settings) {
331 std::string print_server_url_str; 578 return new PrintSystemCUPS(print_system_settings);
332 if (print_system_settings) {
333 print_system_settings->GetString(kCUPSPrintServerURL,
334 &print_server_url_str);
335 }
336 GURL print_server_url(print_server_url_str.c_str());
337 return new PrintSystemCUPS(print_server_url, print_system_settings);
338 } 579 }
339 580
340 int PrintSystemCUPS::PrintFile(const char* name, const char* filename, 581 int PrintSystemCUPS::PrintFile(const GURL& url, const char* name,
341 const char* title, int num_options, 582 const char* filename, const char* title,
342 cups_option_t* options) { 583 int num_options, cups_option_t* options) {
343 if (print_server_url_.is_empty()) { // Use default (local) print server. 584 DCHECK(initialized_);
585 if (url.is_empty()) { // Use default (local) print server.
344 return cupsPrintFile(name, filename, title, num_options, options); 586 return cupsPrintFile(name, filename, title, num_options, options);
345 } else { 587 } else {
346 printing::HttpConnectionCUPS http(print_server_url_); 588 printing::HttpConnectionCUPS http(url);
347 return cupsPrintFile2(http.http(), name, filename, 589 return cupsPrintFile2(http.http(), name, filename,
348 title, num_options, options); 590 title, num_options, options);
349 } 591 }
350 } 592 }
351 593
352 int PrintSystemCUPS::GetJobs(cups_job_t** jobs, const char* name, 594 int PrintSystemCUPS::GetJobs(cups_job_t** jobs, const GURL& url,
353 int myjobs, int whichjobs) { 595 const char* name, int myjobs, int whichjobs) {
354 if (print_server_url_.is_empty()) { // Use default (local) print server. 596 DCHECK(initialized_);
597 if (url.is_empty()) { // Use default (local) print server.
355 return cupsGetJobs(jobs, name, myjobs, whichjobs); 598 return cupsGetJobs(jobs, name, myjobs, whichjobs);
356 } else { 599 } else {
357 printing::HttpConnectionCUPS http(print_server_url_); 600 printing::HttpConnectionCUPS http(url);
358 return cupsGetJobs2(http.http(), jobs, name, myjobs, whichjobs); 601 return cupsGetJobs2(http.http(), jobs, name, myjobs, whichjobs);
359 } 602 }
360 } 603 }
361 604
362 PlatformJobId PrintSystemCUPS::SpoolPrintJob( 605 PlatformJobId PrintSystemCUPS::SpoolPrintJob(
363 const std::string& print_ticket, 606 const std::string& print_ticket,
364 const FilePath& print_data_file_path, 607 const FilePath& print_data_file_path,
365 const std::string& print_data_mime_type, 608 const std::string& print_data_mime_type,
366 const std::string& printer_name, 609 const std::string& printer_name,
367 const std::string& job_title) { 610 const std::string& job_title) {
611 DCHECK(initialized_);
368 VLOG(1) << "CP_CUPS: Spooling print job for: " << printer_name; 612 VLOG(1) << "CP_CUPS: Spooling print job for: " << printer_name;
369 613
614 PrintersMap::iterator print_server = printer_map_.find(printer_name);
615 if (print_server == printer_map_.end())
616 return 0;
617
370 // We need to store options as char* string for the duration of the 618 // We need to store options as char* string for the duration of the
371 // cupsPrintFile2 call. We'll use map here to store options, since 619 // cupsPrintFile2 call. We'll use map here to store options, since
372 // Dictionary value from JSON parser returns wchat_t. 620 // Dictionary value from JSON parser returns wchat_t.
373 std::map<std::string, std::string> options; 621 std::map<std::string, std::string> options;
374 bool res = ParsePrintTicket(print_ticket, &options); 622 bool res = ParsePrintTicket(print_ticket, &options);
375 DCHECK(res); // If print ticket is invalid we still print using defaults. 623 DCHECK(res); // If print ticket is invalid we still print using defaults.
376 624
377 std::vector<cups_option_t> cups_options; 625 std::vector<cups_option_t> cups_options;
378 std::map<std::string, std::string>::iterator it; 626 std::map<std::string, std::string>::iterator it;
379 for (it = options.begin(); it != options.end(); ++it) { 627 for (it = options.begin(); it != options.end(); ++it) {
380 cups_option_t opt; 628 cups_option_t opt;
381 opt.name = const_cast<char*>(it->first.c_str()); 629 opt.name = const_cast<char*>(it->first.c_str());
382 opt.value = const_cast<char*>(it->second.c_str()); 630 opt.value = const_cast<char*>(it->second.c_str());
383 cups_options.push_back(opt); 631 cups_options.push_back(opt);
384 } 632 }
385 633
386 int job_id = PrintFile(printer_name.c_str(), 634 int job_id = PrintFile(print_server->second->url,
635 printer_name.c_str(),
387 print_data_file_path.value().c_str(), 636 print_data_file_path.value().c_str(),
388 job_title.c_str(), 637 job_title.c_str(),
389 cups_options.size(), 638 cups_options.size(),
390 &(cups_options[0])); 639 &(cups_options[0]));
391 640
392 VLOG(1) << "CP_CUPS: Job spooled, id: " << job_id; 641 VLOG(1) << "CP_CUPS: Job spooled, id: " << job_id;
393 642
394 return job_id; 643 return job_id;
395 } 644 }
396 645
397 } // namespace cloud_print 646 } // namespace cloud_print
OLDNEW
« no previous file with comments | « chrome/service/cloud_print/print_system.h ('k') | chrome/service/cloud_print/print_system_win.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698