root / pykota / trunk / pykota / accounters / hardware.py @ 1685

Revision 1685, 6.4 kB (checked in by jalet, 20 years ago)

No answer from subprocess now is really a fatal error. Waiting for some
time to make this configurable...

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1# PyKota
2# -*- coding: ISO-8859-15 -*-
3#
4# PyKota - Print Quotas for CUPS and LPRng
5#
6# (c) 2003-2004 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# $Log$
24# Revision 1.10  2004/08/27 22:49:04  jalet
25# No answer from subprocess now is really a fatal error. Waiting for some
26# time to make this configurable...
27#
28# Revision 1.9  2004/08/25 22:34:39  jalet
29# Now both software and hardware accounting raise an exception when no valid
30# result can be extracted from the subprocess' output.
31# Hardware accounting now reads subprocess' output until an integer is read
32# or data is exhausted : it now behaves just like software accounting in this
33# aspect.
34#
35# Revision 1.8  2004/07/22 22:41:48  jalet
36# Hardware accounting for LPRng should be OK now. UNTESTED.
37#
38# Revision 1.7  2004/07/16 12:22:47  jalet
39# LPRng support early version
40#
41# Revision 1.6  2004/07/01 19:56:42  jalet
42# Better dispatching of error messages
43#
44# Revision 1.5  2004/06/10 22:42:06  jalet
45# Better messages in logs
46#
47# Revision 1.4  2004/05/24 22:45:49  jalet
48# New 'enforcement' directive added
49# Polling loop improvements
50#
51# Revision 1.3  2004/05/24 14:36:40  jalet
52# Revert to old polling loop. Will need optimisations
53#
54# Revision 1.2  2004/05/18 14:49:22  jalet
55# Big code changes to completely remove the need for "requester" directives,
56# jsut use "hardware(... your previous requester directive's content ...)"
57#
58# Revision 1.1  2004/05/13 13:59:30  jalet
59# Code simplifications
60#
61#
62#
63
64import sys
65import os
66import popen2
67from pykota.accounter import AccounterBase, PyKotaAccounterError
68
69class Accounter(AccounterBase) :
70    def __init__(self, kotabackend, arguments) :
71        """Initializes querying accounter."""
72        AccounterBase.__init__(self, kotabackend, arguments)
73        self.isSoftware = 0
74       
75    def getPrinterInternalPageCounter(self) :   
76        """Returns the printer's internal page counter."""
77        self.filter.logdebug("Reading printer's internal page counter...")
78        counter = self.askPrinterPageCounter(self.filter.printerhostname)
79        self.filter.logdebug("Printer's internal page counter value is : %s" % str(counter))
80        return counter   
81       
82    def beginJob(self, printer) :   
83        """Saves printer internal page counter at start of job."""
84        # save page counter before job
85        self.LastPageCounter = self.getPrinterInternalPageCounter()
86        self.fakeBeginJob()
87       
88    def fakeBeginJob(self) :   
89        """Fakes a begining of a job."""
90        self.counterbefore = self.getLastPageCounter()
91       
92    def endJob(self, printer) :   
93        """Saves printer internal page counter at end of job."""
94        # save page counter after job
95        self.LastPageCounter = self.counterafter = self.getPrinterInternalPageCounter()
96       
97    def getJobSize(self) :   
98        """Returns the actual job size."""
99        try :
100            jobsize = (self.counterafter - self.counterbefore)   
101            if jobsize < 0 :
102                # Try to take care of HP printers
103                # Their internal page counter is saved to NVRAM
104                # only every 10 pages. If the printer was switched
105                # off then back on during the job, and that the
106                # counters difference is negative, we know
107                # the formula (we can't know if more than eleven
108                # pages were printed though) :
109                if jobsize > -10 :
110                    jobsize += 10
111                else :   
112                    # here we may have got a printer being replaced
113                    # DURING the job. This is HIGHLY improbable !
114                    jobsize = 0
115        except :   
116            # takes care of the case where one counter (or both) was never set.
117            jobsize = 0
118        return jobsize
119       
120    def askPrinterPageCounter(self, printer) :
121        """Returns the page counter from the printer via an external command.
122       
123           The external command must report the life time page number of the printer on stdout.
124        """
125        commandline = self.arguments.strip() % locals()
126        if printer is None :
127            raise PyKotaAccounterError, _("Unknown printer address in HARDWARE(%s) for printer %s") % (commandline, self.filter.printername)
128        self.filter.printInfo(_("Launching HARDWARE(%s)...") % commandline)
129        pagecounter = None
130        child = popen2.Popen4(commandline)   
131        try :
132            answer = child.fromchild.read()
133        except IOError :   
134            # we were interrupted by a signal, certainely a SIGTERM
135            # caused by the user cancelling the current job
136            try :
137                os.kill(child.pid, signal.SIGTERM)
138            except :   
139                pass # already killed ?
140            self.filter.printInfo(_("SIGTERM was sent to hardware accounter %s (pid: %s)") % (commandline, child.pid))
141        else :   
142            lines = [l.strip() for l in answer.split("\n")]
143            for i in range(len(lines)) : 
144                try :
145                    pagecounter = int(lines[i])
146                except (AttributeError, ValueError) :
147                    self.filter.printInfo(_("Line [%s] skipped in accounter's output. Trying again...") % lines[i])
148                else :   
149                    break
150        child.fromchild.close()   
151        child.tochild.close()
152        try :
153            status = child.wait()
154        except OSError, msg :   
155            self.filter.logdebug("Error while waiting for hardware accounter pid %s : %s" % (child.pid, msg))
156        if (pagecounter is not None) and os.WIFEXITED(status) and (not os.WEXITSTATUS(status)) :
157            return pagecounter
158        else :   
159            raise PyKotaAccounterError, _("Unable to query printer %s via HARDWARE(%s)") % (printer, commandline) 
160           
Note: See TracBrowser for help on using the browser.