root / tea4cups / trunk / cupsoftee @ 569

Revision 569, 7.5 kB (checked in by jerome, 19 years ago)

Avoids launching non-executable backends (like backends deactivated
by the Debian distribution for example)

  • 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 discoverOtherBackends(self) :   
39        """Discovers the other CUPS backends.
40       
41           Executes each existing backend in turn in device enumeration mode.
42           Returns the list of available backends.
43        """
44        # Unfortunately this method can't output any debug information
45        # to stdout or stderr, else CUPS considers that the device is
46        # not available.
47        available = []
48        (directory, myname) = os.path.split(sys.argv[0])
49        tmpdir = tempfile.gettempdir()
50        lockfilename = os.path.join(tmpdir, "%s..LCK" % myname)
51        if os.path.exists(lockfilename) :
52            lockfile = open(lockfilename, "r")
53            pid = int(lockfile.read())
54            lockfile.close()
55            try :
56                # see if the pid contained in the lock file is still running
57                os.kill(pid, 0)
58            except OSError, e :   
59                if e.errno != errno.EPERM :
60                    # process doesn't exist anymore
61                    os.remove(lockfilename)
62           
63        if not os.path.exists(lockfilename) :
64            lockfile = open(lockfilename, "w")
65            lockfile.write("%i" % os.getpid())
66            lockfile.close()
67            allbackends = [ os.path.join(directory, b) \
68                                for b in os.listdir(directory) 
69                                    if os.access(os.path.join(directory, b), os.X_OK) \
70                                        and (b != myname)] 
71            for backend in allbackends :                           
72                answer = os.popen(backend, "r")
73                try :
74                    devices = [line.strip() for line in answer.readlines()]
75                except :   
76                    devices = []
77                status = answer.close()
78                if status is None :
79                    for d in devices :
80                        # each line is of the form :
81                        # 'xxxx xxxx "xxxx xxx" "xxxx xxx"'
82                        # so we have to decompose it carefully
83                        fdevice = cStringIO.StringIO(d)
84                        tokenizer = shlex.shlex(fdevice)
85                        tokenizer.wordchars = tokenizer.wordchars + \
86                                                        r".:,?!~/\_$*-+={}[]()#"
87                        arguments = []
88                        while 1 :
89                            token = tokenizer.get_token()
90                            if token :
91                                arguments.append(token)
92                            else :
93                                break
94                        fdevice.close()
95                        try :
96                            (devicetype, device, name, fullname) = arguments
97                        except ValueError :   
98                            pass    # ignore this 'bizarre' device
99                        else :   
100                            if name.startswith('"') and name.endswith('"') :
101                                name = name[1:-1]
102                            if fullname.startswith('"') and fullname.endswith('"') :
103                                fullname = fullname[1:-1]
104                            available.append('%s cupsoftee:%s "CupsOfTee+%s" "CupsOfTee managed %s"' \
105                                                 % (devicetype, device, name, fullname))
106            os.remove(lockfilename)
107        return available
108                       
109    def fakePrint(self) :   
110        """Fakes to print the job."""
111        if os.environ.has_key("CUPS_SERVERROOT") and os.path.isdir(os.environ.get("CUPS_SERVERROOT", "")) :
112            # Either the job's datas are on our stdin, or in a file
113            if len(sys.argv) == 7 :
114                self.InputFile = sys.argv[6]
115            else :   
116                self.InputFile = None
117               
118            # check that the DEVICE_URI environment variable's value is
119            # prefixed with "cupsoftee:" otherwise don't touch it.
120            # If this is the case, we have to remove the prefix from
121            # the environment before launching the real backend in cupspykota
122            device_uri = os.environ.get("DEVICE_URI", "")
123            if device_uri.startswith("cupspykota:") :
124                fulldevice_uri = device_uri[:]
125                device_uri = fulldevice_uri[len("cupspykota:"):]
126                if device_uri.startswith("//") :    # lpd (at least)
127                    device_uri = device_uri[2:]
128                os.environ["DEVICE_URI"] = device_uri   # TODO : side effect !
129            # TODO : check this for more complex urls than ipp://myprinter.dot.com:631/printers/lp
130            try :
131                (backend, destination) = device_uri.split(":", 1) 
132            except ValueError :   
133                raise PyKotaToolError, "Invalid DEVICE_URI : %s\n" % device_uri
134            while destination.startswith("/") :
135                destination = destination[1:]
136            checkauth = destination.split("@", 1)   
137            if len(checkauth) == 2 :
138                destination = checkauth[1]
139            printerhostname = destination.split("/")[0].split(":")[0]
140            return ("CUPS", \
141                    printerhostname, \
142                    os.environ.get("PRINTER"), \
143                    sys.argv[2].strip(), \
144                    sys.argv[1].strip(), \
145                    inputfile, \
146                    int(sys.argv[4].strip()), \
147                    sys.argv[3], \
148                    sys.argv[5], \
149                    backend)
150       
151    def logDebug(self, message) :   
152        """Logs something to debug output if debug is enabled."""
153        if self.debug :
154            sys.stderr.write("DEBUG: %s\n" % message)
155            sys.stderr.flush()
156           
157    def logInfo(self, message, level="info") :       
158        """Logs a message to CUPS' error_log file."""
159        sys.stderr.write("%s: %s\n" % (level.upper(), message))
160        sys.stderr.flush()
161
162if __name__ == "__main__" :   
163    # This is a CUPS backend, we should act and die like a CUPS backend
164    wrapper = CupsBackend()
165    if len(sys.argv) == 1 :
166        print "\n".join(wrapper.discoverOtherBackends())
167        sys.exit(0)               
168    elif len(sys.argv) not in (6, 7) :   
169        sys.stderr.write("ERROR: %s job-id user title copies options [file]\n"\
170                              % sys.argv[0])
171        sys.exit(1)
172    else :   
173        sys.stderr.write("ERROR: Not Yet !\n")
174        sys.exit(1)
Note: See TracBrowser for help on using the browser.