OLD | NEW |
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 <algorithm> |
13 #include <list> | 13 #include <list> |
14 #include <map> | 14 #include <map> |
15 | 15 |
16 #include "base/file_path.h" | 16 #include "base/file_path.h" |
17 #include "base/json/json_reader.h" | 17 #include "base/json/json_reader.h" |
18 #include "base/lock.h" | 18 #include "base/lock.h" |
19 #include "base/logging.h" | 19 #include "base/logging.h" |
20 #include "base/md5.h" | 20 #include "base/md5.h" |
21 #include "base/message_loop.h" | 21 #include "base/message_loop.h" |
22 #include "base/rand_util.h" | 22 #include "base/rand_util.h" |
23 #include "base/scoped_ptr.h" | 23 #include "base/scoped_ptr.h" |
24 #include "base/string_number_conversions.h" | 24 #include "base/string_number_conversions.h" |
25 #include "base/string_util.h" | 25 #include "base/string_util.h" |
26 #include "base/task.h" | 26 #include "base/task.h" |
27 #include "base/values.h" | 27 #include "base/values.h" |
28 #include "base/utf_string_conversions.h" | 28 #include "base/utf_string_conversions.h" |
| 29 #include "chrome/service/cloud_print/cloud_print_consts.h" |
| 30 #include "chrome/service/cloud_print/cloud_print_helpers.h" |
29 #include "googleurl/src/gurl.h" | 31 #include "googleurl/src/gurl.h" |
30 #include "printing/backend/cups_helper.h" | 32 #include "printing/backend/cups_helper.h" |
31 #include "printing/backend/print_backend.h" | 33 #include "printing/backend/print_backend.h" |
32 | 34 |
33 namespace { | 35 namespace { |
34 static const char kCUPSPrinterInfoOpt[] = "printer-info"; | 36 static const char kCUPSPrinterInfoOpt[] = "printer-info"; |
35 static const char kCUPSPrinterStateOpt[] = "printer-state"; | 37 static const char kCUPSPrinterStateOpt[] = "printer-state"; |
36 static const char kCUPSPrintServerURLs[] = "print_server_urls"; | 38 static const char kCUPSPrintServerURLs[] = "print_server_urls"; |
37 static const char kCUPSUpdateTimeoutMs[] = "update_timeout_ms"; | 39 static const char kCUPSUpdateTimeoutMs[] = "update_timeout_ms"; |
38 static const char kCUPSPrintBackendServerURL[] = "print_server_url"; | 40 static const char kCUPSPrintBackendServerURL[] = "print_server_url"; |
39 | 41 |
40 // Default port for IPP print servers. | 42 // Default port for IPP print servers. |
41 static const int kDefaultIPPServerPort = 631; | 43 static const int kDefaultIPPServerPort = 631; |
42 | 44 |
43 // Time interval to check for printer's updates. | 45 // Time interval to check for printer's updates. |
44 const int kCheckForPrinterUpdatesMs = 6*60*60*1000; | 46 const int kCheckForPrinterUpdatesMs = 6*60*60*1000; |
45 | 47 |
46 // Job update timeput | 48 // Job update timeput |
47 const int kJobUpdateTimeoutMs = 5000; | 49 const int kJobUpdateTimeoutMs = 5000; |
48 | 50 |
| 51 // Job id for dry run (it should not affect CUPS job ids, since 0 job-id is |
| 52 // invalid in CUPS. |
| 53 const int kDryRunJobId = 0; |
| 54 |
49 } // namespace | 55 } // namespace |
50 | 56 |
51 namespace cloud_print { | 57 namespace cloud_print { |
52 | 58 |
53 struct PrintServerInfoCUPS { | 59 struct PrintServerInfoCUPS { |
54 GURL url; | 60 GURL url; |
55 scoped_refptr<printing::PrintBackend> backend; | 61 scoped_refptr<printing::PrintBackend> backend; |
56 printing::PrinterList printers; | 62 printing::PrinterList printers; |
57 // CapsMap cache PPD until the next update and give a fast access to it by | 63 // CapsMap cache PPD until the next update and give a fast access to it by |
58 // printer name. PPD request is relatively expensive and this should minimize | 64 // printer name. PPD request is relatively expensive and this should minimize |
(...skipping 27 matching lines...) Expand all Loading... |
86 virtual PrintSystem::PrintServerWatcher* CreatePrintServerWatcher(); | 92 virtual PrintSystem::PrintServerWatcher* CreatePrintServerWatcher(); |
87 virtual PrintSystem::PrinterWatcher* CreatePrinterWatcher( | 93 virtual PrintSystem::PrinterWatcher* CreatePrinterWatcher( |
88 const std::string& printer_name); | 94 const std::string& printer_name); |
89 virtual PrintSystem::JobSpooler* CreateJobSpooler(); | 95 virtual PrintSystem::JobSpooler* CreateJobSpooler(); |
90 | 96 |
91 // Helper functions. | 97 // Helper functions. |
92 PlatformJobId SpoolPrintJob(const std::string& print_ticket, | 98 PlatformJobId SpoolPrintJob(const std::string& print_ticket, |
93 const FilePath& print_data_file_path, | 99 const FilePath& print_data_file_path, |
94 const std::string& print_data_mime_type, | 100 const std::string& print_data_mime_type, |
95 const std::string& printer_name, | 101 const std::string& printer_name, |
96 const std::string& job_title); | 102 const std::string& job_title, |
| 103 const std::vector<std::string>& tags, |
| 104 bool* dry_run); |
97 bool GetPrinterInfo(const std::string& printer_name, | 105 bool GetPrinterInfo(const std::string& printer_name, |
98 printing::PrinterBasicInfo* info); | 106 printing::PrinterBasicInfo* info); |
99 bool ParsePrintTicket(const std::string& print_ticket, | 107 bool ParsePrintTicket(const std::string& print_ticket, |
100 std::map<std::string, std::string>* options); | 108 std::map<std::string, std::string>* options); |
101 | 109 |
102 int GetUpdateTimeoutMs() const { | 110 int GetUpdateTimeoutMs() const { |
103 return update_timeout_; | 111 return update_timeout_; |
104 } | 112 } |
105 | 113 |
106 private: | 114 private: |
(...skipping 196 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
303 explicit JobSpoolerCUPS(PrintSystemCUPS* print_system) | 311 explicit JobSpoolerCUPS(PrintSystemCUPS* print_system) |
304 : print_system_(print_system) { | 312 : print_system_(print_system) { |
305 DCHECK(print_system_.get()); | 313 DCHECK(print_system_.get()); |
306 } | 314 } |
307 // PrintSystem::JobSpooler implementation. | 315 // PrintSystem::JobSpooler implementation. |
308 virtual bool Spool(const std::string& print_ticket, | 316 virtual bool Spool(const std::string& print_ticket, |
309 const FilePath& print_data_file_path, | 317 const FilePath& print_data_file_path, |
310 const std::string& print_data_mime_type, | 318 const std::string& print_data_mime_type, |
311 const std::string& printer_name, | 319 const std::string& printer_name, |
312 const std::string& job_title, | 320 const std::string& job_title, |
| 321 const std::vector<std::string>& tags, |
313 JobSpooler::Delegate* delegate) { | 322 JobSpooler::Delegate* delegate) { |
314 DCHECK(delegate); | 323 DCHECK(delegate); |
| 324 bool dry_run = false; |
315 int job_id = print_system_->SpoolPrintJob( | 325 int job_id = print_system_->SpoolPrintJob( |
316 print_ticket, print_data_file_path, print_data_mime_type, | 326 print_ticket, print_data_file_path, print_data_mime_type, |
317 printer_name, job_title); | 327 printer_name, job_title, tags, &dry_run); |
318 MessageLoop::current()->PostTask(FROM_HERE, | 328 MessageLoop::current()->PostTask(FROM_HERE, |
319 NewRunnableFunction( | 329 NewRunnableFunction( |
320 &JobSpoolerCUPS::NotifyDelegate, | 330 &JobSpoolerCUPS::NotifyDelegate, |
321 delegate, | 331 delegate, |
322 job_id)); | 332 job_id, |
| 333 dry_run)); |
323 return true; | 334 return true; |
324 } | 335 } |
325 | 336 |
326 static void NotifyDelegate(JobSpooler::Delegate* delegate, int job_id) { | 337 static void NotifyDelegate(JobSpooler::Delegate* delegate, |
327 if (job_id) | 338 int job_id, bool dry_run) { |
| 339 if (dry_run || job_id) |
328 delegate->OnJobSpoolSucceeded(job_id); | 340 delegate->OnJobSpoolSucceeded(job_id); |
329 else | 341 else |
330 delegate->OnJobSpoolFailed(); | 342 delegate->OnJobSpoolFailed(); |
331 } | 343 } |
332 private: | 344 private: |
333 scoped_refptr<PrintSystemCUPS> print_system_; | 345 scoped_refptr<PrintSystemCUPS> print_system_; |
334 DISALLOW_COPY_AND_ASSIGN(JobSpoolerCUPS); | 346 DISALLOW_COPY_AND_ASSIGN(JobSpoolerCUPS); |
335 }; | 347 }; |
336 | 348 |
337 PrintSystemCUPS::PrintSystemCUPS(const DictionaryValue* print_system_settings) | 349 PrintSystemCUPS::PrintSystemCUPS(const DictionaryValue* print_system_settings) |
(...skipping 148 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
486 std::string short_printer_name; | 498 std::string short_printer_name; |
487 PrintServerInfoCUPS* server_info = | 499 PrintServerInfoCUPS* server_info = |
488 FindServerByFullName(printer_name, &short_printer_name); | 500 FindServerByFullName(printer_name, &short_printer_name); |
489 if (!server_info) | 501 if (!server_info) |
490 return false; | 502 return false; |
491 | 503 |
492 cups_job_t* jobs = NULL; | 504 cups_job_t* jobs = NULL; |
493 int num_jobs = GetJobs(&jobs, server_info->url, | 505 int num_jobs = GetJobs(&jobs, server_info->url, |
494 short_printer_name.c_str(), 1, -1); | 506 short_printer_name.c_str(), 1, -1); |
495 | 507 |
| 508 |
| 509 // Check if the request is for dummy dry run job. |
| 510 // We check this after calling GetJobs API to see if this printer is actually |
| 511 // accessible through CUPS. |
| 512 if (job_id == kDryRunJobId) { |
| 513 if (num_jobs >= 0) { |
| 514 job_details->status = PRINT_JOB_STATUS_COMPLETED; |
| 515 VLOG(1) << "CP_CUPS: Dry run job succeeded for: " << printer_name; |
| 516 } else { |
| 517 job_details->status = PRINT_JOB_STATUS_ERROR; |
| 518 VLOG(1) << "CP_CUPS: Dry run job faield for: " << printer_name; |
| 519 } |
| 520 return true; |
| 521 } |
| 522 |
496 bool found = false; | 523 bool found = false; |
497 for (int i = 0; i < num_jobs; i++) { | 524 for (int i = 0; i < num_jobs; i++) { |
498 if (jobs[i].id == job_id) { | 525 if (jobs[i].id == job_id) { |
499 found = true; | 526 found = true; |
500 switch (jobs[i].state) { | 527 switch (jobs[i].state) { |
501 case IPP_JOB_PENDING : | 528 case IPP_JOB_PENDING : |
502 case IPP_JOB_HELD : | 529 case IPP_JOB_HELD : |
503 case IPP_JOB_PROCESSING : | 530 case IPP_JOB_PROCESSING : |
504 job_details->status = PRINT_JOB_STATUS_IN_PROGRESS; | 531 job_details->status = PRINT_JOB_STATUS_IN_PROGRESS; |
505 break; | 532 break; |
(...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
608 printing::HttpConnectionCUPS http(url); | 635 printing::HttpConnectionCUPS http(url); |
609 return cupsGetJobs2(http.http(), jobs, name, myjobs, whichjobs); | 636 return cupsGetJobs2(http.http(), jobs, name, myjobs, whichjobs); |
610 } | 637 } |
611 } | 638 } |
612 | 639 |
613 PlatformJobId PrintSystemCUPS::SpoolPrintJob( | 640 PlatformJobId PrintSystemCUPS::SpoolPrintJob( |
614 const std::string& print_ticket, | 641 const std::string& print_ticket, |
615 const FilePath& print_data_file_path, | 642 const FilePath& print_data_file_path, |
616 const std::string& print_data_mime_type, | 643 const std::string& print_data_mime_type, |
617 const std::string& printer_name, | 644 const std::string& printer_name, |
618 const std::string& job_title) { | 645 const std::string& job_title, |
| 646 const std::vector<std::string>& tags, |
| 647 bool* dry_run) { |
619 DCHECK(initialized_); | 648 DCHECK(initialized_); |
620 VLOG(1) << "CP_CUPS: Spooling print job for: " << printer_name; | 649 VLOG(1) << "CP_CUPS: Spooling print job for: " << printer_name; |
621 | 650 |
622 std::string short_printer_name; | 651 std::string short_printer_name; |
623 PrintServerInfoCUPS* server_info = | 652 PrintServerInfoCUPS* server_info = |
624 FindServerByFullName(printer_name, &short_printer_name); | 653 FindServerByFullName(printer_name, &short_printer_name); |
625 if (!server_info) | 654 if (!server_info) |
626 return false; | 655 return false; |
627 | 656 |
628 // We need to store options as char* string for the duration of the | 657 // We need to store options as char* string for the duration of the |
629 // cupsPrintFile2 call. We'll use map here to store options, since | 658 // cupsPrintFile2 call. We'll use map here to store options, since |
630 // Dictionary value from JSON parser returns wchat_t. | 659 // Dictionary value from JSON parser returns wchat_t. |
631 std::map<std::string, std::string> options; | 660 std::map<std::string, std::string> options; |
632 bool res = ParsePrintTicket(print_ticket, &options); | 661 bool res = ParsePrintTicket(print_ticket, &options); |
633 DCHECK(res); // If print ticket is invalid we still print using defaults. | 662 DCHECK(res); // If print ticket is invalid we still print using defaults. |
634 | 663 |
| 664 // Check if this is a dry run (test) job. |
| 665 *dry_run = CloudPrintHelpers::IsDryRunJob(tags); |
| 666 if (*dry_run) { |
| 667 VLOG(1) << "CP_CUPS: Dry run job spooled."; |
| 668 return kDryRunJobId; |
| 669 } |
| 670 |
635 std::vector<cups_option_t> cups_options; | 671 std::vector<cups_option_t> cups_options; |
636 std::map<std::string, std::string>::iterator it; | 672 std::map<std::string, std::string>::iterator it; |
| 673 |
637 for (it = options.begin(); it != options.end(); ++it) { | 674 for (it = options.begin(); it != options.end(); ++it) { |
638 cups_option_t opt; | 675 cups_option_t opt; |
639 opt.name = const_cast<char*>(it->first.c_str()); | 676 opt.name = const_cast<char*>(it->first.c_str()); |
640 opt.value = const_cast<char*>(it->second.c_str()); | 677 opt.value = const_cast<char*>(it->second.c_str()); |
641 cups_options.push_back(opt); | 678 cups_options.push_back(opt); |
642 } | 679 } |
643 | 680 |
644 int job_id = PrintFile(server_info->url, | 681 int job_id = PrintFile(server_info->url, |
645 short_printer_name.c_str(), | 682 short_printer_name.c_str(), |
646 print_data_file_path.value().c_str(), | 683 print_data_file_path.value().c_str(), |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
689 *short_printer_name = full_printer_name.substr(separator + 1); | 726 *short_printer_name = full_printer_name.substr(separator + 1); |
690 return &(*it); | 727 return &(*it); |
691 } | 728 } |
692 } | 729 } |
693 | 730 |
694 LOG(WARNING) << "Server not found for printer: " << full_printer_name; | 731 LOG(WARNING) << "Server not found for printer: " << full_printer_name; |
695 return NULL; | 732 return NULL; |
696 } | 733 } |
697 | 734 |
698 } // namespace cloud_print | 735 } // namespace cloud_print |
OLD | NEW |