| 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 |