Index: tea4cups/trunk/TODO
===================================================================
--- tea4cups/trunk/TODO (revision 691)
+++ tea4cups/trunk/TODO (revision 3438)
@@ -22,7 +22,7 @@
 
 TODO, in no particular order :
-        
+
         - Give some complex examples.
-        
+
 ============================================================
 
Index: tea4cups/trunk/tea4cups
===================================================================
--- tea4cups/trunk/tea4cups (revision 693)
+++ tea4cups/trunk/tea4cups (revision 3438)
@@ -1,4 +1,4 @@
 #! /usr/bin/env python
-# -*- coding: ISO-8859-15 -*-
+# -*- coding: utf-8 -*-
 
 # Tea4CUPS : Tee for CUPS
@@ -35,10 +35,10 @@
   the Free Software Foundation; either version 2 of the License, or
   (at your option) any later version.
-  
+
   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.
-  
+
   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
@@ -49,25 +49,25 @@
 
   Copy the different files where they belong :
-  
+
     $ cp tea4cups /usr/lib/cups/backend/
     $ chown root.root /usr/lib/cups/backend/tea4cups
     $ chmod 700 /usr/lib/cups/backend/tea4cups
     $ cp tea4cups.conf /etc/cupsd/
-  
+
   Now edit the configuration file to suit your needs :
-  
+
     $ vi /etc/cupsd/tea4cups.conf
-    
+
     NB : you can use emacs as well :-)
-    
+
   Finally restart CUPS :
-  
+
     $ /etc/init.d/cupsys restart
-  
+
   You can now create "Tea4CUPS Managed" print queues from
   CUPS' web interface, or using lpadmin.
-  
-Send bug reports to : alet@librelogiciel.com  
-"""        
+
+Send bug reports to : alet@librelogiciel.com
+"""
 
 import sys
@@ -105,5 +105,5 @@
     """IPP related exceptions."""
     pass
-    
+
 IPP_VERSION = "1.1"     # default version number
 
@@ -314,5 +314,5 @@
 IPP_MULTIPLE_JOBS_NOT_SUPPORTED = 0x0509
 IPP_PRINTER_IS_DEACTIVATED = 0x50a
-  
+
 CUPS_PRINTER_LOCAL = 0x0000
 CUPS_PRINTER_CLASS = 0x0001
@@ -341,5 +341,5 @@
 CUPS_PRINTER_COMMANDS = 0x8000
 CUPS_PRINTER_OPTIONS = 0xe6ff
-  
+
 class FakeAttribute :
     """Fakes an IPPRequest attribute to simplify usage syntax."""
@@ -348,5 +348,5 @@
         self.request = request
         self.name = name
-        
+
     def __setitem__(self, key, value) :
         """Appends the value to the real attribute."""
@@ -359,6 +359,6 @@
                     attribute[j][1].append(value)
                     return
-            attribute.append((key, [value]))        
-            
+            attribute.append((key, [value]))
+
     def __getitem__(self, key) :
         """Returns an attribute's value."""
@@ -373,18 +373,18 @@
         if answer :
             return answer
-        raise KeyError, key            
-    
+        raise KeyError, key
+
 class IPPRequest :
     """A class for IPP requests."""
     attributes_types = ("operation", "job", "printer", "unsupported", \
                                      "subscription", "event_notification")
