#include "EXTERN.h" #include "perl.h" #include "XSUB.h" #include "ppport.h" #include /*#include */ #include #include #include #include #include #include #include #include #include #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