root / pykota / trunk / bin / pkhint @ 1342

Revision 1342, 10.1 kB (checked in by jalet, 20 years ago)

De-uglyfication.
Now works with older CUPS (1.14) which don't detect the cupspykota backend but accept it anyway.

  • Property svn:eol-style set to native
  • Property svn:executable set to *
  • Property svn:keywords set to Author Date Id Revision
Line 
1#! /usr/bin/env python
2# -*- coding: ISO-8859-15 -*-
3
4# PyKota tool to hint for printer accounters
5#
6# PyKota - Print Quotas for CUPS and LPRng
7#
8# (c) 2003-2004 Jerome Alet <alet@librelogiciel.com>
9# This program is free software; you can redistribute it and/or modify
10# it under the terms of the GNU General Public License as published by
11# the Free Software Foundation; either version 2 of the License, or
12# (at your option) any later version.
13#
14# This program is distributed in the hope that it will be useful,
15# but WITHOUT ANY WARRANTY; without even the implied warranty of
16# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17# GNU General Public License for more details.
18#
19# You should have received a copy of the GNU General Public License
20# along with this program; if not, write to the Free Software
21# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
22#
23# $Id$
24#
25# $Log$
26# Revision 1.4  2004/02/09 12:35:19  jalet
27# De-uglyfication.
28# Now works with older CUPS (1.14) which don't detect the cupspykota backend but accept it anyway.
29#
30# Revision 1.3  2004/02/07 13:56:03  jalet
31# Help
32#
33# Revision 1.2  2004/02/07 13:47:55  jalet
34# More warnings
35#
36# Revision 1.1  2004/02/07 13:45:51  jalet
37# Preliminary work on the pkhint command
38#
39#
40#
41
42import sys
43import os
44
45from pykota import version
46from pykota.tool import PyKotaTool,PyKotaToolError
47from pykota.config import PyKotaConfigError
48from pykota.storage import PyKotaStorageError
49
50__doc__ = """pkhint v%s (c) 2003-2004 C@LL - Conseil Internet & Logiciels Libres
51A tool to give hints on what accounting method is best for each printer.
52
53command line usage :
54
55  pkhint [options] [printer1 printer2 printer3 ... printerN] <file.conf
56
57options :
58
59  -v | --version       Prints pkhint's version number then exits.
60  -h | --help          Prints this message then exits.
61 
62examples :                             
63
64  $ pkhint "hp*" printer103 </etc/cups/printers.conf
65 
66  Will analyze your printing system to test which accounter
67  is the best for each of the defined printer which
68  name matches one of the parameters.
69 
70  If you don't pass any argument on the command line, all
71  printers will be analyzed.
72 
73This program is free software; you can redistribute it and/or modify
74it under the terms of the GNU General Public License as published by
75the Free Software Foundation; either version 2 of the License, or
76(at your option) any later version.
77
78This program is distributed in the hope that it will be useful,
79but WITHOUT ANY WARRANTY; without even the implied warranty of
80MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
81GNU General Public License for more details.
82
83You should have received a copy of the GNU General Public License
84along with this program; if not, write to the Free Software
85Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
86
87Please e-mail bugs to: %s""" % (version.__version__, version.__author__)
88       
89SNMPTESTS = [ \
90              '/usr/bin/npadmin --pagecount %(printer)s 2>/dev/null', \
91              '/usr/bin/snmpget -v1 -c public -Ov %(printer)s mib-2.43.10.2.1.4.1.1 2>/dev/null | cut -f 2,2 -d " "', \
92              '/usr/bin/snmpwalk -v 1 -Cc -c public %(printer)s 2>/dev/null | grep mib-2.43.10.2.1.4.1.1 | cut -d " " -f4', \
93              '/usr/bin/snmpwalk -v 1 -Cc -c public -Ov %(printer)s 2>/dev/null | grep Counter32 | tail -2 | head -1 | cut -d " " -f2', \
94            ]
95
96class PKHint(PyKotaTool) :
97    """A class to autodetect the best accounting method for printers."""
98    def extractPrintersInformation(self) :   
99        """Extracts printer information from the printing system.
100         
101           Returns a mapping { queuename : device, ... }
102        """   
103        printers = {}
104        current_printer = None
105        for line in [l.strip() for l in sys.stdin.readlines()] :
106            testline = line.lower()
107            if testline.startswith("<printer ") or testline.startswith("<defaultprinter ") :
108                # beginning of a CUPS printer definition
109                current_printer = line.split()[-1][:-1]
110            elif testline.startswith("</printer ") :
111                # end of a CUPS printer definition
112                current_printer = None
113            elif testline.startswith("deviceuri ") :
114                # CUPS printer device_uri
115                device = testline.split()[-1]
116                if current_printer is not None :
117                    printers[current_printer] = device
118            else :       
119                # LPRng printcap specific code here
120                pass
121        return printers
122       
123    def extractDevices(self) :   
124        """Extracts the list of available CUPS devices.
125       
126           Returns a mapping { device : devicetype, ... }
127           
128           WARNING : CUPS ONLY FOR NOW
129        """   
130        inp = os.popen("/usr/sbin/lpinfo -v 2>/dev/null")
131        deviceslist = [l.strip() for l in inp.readlines()]
132        inp.close()
133        devicestypes = {}
134        for device in deviceslist :
135            (dtype, dname) = device.split()
136            devicestypes[dname] = dtype
137        return devicestypes
138       
139    def searchDeviceType(self, devicestypes, device) :   
140        """Returns the device type for current device."""
141        if device.startswith("cupspykota:") :
142            fulldevice = device[:]
143            device = fulldevice[len("cupspykota:"):]
144            if device.startswith("//") :
145                device = device[2:]
146        for (k, v) in devicestypes.items() :
147            if device.startswith(k) :
148                return v
149               
150    def extractDeviceFromURI(self, device) :   
151        """Cleans the device URI to remove any trace of PyKota."""
152        if device.startswith("cupspykota:") :
153            fulldevice = device[:]
154            device = fulldevice[len("cupspykota:"):]
155            if device.startswith("//") :
156                device = device[2:]
157        try :
158            (backend, destination) = device.split(":", 1) 
159        except ValueError :   
160            raise PyKotaToolError, "Invalid DEVICE_URI : %s\n" % device
161        while destination.startswith("/") :
162            destination = destination[1:]
163        checkauth = destination.split("@", 1)   
164        if len(checkauth) == 2 :
165            destination = checkauth[1]
166        return destination.split("/")[0]
167       
168    def accepts(self, printer, commands) :   
169        """Tries to get the printer's internal page counter via SNMP."""
170        for command in commands :
171            inp = os.popen(command % locals())
172            value = inp.readline().strip()
173            inp.close()
174            try :
175                pagecounter = int(value)
176            except :   
177                pass
178            else :   
179                return command
180       
181    def main(self, args, options) :
182        """Main work is done here."""
183        print "\nPlease wait while pkhint analyzes your printing system's configuration..."
184        printers = self.extractPrintersInformation()
185        devicestypes = self.extractDevices() # TODO : IT'S CUPS ONLY FOR NOW
186        configuration = []
187        for (printer, device) in printers.items() :
188            if self.matchString(printer, args) :
189                devicetype = self.searchDeviceType(devicestypes, device)
190                device = self.extractDeviceFromURI(device)
191                if devicetype is None :
192                    sys.stderr.write("Unknown device %s for printer %s\n" % (device, printer))
193                elif devicetype == "network" :
194                    try :
195                        hostname, port = device.split(':')
196                    except ValueError :   
197                        hostname = device
198                    snmpcommand = self.accepts(hostname, SNMPTESTS)
199                    if snmpcommand is not None :
200                        accounter = "querying"
201                        requester = 'external(/usr/bin/waitprinter.sh %(printer)s && ' + snmpcommand + ')'
202                        configuration.append((printer, accounter, requester))
203                elif devicetype == "direct" : 
204                    sys.stderr.write("Can't currently handle device %s for printer %s\n" % (device, printer))
205                elif devicetype == "serial" : 
206                    sys.stderr.write("Can't currently handle device %s for printer %s\n" % (device, printer))
207                else :
208                    sys.stderr.write("Can't currently handle device %s for printer %s\n" % (device, printer))
209                   
210        if not configuration :           
211            print "\nSorry, pkhint can't help you for now. Please configure PyKota manually."
212        else :
213            print "\nPut the following lines into your /etc/pykota/pykota.conf file :\n"
214            for (printer, accounter, requester) in configuration :
215                print "[%s]" % printer
216                print "accounter: %s" % accounter
217                if requester is not None :
218                    print "requester: %s" % requester
219                print   
220       
221if __name__ == "__main__" : 
222    sys.stderr.write("BEWARE : This tool doesn't support LPRng's printcap files yet.\n")
223    sys.stderr.write("This tool is currently highly experimental, so don't rely on it.\n")
224    retcode = 0
225    try :
226        short_options = "hv"
227        long_options = ["help", "version"]
228       
229        # Initializes the command line tool
230        manager = PKHint(doc=__doc__)
231       
232        (options, args) = manager.parseCommandline(sys.argv[1:], short_options, long_options)
233       
234        # sets long options
235        options["help"] = options["h"] or options["help"]
236        options["version"] = options["v"] or options["version"]
237       
238        if options["help"] :
239            manager.display_usage_and_quit()
240        elif options["version"] :
241            manager.display_version_and_quit()
242        else :
243            if not args :
244                args = [ "*" ]
245            retcode = manager.main(args, options)
246    except (PyKotaToolError, PyKotaConfigError, PyKotaStorageError), msg :           
247        sys.stderr.write("%s\n" % msg)
248        sys.stderr.flush()
249        retcode = -1
250
251    try :
252        manager.storage.close()
253    except (TypeError, NameError, AttributeError) :   
254        pass
255       
256    sys.exit(retcode)   
Note: See TracBrowser for help on using the browser.