Skip to content

Commit

Permalink
posix: new method getPrinter, getJob, setJob. Added jobs in printer info
Browse files Browse the repository at this point in the history
  • Loading branch information
tojocky committed Jun 15, 2014
1 parent 4720f99 commit 610d8bd
Show file tree
Hide file tree
Showing 6 changed files with 294 additions and 86 deletions.
3 changes: 3 additions & 0 deletions examples/getSupportedJobCommands.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
var printer = require("../lib"), //=require('pritner')
util = require('util');
console.log("supported job commands:\n"+util.inspect(printer.getSupportedJobCommands(), {colors:true, depth:10}));
18 changes: 16 additions & 2 deletions lib/printer.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,30 @@ var printer_helper = {}

printer_helper = require('../build/Release/node_printer.node');

/** Return all installed printers including active jobs
*/
module.exports.getPrinters = getPrinters;

/** send data to printer
*/
module.exports.printDirect = printDirect
module.exports.getSupportedFormats = printer_helper.getSupportedFormats;

/** Get supported print format for printDirect
*/
module.exports.getSupportedPrintFormats = printer_helper.getSupportedPrintFormats;

/**
* Get possible job command for setJob. It depends on os.
* @return Array of string. e.g.: DELETE, PAUSE, RESUME
*/
module.exports.getJobCommands = printer_helper.getJobCommands;
module.exports.getSupportedJobCommands = printer_helper.getSupportedJobCommands;

/** get printer info object. It includes all active jobs
*/
module.exports.getPrinter = getPrinter;

/** get printer job info object
*/
module.exports.getJob = getJob;
module.exports.setJob = setJob;

Expand Down
4 changes: 2 additions & 2 deletions src/node_printer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ void initNode(v8::Handle<v8::Object> exports) {
NODE_SET_METHOD(exports, "getJob", getJob);
NODE_SET_METHOD(exports, "setJob", setJob);
NODE_SET_METHOD(exports, "printDirect", PrintDirect);
NODE_SET_METHOD(exports, "getSupportedFormats", getSupportedFormats);
NODE_SET_METHOD(exports, "getJobCommands", getJobCommands);
NODE_SET_METHOD(exports, "getSupportedPrintFormats", getSupportedPrintFormats);
NODE_SET_METHOD(exports, "getSupportedJobCommands", getSupportedJobCommands);

}

Expand Down
18 changes: 12 additions & 6 deletions src/node_printer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,16 +24,23 @@ v8::Handle<v8::Value> PrintDirect(const v8::Arguments& iArgs);
v8::Handle<v8::Value> getPrinters(const v8::Arguments& iArgs);

/** Retrieve printer info and jobs
* @param printer name String
*/
v8::Handle<v8::Value> getPrinter(const v8::Arguments& iArgs);

/** Retrieve job info
* @param printer name String
* @param job id Number
*/
v8::Handle<v8::Value> getJob(const v8::Arguments& iArgs);

//TODO
/** Set job command.
* Possible command:
* arguments:
* @param printer name String
* @param job id Number
* @param job command String
* Possible commands:
* "CANCEL"
* "PAUSE"
* "RESTART"
Expand All @@ -46,15 +53,14 @@ v8::Handle<v8::Value> getJob(const v8::Arguments& iArgs);
*/
v8::Handle<v8::Value> setJob(const v8::Arguments& iArgs);

/** Get Supported format array depends on the system
/** Get supported print formats for printDirect. It depends on platform
*/
v8::Handle<v8::Value> getSupportedFormats(const v8::Arguments& iArgs);
v8::Handle<v8::Value> getSupportedPrintFormats(const v8::Arguments& iArgs);

/** Get Supported format array depends on the system
/** Get supported job commands for setJob method
*/
v8::Handle<v8::Value> getJobCommands(const v8::Arguments& iArgs);
v8::Handle<v8::Value> getSupportedJobCommands(const v8::Arguments& iArgs);

//TODO:
// to see if the printer is already printing
// optional ability to get printer spool
#endif
265 changes: 223 additions & 42 deletions src/node_printer_posix.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,101 @@

