root / pykota / trunk / bin / pkhint @ 1354

Revision 1343, 10.9 kB (checked in by jalet, 21 years ago)

Should now be able to handle network + pjl printers

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