Tizen 2.1 base
[platform/upstream/hplip.git] / prnt / cupsext / cupsext.c
1 /*\r
2 cupsext - Python extension class for CUPS 1.1+\r
3 \r
4 (c) Copyright 2003-2007 Hewlett-Packard Development Company, L.P.\r
5 \r
6 This program is free software; you can redistribute it and/or modify\r
7 it under the terms of the GNU General Public License as published by\r
8 the Free Software Foundation; either version 2 of the License, or\r
9 (at your option) any later version.\r
10 \r
11 This program is distributed in the hope that it will be useful,\r
12 but WITHOUT ANY WARRANTY; without even the implied warranty of\r
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
14 GNU General Public License for more details.\r
15 \r
16 You should have received a copy of the GNU General Public License\r
17 along with this program; if not, write to the Free Software\r
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA\r
19 \r
20 \r
21 Portions based on:\r
22 "lpadmin" command for the Common UNIX Printing System (CUPS).\r
23 \r
24 Copyright 1997-2003 by Easy Software Products.\r
25 \r
26 These coded instructions, statements, and computer programs are the\r
27 property of Easy Software Products and are protected by Federal\r
28 copyright law.  Distribution and use rights are outlined in the file\r
29 "LICENSE.txt" which should have been included with this file.  If this\r
30 file is missing or damaged please contact Easy Software Products\r
31 at:\r
32 \r
33 Attn: CUPS Licensing Information\r
34 Easy Software Products\r
35 44141 Airport View Drive, Suite 204\r
36 Hollywood, Maryland 20636-3111 USA\r
37 \r
38 Voice: (301) 373-9603\r
39 EMail: cups-info@cups.org\r
40   WWW: http://www.cups.org\r
41 \r
42 Redistribution and use in source and binary forms, with or without\r
43 modification, are permitted provided that the following conditions\r
44 are met:\r
45 1. Redistributions of source code must retain the above copyright\r
46 notice, this list of conditions and the following disclaimer.\r
47 2. Redistributions in binary form must reproduce the above copyright\r
48 notice, this list of conditions and the following disclaimer in the\r
49 documentation and/or other materials provided with the distribution.\r
50 3. Neither the name of Hewlett-Packard nor the names of its\r
51 contributors may be used to endorse or promote products derived\r
52 from this software without specific prior written permission.\r
53 \r
54 THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR IMPLIED\r
55 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\r
56 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN\r
57 NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\r
58 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED\r
59 TO, PATENT INFRINGEMENT; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS\r
60 OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON\r
61 ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r
62 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF\r
63 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
64 \r
65 \r
66 Requires:\r
67 CUPS 1.1+\r
68 Python 2.2+\r
69 \r
70 Author:\r
71 Don Welch
72 Yashwant Kumar Sahu\r
73 \r
74 */\r
75 \r
76 \r
77 #include <Python.h>\r
78 #include <structmember.h>\r
79 #include <cups/cups.h>\r
80 #include <cups/language.h>\r
81 #include <cups/ppd.h>\r
82 \r
83 /* Ref: PEP 353 (Python 2.5) */\r
84 #if PY_VERSION_HEX < 0x02050000\r
85 typedef int Py_ssize_t;\r
86 #define PY_SSIZE_T_MAX INT_MAX\r
87 #define PY_SSIZE_T_MIN INT_MIN\r
88 #endif\r
89 \r
90 \r
91 int g_num_options = 0;\r
92 cups_option_t * g_options;\r
93 \r
94 ppd_file_t * ppd = NULL;\r
95 cups_dest_t * dest = NULL;\r
96 \r
97 cups_dest_t * g_dests = NULL;\r
98 int g_num_dests = 0;\r
99 \r
100 const char * g_ppd_file = NULL;\r
101 \r
102 /*\r
103  * 'validate_name()' - Make sure the printer name only contains valid chars.\r
104  */\r
105 \r
106 static int                                /* O - 0 if name is no good, 1 if name is good */\r
107 validate_name( const char *name )         /* I - Name to check */\r
108 {\r
109     return 1; // TODO: Make it work with utf-8 encoding\r
110 }\r
111 \r
112 static PyObject * PyObj_from_UTF8(const char *utf8)\r
113 {\r
114     PyObject *val = PyUnicode_Decode(utf8, strlen(utf8), "utf-8", NULL);\r
115 \r
116     if (!val)\r
117     {\r
118         // CUPS 1.2 always gives us UTF-8.  Before CUPS 1.2, the\r
119         // ppd-* strings come straight from the PPD with no\r
120         // transcoding, but the attributes-charset is still 'utf-8'\r
121         // so we've no way of knowing the real encoding.\r
122         // In that case, detect the error and force it to ASCII.\r
123         char * ascii;\r
124         const char * orig = utf8;\r
125         int i;\r
126 \r
127         PyErr_Clear();\r
128         ascii = malloc(1 + strlen (orig));\r
129 \r
130         for (i = 0; orig[i]; i++)\r
131         {\r
132             ascii[i] = orig[i] & 0x7f;\r
133         }\r
134 \r
135         ascii[i] = '\0';\r
136         val = PyString_FromString( ascii );\r
137         free( ascii );\r
138     }\r
139 \r
140     return val;\r
141 }\r
142 \r
143 void debug(const char * text)\r
144 {\r
145     char buf[4096];\r
146     sprintf( buf, "print '%s'", text);\r
147     PyRun_SimpleString( buf );\r
148 \r
149 }\r
150 \r
151 staticforward PyTypeObject printer_Type;\r
152 \r
153 #define printerObject_Check(v) ((v)->ob_type == &printer_Type)\r
154 \r
155 typedef struct\r
156 {\r
157     PyObject_HEAD\r
158     PyObject * device_uri;\r
159     PyObject * printer_uri;\r
160     PyObject * name;\r
161     PyObject * location;\r
162     PyObject * makemodel;\r
163     PyObject * info;\r
164     int accepting;\r
165     int state;\r
166 }\r
167 printer_Object;\r
168 \r
169 \r
170 static void printer_dealloc( printer_Object * self )\r
171 {\r
172 \r
173     Py_XDECREF( self->name );\r
174     Py_XDECREF( self->device_uri );\r
175     Py_XDECREF( self->printer_uri );\r
176     Py_XDECREF( self->location );\r
177     Py_XDECREF( self->makemodel );\r
178     Py_XDECREF( self->info );\r
179     PyObject_DEL( self );\r
180 }\r
181 \r
182 \r
183 static PyMemberDef printer_members[] =\r
184     {\r
185         { "device_uri", T_OBJECT_EX, offsetof( printer_Object, device_uri ), 0, "Device URI (device-uri)" },\r
186         { "printer_uri", T_OBJECT_EX, offsetof( printer_Object, printer_uri ), 0, "Printer URI (printer-uri)" },\r
187         { "name", T_OBJECT_EX, offsetof( printer_Object, name ), 0, "Name (printer-name)" },\r
188         { "location", T_OBJECT_EX, offsetof( printer_Object, location ), 0, "Location (printer-location)" },\r
189         { "makemodel", T_OBJECT_EX, offsetof( printer_Object, makemodel ), 0, "Make and model (printer-make-and-model)" },\r
190         { "state", T_INT, offsetof( printer_Object, state ), 0, "State (printer-state)" },\r
191         { "info", T_OBJECT_EX, offsetof( printer_Object, info ), 0, "Info/description (printer-info)" },\r
192         { "accepting", T_INT, offsetof( printer_Object, accepting ), 0, "Accepting/rejecting" },\r
193         {0}\r
194     };\r
195 \r
196 static PyTypeObject printer_Type =\r
197     {\r
198         PyObject_HEAD_INIT( &PyType_Type )\r
199         0,                                     /* ob_size */\r
200         "cupsext.Printer",                   /* tp_name */\r
201         sizeof( printer_Object ),              /* tp_basicsize */\r
202         0,                                     /* tp_itemsize */\r
203         ( destructor ) printer_dealloc,           /* tp_dealloc */\r
204         0,                                     /* tp_print */\r
205         0,                                     /* tp_getattr */\r
206         0,                                     /* tp_setattr */\r
207         0,                                     /* tp_compare */\r
208         0,                                     /* tp_repr */\r
209         0,                                     /* tp_as_number */\r
210         0,                                     /* tp_as_sequence */\r
211         0,                                     /* tp_as_mapping */\r
212         0,                                     /* tp_hash */\r
213         0,                                     /* tp_call */\r
214         0,                                     /* tp_str */\r
215         PyObject_GenericGetAttr,               /* tp_getattro */\r
216         PyObject_GenericSetAttr,               /* tp_setattro */\r
217         0,                                     /* tp_as_buffer */\r
218         Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,         /* tp_flags */\r
219         "CUPS Printer object",                 /* tp_doc */\r
220         0,                                     /* tp_traverse */\r
221         0,                                     /* tp_clear */\r
222         0,                                     /* tp_richcompare */\r
223         0,                                     /* tp_weaklistoffset */\r
224         0,                                     /* tp_iter */\r
225         0,                                     /* tp_iternext */\r
226         0,         /*job_methods, */           /* tp_methods */\r
227         printer_members,                       /* tp_members */\r
228         0,                                     /* tp_getset */\r
229         0,                                     /* tp_base */\r
230         0,                                     /* tp_dict */\r
231         0,                                     /* tp_descr_get */\r
232         0,                                     /* tp_descr_set */\r
233         0,                                     /* tp_dictoffset */\r
234         0,                                     /* tp_init */\r
235         0,                                     /* tp_alloc */\r
236         0,                                     /* tp_new */\r
237     };\r
238 \r
239 \r
240 \r
241 \r
242 static PyObject * _newPrinter( char * device_uri,\r
243                                char * name,\r
244                                char * printer_uri,\r
245                                char * location,\r
246                                char * makemodel,\r
247                                char * info,\r
248                                int state,\r
249                                int accepting )\r
250 {\r
251     printer_Object * self = PyObject_New( printer_Object, &printer_Type );\r
252 \r
253     if ( !self )\r
254         return NULL;\r
255 \r
256     if ( device_uri != NULL )\r
257         self->device_uri = Py_BuildValue( "s", device_uri );\r
258 \r
259     if ( printer_uri != NULL )\r
260         self->printer_uri = Py_BuildValue( "s", printer_uri );\r
261 \r
262     if ( name != NULL )\r
263         self->name = Py_BuildValue( "s", name );\r
264 \r
265     if ( location != NULL )\r
266         self->location = Py_BuildValue( "s", location );\r
267 \r
268     if ( makemodel != NULL )\r
269         self->makemodel = Py_BuildValue( "s", makemodel );\r
270 \r
271     if ( info != NULL )\r
272         self->info = Py_BuildValue( "s", info );\r
273 \r
274     self->accepting = accepting;\r
275     self->state = state;\r
276 \r
277     return ( PyObject * ) self;\r
278 }\r
279 \r
280 static PyObject * newPrinter( PyObject * self, PyObject * args, PyObject * kwargs )\r
281 {\r
282     char * device_uri = "";\r
283     char * name = "";\r
284     char * location = "";\r
285     char * makemodel = "";\r
286     int state = 0;\r
287     char * printer_uri = "";\r
288     char * info = "";\r
289     int accepting = 0;\r
290 \r
291     char * kwds[] = { "device_uri", "name", "printer_uri", "location",\r
292                       "makemodel", "info", "state", "accepting", NULL };\r
293 \r
294     if ( !PyArg_ParseTupleAndKeywords( args, kwargs, "zz|zzzzii", kwds,\r
295                                        &device_uri, &name, &printer_uri,\r
296                                        &location, &makemodel, &info, &state,\r
297                                        &accepting )        )\r
298         return NULL;\r
299 \r
300     return _newPrinter( device_uri, printer_uri, name, location, makemodel, info, state, accepting);\r
301 }\r
302 \r
303 \r
304 \r
305 PyObject * getPrinters( PyObject * self, PyObject * args )\r
306 {\r
307     http_t * http = NULL;     /* HTTP object */\r
308     ipp_t *request = NULL;  /* IPP request object */\r
309     ipp_t *response = NULL; /* IPP response object */\r
310     ipp_attribute_t *attr;     /* Current IPP attribute */\r
311     PyObject * printer_list;\r
312     cups_lang_t * language;\r
313 \r
314     static const char * attrs[] =         /* Requested attributes */\r
315     {\r
316         "printer-info",\r
317         "printer-location",\r
318         "printer-make-and-model",\r
319         "printer-state",\r
320         "printer-name",\r
321         "device-uri",\r
322         "printer-uri-supported",\r
323         "printer-is-accepting-jobs",\r
324     };\r
325 \r
326     /* Connect to the HTTP server */\r
327     if ( ( http = httpConnectEncrypt( cupsServer(), ippPort(), cupsEncryption() ) ) == NULL )\r
328     {\r
329         goto abort;\r
330     }\r
331 \r
332     /* Assemble the IPP request */\r
333     request = ippNew();\r
334     language = cupsLangDefault();\r
335 \r
336     request->request.op.operation_id = CUPS_GET_PRINTERS;\r
337     request->request.any.request_id = 1;\r
338 \r
339     ippAddString( request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,\r
340                   "attributes-charset", NULL, cupsLangEncoding( language ) );\r
341 \r
342     ippAddString( request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,\r
343                   "attributes-natural-language", NULL, language->language );\r
344 \r
345     ippAddStrings( request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,\r
346                    "requested-attributes", sizeof( attrs ) / sizeof( attrs[ 0 ] ),\r
347                    NULL, attrs );\r
348 \r
349     /* Send the request and get a response. */\r
350     if ( ( response = cupsDoRequest( http, request, "/" ) ) == NULL )\r
351     {\r
352         goto abort;\r
353     }\r
354 \r
355     Py_ssize_t max_count = 0;\r
356 \r
357     for ( attr = ippFindAttribute( response, "printer-name", IPP_TAG_NAME ),\r
358             max_count = 0;\r
359             attr != NULL;\r
360             attr = ippFindNextAttribute( response, "printer-name", IPP_TAG_NAME ),\r
361             max_count++ )\r
362         ;\r
363 \r
364     if ( max_count > 0 )\r
365     {\r
366 \r
367         //printer_list = PyList_New( max_count );\r
368         printer_list = PyList_New( 0 );\r
369 \r
370         char * device_uri = "";\r
371         char * printer_uri = "";\r
372         char * info = "";\r
373         char * location = "";\r
374         char * make_model = "";\r
375         char * name = "";\r
376         int accepting = 0;\r
377         cups_ptype_t type;\r
378         ipp_pstate_t state;\r
379         int i = 0;\r
380 \r
381         for ( attr = response->attrs; attr != NULL; attr = attr->next )\r
382         {\r
383             while ( attr != NULL && attr->group_tag != IPP_TAG_PRINTER )\r
384                 attr = attr->next;\r
385 \r
386             if ( attr == NULL )\r
387                 break;\r
388 \r
389             type = CUPS_PRINTER_REMOTE;\r
390             state = IPP_PRINTER_IDLE;\r
391             accepting = 0;\r
392 \r
393             while ( attr != NULL && attr->group_tag == IPP_TAG_PRINTER )\r
394             {\r
395                 if ( strcmp( attr->name, "printer-name" ) == 0 &&\r
396                         attr->value_tag == IPP_TAG_NAME )\r
397                     name = attr->values[ 0 ].string.text;\r
398 \r
399                 else if ( strcmp( attr->name, "device-uri" ) == 0 &&\r
400                         attr->value_tag == IPP_TAG_URI )\r
401                     device_uri = attr->values[ 0 ].string.text;\r
402 \r
403                 else if ( strcmp( attr->name, "printer-uri-supported" ) == 0 &&\r
404                         attr->value_tag == IPP_TAG_URI )\r
405                     printer_uri = attr->values[ 0 ].string.text;\r
406 \r
407                 else if ( strcmp( attr->name, "printer-info" ) == 0 &&\r
408                         attr->value_tag == IPP_TAG_TEXT )\r
409                     info = attr->values[ 0 ].string.text;\r
410 \r
411                 else if ( strcmp( attr->name, "printer-location" ) == 0 &&\r
412                         attr->value_tag == IPP_TAG_TEXT )\r
413                     location = attr->values[ 0 ].string.text;\r
414 \r
415                 else if ( strcmp( attr->name, "printer-make-and-model" ) == 0 &&\r
416                         attr->value_tag == IPP_TAG_TEXT )\r
417                     make_model = attr->values[ 0 ].string.text;\r
418 \r
419                 else if ( strcmp( attr->name, "printer-state" ) == 0 &&\r
420                         attr->value_tag == IPP_TAG_ENUM )\r
421                     state = ( ipp_pstate_t ) attr->values[ 0 ].integer;\r
422 \r
423                 else if (!strcmp(attr->name, "printer-is-accepting-jobs") &&\r
424                         attr->value_tag == IPP_TAG_BOOLEAN)\r
425                     accepting = attr->values[ 0 ].boolean;\r
426 \r
427                 attr = attr->next;\r
428             }\r
429 \r
430             if ( device_uri == NULL )\r
431             {\r
432                 if ( attr == NULL )\r
433                     break;\r
434                 else\r
435                     continue;\r
436             }\r
437 \r
438             printer_Object * printer;\r
439             printer = ( printer_Object * ) _newPrinter( device_uri, name, printer_uri, location, make_model,\r
440                     info, state, accepting );\r
441 \r
442             //PyList_SetItem( printer_list, i, ( PyObject * ) printer );\r
443             PyList_Append( printer_list, ( PyObject * ) printer );\r
444 \r
445             i++;\r
446 \r
447             if ( attr == NULL )\r
448                 break;\r
449         }\r
450 \r
451         return printer_list;\r
452     }\r
453 abort:\r
454     if ( response != NULL )\r
455         ippDelete( response );\r
456 \r
457     if ( http != NULL )\r
458         httpClose( http );\r
459 \r
460     printer_list = PyList_New( ( Py_ssize_t ) 0 );\r
461     return printer_list;\r
462 }\r
463 \r
464 \r
465 PyObject * addPrinter( PyObject * self, PyObject * args )\r
466 {\r
467     //char buf[1024];\r
468     ipp_status_t status;\r
469     http_t *http = NULL;     /* HTTP object */\r
470     ipp_t *request = NULL;  /* IPP request object */\r
471     ipp_t *response = NULL; /* IPP response object */\r
472     cups_lang_t * language;\r
473     int r;\r
474     char printer_uri[ HTTP_MAX_URI ];\r
475     char * name, * device_uri, *location, *ppd_file, * info, * model;\r
476     const char * status_str = "successful-ok";\r
477 \r
478     if ( !PyArg_ParseTuple( args, "zzzzzz",\r
479                             &name,             // name of printer\r
480                             &device_uri,       // DeviceURI (e.g., hp:/usb/PSC_2200_Series?serial=0000000010)\r
481                             &location,         // location of printer\r
482                             &ppd_file,         // path to PPD file (uncompressed, must exist)\r
483                             &model,            // model name (e.g., foomatic:...)\r
484                             &info              // info/description\r
485                           ) )\r
486     {\r
487         r = 0;\r
488         status_str = "Invalid arguments";\r
489         goto abort;\r
490     }\r
491 \r
492     if ( ( strlen( ppd_file ) > 0 && strlen( model ) > 0 ) ||\r
493          ( strlen( ppd_file ) == 0 && strlen( model ) == 0) )\r
494     {\r
495         r = 0;\r
496         status_str = "Invalid arguments: specify only ppd_file or model, not both or neither";\r
497         goto abort;\r
498     }\r
499 \r
500     if ( !validate_name( name ) )\r
501     {\r
502         r = 0;\r
503         status_str = "Invalid printer name";\r
504         goto abort;\r
505     }\r
506 \r
507 \r
508     sprintf( printer_uri, "ipp://localhost/printers/%s", name );\r
509 \r
510     if ( info == NULL )\r
511         strcpy( info, name );\r
512 \r
513     /* Connect to the HTTP server */\r
514     if ( ( http = httpConnectEncrypt( cupsServer(), ippPort(), cupsEncryption() ) ) == NULL )\r
515     {\r
516         r = 0;\r
517         status_str = "Unable to connect to CUPS server";\r
518         goto abort;\r
519     }\r
520 \r
521     /* Assemble the IPP request */\r
522     request = ippNew();\r
523     language = cupsLangDefault();\r
524 \r
525     request->request.op.operation_id = CUPS_ADD_PRINTER;\r
526     request->request.any.request_id = 1;\r
527 \r
528     ippAddString( request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,\r
529                   "attributes-charset", NULL, cupsLangEncoding( language ) );\r
530 \r
531     ippAddString( request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,\r
532                   "attributes-natural-language", NULL, language->language );\r
533 \r
534     ippAddString( request, IPP_TAG_OPERATION, IPP_TAG_URI,\r
535                   "printer-uri", NULL, printer_uri );\r
536 \r
537     ippAddInteger( request, IPP_TAG_PRINTER, IPP_TAG_ENUM,\r
538                    "printer-state", IPP_PRINTER_IDLE );\r
539 \r
540     ippAddBoolean( request, IPP_TAG_PRINTER, "printer-is-accepting-jobs", 1 );\r
541 \r
542     ippAddString( request, IPP_TAG_PRINTER, IPP_TAG_URI, "device-uri", NULL,\r
543                   device_uri );\r
544 \r
545     ippAddString( request, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-info", NULL,\r
546                   info );\r
547 \r
548     ippAddString( request, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-location", NULL,\r
549                   location );\r
550 \r
551     if ( strlen( model ) > 0 )\r
552     {\r
553         ippAddString( request, IPP_TAG_PRINTER, IPP_TAG_NAME, "ppd-name", NULL, model );\r
554 \r
555         /* Send the request and get a response. */\r
556         response = cupsDoRequest( http, request, "/admin/" );\r
557     }\r
558     else\r
559     {\r
560         /* Send the request and get a response. */\r
561         response = cupsDoFileRequest( http, request, "/admin/", ppd_file );\r
562     }\r
563 \r
564     if ( response == NULL )\r
565     {\r
566         status = cupsLastError();\r
567         r = 0;\r
568     }\r
569     else\r
570     {\r
571         status = response->request.status.status_code;\r
572         //ippDelete( response );\r
573         r = 1;\r
574     }\r
575 \r
576     status_str = ippErrorString( status );\r
577 \r
578 abort:\r
579 \r
580     if ( http != NULL )\r
581         httpClose( http );\r
582 \r
583     if ( response != NULL )\r
584         ippDelete( response );\r
585 \r
586     return Py_BuildValue( "is", r, status_str );\r
587 \r
588 }\r
589 \r
590 /*\r
591  * 'delPrinter()' - Delete a printer from the system...\r
592  */\r
593 PyObject * delPrinter( PyObject * self, PyObject * args )\r
594 {\r
595     ipp_t * request = NULL,                        /* IPP Request */\r
596                       *response = NULL;                /* IPP Response */\r
597     cups_lang_t *language;                /* Default language */\r
598     char uri[ HTTP_MAX_URI ];        /* URI for printer/class */\r
599     char * name;\r
600     http_t *http = NULL;     /* HTTP object */\r
601     int r = 0;\r
602     const char *username = NULL;\r
603 \r
604     username = cupsUser();\r
605 \r
606     if ( !PyArg_ParseTuple( args, "z",\r
607                             &name ) )         // name of printer\r
608     {\r
609         goto abort;\r
610     }\r
611 \r
612     if ( !validate_name( name ) )\r
613     {\r
614         goto abort;\r
615     }\r
616 \r
617     /* Connect to the HTTP server */\r
618     if ( ( http = httpConnectEncrypt( cupsServer(), ippPort(), cupsEncryption() ) ) == NULL )\r
619     {\r
620         goto abort;\r
621     }\r
622     snprintf( uri, sizeof( uri ), "ipp://localhost/printers/%s", name );\r
623 \r
624     /*\r
625         * Build a CUPS_DELETE_PRINTER request, which requires the following\r
626         * attributes:\r
627         *\r
628         *    attributes-charset\r
629         *    attributes-natural-language\r
630         *    printer-uri\r
631        */\r
632     request = ippNew();\r
633 \r
634     request->request.op.operation_id = CUPS_DELETE_PRINTER;\r
635     request->request.op.request_id = 1;\r
636 \r
637     language = cupsLangDefault();\r
638 \r
639     ippAddString( request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,\r
640                   "attributes-charset", NULL, cupsLangEncoding( language ) );\r
641 \r
642     ippAddString( request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,\r
643                   "attributes-natural-language", NULL, language->language );\r
644 \r
645     ippAddString( request, IPP_TAG_OPERATION, IPP_TAG_URI,\r
646                   "printer-uri", NULL, uri );\r
647 \r
648     /*\r
649      * Do the request and get back a response...\r
650      */\r
651     response = cupsDoRequest( http, request, "/admin/" );\r
652 \r
653     if ( ( response != NULL ) && ( response->request.status.status_code <= IPP_OK_CONFLICT ) )\r
654     {\r
655         r = 1;\r
656     }\r
657 \r
658 abort:\r
659     if (username)\r
660         cupsSetUser(username);\r
661 \r
662     if ( http != NULL )\r
663         httpClose( http );\r
664 \r
665     if ( response != NULL )\r
666         ippDelete( response );\r
667 \r
668     return Py_BuildValue( "i", r );\r
669 \r
670 }\r
671 \r
672 /*\r
673  * 'setDefaultPrinter()' - Set the default printing destination.\r
674  */\r
675 \r
676 PyObject * setDefaultPrinter( PyObject * self, PyObject * args )\r
677 \r
678 {\r
679     char uri[ HTTP_MAX_URI ];        /* URI for printer/class */\r
680     ipp_t *request = NULL,                        /* IPP Request */\r
681           *response = NULL;                /* IPP Response */\r
682     cups_lang_t *language;                /* Default language */\r
683     char * name;\r
684     http_t *http = NULL;     /* HTTP object */\r
685     int r = 0;\r
686     const char *username = NULL;\r
687 \r
688     username = cupsUser();\r
689 \r
690     if ( !PyArg_ParseTuple( args, "z",\r
691                             &name ) )         // name of printer\r
692     {\r
693         goto abort;\r
694     }\r
695 \r
696     //char buf[1024];\r
697     //sprintf( buf, "print '%s'", name);\r
698     //PyRun_SimpleString( buf );\r
699 \r
700     if ( !validate_name( name ) )\r
701     {\r
702         goto abort;\r
703     }\r
704 \r
705     /* Connect to the HTTP server */\r
706     if ( ( http = httpConnectEncrypt( cupsServer(), ippPort(), cupsEncryption() ) ) == NULL )\r
707     {\r
708         goto abort;\r
709     }\r
710 \r
711     /*\r
712       * Build a CUPS_SET_DEFAULT request, which requires the following\r
713       * attributes:\r
714       *\r
715       *    attributes-charset\r
716       *    attributes-natural-language\r
717       *    printer-uri\r
718       */\r
719 \r
720     snprintf( uri, sizeof( uri ), "ipp://localhost/printers/%s", name );\r
721 \r
722     request = ippNew();\r
723 \r
724     request->request.op.operation_id = CUPS_SET_DEFAULT;\r
725     request->request.op.request_id = 1;\r
726 \r
727     language = cupsLangDefault();\r
728 \r
729     ippAddString( request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,\r
730                   "attributes-charset", NULL, "utf-8" ); //cupsLangEncoding( language ) );\r
731 \r
732     ippAddString( request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,\r
733                   "attributes-natural-language",\r
734                   //NULL, language != NULL ? language->language : "en");\r
735                   NULL, language->language );\r
736 \r
737     ippAddString( request, IPP_TAG_OPERATION, IPP_TAG_URI,\r
738                   "printer-uri", NULL, uri );\r
739 \r
740     /*\r
741      * Do the request and get back a response...\r
742      */\r
743 \r
744     response = cupsDoRequest( http, request, "/admin/" );\r
745 \r
746     if ( ( response != NULL ) && ( response->request.status.status_code <= IPP_OK_CONFLICT ) )\r
747     {\r
748         r = 1;\r
749     }\r
750 \r
751 abort:\r
752     if (username)\r
753         cupsSetUser(username);\r
754 \r
755     if ( http != NULL )\r
756         httpClose( http );\r
757 \r
758     if ( response != NULL )\r
759         ippDelete( response );\r
760 \r
761     return Py_BuildValue( "i", r );\r
762 \r
763 \r
764 }\r
765 \r
766 \r
767 \r
768 PyObject * controlPrinter( PyObject * self, PyObject * args )\r
769 {\r
770     ipp_t *request = NULL,                 /* IPP Request */\r
771           *response = NULL;                /* IPP Response */\r
772     char * name;\r
773     http_t *http = NULL;     /* HTTP object */\r
774     int op;\r
775     int r = 0;\r
776     char uri[ HTTP_MAX_URI ];        /* URI for printer/class */\r
777     cups_lang_t *language;\r
778     const char *username = NULL;\r
779 \r
780     username = cupsUser();\r
781 \r
782     if ( !PyArg_ParseTuple( args, "zi", &name, &op) )\r
783     {\r
784         goto abort;\r
785     }\r
786 \r
787     if ( !validate_name( name ) )\r
788     {\r
789         goto abort;\r
790     }\r
791 \r
792     /* Connect to the HTTP server */\r
793     if ( ( http = httpConnectEncrypt( cupsServer(), ippPort(), cupsEncryption() ) ) == NULL )\r
794     {\r
795         goto abort;\r
796     }\r
797 \r
798     request = ippNew();\r
799 \r
800     request->request.op.operation_id = op;\r
801     request->request.op.request_id = 1;\r
802 \r
803     language = cupsLangDefault();\r
804 \r
805     snprintf( uri, sizeof( uri ), "ipp://localhost/printers/%s", name );\r
806 \r
807     ippAddString( request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,\r
808                   "attributes-charset", NULL, cupsLangEncoding( language ) );\r
809 \r
810     ippAddString( request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,\r
811                   "attributes-natural-language", NULL, language->language );\r
812 \r
813     ippAddString( request, IPP_TAG_OPERATION, IPP_TAG_URI,\r
814                   "printer-uri", NULL, uri );\r
815 \r
816 \r
817     ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,\r
818                 "requesting-user-name", NULL, cupsUser());\r
819 \r
820     if (op == IPP_PURGE_JOBS)\r
821         ippAddBoolean(request, IPP_TAG_OPERATION, "purge-jobs", 1);\r
822 \r
823     response = cupsDoRequest(http, request, "/admin/");\r
824 \r
825     if (( response != NULL ) && (response->request.status.status_code <= IPP_OK_CONFLICT))\r
826     {\r
827         r = 1;\r
828     }\r
829 \r
830 abort:\r
831     if (username)\r
832         cupsSetUser(username);\r
833 \r
834     if ( http != NULL )\r
835         httpClose( http );\r
836 \r
837     if ( response != NULL )\r
838         ippDelete( response );\r
839 \r
840     return Py_BuildValue( "i", r );;\r
841 }\r
842 \r
843 \r
844 \r
845 staticforward PyTypeObject job_Type;\r
846 \r
847 typedef struct\r
848 {\r
849     PyObject_HEAD\r
850     int id;\r
851     PyObject * dest;\r
852     PyObject * title;\r
853     PyObject * user;\r
854     int state;\r
855     int size;\r
856 }\r
857 job_Object;\r
858 \r
859 \r
860 \r
861 static void job_dealloc( job_Object * self )\r
862 {\r
863 \r
864     Py_XDECREF( self->dest );\r
865     Py_XDECREF( self->title );\r
866     Py_XDECREF( self->user );\r
867     PyObject_DEL( self );\r
868 }\r
869 \r
870 static PyMemberDef job_members[] =\r
871     {\r
872         { "id", T_INT, offsetof( job_Object, id ), 0, "Id" },\r
873         { "dest", T_OBJECT_EX, offsetof( job_Object, dest ), 0, "Destination" },\r
874         { "state", T_INT, offsetof( job_Object, state ), 0, "State" },\r
875         { "title", T_OBJECT_EX, offsetof( job_Object, title ), 0, "Title" },\r
876         { "user", T_OBJECT_EX, offsetof( job_Object, user ), 0, "User" },\r
877         { "size", T_INT, offsetof( job_Object, size ), 0, "Size" },\r
878         {0}\r
879     };\r
880 \r
881 \r
882 \r
883 static PyTypeObject job_Type =\r
884     {\r
885         PyObject_HEAD_INIT( &PyType_Type )\r
886         0,                                     /* ob_size */\r
887         "Job",                                 /* tp_name */\r
888         sizeof( job_Object ),                  /* tp_basicsize */\r
889         0,                                     /* tp_itemsize */\r
890         ( destructor ) job_dealloc,               /* tp_dealloc */\r
891         0,                                     /* tp_print */\r
892         0,                                     /* tp_getattr */\r
893         0,                                     /* tp_setattr */\r
894         0,                                     /* tp_compare */\r
895         0,                                     /* tp_repr */\r
896         0,                                     /* tp_as_number */\r
897         0,                                     /* tp_as_sequence */\r
898         0,                                     /* tp_as_mapping */\r
899         0,                                     /* tp_hash */\r
900         0,                                     /* tp_call */\r
901         0,                                     /* tp_str */\r
902         PyObject_GenericGetAttr,               /* tp_getattro */\r
903         PyObject_GenericSetAttr,               /* tp_setattro */\r
904         0,                                     /* tp_as_buffer */\r
905         Py_TPFLAGS_DEFAULT,                    /* tp_flags */\r
906         "CUPS Job object",                     /* tp_doc */\r
907         0,                                     /* tp_traverse */\r
908         0,                                     /* tp_clear */\r
909         0,                                     /* tp_richcompare */\r
910         0,                                     /* tp_weaklistoffset */\r
911         0,                                     /* tp_iter */\r
912         0,                                     /* tp_iternext */\r
913         0,         /*job_methods, */                  /* tp_methods */\r
914         job_members,                           /* tp_members */\r
915         0,                                     /* tp_getset */\r
916         0,                                     /* tp_base */\r
917         0,                                     /* tp_dict */\r
918         0,                                     /* tp_descr_get */\r
919         0,                                     /* tp_descr_set */\r
920         0,                                     /* tp_dictoffset */\r
921         0,                                     /* tp_init */\r
922         0,        //(initproc)job_init,            /* tp_init */\r
923         0,                                     /* tp_alloc */\r
924         //PyType_GenericAlloc,\r
925         0,         //job_new,                       /* tp_new */\r
926         //PyType_GenericNew,\r
927     };\r
928 \r
929 \r
930 static /*job_Object **/ PyObject * _newJob( int id, int state, char * dest, char * title, char * user, int size )\r
931 {\r
932     job_Object * jo;\r
933     jo = PyObject_New( job_Object, &job_Type );\r
934     if ( jo == NULL )\r
935         return NULL;\r
936     jo->id = id;\r
937     jo->size = size;\r
938     jo->state = state;\r
939     if ( dest != NULL )\r
940         jo->dest = PyObj_from_UTF8( dest );\r
941     else\r
942         jo->dest = Py_BuildValue( "" );\r
943 \r
944     if ( title != NULL )\r
945         jo->title = PyObj_from_UTF8( title );\r
946     else\r
947         jo->title = Py_BuildValue( "" );\r
948 \r
949     if ( user != NULL )\r
950         jo->user = PyObj_from_UTF8( user );\r
951     else\r
952         jo->user = Py_BuildValue( "" );\r
953 \r
954     return ( PyObject * ) jo;\r
955 \r
956 }\r
957 \r
958 static /*job_Object **/ PyObject * newJob( PyObject * self, PyObject * args, PyObject * kwargs )\r
959 {\r
960     char * dest = "";\r
961     int id = 0;\r
962     int state = 0;\r
963     char * title = "";\r
964     char * user = "";\r
965     int size = 0;\r
966 \r
967     char * kwds[] = { "id", "state", "dest", "title", "user", "size", NULL };\r
968 \r
969     if ( !PyArg_ParseTupleAndKeywords( args, kwargs, "i|izzzi", kwds,\r
970                                        &id, &state, &dest, &title, &user, &size ) )\r
971         return NULL;\r
972 \r
973     return _newJob( id, state, dest, title, user, size );\r
974 \r
975 }\r
976 \r
977 \r
978 \r
979 \r
980 PyObject * getDefaultPrinter( PyObject * self, PyObject * args )\r
981 {\r
982     const char * defdest;\r
983     defdest = cupsGetDefault();\r
984 \r
985     /*char buf[1024];\r
986     sprintf( buf, "print 'Default Printer: %s'", defdest);\r
987     PyRun_SimpleString( buf );\r
988     */\r
989 \r
990     if ( defdest == NULL )\r
991         return Py_BuildValue( "" ); // None\r
992     else\r
993         return Py_BuildValue( "s", defdest );\r
994 \r
995 }\r
996 \r
997 \r
998 PyObject * cancelJob( PyObject * self, PyObject * args )         // cancelJob( dest, jobid )\r
999 {\r
1000     int status;\r
1001     int jobid;\r
1002     char * dest;\r
1003 \r
1004     if ( !PyArg_ParseTuple( args, "si", &dest, &jobid ) )\r
1005     {\r
1006         return Py_BuildValue( "i", 0 );\r
1007     }\r
1008 \r
1009     status = cupsCancelJob( dest, jobid );\r
1010 \r
1011     return Py_BuildValue( "i", status );\r
1012 }\r
1013 \r
1014 PyObject * getJobs( PyObject * self, PyObject * args )\r
1015 {\r
1016     cups_job_t * jobs;\r
1017     Py_ssize_t i;\r
1018     int num_jobs;\r
1019     PyObject * job_list;\r
1020     int my_job;\r
1021     int completed;\r
1022 \r
1023     if ( !PyArg_ParseTuple( args, "ii", &my_job, &completed ) )\r
1024     {\r
1025         return PyList_New( ( Py_ssize_t ) 0 );\r
1026     }\r
1027 \r
1028     num_jobs = cupsGetJobs( &jobs, NULL, my_job, completed );\r
1029 \r
1030     if ( num_jobs > 0 )\r
1031     {\r
1032         job_list = PyList_New( num_jobs );\r
1033 \r
1034         for ( i = 0; i < num_jobs; i++ )\r
1035         {\r
1036             job_Object * newjob;\r
1037             newjob = ( job_Object * ) _newJob( jobs[ i ].id,\r
1038                                                jobs[ i ].state,\r
1039                                                jobs[ i ].dest,\r
1040                                                jobs[ i ].title,\r
1041                                                jobs[ i ].user,\r
1042                                                jobs[ i ].size );\r
1043 \r
1044             PyList_SetItem( job_list, i, ( PyObject * ) newjob );\r
1045 \r
1046         }\r
1047         cupsFreeJobs( num_jobs, jobs );\r
1048     }\r
1049     else\r
1050     {\r
1051         job_list = PyList_New( ( Py_ssize_t ) 0 );\r
1052     }\r
1053     return job_list;\r
1054 }\r
1055 \r
1056 PyObject * getVersion( PyObject * self, PyObject * args )\r
1057 {\r
1058     return Py_BuildValue( "f", CUPS_VERSION );\r
1059 }\r
1060 \r
1061 PyObject * getVersionTuple( PyObject * self, PyObject * args )\r
1062 {\r
1063     return Py_BuildValue( "(iii)", CUPS_VERSION_MAJOR, CUPS_VERSION_MINOR, CUPS_VERSION_PATCH );\r
1064 }\r
1065 \r
1066 PyObject * getServer( PyObject * self, PyObject * args )\r
1067 {\r
1068     return Py_BuildValue( "s", cupsServer() );\r
1069 }\r
1070 \r
1071 PyObject * setServer( PyObject * self, PyObject * args )\r
1072 {\r
1073     char * server = NULL;\r
1074 \r
1075     if (!PyArg_ParseTuple(args, "z", &server))\r
1076         return Py_BuildValue( "" );\r
1077 \r
1078     if (!strlen(server)) // Pass an empty string to restore default server\r
1079         server = NULL;\r
1080 \r
1081     cupsSetServer(server);\r
1082 \r
1083     return Py_BuildValue( "" );\r
1084 }\r
1085 \r
1086 \r
1087 // ***************************************************************************************************\r
1088 \r
1089 PyObject * getPPDList( PyObject * self, PyObject * args )\r
1090 {\r
1091 \r
1092 /*\r
1093     * Build a CUPS_GET_PPDS request, which requires the following\r
1094     * attributes:\r
1095     *\r
1096     *    attributes-charset\r
1097     *    attributes-natural-language\r
1098     *    printer-uri\r
1099     */\r
1100 \r
1101     ipp_t *request = NULL,                 /* IPP Request */\r
1102           *response = NULL;                /* IPP Response */\r
1103     PyObject * result;\r
1104     cups_lang_t *language;\r
1105     ipp_attribute_t * attr;\r
1106     //PyObject * ppd_list;\r
1107     http_t *http = NULL;     /* HTTP object */\r
1108     //char buf[1024];\r
1109 \r
1110     result = PyDict_New ();\r
1111 \r
1112     if ( ( http = httpConnectEncrypt( cupsServer(), ippPort(), cupsEncryption() ) ) == NULL )\r
1113     {\r
1114         goto abort;\r
1115     }\r
1116 \r
1117     request = ippNew();\r
1118 \r
1119     request->request.op.operation_id = CUPS_GET_PPDS;\r
1120     request->request.op.request_id   = 1;\r
1121 \r
1122     language = cupsLangDefault();\r
1123 \r
1124     ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,\r
1125              "attributes-charset", NULL, cupsLangEncoding(language));\r
1126 \r
1127     ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,\r
1128              "attributes-natural-language", NULL, language->language);\r
1129 \r
1130     //ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",\r
1131     //             NULL, "ipp://localhost/printers/");\r
1132 \r
1133     ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",\r
1134                  NULL, "ipp://localhost/printers/officejet_4100");\r
1135 \r
1136     ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "requested-attributes",\r
1137                  NULL, "all");\r
1138 \r
1139     /*\r
1140     * Do the request and get back a response...\r
1141     */\r
1142 \r
1143     if ((response = cupsDoRequest(http, request, "/")) != NULL)\r
1144     {\r
1145 \r
1146         for (attr = response->attrs; attr; attr = attr->next)\r
1147         {\r
1148             PyObject *dict;\r
1149             char *ppdname = NULL;\r
1150 \r
1151             while (attr && attr->group_tag != IPP_TAG_PRINTER)\r
1152                 attr = attr->next;\r
1153 \r
1154             if (!attr)\r
1155                 break;\r
1156 \r
1157             dict = PyDict_New ();\r
1158 \r
1159             for (; attr && attr->group_tag == IPP_TAG_PRINTER; attr = attr->next)\r
1160             {\r
1161                 PyObject *val = NULL;\r
1162 \r
1163                 if (!strcmp (attr->name, "ppd-name") && attr->value_tag == IPP_TAG_NAME)\r
1164                 {\r
1165                     ppdname = attr->values[0].string.text;\r
1166 \r
1167                     //sprintf( buf, "print '%s'", ppdname);\r
1168                     //PyRun_SimpleString( buf );\r
1169                 }\r
1170 \r
1171                 else if (attr->value_tag == IPP_TAG_TEXT || attr->value_tag == IPP_TAG_NAME || attr->value_tag == IPP_TAG_KEYWORD)\r
1172                 //else if ((!strcmp (attr->name, "ppd-natural-language") && attr->value_tag == IPP_TAG_LANGUAGE) ||\r
1173                 //    (!strcmp (attr->name, "ppd-make-and-model") && attr->value_tag == IPP_TAG_TEXT) ||\r
1174                 //    (!strcmp (attr->name, "ppd-make") && attr->value_tag == IPP_TAG_TEXT) ||\r
1175                 //    (!strcmp (attr->name, "ppd-device-id") && attr->value_tag == IPP_TAG_TEXT))\r
1176                 {\r
1177                     val = PyObj_from_UTF8(attr->values[0].string.text);\r
1178                 }\r
1179 \r
1180                 if (val)\r
1181                 {\r
1182                     PyDict_SetItemString (dict, attr->name, val);\r
1183                     Py_DECREF (val);\r
1184                 }\r
1185             }\r
1186 \r
1187             if (ppdname)\r
1188             {\r
1189                 PyDict_SetItemString (result, ppdname, dict);\r
1190             }\r
1191             else\r
1192             {\r
1193                 Py_DECREF (dict);\r
1194             }\r
1195 \r
1196             if (!attr)\r
1197                 break;\r
1198         }\r
1199 \r
1200         //return result;\r
1201     }\r
1202 \r
1203 abort:\r
1204     if ( http != NULL )\r
1205         httpClose( http );\r
1206 \r
1207     if ( response != NULL )\r
1208         ippDelete( response );\r
1209 \r
1210     return result;\r
1211 }\r
1212 \r
1213 \r
1214 PyObject * openPPD( PyObject * self, PyObject * args )\r
1215 {\r
1216     char * printer;\r
1217     FILE * file;\r
1218     int j;\r
1219 \r
1220     if ( !PyArg_ParseTuple( args, "z", &printer ) )\r
1221     {\r
1222         return Py_BuildValue( "" ); // None\r
1223     }\r
1224 \r
1225     if ( ( g_ppd_file = cupsGetPPD( ( const char * ) printer ) ) == NULL )\r
1226     {\r
1227         goto bailout;\r
1228     }\r
1229 \r
1230     if ( ( file = fopen( g_ppd_file, "r" )) == NULL )\r
1231     {\r
1232       unlink(g_ppd_file);\r
1233       g_ppd_file = NULL;\r
1234       goto bailout;\r
1235     }\r
1236 \r
1237     ppd = ppdOpen( file );\r
1238     ppdLocalize( ppd );\r
1239     fclose( file );\r
1240 \r
1241     g_num_dests = cupsGetDests( &g_dests );\r
1242 \r
1243     if ( g_num_dests == 0 )\r
1244     {\r
1245         goto bailout;\r
1246     }\r
1247 \r
1248     if ( ( dest = cupsGetDest( printer, NULL, g_num_dests, g_dests ) ) == NULL )\r
1249     {\r
1250         goto bailout;\r
1251     }\r
1252 \r
1253     ppdMarkDefaults( ppd );\r
1254     cupsMarkOptions( ppd, dest->num_options, dest->options );\r
1255 \r
1256     for ( j = 0; j < dest->num_options; j++ )\r
1257     {\r
1258         if ( cupsGetOption( dest->options[ j ].name, g_num_options, g_options ) == NULL )\r
1259         {\r
1260             g_num_options = cupsAddOption( dest->options[ j ].name, dest->options[ j ].value, g_num_options, &g_options );\r
1261         }\r
1262     }\r
1263 \r
1264 bailout:\r
1265     return Py_BuildValue( "s", g_ppd_file );\r
1266 }\r
1267 \r
1268 \r
1269 PyObject * closePPD( PyObject * self, PyObject * args )\r
1270 {\r
1271     if ( ppd != NULL )\r
1272     {\r
1273         ppdClose( ppd );\r
1274         unlink( g_ppd_file );\r
1275     }\r
1276 \r
1277     ppd = NULL;\r
1278 \r
1279     return Py_BuildValue( "" ); // None\r
1280 }\r
1281 \r
1282 \r
1283 PyObject * getPPD( PyObject * self, PyObject * args )\r
1284 {\r
1285     char * printer;\r
1286 \r
1287     if ( !PyArg_ParseTuple( args, "z", &printer ) )\r
1288     {\r
1289         return Py_BuildValue( "" ); // None\r
1290     }\r
1291 \r
1292     const char * ppd_file;\r
1293     ppd_file = cupsGetPPD( ( const char * ) printer );\r
1294 \r
1295     return Py_BuildValue( "s", ppd_file );\r
1296 \r
1297 }\r
1298
1299 \r
1300 PyObject * getPPDOption( PyObject * self, PyObject * args )\r
1301 {\r
1302     if ( ppd != NULL )\r
1303     {\r
1304         char * option;\r
1305 \r
1306         if ( !PyArg_ParseTuple( args, "z", &option ) )\r
1307         {\r
1308             return Py_BuildValue( "" ); // None\r
1309         }\r
1310 \r
1311         ppd_choice_t * marked_choice;\r
1312         marked_choice = ppdFindMarkedChoice( ppd, option );\r
1313 \r
1314         if ( marked_choice == NULL )\r
1315         {\r
1316             return Py_BuildValue( "" ); // None\r
1317         }\r
1318         else\r
1319         {\r
1320             return Py_BuildValue( "s", marked_choice->text );\r
1321         }\r
1322     }\r
1323     else\r
1324     {\r
1325         return Py_BuildValue( "" ); // None\r
1326     }\r
1327 }\r
1328
1329 PyObject * findPPDAttribute( PyObject * self, PyObject * args )
1330 {
1331         if ( ppd != NULL )
1332         {
1333                 char * name;
1334                 char * spec;
1335
1336                 if ( !PyArg_ParseTuple( args, "zz", &name, &spec ) )
1337                 {
1338                         return Py_BuildValue( "" ); // None
1339                 }
1340                 
1341                 ppd_attr_t * ppd_attr;
1342                 ppd_attr = ppdFindAttr(ppd, name, spec );
1343                 if ( ppd_attr == NULL )
1344                 {
1345                         return Py_BuildValue( "" ); // None
1346                 }
1347                 else
1348                 {
1349                         return Py_BuildValue( "s", ppd_attr->value );
1350                 }
1351         }
1352         else
1353         {
1354                 return Py_BuildValue( "" ); // None
1355         }
1356 }
1357
1358 PyObject * getPPDPageSize( PyObject * self, PyObject * args )\r
1359 {\r
1360     //char buf[1024];\r
1361 \r
1362     if ( ppd != NULL )\r
1363     {\r
1364         ppd_size_t * size = NULL;\r
1365         float width = 0.0;\r
1366         float length = 0.0;\r
1367         ppd_choice_t * page_size = NULL;\r
1368 \r
1369         page_size = ppdFindMarkedChoice( ppd, "PageSize" );\r
1370 \r
1371         //sprintf( buf, "print '%s'", page_size->text );\r
1372         //PyRun_SimpleString( buf );\r
1373 \r
1374         if ( page_size == NULL )\r
1375             goto bailout;\r
1376 \r
1377         size = ppdPageSize( ppd, page_size->text );\r
1378 \r
1379         if ( size == NULL )\r
1380             goto bailout;\r
1381 \r
1382         //sprintf( buf, "print '%s'", size->name );\r
1383         //PyRun_SimpleString( buf );\r
1384 \r
1385         width = ppdPageWidth( ppd, page_size->text );\r
1386         length = ppdPageLength( ppd, page_size->text );\r
1387 \r
1388         return Py_BuildValue( "(sffffff)", page_size->text, width, length, size->left,\r
1389             size->bottom, size->right, size->top );\r
1390     }\r
1391 \r
1392 bailout:\r
1393     return Py_BuildValue( "(sffffff)", "", 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 );\r
1394 }\r
1395 \r
1396 // ***************************************************************************************************\r
1397 \r
1398 \r
1399 \r
1400 PyObject * resetOptions( PyObject * self, PyObject * args )\r
1401 {\r
1402     if ( g_num_options > 0 )\r
1403         cupsFreeOptions( g_num_options, g_options );\r
1404     g_num_options = 0;\r
1405     g_options = ( cups_option_t * ) 0;\r
1406 \r
1407     return Py_BuildValue( "" );\r
1408 \r
1409 }\r
1410 \r
1411 PyObject * addOption( PyObject * self, PyObject * args )\r
1412 {\r
1413     char * option;\r
1414 \r
1415     if ( !PyArg_ParseTuple( args, "z", &option ) )\r
1416     {\r
1417         return Py_BuildValue( "i", 0 );\r
1418     }\r
1419 \r
1420     g_num_options = cupsParseOptions( option, g_num_options, &g_options );\r
1421 \r
1422     return Py_BuildValue( "i", g_num_options ); // >0\r
1423 }\r
1424 \r
1425 PyObject * removeOption( PyObject * self, PyObject * args )\r
1426 {\r
1427     char * option;\r
1428     int j;\r
1429     int r = 0;\r
1430 \r
1431     if ( !PyArg_ParseTuple( args, "z", &option ) )\r
1432     {\r
1433         return Py_BuildValue( "i", 0 );\r
1434     }\r
1435 \r
1436     for (j = 0; j < g_num_options; j++)\r
1437     {\r
1438         if ( !strcasecmp(g_options[j].name, option) )\r
1439         {\r
1440             g_num_options--;\r
1441 \r
1442             if ( j < g_num_options )\r
1443             {\r
1444                 memcpy( (g_options + j), (g_options + j + 1),\r
1445                     sizeof(cups_option_t) * (g_num_options - j) );\r
1446 \r
1447                 r = 1;\r
1448             }\r
1449         }\r
1450     }\r
1451 \r
1452     return Py_BuildValue( "i", r );\r
1453 }\r
1454 \r
1455 \r
1456 PyObject * getOptions( PyObject * self, PyObject * args )\r
1457 {\r
1458     PyObject * option_list;\r
1459     int j;\r
1460 \r
1461     option_list = PyList_New( ( Py_ssize_t ) 0 );\r
1462     for ( j = 0; j < g_num_options; j++ )\r
1463     {\r
1464         PyList_Append( option_list, Py_BuildValue( "(ss)", g_options[ j ].name, g_options[ j ].value ) );\r
1465     }\r
1466 \r
1467     return option_list;\r
1468 }\r
1469 \r
1470 \r
1471 // ***************************************************************************************************\r
1472 \r
1473 \r
1474 \r
1475 PyObject * getGroupList( PyObject * self, PyObject * args )\r
1476 {\r
1477     PyObject * group_list;\r
1478     ppd_group_t *group;\r
1479     int i;\r
1480 \r
1481 /*  debug("at 0"); */\r
1482 \r
1483     if ( ppd != NULL && dest != NULL )\r
1484     {\r
1485 /*      debug("at 1"); */\r
1486 \r
1487         group_list = PyList_New( ( Py_ssize_t ) 0 );\r
1488         for ( i = ppd->num_groups, group = ppd->groups; i > 0; i--, group++ )\r
1489         {\r
1490 /*          debug(group->name); */\r
1491             PyList_Append( group_list, PyObj_from_UTF8( group->name ) );\r
1492         }\r
1493 \r
1494         return group_list;\r
1495     }\r
1496 \r
1497     return PyList_New( ( Py_ssize_t ) 0 );\r
1498 }\r
1499 \r
1500 \r
1501 PyObject * getGroup( PyObject * self, PyObject * args )\r
1502 {\r
1503     const char *the_group;\r
1504     ppd_group_t *group;\r
1505     int i;\r
1506 \r
1507     if ( !PyArg_ParseTuple( args, "z", &the_group ) )\r
1508     {\r
1509         goto bailout;\r
1510     }\r
1511 \r
1512     if ( ppd != NULL && dest != NULL )\r
1513     {\r
1514         for ( i = ppd->num_groups, group = ppd->groups; i > 0; i--, group++ )\r
1515         {\r
1516             if ( strcasecmp( group->name, the_group ) == 0 )\r
1517             {\r
1518                 return Py_BuildValue( "(si)", group->text, group->num_subgroups);\r
1519             }\r
1520         }\r
1521     }\r
1522 \r
1523 bailout:\r
1524     return Py_BuildValue( "" );\r
1525 }\r
1526 \r
1527 \r
1528 \r
1529 PyObject * getOptionList( PyObject * self, PyObject * args )\r
1530 {\r
1531     PyObject * option_list;\r
1532     const char *the_group;\r
1533     ppd_group_t *group;\r
1534     int i, j;\r
1535     ppd_option_t *option;\r
1536 \r
1537     if ( !PyArg_ParseTuple( args, "z", &the_group ) )\r
1538     {\r
1539         goto bailout;\r
1540     }\r
1541 \r
1542     if ( ppd != NULL && dest != NULL )\r
1543     {\r
1544         option_list = PyList_New( ( Py_ssize_t ) 0 );\r
1545 \r
1546         for ( i = ppd->num_groups, group = ppd->groups; i > 0; i--, group++ )\r
1547         {\r
1548             if ( strcasecmp( group->name, the_group ) == 0 )\r
1549             {\r
1550                 for ( j = group->num_options, option = group->options; j > 0; j--, option++ )\r
1551                 {\r
1552                     PyList_Append( option_list, PyObj_from_UTF8( option->keyword ) );\r
1553                 }\r
1554 \r
1555                 break;\r
1556             }\r
1557         }\r
1558 \r
1559         return option_list;\r
1560     }\r
1561 \r
1562 \r
1563 \r
1564 bailout:\r
1565     return PyList_New( ( Py_ssize_t ) 0 );\r
1566 }\r
1567 \r
1568 \r
1569 \r
1570 \r
1571 PyObject * getOption( PyObject * self, PyObject * args )\r
1572 {\r
1573     const char *the_group;\r
1574     const char *the_option;\r
1575     ppd_group_t *group;\r
1576     int i, j;\r
1577     ppd_option_t *option;\r
1578 \r
1579 \r
1580     if ( !PyArg_ParseTuple( args, "zz", &the_group, &the_option ) )\r
1581     {\r
1582         goto bailout;\r
1583     }\r
1584 \r
1585     if ( ppd != NULL && dest != NULL )\r
1586     {\r
1587 \r
1588         for ( i = ppd->num_groups, group = ppd->groups; i > 0; i--, group++ )\r
1589         {\r
1590             if ( strcasecmp( group->name, the_group ) == 0 )\r
1591             {\r
1592                 for ( j = group->num_options, option = group->options; j > 0; j--, option++ )\r
1593                 {\r
1594                     if ( strcasecmp( option->keyword, the_option ) == 0 )\r
1595                     {\r
1596                         return Py_BuildValue( "(ssbi)", option->text, option->defchoice,\r
1597                                               option->conflicted > 0 ? 1 : 0, option->ui );\r
1598                     }\r
1599                 }\r
1600             }\r
1601         }\r
1602     }\r
1603 \r
1604 bailout:\r
1605     return Py_BuildValue( "" );\r
1606 }\r
1607 \r
1608 \r
1609 PyObject * getChoiceList( PyObject * self, PyObject * args )\r
1610 {\r
1611     PyObject * choice_list;\r
1612     const char *the_group;\r
1613     const char *the_option;\r
1614     ppd_group_t *group;\r
1615     int i, j, k;\r
1616     ppd_option_t *option;\r
1617     ppd_choice_t *choice;\r
1618 \r
1619     if ( !PyArg_ParseTuple( args, "zz", &the_group, &the_option ) )\r
1620     {\r
1621         goto bailout;\r
1622     }\r
1623 \r
1624     if ( ppd != NULL && dest != NULL )\r
1625     {\r
1626         choice_list = PyList_New( ( Py_ssize_t ) 0 );\r
1627 \r
1628         for ( i = ppd->num_groups, group = ppd->groups; i > 0; i--, group++ )\r
1629         {\r
1630             if ( strcasecmp( group->name, the_group ) == 0 )\r
1631             {\r
1632                 for ( j = group->num_options, option = group->options; j > 0; j--, option++ )\r
1633                 {\r
1634                     if ( strcasecmp( option->keyword, the_option ) == 0 )\r
1635                     {\r
1636                         for ( k = option->num_choices, choice = option->choices; k > 0; k--, choice++ )\r
1637                         {\r
1638                             PyList_Append( choice_list, PyObj_from_UTF8( choice->choice ) );\r
1639                         }\r
1640 \r
1641                         break;\r
1642                     }\r
1643                 }\r
1644                 break;\r
1645             }\r
1646         }\r
1647 \r
1648         return choice_list;\r
1649     }\r
1650 \r
1651 \r
1652 bailout:\r
1653     return PyList_New( ( Py_ssize_t ) 0 );\r
1654 }\r
1655 \r
1656 \r
1657 \r
1658 PyObject * getChoice( PyObject * self, PyObject * args )\r
1659 {\r
1660     const char * the_group;\r
1661     const char *the_option;\r
1662     const char *the_choice;\r
1663     ppd_group_t *group;\r
1664     int i, j, k;\r
1665     ppd_option_t *option;\r
1666     ppd_choice_t *choice;\r
1667 \r
1668 \r
1669     if ( !PyArg_ParseTuple( args, "zzz", &the_group, &the_option, &the_choice ) )\r
1670     {\r
1671         goto bailout;\r
1672     }\r
1673 \r
1674     if ( ppd != NULL && dest != NULL )\r
1675     {\r
1676         for ( i = ppd->num_groups, group = ppd->groups; i > 0; i--, group++ )\r
1677         {\r
1678             if ( strcasecmp( group->name, the_group ) == 0 )\r
1679             {\r
1680                 for ( j = group->num_options, option = group->options; j > 0; j--, option++ )\r
1681                 {\r
1682                     if ( strcasecmp( option->keyword, the_option ) == 0 )\r
1683                     {\r
1684                         for ( k = option->num_choices, choice = option->choices; k > 0; k--, choice++ )\r
1685                         {\r
1686                             if ( strcasecmp( choice->choice, the_choice ) == 0 )\r
1687                             {\r
1688                                 return Py_BuildValue( "(sb)", choice->text, choice->marked > 0 ? 1 : 0 );\r
1689                             }\r
1690                         }\r
1691                     }\r
1692                 }\r
1693             }\r
1694         }\r
1695     }\r
1696 \r
1697 \r
1698 bailout:\r
1699     return Py_BuildValue( "" );\r
1700 \r
1701 \r
1702 \r
1703 }\r
1704 \r
1705 PyObject * setOptions( PyObject * self, PyObject * args )\r
1706 {\r
1707     if ( ppd != NULL && dest != NULL )\r
1708     {\r
1709         cupsFreeOptions( dest->num_options, dest->options );\r
1710         dest->num_options = g_num_options;\r
1711         dest->options = g_options;\r
1712         cupsSetDests( g_num_dests, g_dests );\r
1713         cupsMarkOptions( ppd, dest->num_options, dest->options );\r
1714     }\r
1715 \r
1716     return Py_BuildValue( "" );\r
1717 }\r
1718 \r
1719 // ***************************************************************************************************\r
1720 \r
1721 PyObject * printFileWithOptions( PyObject * self, PyObject * args )\r
1722 {\r
1723     char * printer;\r
1724     char * filename;\r
1725     char * title;\r
1726     int job_id = -1;\r
1727     cups_dest_t * dests = NULL;\r
1728     cups_dest_t * dest = NULL;\r
1729     int num_dests = 0;\r
1730     int i = 0;\r
1731 \r
1732     if ( !PyArg_ParseTuple( args, "zzz", &printer, &filename, &title ) )\r
1733     {\r
1734         return Py_BuildValue( "" ); // None\r
1735     }\r
1736 \r
1737     num_dests = cupsGetDests(&dests);\r
1738     dest = cupsGetDest( printer, NULL, num_dests, dests );\r
1739 \r
1740     if ( dest != NULL )\r
1741     {\r
1742         for( i = 0; i < dest->num_options; i++ )\r
1743         {\r
1744             if ( cupsGetOption( dest->options[i].name, g_num_options, g_options ) == NULL )\r
1745                 g_num_options = cupsAddOption( dest->options[i].name, dest->options[i].value, g_num_options, &g_options );\r
1746 \r
1747         }\r
1748 \r
1749         job_id = cupsPrintFile( dest->name, filename, title, g_num_options, g_options );\r
1750 \r
1751         return Py_BuildValue( "i", job_id );\r
1752     }\r
1753 \r
1754     return Py_BuildValue( "i", -1 );\r
1755 }\r
1756 \r
1757 // ***************************************************************************************************\r
1758 \r
1759 static PyObject * passwordFunc = NULL;\r
1760 static char *passwordPrompt = NULL;\r
1761 \r
1762 const char * password_callback(const char * prompt)\r
1763 {\r
1764 \r
1765     PyObject *result = NULL;\r
1766     PyObject *usernameObj = NULL;\r
1767     PyObject *passwordObj = NULL;\r
1768     char *username = NULL;\r
1769     char *password = NULL;\r
1770 \r
1771     if (passwordFunc != NULL)  {\r
1772 \r
1773         if (passwordPrompt)\r
1774             prompt = passwordPrompt;\r
1775 \r
1776         result = PyObject_CallFunction(passwordFunc, "s", prompt);\r
1777         if (!result)\r
1778             return "";\r
1779 \r
1780         usernameObj = PyTuple_GetItem(result, 0);\r
1781         if (!usernameObj)\r
1782             return "";\r
1783         username = PyString_AsString(usernameObj);\r
1784 /*      printf("usernameObj=%p, username='%s'\n", usernameObj, username); */\r
1785         if (!username)\r
1786             return "";\r
1787 \r
1788         passwordObj = PyTuple_GetItem(result, 1);\r
1789         if (!passwordObj)\r
1790             return "";\r
1791         password = PyString_AsString(passwordObj);\r
1792 /*      printf("passwordObj=%p, password='%s'\n", passwordObj, password); */\r
1793         if (!password)\r
1794             return "";\r
1795 \r
1796         cupsSetUser(username);\r
1797         return password;\r
1798 \r
1799     }\r
1800 \r
1801     return "";\r
1802 \r
1803 }\r
1804 \r
1805 PyObject *setPasswordPrompt(PyObject *self, PyObject *args)\r
1806 {\r
1807 \r
1808     char *userPrompt = NULL;\r
1809 \r
1810     if (!PyArg_ParseTuple(args, "z", &userPrompt))\r
1811         return Py_BuildValue("");\r
1812 \r
1813     if (strlen(userPrompt) != 0)\r
1814         passwordPrompt = userPrompt;\r
1815     else\r
1816         passwordPrompt = NULL;\r
1817 \r
1818     return Py_BuildValue("");\r
1819 \r
1820 }\r
1821 \r
1822 PyObject * setPasswordCallback( PyObject * self, PyObject * args )\r
1823 {\r
1824     if( !PyArg_ParseTuple( args, "O", &passwordFunc ) )\r
1825     {\r
1826         return Py_BuildValue( "i", 0 );\r
1827     }\r
1828 \r
1829     cupsSetPasswordCB(password_callback);\r
1830 \r
1831     return Py_BuildValue( "i", 1 );\r
1832 }\r
1833 \r
1834 \r
1835 PyObject * getPassword( PyObject * self, PyObject * args )\r
1836 {\r
1837     const char * pwd;\r
1838     char * prompt;\r
1839 \r
1840     if( !PyArg_ParseTuple( args, "s", &prompt ) )\r
1841     {\r
1842         return Py_BuildValue( "" );\r
1843     }\r
1844 \r
1845     pwd = cupsGetPassword( prompt );\r
1846 \r
1847     if( pwd )\r
1848     {\r
1849         return Py_BuildValue( "s", pwd );\r
1850     }\r
1851     else\r
1852     {\r
1853         return Py_BuildValue( "" );\r
1854     }\r
1855 }\r
1856 \r
1857 \r
1858 \r
1859 \r
1860 \r
1861 \r
1862 // ***************************************************************************************************\r
1863 \r
1864 static PyMethodDef cupsext_methods[] =\r
1865     {\r
1866         { "getPrinters", ( PyCFunction ) getPrinters, METH_VARARGS },\r
1867         { "addPrinter", ( PyCFunction ) addPrinter, METH_VARARGS },\r
1868         { "delPrinter", ( PyCFunction ) delPrinter, METH_VARARGS },\r
1869         { "getDefaultPrinter", ( PyCFunction ) getDefaultPrinter, METH_VARARGS },\r
1870         { "setDefaultPrinter", ( PyCFunction ) setDefaultPrinter, METH_VARARGS },\r
1871         { "controlPrinter", ( PyCFunction ) controlPrinter, METH_VARARGS },\r
1872         { "getPPDList", ( PyCFunction ) getPPDList, METH_VARARGS },\r
1873         { "getPPD", ( PyCFunction ) getPPD, METH_VARARGS },\r
1874         { "openPPD", ( PyCFunction ) openPPD, METH_VARARGS },\r
1875         { "closePPD", ( PyCFunction ) closePPD, METH_VARARGS },\r
1876         { "getPPDOption", ( PyCFunction ) getPPDOption, METH_VARARGS },\r
1877         { "getPPDPageSize", ( PyCFunction ) getPPDPageSize, METH_VARARGS },\r
1878         { "getVersion", ( PyCFunction ) getVersion, METH_VARARGS },\r
1879         { "getVersionTuple", ( PyCFunction ) getVersionTuple, METH_VARARGS },\r
1880         { "cancelJob", ( PyCFunction ) cancelJob, METH_VARARGS },\r
1881         { "getJobs", ( PyCFunction ) getJobs, METH_VARARGS },\r
1882         { "getServer", ( PyCFunction ) getServer, METH_VARARGS },\r
1883         { "setServer", ( PyCFunction ) setServer, METH_VARARGS },\r
1884         { "addOption", ( PyCFunction ) addOption, METH_VARARGS },\r
1885         { "removeOption", ( PyCFunction ) removeOption, METH_VARARGS },\r
1886         { "resetOptions", ( PyCFunction ) resetOptions, METH_VARARGS },\r
1887         { "printFileWithOptions", ( PyCFunction ) printFileWithOptions, METH_VARARGS },\r
1888         { "Job", ( PyCFunction ) newJob, METH_VARARGS | METH_KEYWORDS },\r
1889         { "Printer", ( PyCFunction ) newPrinter, METH_VARARGS | METH_KEYWORDS },\r
1890         { "getGroupList", ( PyCFunction ) getGroupList, METH_VARARGS },\r
1891         { "getGroup", ( PyCFunction ) getGroup, METH_VARARGS },\r
1892         { "getOptionList", ( PyCFunction ) getOptionList, METH_VARARGS },\r
1893         { "getOption", ( PyCFunction ) getOption, METH_VARARGS },\r
1894         { "getChoiceList", ( PyCFunction ) getChoiceList, METH_VARARGS },\r
1895         { "getChoice", ( PyCFunction ) getChoice, METH_VARARGS },\r
1896         { "setOptions", ( PyCFunction ) setOptions, METH_VARARGS },\r
1897         { "getOptions", ( PyCFunction ) getOptions, METH_VARARGS },\r
1898         { "setPasswordPrompt", (PyCFunction) setPasswordPrompt, METH_VARARGS },\r
1899         { "setPasswordCallback", ( PyCFunction ) setPasswordCallback, METH_VARARGS },\r
1900         { "getPassword", ( PyCFunction ) getPassword, METH_VARARGS },
1901                 { "findPPDAttribute", ( PyCFunction ) findPPDAttribute, METH_VARARGS },
1902                 { NULL, NULL }\r
1903     };\r
1904 \r
1905 \r
1906 static char cupsext_documentation[] = "Python extension for CUPS 1.x";\r
1907 \r
1908 void initcupsext( void )\r
1909 {\r
1910 \r
1911     PyObject * mod = Py_InitModule4( "cupsext", cupsext_methods,\r
1912                                      cupsext_documentation, ( PyObject* ) NULL,\r
1913                                      PYTHON_API_VERSION );\r
1914 \r
1915     if ( mod == NULL )\r
1916         return ;\r
1917 \r
1918 \r
1919 }\r
1920 \r
1921 \r