#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"
#include "ppport.h"
#include <cups/cups.h>
/*#include <cups/backend.h>*/
#include <cups/http.h>
#include <cups/image.h>
#include <cups/ipp.h>
#include <cups/ppd.h>
#include <cups/file.h>
#include <cups/dir.h>
#include <cups/language.h>
#include <cups/transcode.h>
#include <cups/adminutil.h>
#include "const-c.inc"
#include "packer.c"
static SV *password_cb = (SV*) NULL;
const char *
password_cb_wrapper(const char *prompt)
{
/* This variable will show up as unused on certain platforms. */
STRLEN n_a;
static char password[255] = { '\0' };
if (! password_cb)
return NULL;
dSP;
ENTER;
SAVETMPS;
PUSHMARK(SP);
XPUSHs(sv_2mortal(newSVpv(prompt, 0)));
PUTBACK;
call_sv(password_cb, G_SCALAR);
SPAGAIN;
strncpy(password, POPpx, 254);
PUTBACK;
FREETMPS;
LEAVE;
return password;
}
MODULE = Net::CUPS PACKAGE = Net::CUPS
PROTOTYPES: DISABLE
INCLUDE: const-xs.inc
const char*
NETCUPS_getServer()
CODE:
RETVAL = cupsServer();
OUTPUT:
RETVAL
const char*
NETCUPS_getUsername()
CODE:
RETVAL = cupsUser();
OUTPUT:
RETVAL
void
NETCUPS_setServer( name )
const char* name;
CODE:
cupsSetServer( name );
void
NETCUPS_setUsername( username )
const char* username;
CODE:
cupsSetUser( username );
void
NETCUPS_setPasswordCB( callback )
SV* callback;
CODE:
if( password_cb == (SV*) NULL )
{
password_cb = newSVsv( callback );
cupsSetPasswordCB( password_cb_wrapper );
}
else
{
SvSetSV( password_cb, callback );
}
const char*
NETCUPS_getPassword( prompt )
const char* prompt;
CODE:
RETVAL = cupsGetPassword( prompt );
OUTPUT:
RETVAL
void
NETCUPS_getDestination( name )
char* name;
PPCODE:
cups_dest_t * destinations = NULL;
cups_dest_t * destination = NULL;
int count = 0;
SV* rv = NULL;
count = cupsGetDests( &destinations );
/* If we have a NULL for destination name, then we are going
to assume we want the default. */
if( !strlen( name ) )
{
name = cupsGetDefault();
}
destination = cupsGetDest( name, NULL, count, destinations );
rv = sv_newmortal();
sv_setref_pv( rv, "Net::CUPS::Destination", destination );
XPUSHs( rv );
XSRETURN( 1 );
void
NETCUPS_getDestinations()
PPCODE:
cups_dest_t * destinations = NULL;
int count = 0;
int loop = 0;
SV* rv = NULL;
count = cupsGetDests( &destinations );
for( loop = 0; loop < count; loop++ )
{
rv = sv_newmortal();
sv_setref_pv( rv, "Net::CUPS::Destination", &destinations[loop] );
XPUSHs( rv );
}
XSRETURN( count );
ppd_file_t*
NETCUPS_getPPD( name )
const char* name;
INIT:
const char* filename = NULL;
CODE:
filename = cupsGetPPD( name );
RETVAL = ppdOpenFile( filename );
OUTPUT:
RETVAL
void
NETCUPS_requestData( request, resource, filename )
ipp_t* request;
const char* resource;
const char* filename;
PPCODE:
http_t* http = NULL;
ipp_t* response = NULL;
const char* server = NULL;
SV* rv = NULL;
int port;
server = cupsServer();
port = ippPort();
httpInitialize();
http = httpConnect( server, port );
if( strlen( filename ) == 0 )
filename = NULL;
response = cupsDoFileRequest( http, request, resource, filename );
rv = sv_newmortal();
sv_setref_pv( rv, "Net::CUPS::IPP", response );
XPUSHs( rv );
httpClose( http );
XSRETURN( 1 );
void
NETCUPS_getPPDMakes()
http_t *http; /* HTTP object */
ipp_t *request; /* IPP request object */
ipp_t *response; /* IPP response object */
ipp_attribute_t *attr; /* Current IPP attribute */
PPCODE:
SV* rv = NULL;
int count = 0;
cups_lang_t *language;
language = cupsLangDefault();
http = httpConnectEncrypt(cupsServer(), ippPort(), cupsEncryption());
request = ippNewRequest(CUPS_GET_PPDS);
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
"attributes-charset", NULL, "utf-8");
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
"attributes-natural-language", NULL, language->language);
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
"requested-attributes", NULL, "ppd-make");
response = cupsDoRequest(http, request, "/");
if (response != NULL) {
attr = ippFindAttribute(response, "ppd-make", IPP_TAG_TEXT);
rv = sv_newmortal();
sv_setpv(rv, attr->values[0].string.text);
XPUSHs(rv);
count++;
while (attr != NULL) {
attr = ippFindNextAttribute(response, "ppd-make", IPP_TAG_TEXT);
if (attr == NULL) {
break;
}
rv = sv_newmortal();
sv_setpv(rv, attr->values[0].string.text);
XPUSHs(rv);
count++;
}
ippDelete(response);
httpClose(http);
}
else {
XSRETURN ( 0 );
}
XSRETURN( count );
void
NETCUPS_getAllPPDs ()
http_t *http; /* HTTP object */
ipp_t *request; /* IPP request object */
ipp_t *response; /* IPP response object */
ipp_attribute_t *attr; /* Current IPP attribute */
PPCODE:
SV* rv = NULL;
int count = 0;
cups_lang_t *language;
language = cupsLangDefault();
http = httpConnectEncrypt(cupsServer(), ippPort(), cupsEncryption());
request = ippNewRequest(CUPS_GET_PPDS);
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
"attributes-charset", NULL, "utf-8");
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
"attributes-natural-language", NULL, language->language);
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
"requested-attributes", NULL, "ppd-make-and-model");
response = cupsDoRequest(http, request, "/");
if (response != NULL) {
attr = ippFindAttribute(response,
"ppd-make-and-model",
IPP_TAG_TEXT);
rv = sv_newmortal();
sv_setpv(rv, attr->values[0].string.text);
XPUSHs(rv);
count++;
while (attr != NULL) {
attr = ippFindNextAttribute(response,
"ppd-make-and-model",
IPP_TAG_TEXT);
if (attr == NULL) {
break;
}
rv = sv_newmortal();
sv_setpv(rv, attr->values[0].string.text);
XPUSHs(rv);
count++;
}
ippDelete(response);
httpClose(http);
}
else {
XSRETURN ( 0 );
}
XSRETURN( count );
void
NETCUPS_deleteDestination( destination );
const char* destination;
PPCODE:
ipp_t *request;
http_t *http;
char uri[HTTP_MAX_URI];
httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
cupsServer(), 0, "/printers/%s", destination);
http = httpConnectEncrypt(cupsServer(), ippPort(), cupsEncryption());
request = ippNewRequest(CUPS_DELETE_PRINTER);
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
NULL, uri);
ippDelete(cupsDoRequest(http, request, "/admin/"));
void
NETCUPS_addDestination(name, location, printer_info, ppd_name, device_uri);
const char* name;
const char* location;
const char* printer_info;
const char* ppd_name;
const char* device_uri;
PPCODE:
http_t *http = NULL; /* HTTP object */
ipp_t *request = NULL; /* IPP request object */
char uri[HTTP_MAX_URI]; /* Job URI */
http = httpConnectEncrypt(cupsServer(), ippPort(), cupsEncryption());
request = ippNewRequest(CUPS_ADD_PRINTER);
httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
cupsServer(), 0, "/printers/%s", name);
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
NULL, uri);
ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-location",
NULL, location);
ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-info",
NULL, printer_info );
ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_NAME, "ppd-name",
NULL, ppd_name);
strncpy(uri, device_uri, sizeof(uri));
ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_URI, "device-uri",
NULL, uri);
ippAddBoolean(request, IPP_TAG_PRINTER, "printer-is-accepting-jobs", 1);
ippAddInteger(request, IPP_TAG_PRINTER, IPP_TAG_ENUM, "printer-state",
IPP_PRINTER_IDLE);
ippDelete(cupsDoRequest(http, request, "/admin/"));
void
NETCUPS_getPPDFileName(ppdfilename);
const char* ppdfilename;
PPCODE:
http_t *http; /* HTTP object */
ipp_t *request; /* IPP request object */
ipp_t *response; /* IPP response object */
ipp_attribute_t *attr; /* Current IPP attribute */
int i = 0;
char* tmpppd;
char test[1024];
SV* rv = NULL;
http = httpConnectEncrypt(cupsServer(), ippPort(), cupsEncryption());
request = ippNewRequest(CUPS_GET_PPDS);
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
"attributes-charset", NULL, "utf-8");
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
"attributes-natural-language", NULL, "en");
response = cupsDoRequest(http, request, "/");
if (response != NULL) {
attr = ippFindAttribute(response, "ppd-name", IPP_TAG_NAME );
while ((attr != NULL) && (i < 1)) {
tmpppd = attr->values[0].string.text;
attr = ippFindNextAttribute(response,
"ppd-make",
IPP_TAG_TEXT);
attr = ippFindNextAttribute(response,
"ppd-make-and-model",
IPP_TAG_TEXT);
if (strcmp(attr->values[0].string.text, ppdfilename) == 0 ) {
/* return tmpppd; */
strcpy(test, tmpppd);
break;
}
attr = ippFindNextAttribute(response, "ppd-name", IPP_TAG_NAME);
}
}
ippDelete(response);
httpClose(http);
rv = sv_newmortal();
sv_setpv( rv, test);
XPUSHs( rv );
MODULE = Net::CUPS PACKAGE = Net::CUPS::Destination
PROTOTYPES: DISABLE
INCLUDE: const-xs.inc
void
NETCUPS_getDeviceAttribute( device, attribute, attribute_type )
const char* device;
const char* attribute;
int attribute_type;
PPCODE:
http_t *http = NULL; /* HTTP object */
ipp_t *request = NULL; /* IPP request */
ipp_t *response = NULL; /* IPP response */
ipp_attribute_t *attr = NULL; /* IPP attribute */
SV* rv = NULL;
char *description = NULL;
http = httpConnectEncrypt( cupsServer(), ippPort(), cupsEncryption() );
if (http == NULL) {
perror ("Unable to connect to server");
/* return (1); */
}
request = ippNewRequest (CUPS_GET_PRINTERS);
if ((response = cupsDoRequest (http, request, "/")) != NULL) {
attr = ippFindNextAttribute(response, "printer-name", IPP_TAG_NAME);
while (attr != NULL) {
if (strcmp(attr->values[0].string.text, device) == 0) {
attr = ippFindNextAttribute( response,
attribute,
attribute_type);
rv = sv_newmortal();
sv_setpv( rv, attr->values[0].string.text);
XPUSHs( rv );
break;
}
attr = ippFindNextAttribute( response,
"printer-name",
IPP_TAG_NAME);
if (attr == NULL) {
break;
}
}
}
ippDelete( response );
httpClose( http );
XSRETURN( 1 );
int
NETCUPS_addOption( self, name, value )
cups_dest_t* self;
const char* name;
const char* value;
CODE:
int num_options;
num_options =
cupsAddOption( name, value, self->num_options, &self->options );
self->num_options = num_options;
RETVAL = num_options;
OUTPUT:
RETVAL
int
NETCUPS_cancelJob( self, jobid )
const char* self;
int jobid;
CODE:
RETVAL = cupsCancelJob( self, jobid );
OUTPUT:
RETVAL
int
NETCUPS_freeDestination( self )
cups_dest_t* self;
CODE:
/* If we use the following function, then we will get errors */
/* about double frees. */
/*cupsFreeDests( 1, self ); */
if( self->instance )
free( self->instance );
cupsFreeOptions( self->num_options, self->options );
/* I am working under the assumption that the actual 'cups_dest_t */
/* will be freed when perl does its garbage collection. */
/* I really need to research it more. */
RETVAL = 1;
OUTPUT:
RETVAL
char*
NETCUPS_getDestinationName( self )
cups_dest_t *self;
CODE:
RETVAL = self->name;
OUTPUT:
RETVAL
const char*
NETCUPS_getDestinationOptionValue( self, option )
cups_dest_t *self;
char* option;
CODE:
RETVAL = cupsGetOption( option, self->num_options, self->options );
OUTPUT:
RETVAL
void
NETCUPS_getDestinationOptions( self )
cups_dest_t* self
INIT:
int count = 0;
int loop = 0;
SV* rv = NULL;
cups_option_t* options = NULL;
PPCODE:
count = self->num_options;
options = self->options;
for( loop = 0; loop < count; loop++ )
{
rv = newSV(0);
sv_setpv( rv, options[loop].name );
XPUSHs( rv );
}
XSRETURN( count );
SV*
NETCUPS_getJob( dest, jobid )
const char* dest;
int jobid;
CODE:
int loop = 0;
int count = 0;
HV* hv = NULL;
cups_job_t* jobs = NULL;
char *tstate = NULL;
RETVAL = &PL_sv_undef;
count = cupsGetJobs( &jobs, dest, 0, -1 );
for( loop = 0; loop < count; loop++ )
{
if( jobs[loop].id == jobid )
{
hv = newHV();
hv_store( hv, "completed_time",
strlen( "completed_time" ),
newSVnv( jobs[loop].completed_time ),
0 );
hv_store( hv, "creation_time",
strlen( "creation_time" ),
newSVnv( jobs[loop].creation_time ),
0 );
hv_store( hv, "dest",
strlen( "dest" ),
newSVpv( jobs[loop].dest,
strlen( jobs[loop].dest ) ), 0 );
hv_store( hv, "format",
strlen( "format" ),
newSVpv( jobs[loop].format,
strlen( jobs[loop].format ) ), 0 );
hv_store( hv, "id",
strlen( "id" ),
newSViv( jobs[loop].id ), 0 );
hv_store( hv, "priority",
strlen( "priority" ),
newSViv( jobs[loop].priority ), 0 );
hv_store( hv, "processing_time",
strlen( "processing_time" ),
newSVnv( jobs[loop].processing_time ), 0 );
hv_store( hv, "size",
strlen( "size" ),
newSViv( jobs[loop].size ), 0 );
hv_store( hv, "state",
strlen( "state" ),
newSViv( jobs[loop].state ), 0 );
hv_store( hv, "title",
strlen( "title" ),
newSVpv( jobs[loop].title,
strlen( jobs[loop].title ) ), 0 );
hv_store( hv, "user",
strlen( "user" ),
newSVpv( jobs[loop].user,
strlen( jobs[loop].user ) ), 0 );
switch( jobs[loop].state )
{
case IPP_JOB_PENDING:
{
tstate = "pending";
break;
}
case IPP_JOB_HELD:
{
tstate = "held";
break;
}
case IPP_JOB_PROCESSING:
{
tstate = "processing";
break;
}
case IPP_JOB_STOPPED:
{
tstate = "stopped";
break;
}
/* CANCELLED is not a TYPO! (Well, it is, but it
is not my fault! */
case IPP_JOB_CANCELLED:
{
tstate = "canceled";
break;
}
case IPP_JOB_ABORTED:
{
tstate = "aborted";
break;
}
case IPP_JOB_COMPLETED:
{
tstate = "completed";
break;
}
default:
{
tstate = "unknown";
break;
}
}
hv_store( hv, "state_text",
strlen( "state_text" ),
newSVpv( tstate,
strlen( tstate ) ), 0 );
RETVAL = newRV((SV*)hv);
}
}
OUTPUT:
RETVAL
void
NETCUPS_getJobs( dest, whose, scope )
const char* dest;
int whose;
int scope;
PPCODE:
int loop = 0;
int count = 0;
SV* rv = NULL;
cups_job_t* jobs = NULL;
count = cupsGetJobs( &jobs, dest, whose, scope );
for( loop = 0; loop < count; loop++ )
{
rv = newSV(0);
sv_setiv( rv, jobs[loop].id );
XPUSHs( rv );
}
XSRETURN( count );
const char*
NETCUPS_getError()
CODE:
RETVAL = cupsLastErrorString();
OUTPUT:
RETVAL
int
NETCUPS_printFile( self, filename, title )
cups_dest_t* self;
const char* filename;
const char* title;
CODE:
RETVAL = cupsPrintFile( self->name,
filename,
title,
self->num_options,
self->options );
OUTPUT:
RETVAL
MODULE = Net::CUPS PACKAGE = Net::CUPS::PPD
PROTOTYPES: DISABLE
INCLUDE: const-xs.inc
int
NETCUPS_freePPD( ppd )
ppd_file_t *ppd;
CODE:
ppdClose( ppd );
RETVAL = 1;
OUTPUT:
RETVAL
HV*
NETCUPS_getFirstOption( ppd )
ppd_file_t *ppd;
INIT:
ppd_option_t *option;
CODE:
option = ppdFirstOption( ppd );
RETVAL = hash_ppd_option_t( option );
OUTPUT:
RETVAL
HV*
NETCUPS_getNextOption( ppd )
ppd_file_t *ppd;
INIT:
ppd_option_t *option;
CODE:
option = ppdNextOption( ppd );
RETVAL = hash_ppd_option_t( option );
OUTPUT:
RETVAL
HV*
NETCUPS_getOption( ppd, keyword )
ppd_file_t *ppd;
const char* keyword;
INIT:
ppd_option_t *option;
CODE:
option = ppdFindOption( ppd, keyword );
RETVAL = hash_ppd_option_t( option );
OUTPUT:
RETVAL
int
NETCUPS_getPageLength( ppd, size )
ppd_file_t *ppd;
const char* size;
CODE:
RETVAL = ppdPageLength( ppd, size );
OUTPUT:
RETVAL
HV*
NETCUPS_getPageSize( ppd, size )
ppd_file_t *ppd;
const char* size;
INIT:
ppd_size_t* page_size;
HV* hv;
CODE:
page_size = ppdPageSize( ppd, size );
hv = newHV();
if( page_size != NULL )
{
hv_store( hv, "bottom",
strlen( "bottom" ),
newSViv( page_size->bottom ), 0 );
hv_store( hv, "left",
strlen( "left" ),
newSViv( page_size->left ), 0 );
hv_store( hv, "length",
strlen( "length" ),
newSViv( page_size->length ), 0 );
hv_store( hv, "marked",
strlen( "marked" ),
newSViv( page_size->marked ), 0 );
hv_store( hv, "name",
strlen( "name" ),
newSVpv( page_size->name, PPD_MAX_NAME ), 0 );
hv_store( hv, "right",
strlen( "right" ),
newSViv( page_size->right ), 0 );
hv_store( hv, "top",
strlen( "top" ),
newSViv( page_size->top ), 0 );
hv_store( hv, "width",
strlen( "width" ),
newSViv( page_size->width ), 0 );
}
RETVAL = hv;
OUTPUT:
RETVAL
int
NETCUPS_getPageWidth( ppd, size )
ppd_file_t *ppd;
const char* size;
CODE:
RETVAL = ppdPageWidth( ppd, size );
OUTPUT:
RETVAL
int
NETCUPS_isMarked( ppd, option, choice )
ppd_file_t *ppd;
const char* option;
const char* choice;
CODE:
RETVAL = ppdIsMarked( ppd, option, choice );
OUTPUT:
RETVAL
int
NETCUPS_markDefaults( ppd )
ppd_file_t *ppd;
CODE:
ppdMarkDefaults( ppd );
RETVAL = 1;
OUTPUT:
RETVAL
int
NETCUPS_markOption( ppd, option, choice )
ppd_file_t *ppd;
const char* option;
const char* choice;
CODE:
RETVAL = ppdMarkOption( ppd, option, choice );
OUTPUT:
RETVAL
MODULE = Net::CUPS PACKAGE = Net::CUPS::IPP
PROTOTYPES: DISABLE
INCLUDE: const-xs.inc
int
NETCUPS_freeIPP( ipp )
ipp_t* ipp;
CODE:
ippDelete( ipp );
RETVAL = 1;
OUTPUT:
RETVAL
int
NETCUPS_addString( ipp, group, type, name, charset, value )
ipp_t* ipp;
ipp_tag_t group;
ipp_tag_t type;
const char* name;
const char* charset;
const char* value;
CODE:
ipp_attribute_t* attribute = NULL;
attribute = ippAddString( ipp, group, type, name, charset, value );
RETVAL = 1;
OUTPUT:
RETVAL
void
NETCUPS_getAttributes( ipp )
ipp_t* ipp;
PPCODE:
SV* rv = NULL;
int count = 0;
ipp_attribute_t* attr = NULL;
for (attr = ipp->attrs; attr != NULL; attr = attr->next)
{
while (attr != NULL && attr->group_tag != IPP_TAG_JOB)
attr = attr->next;
if (attr == NULL)
break;
rv = sv_newmortal();
sv_setpv( rv, attr->name );
XPUSHs( rv );
count++;
}
XSRETURN( count );
void
NETCUPS_getAttributeValue( ipp, name )
ipp_t* ipp;
const char* name;
PPCODE:
SV* rv = NULL;
int count = 0;
ipp_attribute_t* attr = NULL;
for (attr = ipp->attrs; attr != NULL; attr = attr->next)
{
while (attr != NULL && attr->group_tag != IPP_TAG_JOB)
attr = attr->next;
if (attr == NULL)
break;
if( !strcmp( attr->name, name ) )
{
rv = sv_newmortal();
if( ( attr->value_tag == IPP_TAG_INTEGER ) ||
( attr->value_tag == IPP_TAG_ENUM ) )
{
/* We have a number with any luck ... */
sv_setiv( rv, attr->values[0].integer );
}
else
{
/* We have a string ... maybe ... try to set it. */
sv_setpv( rv, attr->values[0].string.text );
}
XPUSHs( rv );
count++;
break;
}
}
XSRETURN( count );
int
NETCUPS_getPort()
CODE:
RETVAL = ippPort();
OUTPUT:
RETVAL
size_t
NETCUPS_getSize( ipp )
ipp_t* ipp;
CODE:
RETVAL = ippLength( ipp );
OUTPUT:
RETVAL
void
NETCUPS_newIPP()
PPCODE:
ipp_t * ipp = NULL;
SV* rv = NULL;
ipp = ippNew();
rv = sv_newmortal();
sv_setref_pv( rv, "Net::CUPS::IPP", ipp );
XPUSHs( rv );
XSRETURN( 1 );
void
NETCUPS_newIPPRequest( op )
ipp_op_t op;
PPCODE:
ipp_t * ipp = NULL;
SV* rv = NULL;
ipp = ippNewRequest( op );
rv = sv_newmortal();
sv_setref_pv( rv, "Net::CUPS::IPP", ipp );
XPUSHs( rv );
XSRETURN( 1 );
int
NETCUPS_setPort( port )
int port;
CODE:
ippSetPort( port );
RETVAL = ippPort();
OUTPUT:
RETVAL