-    def __init__(self, data="", version=IPP_VERSION, 
+    def __init__(self, data="", version=IPP_VERSION,
                                 operation_id=None, \
                                 request_id=None, \
                                 debug=False) :
         """Initializes an IPP Message object.
-        
+
            Parameters :
-           
+
              data : the complete IPP Message's content.
              debug : a boolean value to output debug info on stderr.
@@ -393,17 +393,17 @@
         self._data = data
         self.parsed = False
-        
+
         # Initializes message
-        self.setVersion(version)                
+        self.setVersion(version)
         self.setOperationId(operation_id)
         self.setRequestId(request_id)
         self.data = ""
-        
+
         for attrtype in self.attributes_types :
             setattr(self, "_%s_attributes" % attrtype, [[]])
-        
-        # Initialize tags    
+
+        # Initialize tags
         self.tags = [ None ] * 256 # by default all tags reserved
-        
+
         # Delimiter tags
         self.tags[0x01] = "operation-attributes-tag"
@@ -414,5 +414,5 @@
         self.tags[0x06] = "subscription-attributes-tag"
         self.tags[0x07] = "event_notification-attributes-tag"
-        
+
         # out of band values
         self.tags[0x10] = "unsupported"
@@ -423,5 +423,5 @@
         self.tags[0x16] = "delete-attribute"
         self.tags[0x17] = "admin-define"
-  
+
         # integer values
         self.tags[0x20] = "generic-integer"
@@ -429,5 +429,5 @@
         self.tags[0x22] = "boolean"
         self.tags[0x23] = "enum"
-        
+
         # octetString
         self.tags[0x30] = "octetString-with-an-unspecified-format"
@@ -439,5 +439,5 @@
         self.tags[0x36] = "nameWithLanguage"
         self.tags[0x37] = "endCollection"
-        
+
         # character strings
         self.tags[0x40] = "generic-character-string"
@@ -451,5 +451,5 @@
         self.tags[0x49] = "mimeMediaType"
         self.tags[0x4a] = "memberAttrName"
-        
+
         # Reverse mapping to generate IPP messages
         self.tagvalues = {}
@@ -458,6 +458,6 @@
             if value is not None :
                 self.tagvalues[value] = i
-                                     
-    def __getattr__(self, name) :                                 
+
+    def __getattr__(self, name) :
         """Fakes attribute access."""
         if name in self.attributes_types :
@@ -465,6 +465,6 @@
         else :
             raise AttributeError, name
-            
-    def __str__(self) :        
+
+    def __str__(self) :
         """Returns the parsed IPP message in a readable form."""
         if not self.parsed :
@@ -480,14 +480,14 @@
                 for (name, value) in attribute :
                     mybuffer.append("  %s : %s" % (name, value))
-        if self.data :            
+        if self.data :
             mybuffer.append("IPP datas : %s" % repr(self.data))
         return "\n".join(mybuffer)
-        
-    def logDebug(self, msg) :    
+
+    def logDebug(self, msg) :
         """Prints a debug message."""
         if self.debug :
             sys.stderr.write("%s\n" % msg)
             sys.stderr.flush()
-            
+
     def setVersion(self, version) :
         """Sets the request's operation id."""
@@ -498,23 +498,23 @@
                 if len(version) == 2 : # 2-tuple
                     self.version = version
-                else :    
+                else :
                     try :
                         self.version = [int(p) for p in str(float(version)).split(".")]
                     except :
                         self.version = [int(p) for p in IPP_VERSION.split(".")]
-        
-    def setOperationId(self, opid) :        
+
+    def setOperationId(self, opid) :
         """Sets the request's operation id."""
         self.operation_id = opid
-        
-    def setRequestId(self, reqid) :        
+
+    def setRequestId(self, reqid) :
         """Sets the request's request id."""
         self.request_id = reqid
-        
-    def dump(self) :    
+
+    def dump(self) :
         """Generates an IPP Message.
-        
+
            Returns the message as a string of text.
-        """    
+        """
         mybuffer = []
         if None not in (self.version, self.operation_id) :
@@ -534,5 +534,5 @@
                                 mybuffer.append(attrname)
                                 nameprinted = 1
-                            else :     
+                            else :
                                 mybuffer.append(pack(">H", 0))
                             if vtype in ("integer", "enum") :
@@ -542,19 +542,19 @@
                                 mybuffer.append(pack(">H", 1))
                                 mybuffer.append(chr(val))
-                            else :    
+                            else :
                                 mybuffer.append(pack(">H", len(val)))
                                 mybuffer.append(val)
             mybuffer.append(chr(self.tagvalues["end-of-attributes-tag"]))
-        mybuffer.append(self.data)    
+        mybuffer.append(self.data)
         return "".join(mybuffer)
-            
+
     def parse(self) :
         """Parses an IPP Request.
-        
+
            NB : Only a subset of RFC2910 is implemented.
         """
         self._curname = None
         self._curattributes = None
-        
+
         self.setVersion((ord(self._data[0]), ord(self._data[1])))
         self.setOperationId(unpack(">H", self._data[2:4])[0])
@@ -575,5 +575,5 @@
                         self.position -= 1
                         continue
-                oldtag = tag        
+                oldtag = tag
                 tag = ord(self._data[self.position])
                 if tag == oldtag :
@@ -581,9 +581,9 @@
         except IndexError :
             raise IPPError, "Unexpected end of IPP message."
-            
-        self.data = self._data[self.position+1:]            
+
+        self.data = self._data[self.position+1:]
         self.parsed = True
-        
-    def parseTag(self) :    
+
+    def parseTag(self) :
         """Extracts information from an IPP tag."""
         pos = self.position
@@ -594,5 +594,5 @@
         if not namelength :
             name = self._curname
-        else :    
+        else :
             posend += namelength
             self._curname = name = self._data[pos2:posend]
@@ -603,48 +603,48 @@
         if tagtype in ("integer", "enum") :
             value = unpack(">I", value)[0]
-        elif tagtype == "boolean" :    
+        elif tagtype == "boolean" :
             value = ord(value)
-        try :    
+        try :
             (oldname, oldval) = self._curattributes[-1][-1]
             if oldname == name :
                 oldval.append((tagtype, value))
-            else :    
+            else :
                 raise IndexError
-        except IndexError :    
+        except IndexError :
             self._curattributes[-1].append((name, [(tagtype, value)]))
         self.logDebug("%s(%s) : %s" % (name, tagtype, value))
         return posend - self.position
-        
-    def operation_attributes_tag(self) : 
+
+    def operation_attributes_tag(self) :
         """Indicates that the parser enters into an operation-attributes-tag group."""
         self._curattributes = self._operation_attributes
         return self.parseTag()
-        
-    def job_attributes_tag(self) : 
+
+    def job_attributes_tag(self) :
         """Indicates that the parser enters into a job-attributes-tag group."""
         self._curattributes = self._job_attributes
         return self.parseTag()
-        
-    def printer_attributes_tag(self) : 
+
+    def printer_attributes_tag(self) :
         """Indicates that the parser enters into a printer-attributes-tag group."""
         self._curattributes = self._printer_attributes
         return self.parseTag()
-        
-    def unsupported_attributes_tag(self) : 
+
+    def unsupported_attributes_tag(self) :
         """Indicates that the parser enters into an unsupported-attributes-tag group."""
         self._curattributes = self._unsupported_attributes
         return self.parseTag()
-        
-    def subscription_attributes_tag(self) : 
+
+    def subscription_attributes_tag(self) :
         """Indicates that the parser enters into a subscription-attributes-tag group."""
         self._curattributes = self._subscription_attributes
         return self.parseTag()
-        
-    def event_notification_attributes_tag(self) : 
+
+    def event_notification_attributes_tag(self) :
         """Indicates that the parser enters into an event-notification-attributes-tag group."""
         self._curattributes = self._event_notification_attributes
         return self.parseTag()
-        
-            
+
+
 class CUPS :
     """A class for a CUPS instance."""
@@ -655,5 +655,5 @@
             if self.url.endswith("/") :
                 self.url = self.url[:-1]
-        else :        
+        else :
             self.url = self.getDefaultURL()
         self.username = username
@@ -665,6 +665,6 @@
         self.lastErrorMessage = None
         self.requestId = None
-        
-    def getDefaultURL(self) :    
+
+    def getDefaultURL(self) :
         """Builds a default URL."""
         # TODO : encryption methods.
@@ -675,7 +675,7 @@
             # we can't handle this right now, so we use the default instead.
             return "http://localhost:%s" % port
-        else :    
+        else :
             return "http://%s:%s" % (server, port)
-            
+
     def identifierToURI(self, service, ident) :
         """Transforms an identifier into a particular URI depending on requested service."""
@@ -683,13 +683,13 @@
                              service,
                              ident)
-        
-    def nextRequestId(self) :        
+
+    def nextRequestId(self) :
         """Increments the current request id and returns the new value."""
         try :
             self.requestId += 1
-        except TypeError :    
+        except TypeError :
             self.requestId = 1
         return self.requestId
-            
+
     def newRequest(self, operationid=None) :
         """Generates a new empty request."""
@@ -701,9 +701,9 @@
             req.operation["attributes-natural-language"] = ("naturalLanguage", self.language)
             return req
-    
+
     def doRequest(self, req, url=None) :
         """Sends a request to the CUPS server.
            returns a new IPPRequest object, containing the parsed answer.
-        """   
+        """
         connexion = urllib2.Request(url=url or self.url, \
                              data=req.dump())
@@ -715,22 +715,22 @@
                                    self.username, \
                                    self.password or "")
