57 | | |
| 59 | |
| 60 | IPP_VERSION = "1.1" # default version number |
| 61 | |
| 62 | IPP_PORT = 631 |
| 63 | |
| 64 | IPP_MAX_NAME = 256 |
| 65 | IPP_MAX_VALUES = 8 |
| 66 | |
| 67 | IPP_TAG_ZERO = 0x00 |
| 68 | IPP_TAG_OPERATION = 0x01 |
| 69 | IPP_TAG_JOB = 0x02 |
| 70 | IPP_TAG_END = 0x03 |
| 71 | IPP_TAG_PRINTER = 0x04 |
| 72 | IPP_TAG_UNSUPPORTED_GROUP = 0x05 |
| 73 | IPP_TAG_SUBSCRIPTION = 0x06 |
| 74 | IPP_TAG_EVENT_NOTIFICATION = 0x07 |
| 75 | IPP_TAG_UNSUPPORTED_VALUE = 0x10 |
| 76 | IPP_TAG_DEFAULT = 0x11 |
| 77 | IPP_TAG_UNKNOWN = 0x12 |
| 78 | IPP_TAG_NOVALUE = 0x13 |
| 79 | IPP_TAG_NOTSETTABLE = 0x15 |
| 80 | IPP_TAG_DELETEATTR = 0x16 |
| 81 | IPP_TAG_ADMINDEFINE = 0x17 |
| 82 | IPP_TAG_INTEGER = 0x21 |
| 83 | IPP_TAG_BOOLEAN = 0x22 |
| 84 | IPP_TAG_ENUM = 0x23 |
| 85 | IPP_TAG_STRING = 0x30 |
| 86 | IPP_TAG_DATE = 0x31 |
| 87 | IPP_TAG_RESOLUTION = 0x32 |
| 88 | IPP_TAG_RANGE = 0x33 |
| 89 | IPP_TAG_BEGIN_COLLECTION = 0x34 |
| 90 | IPP_TAG_TEXTLANG = 0x35 |
| 91 | IPP_TAG_NAMELANG = 0x36 |
| 92 | IPP_TAG_END_COLLECTION = 0x37 |
| 93 | IPP_TAG_TEXT = 0x41 |
| 94 | IPP_TAG_NAME = 0x42 |
| 95 | IPP_TAG_KEYWORD = 0x44 |
| 96 | IPP_TAG_URI = 0x45 |
| 97 | IPP_TAG_URISCHEME = 0x46 |
| 98 | IPP_TAG_CHARSET = 0x47 |
| 99 | IPP_TAG_LANGUAGE = 0x48 |
| 100 | IPP_TAG_MIMETYPE = 0x49 |
| 101 | IPP_TAG_MEMBERNAME = 0x4a |
| 102 | IPP_TAG_MASK = 0x7fffffff |
| 103 | IPP_TAG_COPY = -0x7fffffff-1 |
| 104 | |
| 105 | IPP_RES_PER_INCH = 3 |
| 106 | IPP_RES_PER_CM = 4 |
| 107 | |
| 108 | IPP_FINISHINGS_NONE = 3 |
| 109 | IPP_FINISHINGS_STAPLE = 4 |
| 110 | IPP_FINISHINGS_PUNCH = 5 |
| 111 | IPP_FINISHINGS_COVER = 6 |
| 112 | IPP_FINISHINGS_BIND = 7 |
| 113 | IPP_FINISHINGS_SADDLE_STITCH = 8 |
| 114 | IPP_FINISHINGS_EDGE_STITCH = 9 |
| 115 | IPP_FINISHINGS_FOLD = 10 |
| 116 | IPP_FINISHINGS_TRIM = 11 |
| 117 | IPP_FINISHINGS_BALE = 12 |
| 118 | IPP_FINISHINGS_BOOKLET_MAKER = 13 |
| 119 | IPP_FINISHINGS_JOB_OFFSET = 14 |
| 120 | IPP_FINISHINGS_STAPLE_TOP_LEFT = 20 |
| 121 | IPP_FINISHINGS_STAPLE_BOTTOM_LEFT = 21 |
| 122 | IPP_FINISHINGS_STAPLE_TOP_RIGHT = 22 |
| 123 | IPP_FINISHINGS_STAPLE_BOTTOM_RIGHT = 23 |
| 124 | IPP_FINISHINGS_EDGE_STITCH_LEFT = 24 |
| 125 | IPP_FINISHINGS_EDGE_STITCH_TOP = 25 |
| 126 | IPP_FINISHINGS_EDGE_STITCH_RIGHT = 26 |
| 127 | IPP_FINISHINGS_EDGE_STITCH_BOTTOM = 27 |
| 128 | IPP_FINISHINGS_STAPLE_DUAL_LEFT = 28 |
| 129 | IPP_FINISHINGS_STAPLE_DUAL_TOP = 29 |
| 130 | IPP_FINISHINGS_STAPLE_DUAL_RIGHT = 30 |
| 131 | IPP_FINISHINGS_STAPLE_DUAL_BOTTOM = 31 |
| 132 | IPP_FINISHINGS_BIND_LEFT = 50 |
| 133 | IPP_FINISHINGS_BIND_TOP = 51 |
| 134 | IPP_FINISHINGS_BIND_RIGHT = 52 |
| 135 | IPP_FINISHINGS_BIND_BOTTO = 53 |
| 136 | |
| 137 | IPP_PORTRAIT = 3 |
| 138 | IPP_LANDSCAPE = 4 |
| 139 | IPP_REVERSE_LANDSCAPE = 5 |
| 140 | IPP_REVERSE_PORTRAIT = 6 |
| 141 | |
| 142 | IPP_QUALITY_DRAFT = 3 |
| 143 | IPP_QUALITY_NORMAL = 4 |
| 144 | IPP_QUALITY_HIGH = 5 |
| 145 | |
| 146 | IPP_JOB_PENDING = 3 |
| 147 | IPP_JOB_HELD = 4 |
| 148 | IPP_JOB_PROCESSING = 5 |
| 149 | IPP_JOB_STOPPED = 6 |
| 150 | IPP_JOB_CANCELLED = 7 |
| 151 | IPP_JOB_ABORTED = 8 |
| 152 | IPP_JOB_COMPLETE = 9 |
| 153 | |
| 154 | IPP_PRINTER_IDLE = 3 |
| 155 | IPP_PRINTER_PROCESSING = 4 |
| 156 | IPP_PRINTER_STOPPED = 5 |
| 157 | |
| 158 | IPP_ERROR = -1 |
| 159 | IPP_IDLE = 0 |
| 160 | IPP_HEADER = 1 |
| 161 | IPP_ATTRIBUTE = 2 |
| 162 | IPP_DATA = 3 |
| 163 | |
| 164 | IPP_PRINT_JOB = 0x0002 |
| 165 | IPP_PRINT_URI = 0x0003 |
| 166 | IPP_VALIDATE_JOB = 0x0004 |
| 167 | IPP_CREATE_JOB = 0x0005 |
| 168 | IPP_SEND_DOCUMENT = 0x0006 |
| 169 | IPP_SEND_URI = 0x0007 |
| 170 | IPP_CANCEL_JOB = 0x0008 |
| 171 | IPP_GET_JOB_ATTRIBUTES = 0x0009 |
| 172 | IPP_GET_JOBS = 0x000a |
| 173 | IPP_GET_PRINTER_ATTRIBUTES = 0x000b |
| 174 | IPP_HOLD_JOB = 0x000c |
| 175 | IPP_RELEASE_JOB = 0x000d |
| 176 | IPP_RESTART_JOB = 0x000e |
| 177 | IPP_PAUSE_PRINTER = 0x0010 |
| 178 | IPP_RESUME_PRINTER = 0x0011 |
| 179 | IPP_PURGE_JOBS = 0x0012 |
| 180 | IPP_SET_PRINTER_ATTRIBUTES = 0x0013 |
| 181 | IPP_SET_JOB_ATTRIBUTES = 0x0014 |
| 182 | IPP_GET_PRINTER_SUPPORTED_VALUES = 0x0015 |
| 183 | IPP_CREATE_PRINTER_SUBSCRIPTION = 0x0016 |
| 184 | IPP_CREATE_JOB_SUBSCRIPTION = 0x0017 |
| 185 | IPP_GET_SUBSCRIPTION_ATTRIBUTES = 0x0018 |
| 186 | IPP_GET_SUBSCRIPTIONS = 0x0019 |
| 187 | IPP_RENEW_SUBSCRIPTION = 0x001a |
| 188 | IPP_CANCEL_SUBSCRIPTION = 0x001b |
| 189 | IPP_GET_NOTIFICATIONS = 0x001c |
| 190 | IPP_SEND_NOTIFICATIONS = 0x001d |
| 191 | IPP_GET_PRINT_SUPPORT_FILES = 0x0021 |
| 192 | IPP_ENABLE_PRINTER = 0x0022 |
| 193 | IPP_DISABLE_PRINTER = 0x0023 |
| 194 | IPP_PAUSE_PRINTER_AFTER_CURRENT_JOB = 0x0024 |
| 195 | IPP_HOLD_NEW_JOBS = 0x0025 |
| 196 | IPP_RELEASE_HELD_NEW_JOBS = 0x0026 |
| 197 | IPP_DEACTIVATE_PRINTER = 0x0027 |
| 198 | IPP_ACTIVATE_PRINTER = 0x0028 |
| 199 | IPP_RESTART_PRINTER = 0x0029 |
| 200 | IPP_SHUTDOWN_PRINTER = 0x002a |
| 201 | IPP_STARTUP_PRINTER = 0x002b |
| 202 | IPP_REPROCESS_JOB = 0x002c |
| 203 | IPP_CANCEL_CURRENT_JOB = 0x002d |
| 204 | IPP_SUSPEND_CURRENT_JOB = 0x002e |
| 205 | IPP_RESUME_JOB = 0x002f |
| 206 | IPP_PROMOTE_JOB = 0x0030 |
| 207 | IPP_SCHEDULE_JOB_AFTER = 0x0031 |
| 208 | IPP_PRIVATE = 0x4000 |
| 209 | CUPS_GET_DEFAULT = 0x4001 |
| 210 | CUPS_GET_PRINTERS = 0x4002 |
| 211 | CUPS_ADD_PRINTER = 0x4003 |
| 212 | CUPS_DELETE_PRINTER = 0x4004 |
| 213 | CUPS_GET_CLASSES = 0x4005 |
| 214 | CUPS_ADD_CLASS = 0x4006 |
| 215 | CUPS_DELETE_CLASS = 0x4007 |
| 216 | CUPS_ACCEPT_JOBS = 0x4008 |
| 217 | CUPS_REJECT_JOBS = 0x4009 |
| 218 | CUPS_SET_DEFAULT = 0x400a |
| 219 | CUPS_GET_DEVICES = 0x400b |
| 220 | CUPS_GET_PPDS = 0x400c |
| 221 | CUPS_MOVE_JOB = 0x400d |
| 222 | CUPS_AUTHENTICATE_JOB = 0x400e |
| 223 | |
| 224 | IPP_OK = 0x0000 |
| 225 | IPP_OK_SUBST = 0x0001 |
| 226 | IPP_OK_CONFLICT = 0x0002 |
| 227 | IPP_OK_IGNORED_SUBSCRIPTIONS = 0x0003 |
| 228 | IPP_OK_IGNORED_NOTIFICATIONS = 0x0004 |
| 229 | IPP_OK_TOO_MANY_EVENTS = 0x0005 |
| 230 | IPP_OK_BUT_CANCEL_SUBSCRIPTION = 0x0006 |
| 231 | IPP_REDIRECTION_OTHER_SITE = 0x0300 |
| 232 | IPP_BAD_REQUEST = 0x0400 |
| 233 | IPP_FORBIDDEN = 0x0401 |
| 234 | IPP_NOT_AUTHENTICATED = 0x0402 |
| 235 | IPP_NOT_AUTHORIZED = 0x0403 |
| 236 | IPP_NOT_POSSIBLE = 0x0404 |
| 237 | IPP_TIMEOUT = 0x0405 |
| 238 | IPP_NOT_FOUND = 0x0406 |
| 239 | IPP_GONE = 0x0407 |
| 240 | IPP_REQUEST_ENTITY = 0x0408 |
| 241 | IPP_REQUEST_VALUE = 0x0409 |
| 242 | IPP_DOCUMENT_FORMAT = 0x040a |
| 243 | IPP_ATTRIBUTES = 0x040b |
| 244 | IPP_URI_SCHEME = 0x040c |
| 245 | IPP_CHARSET = 0x040d |
| 246 | IPP_CONFLICT = 0x040e |
| 247 | IPP_COMPRESSION_NOT_SUPPORTED = 0x040f |
| 248 | IPP_COMPRESSION_ERROR = 0x0410 |
| 249 | IPP_DOCUMENT_FORMAT_ERROR = 0x0411 |
| 250 | IPP_DOCUMENT_ACCESS_ERROR = 0x0412 |
| 251 | IPP_ATTRIBUTES_NOT_SETTABLE = 0x0413 |
| 252 | IPP_IGNORED_ALL_SUBSCRIPTIONS = 0x0414 |
| 253 | IPP_TOO_MANY_SUBSCRIPTIONS = 0x0415 |
| 254 | IPP_IGNORED_ALL_NOTIFICATIONS = 0x0416 |
| 255 | IPP_PRINT_SUPPORT_FILE_NOT_FOUND = 0x0417 |
| 256 | |
| 257 | IPP_INTERNAL_ERROR = 0x0500 |
| 258 | IPP_OPERATION_NOT_SUPPORTED = 0x0501 |
| 259 | IPP_SERVICE_UNAVAILABLE = 0x0502 |
| 260 | IPP_VERSION_NOT_SUPPORTED = 0x0503 |
| 261 | IPP_DEVICE_ERROR = 0x0504 |
| 262 | IPP_TEMPORARY_ERROR = 0x0505 |
| 263 | IPP_NOT_ACCEPTING = 0x0506 |
| 264 | IPP_PRINTER_BUSY = 0x0507 |
| 265 | IPP_ERROR_JOB_CANCELLED = 0x0508 |
| 266 | IPP_MULTIPLE_JOBS_NOT_SUPPORTED = 0x0509 |
| 267 | IPP_PRINTER_IS_DEACTIVATED = 0x50a |
| 268 | |
| 269 | CUPS_PRINTER_LOCAL = 0x0000 |
| 270 | CUPS_PRINTER_CLASS = 0x0001 |
| 271 | CUPS_PRINTER_REMOTE = 0x0002 |
| 272 | CUPS_PRINTER_BW = 0x0004 |
| 273 | CUPS_PRINTER_COLOR = 0x0008 |
| 274 | CUPS_PRINTER_DUPLEX = 0x0010 |
| 275 | CUPS_PRINTER_STAPLE = 0x0020 |
| 276 | CUPS_PRINTER_COPIES = 0x0040 |
| 277 | CUPS_PRINTER_COLLATE = 0x0080 |
| 278 | CUPS_PRINTER_PUNCH = 0x0100 |
| 279 | CUPS_PRINTER_COVER = 0x0200 |
| 280 | CUPS_PRINTER_BIND = 0x0400 |
| 281 | CUPS_PRINTER_SORT = 0x0800 |
| 282 | CUPS_PRINTER_SMALL = 0x1000 |
| 283 | CUPS_PRINTER_MEDIUM = 0x2000 |
| 284 | CUPS_PRINTER_LARGE = 0x4000 |
| 285 | CUPS_PRINTER_VARIABLE = 0x8000 |
| 286 | CUPS_PRINTER_IMPLICIT = 0x1000 |
| 287 | CUPS_PRINTER_DEFAULT = 0x2000 |
| 288 | CUPS_PRINTER_FAX = 0x4000 |
| 289 | CUPS_PRINTER_REJECTING = 0x8000 |
| 290 | CUPS_PRINTER_DELETE = 0x1000 |
| 291 | CUPS_PRINTER_NOT_SHARED = 0x2000 |
| 292 | CUPS_PRINTER_AUTHENTICATED = 0x4000 |
| 293 | CUPS_PRINTER_COMMANDS = 0x8000 |
| 294 | CUPS_PRINTER_OPTIONS = 0xe6ff |
| 295 | |
| 296 | class FakeAttribute : |
| 297 | """Fakes an IPPRequest attribute to simplify usage syntax.""" |
| 298 | def __init__(self, request, name) : |
| 299 | """Initializes the fake attribute.""" |
| 300 | self.request = request |
| 301 | self.name = name |
| 302 | |
| 303 | def __setitem__(self, key, value) : |
| 304 | """Appends the value to the real attribute.""" |
| 305 | attributeslist = getattr(self.request, "_%s_attributes" % self.name) |
| 306 | for i in range(len(attributeslist)) : |
| 307 | attribute = attributeslist[i] |
| 308 | for j in range(len(attribute)) : |
| 309 | (attrname, attrvalue) = attribute[j] |
| 310 | if attrname == key : |
| 311 | attribute[j][1].append(value) |
| 312 | return |
| 313 | attribute.append((key, [value])) |
| 314 | |
| 315 | def __getitem__(self, key) : |
| 316 | """Returns an attribute's value.""" |
| 317 | answer = [] |
| 318 | attributeslist = getattr(self.request, "_%s_attributes" % self.name) |
| 319 | for i in range(len(attributeslist)) : |
| 320 | attribute = attributeslist[i] |
| 321 | for j in range(len(attribute)) : |
| 322 | (attrname, attrvalue) = attribute[j] |
| 323 | if attrname == key : |
| 324 | answer.extend(attrvalue) |
| 325 | if answer : |
| 326 | return answer |
| 327 | raise KeyError, key |
| 328 | |
208 | | tagprinted = 0 |
209 | | for (attrname, value) in getattr(self, "%s_attributes" % attrtype).items() : |
210 | | if not tagprinted : |
211 | | mybuffer.append(chr(self.dictags["%s-attributes-tag" % attrtype])) |
212 | | tagprinted = 1 |
213 | | if type(value) != type([]) : |
214 | | value = [ value ] |
215 | | for (vtype, val) in value : |
216 | | mybuffer.append(chr(self.dictags[vtype])) |
217 | | mybuffer.append(pack(">H", len(attrname))) |
218 | | mybuffer.append(attrname) |
219 | | if vtype in ("integer", "enum") : |
220 | | mybuffer.append(pack(">H", 4)) |
221 | | mybuffer.append(pack(">I", val)) |
222 | | elif vtype == "boolean" : |
223 | | mybuffer.append(pack(">H", 1)) |
224 | | mybuffer.append(chr(val)) |
225 | | else : |
226 | | mybuffer.append(pack(">H", len(val))) |
227 | | mybuffer.append(val) |
228 | | mybuffer.append(chr(self.dictags["end-of-attributes-tag"])) |
| 477 | for attribute in getattr(self, "_%s_attributes" % attrtype) : |
| 478 | if attribute : |
| 479 | mybuffer.append(chr(self.tagvalues["%s-attributes-tag" % attrtype])) |
| 480 | for (attrname, value) in attribute : |
| 481 | nameprinted = 0 |
| 482 | for (vtype, val) in value : |
| 483 | mybuffer.append(chr(self.tagvalues[vtype])) |
| 484 | if not nameprinted : |
| 485 | mybuffer.append(pack(">H", len(attrname))) |
| 486 | mybuffer.append(attrname) |
| 487 | nameprinted = 1 |
| 488 | else : |
| 489 | mybuffer.append(pack(">H", 0)) |
| 490 | if vtype in ("integer", "enum") : |
| 491 | mybuffer.append(pack(">H", 4)) |
| 492 | mybuffer.append(pack(">I", val)) |
| 493 | elif vtype == "boolean" : |
| 494 | mybuffer.append(pack(">H", 1)) |
| 495 | mybuffer.append(chr(val)) |
| 496 | else : |
| 497 | mybuffer.append(pack(">H", len(val))) |
| 498 | mybuffer.append(val) |
| 499 | mybuffer.append(chr(self.tagvalues["end-of-attributes-tag"])) |
| 599 | |
| 600 | |
| 601 | class CUPS : |
| 602 | """A class for a CUPS instance.""" |
| 603 | def __init__(self, url=None, username=None, password=None, charset="utf-8", language="en-us", debug=False) : |
| 604 | """Initializes the CUPS instance.""" |
| 605 | if url is not None : |
| 606 | self.url = url.replace("ipp://", "http://") |
| 607 | if self.url.endswith("/") : |
| 608 | self.url = self.url[:-1] |
| 609 | else : |
| 610 | self.url = self.getDefaultURL() |
| 611 | self.username = username |
| 612 | self.password = password |
| 613 | self.charset = charset |
| 614 | self.language = language |
| 615 | self.debug = debug |
| 616 | self.lastError = None |
| 617 | self.lastErrorMessage = None |
| 618 | self.requestId = None |
| 619 | |
| 620 | def getDefaultURL(self) : |
| 621 | """Builds a default URL.""" |
| 622 | # TODO : encryption methods. |
| 623 | server = os.environ.get("CUPS_SERVER") or "localhost" |
| 624 | port = os.environ.get("IPP_PORT") or 631 |
| 625 | if server.startswith("/") : |
| 626 | # it seems it's a unix domain socket. |
| 627 | # we can't handle this right now, so we use the default instead. |
| 628 | return "http://localhost:%s" % port |
| 629 | else : |
| 630 | return "http://%s:%s" % (server, port) |
| 631 | |
| 632 | def identifierToURI(self, service, ident) : |
| 633 | """Transforms an identifier into a particular URI depending on requested service.""" |
| 634 | return "%s/%s/%s" % (self.url.replace("http://", "ipp://"), |
| 635 | service, |
| 636 | ident) |
| 637 | |
| 638 | def nextRequestId(self) : |
| 639 | """Increments the current request id and returns the new value.""" |
| 640 | try : |
| 641 | self.requestId += 1 |
| 642 | except TypeError : |
| 643 | self.requestId = 1 |
| 644 | return self.requestId |
| 645 | |
| 646 | def newRequest(self, operationid=None) : |
| 647 | """Generates a new empty request.""" |
| 648 | if operationid is not None : |
| 649 | req = IPPRequest(operation_id=operationid, \ |
| 650 | request_id=self.nextRequestId(), \ |
| 651 | debug=self.debug) |
| 652 | req.operation["attributes-charset"] = ("charset", self.charset) |
| 653 | req.operation["attributes-natural-language"] = ("naturalLanguage", self.language) |
| 654 | return req |
| 655 | |
| 656 | def doRequest(self, req, url=None) : |
| 657 | """Sends a request to the CUPS server. |
| 658 | returns a new IPPRequest object, containing the parsed answer. |
| 659 | """ |
| 660 | connexion = urllib2.Request(url=url or self.url, \ |
| 661 | data=req.dump()) |
| 662 | connexion.add_header("Content-Type", "application/ipp") |
| 663 | if self.username : |
| 664 | pwmanager = urllib2.HTTPPasswordMgrWithDefaultRealm() |
| 665 | pwmanager.add_password(None, \ |
| 666 | "%s%s" % (connexion.get_host(), connexion.get_selector()), \ |
| 667 | self.username, \ |
| 668 | self.password or "") |
| 669 | authhandler = urllib2.HTTPBasicAuthHandler(pwmanager) |
| 670 | opener = urllib2.build_opener(authhandler) |
| 671 | urllib2.install_opener(opener) |
| 672 | self.lastError = None |
| 673 | self.lastErrorMessage = None |
| 674 | try : |
| 675 | response = urllib2.urlopen(connexion) |
| 676 | except (urllib2.URLError, urllib2.HTTPError, socket.error), error : |
| 677 | self.lastError = error |
| 678 | self.lastErrorMessage = str(error) |
| 679 | return None |
| 680 | else : |
| 681 | datas = response.read() |
| 682 | ippresponse = IPPRequest(datas) |
| 683 | ippresponse.parse() |
| 684 | return ippresponse |
| 685 | |
| 686 | def getPPD(self, queuename) : |
| 687 | """Retrieves the PPD for a particular queuename.""" |
| 688 | req = self.newRequest(IPP_GET_PRINTER_ATTRIBUTES) |
| 689 | req.operation["printer-uri"] = ("uri", self.identifierToURI("printers", queuename)) |
| 690 | for attrib in ("printer-uri-supported", "printer-type", "member-uris") : |
| 691 | req.operation["requested-attributes"] = ("nameWithoutLanguage", attrib) |
| 692 | return self.doRequest(req) # TODO : get the PPD from the actual print server |
| 693 | |
| 694 | def getDefault(self) : |
| 695 | """Retrieves CUPS' default printer.""" |
| 696 | return self.doRequest(self.newRequest(CUPS_GET_DEFAULT)) |
| 697 | |
| 698 | def getJobAttributes(self, jobid) : |
| 699 | """Retrieves a print job's attributes.""" |
| 700 | req = self.newRequest(IPP_GET_JOB_ATTRIBUTES) |
| 701 | req.operation["job-uri"] = ("uri", self.identifierToURI("jobs", jobid)) |
| 702 | return self.doRequest(req) |
| 703 | |
| 704 | def getPrinters(self) : |
| 705 | """Returns the list of print queues names.""" |
| 706 | req = self.newRequest(CUPS_GET_PRINTERS) |
| 707 | req.operation["requested-attributes"] = ("keyword", "printer-name") |
| 708 | req.operation["printer-type"] = ("enum", 0) |
| 709 | req.operation["printer-type-mask"] = ("enum", CUPS_PRINTER_CLASS) |
| 710 | return [printer[1] for printer in self.doRequest(req).printer["printer-name"]] |
| 711 | |
| 712 | def getDevices(self) : |
| 713 | """Returns a list of devices as (deviceclass, deviceinfo, devicemakeandmodel, deviceuri) tuples.""" |
| 714 | answer = self.doRequest(self.newRequest(CUPS_GET_DEVICES)) |
| 715 | return zip([d[1] for d in answer.printer["device-class"]], \ |
| 716 | [d[1] for d in answer.printer["device-info"]], \ |
| 717 | [d[1] for d in answer.printer["device-make-and-model"]], \ |
| 718 | [d[1] for d in answer.printer["device-uri"]]) |
| 719 | |
| 720 | def getPPDs(self) : |
| 721 | """Returns a list of PPDs as (ppdnaturallanguage, ppdmake, ppdmakeandmodel, ppdname) tuples.""" |
| 722 | answer = self.doRequest(self.newRequest(CUPS_GET_PPDS)) |
| 723 | return zip([d[1] for d in answer.printer["ppd-natural-language"]], \ |
| 724 | [d[1] for d in answer.printer["ppd-make"]], \ |
| 725 | [d[1] for d in answer.printer["ppd-make-and-model"]], \ |
| 726 | [d[1] for d in answer.printer["ppd-name"]]) |
| 727 | |
| 728 | def createSubscription(self, uri, events=["all"], |
| 729 | userdata=None, |
| 730 | recipient=None, |
| 731 | pullmethod=None, |
| 732 | charset=None, |
| 733 | naturallanguage=None, |
| 734 | leaseduration=None, |
| 735 | timeinterval=None, |
| 736 | jobid=None) : |
| 737 | """Creates a job, printer or server subscription. |
| 738 | |
| 739 | uri : the subscription's uri, e.g. ipp://server |
| 740 | events : a list of events to subscribe to, e.g. ["printer-added", "printer-deleted"] |
| 741 | recipient : the notifier's uri |
| 742 | pullmethod : the pull method to use |
| 743 | charset : the charset to use when sending notifications |
| 744 | naturallanguage : the language to use when sending notifications |
| 745 | leaseduration : the duration of the lease in seconds |
| 746 | timeinterval : the interval of time during notifications |
| 747 | jobid : the optional job id in case of a job subscription |
| 748 | """ |
| 749 | if jobid is not None : |
| 750 | opid = IPP_CREATE_JOB_SUBSCRIPTION |
| 751 | uritype = "job-uri" |
| 752 | else : |
| 753 | opid = IPP_CREATE_PRINTER_SUBSCRIPTION |
| 754 | uritype = "printer-uri" |
| 755 | req = self.newRequest(opid) |
| 756 | req.operation[uritype] = ("uri", uri) |
| 757 | for event in events : |
| 758 | req.subscription["notify-events"] = ("keyword", event) |
| 759 | if userdata is not None : |
| 760 | req.subscription["notify-user-data"] = ("octetString-with-an-unspecified-format", userdata) |
| 761 | if recipient is not None : |
| 762 | req.subscription["notify-recipient"] = ("uri", recipient) |
| 763 | if pullmethod is not None : |
| 764 | req.subscription["notify-pull-method"] = ("keyword", pullmethod) |
| 765 | if charset is not None : |
| 766 | req.subscription["notify-charset"] = ("charset", charset) |
| 767 | if naturallanguage is not None : |
| 768 | req.subscription["notify-natural-language"] = ("naturalLanguage", naturallanguage) |
| 769 | if leaseduration is not None : |
| 770 | req.subscription["notify-lease-duration"] = ("integer", leaseduration) |
| 771 | if timeinterval is not None : |
| 772 | req.subscription["notify-time-interval"] = ("integer", timeinterval) |
| 773 | if jobid is not None : |
| 774 | req.subscription["notify-job-id"] = ("integer", jobid) |
| 775 | return self.doRequest(req) |
| 776 | |
| 777 | def cancelSubscription(self, uri, subscriptionid, jobid=None) : |
| 778 | """Cancels a subscription. |
| 779 | |
| 780 | uri : the subscription's uri. |
| 781 | subscriptionid : the subscription's id. |
| 782 | jobid : the optional job's id. |
| 783 | """ |
| 784 | req = self.newRequest(IPP_CANCEL_SUBSCRIPTION) |
| 785 | if jobid is not None : |
| 786 | uritype = "job-uri" |
| 787 | else : |
| 788 | uritype = "printer-uri" |
| 789 | req.operation[uritype] = ("uri", uri) |
| 790 | req.event_notification["notify-subscription-id"] = ("integer", subscriptionid) |
| 791 | return self.doRequest(req) |
| 792 | |