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