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

Revision 1680, 6.5 kB (checked in by jalet, 20 years ago)

Now both software and hardware accounting raise an exception when no valid
result can be extracted from the subprocess' output.
Hardware accounting now reads subprocess' output until an integer is read
or data is exhausted : it now behaves just like software accounting in this
aspect.

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