This source file includes following definitions.
- Init
- blocking_
- EnumeratePrinters
- GetDefaultPrinterName
- GetPrinterSemanticCapsAndDefaults
- GetPrinterCapsAndDefaults
- GetPrinterDriverInfo
- IsValidPrinter
- CreateInstance
- GetDests
- GetPPD
#include "printing/backend/print_backend.h"
#include "build/build_config.h"
#include <dlfcn.h>
#include <errno.h>
#include <pthread.h>
#if !defined(OS_MACOSX)
#include <gcrypt.h>
#endif
#include "base/debug/leak_annotations.h"
#include "base/file_util.h"
#include "base/lazy_instance.h"
#include "base/logging.h"
#include "base/strings/string_number_conversions.h"
#include "base/synchronization/lock.h"
#include "base/values.h"
#include "printing/backend/cups_helper.h"
#include "printing/backend/print_backend_consts.h"
#include "url/gurl.h"
#if !defined(OS_MACOSX)
GCRY_THREAD_OPTION_PTHREAD_IMPL;
namespace {
class GcryptInitializer {
public:
GcryptInitializer() {
Init();
}
private:
void Init() {
const char* kGnuTlsFiles[] = {
"libgnutls.so.28",
"libgnutls.so.26",
"libgnutls.so",
};
gcry_control(GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread);
for (size_t i = 0; i < arraysize(kGnuTlsFiles); ++i) {
void* gnutls_lib = dlopen(kGnuTlsFiles[i], RTLD_NOW);
if (!gnutls_lib) {
VLOG(1) << "Cannot load " << kGnuTlsFiles[i];
continue;
}
const char* kGnuTlsInitFuncName = "gnutls_global_init";
int (*pgnutls_global_init)(void) = reinterpret_cast<int(*)()>(
dlsym(gnutls_lib, kGnuTlsInitFuncName));
if (!pgnutls_global_init) {
VLOG(1) << "Could not find " << kGnuTlsInitFuncName
<< " in " << kGnuTlsFiles[i];
continue;
}
{
ANNOTATE_SCOPED_MEMORY_LEAK;
if ((*pgnutls_global_init)() != 0)
LOG(ERROR) << "gnutls_global_init() failed";
}
return;
}
LOG(ERROR) << "Cannot find libgnutls";
}
};
base::LazyInstance<GcryptInitializer> g_gcrypt_initializer =
LAZY_INSTANCE_INITIALIZER;
}
#endif
namespace printing {
static const char kCUPSPrinterInfoOpt[] = "printer-info";
static const char kCUPSPrinterStateOpt[] = "printer-state";
static const char kCUPSPrinterTypeOpt[] = "printer-type";
static const char kCUPSPrinterMakeModelOpt[] = "printer-make-and-model";
class PrintBackendCUPS : public PrintBackend {
public:
PrintBackendCUPS(const GURL& print_server_url,
http_encryption_t encryption, bool blocking);
virtual bool EnumeratePrinters(PrinterList* printer_list) OVERRIDE;
virtual std::string GetDefaultPrinterName() OVERRIDE;
virtual bool GetPrinterSemanticCapsAndDefaults(
const std::string& printer_name,
PrinterSemanticCapsAndDefaults* printer_info) OVERRIDE;
virtual bool GetPrinterCapsAndDefaults(
const std::string& printer_name,
PrinterCapsAndDefaults* printer_info) OVERRIDE;
virtual std::string GetPrinterDriverInfo(
const std::string& printer_name) OVERRIDE;
virtual bool IsValidPrinter(const std::string& printer_name) OVERRIDE;
protected:
virtual ~PrintBackendCUPS() {}
private:
int GetDests(cups_dest_t** dests);
base::FilePath GetPPD(const char* name);
GURL print_server_url_;
http_encryption_t cups_encryption_;
bool blocking_;
};
PrintBackendCUPS::PrintBackendCUPS(const GURL& print_server_url,
http_encryption_t encryption,
bool blocking)
: print_server_url_(print_server_url),
cups_encryption_(encryption),
blocking_(blocking) {
}
bool PrintBackendCUPS::EnumeratePrinters(PrinterList* printer_list) {
DCHECK(printer_list);
printer_list->clear();
cups_dest_t* destinations = NULL;
int num_dests = GetDests(&destinations);
if ((num_dests == 0) && (cupsLastError() > IPP_OK_EVENTS_COMPLETE)) {
VLOG(1) << "CUPS: Error getting printers from CUPS server"
<< ", server: " << print_server_url_
<< ", error: " << static_cast<int>(cupsLastError());
return false;
}
for (int printer_index = 0; printer_index < num_dests; ++printer_index) {
const cups_dest_t& printer = destinations[printer_index];
const char* type_str = cupsGetOption(kCUPSPrinterTypeOpt,
printer.num_options, printer.options);
if (type_str != NULL) {
int type;
if (base::StringToInt(type_str, &type) && (type & CUPS_PRINTER_SCANNER))
continue;
}
PrinterBasicInfo printer_info;
printer_info.printer_name = printer.name;
printer_info.is_default = printer.is_default;
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);
const char* drv_info = cupsGetOption(kCUPSPrinterMakeModelOpt,
printer.num_options,
printer.options);
if (drv_info)
printer_info.options[kDriverInfoTagName] = *drv_info;
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);
VLOG(1) << "CUPS: Enumerated printers"
<< ", server: " << print_server_url_
<< ", # of printers: " << printer_list->size();
return true;
}
std::string PrintBackendCUPS::GetDefaultPrinterName() {
cups_dest_t* dests;
int num_dests = GetDests(&dests);
cups_dest_t* dest = cupsGetDest(NULL, NULL, num_dests, dests);
std::string name = dest ? std::string(dest->name) : std::string();
cupsFreeDests(num_dests, dests);
return name;
}
bool PrintBackendCUPS::GetPrinterSemanticCapsAndDefaults(
const std::string& printer_name,
PrinterSemanticCapsAndDefaults* printer_info) {
PrinterCapsAndDefaults info;
if (!GetPrinterCapsAndDefaults(printer_name, &info) )
return false;
return ParsePpdCapabilities(
printer_name, info.printer_capabilities, printer_info);
}
bool PrintBackendCUPS::GetPrinterCapsAndDefaults(
const std::string& printer_name,
PrinterCapsAndDefaults* printer_info) {
DCHECK(printer_info);
VLOG(1) << "CUPS: Getting caps and defaults"
<< ", printer name: " << printer_name;
base::FilePath ppd_path(GetPPD(printer_name.c_str()));
if (ppd_path.empty()) {
LOG(ERROR) << "CUPS: Failed to get PPD"
<< ", printer name: " << printer_name;
return false;
}
std::string content;
bool res = base::ReadFileToString(ppd_path, &content);
base::DeleteFile(ppd_path, false);
if (res) {
printer_info->printer_capabilities.swap(content);
printer_info->caps_mime_type = "application/pagemaker";
printer_info->printer_defaults.clear();
printer_info->defaults_mime_type.clear();
}
return res;
}
std::string PrintBackendCUPS::GetPrinterDriverInfo(
const std::string& printer_name) {
cups_dest_t* destinations = NULL;
int num_dests = GetDests(&destinations);
std::string result;
for (int printer_index = 0; printer_index < num_dests; ++printer_index) {
const cups_dest_t& printer = destinations[printer_index];
if (printer_name == printer.name) {
const char* info = cupsGetOption(kCUPSPrinterMakeModelOpt,
printer.num_options,
printer.options);
if (info)
result = *info;
}
}
cupsFreeDests(num_dests, destinations);
return result;
}
bool PrintBackendCUPS::IsValidPrinter(const std::string& printer_name) {
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 base::DictionaryValue* print_backend_settings) {
#if !defined(OS_MACOSX)
g_gcrypt_initializer.Get();
#endif
std::string print_server_url_str, cups_blocking;
int encryption = HTTP_ENCRYPT_NEVER;
if (print_backend_settings) {
print_backend_settings->GetString(kCUPSPrintServerURL,
&print_server_url_str);
print_backend_settings->GetString(kCUPSBlocking,
&cups_blocking);
print_backend_settings->GetInteger(kCUPSEncryption, &encryption);
}
GURL print_server_url(print_server_url_str.c_str());
return new PrintBackendCUPS(print_server_url,
static_cast<http_encryption_t>(encryption),
cups_blocking == kValueTrue);
}
int PrintBackendCUPS::GetDests(cups_dest_t** dests) {
if (print_server_url_.is_empty()) {
return cupsGetDests(dests);
} else {
HttpConnectionCUPS http(print_server_url_, cups_encryption_);
http.SetBlocking(blocking_);
return cupsGetDests2(http.http(), dests);
}
}
base::FilePath PrintBackendCUPS::GetPPD(const char* name) {
CR_DEFINE_STATIC_LOCAL(base::Lock, ppd_lock, ());
base::AutoLock ppd_autolock(ppd_lock);
base::FilePath ppd_path;
const char* ppd_file_path = NULL;
if (print_server_url_.is_empty()) {
ppd_file_path = cupsGetPPD(name);
if (ppd_file_path)
ppd_path = base::FilePath(ppd_file_path);
} else {
HttpConnectionCUPS http(print_server_url_, cups_encryption_);
http.SetBlocking(blocking_);
ppd_file_path = cupsGetPPD2(http.http(), name);
if (ppd_file_path) {
ppd_path = base::FilePath(ppd_file_path);
ipp_status_t error_code = cupsLastError();
int http_error = httpError(http.http());
if (error_code > IPP_OK_EVENTS_COMPLETE || http_error != 0) {
LOG(ERROR) << "Error downloading PPD file"
<< ", name: " << name
<< ", CUPS error: " << static_cast<int>(error_code)
<< ", HTTP error: " << http_error;
base::DeleteFile(ppd_path, false);
ppd_path.clear();
}
}
}
return ppd_path;
}
}