-            authhandler = urllib2.HTTPBasicAuthHandler(pwmanager)                       
+            authhandler = urllib2.HTTPBasicAuthHandler(pwmanager)
             opener = urllib2.build_opener(authhandler)
             urllib2.install_opener(opener)
-        self.lastError = None    
+        self.lastError = None
         self.lastErrorMessage = None
-        try :    
+        try :
             response = urllib2.urlopen(connexion)
-        except (urllib2.URLError, urllib2.HTTPError, socket.error), error :    
+        except (urllib2.URLError, urllib2.HTTPError, socket.error), error :
             self.lastError = error
             self.lastErrorMessage = str(error)
             return None
-        else :    
+        else :
             datas = response.read()
             ippresponse = IPPRequest(datas)
             ippresponse.parse()
             return ippresponse
-    
-    def getPPD(self, queuename) :    
+
+    def getPPD(self, queuename) :
         """Retrieves the PPD for a particular queuename."""
         req = self.newRequest(IPP_GET_PRINTER_ATTRIBUTES)
@@ -739,16 +739,16 @@
             req.operation["requested-attributes"] = ("nameWithoutLanguage", attrib)
         return self.doRequest(req)  # TODO : get the PPD from the actual print server
-        
+
     def getDefault(self) :
         """Retrieves CUPS' default printer."""
         return self.doRequest(self.newRequest(CUPS_GET_DEFAULT))