#include <cups/cups.h>

v8::Handle<v8::Value> getPrinters(const v8::Arguments& iArgs)
namespace
{
v8::HandleScope scope;
typedef std::map<std::string, int> StatusMapType;
typedef std::map<std::string, std::string> FormatMap;

cups_dest_t *printers = NULL, *printer = NULL;
int printers_size = cupsGetDests(&printers);
v8::Local<v8::Array> result = v8::Array::New(printers_size);
int i, j;
for(i = 0, printer = printers; i < printers_size; ++i, ++printer)
const StatusMapType& getJobStatusMap()
{
static StatusMapType result;
if(!result.empty())
{
return result;
}
// add only first time
#define STATUS_PRINTER_ADD(value, type) result.insert(std::make_pair(value, type))
// Common statuses
STATUS_PRINTER_ADD("PRINTING", IPP_JOB_PROCESSING);
STATUS_PRINTER_ADD("PRINTED", IPP_JOB_COMPLETED);
STATUS_PRINTER_ADD("PAUSED", IPP_JOB_HELD);
// Specific statuses
STATUS_PRINTER_ADD("PENDING", IPP_JOB_PENDING);
STATUS_PRINTER_ADD("PAUSED", IPP_JOB_STOPPED);
STATUS_PRINTER_ADD("CANCELLED", IPP_JOB_CANCELLED);
STATUS_PRINTER_ADD("ABORTED", IPP_JOB_ABORTED);

#undef STATUS_PRINTER_ADD
return result;
}

const FormatMap& getPrinterFormatMap()
{
static FormatMap result;
if(!result.empty())
{
return result;
}
result.insert(std::make_pair("RAW", CUPS_FORMAT_RAW));
result.insert(std::make_pair("TEXT", CUPS_FORMAT_TEXT));
result.insert(std::make_pair("PDF", CUPS_FORMAT_PDF));
result.insert(std::make_pair("JPEG", CUPS_FORMAT_JPEG));
result.insert(std::make_pair("POSTSCRIPT", CUPS_FORMAT_POSTSCRIPT));
result.insert(std::make_pair("COMMAND", CUPS_FORMAT_COMMAND));
result.insert(std::make_pair("AUTO", CUPS_FORMAT_AUTO));
return result;
}

void parseJobObject(const cups_job_t *job, v8::Handle<v8::Object> result_printer_job)
{
//Common fields
result_printer_job.Set(v8::String::NewSymbol("id"), v8::Number::New(job->id));
result_printer_job.Set(v8::String::NewSymbol("name"), v8::String::New(job->title));
result_printer_job.Set(v8::String::NewSymbol("printerName"), v8::String::New(job->dest));
result_printer_job.Set(v8::String::NewSymbol("user"), v8::String::New(job->user));
std::string job_format(job->format);

// Try to parse the data format, otherwise will write the unformatted one
for(FormatMap::const_ietartor itFormat = getPrinterFormatMap().begin(); itFormat != getPrinterFormatMap().end(); ++itFormat)
{
if(itFormat->second == job_format)
{
job_format = itFormat->first;
break;
}
}

result_printer_job.Set(v8::String::NewSymbol("format"), v8::String::New(job_format.c_str()));
result_printer_job.Set(v8::String::NewSymbol("priority"), v8::Number::New(job->priority));
result_printer_job.Set(v8::String::NewSymbol("size"), v8::Number::New(job->size));
v8::Local<v8::Array> result_printer_job_status = v8::Array::New();
int i_status = 0;
for(StatusMapType::const_iterator itStatus = getJobStatusMap().begin(); itStatus != getJobStatusMap().end(); ++itStatus)
{
if(job->state == itStatus->second)
{
result_printer_job_status->Set(i_status++, v8::String::New(itStatus->first.c_str()));
// only one status could be on posix
break;
}
}
if(i_status == 0)
{
// A new status? encode as it is
result_printer_job_status.Set(i_status++, v8::String::New(job->state));
}

result_printer_job.Set(v8::String::NewSymbol("status"), result_printer_job_status);

//Specific fields
// Ecmascript store time in milliseconds, but time_t in seconds
result_printer_job.Set(v8::String::NewSymbol("completedTime"), job->completed_time*1000);
result_printer_job.Set(v8::String::NewSymbol("creationTime"), job->creation_time*1000);
result_printer_job.Set(v8::String::NewSymbol("processingTime"), job->processing_time*1000);
}

void parsePrinterInfo(const cups_dest_t * printer, v8::Handle<v8::Object> result_printer)
{
v8::Local<v8::Object> result_printer = v8::Object::New();
result_printer->Set(v8::String::NewSymbol("name"), v8::String::New(printer->name));
result_printer->Set(v8::String::NewSymbol("isDefault"), v8::Boolean::New(static_cast<bool>(printer->is_default)));

Expand All @@ -29,23 +113,143 @@ v8::Handle<v8::Value> getPrinters(const v8::Arguments& iArgs)
result_printer_options->Set(v8::String::NewSymbol(dest_option->name), v8::String::New(dest_option->value));
}
result_printer->Set(v8::String::NewSymbol("options"), result_printer_options);
// Get printer jobs
cups_job_t * jobs;
int totalJobs = cupsGetJobs(&jobs, printer->name, 0 /*0 means all users*/, CUPS_WHICHJOBS_ACTIVE);
if(totalJobs > 0)
{
v8::Local<v8::Array> result_priner_jobs = v8::Array::New(printers_size);
int jobi =0;
cups_job_t * job = jobs;
for(; jobi < totalJobs; ++jobi, ++job)
{
v8::Local<v8::Object> result_printer_job = v8::Object::New();
parseJobObject(job, result_printer_job);
result_priner_jobs.Set(jobi, result_printer_job);
}
result_printer->Set(v8::String::NewSymbol("jobs"), result_priner_jobs);
}
cupsFreeJobs(totalJobs, jobs);
}
}

