1 #include "EXTERN.h"
2 #include "perl.h"
3 #include "XSUB.h"
4 
5 #include "ppport.h"
6 
7 #include <cups/cups.h>
8 #if (CUPS_VERSION_MAJOR > 1) || (CUPS_VERSION_MINOR > 5)
9 #define HAVE_CUPS_1_6 1
10 #endif
11 
12 /*#include <cups/backend.h>*/
13 #include <cups/http.h>
14 #ifdef HAVE_CUPS_1_6
15  #include <cupsfilters/image.h>
16 #else
17  #include <cups/image.h>
18 #endif
19 #include <cups/ipp.h>
20 #include <cups/ppd.h>
21 #include <cups/file.h>
22 #include <cups/dir.h>
23 #include <cups/language.h>
24 #include <cups/transcode.h>
25 #include <cups/adminutil.h>
26 
27 #include "const-c.inc"
28 #include "packer.c"
29 
30 #ifndef HAVE_CUPS_1_6
31 #define ippGetGroupTag(attr)  attr->group_tag
32 #define ippGetName(attr)      attr->name
33 #define ippGetCount(attr)     attr->num_values
34 #define ippGetValueTag(attr)  attr->value_tag
35 #define ippGetInteger(attr, element) attr->values[element].integer
36 #define ippGetBoolean(attr, element) attr->values[element].boolean
37 #define ippGetString(attr, element, language) attr->values[element].string.text
38 #define ippGetStatusCode(ipp)  ipp->request.status.status_code
39 #define ippFirstAttribute(ipp) ipp->current = ipp->attrs
40 #define ippNextAttribute(ipp)  ipp->current = ipp->current->next
41 #endif
42 
43 static SV *password_cb = (SV*) NULL;
44 
45 const char *
password_cb_wrapper(const char * prompt)46 password_cb_wrapper(const char *prompt)
47 {
48 	/* This variable will show up as unused on certain platforms. */
49     STRLEN n_a;
50     static char password[255] = { '\0' };
51 
52     if (! password_cb)
53         return NULL;
54 
55     dSP;
56     ENTER;
57     SAVETMPS;
58     PUSHMARK(SP);
59     XPUSHs(sv_2mortal(newSVpv(prompt, 0)));
60     PUTBACK;
61     call_sv(password_cb, G_SCALAR);
62     SPAGAIN;
63     strncpy(password, POPpx, 254);
64 
65     PUTBACK;
66     FREETMPS;
67     LEAVE;
68 
69     return password;
70 }
71 
cupsCloneDest(cups_dest_t * src)72 cups_dest_t* cupsCloneDest(cups_dest_t* src) {
73 	int i;
74 	cups_dest_t *dst = malloc(sizeof(cups_dest_t));
75 	memcpy(dst, src, sizeof(cups_dest_t));
76 	if(src->name != NULL)
77 		dst->name = strdup(src->name);
78 	if(src->instance != NULL)
79 		dst->instance = strdup(src->instance);
80 	dst->options = malloc(src->num_options * sizeof(cups_option_t));
81 	for(i = 0; i < src->num_options; i++) {
82 		memcpy(&dst->options[i], &src->options[i], sizeof(cups_option_t));
83 		if(src->options[i].name != NULL)
84 			dst->options[i].name = strdup(src->options[i].name);
85 		if(src->options[i].value != NULL)
86 			dst->options[i].value = strdup(src->options[i].value);
87 	}
88 	return(dst);
89 }
90 
91 MODULE = Net::CUPS		PACKAGE = Net::CUPS
92 
93 PROTOTYPES: DISABLE
94 
95 INCLUDE: const-xs.inc
96 
97 const char*
98 NETCUPS_getServer()
99 	CODE:
100 		RETVAL = cupsServer();
101 	OUTPUT:
102 		RETVAL
103 
104 const char*
105 NETCUPS_getUsername()
106 	CODE:
107 		RETVAL = cupsUser();
108 	OUTPUT:
109 		RETVAL
110 
111 void
112 NETCUPS_setServer( name )
113 		const char* name;
114 	CODE:
115 		cupsSetServer( name );
116 
117 void
118 NETCUPS_setUsername( username )
119 		const char* username;
120 	CODE:
121 		cupsSetUser( username );
122 
123 void
NETCUPS_setPasswordCB(callback)124 NETCUPS_setPasswordCB( callback )
125 		SV* callback;
126 	CODE:
127 		if( password_cb == (SV*) NULL )
128 		{
129 			password_cb = newSVsv( callback );
130 			cupsSetPasswordCB( password_cb_wrapper );
131 		}
132 		else
133 		{
134 			SvSetSV( password_cb, callback );
135 		}
136 
137 const char*
138 NETCUPS_getPassword( prompt )
139 		const char* prompt;
140 	CODE:
141 		RETVAL = cupsGetPassword( prompt );
142 	OUTPUT:
143 		RETVAL
144 
145 void
146 NETCUPS_getDestination( name )
147 		char* name;
148 	PPCODE:
149 		cups_dest_t * destinations = NULL;
150 		cups_dest_t * destination = NULL;
151 		int count = 0;
152 		SV* rv = NULL;
153 		count = cupsGetDests( &destinations );
154 		/* If we have a NULL for destination name, then we are going
155            to assume we want the default. */
156 		if( !strlen( name ) )
157 		{
158 			name = cupsGetDefault();
159 		}
160 		destination = cupsGetDest( name, NULL, count, destinations );
161 		rv = sv_newmortal();
162 		sv_setref_pv( rv, "Net::CUPS::Destination", destination );
163 		XPUSHs( rv );
164 		XSRETURN( 1 );
165 
166 void
167 NETCUPS_getDestinations()
168 	PPCODE:
169 		cups_dest_t * destinations = NULL;
170 		int count = 0;
171 		int loop = 0;
172 		SV* rv = NULL;
173 		count = cupsGetDests( &destinations );
174 		for( loop = 0; loop < count; loop++ )
175 		{
176 			rv = sv_newmortal();
177 			/* FIXME cloning is probably not the best way to go at this.
178 			   It's at best a band aid for incorrect memory management
179 			   throughout this code base. Also there's a cupsCopyDest
180 			   function that seems to be doing the same as cupsCloneDest. */
181 			cups_dest_t *single = cupsCloneDest( &destinations[loop] );
182 			sv_setref_pv( rv, "Net::CUPS::Destination", single );
183 			XPUSHs( rv );
184 		}
185 		cupsFreeDests(count, destinations);
186 		XSRETURN( count );
187 
188 ppd_file_t*
189 NETCUPS_getPPD( name )
190 		const char* name;
191 	INIT:
192 		const char* filename = NULL;
193 	CODE:
194 		filename = cupsGetPPD( name );
195 		RETVAL = ppdOpenFile( filename );
196 	OUTPUT:
197 		RETVAL
198 
199 void
200 NETCUPS_requestData( request, resource, filename )
201 		ipp_t* request;
202 		const char* resource;
203 		const char* filename;
204 	PPCODE:
205 		http_t* http = NULL;
206 		ipp_t* response = NULL;
207 		const char* server = NULL;
208 		SV* rv = NULL;
209 		int port;
210 		server = cupsServer();
211 		port = ippPort();
212 		httpInitialize();
213 		http = httpConnect( server, port );
214 		if( strlen( filename ) == 0  )
215 			filename = NULL;
216 		response = cupsDoFileRequest( http, request, resource, filename );
217 		rv = sv_newmortal();
218 		sv_setref_pv( rv, "Net::CUPS::IPP", response );
219 		XPUSHs( rv );
220 		httpClose( http );
221 		XSRETURN( 1 );
222 
223 void
224 NETCUPS_getPPDMakes()
225 	http_t          *http;     /* HTTP object */
226 	ipp_t           *request;  /* IPP request object */
227 	ipp_t           *response; /* IPP response object */
228 	ipp_attribute_t *attr;     /* Current IPP attribute */
229 
230 	PPCODE:
231 		SV* rv = NULL;
232 		int count = 0;
233 		cups_lang_t *language;
234 		language = cupsLangDefault();
235 		http = httpConnectEncrypt(cupsServer(), ippPort(), cupsEncryption());
236 		request =  ippNewRequest(CUPS_GET_PPDS);
237 		ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
238 					 "attributes-charset", NULL, "utf-8");
239 		ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
240 					 "attributes-natural-language", NULL, language->language);
241 		ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
242 					 "requested-attributes", NULL, "ppd-make");
243 
244 		response = cupsDoRequest(http, request, "/");
245 
246 		if (response != NULL) {
247 			attr = ippFindAttribute(response, "ppd-make", IPP_TAG_TEXT);
248 			rv = sv_newmortal();
249 			sv_setpv(rv, ippGetString(attr, 0, NULL));
250 			XPUSHs(rv);
251 			count++;
252 
253 			while (attr != NULL) {
254 				attr = ippFindNextAttribute(response, "ppd-make", IPP_TAG_TEXT);
255 				if (attr == NULL) {
256 					break;
257 				}
258 
259 				rv = sv_newmortal();
260 				sv_setpv(rv, ippGetString(attr, 0, NULL));
261 				XPUSHs(rv);
262 				count++;
263 			}
264 
265 		ippDelete(response);
266 		httpClose(http);
267 	}
268 	else {
269 		XSRETURN ( 0 );
270 	}
271 	XSRETURN( count );
272 
273 
274 void
275 NETCUPS_getAllPPDs ()
276 	http_t          *http;     /* HTTP object */
277 	ipp_t           *request;  /* IPP request object */
278 	ipp_t           *response; /* IPP response object */
279 	ipp_attribute_t *attr;     /* Current IPP attribute */
280 
281 	PPCODE:
282 		SV* rv = NULL;
283 		int count = 0;
284 		cups_lang_t *language;
285 		language = cupsLangDefault();
286 		http = httpConnectEncrypt(cupsServer(), ippPort(), cupsEncryption());
287 		request =  ippNewRequest(CUPS_GET_PPDS);
288 		ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
289 					 "attributes-charset", NULL, "utf-8");
290 		ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
291 					 "attributes-natural-language", NULL, language->language);
292 		ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
293 					 "requested-attributes", NULL, "ppd-make-and-model");
294 		response = cupsDoRequest(http, request, "/");
295 
296 		if (response != NULL) {
297 			attr = ippFindAttribute(response,
298 									"ppd-make-and-model",
299 									IPP_TAG_TEXT);
300 			rv = sv_newmortal();
301 			sv_setpv(rv, ippGetString(attr, 0, NULL));
302 			XPUSHs(rv);
303 			count++;
304 			while (attr != NULL) {
305 				attr = ippFindNextAttribute(response,
306 											"ppd-make-and-model",
307 											IPP_TAG_TEXT);
308 				if (attr == NULL) {
309 					break;
310 				}
311 				rv = sv_newmortal();
312 				sv_setpv(rv, ippGetString(attr, 0, NULL));
313 				XPUSHs(rv);
314 				count++;
315 			}
316 
317 			ippDelete(response);
318 			httpClose(http);
319 		}
320 		else {
321 			XSRETURN ( 0 );
322 		}
323 	XSRETURN( count );
324 
325 void
326 NETCUPS_deleteDestination( destination );
327 	const char* destination;
328 
329 	PPCODE:
330 		ipp_t *request;
331 		http_t *http;
332 		char uri[HTTP_MAX_URI];
333 
334 		httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
335 						 cupsServer(), 0, "/printers/%s", destination);
336 		http = httpConnectEncrypt(cupsServer(), ippPort(), cupsEncryption());
337 		request = ippNewRequest(CUPS_DELETE_PRINTER);
338 		ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
339 					 NULL, uri);
340 		ippDelete(cupsDoRequest(http, request, "/admin/"));
341 
342 void
343 NETCUPS_addDestination(name, location, printer_info, ppd_name, device_uri);
344 	const char* name;
345 	const char* location;
346 	const char* printer_info;
347 	const char* ppd_name;
348 	const char* device_uri;
349 
350 	PPCODE:
351 		http_t *http = NULL;     /* HTTP object */
352 		ipp_t *request = NULL;  /* IPP request object */
353 		char uri[HTTP_MAX_URI];	/* Job URI */
354 
355 		http = httpConnectEncrypt(cupsServer(), ippPort(), cupsEncryption());
356 
357 		request = ippNewRequest(CUPS_ADD_PRINTER);
358 
359 		httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
360 						 cupsServer(), 0, "/printers/%s", name);
361 		ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
362 					 NULL, uri);
363 		ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-location",
364 					 NULL, location);
365 		ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-info",
366 					 NULL, printer_info );
367 		ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_NAME, "ppd-name",
368 					 NULL, ppd_name);
369 		strncpy(uri, device_uri, sizeof(uri));
370 		ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_URI, "device-uri",
371 					 NULL, uri);
372 		ippAddBoolean(request, IPP_TAG_PRINTER, "printer-is-accepting-jobs", 1);
373 		ippAddInteger(request, IPP_TAG_PRINTER, IPP_TAG_ENUM, "printer-state",
374 					  IPP_PRINTER_IDLE);
375 		ippDelete(cupsDoRequest(http, request, "/admin/"));
376 
377 void
378 NETCUPS_getPPDFileName(ppdfilename);
379 	const char* ppdfilename;
380 
381 	PPCODE:
382 		http_t          *http;     /* HTTP object */
383 		ipp_t           *request;  /* IPP request object */
384 		ipp_t           *response; /* IPP response object */
385 		ipp_attribute_t *attr;     /* Current IPP attribute */
386 		int i = 0;
387 		char* tmpppd;
388 		char test[1024];
389 		SV* rv = NULL;
390 
391 		http = httpConnectEncrypt(cupsServer(), ippPort(), cupsEncryption());
392 
393 		request = ippNewRequest(CUPS_GET_PPDS);
394 
395 		ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
396 					 "attributes-charset", NULL, "utf-8");
397 		ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
398 					 "attributes-natural-language", NULL, "en");
399 
400 		response = cupsDoRequest(http, request, "/");
401 
402 		if (response != NULL) {
403 			attr = ippFindAttribute(response, "ppd-name", IPP_TAG_NAME );
404 			while ((attr != NULL) && (i < 1)) {
405 				tmpppd = ippGetString(attr, 0, NULL);
406 				attr = ippFindNextAttribute(response,
407 											"ppd-make",
408 											IPP_TAG_TEXT);
409 				attr = ippFindNextAttribute(response,
410 											"ppd-make-and-model",
411 											IPP_TAG_TEXT);
412 				if (strcmp(ippGetString(attr, 0, NULL), ppdfilename) == 0 ) {
413 					/* return tmpppd; */
414 					strcpy(test, tmpppd);
415 					break;
416 				}
417 				attr = ippFindNextAttribute(response, "ppd-name", IPP_TAG_NAME);
418 			}
419 		}
420 		ippDelete(response);
421 		httpClose(http);
422 		rv = sv_newmortal();
423 		sv_setpv( rv, test);
424 		XPUSHs( rv );
425 
426 MODULE = Net::CUPS      PACKAGE = Net::CUPS::Destination
427 
428 PROTOTYPES: DISABLE
429 
430 INCLUDE: const-xs.inc
431 
432 void
433 NETCUPS_getDeviceAttribute( device, attribute, attribute_type )
434 	const char* device;
435 	const char* attribute;
436 	int attribute_type;
437 
438 	PPCODE:
439 		http_t *http = NULL;			/* HTTP object */
440 		ipp_t *request = NULL; 		/* IPP request */
441 		ipp_t *response = NULL;			/* IPP response */
442 		ipp_attribute_t *attr = NULL;	/* IPP attribute */
443 		SV* rv = NULL;
444 		char *description = NULL;
445 
446 		http = httpConnectEncrypt( cupsServer(), ippPort(), cupsEncryption() );
447 
448 		if (http == NULL) {
449 			perror ("Unable to connect to server");
450 			/* return (1); */
451 		}
452 
453 		request = ippNewRequest (CUPS_GET_PRINTERS);
454 
455 		if ((response = cupsDoRequest (http, request, "/")) != NULL) {
456 			rv = sv_newmortal();
457 			int match = 0;
458 			for (attr = ippFirstAttribute(response); attr != NULL; attr = ippNextAttribute(response)) {
459 				if (ippGetName(attr) == NULL) {
460 					if (match) break; else continue;
461 				}
462 				if (!strcmp(ippGetName(attr), "printer-name") && ippGetValueTag(attr) == IPP_TAG_NAME) {
463 					match = !strcmp(ippGetString(attr, 0, NULL), device);
464 				} else if (!strcmp(ippGetName(attr), attribute) && ippGetValueTag(attr) == attribute_type) {
465 					if (ippGetCount(attr) == 1) {
466 						switch (attribute_type) {
467 							case IPP_TAG_TEXT:
468 							case IPP_TAG_NAME:
469 							case IPP_TAG_KEYWORD:
470 							case IPP_TAG_URI:
471 							case IPP_TAG_CHARSET:
472 							case IPP_TAG_LANGUAGE:
473 								sv_setpv(rv, ippGetString(attr, 0, NULL));
474 								break;
475 							case IPP_TAG_BOOLEAN:
476 								sv_setiv(rv, ippGetBoolean(attr, 0));
477 								break;
478 							case IPP_TAG_INTEGER:
479 							case IPP_TAG_ENUM:
480 								sv_setiv(rv, ippGetInteger(attr, 0));
481 								break;
482 						}
483 					} else {
484 						/* XXX */
485 					}
486 				}
487 			}
488 			if (match) XPUSHs(rv);
489 		}
490 		ippDelete( response );
491 		httpClose( http );
492 		XSRETURN( 1 );
493 
494 int
495 NETCUPS_addOption( self, name, value )
496 		cups_dest_t* self;
497 		const char* name;
498 		const char* value;
499 	CODE:
500 		int num_options;
501 		num_options =
502 			cupsAddOption( name, value, self->num_options, &self->options );
503 		self->num_options = num_options;
504 		RETVAL = num_options;
505 	OUTPUT:
506 		RETVAL
507 
508 int
509 NETCUPS_cancelJob( self, jobid )
510 		const char* self;
511 		int jobid;
512 	CODE:
513 		RETVAL = cupsCancelJob( self, jobid );
514 	OUTPUT:
515 		RETVAL
516 
517 int
518 NETCUPS_freeDestination( self )
519 		cups_dest_t* self;
520 	CODE:
521 		/* If we use the following function, then we will get errors */
522 		/* about double frees.                                       */
523 		/*cupsFreeDests( 1, self );                                  */
524 		if( self->instance )
525 			free( self->instance );
526 		cupsFreeOptions( self->num_options, self->options );
527 		/* I am working under the assumption that the actual 'cups_dest_t */
528 		/* will be freed when perl does its garbage collection.           */
529 		/* I really need to research it more.                             */
530 		RETVAL = 1;
531 	OUTPUT:
532 		RETVAL
533 
534 char*
535 NETCUPS_getDestinationName( self )
536 		cups_dest_t *self;
537 	CODE:
538 		RETVAL = self->name;
539 	OUTPUT:
540 		RETVAL
541 
542 const char*
543 NETCUPS_getDestinationOptionValue( self, option )
544 		cups_dest_t *self;
545 		char* option;
546 	CODE:
547 		RETVAL = cupsGetOption( option, self->num_options, self->options );
548 	OUTPUT:
549 		RETVAL
550 
551 void
552 NETCUPS_getDestinationOptions( self )
553 		cups_dest_t* self
554 	INIT:
555 		int count = 0;
556 		int loop = 0;
557 		SV* rv = NULL;
558 		cups_option_t* options = NULL;
559 	PPCODE:
560 		count = self->num_options;
561 		options = self->options;
562 
563 		for( loop = 0; loop < count; loop++ )
564 		{
565 			rv = newSV(0);
566 			sv_setpv( rv, options[loop].name );
567 			XPUSHs( rv );
568 		}
569 		XSRETURN( count );
570 
571 SV*
572 NETCUPS_getJob( dest, jobid )
573 		const char* dest;
574 		int jobid;
575 	CODE:
576 		int loop = 0;
577 		int count = 0;
578 		HV* hv = NULL;
579 		cups_job_t* jobs = NULL;
580 		char *tstate = NULL;
581 		RETVAL = &PL_sv_undef;
582 		count = cupsGetJobs( &jobs, dest, 0, -1 );
583 		for( loop = 0; loop < count; loop++ )
584 		{
585 			if( jobs[loop].id == jobid )
586 			{
587 				hv = newHV();
588 
589 				hv_store( hv, "completed_time",
590 						  strlen( "completed_time" ),
591 						  newSVnv( jobs[loop].completed_time ),
592 						  0 );
593 
594 				hv_store( hv, "creation_time",
595 						  strlen( "creation_time" ),
596 						  newSVnv( jobs[loop].creation_time ),
597 						  0 );
598 
599 				hv_store( hv, "dest",
600 						  strlen( "dest" ),
601 						  newSVpv( jobs[loop].dest,
602 								   strlen( jobs[loop].dest ) ), 0 );
603 
604 				hv_store( hv, "format",
605 						  strlen( "format" ),
606 						  newSVpv( jobs[loop].format,
607 								   strlen( jobs[loop].format ) ), 0 );
608 
609 				hv_store( hv, "id",
610 						  strlen( "id" ),
611 						  newSViv( jobs[loop].id ), 0 );
612 
613 				hv_store( hv, "priority",
614 						  strlen( "priority" ),
615 						  newSViv( jobs[loop].priority ), 0 );
616 
617 				hv_store( hv, "processing_time",
618 						  strlen( "processing_time" ),
619 						  newSVnv( jobs[loop].processing_time ), 0 );
620 
621 				hv_store( hv, "size",
622 						  strlen( "size" ),
623 						  newSViv( jobs[loop].size ), 0 );
624 
625 				hv_store( hv, "state",
626 						  strlen( "state" ),
627 						  newSViv( jobs[loop].state ), 0 );
628 
629 				hv_store( hv, "title",
630 						  strlen( "title" ),
631 						  newSVpv( jobs[loop].title,
632 								   strlen( jobs[loop].title ) ), 0 );
633 
634 				hv_store( hv, "user",
635 						  strlen( "user" ),
636 						  newSVpv( jobs[loop].user,
637 								   strlen( jobs[loop].user ) ), 0 );
638 
639 				switch( jobs[loop].state )
640 				{
641 					case IPP_JOB_PENDING:
642 					{
643 							tstate = "pending";
644 							break;
645 					}
646 					case IPP_JOB_HELD:
647 					{
648 							tstate = "held";
649 							break;
650 					}
651 					case IPP_JOB_PROCESSING:
652 					{
653 							tstate = "processing";
654 							break;
655 					}
656 					case IPP_JOB_STOPPED:
657 					{
658 							tstate = "stopped";
659 							break;
660 					}
661 					/* CANCELLED is not a TYPO! (Well, it is, but it
662  					   is not my fault! */
663 					case IPP_JOB_CANCELLED:
664 					{
665 							tstate = "canceled";
666 							break;
667 					}
668 					case IPP_JOB_ABORTED:
669 					{
670 							tstate = "aborted";
671 							break;
672 					}
673 					case IPP_JOB_COMPLETED:
674 					{
675 							tstate = "completed";
676 							break;
677 					}
678 					default:
679 					{
680 							tstate = "unknown";
681 							break;
682 					}
683 				}
684 
685 				hv_store( hv, "state_text",
686 						  strlen( "state_text" ),
687 						  newSVpv( tstate,
688 								   strlen( tstate ) ), 0 );
689 
690 				RETVAL = newRV((SV*)hv);
691 			}
692 		}
693 	OUTPUT:
694 		RETVAL
695 
696 void
697 NETCUPS_getJobs( dest, whose, scope )
698 		const char* dest;
699 		int whose;
700 		int scope;
701 	PPCODE:
702 		int loop = 0;
703 		int count = 0;
704 		SV* rv = NULL;
705 		cups_job_t* jobs = NULL;
706 		count = cupsGetJobs( &jobs, dest, whose, scope );
707 		for( loop = 0; loop < count; loop++ )
708 		{
709 			rv = newSV(0);
710 			sv_setiv( rv, jobs[loop].id );
711 			XPUSHs( rv );
712 		}
713 		XSRETURN( count );
714 
715 const char*
716 NETCUPS_getError()
717 	CODE:
718 		RETVAL = cupsLastErrorString();
719 	OUTPUT:
720 		RETVAL
721 
722 int
723 NETCUPS_printFile( self, filename, title )
724 		cups_dest_t* self;
725 		const char* filename;
726 		const char* title;
727 	CODE:
728 		RETVAL = cupsPrintFile( self->name,
729 								filename,
730 								title,
731 								self->num_options,
732 								self->options );
733 	OUTPUT:
734 		RETVAL
735 
736 
737 MODULE = Net::CUPS      PACKAGE = Net::CUPS::PPD
738 
739 PROTOTYPES: DISABLE
740 
741 INCLUDE: const-xs.inc
742 
743 int
744 NETCUPS_freePPD( ppd )
745 		ppd_file_t *ppd;
746 	CODE:
747 		ppdClose( ppd );
748 		RETVAL = 1;
749 	OUTPUT:
750 		RETVAL
751 
752 HV*
753 NETCUPS_getFirstOption( ppd )
754 		ppd_file_t *ppd;
755 	INIT:
756 		ppd_option_t *option;
757 	CODE:
758 		option = ppdFirstOption( ppd );
759 		RETVAL = hash_ppd_option_t( option );
760                 if (RETVAL == 0)
761 		  XSRETURN_UNDEF;
762 	OUTPUT:
763 		RETVAL
764 
765 HV*
766 NETCUPS_getNextOption( ppd )
767 		ppd_file_t *ppd;
768 	INIT:
769 		ppd_option_t *option;
770 	CODE:
771 		option = ppdNextOption( ppd );
772 		RETVAL = hash_ppd_option_t( option );
773                 if (RETVAL == 0)
774 		  XSRETURN_UNDEF;
775 	OUTPUT:
776 		RETVAL
777 
778 HV*
779 NETCUPS_getOption( ppd, keyword )
780 		ppd_file_t *ppd;
781 		const char* keyword;
782 	INIT:
783 		ppd_option_t *option;
784 	CODE:
785 		option = ppdFindOption( ppd, keyword );
786 		RETVAL = hash_ppd_option_t( option );
787                 if (RETVAL == 0)
788 		  XSRETURN_UNDEF;
789 	OUTPUT:
790 		RETVAL
791 
792 int
793 NETCUPS_getPageLength( ppd, size )
794 		ppd_file_t *ppd;
795 		const char* size;
796 	CODE:
797 		RETVAL = ppdPageLength( ppd, size );
798 	OUTPUT:
799 		RETVAL
800 
801 HV*
802 NETCUPS_getPageSize( ppd, size )
803 		ppd_file_t *ppd;
804 		const char* size;
805 	INIT:
806 		ppd_size_t* page_size;
807 		HV* hv;
808 	CODE:
809 		page_size = ppdPageSize( ppd, size );
810 		hv = newHV();
811 
812 		if( page_size != NULL )
813 		{
814 			hv_store( hv, "bottom",
815 					  strlen( "bottom" ),
816 					  newSViv( page_size->bottom ), 0 );
817 
818 			hv_store( hv, "left",
819 					  strlen( "left" ),
820 					  newSViv( page_size->left ), 0 );
821 
822 			hv_store( hv, "length",
823 					  strlen( "length" ),
824 					  newSViv( page_size->length ), 0 );
825 
826 			hv_store( hv, "marked",
827 					  strlen( "marked" ),
828 					  newSViv( page_size->marked ), 0 );
829 
830 			hv_store( hv, "name",
831 					  strlen( "name" ),
832 					  newSVpv( page_size->name, PPD_MAX_NAME ), 0 );
833 
834 			hv_store( hv, "right",
835 					  strlen( "right" ),
836 					  newSViv( page_size->right ), 0 );
837 
838 			hv_store( hv, "top",
839 					  strlen( "top" ),
840 					  newSViv( page_size->top ), 0 );
841 
842 			hv_store( hv, "width",
843 					  strlen( "width" ),
844 					  newSViv( page_size->width ), 0 );
845 		}
846 		RETVAL = hv;
847 	OUTPUT:
848 		RETVAL
849 
850 int
851 NETCUPS_getPageWidth( ppd, size )
852 		ppd_file_t *ppd;
853 		const char* size;
854 	CODE:
855 		RETVAL = ppdPageWidth( ppd, size );
856 	OUTPUT:
857 		RETVAL
858 
859 
860 int
861 NETCUPS_isMarked( ppd, option, choice )
862 		ppd_file_t *ppd;
863 		const char* option;
864 		const char* choice;
865 	CODE:
866 		RETVAL = ppdIsMarked( ppd, option, choice );
867 	OUTPUT:
868 		RETVAL
869 
870 int
871 NETCUPS_markDefaults( ppd )
872 		ppd_file_t *ppd;
873 	CODE:
874 		ppdMarkDefaults( ppd );
875 		RETVAL = 1;
876 	OUTPUT:
877 		RETVAL
878 
879 int
880 NETCUPS_markOption( ppd, option, choice )
881 		ppd_file_t *ppd;
882 		const char* option;
883 		const char* choice;
884 	CODE:
885 		RETVAL = ppdMarkOption( ppd, option, choice );
886 	OUTPUT:
887 		RETVAL
888 
889 MODULE = Net::CUPS      PACKAGE = Net::CUPS::IPP
890 
891 PROTOTYPES: DISABLE
892 
893 INCLUDE: const-xs.inc
894 
895 int
896 NETCUPS_freeIPP( ipp )
897 		ipp_t* ipp;
898 	CODE:
899 		ippDelete( ipp );
900 		RETVAL = 1;
901 	OUTPUT:
902 		RETVAL
903 
904 int
905 NETCUPS_addString( ipp, group, type, name, charset, value )
906 		ipp_t* ipp;
907 		ipp_tag_t group;
908 		ipp_tag_t type;
909 		const char* name;
910 		const char* charset;
911 		const char* value;
912 	CODE:
913 		ipp_attribute_t* attribute = NULL;
914 		attribute = ippAddString( ipp, group, type, name, charset, value );
915 		RETVAL = 1;
916 	OUTPUT:
917 		RETVAL
918 
919 
920 void
921 NETCUPS_getAttributes( ipp )
922 		ipp_t* ipp;
923 	PPCODE:
924 		SV* rv = NULL;
925 		int count = 0;
926 		ipp_attribute_t* attr = NULL;
927 		for (attr = ippFirstAttribute(ipp); attr != NULL; attr = ippNextAttribute(ipp))
928 		{
929 			while (attr != NULL && ippGetGroupTag(attr) != IPP_TAG_JOB)
930  		       attr = ippNextAttribute(ipp);
931 
932 			if (attr == NULL)
933 				break;
934 			rv = sv_newmortal();
935 			sv_setpv( rv, ippGetName(attr) );
936 			XPUSHs( rv );
937 			count++;
938 		}
939 		XSRETURN( count );
940 
941 void
942 NETCUPS_getAttributeValue( ipp, name )
943 		ipp_t* ipp;
944 		const char* name;
945 	PPCODE:
946 		SV* rv = NULL;
947 		int count = 0;
948 		ipp_attribute_t* attr = NULL;
949 		for (attr = ippFirstAttribute(ipp); attr != NULL; attr = ippNextAttribute(ipp))
950 		{
951 			while (attr != NULL && ippGetGroupTag(attr) != IPP_TAG_JOB)
952  		       attr = ippNextAttribute(ipp);
953 
954 			if (attr == NULL)
955 				break;
956 
957 			if( !strcmp( ippGetName(attr), name ) )
958 			{
959 				rv = sv_newmortal();
960 				if( ( ippGetValueTag(attr) == IPP_TAG_INTEGER ) ||
961 					( ippGetValueTag(attr) == IPP_TAG_ENUM ) )
962 				{
963 					/* We have a number with any luck ... */
964 					sv_setiv( rv, ippGetInteger(attr, 0) );
965 				}
966 				else
967 				{
968 					/* We have a string ... maybe ... try to set it. */
969 					sv_setpv( rv, ippGetString(attr, 0, NULL) );
970 				}
971 
972 				XPUSHs( rv );
973 				count++;
974 				break;
975 			}
976 		}
977 		XSRETURN( count );
978 
979 int
980 NETCUPS_getPort()
981 	CODE:
982 		RETVAL = ippPort();
983 	OUTPUT:
984 		RETVAL
985 
986 size_t
987 NETCUPS_getSize( ipp )
988 		ipp_t* ipp;
989 	CODE:
990 		RETVAL = ippLength( ipp );
991 	OUTPUT:
992 		RETVAL
993 
994 void
995 NETCUPS_newIPP()
996 	PPCODE:
997 		ipp_t * ipp = NULL;
998 		SV* rv = NULL;
999 		ipp = ippNew();
1000 		rv = sv_newmortal();
1001 		sv_setref_pv( rv, "Net::CUPS::IPP", ipp );
1002 		XPUSHs( rv );
1003 		XSRETURN( 1 );
1004 
1005 void
1006 NETCUPS_newIPPRequest( op )
1007 		ipp_op_t op;
1008 	PPCODE:
1009 		ipp_t * ipp = NULL;
1010 		SV* rv = NULL;
1011 		ipp = ippNewRequest( op );
1012 		rv = sv_newmortal();
1013 		sv_setref_pv( rv, "Net::CUPS::IPP", ipp );
1014 		XPUSHs( rv );
1015 		XSRETURN( 1 );
1016 
1017 int
1018 NETCUPS_setPort( port )
1019 		int port;
1020 	CODE:
1021 		ippSetPort( port );
1022 		RETVAL = ippPort();
1023 	OUTPUT:
1024 		RETVAL
1025