-    
-    def getJobAttributes(self, jobid) :    
+
+    def getJobAttributes(self, jobid) :
         """Retrieves a print job's attributes."""
         req = self.newRequest(IPP_GET_JOB_ATTRIBUTES)
         req.operation["job-uri"] = ("uri", self.identifierToURI("jobs", jobid))
         return self.doRequest(req)
-        
-    def getPrinters(self) :    
+
+    def getPrinters(self) :
         """Returns the list of print queues names."""
         req = self.newRequest(CUPS_GET_PRINTERS)
@@ -757,6 +757,6 @@
         req.operation["printer-type-mask"] = ("enum", CUPS_PRINTER_CLASS)
         return [printer[1] for printer in self.doRequest(req).printer["printer-name"]]
-        
-    def getDevices(self) :    
+
+    def getDevices(self) :
         """Returns a list of devices as (deviceclass, deviceinfo, devicemakeandmodel, deviceuri) tuples."""
         answer = self.doRequest(self.newRequest(CUPS_GET_DEVICES))
@@ -765,6 +765,6 @@
                    [d[1] for d in answer.printer["device-make-and-model"]], \
                    [d[1] for d in answer.printer["device-uri"]])
-                   
-    def getPPDs(self) :    
+
+    def getPPDs(self) :
         """Returns a list of PPDs as (ppdnaturallanguage, ppdmake, ppdmakeandmodel, ppdname) tuples."""
         answer = self.doRequest(self.newRequest(CUPS_GET_PPDS))
@@ -773,5 +773,5 @@
                    [d[1] for d in answer.printer["ppd-make-and-model"]], \
                    [d[1] for d in answer.printer["ppd-name"]])
-                   
+
     def createSubscription(self, uri, events=["all"],
                                       userdata=None,
@@ -784,5 +784,5 @@
                                       jobid=None) :
         """Creates a job, printer or server subscription.
-         
+
            uri : the subscription's uri, e.g. ipp://server
            events : a list of events to subscribe to, e.g. ["printer-added", "printer-deleted"]
@@ -794,5 +794,5 @@
            timeinterval : the interval of time during notifications
            jobid : the optional job id in case of a job subscription
-        """   
+        """
         if jobid is not None :
             opid = IPP_CREATE_JOB_SUBSCRIPTION
@@ -805,7 +805,7 @@
         for event in events :
             req.subscription["notify-events"] = ("keyword", event)
-        if userdata is not None :    
+        if userdata is not None :
             req.subscription["notify-user-data"] = ("octetString-with-an-unspecified-format", userdata)
-        if recipient is not None :    
+        if recipient is not None :
             req.subscription["notify-recipient"] = ("uri", recipient)
         if pullmethod is not None :
@@ -822,8 +822,8 @@
             req.subscription["notify-job-id"] = ("integer", jobid)
         return self.doRequest(req)
-            
-    def cancelSubscription(self, uri, subscriptionid, jobid=None) :    
+
+    def cancelSubscription(self, uri, subscriptionid, jobid=None) :
         """Cancels a subscription.
