diff options
author | thestig@chromium.org <thestig@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-10-25 20:05:44 +0000 |
---|---|---|
committer | thestig@chromium.org <thestig@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-10-25 20:05:44 +0000 |
commit | 8e553f499860ac0b3bdea8326b7bc95a7650e250 (patch) | |
tree | 7c28ec6cbfae93e10038d97507a936a6e918aa2b | |
parent | 992848f4eb2e39e73b0bc2932253e9396eaf0369 (diff) | |
download | chromium_src-8e553f499860ac0b3bdea8326b7bc95a7650e250.zip chromium_src-8e553f499860ac0b3bdea8326b7bc95a7650e250.tar.gz chromium_src-8e553f499860ac0b3bdea8326b7bc95a7650e250.tar.bz2 |
Move useful printing backend code from chrome/service/cloud_print to printing/backend.
BUG=none
TEST=none
Review URL: http://codereview.chromium.org/3945003
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@63772 0039d316-1c4b-4281-b951-d872f2087c98
26 files changed, 790 insertions, 446 deletions
diff --git a/build/common.gypi b/build/common.gypi index 9f87a44..4d5836e 100644 --- a/build/common.gypi +++ b/build/common.gypi @@ -392,6 +392,11 @@ 'NACL_WIN64', ], }], + ['OS=="linux" and chromeos==0 and target_arch!="arm"', { + 'use_cups%': 1, + }, { + 'use_cups%': 0, + }], ], # NOTE: When these end up in the Mac bundle, we need to replace '-' for '_' diff --git a/chrome/chrome.gyp b/chrome/chrome.gyp index 3a414cd..d306fdc 100644 --- a/chrome/chrome.gyp +++ b/chrome/chrome.gyp @@ -1148,15 +1148,6 @@ 'include_dirs': [ '..', ], - 'variables': { - 'conditions': [ - ['OS=="linux" and chromeos==0 and target_arch!="arm"', { - 'use_cups%': 1, - }, { - 'use_cups%': 0, - }], - ], - }, 'conditions': [ ['OS=="win"', { 'defines': [ diff --git a/chrome/service/cloud_print/cloud_print_consts.cc b/chrome/service/cloud_print/cloud_print_consts.cc index 0974205..7513875 100644 --- a/chrome/service/cloud_print/cloud_print_consts.cc +++ b/chrome/service/cloud_print/cloud_print_consts.cc @@ -28,8 +28,6 @@ const char kPrinterCapsHashValue[] = "capsHash"; const char kPrinterTagsValue[] = "tags"; const char kProxyTagPrefix[] = "__cp__"; const char kTagsHashTagName[] = "__cp__tagshash"; -const char kLocationTagName[] = "location"; -const char kDriverNameTagName[] = "drivername"; const char kDefaultCloudPrintServerUrl[] = "https://www.google.com/cloudprint"; diff --git a/chrome/service/cloud_print/cloud_print_consts.h b/chrome/service/cloud_print/cloud_print_consts.h index 0e98b94..532f717 100644 --- a/chrome/service/cloud_print/cloud_print_consts.h +++ b/chrome/service/cloud_print/cloud_print_consts.h @@ -30,8 +30,6 @@ extern const char kPrinterCapsHashValue[]; extern const char kPrinterTagsValue[]; extern const char kProxyTagPrefix[]; extern const char kTagsHashTagName[]; -extern const char kLocationTagName[]; -extern const char kDriverNameTagName[]; extern const char kDefaultCloudPrintServerUrl[]; extern const char kGaiaUrl[]; extern const char kCloudPrintGaiaServiceId[]; diff --git a/chrome/service/cloud_print/cloud_print_proxy.cc b/chrome/service/cloud_print/cloud_print_proxy.cc index f2fa628..4141b2d 100644 --- a/chrome/service/cloud_print/cloud_print_proxy.cc +++ b/chrome/service/cloud_print/cloud_print_proxy.cc @@ -12,6 +12,7 @@ #include "chrome/common/pref_names.h" #include "chrome/common/json_pref_store.h" #include "chrome/service/cloud_print/cloud_print_consts.h" +#include "chrome/service/cloud_print/print_system.h" #include "chrome/service/service_process.h" // This method is invoked on the IO thread to launch the browser process to @@ -133,7 +134,7 @@ void CloudPrintProxy::Shutdown() { // Notification methods from the backend. Called on UI thread. void CloudPrintProxy::OnPrinterListAvailable( - const cloud_print::PrinterList& printer_list) { + const printing::PrinterList& printer_list) { DCHECK(CalledOnValidThread()); // We could potentially show UI here allowing the user to select which // printers to register. For now, we just register all. @@ -163,4 +164,3 @@ void CloudPrintProxy::OnAuthenticationFailed() { g_service_process->io_thread()->message_loop_proxy()->PostTask( FROM_HERE, NewRunnableFunction(&ShowTokenExpiredNotificationInBrowser)); } - diff --git a/chrome/service/cloud_print/cloud_print_proxy.h b/chrome/service/cloud_print/cloud_print_proxy.h index cccf2b4..36399ca 100644 --- a/chrome/service/cloud_print/cloud_print_proxy.h +++ b/chrome/service/cloud_print/cloud_print_proxy.h @@ -46,7 +46,7 @@ class CloudPrintProxy : public CloudPrintProxyFrontend, // Notification methods from the backend. Called on UI thread. virtual void OnPrinterListAvailable( - const cloud_print::PrinterList& printer_list); + const printing::PrinterList& printer_list); virtual void OnAuthenticated(const std::string& cloud_print_token, const std::string& cloud_print_xmpp_token, const std::string& email); @@ -72,4 +72,3 @@ class CloudPrintProxy : public CloudPrintProxyFrontend, }; #endif // CHROME_SERVICE_CLOUD_PRINT_CLOUD_PRINT_PROXY_H_ - diff --git a/chrome/service/cloud_print/cloud_print_proxy_backend.cc b/chrome/service/cloud_print/cloud_print_proxy_backend.cc index d30160e..ac4e110 100644 --- a/chrome/service/cloud_print/cloud_print_proxy_backend.cc +++ b/chrome/service/cloud_print/cloud_print_proxy_backend.cc @@ -4,6 +4,9 @@ #include "chrome/service/cloud_print/cloud_print_proxy_backend.h" +#include <map> +#include <vector> + #include "base/file_util.h" #include "base/md5.h" #include "base/rand_util.h" @@ -17,11 +20,10 @@ #include "chrome/service/cloud_print/printer_job_handler.h" #include "chrome/service/gaia/service_gaia_authenticator.h" #include "chrome/service/service_process.h" +#include "googleurl/src/gurl.h" #include "jingle/notifier/base/notifier_options.h" #include "jingle/notifier/listener/push_notifications_thread.h" #include "jingle/notifier/listener/talk_mediator_impl.h" - -#include "googleurl/src/gurl.h" #include "net/url_request/url_request_status.h" // The real guts of CloudPrintProxyBackend, to keep the public client API clean. @@ -58,7 +60,7 @@ class CloudPrintProxyBackend::Core // shutdown. void DoShutdown(); void DoRegisterSelectedPrinters( - const cloud_print::PrinterList& printer_list); + const printing::PrinterList& printer_list); // URLFetcher::Delegate implementation. virtual void OnURLFetchComplete(const URLFetcher* source, const GURL& url, @@ -103,7 +105,7 @@ class CloudPrintProxyBackend::Core // NotifyXXX is how the Core communicates with the frontend across // threads. void NotifyPrinterListAvailable( - const cloud_print::PrinterList& printer_list); + const printing::PrinterList& printer_list); void NotifyAuthenticated( const std::string& cloud_print_token, const std::string& cloud_print_xmpp_token, @@ -149,7 +151,7 @@ class CloudPrintProxyBackend::Core // registered. We then pass a copy of this list to the frontend to give the // user a chance to further trim the list. When the frontend gives us the // final list we make a copy into this so that we can start registering. - cloud_print::PrinterList printer_list_; + printing::PrinterList printer_list_; // The URLFetcher instance for the current request scoped_ptr<URLFetcher> request_; // The index of the nex printer to be uploaded. @@ -164,7 +166,7 @@ class CloudPrintProxyBackend::Core // so we won't have to requery the printer if the upload fails and we need // to retry. std::string last_uploaded_printer_name_; - cloud_print::PrinterCapsAndDefaults last_uploaded_printer_info_; + printing::PrinterCapsAndDefaults last_uploaded_printer_info_; // A map of printer id to job handler. typedef std::map<std::string, scoped_refptr<PrinterJobHandler> > JobHandlerMap; @@ -235,7 +237,7 @@ void CloudPrintProxyBackend::Shutdown() { } void CloudPrintProxyBackend::RegisterPrinters( - const cloud_print::PrinterList& printer_list) { + const printing::PrinterList& printer_list) { core_thread_.message_loop()->PostTask(FROM_HERE, NewRunnableMethod( core_.get(), @@ -344,7 +346,7 @@ void CloudPrintProxyBackend::Core::DoInitializeWithToken( void CloudPrintProxyBackend::Core::StartRegistration() { DCHECK(MessageLoop::current() == backend_->core_thread_.message_loop()); printer_list_.clear(); - print_system_->EnumeratePrinters(&printer_list_); + print_system_->GetPrintBackend()->EnumeratePrinters(&printer_list_); server_error_count_ = 0; // Now we need to ask the server about printers that were registered on the // server so that we can trim this list. @@ -381,7 +383,7 @@ void CloudPrintProxyBackend::Core::DoShutdown() { } void CloudPrintProxyBackend::Core::DoRegisterSelectedPrinters( - const cloud_print::PrinterList& printer_list) { + const printing::PrinterList& printer_list) { DCHECK(MessageLoop::current() == backend_->core_thread_.message_loop()); if (!print_system_.get()) return; // No print system available. @@ -409,14 +411,15 @@ void CloudPrintProxyBackend::Core::RegisterNextPrinter() { // For the next printer to be uploaded, create a multi-part post request to // upload the printer capabilities and the printer defaults. if (next_upload_index_ < printer_list_.size()) { - const cloud_print::PrinterBasicInfo& info = + const printing::PrinterBasicInfo& info = printer_list_.at(next_upload_index_); bool have_printer_info = true; // If we are retrying a previous upload, we don't need to fetch the caps // and defaults again. if (info.printer_name != last_uploaded_printer_name_) { - have_printer_info = print_system_->GetPrinterCapsAndDefaults( - info.printer_name.c_str(), &last_uploaded_printer_info_); + have_printer_info = + print_system_->GetPrintBackend()->GetPrinterCapsAndDefaults( + info.printer_name.c_str(), &last_uploaded_printer_info_); } if (have_printer_info) { last_uploaded_printer_name_ = info.printer_name; @@ -536,7 +539,7 @@ void CloudPrintProxyBackend::Core::OnURLFetchComplete( } void CloudPrintProxyBackend::Core::NotifyPrinterListAvailable( - const cloud_print::PrinterList& printer_list) { + const printing::PrinterList& printer_list) { DCHECK(MessageLoop::current() == backend_->frontend_loop_); backend_->frontend_->OnPrinterListAvailable(printer_list); } @@ -617,7 +620,7 @@ void CloudPrintProxyBackend::Core::InitJobHandlerForPrinter( printer_info_cloud.printer_id); // We might already have a job handler for this printer if (index == job_handler_map_.end()) { - cloud_print::PrinterBasicInfo printer_info; + printing::PrinterBasicInfo printer_info; printer_data->GetString(kNameValue, &printer_info.printer_name); DCHECK(!printer_info.printer_name.empty()); printer_data->GetString(kPrinterDescValue, @@ -635,7 +638,7 @@ void CloudPrintProxyBackend::Core::InitJobHandlerForPrinter( if (StartsWithASCII(tag, kTagsHashTagName, false)) { std::vector<std::string> tag_parts; base::SplitStringDontTrim(tag, '=', &tag_parts); - DCHECK(tag_parts.size() == 2); + DCHECK_EQ(tag_parts.size(), 2U); if (tag_parts.size() == 2) printer_info_cloud.tags_hash = tag_parts[1]; } @@ -695,7 +698,7 @@ void CloudPrintProxyBackend::Core::HandleServerError(Task* task_to_retry) { bool CloudPrintProxyBackend::Core::RemovePrinterFromList( const std::string& printer_name) { DCHECK(MessageLoop::current() == backend_->core_thread_.message_loop()); - for (cloud_print::PrinterList::iterator index = printer_list_.begin(); + for (printing::PrinterList::iterator index = printer_list_.begin(); index != printer_list_.end(); index++) { if (0 == base::strcasecmp(index->printer_name.c_str(), printer_name.c_str())) { @@ -758,4 +761,3 @@ void CloudPrintProxyBackend::Core::OnAuthError() { backend_->frontend_loop_->PostTask(FROM_HERE, NewRunnableMethod(this, &Core::NotifyAuthenticationFailed)); } - diff --git a/chrome/service/cloud_print/cloud_print_proxy_backend.h b/chrome/service/cloud_print/cloud_print_proxy_backend.h index e5a82c7..931fd91 100644 --- a/chrome/service/cloud_print/cloud_print_proxy_backend.h +++ b/chrome/service/cloud_print/cloud_print_proxy_backend.h @@ -9,9 +9,9 @@ #include <string> #include "base/thread.h" -#include "chrome/service/cloud_print/print_system.h" #include "chrome/common/net/url_fetcher.h" #include "googleurl/src/gurl.h" +#include "printing/backend/print_backend.h" class CloudPrintProxyService; class DictionaryValue; @@ -27,7 +27,7 @@ class CloudPrintProxyFrontend { // There is a list of printers available that can be registered. virtual void OnPrinterListAvailable( - const cloud_print::PrinterList& printer_list) = 0; + const printing::PrinterList& printer_list) = 0; // We successfully authenticated with the cloud print server. This callback // allows the frontend to persist the tokens. virtual void OnAuthenticated(const std::string& cloud_print_token, @@ -59,7 +59,7 @@ class CloudPrintProxyBackend { const std::string email, const std::string& proxy_id); void Shutdown(); - void RegisterPrinters(const cloud_print::PrinterList& printer_list); + void RegisterPrinters(const printing::PrinterList& printer_list); private: // The real guts of SyncBackendHost, to keep the public client API clean. @@ -82,4 +82,3 @@ class CloudPrintProxyBackend { }; #endif // CHROME_SERVICE_CLOUD_PRINT_CLOUD_PRINT_PROXY_BACKEND_H_ - diff --git a/chrome/service/cloud_print/print_system.cc b/chrome/service/cloud_print/print_system.cc index 57c1342..f15d6b8 100644 --- a/chrome/service/cloud_print/print_system.cc +++ b/chrome/service/cloud_print/print_system.cc @@ -6,10 +6,6 @@ namespace cloud_print { -PrinterBasicInfo::PrinterBasicInfo() : printer_status(0) {} - -PrinterBasicInfo::~PrinterBasicInfo() {} - PrintJobDetails::PrintJobDetails() : status(PRINT_JOB_STATUS_INVALID), platform_status_flags(0), diff --git a/chrome/service/cloud_print/print_system.h b/chrome/service/cloud_print/print_system.h index 2abdcc3..c6949bd 100644 --- a/chrome/service/cloud_print/print_system.h +++ b/chrome/service/cloud_print/print_system.h @@ -15,30 +15,16 @@ class DictionaryValue; class FilePath; +namespace printing { +class PrintBackend; +struct PrinterBasicInfo; +} + // This is the interface for platform-specific code for cloud print namespace cloud_print { typedef int PlatformJobId; -struct PrinterBasicInfo { - PrinterBasicInfo(); - ~PrinterBasicInfo(); - - std::string printer_name; - std::string printer_description; - int printer_status; - std::map<std::string, std::string> options; -}; - -typedef std::vector<PrinterBasicInfo> PrinterList; - -struct PrinterCapsAndDefaults { - std::string printer_capabilities; - std::string caps_mime_type; - std::string printer_defaults; - std::string defaults_mime_type; -}; - enum PrintJobStatus { PRINT_JOB_STATUS_INVALID, PRINT_JOB_STATUS_IN_PROGRESS, @@ -75,7 +61,7 @@ struct PrintJobDetails { // obtain available printing system. // Please note, that PrintSystem is not platform specific, but rather // print system specific. For example, CUPS is available on both Linux and Mac, -// but not avaialble on ChromeOS, etc. This design allows us to add more +// but not available on ChromeOS, etc. This design allows us to add more // functionality on some platforms, while reusing core (CUPS) functions. class PrintSystem : public base::RefCountedThreadSafe<PrintSystem> { public: @@ -113,7 +99,8 @@ class PrintSystem : public base::RefCountedThreadSafe<PrintSystem> { virtual ~PrinterWatcher(); virtual bool StartWatching(PrinterWatcher::Delegate* delegate) = 0; virtual bool StopWatching() = 0; - virtual bool GetCurrentPrinterInfo(PrinterBasicInfo* printer_info) = 0; + virtual bool GetCurrentPrinterInfo( + printing::PrinterBasicInfo* printer_info) = 0; }; class JobSpooler : public base::RefCountedThreadSafe<JobSpooler> { @@ -141,12 +128,8 @@ class PrintSystem : public base::RefCountedThreadSafe<PrintSystem> { virtual ~PrintSystem(); - // Enumerates the list of installed local and network printers. - virtual void EnumeratePrinters(PrinterList* printer_list) = 0; - - // Gets the capabilities and defaults for a specific printer. - virtual bool GetPrinterCapsAndDefaults(const std::string& printer_name, - PrinterCapsAndDefaults* printer_info) = 0; + // Get the printing backend. + virtual printing::PrintBackend* GetPrintBackend() = 0; // Returns true if ticket is valid. virtual bool ValidatePrintTicket(const std::string& printer_name, @@ -157,9 +140,6 @@ class PrintSystem : public base::RefCountedThreadSafe<PrintSystem> { PlatformJobId job_id, PrintJobDetails *job_details) = 0; - // Returns true if printer_name points to a valid printer. - virtual bool IsValidPrinter(const std::string& printer_name) = 0; - // Factory methods to create corresponding watcher. Callee is responsible // for deleting objects. Return NULL if failed. virtual PrintServerWatcher* CreatePrintServerWatcher() = 0; diff --git a/chrome/service/cloud_print/print_system_cups.cc b/chrome/service/cloud_print/print_system_cups.cc index b8a7378..99e3d1d 100644 --- a/chrome/service/cloud_print/print_system_cups.cc +++ b/chrome/service/cloud_print/print_system_cups.cc @@ -14,7 +14,6 @@ #include <map> #include "base/file_path.h" -#include "base/file_util.h" #include "base/json/json_reader.h" #include "base/lock.h" #include "base/logging.h" @@ -26,58 +25,8 @@ #include "base/values.h" #include "base/utf_string_conversions.h" #include "googleurl/src/gurl.h" - -namespace { - -// Init GCrypt library (needed for CUPS) using pthreads. -// I've hit a bug in CUPS library, when it crashed with: "ath.c:184: -// _gcry_ath_mutex_lock: Assertion `*lock == ((ath_mutex_t) 0)' failed." -// It happened whe multiple threads tried printing simultaneously. -// Google search for 'gnutls thread safety' provided with following solution -// where we initialize gcrypt by initializing gnutls. -// -// Initially, we linked with -lgnutls and simply called gnutls_global_init(), -// but this did not work well since we build one binary on Ubuntu Hardy and -// expect it to run on many Linux distros. (See http://crbug.com/46954) -// So instead we use dlopen() and dlsym() to dynamically load and call -// gnutls_global_init(). - -GCRY_THREAD_OPTION_PTHREAD_IMPL; - -bool init_gnutls() { - const char* kGnuTlsFile = "libgnutls.so"; - void* gnutls_lib = dlopen(kGnuTlsFile, RTLD_NOW); - if (!gnutls_lib) { - LOG(ERROR) << "Cannot load " << kGnuTlsFile; - return false; - } - const char* kGnuTlsInitFuncName = "gnutls_global_init"; - int (*pgnutls_global_init)(void) = reinterpret_cast<int(*)()>( - dlsym(gnutls_lib, kGnuTlsInitFuncName)); - if (!pgnutls_global_init) { - LOG(ERROR) << "Could not find " << kGnuTlsInitFuncName - << " in " << kGnuTlsFile; - return false; - } - return ((*pgnutls_global_init)() == 0); -} - -void init_gcrypt() { - // The gnutls_global_init() man page warns it's not thread safe. Locking this - // entire function just to be on the safe side. - static Lock init_gcrypt_lock; - AutoLock init_gcrypt_autolock(init_gcrypt_lock); - static bool gcrypt_initialized = false; - if (!gcrypt_initialized) { - gcry_control(GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread); - gcrypt_initialized = init_gnutls(); - if (!gcrypt_initialized) { - LOG(ERROR) << "Gcrypt initialization failed"; - } - } -} - -} // namespace +#include "printing/backend/cups_helper.h" +#include "printing/backend/print_backend.h" namespace cloud_print { @@ -88,49 +37,13 @@ static const char kCUPSPrintServerURL[] = "print_server_url"; // Default port for IPP print servers. static const int kDefaultIPPServerPort = 631; -// Helper wrapper around http_t structure, with connection and cleanup -// functionality. -class HttpConnectionCUPS { - public: - explicit HttpConnectionCUPS(const GURL& print_server_url) : http_(NULL) { - // If we have an empty url, use default print server. - if (print_server_url.is_empty()) - return; - - int port = print_server_url.IntPort(); - if (port == url_parse::PORT_UNSPECIFIED) - port = kDefaultIPPServerPort; - - http_ = httpConnectEncrypt(print_server_url.host().c_str(), port, - HTTP_ENCRYPT_NEVER); - if (http_ == NULL) { - LOG(ERROR) << "CP_CUPS: Failed connecting to print server: " << - print_server_url; - } - } - - ~HttpConnectionCUPS() { - if (http_ != NULL) - httpClose(http_); - } - - http_t* http() { - return http_; - } - - private: - http_t* http_; -}; - class PrintSystemCUPS : public PrintSystem { public: - explicit PrintSystemCUPS(const GURL& print_server_url); + PrintSystemCUPS(const GURL& print_server_url, + const DictionaryValue* print_system_settings); // PrintSystem implementation. - virtual void EnumeratePrinters(PrinterList* printer_list); - - virtual bool GetPrinterCapsAndDefaults(const std::string& printer_name, - PrinterCapsAndDefaults* printer_info); + virtual printing::PrintBackend* GetPrintBackend(); virtual bool ValidatePrintTicket(const std::string& printer_name, const std::string& print_ticket_data); @@ -139,9 +52,6 @@ class PrintSystemCUPS : public PrintSystem { PlatformJobId job_id, PrintJobDetails *job_details); - virtual bool IsValidPrinter(const std::string& printer_name); - - // TODO(gene): Add implementation for CUPS print server watcher. class PrintServerWatcherCUPS : public PrintSystem::PrintServerWatcher { @@ -185,7 +95,7 @@ class PrintSystemCUPS : public PrintSystem { delegate_ = NULL; return true; } - bool GetCurrentPrinterInfo(PrinterBasicInfo* printer_info) { + bool GetCurrentPrinterInfo(printing::PrinterBasicInfo* printer_info) { DCHECK(printer_info); return print_system_->GetPrinterInfo(printer_name_, printer_info); } @@ -258,7 +168,8 @@ class PrintSystemCUPS : public PrintSystem { const std::string& print_data_mime_type, const std::string& printer_name, const std::string& job_title); - bool GetPrinterInfo(const std::string& printer_name, PrinterBasicInfo* info); + bool GetPrinterInfo(const std::string& printer_name, + printing::PrinterBasicInfo* info); bool ParsePrintTicket(const std::string& print_ticket, std::map<std::string, std::string>* options); @@ -267,84 +178,30 @@ class PrintSystemCUPS : public PrintSystem { // <functions>2() are called when print server is specified, and plain // version in another case. There is an issue specifing CUPS_HTTP_DEFAULT // in the <functions>2(), it does not work in CUPS prior to 1.4. - int GetDests(cups_dest_t** dests); - FilePath GetPPD(const char* name); int GetJobs(cups_job_t** jobs, const char* name, int myjobs, int whichjobs); int PrintFile(const char* name, const char* filename, const char* title, int num_options, cups_option_t* options); + void Init(const DictionaryValue* print_system_settings); + GURL print_server_url_; + scoped_refptr<printing::PrintBackend> print_backend_; }; -PrintSystemCUPS::PrintSystemCUPS(const GURL& print_server_url) +PrintSystemCUPS::PrintSystemCUPS(const GURL& print_server_url, + const DictionaryValue* print_system_settings) : print_server_url_(print_server_url) { + Init(print_system_settings); } -void PrintSystemCUPS::EnumeratePrinters(PrinterList* printer_list) { - DCHECK(printer_list); - printer_list->clear(); - - cups_dest_t* destinations = NULL; - int num_dests = GetDests(&destinations); - - for (int printer_index = 0; printer_index < num_dests; printer_index++) { - const cups_dest_t& printer = destinations[printer_index]; - - PrinterBasicInfo printer_info; - printer_info.printer_name = printer.name; - - const char* info = cupsGetOption(kCUPSPrinterInfoOpt, - printer.num_options, printer.options); - if (info != NULL) - printer_info.printer_description = info; - - const char* state = cupsGetOption(kCUPSPrinterStateOpt, - printer.num_options, printer.options); - if (state != NULL) - base::StringToInt(state, &printer_info.printer_status); - - // Store printer options. - for (int opt_index = 0; opt_index < printer.num_options; opt_index++) { - printer_info.options[printer.options[opt_index].name] = - printer.options[opt_index].value; - } - - printer_list->push_back(printer_info); - } - - cupsFreeDests(num_dests, destinations); - - LOG(INFO) << "CP_CUPS: Enumerated " << printer_list->size() << " printers."; +void PrintSystemCUPS::Init(const DictionaryValue* print_system_settings) { + print_backend_ = + printing::PrintBackend::CreateInstance(print_system_settings); } -bool PrintSystemCUPS::GetPrinterCapsAndDefaults(const std::string& printer_name, - PrinterCapsAndDefaults* printer_info) { - DCHECK(printer_info); - - LOG(INFO) << "CP_CUPS: Getting Caps and Defaults for: " << printer_name; - - FilePath ppd_path(GetPPD(printer_name.c_str())); - // In some cases CUPS failed to get ppd file. - if (ppd_path.empty()) { - LOG(ERROR) << "CP_CUPS: Failed to get PPD for: " << printer_name; - return false; - } - - std::string content; - bool res = file_util::ReadFileToString(ppd_path, &content); - - file_util::Delete(ppd_path, false); - - if (res) { - printer_info->printer_capabilities.swap(content); - printer_info->caps_mime_type = "application/pagemaker"; - // In CUPS, printer defaults is a part of PPD file. Nothing to upload here. - printer_info->printer_defaults.clear(); - printer_info->defaults_mime_type.clear(); - } - - return res; +printing::PrintBackend* PrintSystemCUPS::GetPrintBackend() { + return print_backend_; } bool PrintSystemCUPS::ValidatePrintTicket(const std::string& printer_name, @@ -425,7 +282,7 @@ bool PrintSystemCUPS::GetJobDetails(const std::string& printer_name, } bool PrintSystemCUPS::GetPrinterInfo(const std::string& printer_name, - PrinterBasicInfo* info) { + printing::PrinterBasicInfo* info) { DCHECK(info); LOG(INFO) << "CP_CUPS: Getting printer info for: " << printer_name; @@ -433,10 +290,10 @@ bool PrintSystemCUPS::GetPrinterInfo(const std::string& printer_name, // This is not very efficient way to get specific printer info. CUPS 1.4 // supports cupsGetNamedDest() function. However, CUPS 1.4 is not available // everywhere (for example, it supported from Mac OS 10.6 only). - PrinterList printer_list; - EnumeratePrinters(&printer_list); + printing::PrinterList printer_list; + print_backend_->EnumeratePrinters(&printer_list); - PrinterList::iterator it; + printing::PrinterList::iterator it; for (it = printer_list.begin(); it != printer_list.end(); ++it) { if (it->printer_name == printer_name) { *info = *it; @@ -446,11 +303,6 @@ bool PrintSystemCUPS::GetPrinterInfo(const std::string& printer_name, return false; } -bool PrintSystemCUPS::IsValidPrinter(const std::string& printer_name) { - PrinterBasicInfo info; - return GetPrinterInfo(printer_name, &info); -} - PrintSystem::PrintServerWatcher* PrintSystemCUPS::CreatePrintServerWatcher() { return new PrintServerWatcherCUPS(); @@ -477,43 +329,13 @@ std::string PrintSystem::GenerateProxyId() { scoped_refptr<PrintSystem> PrintSystem::CreateInstance( const DictionaryValue* print_system_settings) { - // Initialize gcrypt library. - init_gcrypt(); - std::string print_server_url_str; if (print_system_settings) { - print_system_settings->GetString( - kCUPSPrintServerURL, &print_server_url_str); + print_system_settings->GetString(kCUPSPrintServerURL, + &print_server_url_str); } GURL print_server_url(print_server_url_str.c_str()); - return new PrintSystemCUPS(print_server_url); -} - -int PrintSystemCUPS::GetDests(cups_dest_t** dests) { - if (print_server_url_.is_empty()) { // Use default (local) print server. - return cupsGetDests(dests); - } else { - HttpConnectionCUPS http(print_server_url_); - return cupsGetDests2(http.http(), dests); - } -} - -FilePath PrintSystemCUPS::GetPPD(const char* name) { - // cupsGetPPD returns a filename stored in a static buffer in CUPS. - // Protect this code with lock. - static Lock ppd_lock; - AutoLock ppd_autolock(ppd_lock); - FilePath ppd_path; - const char* ppd_file_path = NULL; - if (print_server_url_.is_empty()) { // Use default (local) print server. - ppd_file_path = cupsGetPPD(name); - } else { - HttpConnectionCUPS http(print_server_url_); - ppd_file_path = cupsGetPPD2(http.http(), name); - } - if (ppd_file_path) - ppd_path = FilePath(ppd_file_path); - return ppd_path; + return new PrintSystemCUPS(print_server_url, print_system_settings); } int PrintSystemCUPS::PrintFile(const char* name, const char* filename, @@ -522,7 +344,7 @@ int PrintSystemCUPS::PrintFile(const char* name, const char* filename, if (print_server_url_.is_empty()) { // Use default (local) print server. return cupsPrintFile(name, filename, title, num_options, options); } else { - HttpConnectionCUPS http(print_server_url_); + printing::HttpConnectionCUPS http(print_server_url_); return cupsPrintFile2(http.http(), name, filename, title, num_options, options); } @@ -533,7 +355,7 @@ int PrintSystemCUPS::GetJobs(cups_job_t** jobs, const char* name, if (print_server_url_.is_empty()) { // Use default (local) print server. return cupsGetJobs(jobs, name, myjobs, whichjobs); } else { - HttpConnectionCUPS http(print_server_url_); + printing::HttpConnectionCUPS http(print_server_url_); return cupsGetJobs2(http.http(), jobs, name, myjobs, whichjobs); } } diff --git a/chrome/service/cloud_print/print_system_win.cc b/chrome/service/cloud_print/print_system_win.cc index fc3cc02..77272d6 100644 --- a/chrome/service/cloud_print/print_system_win.cc +++ b/chrome/service/cloud_print/print_system_win.cc @@ -4,15 +4,11 @@ #include "chrome/service/cloud_print/print_system.h" -#include <windows.h> #include <objidl.h> -#include <ocidl.h> -#include <olectl.h> #include <prntvpt.h> #include <winspool.h> -#include "base/lock.h" -#include "base/file_util.h" +#include "base/file_path.h" #include "base/object_watcher.h" #include "base/scoped_ptr.h" #include "base/utf_string_conversions.h" @@ -22,11 +18,13 @@ #include "chrome/service/service_process.h" #include "chrome/service/service_utility_process_host.h" #include "gfx/rect.h" +#include "printing/backend/print_backend.h" +#include "printing/backend/print_backend_consts.h" +#include "printing/backend/win_helper.h" #include "printing/native_metafile.h" #include "printing/page_range.h" #pragma comment(lib, "prntvpt.lib") -#pragma comment(lib, "rpcrt4.lib") using base::win::ScopedBstr; using base::win::ScopedComPtr; @@ -55,11 +53,6 @@ class DevMode { DISALLOW_COPY_AND_ASSIGN(DevMode); }; -bool InitXPSModule() { - HMODULE prntvpt_module = LoadLibrary(L"prntvpt.dll"); - return (NULL != prntvpt_module); -} - inline HRESULT GetLastErrorHR() { LONG error = GetLastError(); return HRESULT_FROM_WIN32(error); @@ -81,19 +74,6 @@ HRESULT StreamFromPrintTicket(const std::string& print_ticket, return S_OK; } -HRESULT StreamOnHGlobalToString(IStream* stream, std::string* out) { - DCHECK(stream); - DCHECK(out); - HGLOBAL hdata = NULL; - HRESULT hr = GetHGlobalFromStream(stream, &hdata); - if (SUCCEEDED(hr)) { - DCHECK(hdata); - ScopedHGlobal<char> locked_data(hdata); - out->assign(locked_data.release(), locked_data.Size()); - } - return hr; -} - HRESULT PrintTicketToDevMode(const std::string& printer_name, const std::string& print_ticket, DevMode* dev_mode) { @@ -209,7 +189,7 @@ class PrintSystemWatcherWin watcher_.StartWatching(printer_change_, this); } - bool GetCurrentPrinterInfo(PrinterBasicInfo* printer_info) { + bool GetCurrentPrinterInfo(printing::PrinterBasicInfo* printer_info) { DCHECK(printer_info); if (!printer_) return false; @@ -256,10 +236,10 @@ typedef PrintSystemWatcherWin::Delegate PrintSystemWatcherWinDelegate; class PrintSystemWin : public PrintSystem { public: - virtual void EnumeratePrinters(PrinterList* printer_list); + PrintSystemWin(); - virtual bool GetPrinterCapsAndDefaults(const std::string& printer_name, - PrinterCapsAndDefaults* printer_info); + // PrintSystem implementation. + virtual printing::PrintBackend* GetPrintBackend(); virtual bool ValidatePrintTicket(const std::string& printer_name, const std::string& print_ticket_data); @@ -268,8 +248,6 @@ class PrintSystemWin : public PrintSystem { PlatformJobId job_id, PrintJobDetails *job_details); - virtual bool IsValidPrinter(const std::string& printer_name); - class PrintServerWatcherWin : public PrintSystem::PrintServerWatcher, public PrintSystemWatcherWinDelegate { @@ -323,7 +301,8 @@ class PrintSystemWin : public PrintSystem { delegate_ = NULL; return ret; } - virtual bool GetCurrentPrinterInfo(PrinterBasicInfo* printer_info) { + virtual bool GetCurrentPrinterInfo( + printing::PrinterBasicInfo* printer_info) { return watcher_.GetCurrentPrinterInfo(printer_info); } @@ -390,7 +369,7 @@ class PrintSystemWin : public PrintSystem { return false; } - if (!InitXPSModule()) { + if (!printing::InitXPSModule()) { // TODO(sanjeevr): Handle legacy proxy case (with no prntvpt.dll) return false; } @@ -527,115 +506,29 @@ class PrintSystemWin : public PrintSystem { virtual PrintSystem::PrinterWatcher* CreatePrinterWatcher( const std::string& printer_name); virtual PrintSystem::JobSpooler* CreateJobSpooler(); + + private: + void Init(); + + scoped_refptr<printing::PrintBackend> print_backend_; }; -void PrintSystemWin::EnumeratePrinters(PrinterList* printer_list) { - DCHECK(printer_list); - DWORD bytes_needed = 0; - DWORD count_returned = 0; - BOOL ret = EnumPrinters(PRINTER_ENUM_LOCAL|PRINTER_ENUM_CONNECTIONS, NULL, 2, - NULL, 0, &bytes_needed, &count_returned); - if (0 != bytes_needed) { - scoped_ptr<BYTE> printer_info_buffer(new BYTE[bytes_needed]); - ret = EnumPrinters(PRINTER_ENUM_LOCAL|PRINTER_ENUM_CONNECTIONS, NULL, 2, - printer_info_buffer.get(), bytes_needed, &bytes_needed, - &count_returned); - DCHECK(ret); - PRINTER_INFO_2* printer_info = - reinterpret_cast<PRINTER_INFO_2*>(printer_info_buffer.get()); - for (DWORD index = 0; index < count_returned; index++) { - PrinterBasicInfo info; - info.printer_name = WideToUTF8(printer_info[index].pPrinterName); - if (printer_info[index].pComment) - info.printer_description = WideToUTF8(printer_info[index].pComment); - info.printer_status = printer_info[index].Status; - if (printer_info[index].pLocation) - info.options[kLocationTagName] = - WideToUTF8(printer_info[index].pLocation); - if (printer_info[index].pDriverName) - info.options[kDriverNameTagName] = - WideToUTF8(printer_info[index].pDriverName); - printer_list->push_back(info); - } - } +PrintSystemWin::PrintSystemWin() { + Init(); } -bool PrintSystemWin::GetPrinterCapsAndDefaults( - const std::string& printer_name, - PrinterCapsAndDefaults* printer_info) { - if (!InitXPSModule()) { - // TODO(sanjeevr): Handle legacy proxy case (with no prntvpt.dll) - return false; - } - if (!IsValidPrinter(printer_name)) { - return false; - } - DCHECK(printer_info); - HPTPROVIDER provider = NULL; - std::wstring printer_name_wide = UTF8ToWide(printer_name); - HRESULT hr = PTOpenProvider(printer_name_wide.c_str(), 1, &provider); - DCHECK(SUCCEEDED(hr)); - if (provider) { - ScopedComPtr<IStream> print_capabilities_stream; - hr = CreateStreamOnHGlobal(NULL, TRUE, - print_capabilities_stream.Receive()); - DCHECK(SUCCEEDED(hr)); - if (print_capabilities_stream) { - ScopedBstr error; - hr = PTGetPrintCapabilities(provider, NULL, print_capabilities_stream, - error.Receive()); - DCHECK(SUCCEEDED(hr)); - if (FAILED(hr)) { - return false; - } - hr = StreamOnHGlobalToString(print_capabilities_stream.get(), - &printer_info->printer_capabilities); - DCHECK(SUCCEEDED(hr)); - printer_info->caps_mime_type = "text/xml"; - } - // TODO(sanjeevr): Add ScopedPrinterHandle - HANDLE printer_handle = NULL; - OpenPrinter(const_cast<LPTSTR>(printer_name_wide.c_str()), &printer_handle, - NULL); - DCHECK(printer_handle); - if (printer_handle) { - DWORD devmode_size = DocumentProperties( - NULL, printer_handle, const_cast<LPTSTR>(printer_name_wide.c_str()), - NULL, NULL, 0); - DCHECK(0 != devmode_size); - scoped_ptr<BYTE> devmode_out_buffer(new BYTE[devmode_size]); - DEVMODE* devmode_out = - reinterpret_cast<DEVMODE*>(devmode_out_buffer.get()); - DocumentProperties( - NULL, printer_handle, const_cast<LPTSTR>(printer_name_wide.c_str()), - devmode_out, NULL, DM_OUT_BUFFER); - ScopedComPtr<IStream> printer_defaults_stream; - hr = CreateStreamOnHGlobal(NULL, TRUE, - printer_defaults_stream.Receive()); - DCHECK(SUCCEEDED(hr)); - if (printer_defaults_stream) { - hr = PTConvertDevModeToPrintTicket(provider, devmode_size, - devmode_out, kPTJobScope, - printer_defaults_stream); - DCHECK(SUCCEEDED(hr)); - if (SUCCEEDED(hr)) { - hr = StreamOnHGlobalToString(printer_defaults_stream.get(), - &printer_info->printer_defaults); - DCHECK(SUCCEEDED(hr)); - printer_info->defaults_mime_type = "text/xml"; - } - } - ClosePrinter(printer_handle); - } - PTCloseProvider(provider); - } - return true; +void PrintSystemWin::Init() { + print_backend_ = printing::PrintBackend::CreateInstance(NULL); +} + +printing::PrintBackend* PrintSystemWin::GetPrintBackend() { + return print_backend_; } bool PrintSystemWin::ValidatePrintTicket( const std::string& printer_name, const std::string& print_ticket_data) { - if (!InitXPSModule()) { + if (!printing::InitXPSModule()) { // TODO(sanjeevr): Handle legacy proxy case (with no prntvpt.dll) return false; } @@ -712,19 +605,6 @@ bool PrintSystemWin::GetJobDetails(const std::string& printer_name, return ret; } -bool PrintSystemWin::IsValidPrinter(const std::string& printer_name) { - std::wstring printer_name_wide = UTF8ToWide(printer_name); - HANDLE printer_handle = NULL; - OpenPrinter(const_cast<LPTSTR>(printer_name_wide.c_str()), &printer_handle, - NULL); - bool ret = false; - if (printer_handle) { - ret = true; - ClosePrinter(printer_handle); - } - return ret; -} - PrintSystem::PrintServerWatcher* PrintSystemWin::CreatePrintServerWatcher() { return new PrintServerWatcherWin(); @@ -760,4 +640,3 @@ scoped_refptr<PrintSystem> PrintSystem::CreateInstance( } } // namespace cloud_print - diff --git a/chrome/service/cloud_print/printer_job_handler.cc b/chrome/service/cloud_print/printer_job_handler.cc index bdc5801..9d4f46f 100644 --- a/chrome/service/cloud_print/printer_job_handler.cc +++ b/chrome/service/cloud_print/printer_job_handler.cc @@ -18,7 +18,7 @@ #include "net/http/http_response_headers.h" PrinterJobHandler::PrinterJobHandler( - const cloud_print::PrinterBasicInfo& printer_info, + const printing::PrinterBasicInfo& printer_info, const PrinterInfoFromCloud& printer_info_cloud, const std::string& auth_token, const GURL& cloud_print_server_url, @@ -45,7 +45,8 @@ PrinterJobHandler::PrinterJobHandler( } bool PrinterJobHandler::Initialize() { - if (print_system_->IsValidPrinter(printer_info_.printer_name)) { + if (print_system_->GetPrintBackend()->IsValidPrinter( + printer_info_.printer_name)) { printer_watcher_ = print_system_->CreatePrinterWatcher( printer_info_.printer_name); printer_watcher_->StartWatching(this); @@ -136,14 +137,14 @@ bool PrinterJobHandler::UpdatePrinterInfo() { << printer_info_cloud_.printer_id; // We need to update the parts of the printer info that have changed // (could be printer name, description, status or capabilities). - cloud_print::PrinterBasicInfo printer_info; + printing::PrinterBasicInfo printer_info; printer_watcher_->GetCurrentPrinterInfo(&printer_info); - cloud_print::PrinterCapsAndDefaults printer_caps; + printing::PrinterCapsAndDefaults printer_caps; std::string post_data; std::string mime_boundary; CloudPrintHelpers::CreateMimeBoundaryForUpload(&mime_boundary); - if (print_system_->GetPrinterCapsAndDefaults(printer_info.printer_name, - &printer_caps)) { + if (print_system_->GetPrintBackend()->GetPrinterCapsAndDefaults( + printer_info.printer_name, &printer_caps)) { std::string caps_hash = MD5String(printer_caps.printer_capabilities); if (caps_hash != printer_info_cloud_.caps_hash) { // Hashes don't match, we need to upload new capabilities (the defaults @@ -679,4 +680,3 @@ void PrinterJobHandler::OnJobSpoolFailed() { &PrinterJobHandler::JobFailed, PRINT_FAILED)); } - diff --git a/chrome/service/cloud_print/printer_job_handler.h b/chrome/service/cloud_print/printer_job_handler.h index 2831fb90..02c7be3 100644 --- a/chrome/service/cloud_print/printer_job_handler.h +++ b/chrome/service/cloud_print/printer_job_handler.h @@ -14,10 +14,10 @@ #include "base/message_loop_proxy.h" #include "base/thread.h" #include "chrome/service/cloud_print/job_status_updater.h" -#include "chrome/service/cloud_print/print_system.h" #include "chrome/common/net/url_fetcher.h" #include "googleurl/src/gurl.h" #include "net/url_request/url_request_status.h" +#include "printing/backend/print_backend.h" // A class that handles cloud print jobs for a particular printer. This class // imlements a state machine that transitions from Start to various states. The @@ -104,7 +104,7 @@ class PrinterJobHandler : public base::RefCountedThreadSafe<PrinterJobHandler>, }; // Begin public interface - PrinterJobHandler(const cloud_print::PrinterBasicInfo& printer_info, + PrinterJobHandler(const printing::PrinterBasicInfo& printer_info, const PrinterInfoFromCloud& printer_info_from_server, const std::string& auth_token, const GURL& cloud_print_server_url, @@ -232,7 +232,7 @@ class PrinterJobHandler : public base::RefCountedThreadSafe<PrinterJobHandler>, scoped_ptr<URLFetcher> request_; scoped_refptr<cloud_print::PrintSystem> print_system_; - cloud_print::PrinterBasicInfo printer_info_; + printing::PrinterBasicInfo printer_info_; PrinterInfoFromCloud printer_info_cloud_; std::string auth_token_; GURL cloud_print_server_url_; @@ -280,4 +280,3 @@ class PrinterJobHandler : public base::RefCountedThreadSafe<PrinterJobHandler>, typedef PrinterJobHandler::Delegate PrinterJobHandlerDelegate; #endif // CHROME_SERVICE_CLOUD_PRINT_PRINTER_JOB_HANDLER_H_ - diff --git a/printing/backend/cups_helper.cc b/printing/backend/cups_helper.cc new file mode 100644 index 0000000..2c3b853 --- /dev/null +++ b/printing/backend/cups_helper.cc @@ -0,0 +1,44 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "printing/backend/cups_helper.h" + +#include "base/logging.h" +#include "googleurl/src/gurl.h" + +namespace printing { + +// Default port for IPP print servers. +static const int kDefaultIPPServerPort = 631; + +// Helper wrapper around http_t structure, with connection and cleanup +// functionality. +HttpConnectionCUPS::HttpConnectionCUPS(const GURL& print_server_url) + : http_(NULL) { + // If we have an empty url, use default print server. + if (print_server_url.is_empty()) + return; + + int port = print_server_url.IntPort(); + if (port == url_parse::PORT_UNSPECIFIED) + port = kDefaultIPPServerPort; + + http_ = httpConnectEncrypt(print_server_url.host().c_str(), port, + HTTP_ENCRYPT_NEVER); + if (http_ == NULL) { + LOG(ERROR) << "CP_CUPS: Failed connecting to print server: " << + print_server_url; + } +} + +HttpConnectionCUPS::~HttpConnectionCUPS() { + if (http_ != NULL) + httpClose(http_); +} + +http_t* HttpConnectionCUPS::http() { + return http_; +} + +} // namespace printing diff --git a/printing/backend/cups_helper.h b/printing/backend/cups_helper.h new file mode 100644 index 0000000..16841bc --- /dev/null +++ b/printing/backend/cups_helper.h @@ -0,0 +1,31 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef PRINTING_BACKEND_CUPS_HELPER_H_ +#define PRINTING_BACKEND_CUPS_HELPER_H_ +#pragma once + +#include <cups/cups.h> + +class GURL; + +// These are helper functions for dealing with CUPS. +namespace printing { + +// Helper wrapper around http_t structure, with connection and cleanup +// functionality. +class HttpConnectionCUPS { + public: + explicit HttpConnectionCUPS(const GURL& print_server_url); + ~HttpConnectionCUPS(); + + http_t* http(); + + private: + http_t* http_; +}; + +} // namespace printing + +#endif // PRINTING_BACKEND_CUPS_HELPER_H_ diff --git a/printing/backend/print_backend.cc b/printing/backend/print_backend.cc new file mode 100644 index 0000000..307897d --- /dev/null +++ b/printing/backend/print_backend.cc @@ -0,0 +1,15 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "printing/backend/print_backend.h" + +namespace printing { + +PrinterBasicInfo::PrinterBasicInfo() : printer_status(0) {} + +PrinterBasicInfo::~PrinterBasicInfo() {} + +PrintBackend::~PrintBackend() {} + +} // namespace printing diff --git a/printing/backend/print_backend.h b/printing/backend/print_backend.h new file mode 100644 index 0000000..3b55268 --- /dev/null +++ b/printing/backend/print_backend.h @@ -0,0 +1,70 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef PRINTING_BACKEND_PRINT_BACKEND_H_ +#define PRINTING_BACKEND_PRINT_BACKEND_H_ +#pragma once + +#include <map> +#include <string> +#include <vector> + +#include "base/ref_counted.h" + +class DictionaryValue; + +// This is the interface for platform-specific code for a print backend +namespace printing { + +struct PrinterBasicInfo { + PrinterBasicInfo(); + ~PrinterBasicInfo(); + + std::string printer_name; + std::string printer_description; + int printer_status; + std::map<std::string, std::string> options; +}; + +typedef std::vector<PrinterBasicInfo> PrinterList; + +struct PrinterCapsAndDefaults { + std::string printer_capabilities; + std::string caps_mime_type; + std::string printer_defaults; + std::string defaults_mime_type; +}; + +// PrintBackend class will provide interface for different print backends +// (Windows, CUPS) to implement. User will call CreateInstance() to +// obtain available print backend. +// Please note, that PrintBackend is not platform specific, but rather +// print system specific. For example, CUPS is available on both Linux and Mac, +// but not available on ChromeOS, etc. This design allows us to add more +// functionality on some platforms, while reusing core (CUPS) functions. +class PrintBackend : public base::RefCountedThreadSafe<PrintBackend> { + public: + virtual ~PrintBackend(); + + // Enumerates the list of installed local and network printers. + virtual void EnumeratePrinters(PrinterList* printer_list) = 0; + + // Gets the capabilities and defaults for a specific printer. + virtual bool GetPrinterCapsAndDefaults( + const std::string& printer_name, + PrinterCapsAndDefaults* printer_info) = 0; + + // Returns true if printer_name points to a valid printer. + virtual bool IsValidPrinter(const std::string& printer_name) = 0; + + // Allocate a print backend. If |print_backend_settings| is NULL, default + // settings will be used. + // Return NULL if no print backend available. + static scoped_refptr<PrintBackend> CreateInstance( + const DictionaryValue* print_backend_settings); +}; + +} // namespace printing + +#endif // PRINTING_BACKEND_PRINT_BACKEND_H_ diff --git a/printing/backend/print_backend_consts.cc b/printing/backend/print_backend_consts.cc new file mode 100644 index 0000000..77a0020 --- /dev/null +++ b/printing/backend/print_backend_consts.cc @@ -0,0 +1,10 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Constant defines used in the print backend code + +#include "printing/backend/print_backend_consts.h" + +const char kLocationTagName[] = "location"; +const char kDriverNameTagName[] = "drivername"; diff --git a/printing/backend/print_backend_consts.h b/printing/backend/print_backend_consts.h new file mode 100644 index 0000000..003a87d --- /dev/null +++ b/printing/backend/print_backend_consts.h @@ -0,0 +1,12 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef PRINTING_BACKEND_PRINT_BACKEND_CONSTS_H_ +#define PRINTING_BACKEND_PRINT_BACKEND_CONSTS_H_ +#pragma once + +extern const char kLocationTagName[]; +extern const char kDriverNameTagName[]; + +#endif // PRINTING_BACKEND_PRINT_BACKEND_CONSTS_H_ diff --git a/printing/backend/print_backend_cups.cc b/printing/backend/print_backend_cups.cc new file mode 100644 index 0000000..9693299 --- /dev/null +++ b/printing/backend/print_backend_cups.cc @@ -0,0 +1,224 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "printing/backend/print_backend.h" + +#include <dlfcn.h> +#include <errno.h> +#include <gcrypt.h> +#include <pthread.h> + +#include "base/file_util.h" +#include "base/lock.h" +#include "base/logging.h" +#include "base/singleton.h" +#include "base/string_number_conversions.h" +#include "base/values.h" +#include "googleurl/src/gurl.h" +#include "printing/backend/cups_helper.h" + +GCRY_THREAD_OPTION_PTHREAD_IMPL; + +namespace { + +// Init GCrypt library (needed for CUPS) using pthreads. +// There exists a bug in CUPS library, where it crashed with: "ath.c:184: +// _gcry_ath_mutex_lock: Assertion `*lock == ((ath_mutex_t) 0)' failed." +// It happened when multiple threads tried printing simultaneously. +// Google search for 'gnutls thread safety' provided a solution that +// initialized gcrypt and gnutls. + +// Initially, we linked with -lgnutls and simply called gnutls_global_init(), +// but this did not work well since we build one binary on Ubuntu Hardy and +// expect it to run on many Linux distros. (See http://crbug.com/46954) +// So instead we use dlopen() and dlsym() to dynamically load and call +// gnutls_global_init(). + +class GcryptInitializer { + public: + GcryptInitializer() { + Init(); + } + + private: + void Init() { + gcry_control(GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread); + const char* kGnuTlsFile = "libgnutls.so"; + void* gnutls_lib = dlopen(kGnuTlsFile, RTLD_NOW); + if (!gnutls_lib) { + LOG(ERROR) << "Cannot load " << kGnuTlsFile; + return; + } + const char* kGnuTlsInitFuncName = "gnutls_global_init"; + int (*pgnutls_global_init)(void) = reinterpret_cast<int(*)()>( + dlsym(gnutls_lib, kGnuTlsInitFuncName)); + if (!pgnutls_global_init) { + LOG(ERROR) << "Could not find " << kGnuTlsInitFuncName + << " in " << kGnuTlsFile; + return; + } + if ((*pgnutls_global_init)() != 0) + LOG(ERROR) << "Gnutls initialization failed"; + } +}; + +} // namespace + +namespace printing { + +static const char kCUPSPrinterInfoOpt[] = "printer-info"; +static const char kCUPSPrinterStateOpt[] = "printer-state"; +static const char kCUPSPrintServerURL[] = "print_server_url"; + +class PrintBackendCUPS : public PrintBackend { + public: + explicit PrintBackendCUPS(const GURL& print_server_url); + virtual ~PrintBackendCUPS() {} + + // PrintBackend implementation. + virtual void EnumeratePrinters(PrinterList* printer_list); + + virtual bool GetPrinterCapsAndDefaults(const std::string& printer_name, + PrinterCapsAndDefaults* printer_info); + + virtual bool IsValidPrinter(const std::string& printer_name); + + private: + // Following functions are wrappers around corresponding CUPS functions. + // <functions>2() are called when print server is specified, and plain + // version in another case. There is an issue specifing CUPS_HTTP_DEFAULT + // in the <functions>2(), it does not work in CUPS prior to 1.4. + int GetDests(cups_dest_t** dests); + FilePath GetPPD(const char* name); + + GURL print_server_url_; +}; + +PrintBackendCUPS::PrintBackendCUPS(const GURL& print_server_url) + : print_server_url_(print_server_url) { +} + +void PrintBackendCUPS::EnumeratePrinters(PrinterList* printer_list) { + DCHECK(printer_list); + printer_list->clear(); + + cups_dest_t* destinations = NULL; + int num_dests = GetDests(&destinations); + + for (int printer_index = 0; printer_index < num_dests; printer_index++) { + const cups_dest_t& printer = destinations[printer_index]; + + PrinterBasicInfo printer_info; + printer_info.printer_name = printer.name; + + const char* info = cupsGetOption(kCUPSPrinterInfoOpt, + printer.num_options, printer.options); + if (info != NULL) + printer_info.printer_description = info; + + const char* state = cupsGetOption(kCUPSPrinterStateOpt, + printer.num_options, printer.options); + if (state != NULL) + base::StringToInt(state, &printer_info.printer_status); + + // Store printer options. + for (int opt_index = 0; opt_index < printer.num_options; opt_index++) { + printer_info.options[printer.options[opt_index].name] = + printer.options[opt_index].value; + } + + printer_list->push_back(printer_info); + } + + cupsFreeDests(num_dests, destinations); + + LOG(INFO) << "CUPS: Enumerated " << printer_list->size() << " printers."; +} + +bool PrintBackendCUPS::GetPrinterCapsAndDefaults( + const std::string& printer_name, + PrinterCapsAndDefaults* printer_info) { + DCHECK(printer_info); + + LOG(INFO) << "CUPS: Getting Caps and Defaults for: " << printer_name; + + FilePath ppd_path(GetPPD(printer_name.c_str())); + // In some cases CUPS failed to get ppd file. + if (ppd_path.empty()) { + LOG(ERROR) << "CUPS: Failed to get PPD for: " << printer_name; + return false; + } + + std::string content; + bool res = file_util::ReadFileToString(ppd_path, &content); + + file_util::Delete(ppd_path, false); + + if (res) { + printer_info->printer_capabilities.swap(content); + printer_info->caps_mime_type = "application/pagemaker"; + // In CUPS, printer defaults is a part of PPD file. Nothing to upload here. + printer_info->printer_defaults.clear(); + printer_info->defaults_mime_type.clear(); + } + + return res; +} + +bool PrintBackendCUPS::IsValidPrinter(const std::string& printer_name) { + // This is not very efficient way to get specific printer info. CUPS 1.4 + // supports cupsGetNamedDest() function. However, CUPS 1.4 is not available + // everywhere (for example, it supported from Mac OS 10.6 only). + PrinterList printer_list; + EnumeratePrinters(&printer_list); + + PrinterList::iterator it; + for (it = printer_list.begin(); it != printer_list.end(); ++it) + if (it->printer_name == printer_name) + return true; + return false; +} + +scoped_refptr<PrintBackend> PrintBackend::CreateInstance( + const DictionaryValue* print_backend_settings) { + // Initialize gcrypt library. + Singleton<GcryptInitializer>::get(); + + std::string print_server_url_str; + if (print_backend_settings) { + print_backend_settings->GetString(kCUPSPrintServerURL, + &print_server_url_str); + } + GURL print_server_url(print_server_url_str.c_str()); + return new PrintBackendCUPS(print_server_url); +} + +int PrintBackendCUPS::GetDests(cups_dest_t** dests) { + if (print_server_url_.is_empty()) { // Use default (local) print server. + return cupsGetDests(dests); + } else { + HttpConnectionCUPS http(print_server_url_); + return cupsGetDests2(http.http(), dests); + } +} + +FilePath PrintBackendCUPS::GetPPD(const char* name) { + // cupsGetPPD returns a filename stored in a static buffer in CUPS. + // Protect this code with lock. + static Lock ppd_lock; + AutoLock ppd_autolock(ppd_lock); + FilePath ppd_path; + const char* ppd_file_path = NULL; + if (print_server_url_.is_empty()) { // Use default (local) print server. + ppd_file_path = cupsGetPPD(name); + } else { + HttpConnectionCUPS http(print_server_url_); + ppd_file_path = cupsGetPPD2(http.http(), name); + } + if (ppd_file_path) + ppd_path = FilePath(ppd_file_path); + return ppd_path; +} + +} // namespace printing diff --git a/printing/backend/print_backend_dummy.cc b/printing/backend/print_backend_dummy.cc new file mode 100644 index 0000000..008f00b --- /dev/null +++ b/printing/backend/print_backend_dummy.cc @@ -0,0 +1,23 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// This is dummy implementation for all configurations where there is no +// print backend. +#if !defined(PRINT_BACKEND_AVAILABLE) + +#include "printing/backend/print_backend.h" + +#include "base/logging.h" + +namespace printing { + +scoped_refptr<PrintBackend> PrintBackend::CreateInstance( + const DictionaryValue* print_backend_settings) { + NOTREACHED(); + return NULL; +} + +} // namespace printing + +#endif // PRINT_BACKEND_AVAILABLE diff --git a/printing/backend/print_backend_win.cc b/printing/backend/print_backend_win.cc new file mode 100644 index 0000000..4cfd400 --- /dev/null +++ b/printing/backend/print_backend_win.cc @@ -0,0 +1,179 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "printing/backend/print_backend.h" + +#include <objidl.h> +#include <prntvpt.h> +#include <winspool.h> + +#include "base/scoped_ptr.h" +#include "base/string_piece.h" +#include "base/utf_string_conversions.h" +#include "base/win/scoped_bstr.h" +#include "base/win/scoped_comptr.h" +#include "base/win/scoped_hglobal.h" +#include "printing/backend/print_backend_consts.h" +#include "printing/backend/win_helper.h" + +#pragma comment(lib, "prntvpt.lib") + +using base::win::ScopedBstr; +using base::win::ScopedComPtr; +using base::win::ScopedHGlobal; + +namespace { + +HRESULT StreamOnHGlobalToString(IStream* stream, std::string* out) { + DCHECK(stream); + DCHECK(out); + HGLOBAL hdata = NULL; + HRESULT hr = GetHGlobalFromStream(stream, &hdata); + if (SUCCEEDED(hr)) { + DCHECK(hdata); + ScopedHGlobal<char> locked_data(hdata); + out->assign(locked_data.release(), locked_data.Size()); + } + return hr; +} + +} // namespace + +namespace printing { + +class PrintBackendWin : public PrintBackend { + public: + PrintBackendWin() {} + virtual ~PrintBackendWin() {} + + virtual void EnumeratePrinters(PrinterList* printer_list); + + virtual bool GetPrinterCapsAndDefaults(const std::string& printer_name, + PrinterCapsAndDefaults* printer_info); + + virtual bool IsValidPrinter(const std::string& printer_name); +}; + +void PrintBackendWin::EnumeratePrinters(PrinterList* printer_list) { + DCHECK(printer_list); + DWORD bytes_needed = 0; + DWORD count_returned = 0; + BOOL ret = EnumPrinters(PRINTER_ENUM_LOCAL|PRINTER_ENUM_CONNECTIONS, NULL, 2, + NULL, 0, &bytes_needed, &count_returned); + if (0 != bytes_needed) { + scoped_ptr<BYTE> printer_info_buffer(new BYTE[bytes_needed]); + ret = EnumPrinters(PRINTER_ENUM_LOCAL|PRINTER_ENUM_CONNECTIONS, NULL, 2, + printer_info_buffer.get(), bytes_needed, &bytes_needed, + &count_returned); + DCHECK(ret); + PRINTER_INFO_2* printer_info = + reinterpret_cast<PRINTER_INFO_2*>(printer_info_buffer.get()); + for (DWORD index = 0; index < count_returned; index++) { + PrinterBasicInfo info; + info.printer_name = WideToUTF8(printer_info[index].pPrinterName); + if (printer_info[index].pComment) + info.printer_description = WideToUTF8(printer_info[index].pComment); + info.printer_status = printer_info[index].Status; + if (printer_info[index].pLocation) + info.options[kLocationTagName] = + WideToUTF8(printer_info[index].pLocation); + if (printer_info[index].pDriverName) + info.options[kDriverNameTagName] = + WideToUTF8(printer_info[index].pDriverName); + printer_list->push_back(info); + } + } +} + +bool PrintBackendWin::GetPrinterCapsAndDefaults( + const std::string& printer_name, + PrinterCapsAndDefaults* printer_info) { + if (!printing::InitXPSModule()) { + // TODO(sanjeevr): Handle legacy proxy case (with no prntvpt.dll) + return false; + } + if (!IsValidPrinter(printer_name)) { + return false; + } + DCHECK(printer_info); + HPTPROVIDER provider = NULL; + std::wstring printer_name_wide = UTF8ToWide(printer_name); + HRESULT hr = PTOpenProvider(printer_name_wide.c_str(), 1, &provider); + DCHECK(SUCCEEDED(hr)); + if (provider) { + ScopedComPtr<IStream> print_capabilities_stream; + hr = CreateStreamOnHGlobal(NULL, TRUE, + print_capabilities_stream.Receive()); + DCHECK(SUCCEEDED(hr)); + if (print_capabilities_stream) { + ScopedBstr error; + hr = PTGetPrintCapabilities(provider, NULL, print_capabilities_stream, + error.Receive()); + DCHECK(SUCCEEDED(hr)); + if (FAILED(hr)) { + return false; + } + hr = StreamOnHGlobalToString(print_capabilities_stream.get(), + &printer_info->printer_capabilities); + DCHECK(SUCCEEDED(hr)); + printer_info->caps_mime_type = "text/xml"; + } + // TODO(sanjeevr): Add ScopedPrinterHandle + HANDLE printer_handle = NULL; + OpenPrinter(const_cast<LPTSTR>(printer_name_wide.c_str()), &printer_handle, + NULL); + DCHECK(printer_handle); + if (printer_handle) { + DWORD devmode_size = DocumentProperties( + NULL, printer_handle, const_cast<LPTSTR>(printer_name_wide.c_str()), + NULL, NULL, 0); + DCHECK_NE(0U, devmode_size); + scoped_ptr<BYTE> devmode_out_buffer(new BYTE[devmode_size]); + DEVMODE* devmode_out = + reinterpret_cast<DEVMODE*>(devmode_out_buffer.get()); + DocumentProperties( + NULL, printer_handle, const_cast<LPTSTR>(printer_name_wide.c_str()), + devmode_out, NULL, DM_OUT_BUFFER); + ScopedComPtr<IStream> printer_defaults_stream; + hr = CreateStreamOnHGlobal(NULL, TRUE, + printer_defaults_stream.Receive()); + DCHECK(SUCCEEDED(hr)); + if (printer_defaults_stream) { + hr = PTConvertDevModeToPrintTicket(provider, devmode_size, + devmode_out, kPTJobScope, + printer_defaults_stream); + DCHECK(SUCCEEDED(hr)); + if (SUCCEEDED(hr)) { + hr = StreamOnHGlobalToString(printer_defaults_stream.get(), + &printer_info->printer_defaults); + DCHECK(SUCCEEDED(hr)); + printer_info->defaults_mime_type = "text/xml"; + } + } + ClosePrinter(printer_handle); + } + PTCloseProvider(provider); + } + return true; +} + +bool PrintBackendWin::IsValidPrinter(const std::string& printer_name) { + std::wstring printer_name_wide = UTF8ToWide(printer_name); + HANDLE printer_handle = NULL; + OpenPrinter(const_cast<LPTSTR>(printer_name_wide.c_str()), &printer_handle, + NULL); + bool ret = false; + if (printer_handle) { + ret = true; + ClosePrinter(printer_handle); + } + return ret; +} + +scoped_refptr<PrintBackend> PrintBackend::CreateInstance( + const DictionaryValue* print_backend_settings) { + return new PrintBackendWin; +} + +} // namespace printing diff --git a/printing/backend/win_helper.cc b/printing/backend/win_helper.cc new file mode 100644 index 0000000..a5f515f --- /dev/null +++ b/printing/backend/win_helper.cc @@ -0,0 +1,17 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "printing/backend/win_helper.h" + + +#include <windows.h> + +namespace printing { + +bool InitXPSModule() { + HMODULE prntvpt_module = LoadLibrary(L"prntvpt.dll"); + return (NULL != prntvpt_module); +} + +} // namespace printing diff --git a/printing/backend/win_helper.h b/printing/backend/win_helper.h new file mode 100644 index 0000000..a779ad7 --- /dev/null +++ b/printing/backend/win_helper.h @@ -0,0 +1,16 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef PRINTING_BACKEND_WIN_HELPER_H_ +#define PRINTING_BACKEND_WIN_HELPER_H_ +#pragma once + +// These are helper functions for dealing with Windows Printing. +namespace printing { + +bool InitXPSModule(); + +} // namespace printing + +#endif // PRINTING_BACKEND_WIN_HELPER_H_ diff --git a/printing/printing.gyp b/printing/printing.gyp index 2970a90..a9f36e5 100644 --- a/printing/printing.gyp +++ b/printing/printing.gyp @@ -1,4 +1,4 @@ -# Copyright (c) 2009 The Chromium Authors. All rights reserved. +# Copyright (c) 2010 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. @@ -24,6 +24,11 @@ '..', ], 'sources': [ + 'backend/print_backend.cc', + 'backend/print_backend.h', + 'backend/print_backend_consts.cc', + 'backend/print_backend_consts.h', + 'backend/print_backend_dummy.cc', 'emf_win.cc', 'emf_win.h', 'image.cc', @@ -40,29 +45,29 @@ 'page_range.h', 'page_setup.cc', 'page_setup.h', - 'pdf_metafile_mac.h', 'pdf_metafile_mac.cc', - 'pdf_ps_metafile_cairo.h', + 'pdf_metafile_mac.h', 'pdf_ps_metafile_cairo.cc', - 'print_settings.cc', - 'print_settings.h', - 'printed_document.cc', + 'pdf_ps_metafile_cairo.h', 'printed_document_cairo.cc', + 'printed_document.cc', + 'printed_document.h', 'printed_document_mac.cc', 'printed_document_posix.cc', 'printed_document_win.cc', - 'printed_document.h', 'printed_page.cc', 'printed_page.h', 'printed_pages_source.h', - 'printing_context.h', - 'printing_context.cc', - 'printing_context_cairo.h', 'printing_context_cairo.cc', + 'printing_context_cairo.h', + 'printing_context.cc', + 'printing_context.h', 'printing_context_mac.h', 'printing_context_mac.mm', - 'printing_context_win.h', 'printing_context_win.cc', + 'printing_context_win.h', + 'print_settings.cc', + 'print_settings.h', 'units.cc', 'units.h', ], @@ -88,6 +93,36 @@ '../build/linux/system.gyp:gtkprint', ], }], + ['OS=="win"', { + 'defines': [ + # PRINT_BACKEND_AVAILABLE disables the default dummy implementation + # of the print backend and enables a custom implementation instead. + 'PRINT_BACKEND_AVAILABLE', + ], + 'sources': [ + 'backend/win_helper.cc', + 'backend/win_helper.h', + 'backend/print_backend_win.cc', + ], + }], + ['use_cups==1', { + 'link_settings': { + 'libraries': [ + '-lcups', + '-lgcrypt', + ], + }, + 'defines': [ + # PRINT_BACKEND_AVAILABLE disables the default dummy implementation + # of the print backend and enables a custom implementation instead. + 'PRINT_BACKEND_AVAILABLE', + ], + 'sources': [ + 'backend/cups_helper.cc', + 'backend/cups_helper.h', + 'backend/print_backend_cups.cc', + ], + }], ], }, { |