Chromium Code Reviews| 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 |