-        
+
            uri : the subscription's uri.
            subscriptionid : the subscription's id.
@@ -838,5 +838,5 @@
         req.event_notification["notify-subscription-id"] = ("integer", subscriptionid)
         return self.doRequest(req)
-        
+
 
 class FakeConfig :
@@ -879,5 +879,5 @@
         conffile.close()
     return dirvalues
-    
+
 class CupsBackend :
     """Base class for tools with no database access."""
@@ -912,5 +912,5 @@
         self.LockFile = None
 
-    def waitForLock(self) :    
+    def waitForLock(self) :
         """Waits until we can acquire the lock file."""
         lockfilename = self.DeviceURI.replace("/", ".")
@@ -926,12 +926,12 @@
                 # open the lock file, optionally creating it if needed.
                 self.LockFile = open(lockfilename, "a+")
-                
+
                 # we wait indefinitely for the lock to become available.
                 # works over NFS too.
                 fcntl.lockf(self.LockFile, fcntl.LOCK_EX)
                 haslock = True
-                
+
                 self.logDebug("Lock %s acquired." % lockfilename)
-                
+
                 # Here we save the PID in the lock file, but we don't use
                 # it, because the lock file may be in a directory shared
@@ -942,8 +942,8 @@
                 self.LockFile.write(str(self.pid))
                 self.LockFile.flush()
-            except IOError :            
+            except IOError :
                 self.logDebug("I/O Error while waiting for lock %s" % lockfilename)
                 time.sleep(0.25)
-        
+
     def readConfig(self) :
         """Reads the configuration file."""
@@ -1104,5 +1104,5 @@
         self.Directory = self.getPrintQueueOption(self.PrinterName, "directory", ignore=1) or tempfile.gettempdir()
         self.DataFile = os.path.join(self.Directory, "%s-%s-%s-%s" % (self.myname, self.PrinterName, self.UserName, self.JobId))
-        
+
         # check that the DEVICE_URI environment variable's value is
         # prefixed with self.myname otherwise don't touch it.
@@ -1128,5 +1128,5 @@
         self.RealBackend = backend
         self.DeviceURI = device_uri
-        
+
         try :
             cupsserver = CUPS() # TODO : username and password and/or encryption
@@ -1135,26 +1135,26 @@
                 raise ValueError # don't hande unix domain sockets yet.
             self.ControlFile = "NotUsedAnymore"
-        except :    
+        except :
             (ippfilename, answer) = self.parseIPPRequestFile()
             self.ControlFile = ippfilename
-        
+
         try :
             john = answer.job["job-originating-host-name"]
-        except (KeyError, AttributeError) :    
+        except (KeyError, AttributeError) :
             try :
                 john = answer.operation["job-originating-host-name"]
-            except (KeyError, AttributeError) :    
+            except (KeyError, AttributeError) :
                 john = (None, None)
-        if type(john) == type([]) :                          
+        if type(john) == type([]) :
             john = john[-1]
-        (dummy, self.ClientHost) = john                          
-        try :        
+        (dummy, self.ClientHost) = john
+        try :
             jbing = answer.job["job-billing"]
-        except (KeyError, AttributeError) :    
+        except (KeyError, AttributeError) :
             jbing = (None, None)
-        if type(jbing) == type([]) : 
+        if type(jbing) == type([]) :
             jbing = jbing[-1]
         (dummy, self.JobBilling) = jbing
-        
+
     def parseIPPRequestFile(self) :
         """Parses the IPP message file and returns a tuple (filename, parsedvalue)."""
@@ -1212,8 +1212,8 @@
         else :
             infile = sys.stdin
-            
+
         filtercommand = self.getPrintQueueOption(self.PrinterName, "filter", \
                                                  ignore=1)
-        if filtercommand :                                                 
+        if filtercommand :
             self.logDebug("Data stream will be filtered through [%s]" % filtercommand)
             filteroutput = "%s.filteroutput" % self.DataFile
@@ -1226,7 +1226,7 @@
             infile = open(filteroutput, "rb")
             mustclose = 1
-        else :    
+        else :
             self.logDebug("Data stream will be used as-is (no filter defined)")
-            
+
         CHUNK = 64*1024         # read 64 Kb at a time
         dummy = 0
@@ -1245,15 +1245,15 @@
             dummy += 1
         outfile.close()
