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