root / tea4cups / trunk / cupsoftee @ 568

Revision 568, 7.6 kB (checked in by jerome, 19 years ago)

Autodetection with no reentrance now works

  • Property svn:executable set to *
  • Property svn:keywords set to Author Date Id Rev
Line 
1#! /usr/bin/env python
2# -*- coding: ISO-8859-15 -*-
3
4# CupsOfTee : Tee for CUPS
5#
6# (c) 2005 Jerome Alet <alet@librelogiciel.com>
7# This program is free software; you can redistribute it and/or modify
8# it under the terms of the GNU General Public License as published by
9# the Free Software Foundation; either version 2 of the License, or
10# (at your option) any later version.
11#
12# This program is distributed in the hope that it will be useful,
13# but WITHOUT ANY WARRANTY; without even the implied warranty of
14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15# GNU General Public License for more details.
16#
17# You should have received a copy of the GNU General Public License
18# along with this program; if not, write to the Free Software
19# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
20#
21# $Id$
22#
23#
24
25import sys
26import os
27import errno
28import cStringIO
29import shlex
30import tempfile
31
32class CupsBackend :
33    """Base class for tools with no database access."""
34    def __init__(self) :
35        """Initializes the CUPS backend wrapper."""
36        self.debug = 1
37       
38    def fakePrint(self) :   
39        """Fakes to print the job."""
40        if os.environ.has_key("CUPS_SERVERROOT") and os.path.isdir(os.environ.get("CUPS_SERVERROOT", "")) :
41            # Either the job's datas are on our stdin, or in a file
42            if len(sys.argv) == 7 :
43                self.InputFile = sys.argv[6]
44            else :   
45                self.InputFile = None
46               
47            # check that the DEVICE_URI environment variable's value is
48            # prefixed with "cupsoftee:" otherwise don't touch it.
49            # If this is the case, we have to remove the prefix from
50            # the environment before launching the real backend in cupspykota
51            device_uri = os.environ.get("DEVICE_URI", "")
52            if device_uri.startswith("cupspykota:") :
53                fulldevice_uri = device_uri[:]
54                device_uri = fulldevice_uri[len("cupspykota:"):]
55                if device_uri.startswith("//") :    # lpd (at least)
56                    device_uri = device_uri[2:]
57                os.environ["DEVICE_URI"] = device_uri   # TODO : side effect !
58            # TODO : check this for more complex urls than ipp://myprinter.dot.com:631/printers/lp
59            try :
60                (backend, destination) = device_uri.split(":", 1) 
61            except ValueError :   
62                raise PyKotaToolError, "Invalid DEVICE_URI : %s\n" % device_uri
63            while destination.startswith("/") :
64                destination = destination[1:]
65            checkauth = destination.split("@", 1)   
66            if len(checkauth) == 2 :
67                destination = checkauth[1]
68            printerhostname = destination.split("/")[0].split(":")[0]
69            return ("CUPS", \
70                    printerhostname, \
71                    os.environ.get("PRINTER"), \
72                    sys.argv[2].strip(), \
73                    sys.argv[1].strip(), \
74                    inputfile, \
75                    int(sys.argv[4].strip()), \
76                    sys.argv[3], \
77                    sys.argv[5], \
78                    backend)
79       
80    def discoverOtherBackends(self) :   
81        """Discovers the other CUPS backends.
82       
83           Executes each existing backend in turn in device enumeration mode.
84           Returns the list of available backends.
85        """
86        self.logDebug("Entering device enumeration loop.")
87        available = []
88        tmpdir = tempfile.gettempdir()
89        lockfilename = os.path.join(tmpdir, "cupsoftee..LCK")
90        if os.path.exists(lockfilename) :
91            self.logInfo("Lock file present.")
92            locked = 1
93            lockfile = open(lockfilename, "r")
94            pid = int(lockfile.read())
95            lockfile.close()
96            try :
97                # see if the pid contained in the lock file is still running
98                os.kill(pid, 0)
99            except OSError, e :   
100                if e.errno != errno.EPERM :
101                    # process doesn't exist anymore
102                    self.logInfo("Removing stalled lock.")
103                    os.remove(lockfilename)
104                    locked = 0
105            if locked :       
106                self.logInfo("No device enumeration.")
107           
108        if not os.path.exists(lockfilename) :
109            lockfile = open(lockfilename, "w")
110            lockfile.write("%i" % os.getpid())
111            lockfile.close()
112            (directory, myname) = os.path.split(sys.argv[0])
113            for backend in [ os.path.join(directory, b) \
114                                 for b in os.listdir(directory) 
115                                     if os.path.isfile(os.path.join(directory, b))\
116                                        and (b != myname)] :
117                answer = os.popen(backend, "r")
118                try :
119                    devices = [line.strip() for line in answer.readlines()]
120                except :   
121                    devices = []
122                status = answer.close()
123                if status is None :
124                    for d in devices :
125                        # each line is of the form :
126                        # 'xxxx xxxx "xxxx xxx" "xxxx xxx"'
127                        # so we have to decompose it carefully
128                        fdevice = cStringIO.StringIO(d)
129                        tokenizer = shlex.shlex(fdevice)
130                        tokenizer.wordchars = tokenizer.wordchars + \
131                                                        r".:,?!~/\_$*-+={}[]()#"
132                        arguments = []
133                        while 1 :
134                            token = tokenizer.get_token()
135                            if token :
136                                arguments.append(token)
137                            else :
138                                break
139                        fdevice.close()
140                        try :
141                            (devicetype, device, name, fullname) = arguments
142                        except ValueError :   
143                            pass    # ignore this 'bizarre' device
144                        else :   
145                            if name.startswith('"') and name.endswith('"') :
146                                name = name[1:-1]
147                            if fullname.startswith('"') and fullname.endswith('"') :
148                                fullname = fullname[1:-1]
149                            available.append('%s cupsoftee:%s "CupsOfTee+%s" "CupsOfTee managed %s"' \
150                                                 % (devicetype, device, name, fullname))
151            os.remove(lockfilename)
152        self.logDebug("Exiting device enumeration loop.")
153        return available
154                       
155    def logDebug(self, message) :   
156        """Logs something to debug output if debug is enabled."""
157        if self.debug :
158            sys.stderr.write("DEBUG: %s\n" % message)
159            sys.stderr.flush()
160           
161    def logInfo(self, message, level="info") :       
162        """Logs a message to CUPS' error_log file."""
163        sys.stderr.write("%s: %s\n" % (level.upper(), message))
164        sys.stderr.flush()
165       
166
167if __name__ == "__main__" :   
168    # This is a CUPS backend, we should act and die like a CUPS backend
169    wrapper = CupsBackend()
170    if len(sys.argv) == 1 :
171        print "\n".join(wrapper.discoverOtherBackends())
172        sys.exit(0)               
173    elif len(sys.argv) not in (6, 7) :   
174        sys.stderr.write("ERROR: %s job-id user title copies options [file]\n"\
175                              % sys.argv[0])
176        sys.exit(1)
177    else :   
178        sys.stderr.write("ERROR: Not Yet !\n")
179        sys.exit(1)
Note: See TracBrowser for help on using the browser.