-        
+
         if filtercommand :
             self.logDebug("Removing filter's output file %s" % filteroutput)
             try :
                 os.remove(filteroutput)
-            except :    
+            except :
                 pass
-                
+
         if mustclose :
             infile.close()
-            
+
         self.logDebug("%s bytes saved..." % sizeread)
         self.JobSize = sizeread
@@ -1269,7 +1269,7 @@
             try :
                 os.remove(self.DataFile)
-            except OSError, msg :    
+            except OSError, msg :
                 self.logInfo("Problem when removing %s : %s" % (self.DataFile, msg), "error")
-                
+
         if self.LockFile is not None :
             self.logDebug("Removing lock...")
@@ -1277,7 +1277,7 @@
                 fcntl.lockf(self.LockFile, fcntl.LOCK_UN)
                 self.LockFile.close()
-            except :    
+            except :
                 self.logInfo("Problem while unlocking.", "error")
-            else :    
+            else :
                 self.logDebug("Lock removed.")
         self.logDebug("Clean.")
@@ -1303,10 +1303,10 @@
                         self.logDebug("Launching onfail script %s" % onfail)
                         os.system(onfail)
-                        
+
             os.environ["TEASTATUS"] = str(retcode)
             branches = self.enumBranches(self.PrinterName, "posthook")
             if self.runCommands("posthook", branches, serialize) :
                 self.logInfo("An error occured during the execution of posthooks.", "warn")
-                
+
         for p in [ (k, v) for (k, v) in self.pipes.items() if k != 0 ] :
             os.close(p[1][0])
@@ -1404,11 +1404,11 @@
             try :
                 (number, delay) = [int(p) for p in retry.strip().split(",")]
-            except (ValueError, AttributeError, TypeError) :    
+            except (ValueError, AttributeError, TypeError) :
                 self.logInfo("Invalid value '%s' for the 'retry' directive for printer %s in %s." % (retry, self.PrinterName, self.conffile), "error")
                 number = 1
                 delay = 0
-                
-        loopcount = 1 
-        while 1 :            
+
+        loopcount = 1
+        while 1 :
             retcode = self.runOriginalBackend()
             if not retcode :
@@ -1419,8 +1419,8 @@
                     time.sleep(delay)
                     loopcount += 1
-                else :    
+                else :
                     break
-        return retcode            
-        
+        return retcode
+
     def runOriginalBackend(self) :
         """Launches the original backend."""
@@ -1435,5 +1435,5 @@
                 os.dup2(f.fileno(), 0)
                 f.close()
-            else :    
+            else :
                 arguments[6] = self.DataFile # in case a tea4cups filter was applied
             try :
@@ -1485,5 +1485,5 @@
             except SystemExit, e :
                 returncode = e.code
-            except KeyboardInterrupt :    
+            except KeyboardInterrupt :
                 wrapper.logInfo("Job %s interrupted by the administrator !" % wrapper.JobId, "warn")
             except :
@@ -1498,5 +1498,5 @@
                 sys.stderr.flush()
                 returncode = 1
-        finally :        
+        finally :
             wrapper.cleanUp()
         sys.exit(returncode)
Index: tea4cups/trunk/NEWS
===================================================================
--- tea4cups/trunk/NEWS (revision 691)
+++ tea4cups/trunk/NEWS (revision 3438)
@@ -24,51 +24,51 @@
 
   * 3.13alpha (2006-11-07) :
-  
+
     - Backported locking mechanism from PyKota.
-    
+
   * 3.12 (2006-08-11) :
-  
-    - Serializes accesses to the same device from different queues 
+
+    - Serializes accesses to the same device from different queues
       or print servers through file locking facilities (works over
       NFS).
-    
+
     - Improved support for CUPS 1.2.x and higher.
-    
+
     - Allows the administrator to cleanly stop tea4cups with SIGINT.
-    
+
     - Added a configurable retry directive to the configuration file.
-    
+
     - Fixed several minor bugs.
-    
+
     - Improved the installation instructions and the sample configuration
       file.
-    
-  * 3.11 : 
-  
+
+  * 3.11 :
+
     - Fixed an incompatibility with Python 2.1, thanks to Frank
       Koormann.
-      
+
   * 3.10 :
-  
+
     - Added filters.
-    
+
     - Added the "onfail" directive to tea4cups.conf
-    
+
   * 3.02 :
