Index: tea4cups/trunk/tea4cups
===================================================================
--- tea4cups/trunk/tea4cups (revision 575)
+++ tea4cups/trunk/tea4cups (revision 575)
@@ -0,0 +1,255 @@
+#! /usr/bin/env python
+# -*- coding: ISO-8859-15 -*-
+
+# CupsOfTee : Tee for CUPS
+#
+# (c) 2005 Jerome Alet <alet@librelogiciel.com>
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# 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
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+#
+# $Id$
+#
+#
+
+import sys
+import os
+import errno
+import cStringIO
+import shlex
+import tempfile
+import ConfigParser
+
+class TeeError(Exception):
+    """Base exception for CupsOfTee related stuff."""
+    def __init__(self, message = ""):
+        self.message = message
+        Exception.__init__(self, message)
+    def __repr__(self):
+        return self.message
+    __str__ = __repr__
+    
+class ConfigError(TeeError) :    
+    """Configuration related exceptions."""
+    pass 
+    
+class FakeConfig :    
+    """Fakes a configuration file parser."""
+    def get(self, section, option, raw=0) :
+        """Fakes the retrieval of a global option."""
+        raise ConfigError, "Invalid configuration file : no option %s in section [%s]" % (option, section)
+        
+class CupsBackend :
+    """Base class for tools with no database access."""
+    def __init__(self) :
+        """Initializes the CUPS backend wrapper."""
+        confdir = os.environ.get("CUPS_SERVERROOT", ".") 
+        self.conffile = os.path.join(confdir, "cupsoftee.conf")
+        if os.path.isfile(self.conffile) :
+            self.config = ConfigParser.ConfigParser()
+            self.config.read([self.conffile])
+            self.debug = self.isTrue(self.getGlobalOption("debug", ignore=1))
+        else :    
+            self.config = FakeConfig()
+            self.debug = 1      # no config, so force debug mode !
+        
+    def logDebug(self, message) :    
+        """Logs something to debug output if debug is enabled."""
+        if self.debug :
+            sys.stderr.write("DEBUG: %s\n" % message)
+            sys.stderr.flush()
+            
+    def logInfo(self, message, level="info") :        
+        """Logs a message to CUPS' error_log file."""
+        sys.stderr.write("%s: %s\n" % (level.upper(), message))
+        sys.stderr.flush()
+        
+    def isTrue(self, option) :        
+        """Returns 1 if option is set to true, else 0."""
+        if (option is not None) and (option.upper().strip() in ['Y', 'YES', '1', 'ON', 'T', 'TRUE']) :
+            return 1
+        else :    
+            return 0
+                        
+    def getGlobalOption(self, option, ignore=0) :    
+        """Returns an option from the global section, or raises a ConfigError if ignore is not set, else returns None."""
+        try :
+            return self.config.get("global", option, raw=1)
+        except (ConfigParser.NoSectionError, ConfigParser.NoOptionError) :    
+            if ignore :
+                return
+            else :
+                raise ConfigError, "Option %s not found in section global of %s" % (option, self.conffile)
+                
+    def getSectionOption(self, printqueuename, option) :    
+        """Returns an option from the printer section, or the global section, or raises a ConfigError."""
+        globaloption = self.getGlobalOption(option, ignore=1)
+        try :
+            return self.config.get(printqueuename, option, raw=1)
+        except (ConfigParser.NoSectionError, ConfigParser.NoOptionError) :    
+            if globaloption is not None :
+                return globaloption
+            else :
+                raise ConfigError, "Option %s not found in section [%s] of %s" % (option, printqueuename, self.conffile)
+                
+    def enumTeeBranches(self, printqueuename) :
+        """Returns the list of branches for a particular section's Tee."""
+        try :
+            globalbranches = [ (k, v) for (k, v) in self.config.items("global") if k.startswith("tee_") ]
+        except ConfigParser.NoSectionError, msg :    
+            self.printInfo("Invalid configuration file : %s" % msg, "error")
+            globalbranches = []
+        try :
+            sectionbranches = [ (k, v) for (k, v) in self.config.items(printqueuename) if k.startswith("tee_") ]
+        except ConfigParser.NoSectionError, msg :    
+            self.printInfo("Invalid configuration file : %s" % msg, "error")
+            sectionbranches = []
+        branches = {}
+        for (k, v) in globalbranches :
+            value = v.strip()
+            if value :
+                branches[k] = value
+        for (k, v) in sectionbranches :    
+            value = v.strip()
+            if value :
+                branches[k] = value # overwrite any global option or set a new value
+            else :    
+                del branches[k] # empty value disables a global option
+        return branches
+        
+    def discoverOtherBackends(self) :    
+        """Discovers the other CUPS backends.
+        
+           Executes each existing backend in turn in device enumeration mode.
+           Returns the list of available backends.
+        """
+        # Unfortunately this method can't output any debug information
+        # to stdout or stderr, else CUPS considers that the device is
+        # not available.
+        available = []
+        (directory, myname) = os.path.split(sys.argv[0])
+        tmpdir = tempfile.gettempdir()
+        lockfilename = os.path.join(tmpdir, "%s..LCK" % myname)
+        if os.path.exists(lockfilename) :
+            lockfile = open(lockfilename, "r")
+            pid = int(lockfile.read())
+            lockfile.close()
+            try :
+                # see if the pid contained in the lock file is still running
+                os.kill(pid, 0)
+            except OSError, e :    
+                if e.errno != errno.EPERM :
+                    # process doesn't exist anymore
+                    os.remove(lockfilename)
+            
+        if not os.path.exists(lockfilename) :
+            lockfile = open(lockfilename, "w")
+            lockfile.write("%i" % os.getpid())
+            lockfile.close()
+            allbackends = [ os.path.join(directory, b) \
+                                for b in os.listdir(directory) 
+                                    if os.access(os.path.join(directory, b), os.X_OK) \
+                                        and (b != myname)] 
+            for backend in allbackends :                            
+                answer = os.popen(backend, "r")
+                try :
+                    devices = [line.strip() for line in answer.readlines()]
+                except :    
+                    devices = []
+                status = answer.close()
+                if status is None :
+                    for d in devices :
+                        # each line is of the form : 
+                        # 'xxxx xxxx "xxxx xxx" "xxxx xxx"'
+                        # so we have to decompose it carefully
+                        fdevice = cStringIO.StringIO(d)
+                        tokenizer = shlex.shlex(fdevice)
+                        tokenizer.wordchars = tokenizer.wordchars + \
+                                                        r".:,?!~/\_$*-+={}[]()#"
+                        arguments = []
+                        while 1 :
+                            token = tokenizer.get_token()
+                            if token :
+                                arguments.append(token)
+                            else :
+                                break
+                        fdevice.close()
+                        try :
+                            (devicetype, device, name, fullname) = arguments
+                        except ValueError :    
+                            pass    # ignore this 'bizarre' device
+                        else :    
+                            if name.startswith('"') and name.endswith('"') :
+                                name = name[1:-1]
+                            if fullname.startswith('"') and fullname.endswith('"') :
+                                fullname = fullname[1:-1]
+                            available.append('%s cupsoftee:%s "CupsOfTee+%s" "CupsOfTee managed %s"' \
+                                                 % (devicetype, device, name, fullname))
+            os.remove(lockfilename)
+        return available
+                        
+    def fakePrint(self) :    
+        """Fakes to print the job."""
+        if os.environ.has_key("CUPS_SERVERROOT") and os.path.isdir(os.environ.get("CUPS_SERVERROOT", "")) :
+            # Either the job's datas are on our stdin, or in a file
+            if len(sys.argv) == 7 :
+                self.InputFile = sys.argv[6]
+            else :    
+                self.InputFile = None
+                
+            # check that the DEVICE_URI environment variable's value is 
+            # prefixed with "cupsoftee:" otherwise don't touch it.
+            # If this is the case, we have to remove the prefix from 
+            # the environment before launching the real backend in cupspykota
+            device_uri = os.environ.get("DEVICE_URI", "")
+            if device_uri.startswith("cupspykota:") :
+                fulldevice_uri = device_uri[:]
+                device_uri = fulldevice_uri[len("cupspykota:"):]
+                if device_uri.startswith("//") :    # lpd (at least)
+                    device_uri = device_uri[2:]
+                os.environ["DEVICE_URI"] = device_uri   # TODO : side effect !
+            # TODO : check this for more complex urls than ipp://myprinter.dot.com:631/printers/lp
+            try :
+                (backend, destination) = device_uri.split(":", 1) 
+            except ValueError :    
+                raise PyKotaToolError, "Invalid DEVICE_URI : %s\n" % device_uri
+            while destination.startswith("/") :
+                destination = destination[1:]
+            checkauth = destination.split("@", 1)    
+            if len(checkauth) == 2 :
+                destination = checkauth[1]
+            printerhostname = destination.split("/")[0].split(":")[0]
+            return ("CUPS", \
+                    printerhostname, \
+                    os.environ.get("PRINTER"), \
+                    sys.argv[2].strip(), \
+                    sys.argv[1].strip(), \
+                    inputfile, \
+                    int(sys.argv[4].strip()), \
+                    sys.argv[3], \
+                    sys.argv[5], \
+                    backend)
+
+if __name__ == "__main__" :    
+    # This is a CUPS backend, we should act and die like a CUPS backend
+    wrapper = CupsBackend()
+    if len(sys.argv) == 1 :
+        print "\n".join(wrapper.discoverOtherBackends())
+        sys.exit(0)                
+    elif len(sys.argv) not in (6, 7) :    
+        sys.stderr.write("ERROR: %s job-id user title copies options [file]\n"\
+                              % sys.argv[0])
+        sys.exit(1)
+    else :    
+        sys.stderr.write("ERROR: Not Yet !\n")
+        sys.exit(1)
Index: tea4cups/trunk/tea4cups.conf
===================================================================
--- tea4cups/trunk/tea4cups.conf (revision 575)
+++ tea4cups/trunk/tea4cups.conf (revision 575)
@@ -0,0 +1,34 @@
+# $Id$
+#
+# CupsOfTee : Tee for CUPS
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# 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
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+# 
+#
+[global]
+debug : yes
+#tee_0 : blah
+#tee_1 : blah
+#tee_2 : blah
+
+# Sample section for print queue HP2100
+# Uncomment and adapt to your needs.
+#
+[HP2100]
+#blah: 
+#tee_2 : zut    # overwrites the [global] value of tee_2
+#tee_4 : gniak
+#
+#
Index: tea4cups/trunk/cupsoftee.conf
===================================================================
--- tea4cups/trunk/cupsoftee.conf (revision 573)
+++  (revision )
@@ -1,34 +1,0 @@
-# $Id$
-#
-# CupsOfTee : Tee for CUPS
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# 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
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
-# 
-#
-[global]
-debug : yes
-#tee_0 : blah
-#tee_1 : blah
-#tee_2 : blah
-
-# Sample section for print queue HP2100
-# Uncomment and adapt to your needs.
-#
-[HP2100]
-#blah: 
-#tee_2 : zut    # overwrites the [global] value of tee_2
-#tee_4 : gniak
-#
-#
Index: tea4cups/trunk/cupsoftee
===================================================================
--- tea4cups/trunk/cupsoftee (revision 574)
+++  (revision )
@@ -1,255 +1,0 @@
-#! /usr/bin/env python
-# -*- coding: ISO-8859-15 -*-
-
-# CupsOfTee : Tee for CUPS
-#
-# (c) 2005 Jerome Alet <alet@librelogiciel.com>
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# 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
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
-#
-# $Id$
-#
-#
-
-import sys
-import os
-import errno
-import cStringIO
-import shlex
-import tempfile
-import ConfigParser
-
-class TeeError(Exception):
-    """Base exception for CupsOfTee related stuff."""
-    def __init__(self, message = ""):
-        self.message = message
-        Exception.__init__(self, message)
-    def __repr__(self):
-        return self.message
-    __str__ = __repr__
-    
-class ConfigError(TeeError) :    
-    """Configuration related exceptions."""
-    pass 
-    
-class FakeConfig :    
-    """Fakes a configuration file parser."""
-    def get(self, section, option, raw=0) :
-        """Fakes the retrieval of a global option."""
-        raise ConfigError, "Invalid configuration file : no option %s in section [%s]" % (option, section)
-        
-class CupsBackend :
-    """Base class for tools with no database access."""
-    def __init__(self) :
-        """Initializes the CUPS backend wrapper."""
-        confdir = os.environ.get("CUPS_SERVERROOT", ".") 
-        self.conffile = os.path.join(confdir, "cupsoftee.conf")
-        if os.path.isfile(self.conffile) :
-            self.config = ConfigParser.ConfigParser()
-            self.config.read([self.conffile])
-            self.debug = self.isTrue(self.getGlobalOption("debug", ignore=1))
-        else :    
-            self.config = FakeConfig()
-            self.debug = 1      # no config, so force debug mode !
-        
-    def logDebug(self, message) :    
-        """Logs something to debug output if debug is enabled."""
-        if self.debug :
-            sys.stderr.write("DEBUG: %s\n" % message)
-            sys.stderr.flush()
-            
-    def logInfo(self, message, level="info") :        
-        """Logs a message to CUPS' error_log file."""
-        sys.stderr.write("%s: %s\n" % (level.upper(), message))
-        sys.stderr.flush()
-        
-    def isTrue(self, option) :        
-        """Returns 1 if option is set to true, else 0."""
-        if (option is not None) and (option.upper().strip() in ['Y', 'YES', '1', 'ON', 'T', 'TRUE']) :
-            return 1
-        else :    
-            return 0
-                        
-    def getGlobalOption(self, option, ignore=0) :    
-        """Returns an option from the global section, or raises a ConfigError if ignore is not set, else returns None."""
-        try :
-            return self.config.get("global", option, raw=1)
-        except (ConfigParser.NoSectionError, ConfigParser.NoOptionError) :    
-            if ignore :
-                return
-            else :
-                raise ConfigError, "Option %s not found in section global of %s" % (option, self.conffile)
-                
-    def getSectionOption(self, printqueuename, option) :    
-        """Returns an option from the printer section, or the global section, or raises a ConfigError."""
-        globaloption = self.getGlobalOption(option, ignore=1)
-        try :
-            return self.config.get(printqueuename, option, raw=1)
-        except (ConfigParser.NoSectionError, ConfigParser.NoOptionError) :    
-            if globaloption is not None :
-                return globaloption
-            else :
-                raise ConfigError, "Option %s not found in section [%s] of %s" % (option, printqueuename, self.conffile)
-                
-    def enumTeeBranches(self, printqueuename) :
-        """Returns the list of branches for a particular section's Tee."""
-        try :
-            globalbranches = [ (k, v) for (k, v) in self.config.items("global") if k.startswith("tee_") ]
-        except ConfigParser.NoSectionError, msg :    
-            self.printInfo("Invalid configuration file : %s" % msg, "error")
-            globalbranches = []
-        try :
-            sectionbranches = [ (k, v) for (k, v) in self.config.items(printqueuename) if k.startswith("tee_") ]
-        except ConfigParser.NoSectionError, msg :    
-            self.printInfo("Invalid configuration file : %s" % msg, "error")
-            sectionbranches = []
-        branches = {}
-        for (k, v) in globalbranches :
-            value = v.strip()
-            if value :
-                branches[k] = value
-        for (k, v) in sectionbranches :    
-            value = v.strip()
-            if value :
-                branches[k] = value # overwrite any global option or set a new value
-            else :    
-                del branches[k] # empty value disables a global option
-        return branches
-        
-    def discoverOtherBackends(self) :    
-        """Discovers the other CUPS backends.
-        
-           Executes each existing backend in turn in device enumeration mode.
-           Returns the list of available backends.
-        """
-        # Unfortunately this method can't output any debug information
-        # to stdout or stderr, else CUPS considers that the device is
-        # not available.
-        available = []
-        (directory, myname) = os.path.split(sys.argv[0])
-        tmpdir = tempfile.gettempdir()
-        lockfilename = os.path.join(tmpdir, "%s..LCK" % myname)
-        if os.path.exists(lockfilename) :
-            lockfile = open(lockfilename, "r")
-            pid = int(lockfile.read())
-            lockfile.close()
-            try :
-                # see if the pid contained in the lock file is still running
-                os.kill(pid, 0)
-            except OSError, e :    
-                if e.errno != errno.EPERM :
-                    # process doesn't exist anymore
-                    os.remove(lockfilename)
-            
-        if not os.path.exists(lockfilename) :
-            lockfile = open(lockfilename, "w")
-            lockfile.write("%i" % os.getpid())
-            lockfile.close()
-            allbackends = [ os.path.join(directory, b) \
-                                for b in os.listdir(directory) 
-                                    if os.access(os.path.join(directory, b), os.X_OK) \
-                                        and (b != myname)] 
-            for backend in allbackends :                            
-                answer = os.popen(backend, "r")
-                try :
-                    devices = [line.strip() for line in answer.readlines()]
-                except :    
-                    devices = []
-                status = answer.close()
-                if status is None :
-                    for d in devices :
-                        # each line is of the form : 
-                        # 'xxxx xxxx "xxxx xxx" "xxxx xxx"'
-                        # so we have to decompose it carefully
-                        fdevice = cStringIO.StringIO(d)
-                        tokenizer = shlex.shlex(fdevice)
-                        tokenizer.wordchars = tokenizer.wordchars + \
-                                                        r".:,?!~/\_$*-+={}[]()#"
-                        arguments = []
-                        while 1 :
-                            token = tokenizer.get_token()
-                            if token :
-                                arguments.append(token)
-                            else :
-                                break
-                        fdevice.close()
-                        try :
-                            (devicetype, device, name, fullname) = arguments
-                        except ValueError :    
-                            pass    # ignore this 'bizarre' device
-                        else :    
-                            if name.startswith('"') and name.endswith('"') :
-                                name = name[1:-1]
-                            if fullname.startswith('"') and fullname.endswith('"') :
-                                fullname = fullname[1:-1]
-                            available.append('%s cupsoftee:%s "CupsOfTee+%s" "CupsOfTee managed %s"' \
-                                                 % (devicetype, device, name, fullname))
-            os.remove(lockfilename)
-        return available
-                        
-    def fakePrint(self) :    
-        """Fakes to print the job."""
-        if os.environ.has_key("CUPS_SERVERROOT") and os.path.isdir(os.environ.get("CUPS_SERVERROOT", "")) :
-            # Either the job's datas are on our stdin, or in a file
-            if len(sys.argv) == 7 :
-                self.InputFile = sys.argv[6]
-            else :    
-                self.InputFile = None
-                
-            # check that the DEVICE_URI environment variable's value is 
-            # prefixed with "cupsoftee:" otherwise don't touch it.
-            # If this is the case, we have to remove the prefix from 
-            # the environment before launching the real backend in cupspykota
-            device_uri = os.environ.get("DEVICE_URI", "")
-            if device_uri.startswith("cupspykota:") :
-                fulldevice_uri = device_uri[:]
-                device_uri = fulldevice_uri[len("cupspykota:"):]
-                if device_uri.startswith("//") :    # lpd (at least)
-                    device_uri = device_uri[2:]
-                os.environ["DEVICE_URI"] = device_uri   # TODO : side effect !
-            # TODO : check this for more complex urls than ipp://myprinter.dot.com:631/printers/lp
-            try :
-                (backend, destination) = device_uri.split(":", 1) 
-            except ValueError :    
-                raise PyKotaToolError, "Invalid DEVICE_URI : %s\n" % device_uri
-            while destination.startswith("/") :
-                destination = destination[1:]
-            checkauth = destination.split("@", 1)    
-            if len(checkauth) == 2 :
-                destination = checkauth[1]
-            printerhostname = destination.split("/")[0].split(":")[0]
-            return ("CUPS", \
-                    printerhostname, \
-                    os.environ.get("PRINTER"), \
-                    sys.argv[2].strip(), \
-                    sys.argv[1].strip(), \
-                    inputfile, \
-                    int(sys.argv[4].strip()), \
-                    sys.argv[3], \
-                    sys.argv[5], \
-                    backend)
-
-if __name__ == "__main__" :    
-    # This is a CUPS backend, we should act and die like a CUPS backend
-    wrapper = CupsBackend()
-    if len(sys.argv) == 1 :
-        print "\n".join(wrapper.discoverOtherBackends())
-        sys.exit(0)                
-    elif len(sys.argv) not in (6, 7) :    
-        sys.stderr.write("ERROR: %s job-id user title copies options [file]\n"\
-                              % sys.argv[0])
-        sys.exit(1)
-    else :    
-        sys.stderr.write("ERROR: Not Yet !\n")
-        sys.exit(1)
