root / pykota / trunk / bin / pkhint @ 1423

Revision 1423, 11.0 kB (checked in by jalet, 21 years ago)

Fixed path problem

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