Changeset 3438

Show
Ignore:
Timestamp:
10/06/08 00:26:54 (15 years 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() 
    730730            ippresponse = IPPRequest(datas) 
    731731            ippresponse.parse() 
    732732            return ippresponse 
    733      
    734     def getPPD(self, queuename) :     
     733 
     734    def getPPD(self, queuename) : 
    735735        """Retrieves the PPD for a particular queuename.""" 
    736736        req = self.newRequest(IPP_GET_PRINTER_ATTRIBUTES) 
     
    739739            req.operation["requested-attributes"] = ("nameWithoutLanguage", attrib) 
    740740        return self.doRequest(req)  # TODO : get the PPD from the actual print server 
    741          
     741 
    742742    def getDefault(self) : 
    743743        """Retrieves CUPS' default printer.""" 
    744744        return self.doRequest(self.newRequest(CUPS_GET_DEFAULT)) 
    745      
    746     def getJobAttributes(self, jobid) :     
     745 
     746    def getJobAttributes(self, jobid) : 
    747747        """Retrieves a print job's attributes.""" 
    748748        req = self.newRequest(IPP_GET_JOB_ATTRIBUTES) 
    749749        req.operation["job-uri"] = ("uri", self.identifierToURI("jobs", jobid)) 
    750750        return self.doRequest(req) 
    751          
    752     def getPrinters(self) :     
     751 
     752    def getPrinters(self) : 
    753753        """Returns the list of print queues names.""" 
    754754        req = self.newRequest(CUPS_GET_PRINTERS) 
     
    757757        req.operation["printer-type-mask"] = ("enum", CUPS_PRINTER_CLASS) 
    758758        return [printer[1] for printer in self.doRequest(req).printer["printer-name"]] 
    759          
    760     def getDevices(self) :     
     759 
     760    def getDevices(self) : 
    761761        """Returns a list of devices as (deviceclass, deviceinfo, devicemakeandmodel, deviceuri) tuples.""" 
    762762        answer = self.doRequest(self.newRequest(CUPS_GET_DEVICES)) 
     
    765765                   [d[1] for d in answer.printer["device-make-and-model"]], \ 
    766766                   [d[1] for d in answer.printer["device-uri"]]) 
    767                     
    768     def getPPDs(self) :     
     767 
     768    def getPPDs(self) : 
    769769        """Returns a list of PPDs as (ppdnaturallanguage, ppdmake, ppdmakeandmodel, ppdname) tuples.""" 
    770770        answer = self.doRequest(self.newRequest(CUPS_GET_PPDS)) 
     
    773773                   [d[1] for d in answer.printer["ppd-make-and-model"]], \ 
    774774                   [d[1] for d in answer.printer["ppd-name"]]) 
    775                     
     775 
    776776    def createSubscription(self, uri, events=["all"], 
    777777                                      userdata=None, 
     
    784784                                      jobid=None) : 
    785785        """Creates a job, printer or server subscription. 
    786           
     786 
    787787           uri : the subscription's uri, e.g. ipp://server 
    788788           events : a list of events to subscribe to, e.g. ["printer-added", "printer-deleted"] 
     
    794794           timeinterval : the interval of time during notifications 
    795795           jobid : the optional job id in case of a job subscription 
    796         """    
     796        """ 
    797797        if jobid is not None : 
    798798            opid = IPP_CREATE_JOB_SUBSCRIPTION 
     
    805805        for event in events : 
    806806            req.subscription["notify-events"] = ("keyword", event) 
    807         if userdata is not None :     
     807        if userdata is not None : 
    808808            req.subscription["notify-user-data"] = ("octetString-with-an-unspecified-format", userdata) 
    809         if recipient is not None :     
     809        if recipient is not None : 
    810810            req.subscription["notify-recipient"] = ("uri", recipient) 
    811811        if pullmethod is not None : 
     
    822822            req.subscription["notify-job-id"] = ("integer", jobid) 
    823823        return self.doRequest(req) 
    824              
    825     def cancelSubscription(self, uri, subscriptionid, jobid=None) :     
     824 
     825    def cancelSubscription(self, uri, subscriptionid, jobid=None) : 
    826826        """Cancels a subscription. 
    827          
     827 
    828828           uri : the subscription's uri. 
    829829           subscriptionid : the subscription's id. 
     
    838838        req.event_notification["notify-subscription-id"] = ("integer", subscriptionid) 
    839839        return self.doRequest(req) 
    840          
     840 
    841841 
    842842class FakeConfig : 
     
    879879        conffile.close() 
    880880    return dirvalues 
    881      
     881 
    882882class CupsBackend : 
    883883    """Base class for tools with no database access.""" 
     
    912912        self.LockFile = None 
    913913 
    914     def waitForLock(self) :     
     914    def waitForLock(self) : 
    915915        """Waits until we can acquire the lock file.""" 
    916916        lockfilename = self.DeviceURI.replace("/", ".") 
     
    926926                # open the lock file, optionally creating it if needed. 
    927927                self.LockFile = open(lockfilename, "a+") 
    928                  
     928 
    929929                # we wait indefinitely for the lock to become available. 
    930930                # works over NFS too. 
    931931                fcntl.lockf(self.LockFile, fcntl.LOCK_EX) 
    932932                haslock = True 
    933                  
     933 
    934934                self.logDebug("Lock %s acquired." % lockfilename) 
    935                  
     935 
    936936                # Here we save the PID in the lock file, but we don't use 
    937937                # it, because the lock file may be in a directory shared 
     
    942942                self.LockFile.write(str(self.pid)) 
    943943                self.LockFile.flush() 
    944             except IOError :             
     944            except IOError : 
    945945                self.logDebug("I/O Error while waiting for lock %s" % lockfilename) 
    946946                time.sleep(0.25) 
    947          
     947 
    948948    def readConfig(self) : 
    949949        """Reads the configuration file.""" 
     
    11041104        self.Directory = self.getPrintQueueOption(self.PrinterName, "directory", ignore=1) or tempfile.gettempdir() 
    11051105        self.DataFile = os.path.join(self.Directory, "%s-%s-%s-%s" % (self.myname, self.PrinterName, self.UserName, self.JobId)) 
    1106          
     1106 
    11071107        # check that the DEVICE_URI environment variable's value is 
    11081108        # prefixed with self.myname otherwise don't touch it. 
     
    11281128        self.RealBackend = backend 
    11291129        self.DeviceURI = device_uri 
    1130          
     1130 
    11311131        try : 
    11321132            cupsserver = CUPS() # TODO : username and password and/or encryption 
     
    11351135                raise ValueError # don't hande unix domain sockets yet. 
    11361136            self.ControlFile = "NotUsedAnymore" 
    1137         except :     
     1137        except : 
    11381138            (ippfilename, answer) = self.parseIPPRequestFile() 
    11391139            self.ControlFile = ippfilename 
    1140          
     1140 
    11411141        try : 
    11421142            john = answer.job["job-originating-host-name"] 
    1143         except (KeyError, AttributeError) :     
     1143        except (KeyError, AttributeError) : 
    11441144            try : 
    11451145                john = answer.operation["job-originating-host-name"] 
    1146             except (KeyError, AttributeError) :     
     1146            except (KeyError, AttributeError) : 
    11471147                john = (None, None) 
    1148         if type(john) == type([]) :                           
     1148        if type(john) == type([]) : 
    11491149            john = john[-1] 
    1150         (dummy, self.ClientHost) = john                           
    1151         try :         
     1150        (dummy, self.ClientHost) = john 
     1151        try : 
    11521152            jbing = answer.job["job-billing"] 
    1153         except (KeyError, AttributeError) :     
     1153        except (KeyError, AttributeError) : 
    11541154            jbing = (None, None) 
    1155         if type(jbing) == type([]) :  
     1155        if type(jbing) == type([]) : 
    11561156            jbing = jbing[-1] 
    11571157        (dummy, self.JobBilling) = jbing 
    1158          
     1158 
    11591159    def parseIPPRequestFile(self) : 
    11601160        """Parses the IPP message file and returns a tuple (filename, parsedvalue).""" 
     
    12121212        else : 
    12131213            infile = sys.stdin 
    1214              
     1214 
    12151215        filtercommand = self.getPrintQueueOption(self.PrinterName, "filter", \ 
    12161216                                                 ignore=1) 
    1217         if filtercommand :                                                  
     1217        if filtercommand : 
    12181218            self.logDebug("Data stream will be filtered through [%s]" % filtercommand) 
    12191219            filteroutput = "%s.filteroutput" % self.DataFile 
     
    12261226            infile = open(filteroutput, "rb") 
    12271227            mustclose = 1 
    1228         else :     
     1228        else : 
    12291229            self.logDebug("Data stream will be used as-is (no filter defined)") 
    1230              
     1230 
    12311231        CHUNK = 64*1024         # read 64 Kb at a time 
    12321232        dummy = 0 
     
    12451245            dummy += 1 
    12461246        outfile.close() 
    1247          
     1247 
    12481248        if filtercommand : 
    12491249            self.logDebug("Removing filter's output file %s" % filteroutput) 
    12501250            try : 
    12511251                os.remove(filteroutput) 
    1252             except :     
     1252            except : 
    12531253                pass 
    1254                  
     1254 
    12551255        if mustclose : 
    12561256            infile.close() 
    1257              
     1257 
    12581258        self.logDebug("%s bytes saved..." % sizeread) 
    12591259        self.JobSize = sizeread 
     
    12691269            try : 
    12701270                os.remove(self.DataFile) 
    1271             except OSError, msg :     
     1271            except OSError, msg : 
    12721272                self.logInfo("Problem when removing %s : %s" % (self.DataFile, msg), "error") 
    1273                  
     1273 
    12741274        if self.LockFile is not None : 
    12751275            self.logDebug("Removing lock...") 
     
    12771277                fcntl.lockf(self.LockFile, fcntl.LOCK_UN) 
    12781278                self.LockFile.close() 
    1279             except :     
     1279            except : 
    12801280                self.logInfo("Problem while unlocking.", "error") 
    1281             else :     
     1281            else : 
    12821282                self.logDebug("Lock removed.") 
    12831283        self.logDebug("Clean.") 
     
    13031303                        self.logDebug("Launching onfail script %s" % onfail) 
    13041304                        os.system(onfail) 
    1305                          
     1305 
    13061306            os.environ["TEASTATUS"] = str(retcode) 
    13071307            branches = self.enumBranches(self.PrinterName, "posthook") 
    13081308            if self.runCommands("posthook", branches, serialize) : 
    13091309                self.logInfo("An error occured during the execution of posthooks.", "warn") 
    1310                  
     1310 
    13111311        for p in [ (k, v) for (k, v) in self.pipes.items() if k != 0 ] : 
    13121312            os.close(p[1][0]) 
     
    14041404            try : 
    14051405                (number, delay) = [int(p) for p in retry.strip().split(",")] 
    1406             except (ValueError, AttributeError, TypeError) :     
     1406            except (ValueError, AttributeError, TypeError) : 
    14071407                self.logInfo("Invalid value '%s' for the 'retry' directive for printer %s in %s." % (retry, self.PrinterName, self.conffile), "error") 
    14081408                number = 1 
    14091409                delay = 0 
    1410                  
    1411         loopcount = 1  
    1412         while 1 :             
     1410 
     1411        loopcount = 1 
     1412        while 1 : 
    14131413            retcode = self.runOriginalBackend() 
    14141414            if not retcode : 
     
    14191419                    time.sleep(delay) 
    14201420                    loopcount += 1 
    1421                 else :     
     1421                else : 
    14221422                    break 
    1423         return retcode             
    1424          
     1423        return retcode 
     1424 
    14251425    def runOriginalBackend(self) : 
    14261426        """Launches the original backend.""" 
     
    14351435                os.dup2(f.fileno(), 0) 
    14361436                f.close() 
    1437             else :     
     1437            else : 
    14381438                arguments[6] = self.DataFile # in case a tea4cups filter was applied 
    14391439            try : 
     
    14851485            except SystemExit, e : 
    14861486                returncode = e.code 
    1487             except KeyboardInterrupt :     
     1487            except KeyboardInterrupt : 
    14881488                wrapper.logInfo("Job %s interrupted by the administrator !" % wrapper.JobId, "warn") 
    14891489            except : 
     
    14981498                sys.stderr.flush() 
    14991499                returncode = 1 
    1500         finally :         
     1500        finally : 
    15011501            wrapper.cleanUp() 
    15021502        sys.exit(returncode) 
  • tea4cups/trunk/tea4cups.conf

    r691 r3438  
    6767# 
    6868#           N : number of times to try. If 0, will retry indefinitely, until 
    69 #               the backend accepts all the datas without error.               
     69#               the backend accepts all the datas without error. 
    7070# 
    7171#           S : delay in Seconds between two attempts. 
    7272# 
    7373# The example below would retry up to three times, at 60 seconds interval. 
    74 #  
     74# 
    7575# retry : 3,60 
    7676 
     
    8989 
    9090 
    91 # Should we pass incoming datas through a filter command  
     91# Should we pass incoming datas through a filter command 
    9292# BEFORE doing anything else ? 
    9393# NB : obvisouly the filter command doesn't have any access to 
     
    9696# The value defined in a print queue section takes precedence over the 
    9797# value defined in the [global] section. 
    98 #  
     98# 
    9999# The sample filter below can remove the print job creation date 
    100100# from PostScript jobs, in order to more accurately detect duplicate 
     
    123123 
    124124# When executing the contents of a prehook or posthook directive, as 
    125 # defined below, tea4cups makes the following environment variables  
     125# defined below, tea4cups makes the following environment variables 
    126126# available to your own commands : 
    127127# 
     
    178178 
    179179# Another example : a PDF generator which creates PDF documents 
    180 # in the user's home directory under the names JOB-iiii.pdf  
     180# in the user's home directory under the names JOB-iiii.pdf 
    181181# where iiii is the job id : 
    182182# 
     
    231231# NB : Beware of some software which embed the job printing time into the 
    232232# PostScript job : two identical jobs may have different MD5 checksums 
    233 # if they differ only by the value of the '%%CreationDate:' PostScript  
     233# if they differ only by the value of the '%%CreationDate:' PostScript 
    234234# comment ! 
    235235# 
  • tea4cups/trunk/TODO

    r691 r3438  
    2222 
    2323TODO, in no particular order : 
    24          
     24 
    2525        - Give some complex examples. 
    26          
     26 
    2727============================================================ 
    2828