Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(144)

Unified Diff: printing/backend/print_backend_cups.cc

Issue 3945003: Move useful printing backend code from chrome/service/cloud_print to printing... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: resolve merge conflict Created 10 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « printing/backend/print_backend_consts.cc ('k') | printing/backend/print_backend_dummy.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: printing/backend/print_backend_cups.cc
===================================================================
--- printing/backend/print_backend_cups.cc (revision 0)
+++ printing/backend/print_backend_cups.cc (working copy)
@@ -2,264 +2,88 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "chrome/service/cloud_print/print_system.h"
+#include "printing/backend/print_backend.h"
-#include <cups/cups.h>
#include <dlfcn.h>
#include <errno.h>
#include <gcrypt.h>
#include <pthread.h>
-#include <list>
-#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"
-#include "base/message_loop.h"
-#include "base/rand_util.h"
+#include "base/singleton.h"
#include "base/string_number_conversions.h"
-#include "base/string_util.h"
-#include "base/task.h"
#include "base/values.h"
-#include "base/utf_string_conversions.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.
-// I've hit a bug in CUPS library, when it crashed with: "ath.c:184:
+// 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 whe multiple threads tried printing simultaneously.
-// Google search for 'gnutls thread safety' provided with following solution
-// where we initialize gcrypt by initializing gnutls.
-//
+// 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().
-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;
+class GcryptInitializer {
+ public:
+ GcryptInitializer() {
+ Init();
}
- 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) {
+ private:
+ void Init() {
gcry_control(GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread);
- gcrypt_initialized = init_gnutls();
- if (!gcrypt_initialized) {
- LOG(ERROR) << "Gcrypt initialization failed";
+ 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 cloud_print {
+namespace printing {
static const char kCUPSPrinterInfoOpt[] = "printer-info";
static const char kCUPSPrinterStateOpt[] = "printer-state";
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 {
+class PrintBackendCUPS : public PrintBackend {
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;
+ explicit PrintBackendCUPS(const GURL& print_server_url);
+ virtual ~PrintBackendCUPS() {}
- 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);
-
- // PrintSystem implementation.
+ // PrintBackend implementation.
virtual void EnumeratePrinters(PrinterList* printer_list);
virtual bool GetPrinterCapsAndDefaults(const std::string& printer_name,
PrinterCapsAndDefaults* printer_info);
- virtual bool ValidatePrintTicket(const std::string& printer_name,
- const std::string& print_ticket_data);
-
- virtual bool GetJobDetails(const std::string& printer_name,
- 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 {
- public:
- PrintServerWatcherCUPS() {}
-
- // PrintSystem::PrintServerWatcher interface
- virtual bool StartWatching(
- PrintSystem::PrintServerWatcher::Delegate* delegate) {
- NOTIMPLEMENTED();
- return true;
- }
- virtual bool StopWatching() {
- NOTIMPLEMENTED();
- return true;
- }
- };
-
- class PrinterWatcherCUPS
- : public PrintSystem::PrinterWatcher {
- public:
- explicit PrinterWatcherCUPS(PrintSystemCUPS* print_system,
- const std::string& printer_name)
- : printer_name_(printer_name), print_system_(print_system) {
- }
-
- // PrintSystem::PrinterWatcher interface
- virtual bool StartWatching(
- PrintSystem::PrinterWatcher::Delegate* delegate) {
- if (delegate_ != NULL)
- StopWatching();
- delegate_ = delegate;
- MessageLoop::current()->PostDelayedTask(FROM_HERE,
- NewRunnableMethod(this,
- &PrintSystemCUPS::PrinterWatcherCUPS::Update), 5000);
- return true;
- }
- virtual bool StopWatching() {
- delegate_ = NULL;
- return true;
- }
- bool GetCurrentPrinterInfo(PrinterBasicInfo* printer_info) {
- DCHECK(printer_info);
- return print_system_->GetPrinterInfo(printer_name_, printer_info);
- }
-
- void Update() {
- if (delegate_ == NULL)
- return; // Orphan call. We have been stopped already.
- // For CUPS proxy, we are going to fire OnJobChanged notification
- // periodically. Higher level will check if there are any outstanding
- // jobs for this printer and check their status. If printer has no
- // outstanding jobs, OnJobChanged() will do nothing.
- delegate_->OnJobChanged();
- MessageLoop::current()->PostDelayedTask(FROM_HERE,
- NewRunnableMethod(this,
- &PrintSystemCUPS::PrinterWatcherCUPS::Update),
- kNotificationTimeout);
- }
- private:
- static const int kNotificationTimeout = 5000; // in ms
- std::string printer_name_;
- PrintSystem::PrinterWatcher::Delegate* delegate_;
- scoped_refptr<PrintSystemCUPS> print_system_;
- DISALLOW_COPY_AND_ASSIGN(PrinterWatcherCUPS);
- };
-
- class JobSpoolerCUPS : public PrintSystem::JobSpooler {
- public:
- explicit JobSpoolerCUPS(PrintSystemCUPS* print_system)
- : print_system_(print_system) {
- DCHECK(print_system_.get());
- }
- // PrintSystem::JobSpooler implementation.
- virtual bool Spool(const std::string& print_ticket,
- const FilePath& print_data_file_path,
- const std::string& print_data_mime_type,
- const std::string& printer_name,
- const std::string& job_title,
- JobSpooler::Delegate* delegate) {
- DCHECK(delegate);
- int job_id = print_system_->SpoolPrintJob(
- print_ticket, print_data_file_path, print_data_mime_type,
- printer_name, job_title);
- MessageLoop::current()->PostTask(FROM_HERE,
- NewRunnableFunction(
- &JobSpoolerCUPS::NotifyDelegate,
- delegate,
- job_id));
- return true;
- }
-
- static void NotifyDelegate(JobSpooler::Delegate* delegate, int job_id) {
- if (job_id)
- delegate->OnJobSpoolSucceeded(job_id);
- else
- delegate->OnJobSpoolFailed();
- }
- private:
- scoped_refptr<PrintSystemCUPS> print_system_;
- DISALLOW_COPY_AND_ASSIGN(JobSpoolerCUPS);
- };
-
- virtual PrintSystem::PrintServerWatcher* CreatePrintServerWatcher();
- virtual PrintSystem::PrinterWatcher* CreatePrinterWatcher(
- const std::string& printer_name);
- virtual PrintSystem::JobSpooler* CreateJobSpooler();
-
- // Helper functions.
- PlatformJobId SpoolPrintJob(const std::string& print_ticket,
- const FilePath& print_data_file_path,
- 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 ParsePrintTicket(const std::string& print_ticket,
- std::map<std::string, std::string>* options);
-
private:
// Following functions are wrappers around corresponding CUPS functions.
// <functions>2() are called when print server is specified, and plain
@@ -267,19 +91,15 @@
// 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);
GURL print_server_url_;
};
-PrintSystemCUPS::PrintSystemCUPS(const GURL& print_server_url)
+PrintBackendCUPS::PrintBackendCUPS(const GURL& print_server_url)
: print_server_url_(print_server_url) {
}
-void PrintSystemCUPS::EnumeratePrinters(PrinterList* printer_list) {
+void PrintBackendCUPS::EnumeratePrinters(PrinterList* printer_list) {
DCHECK(printer_list);
printer_list->clear();
@@ -313,19 +133,20 @@
cupsFreeDests(num_dests, destinations);
- LOG(INFO) << "CP_CUPS: Enumerated " << printer_list->size() << " printers.";
+ LOG(INFO) << "CUPS: Enumerated " << printer_list->size() << " printers.";
}
-bool PrintSystemCUPS::GetPrinterCapsAndDefaults(const std::string& printer_name,
- PrinterCapsAndDefaults* printer_info) {
+bool PrintBackendCUPS::GetPrinterCapsAndDefaults(
+ const std::string& printer_name,
+ PrinterCapsAndDefaults* printer_info) {
DCHECK(printer_info);
- LOG(INFO) << "CP_CUPS: Getting Caps and Defaults for: " << printer_name;
+ 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) << "CP_CUPS: Failed to get PPD for: " << printer_name;
+ LOG(ERROR) << "CUPS: Failed to get PPD for: " << printer_name;
return false;
}
@@ -345,89 +166,7 @@
return res;
}
-bool PrintSystemCUPS::ValidatePrintTicket(const std::string& printer_name,
- const std::string& print_ticket_data) {
- scoped_ptr<Value> ticket_value(base::JSONReader::Read(print_ticket_data,
- false));
- return ticket_value != NULL && ticket_value->IsType(Value::TYPE_DICTIONARY);
-}
-
-// Print ticket on linux is a JSON string containing only one dictionary.
-bool PrintSystemCUPS::ParsePrintTicket(const std::string& print_ticket,
- std::map<std::string, std::string>* options) {
- DCHECK(options);
- scoped_ptr<Value> ticket_value(base::JSONReader::Read(print_ticket, false));
- if (ticket_value == NULL || !ticket_value->IsType(Value::TYPE_DICTIONARY))
- return false;
-
- options->clear();
- DictionaryValue* ticket_dict =
- static_cast<DictionaryValue*>(ticket_value.get());
- DictionaryValue::key_iterator it(ticket_dict->begin_keys());
- for (; it != ticket_dict->end_keys(); ++it) {
- const std::string& key = *it;
- std::string value;
- if (ticket_dict->GetString(key, &value)) {
- (*options)[key] = value;
- }
- }
-
- return true;
-}
-
-bool PrintSystemCUPS::GetJobDetails(const std::string& printer_name,
- PlatformJobId job_id,
- PrintJobDetails *job_details) {
- DCHECK(job_details);
-
- cups_job_t* jobs = NULL;
- int num_jobs = GetJobs(&jobs, printer_name.c_str(), 1, -1);
-
- bool found = false;
- for (int i = 0; i < num_jobs; i++) {
- if (jobs[i].id == job_id) {
- found = true;
- switch (jobs[i].state) {
- case IPP_JOB_PENDING :
- case IPP_JOB_HELD :
- case IPP_JOB_PROCESSING :
- job_details->status = PRINT_JOB_STATUS_IN_PROGRESS;
- break;
- case IPP_JOB_STOPPED :
- case IPP_JOB_CANCELLED :
- case IPP_JOB_ABORTED :
- job_details->status = PRINT_JOB_STATUS_ERROR;
- break;
- case IPP_JOB_COMPLETED :
- job_details->status = PRINT_JOB_STATUS_COMPLETED;
- break;
- default:
- job_details->status = PRINT_JOB_STATUS_INVALID;
- }
- job_details->platform_status_flags = jobs[i].state;
-
- // We don't have any details on the number of processed pages here.
- break;
- }
- }
-
- if (found)
- LOG(INFO) << "CP_CUPS: Job details for: " << printer_name <<
- " job_id: " << job_id << " job status: " << job_details->status;
- else
- LOG(WARNING) << "CP_CUPS: Job not found for: " << printer_name <<
- " job_id: " << job_id;
-
- cupsFreeJobs(num_jobs, jobs);
- return found;
-}
-
-bool PrintSystemCUPS::GetPrinterInfo(const std::string& printer_name,
- PrinterBasicInfo* info) {
- DCHECK(info);
-
- LOG(INFO) << "CP_CUPS: Getting printer info for: " << printer_name;
-
+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).
@@ -435,59 +174,27 @@
EnumeratePrinters(&printer_list);
PrinterList::iterator it;
- for (it = printer_list.begin(); it != printer_list.end(); ++it) {
- if (it->printer_name == printer_name) {
- *info = *it;
+ for (it = printer_list.begin(); it != printer_list.end(); ++it)
+ if (it->printer_name == printer_name)
return true;
- }
- }
return false;
}
-bool PrintSystemCUPS::IsValidPrinter(const std::string& printer_name) {
- PrinterBasicInfo info;
- return GetPrinterInfo(printer_name, &info);
-}
-
-PrintSystem::PrintServerWatcher*
-PrintSystemCUPS::CreatePrintServerWatcher() {
- return new PrintServerWatcherCUPS();
-}
-
-PrintSystem::PrinterWatcher* PrintSystemCUPS::CreatePrinterWatcher(
- const std::string& printer_name) {
- DCHECK(!printer_name.empty());
- return new PrinterWatcherCUPS(this, printer_name);
-}
-
-PrintSystem::JobSpooler* PrintSystemCUPS::CreateJobSpooler() {
- return new JobSpoolerCUPS(this);
-}
-
-std::string PrintSystem::GenerateProxyId() {
- // TODO(gene): This code should generate a unique id for proxy. ID should be
- // unique for this user. Rand may return the same number. We'll need to change
- // this in the future.
- std::string id("CP_PROXY_");
- id += base::Uint64ToString(base::RandUint64());
- return id;
-}
-
-scoped_refptr<PrintSystem> PrintSystem::CreateInstance(
- const DictionaryValue* print_system_settings) {
+scoped_refptr<PrintBackend> PrintBackend::CreateInstance(
+ const DictionaryValue* print_backend_settings) {
// Initialize gcrypt library.
- init_gcrypt();
+ Singleton<GcryptInitializer>::get();
std::string print_server_url_str;
- if (print_system_settings) {
- print_system_settings->GetString(
- kCUPSPrintServerURL, &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 PrintSystemCUPS(print_server_url);
+ return new PrintBackendCUPS(print_server_url);
}
-int PrintSystemCUPS::GetDests(cups_dest_t** dests) {
+int PrintBackendCUPS::GetDests(cups_dest_t** dests) {
if (print_server_url_.is_empty()) { // Use default (local) print server.
return cupsGetDests(dests);
} else {
@@ -496,7 +203,7 @@
}
}
-FilePath PrintSystemCUPS::GetPPD(const char* name) {
+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;
@@ -514,61 +221,4 @@
return ppd_path;
}
-int PrintSystemCUPS::PrintFile(const char* name, const char* filename,
- const char* title, int num_options,
- cups_option_t* options) {
- 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_);
- return cupsPrintFile2(http.http(), name, filename,
- title, num_options, options);
- }
-}
-
-int PrintSystemCUPS::GetJobs(cups_job_t** jobs, const char* name,
- int myjobs, int whichjobs) {
- if (print_server_url_.is_empty()) { // Use default (local) print server.
- return cupsGetJobs(jobs, name, myjobs, whichjobs);
- } else {
- HttpConnectionCUPS http(print_server_url_);
- return cupsGetJobs2(http.http(), jobs, name, myjobs, whichjobs);
- }
-}
-
-PlatformJobId PrintSystemCUPS::SpoolPrintJob(
- const std::string& print_ticket,
- const FilePath& print_data_file_path,
- const std::string& print_data_mime_type,
- const std::string& printer_name,
- const std::string& job_title) {
- LOG(INFO) << "CP_CUPS: Spooling print job for: " << printer_name;
-
- // We need to store options as char* string for the duration of the
- // cupsPrintFile2 call. We'll use map here to store options, since
- // Dictionary value from JSON parser returns wchat_t.
- std::map<std::string, std::string> options;
- bool res = ParsePrintTicket(print_ticket, &options);
- DCHECK(res); // If print ticket is invalid we still print using defaults.
-
- std::vector<cups_option_t> cups_options;
- std::map<std::string, std::string>::iterator it;
- for (it = options.begin(); it != options.end(); ++it) {
- cups_option_t opt;
- opt.name = const_cast<char*>(it->first.c_str());
- opt.value = const_cast<char*>(it->second.c_str());
- cups_options.push_back(opt);
- }
-
- int job_id = PrintFile(printer_name.c_str(),
- print_data_file_path.value().c_str(),
- job_title.c_str(),
- cups_options.size(),
- &(cups_options[0]));
-
- LOG(INFO) << "CP_CUPS: Job spooled, id: " << job_id;
-
- return job_id;
-}
-
-} // namespace cloud_print
+} // namespace printing
Property changes on: printing/backend/print_backend_cups.cc
___________________________________________________________________
Added: svn:mergeinfo
« no previous file with comments | « printing/backend/print_backend_consts.cc ('k') | printing/backend/print_backend_dummy.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698