* Copyright 2008 Haiku Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Julun, <host.haiku@gmx.de
*/
#include <Printer.h>
#include <FindDirectory.h>
#include <NodeInfo.h>
#include <NodeMonitor.h>
#include <new>
namespace BPrivate {
namespace Print {
#define PSRV_PRINTER_MIMETYPE "application/x-vnd.Be.printer"
#define PSRV_PRINTER_ATTR_STATE "state"
#define PSRV_PRINTER_ATTR_COMMENTS "Comments"
#define PSRV_PRINTER_ATTR_TRANSPORT "transport"
#define PSRV_PRINTER_ATTR_DRIVER_NAME "Driver Name"
#define PSRV_PRINTER_ATTR_PRINTER_NAME "Printer Name"
#define PSRV_PRINTER_ATTR_DEFAULT_PRINTER "Default Printer"
#define PSRV_PRINTER_ATTR_TRANSPORT_ADDRESS "transport_address"
#define PSRV_FIELD_CURRENT_PRINTER "current_printer"
BPrinter::BPrinter()
: fListener(NULL)
{
memset(&fPrinterEntryRef, 0, sizeof(entry_ref));
}
BPrinter::BPrinter(const BEntry& entry)
: fListener(NULL)
{
SetTo(entry);
}
BPrinter::BPrinter(const BPrinter& printer)
{
*this = printer;
}
BPrinter::BPrinter(const node_ref& nodeRef)
: fListener(NULL)
{
SetTo(nodeRef);
}
BPrinter::BPrinter(const entry_ref& entryRef)
: fListener(NULL)
, fPrinterEntryRef(entryRef)
{
}
BPrinter::BPrinter(const BDirectory& directory)
: fListener(NULL)
{
SetTo(directory);
}
BPrinter::~BPrinter()
{
StopWatching();
}
status_t
BPrinter::SetTo(const BEntry& entry)
{
StopWatching();
entry.GetRef(&fPrinterEntryRef);
return InitCheck();
}
status_t
BPrinter::SetTo(const node_ref& nodeRef)
{
SetTo(BDirectory(&nodeRef));
return InitCheck();
}
status_t
BPrinter::SetTo(const entry_ref& entryRef)
{
StopWatching();
fPrinterEntryRef = entryRef;
return InitCheck();
}
status_t
BPrinter::SetTo(const BDirectory& directory)
{
StopWatching();
BEntry entry;
directory.GetEntry(&entry);
entry.GetRef(&fPrinterEntryRef);
return InitCheck();
}
void
BPrinter::Unset()
{
StopWatching();
memset(&fPrinterEntryRef, 0, sizeof(entry_ref));
}
bool
BPrinter::IsValid() const
{
BDirectory spoolDir(&fPrinterEntryRef);
if (spoolDir.InitCheck() != B_OK)
return false;
BNode node(spoolDir);
char type[B_MIME_TYPE_LENGTH];
BNodeInfo(&node).GetType(type);
if (strcmp(type, PSRV_PRINTER_MIMETYPE) != 0)
return false;
return true;
}
status_t
BPrinter::InitCheck() const
{
BDirectory spoolDir(&fPrinterEntryRef);
return spoolDir.InitCheck();
}
bool
BPrinter::IsFree() const
{
return (State() == "free");
}
bool
BPrinter::IsDefault() const
{
bool isDefault = false;
BDirectory spoolDir(&fPrinterEntryRef);
if (spoolDir.InitCheck() == B_OK)
spoolDir.ReadAttr(PSRV_PRINTER_ATTR_DEFAULT_PRINTER, B_BOOL_TYPE, 0,
&isDefault, sizeof(bool));
return isDefault;
}
bool
BPrinter::IsShareable() const
{
if (Name() == "Preview")
return true;
return false;
}
BString
BPrinter::Name() const
{
return _ReadAttribute(PSRV_PRINTER_ATTR_PRINTER_NAME);
}
BString
BPrinter::State() const
{
return _ReadAttribute(PSRV_PRINTER_ATTR_STATE);
}
BString
BPrinter::Driver() const
{
return _ReadAttribute(PSRV_PRINTER_ATTR_DRIVER_NAME);
}
BString
BPrinter::Comments() const
{
return _ReadAttribute(PSRV_PRINTER_ATTR_COMMENTS);
}
BString
BPrinter::Transport() const
{
return _ReadAttribute(PSRV_PRINTER_ATTR_TRANSPORT);
}
BString
BPrinter::TransportAddress() const
{
return _ReadAttribute(PSRV_PRINTER_ATTR_TRANSPORT_ADDRESS);
}
status_t
BPrinter::DefaultSettings(BMessage& settings)
{
status_t status = B_ERROR;
image_id id = _LoadDriver();
if (id < 0)
return status;
typedef BMessage* (*default_settings_func_t)(BNode*);
default_settings_func_t default_settings;
if (get_image_symbol(id, "default_settings", B_SYMBOL_TYPE_TEXT
, (void**)&default_settings) == B_OK) {
BNode printerNode(&fPrinterEntryRef);
BMessage *newSettings = default_settings(&printerNode);
if (newSettings) {
status = B_OK;
settings = *newSettings;
_AddPrinterName(settings);
}
delete newSettings;
}
unload_add_on(id);
return status;
}
status_t
BPrinter::StartWatching(const BMessenger& listener)
{
StopWatching();
if (!listener.IsValid())
return B_BAD_VALUE;
fListener = new(std::nothrow) BMessenger(listener);
if (!fListener)
return B_NO_MEMORY;
node_ref nodeRef;
nodeRef.device = fPrinterEntryRef.device;
nodeRef.node = fPrinterEntryRef.directory;
return watch_node(&nodeRef, B_WATCH_DIRECTORY, *fListener);
}
void
BPrinter::StopWatching()
{
if (fListener) {
stop_watching(*fListener);
delete fListener;
fListener = NULL;
}
}
BPrinter&
BPrinter::operator=(const BPrinter& printer)
{
if (this != &printer) {
Unset();
fPrinterEntryRef = printer.fPrinterEntryRef;
if (printer.fListener)
StartWatching(*printer.fListener);
}
return *this;
}
bool
BPrinter::operator==(const BPrinter& printer) const
{
return (fPrinterEntryRef == printer.fPrinterEntryRef);
}
bool
BPrinter::operator!=(const BPrinter& printer) const
{
return (fPrinterEntryRef != printer.fPrinterEntryRef);
}
status_t
BPrinter::_Configure() const
{
status_t status = B_ERROR;
image_id id = _LoadDriver();
if (id < 0)
return status;
BString printerName(_ReadAttribute(PSRV_PRINTER_ATTR_PRINTER_NAME));
if (printerName.Length() > 0) {
typedef char* (*add_printer_func_t)(const char*);
add_printer_func_t add_printer;
if (get_image_symbol(id, "add_printer", B_SYMBOL_TYPE_TEXT
, (void**)&add_printer) == B_OK) {
if (add_printer(printerName.String()) != NULL)
status = B_OK;
}
} else {
status = B_ERROR;
}
unload_add_on(id);
return status;
}
status_t
BPrinter::_ConfigureJob(BMessage& settings)
{
status_t status = B_ERROR;
image_id id = _LoadDriver();
if (id < 0)
return status;
typedef BMessage* (*config_job_func_t)(BNode*, const BMessage*);
config_job_func_t configure_job;
if (get_image_symbol(id, "config_job", B_SYMBOL_TYPE_TEXT
, (void**)&configure_job) == B_OK) {
BNode printerNode(&fPrinterEntryRef);
BMessage *newSettings = configure_job(&printerNode, &settings);
if (newSettings && (newSettings->what == 'okok')) {
status = B_OK;
settings = *newSettings;
_AddPrinterName(settings);
}
delete newSettings;
}
unload_add_on(id);
return status;
}
status_t
BPrinter::_ConfigurePage(BMessage& settings)
{
status_t status = B_ERROR;
image_id id = _LoadDriver();
if (id < 0)
return status;
typedef BMessage* (*config_page_func_t)(BNode*, const BMessage*);
config_page_func_t configure_page;
if (get_image_symbol(id, "config_page", B_SYMBOL_TYPE_TEXT
, (void**)&configure_page) == B_OK) {
BNode printerNode(&fPrinterEntryRef);
BMessage *newSettings = configure_page(&printerNode, &settings);
if (newSettings && (newSettings->what == 'okok')) {
status = B_OK;
settings = *newSettings;
_AddPrinterName(settings);
}
delete newSettings;
}
unload_add_on(id);
return status;
}
BPath
BPrinter::_DriverPath() const
{
BString driverName(_ReadAttribute(PSRV_PRINTER_ATTR_DRIVER_NAME));
if (driverName.Length() <= 0)
return BPath();
directory_which directories[] = {
B_USER_NONPACKAGED_ADDONS_DIRECTORY,
B_USER_ADDONS_DIRECTORY,
B_SYSTEM_NONPACKAGED_ADDONS_DIRECTORY,
B_SYSTEM_ADDONS_DIRECTORY
};
BPath path;
driverName.Prepend("Print/");
for (int32 i = 0; i < sizeof(directories) / sizeof(directories[0]); ++i) {
if (find_directory(directories[i], &path) == B_OK) {
path.Append(driverName.String());
BEntry driver(path.Path());
if (driver.InitCheck() == B_OK && driver.Exists() && driver.IsFile())
return path;
}
}
return BPath();
}
image_id
BPrinter::_LoadDriver() const
{
BPath driverPath(_DriverPath());
if (driverPath.InitCheck() != B_OK)
return -1;
return load_add_on(driverPath.Path());
}
void
BPrinter::_AddPrinterName(BMessage& settings)
{
settings.RemoveName(PSRV_FIELD_CURRENT_PRINTER);
settings.AddString(PSRV_FIELD_CURRENT_PRINTER, Name());
}
BString
BPrinter::_ReadAttribute(const char* attribute) const
{
BString value;
BDirectory spoolDir(&fPrinterEntryRef);
if (spoolDir.InitCheck() == B_OK)
spoolDir.ReadAttrString(attribute, &value);
return value;
}
}
}