-  
+
     - Fixed some problems thanks to pychecker.
-    
+
   * 3.01 :
-  
+
     - Fixed an IPP parsing bug in some situations.
-    
+
   * 3.00 :
-  
+
     - Tees don't exist anymore. Only prehooks and posthooks remain.
-      
+
     - Prehooks can now send datas to Posthooks through pipes.
-    
+
     - Major rewrite of the subprocess management code, thanks to Peter Stuge.
-    
+
   * 2.12alpha :
 
Index: tea4cups/trunk/tea4cups.conf
===================================================================
--- tea4cups/trunk/tea4cups.conf (revision 691)
+++ tea4cups/trunk/tea4cups.conf (revision 3438)
@@ -67,10 +67,10 @@
 #
 #           N : number of times to try. If 0, will retry indefinitely, until
-#               the backend accepts all the datas without error.              
+#               the backend accepts all the datas without error.
 #
 #           S : delay in Seconds between two attempts.
 #
 # The example below would retry up to three times, at 60 seconds interval.
-# 
+#
 # retry : 3,60
 
@@ -89,5 +89,5 @@
 
 
-# Should we pass incoming datas through a filter command 
+# Should we pass incoming datas through a filter command
 # BEFORE doing anything else ?
 # NB : obvisouly the filter command doesn't have any access to
@@ -96,5 +96,5 @@
 # The value defined in a print queue section takes precedence over the
 # value defined in the [global] section.
-# 
+#
 # The sample filter below can remove the print job creation date
 # from PostScript jobs, in order to more accurately detect duplicate
@@ -123,5 +123,5 @@
 
 # When executing the contents of a prehook or posthook directive, as
-# defined below, tea4cups makes the following environment variables 
+# defined below, tea4cups makes the following environment variables
 # available to your own commands :
 #
@@ -178,5 +178,5 @@
 
 # Another example : a PDF generator which creates PDF documents
-# in the user's home directory under the names JOB-iiii.pdf 
+# in the user's home directory under the names JOB-iiii.pdf
 # where iiii is the job id :
 #
@@ -231,5 +231,5 @@
 # NB : Beware of some software which embed the job printing time into the
 # PostScript job : two identical jobs may have different MD5 checksums
-# if they differ only by the value of the '%%CreationDate:' PostScript 
+# if they differ only by the value of the '%%CreationDate:' PostScript
 # comment !
 #
Index: tea4cups/trunk/CREDITS
===================================================================
--- tea4cups/trunk/CREDITS (revision 691)
+++ tea4cups/trunk/CREDITS (revision 3438)
@@ -34,5 +34,5 @@
   - Clive Bruton
   - Mark Wolf - ESCO Corporation
-  
+
 
 Contributors :
Index: tea4cups/trunk/README
===================================================================
--- tea4cups/trunk/README (revision 3382)
+++ tea4cups/trunk/README (revision 3438)
@@ -24,5 +24,5 @@
 
 Tea4CUPS behaves just like any other CUPS backend, but allows you to
-modify print jobs' datas as they pass through it and to transparently 
+modify print jobs' datas as they pass through it and to transparently
 send them to any number of outputs : other CUPS backends, files or pipes.
 
@@ -54,5 +54,5 @@
                       print job has been sent to the real printer,
                       unless the job was previously cancelled by a
-                      prehook. Any number of posthooks can be 
+                      prehook. Any number of posthooks can be
                       defined for a particular print queue.
 
@@ -79,5 +79,5 @@
 
         None of these environment variables is available to filters.
-  
+
 NB : Tea4CUPS requires a version of Python >= 2.3
 
@@ -101,7 +101,7 @@
 
         $ cp tea4cups /usr/lib/cups/backend
-        
+
       If you use CUPS v1.2 or higher you must do this as well :
-      
+
         $ chown root.root /usr/lib/cups/backend/tea4cups
         $ chmod 700 /usr/lib/cups/backend/tea4cups
@@ -117,6 +117,6 @@
       Or by directly modifying CUPS' printers.conf file, or with
       the lpadmin command line tool, just prepend each DeviceURI
-      value with 'tea4cups://'. If you modified printers.conf 
-      directly instead of using lpadmin then don't forget to 
+      value with 'tea4cups://'. If you modified printers.conf
+      directly instead of using lpadmin then don't forget to
       restart CUPS.
       (Use this last method if autodetection doesn't work because
