Changes in / [30:20]

Show
Ignore:
Location:
/pkipplib/trunk
Files:
1 removed
4 modified

Legend:

Unmodified
Added
Removed
  • /pkipplib/trunk/tests/test.py

    r28 r13  
    2626import pkipplib         
    2727     
    28 cups = pkipplib.CUPS() 
    29 answer = cups.createSubscription("ipp://localhost/", ["printer-added", "printer-deleted"], 
    30                                                      userdata="samplenotifier:blah", 
    31                                                      recipient="samplenotifier", 
    32                                                      charset="utf-8") 
     28cups = pkipplib.CUPS()     
     29answer = cups.getPPD("HL6050DN") 
     30#answer = cups.getJobAttributes(566) 
    3331print answer 
    34  
    3532#print answer.operation["attributes-charset"] 
    3633 
  • /pkipplib/trunk/pkipplib/pkipplib.py

    r30 r18  
    2424 
    2525import sys 
    26 import os 
    2726import urllib2 
    28 import socket 
    2927from struct import pack, unpack 
    3028 
     
    238236IPP_PRINTER_IS_DEACTIVATED = 0x50a 
    239237   
    240 CUPS_PRINTER_LOCAL = 0x0000 
    241 CUPS_PRINTER_CLASS = 0x0001 
    242 CUPS_PRINTER_REMOTE = 0x0002 
    243 CUPS_PRINTER_BW = 0x0004 
    244 CUPS_PRINTER_COLOR = 0x0008 
    245 CUPS_PRINTER_DUPLEX = 0x0010 
    246 CUPS_PRINTER_STAPLE = 0x0020 
    247 CUPS_PRINTER_COPIES = 0x0040 
    248 CUPS_PRINTER_COLLATE = 0x0080 
    249 CUPS_PRINTER_PUNCH = 0x0100 
    250 CUPS_PRINTER_COVER = 0x0200 
    251 CUPS_PRINTER_BIND = 0x0400 
    252 CUPS_PRINTER_SORT = 0x0800 
    253 CUPS_PRINTER_SMALL = 0x1000 
    254 CUPS_PRINTER_MEDIUM = 0x2000 
    255 CUPS_PRINTER_LARGE = 0x4000 
    256 CUPS_PRINTER_VARIABLE = 0x8000 
    257 CUPS_PRINTER_IMPLICIT = 0x1000 
    258 CUPS_PRINTER_DEFAULT = 0x2000 
    259 CUPS_PRINTER_FAX = 0x4000 
    260 CUPS_PRINTER_REJECTING = 0x8000 
    261 CUPS_PRINTER_DELETE = 0x1000 
    262 CUPS_PRINTER_NOT_SHARED = 0x2000 
    263 CUPS_PRINTER_AUTHENTICATED = 0x4000 
    264 CUPS_PRINTER_COMMANDS = 0x8000 
    265 CUPS_PRINTER_OPTIONS = 0xe6ff 
    266    
    267    
    268238class IPPError(Exception) : 
    269239    """An exception for IPP related stuff.""" 
     
    296266    def __getitem__(self, key) : 
    297267        """Returns an attribute's value.""" 
    298         answer = [] 
    299268        attributeslist = getattr(self.request, "_%s_attributes" % self.name) 
    300269        for i in range(len(attributeslist)) : 
     
    303272                (attrname, attrvalue) = attribute[j] 
    304273                if attrname == key : 
    305                     answer.extend(attrvalue) 
    306         if answer : 
    307             return answer 
     274                    return attrvalue 
    308275        raise KeyError, key             
    309276     
     
    315282                                operation_id=None, \ 
    316283                                request_id=None, \ 
     284                                url = "http://localhost:631", \ 
     285                                username = None, \ 
     286                                password = None, \ 
    317287                                debug=False) : 
    318288        """Initializes an IPP Message object. 
     
    323293             debug : a boolean value to output debug info on stderr. 
    324294        """ 
     295        self.url = url 
     296        self.username = username 
     297        self.password = password 
    325298        self.debug = debug 
    326299        self._data = data 
     
    346319        self.tags[0x05] = "unsupported-attributes-tag" 
    347320        self.tags[0x06] = "subscription-attributes-tag" 
    348         self.tags[0x07] = "event_notification-attributes-tag" 
     321        self.tags[0x07] = "event-notification-attributes-tag" 
    349322         
    350323        # out of band values 
     
    445418        self.request_id = reqid 
    446419         
     420    def nextRequestId(self) :         
     421        """Increments the current request id and returns the new value.""" 
     422        try : 
     423            self.request_id += 1 
     424        except TypeError :     
     425            self.request_id = 1 
     426        return self.request_id 
     427             
    447428    def dump(self) :     
    448429        """Generates an IPP Message. 
     
    452433        mybuffer = [] 
    453434        if None not in (self.version, self.operation_id) : 
     435            if self.request_id is None : 
     436                self.nextRequestId() 
    454437            mybuffer.append(chr(self.version[0]) + chr(self.version[1])) 
    455438            mybuffer.append(pack(">H", self.operation_id)) 
    456             mybuffer.append(pack(">I", self.request_id or 1)) 
     439            mybuffer.append(pack(">I", self.request_id)) 
    457440            for attrtype in self.attributes_types : 
    458441                for attribute in getattr(self, "_%s_attributes" % attrtype) : 
     
    495478        self.position = 8 
    496479        endofattributes = self.tagvalues["end-of-attributes-tag"] 
    497         maxdelimiter = self.tagvalues["event_notification-attributes-tag"] 
     480        maxdelimiter = self.tagvalues["event-notification-attributes-tag"] 
    498481        nulloffset = lambda : 0 
    499482        try : 
     
    579562        return self.parseTag() 
    580563         
     564    def doRequest(self, url=None, username=None, password=None, samerequestid=False) : 
     565        """Sends the current request to the URL. 
     566           NB : only ipp:// URLs are currently unsupported so use 
     567           either http://host:631/ or https://host:443 instead... 
     568            
     569           returns a new IPPRequest object, containing the parsed answer. 
     570        """    
     571        if not samerequestid : 
     572            self.nextRequestId() 
     573        cx = urllib2.Request(url=url or self.url or "http://localhost:631/",  
     574                             data=self.dump()) 
     575        cx.add_header("Content-Type", "application/ipp") 
     576        response = urllib2.urlopen(cx) 
     577        datas = response.read() 
     578        ippresponse = IPPRequest(datas) 
     579        ippresponse.parse() 
     580        return ippresponse 
     581         
    581582             
    582583class CUPS : 
    583584    """A class for a CUPS instance.""" 
    584     def __init__(self, url=None, username=None, password=None, charset="utf-8", language="en-us", debug=False) : 
     585    def __init__(self, url="http://localhost:631", username=None, password=None, charset="utf-8", language="en-us") : 
    585586        """Initializes the CUPS instance.""" 
    586         if url is not None : 
    587             self.url = url.replace("ipp://", "http://") 
    588             if self.url.endswith("/") : 
    589                 self.url = self.url[:-1] 
    590         else :         
    591             self.url = self.getDefaultURL() 
     587        self.url = url 
    592588        self.username = username 
    593589        self.password = password 
    594590        self.charset = charset 
    595591        self.language = language 
    596         self.debug = debug 
    597         self.lastError = None 
    598         self.lastErrorMessage = None 
    599         self.requestId = None 
    600          
    601     def getDefaultURL(self) :     
    602         """Builds a default URL.""" 
    603         # TODO : encryption methods. 
    604         server = os.environ.get("CUPS_SERVER") or "localhost" 
    605         port = os.environ.get("IPP_PORT") or 631 
    606         if server.startswith("/") : 
    607             # it seems it's a unix domain socket. 
    608             # we can't handle this right now, so we use the default instead. 
    609             return "http://localhost:%s" % port 
    610         else :     
    611             return "http://%s:%s" % (server, port) 
    612              
     592         
    613593    def identifierToURI(self, service, ident) : 
    614594        """Transforms an identifier into a particular URI depending on requested service.""" 
     
    617597                             ident) 
    618598         
    619     def nextRequestId(self) :         
    620         """Increments the current request id and returns the new value.""" 
    621         try : 
    622             self.requestId += 1 
    623         except TypeError :     
    624             self.requestId = 1 
    625         return self.requestId 
    626              
    627599    def newRequest(self, operationid=None) : 
    628600        """Generates a new empty request.""" 
    629601        if operationid is not None : 
    630602            req = IPPRequest(operation_id=operationid, \ 
    631                              request_id=self.nextRequestId(), \ 
    632                              debug=self.debug) 
     603                             url=self.url, \ 
     604                             username=self.username, \ 
     605                             password=self.password) 
    633606            req.operation["attributes-charset"] = ("charset", self.charset) 
    634607            req.operation["attributes-natural-language"] = ("naturalLanguage", self.language) 
    635608            return req 
    636609     
    637     def doRequest(self, req, url=None) : 
    638         """Sends a request to the CUPS server. 
    639            returns a new IPPRequest object, containing the parsed answer. 
    640         """    
    641         connexion = urllib2.Request(url=url or self.url, \ 
    642                              data=req.dump()) 
    643         connexion.add_header("Content-Type", "application/ipp") 
    644         if self.username : 
    645             pwmanager = urllib2.HTTPPasswordMgrWithDefaultRealm() 
    646             pwmanager.add_password(None, \ 
    647                                    "%s%s" % (connexion.get_host(), connexion.get_selector()), \ 
    648                                    self.username, \ 
    649                                    self.password or "") 
    650             authhandler = urllib2.HTTPBasicAuthHandler(pwmanager)                        
    651             opener = urllib2.build_opener(authhandler) 
    652             urllib2.install_opener(opener) 
    653         self.lastError = None     
    654         self.lastErrorMessage = None 
    655         try :     
    656             response = urllib2.urlopen(connexion) 
    657         except (urllib2.URLError, urllib2.HTTPError, socket.error), error :     
    658             self.lastError = error 
    659             self.lastErrorMessage = str(error) 
    660             return None 
    661         else :     
    662             datas = response.read() 
    663             ippresponse = IPPRequest(datas) 
    664             ippresponse.parse() 
    665             return ippresponse 
     610    def getDefault(self) : 
     611        """Retrieves CUPS' default printer.""" 
     612        return self.newRequest(CUPS_GET_DEFAULT).doRequest() 
    666613     
     614    def getJobAttributes(self, jobid) :     
     615        """Retrieves a print job's attributes.""" 
     616        req = self.newRequest(IPP_GET_JOB_ATTRIBUTES) 
     617        req.operation["job-uri"] = ("uri", self.identifierToURI("jobs", jobid)) 
     618        return req.doRequest() 
     619         
    667620    def getPPD(self, queuename) :     
    668621        """Retrieves the PPD for a particular queuename.""" 
     
    671624        for attrib in ("printer-uri-supported", "printer-type", "member-uris") : 
    672625            req.operation["requested-attributes"] = ("nameWithoutLanguage", attrib) 
    673         return self.doRequest(req)  # TODO : get the PPD from the actual print server 
    674          
    675     def getDefault(self) : 
    676         """Retrieves CUPS' default printer.""" 
    677         return self.doRequest(self.newRequest(CUPS_GET_DEFAULT)) 
    678      
    679     def getJobAttributes(self, jobid) :     
    680         """Retrieves a print job's attributes.""" 
    681         req = self.newRequest(IPP_GET_JOB_ATTRIBUTES) 
    682         req.operation["job-uri"] = ("uri", self.identifierToURI("jobs", jobid)) 
    683         return self.doRequest(req) 
    684          
    685     def getPrinters(self) :     
    686         """Returns the list of print queues names.""" 
    687         req = self.newRequest(CUPS_GET_PRINTERS) 
    688         req.operation["requested-attributes"] = ("keyword", "printer-name") 
    689         req.operation["printer-type"] = ("enum", 0) 
    690         req.operation["printer-type-mask"] = ("enum", CUPS_PRINTER_CLASS) 
    691         return [printer[1] for printer in self.doRequest(req).printer["printer-name"]] 
    692          
    693     def getDevices(self) :     
    694         """Returns a list of devices as (deviceclass, deviceinfo, devicemakeandmodel, deviceuri) tuples.""" 
    695         answer = self.doRequest(self.newRequest(CUPS_GET_DEVICES)) 
    696         return zip([d[1] for d in answer.printer["device-class"]], \ 
    697                    [d[1] for d in answer.printer["device-info"]], \ 
    698                    [d[1] for d in answer.printer["device-make-and-model"]], \ 
    699                    [d[1] for d in answer.printer["device-uri"]]) 
    700                     
    701     def getPPDs(self) :     
    702         """Returns a list of PPDs as (ppdnaturallanguage, ppdmake, ppdmakeandmodel, ppdname) tuples.""" 
    703         answer = self.doRequest(self.newRequest(CUPS_GET_PPDS)) 
    704         return zip([d[1] for d in answer.printer["ppd-natural-language"]], \ 
    705                    [d[1] for d in answer.printer["ppd-make"]], \ 
    706                    [d[1] for d in answer.printer["ppd-make-and-model"]], \ 
    707                    [d[1] for d in answer.printer["ppd-name"]]) 
    708                     
    709     def createSubscription(self, uri, events=["all"], 
    710                                       userdata=None, 
    711                                       recipient=None, 
    712                                       pullmethod=None, 
    713                                       charset=None, 
    714                                       naturallanguage=None, 
    715                                       leaseduration=None, 
    716                                       timeinterval=None, 
    717                                       jobid=None) : 
    718         """Creates a job, printer or server subscription.""" 
    719         if jobid is not None : 
    720             opid = IPP_CREATE_JOB_SUBSCRIPTION 
    721             uritype = "job-uri" 
    722         else : 
    723             opid = IPP_CREATE_PRINTER_SUBSCRIPTION 
    724             uritype = "printer-uri" 
    725         req = self.newRequest(opid) 
    726         req.operation[uritype] = ("uri", uri) 
    727         for event in events : 
    728             req.subscription["notify-events"] = ("keyword", event) 
    729         if userdata is not None :     
    730             req.subscription["notify-user-data"] = ("octetString-with-an-unspecified-format", userdata) 
    731         if recipient is not None :     
    732             req.subscription["notify-recipient"] = ("uri", recipient) 
    733         if pullmethod is not None : 
    734             req.subscription["notify-pull-method"] = ("keyword", pullmethod) 
    735         if charset is not None : 
    736             req.subscription["notify-charset"] = ("charset", charset) 
    737         if naturallanguage is not None : 
    738             req.subscription["notify-natural-language"] = ("naturalLanguage", naturallanguage) 
    739         if leaseduration is not None : 
    740             req.subscription["notify-lease-duration"] = ("integer", leaseduration) 
    741         if timeinterval is not None : 
    742             req.subscription["notify-time-interval"] = ("integer", timeinterval) 
    743         if jobid is not None : 
    744             req.subscription["notify-job-id"] = ("integer", jobid) 
    745         return self.doRequest(req) 
    746              
    747     def cancelSubscription(self, uri, subscriptionid, jobid=None) :     
    748         """Cancels a subscription.""" 
    749         req = self.newRequest(IPP_CANCEL_SUBSCRIPTION) 
    750         if jobid is not None : 
    751             uritype = "job-uri" 
    752         else : 
    753             uritype = "printer-uri" 
    754         req.operation[uritype] = ("uri", uri) 
    755         req.event_notification["notify-subscription-id"] = ("integer", subscriptionid) 
    756         return self.doRequest(req) 
    757          
     626        return req.doRequest()  # TODO : get the PPD from the actual print server 
     627         
     628             
    758629if __name__ == "__main__" :             
    759630    if (len(sys.argv) < 2) or (sys.argv[1] == "--debug") : 
    760         print "usage : python pkipplib.py /var/spool/cups/c00005 [--debug] (for example)\n" 
     631        print "usage : python ipp.py /var/spool/cups/c00005 [--debug] (for example)\n" 
    761632    else :     
    762633        infile = open(sys.argv[1], "rb") 
    763         filedata = infile.read() 
     634        data = infile.read() 
    764635        infile.close() 
    765636         
    766         msg = IPPRequest(filedata, debug=(sys.argv[-1]=="--debug")) 
    767         msg.parse() 
    768         msg2 = IPPRequest(msg.dump()) 
    769         msg2.parse() 
    770         filedata2 = msg2.dump() 
    771          
    772         if filedata == filedata2 : 
     637        message = IPPRequest(data, debug=(sys.argv[-1]=="--debug")) 
     638        message.parse() 
     639        message2 = IPPRequest(message.dump()) 
     640        message2.parse() 
     641        data2 = message2.dump() 
     642         
     643        if data == data2 : 
    773644            print "Test OK : parsing original and parsing the output of the dump produce the same dump !" 
    774             print str(msg) 
     645            print str(message) 
    775646        else :     
    776647            print "Test Failed !" 
    777             print str(msg) 
     648            print str(message) 
    778649            print 
    779             print str(msg2) 
    780          
     650            print str(message2) 
     651         
  • /pkipplib/trunk/pkipplib/version.py

    r27 r14  
    2121# 
    2222 
    23 __version__ = "0.07" 
     23__version__ = "0.03" 
    2424 
    2525__doc__ = "pkipplib : IPP and CUPS support for Python." 
  • /pkipplib/trunk/README

    r25 r19  
    109109from pkipplib import pkipplib 
    110110 
    111 # Create a CUPS client instance 
    112 # cups = pkipplib.CUPS(url="http://server:631", username="john", password="blah!") 
     111# By default, connects to http://localhost:631 
    113112cups = pkipplib.CUPS() 
    114113 
     
    130129     
    131130# Sends this request to the CUPS server     
    132 answer = cups.doRequest(request) 
     131answer = request.doRequest()     
    133132 
    134133# Print the answer as a string of text