Changeset 3438 for tea4cups

Show
Ignore:
Timestamp:
10/06/08 00:26:54 (3 months ago)
Author:
jerome
Message:

Removed trailing spaces.

Location:
tea4cups/trunk
Files:
6 modified

Legend:

Unmodified
Added
Removed
  • tea4cups/trunk/CREDITS

    r691 r3438  
    3434  - Clive Bruton 
    3535  - Mark Wolf - ESCO Corporation 
    36    
     36 
    3737 
    3838Contributors : 
  • tea4cups/trunk/NEWS

    r691 r3438  
    2424 
    2525  * 3.13alpha (2006-11-07) : 
    26    
     26 
    2727    - Backported locking mechanism from PyKota. 
    28      
     28 
    2929  * 3.12 (2006-08-11) : 
    30    
    31     - Serializes accesses to the same device from different queues  
     30 
     31    - Serializes accesses to the same device from different queues 
    3232      or print servers through file locking facilities (works over 
    3333      NFS). 
    34      
     34 
    3535    - Improved support for CUPS 1.2.x and higher. 
    36      
     36 
    3737    - Allows the administrator to cleanly stop tea4cups with SIGINT. 
    38      
     38 
    3939    - Added a configurable retry directive to the configuration file. 
    40      
     40 
    4141    - Fixed several minor bugs. 
    42      
     42 
    4343    - Improved the installation instructions and the sample configuration 
    4444      file. 
    45      
    46   * 3.11 :  
    47    
     45 
     46  * 3.11 : 
     47 
    4848    - Fixed an incompatibility with Python 2.1, thanks to Frank 
    4949      Koormann. 
    50        
     50 
    5151  * 3.10 : 
    52    
     52 
    5353    - Added filters. 
    54      
     54 
    5555    - Added the "onfail" directive to tea4cups.conf 
    56      
     56 
    5757  * 3.02 : 
    58    
     58 
    5959    - Fixed some problems thanks to pychecker. 
    60      
     60 
    6161  * 3.01 : 
    62    
     62 
    6363    - Fixed an IPP parsing bug in some situations. 
    64      
     64 
    6565  * 3.00 : 
    66    
     66 
    6767    - Tees don't exist anymore. Only prehooks and posthooks remain. 
    68        
     68 
    6969    - Prehooks can now send datas to Posthooks through pipes. 
    70      
     70 
    7171    - Major rewrite of the subprocess management code, thanks to Peter Stuge. 
    72      
     72 
    7373  * 2.12alpha : 
    7474 
  • tea4cups/trunk/README

    r3382 r3438  
    2424 
    2525Tea4CUPS behaves just like any other CUPS backend, but allows you to 
    26 modify print jobs' datas as they pass through it and to transparently  
     26modify print jobs' datas as they pass through it and to transparently 
    2727send them to any number of outputs : other CUPS backends, files or pipes. 
    2828 
     
    5454                      print job has been sent to the real printer, 
    5555                      unless the job was previously cancelled by a 
    56                       prehook. Any number of posthooks can be  
     56                      prehook. Any number of posthooks can be 
    5757                      defined for a particular print queue. 
    5858 
     
    7979 
    8080        None of these environment variables is available to filters. 
    81    
     81 
    8282NB : Tea4CUPS requires a version of Python >= 2.3 
    8383 
     
    101101 
    102102        $ cp tea4cups /usr/lib/cups/backend 
    103          
     103 
    104104      If you use CUPS v1.2 or higher you must do this as well : 
    105        
     105 
    106106        $ chown root.root /usr/lib/cups/backend/tea4cups 
    107107        $ chmod 700 /usr/lib/cups/backend/tea4cups 
     
    117117      Or by directly modifying CUPS' printers.conf file, or with 
    118118      the lpadmin command line tool, just prepend each DeviceURI 
    119       value with 'tea4cups://'. If you modified printers.conf  
    120       directly instead of using lpadmin then don't forget to  
     119      value with 'tea4cups://'. If you modified printers.conf 
     120      directly instead of using lpadmin then don't forget to 
    121121      restart CUPS. 
    122122      (Use this last method if autodetection doesn't work because 
  • tea4cups/trunk/tea4cups

    r693 r3438  
    11#! /usr/bin/env python 
    2 # -*- coding: ISO-8859-15 -*- 
     2# -*- coding: utf-8 -*- 
    33 
    44# Tea4CUPS : Tee for CUPS 
     
    3535  the Free Software Foundation; either version 2 of the License, or 
    3636  (at your option) any later version. 
    37    
     37 
    3838  This program is distributed in the hope that it will be useful, 
    3939  but WITHOUT ANY WARRANTY; without even the implied warranty of 
    4040  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
    4141  GNU General Public License for more details. 
    42    
     42 
    4343  You should have received a copy of the GNU General Public License 
    4444  along with this program; if not, write to the Free Software 
     
    4949 
    5050  Copy the different files where they belong : 
    51    
     51 
    5252    $ cp tea4cups /usr/lib/cups/backend/ 
    5353    $ chown root.root /usr/lib/cups/backend/tea4cups 
    5454    $ chmod 700 /usr/lib/cups/backend/tea4cups 
    5555    $ cp tea4cups.conf /etc/cupsd/ 
    56    
     56 
    5757  Now edit the configuration file to suit your needs : 
    58    
     58 
    5959    $ vi /etc/cupsd/tea4cups.conf 
    60      
     60 
    6161    NB : you can use emacs as well :-) 
    62      
     62 
    6363  Finally restart CUPS : 
    64    
     64 
    6565    $ /etc/init.d/cupsys restart 
    66    
     66 
    6767  You can now create "Tea4CUPS Managed" print queues from 
    6868  CUPS' web interface, or using lpadmin. 
    69    
    70 Send bug reports to : alet@librelogiciel.com   
    71 """         
     69 
     70Send bug reports to : alet@librelogiciel.com 
     71""" 
    7272 
    7373import sys 
     
    105105    """IPP related exceptions.""" 
    106106    pass 
    107      
     107 
    108108IPP_VERSION = "1.1"     # default version number 
    109109 
     
    314314IPP_MULTIPLE_JOBS_NOT_SUPPORTED = 0x0509 
    315315IPP_PRINTER_IS_DEACTIVATED = 0x50a 
    316    
     316 
    317317CUPS_PRINTER_LOCAL = 0x0000 
    318318CUPS_PRINTER_CLASS = 0x0001 
     
    341341CUPS_PRINTER_COMMANDS = 0x8000 
    342342CUPS_PRINTER_OPTIONS = 0xe6ff 
    343    
     343 
    344344class FakeAttribute : 
    345345    """Fakes an IPPRequest attribute to simplify usage syntax.""" 
     
    348348        self.request = request 
    349349        self.name = name 
    350          
     350 
    351351    def __setitem__(self, key, value) : 
    352352        """Appends the value to the real attribute.""" 
     
    359359                    attribute[j][1].append(value) 
    360360                    return 
    361             attribute.append((key, [value]))         
    362              
     361            attribute.append((key, [value])) 
     362 
    363363    def __getitem__(self, key) : 
    364364        """Returns an attribute's value.""" 
     
    373373        if answer : 
    374374            return answer 
    375         raise KeyError, key             
    376      
     375        raise KeyError, key 
     376 
    377377class IPPRequest : 
    378378    """A class for IPP requests.""" 
    379379    attributes_types = ("operation", "job", "printer", "unsupported", \ 
    380380                                     "subscription", "event_notification") 
    381     def __init__(self, data="", version=IPP_VERSION,  
     381    def __init__(self, data="", version=IPP_VERSION, 
    382382                                operation_id=None, \ 
    383383                                request_id=None, \ 
    384384                                debug=False) : 
    385385        """Initializes an IPP Message object. 
    386          
     386 
    387387           Parameters : 
    388             
     388 
    389389             data : the complete IPP Message's content. 
    390390             debug : a boolean value to output debug info on stderr. 
     
    393393        self._data = data 
    394394        self.parsed = False 
    395          
     395 
    396396        # Initializes message 
    397         self.setVersion(version)                 
     397        self.setVersion(version) 
    398398        self.setOperationId(operation_id) 
    399399        self.setRequestId(request_id) 
    400400        self.data = "" 
    401          
     401 
    402402        for attrtype in self.attributes_types : 
    403403            setattr(self, "_%s_attributes" % attrtype, [[]]) 
    404          
    405         # Initialize tags     
     404 
     405        # Initialize tags 
    406406        self.tags = [ None ] * 256 # by default all tags reserved 
    407          
     407 
    408408        # Delimiter tags 
    409409        self.tags[0x01] = "operation-attributes-tag" 
     
    414414        self.tags[0x06] = "subscription-attributes-tag" 
    415415        self.tags[0x07] = "event_notification-attributes-tag" 
    416          
     416 
    417417        # out of band values 
    418418        self.tags[0x10] = "unsupported" 
     
    423423        self.tags[0x16] = "delete-attribute" 
    424424        self.tags[0x17] = "admin-define" 
    425    
     425 
    426426        # integer values 
    427427        self.tags[0x20] = "generic-integer" 
     
    429429        self.tags[0x22] = "boolean" 
    430430        self.tags[0x23] = "enum" 
    431          
     431 
    432432        # octetString 
    433433        self.tags[0x30] = "octetString-with-an-unspecified-format" 
     
    439439        self.tags[0x36] = "nameWithLanguage" 
    440440        self.tags[0x37] = "endCollection" 
    441          
     441 
    442442        # character strings 
    443443        self.tags[0x40] = "generic-character-string" 
     
    451451        self.tags[0x49] = "mimeMediaType" 
    452452        self.tags[0x4a] = "memberAttrName" 
    453          
     453 
    454454        # Reverse mapping to generate IPP messages 
    455455        self.tagvalues = {} 
     
    458458            if value is not None : 
    459459                self.tagvalues[value] = i 
    460                                       
    461     def __getattr__(self, name) :                                  
     460 
     461    def __getattr__(self, name) : 
    462462        """Fakes attribute access.""" 
    463463        if name in self.attributes_types : 
     
    465465        else : 
    466466            raise AttributeError, name 
    467              
    468     def __str__(self) :         
     467 
     468    def __str__(self) : 
    469469        """Returns the parsed IPP message in a readable form.""" 
    470470        if not self.parsed : 
     
    480480                for (name, value) in attribute : 
    481481                    mybuffer.append("  %s : %s" % (name, value)) 
    482         if self.data :             
     482        if self.data : 
    483483            mybuffer.append("IPP datas : %s" % repr(self.data)) 
    484484        return "\n".join(mybuffer) 
    485          
    486     def logDebug(self, msg) :     
     485 
     486    def logDebug(self, msg) : 
    487487        """Prints a debug message.""" 
    488488        if self.debug : 
    489489            sys.stderr.write("%s\n" % msg) 
    490490            sys.stderr.flush() 
    491              
     491 
    492492    def setVersion(self, version) : 
    493493        """Sets the request's operation id.""" 
     
    498498                if len(version) == 2 : # 2-tuple 
    499499                    self.version = version 
    500                 else :     
     500                else : 
    501501                    try : 
    502502                        self.version = [int(p) for p in str(float(version)).split(".")] 
    503503                    except : 
    504504                        self.version = [int(p) for p in IPP_VERSION.split(".")] 
    505          
    506     def setOperationId(self, opid) :         
     505 
     506    def setOperationId(self, opid) : 
    507507        """Sets the request's operation id.""" 
    508508        self.operation_id = opid 
    509          
    510     def setRequestId(self, reqid) :         
     509 
     510    def setRequestId(self, reqid) : 
    511511        """Sets the request's request id.""" 
    512512        self.request_id = reqid 
    513          
    514     def dump(self) :     
     513 
     514    def dump(self) : 
    515515        """Generates an IPP Message. 
    516          
     516 
    517517           Returns the message as a string of text. 
    518         """     
     518        """ 
    519519        mybuffer = [] 
    520520        if None not in (self.version, self.operation_id) : 
     
    534534                                mybuffer.append(attrname) 
    535535                                nameprinted = 1 
    536                             else :      
     536                            else : 
    537537                                mybuffer.append(pack(">H", 0)) 
    538538                            if vtype in ("integer", "enum") : 
     
    542542                                mybuffer.append(pack(">H", 1)) 
    543543                                mybuffer.append(chr(val)) 
    544                             else :     
     544                            else : 
    545545                                mybuffer.append(pack(">H", len(val))) 
    546546                                mybuffer.append(val) 
    547547            mybuffer.append(chr(self.tagvalues["end-of-attributes-tag"])) 
    548         mybuffer.append(self.data)     
     548        mybuffer.append(self.data) 
    549549        return "".join(mybuffer) 
    550              
     550 
    551551    def parse(self) : 
    552552        """Parses an IPP Request. 
    553          
     553 
    554554           NB : Only a subset of RFC2910 is implemented. 
    555555        """ 
    556556        self._curname = None 
    557557        self._curattributes = None 
    558          
     558 
    559559        self.setVersion((ord(self._data[0]), ord(self._data[1]))) 
    560560        self.setOperationId(unpack(">H", self._data[2:4])[0]) 
     
    575575                        self.position -= 1 
    576576                        continue 
    577                 oldtag = tag         
     577                oldtag = tag 
    578578                tag = ord(self._data[self.position]) 
    579579                if tag == oldtag : 
     
    581581        except IndexError : 
    582582            raise IPPError, "Unexpected end of IPP message." 
    583              
    584         self.data = self._data[self.position+1:]             
     583 
     584        self.data = self._data[self.position+1:] 
    585585        self.parsed = True 
    586          
    587     def parseTag(self) :     
     586 
     587    def parseTag(self) : 
    588588        """Extracts information from an IPP tag.""" 
    589589        pos = self.position 
     
    594594        if not namelength : 
    595595            name = self._curname 
    596         else :     
     596        else : 
    597597            posend += namelength 
    598598            self._curname = name = self._data[pos2:posend] 
     
    603603        if tagtype in ("integer", "enum") : 
    604604            value = unpack(">I", value)[0] 
    605         elif tagtype == "boolean" :     
     605        elif tagtype == "boolean" : 
    606606            value = ord(value) 
    607         try :     
     607        try : 
    608608            (oldname, oldval) = self._curattributes[-1][-1] 
    609609            if oldname == name : 
    610610                oldval.append((tagtype, value)) 
    611             else :     
     611            else : 
    612612                raise IndexError 
    613         except IndexError :     
     613        except IndexError : 
    614614            self._curattributes[-1].append((name, [(tagtype, value)])) 
    615615        self.logDebug("%s(%s) : %s" % (name, tagtype, value)) 
    616616        return posend - self.position 
    617          
    618     def operation_attributes_tag(self) :  
     617 
     618    def operation_attributes_tag(self) : 
    619619        """Indicates that the parser enters into an operation-attributes-tag group.""" 
    620620        self._curattributes = self._operation_attributes 
    621621        return self.parseTag() 
    622          
    623     def job_attributes_tag(self) :  
     622 
     623    def job_attributes_tag(self) : 
    624624        """Indicates that the parser enters into a job-attributes-tag group.""" 
    625625        self._curattributes = self._job_attributes 
    626626        return self.parseTag() 
    627          
    628     def printer_attributes_tag(self) :  
     627 
     628    def printer_attributes_tag(self) : 
    629629        """Indicates that the parser enters into a printer-attributes-tag group.""" 
    630630        self._curattributes = self._printer_attributes 
    631631        return self.parseTag() 
    632          
    633     def unsupported_attributes_tag(self) :  
     632 
     633    def unsupported_attributes_tag(self) : 
    634634        """Indicates that the parser enters into an unsupported-attributes-tag group.""" 
    635635        self._curattributes = self._unsupported_attributes 
    636636        return self.parseTag() 
    637          
    638     def subscription_attributes_tag(self) :  
     637 
     638    def subscription_attributes_tag(self) : 
    639639        """Indicates that the parser enters into a subscription-attributes-tag group.""" 
    640640        self._curattributes = self._subscription_attributes 
    641641        return self.parseTag() 
    642          
    643     def event_notification_attributes_tag(self) :  
     642 
     643    def event_notification_attributes_tag(self) : 
    644644        """Indicates that the parser enters into an event-notification-attributes-tag group.""" 
    645645        self._curattributes = self._event_notification_attributes 
    646646        return self.parseTag() 
    647          
    648              
     647 
     648 
    649649class CUPS : 
    650650    """A class for a CUPS instance.""" 
     
    655655            if self.url.endswith("/") : 
    656656                self.url = self.url[:-1] 
    657         else :         
     657        else : 
    658658            self.url = self.getDefaultURL() 
    659659        self.username = username 
     
    665665        self.lastErrorMessage = None 
    666666        self.requestId = None 
    667          
    668     def getDefaultURL(self) :     
     667 
     668    def getDefaultURL(self) : 
    669669        """Builds a default URL.""" 
    670670        # TODO : encryption methods. 
     
    675675            # we can't handle this right now, so we use the default instead. 
    676676            return "http://localhost:%s" % port 
    677         else :     
     677        else : 
    678678            return "http://%s:%s" % (server, port) 
    679              
     679 
    680680    def identifierToURI(self, service, ident) : 
    681681        """Transforms an identifier into a particular URI depending on requested service.""" 
     
    683683                             service, 
    684684                             ident) 
    685          
    686     def nextRequestId(self) :         
     685 
     686    def nextRequestId(self) : 
    687687        """Increments the current request id and returns the new value.""" 
    688688        try : 
    689689            self.requestId += 1 
    690         except TypeError :     
     690        except TypeError : 
    691691            self.requestId = 1 
    692692        return self.requestId 
    693              
     693 
    694694    def newRequest(self, operationid=None) : 
    695695        """Generates a new empty request.""" 
     
    701701            req.operation["attributes-natural-language"] = ("naturalLanguage", self.language) 
    702702            return req 
    703      
     703 
    704704    def doRequest(self, req, url=None) : 
    705705        """Sends a request to the CUPS server. 
    706706           returns a new IPPRequest object, containing the parsed answer. 
    707         """    
     707        """ 
    708708        connexion = urllib2.Request(url=url or self.url, \ 
    709709                             data=req.dump()) 
     
    715715                                   self.username, \ 
    716716                                   self.password or "") 
    717             authhandler = urllib2.HTTPBasicAuthHandler(pwmanager)                        
     717            authhandler = urllib2.HTTPBasicAuthHandler(pwmanager) 
    718718            opener = urllib2.build_opener(authhandler) 
    719719            urllib2.install_opener(opener) 
    720         self.lastError = None     
     720        self.lastError = None 
    721721        self.lastErrorMessage = None 
    722         try :     
     722        try : 
    723723            response = urllib2.urlopen(connexion) 
    724         except (urllib2.URLError, urllib2.HTTPError, socket.error), error :     
     724        except (urllib2.URLError, urllib2.HTTPError, socket.error), error : 
    725725            self.lastError = error 
    726726            self.lastErrorMessage = str(error) 
    727727            return None 
    728         else :     
     728        else : 
    729729            datas = response.read()