v8::Handle<v8::Value> getPrinters(const v8::Arguments& iArgs)
{
v8::HandleScope scope;

cups_dest_t *printers = NULL, *printer = NULL;
int printers_size = cupsGetDests(&printers);
v8::Local<v8::Array> result = v8::Array::New(printers_size);
int i, j;
for(i = 0, printer = printers; i < printers_size; ++i, ++printer)
{
v8::Local<v8::Object> result_printer = v8::Object::New();
parsePrinterInfo(printer, result_printer);
result->Set(i, result_printer);
}
cupsFreeDests(printers_size, printers);
return scope.Close(result);
}

v8::Handle<v8::Value> getSupportedFormats(const v8::Arguments& iArgs) {
v8::Handle<v8::Value> getPrinter(const v8::Arguments& iArgs)
{
v8::HandleScope scope;
REQUIRE_ARGUMENTS(iArgs, 1);
REQUIRE_ARGUMENT_STRING(iArgs, 0, printername);

cups_dest_t *printers = NULL, *printer = NULL;
int printers_size = cupsGetDests(&printers);
printer = cupsGetDest(*printername, NULL, printers_size, printers);
v8::Local<v8::Object> result_printer = v8::Object::New();
if(printer != NULL)
{
parsePrinterInfo(printer, result_printer);
}
cupsFreeDests(printers_size, printers);
if(printer == NULL)
{
// printer not found
RETURN_EXCEPTION_STR("Printer not found");
}
return scope.Close(result_printer);
}

v8::Handle<v8::Value> getJob(const v8::Arguments& iArgs)
{
v8::HandleScope scope;
REQUIRE_ARGUMENTS(iArgs, 2);
REQUIRE_ARGUMENT_STRING(iArgs, 0, printername);
REQUIRE_ARGUMENT_INTEGER(iArgs, 1, jobId);

v8::Local<v8::Object> result_printer_job = v8::Object::New();
// Get printer jobs
cups_job_t *jobs = NULL, *jobFound = NULL;
int totalJobs = cupsGetJobs(&jobs, printername, 0 /*0 means all users*/, CUPS_WHICHJOBS_ALL);
if(totalJobs > 0)
{
int jobi =0;
cups_job_t * job = jobs;
for(; jobi < totalJobs; ++jobi, ++job)
{
if(job->id != jobId)
{
continue;
}
// Job Found
jobFound = job;
parseJobObject(job, result_printer_job);
break;
}
}
cupsFreeJobs(totalJobs, jobs);
if(jobFound == NULL)
{
// printer not found
RETURN_EXCEPTION_STR("Printer job not found");
}
return scope.Close(result_printer_job);
}

v8::Handle<v8::Value> setJob(const v8::Arguments& iArgs)
{
v8::HandleScope scope;
REQUIRE_ARGUMENTS(iArgs, 3);
REQUIRE_ARGUMENT_STRINGW(iArgs, 0, printername);
REQUIRE_ARGUMENT_INTEGER(iArgs, 1, jobId);
REQUIRE_ARGUMENT_STRING(iArgs, 2, jobCommandV8);
if(jobId < 0)
{
RETURN_EXCEPTION_STR("Wrong job number");
}
std::string jobCommandStr(*jobCommandV8);
bool result_ok = false;
if(jobCommandStr == 'CANCEL')
{
result_ok = (cupsCancelJob(*printername, jobId) == 1);
}
else
{
RETURN_EXCEPTION_STR("wrong job command. use getSupportedJobCommands to see the possible commands");
}
return scope.Close(v8::Boolean::New(result_ok));
}

v8::Handle<v8::Value> getSupportedJobCommands(const v8::Arguments& iArgs) {
v8::HandleScope scope;
v8::Local<v8::Array> result = v8::Array::New();
int i = 0;
result->Set(i++, v8::String::New("CANCEL"));
return scope.Close(result);
}

v8::Handle<v8::Value> getSupportedPrintFormats(const v8::Arguments& iArgs) {
v8::HandleScope scope;
v8::Local<v8::Array> result = v8::Array::New();
int i = 0;
result->Set(i++, v8::String::New("RAW"));
result->Set(i++, v8::String::New("TEXT"));
result->Set(i++, v8::String::New("PDF"));
result->Set(i++, v8::String::New("JPEG"));
result->Set(i++, v8::String::New("POSTSCRIPT"));
result->Set(i++, v8::String::New("COMMAND"));
result->Set(i++, v8::String::New("AUTO"));
for(FormatMap::const_ietartor itFormat = getPrinterFormatMap().begin(); itFormat != getPrinterFormatMap().end(); ++itFormat)
{
result->Set(i++, v8::String::New(itFormat->first.c_str()));
}
return scope.Close(result);
}

Expand Down Expand Up @@ -81,33 +285,10 @@ v8::Handle<v8::Value> PrintDirect(const v8::Arguments& iArgs) {
REQUIRE_ARGUMENT_STRING(iArgs, 2, docname);
REQUIRE_ARGUMENT_STRING(iArgs, 3, type);
std::string type_str(*type);
if(type_str == "RAW")
{
type_str = CUPS_FORMAT_RAW;
}
else if (type_str == "TEXT")
{
type_str = CUPS_FORMAT_TEXT;
}
else if (type_str == "PDF")
{
type_str = CUPS_FORMAT_PDF;
}
else if (type_str == "JPEG")
{
type_str = CUPS_FORMAT_JPEG;
}
else if (type_str == "POSTSCRIPT")
{
type_str = CUPS_FORMAT_POSTSCRIPT;
}
else if (type_str == "COMMAND")
{
type_str = CUPS_FORMAT_COMMAND;
}
else if (type_str == "AUTO")
FormatMap::const_ietartor itFormat = getPrinterFormatMap().find(type_str);
if(itFormat == getPrinterFormatMap().end())
{
type_str = CUPS_FORMAT_AUTO;
type_str = itFormat->second;
}
else
{
Expand Down
Loading

0 comments on commit 610d8bd

Please sign in to comment.