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

Revision 3489, 7.8 kB (checked in by jerome, 15 years ago)

Removed bad copy and paste artifact.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
RevLine 
[3489]1# -*- coding: utf-8 -*-
[1475]2#
[3260]3# PyKota : Print Quotas for CUPS
[1475]4#
[3481]5# (c) 2003-2009 Jerome Alet <alet@librelogiciel.com>
[3260]6# This program is free software: you can redistribute it and/or modify
[1475]7# it under the terms of the GNU General Public License as published by
[3260]8# the Free Software Foundation, either version 3 of the License, or
[1475]9# (at your option) any later version.
[3413]10#
[1475]11# This program is distributed in the hope that it will be useful,
12# but WITHOUT ANY WARRANTY; without even the implied warranty of
13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14# GNU General Public License for more details.
[3413]15#
[1475]16# You should have received a copy of the GNU General Public License
[3260]17# along with this program.  If not, see <http://www.gnu.org/licenses/>.
[1475]18#
19# $Id$
20#
[2075]21#
[1475]22
[3289]23"""This module handles hardware page counting for PyKota."""
24
[1475]25import os
[1703]26import signal
[1483]27import popen2
[1729]28
[3288]29from pykota.errors import PyKotaAccounterError
30from pykota.accounter import AccounterBase
[2205]31from pykota.accounters import snmp, pjl
[1475]32
33class Accounter(AccounterBase) :
[3245]34    def __init__(self, kotabackend, arguments, ispreaccounter=0, name="hardware") :
[1475]35        """Initializes querying accounter."""
[3245]36        AccounterBase.__init__(self, kotabackend, arguments, ispreaccounter, name)
[1600]37        self.isSoftware = 0
[3413]38
39    def getPrinterInternalPageCounter(self) :
[1475]40        """Returns the printer's internal page counter."""
[2409]41        self.filter.logdebug("Reading printer %s's internal page counter..." % self.filter.PrinterName)
42        counter = self.askPrinterPageCounter(self.filter.PrinterHostName)
43        self.filter.logdebug("Printer %s's internal page counter value is : %s" % (self.filter.PrinterName, str(counter)))
[3413]44        return counter
45
46    def beginJob(self, printer) :
[1475]47        """Saves printer internal page counter at start of job."""
48        # save page counter before job
[1624]49        self.LastPageCounter = self.getPrinterInternalPageCounter()
50        self.fakeBeginJob()
[3413]51
52    def fakeBeginJob(self) :
[1624]53        """Fakes a begining of a job."""
54        self.counterbefore = self.getLastPageCounter()
[3413]55
56    def endJob(self, printer) :
[1475]57        """Saves printer internal page counter at end of job."""
58        # save page counter after job
59        self.LastPageCounter = self.counterafter = self.getPrinterInternalPageCounter()
[3413]60
61    def getJobSize(self, printer) :
[1475]62        """Returns the actual job size."""
[1713]63        if (not self.counterbefore) or (not self.counterafter) :
64            # there was a problem retrieving page counter
65            self.filter.printInfo(_("A problem occured while reading printer %s's internal page counter.") % printer.Name, "warn")
66            if printer.LastJob.Exists :
67                # if there's a previous job, use the last value from database
68                self.filter.printInfo(_("Retrieving printer %s's page counter from database instead.") % printer.Name, "warn")
[3413]69                if not self.counterbefore :
[1713]70                    self.counterbefore = printer.LastJob.PrinterPageCounter or 0
71                if not self.counterafter :
72                    self.counterafter = printer.LastJob.PrinterPageCounter or 0
[3413]73                before = min(self.counterbefore, self.counterafter)
74                after = max(self.counterbefore, self.counterafter)
[1713]75                self.counterbefore = before
76                self.counterafter = after
[1734]77                if (not self.counterbefore) or (not self.counterafter) or (self.counterbefore == self.counterafter) :
[1713]78                    self.filter.printInfo(_("Couldn't retrieve printer %s's internal page counter either before or after printing.") % printer.Name, "warn")
79                    self.filter.printInfo(_("Job's size forced to 1 page for printer %s.") % printer.Name, "warn")
[1714]80                    self.counterbefore = 0
81                    self.counterafter = 1
[1713]82            else :
83                self.filter.printInfo(_("No previous job in database for printer %s.") % printer.Name, "warn")
84                self.filter.printInfo(_("Job's size forced to 1 page for printer %s.") % printer.Name, "warn")
85                self.counterbefore = 0
86                self.counterafter = 1
[3413]87
88        jobsize = (self.counterafter - self.counterbefore)
[1713]89        if jobsize < 0 :
[3413]90            # Try to take care of HP printers
[1713]91            # Their internal page counter is saved to NVRAM
92            # only every 10 pages. If the printer was switched
93            # off then back on during the job, and that the
[3413]94            # counters difference is negative, we know
[1713]95            # the formula (we can't know if more than eleven
96            # pages were printed though) :
97            if jobsize > -10 :
98                jobsize += 10
[3413]99            else :
[1713]100                # here we may have got a printer being replaced
[2198]101                # DURING the job. This is HIGHLY improbable (but already happened) !
[1713]102                self.filter.printInfo(_("Inconsistent values for printer %s's internal page counter.") % printer.Name, "warn")
103                self.filter.printInfo(_("Job's size forced to 1 page for printer %s.") % printer.Name, "warn")
104                jobsize = 1
[1475]105        return jobsize
[3413]106
[1483]107    def askPrinterPageCounter(self, printer) :
108        """Returns the page counter from the printer via an external command.
[3413]109
[1483]110           The external command must report the life time page number of the printer on stdout.
111        """
[3162]112        skipinitialwait = self.filter.config.getPrinterSkipInitialWait(printer)
[1483]113        commandline = self.arguments.strip() % locals()
[1746]114        cmdlower = commandline.lower()
[2425]115        if (cmdlower == "snmp") or cmdlower.startswith("snmp:") :
[3162]116            return snmp.Handler(self, printer, skipinitialwait).retrieveInternalPageCounter()
[2425]117        elif (cmdlower == "pjl") or cmdlower.startswith("pjl:") :
[3162]118            return pjl.Handler(self, printer, skipinitialwait).retrieveInternalPageCounter()
[3413]119
[1483]120        if printer is None :
[2409]121            raise PyKotaAccounterError, _("Unknown printer address in HARDWARE(%s) for printer %s") % (commandline, self.filter.PrinterName)
[3413]122        while 1 :
[1739]123            self.filter.printInfo(_("Launching HARDWARE(%s)...") % commandline)
124            pagecounter = None
[3413]125            child = popen2.Popen4(commandline)
[1483]126            try :
[1739]127                answer = child.fromchild.read()
[3413]128            except IOError :
[1739]129                # we were interrupted by a signal, certainely a SIGTERM
130                # caused by the user cancelling the current job
[1680]131                try :
[1739]132                    os.kill(child.pid, signal.SIGTERM)
[3413]133                except :
[1739]134                    pass # already killed ?
135                self.filter.printInfo(_("SIGTERM was sent to hardware accounter %s (pid: %s)") % (commandline, child.pid))
[3413]136            else :
[1739]137                lines = [l.strip() for l in answer.split("\n")]
[3413]138                for i in range(len(lines)) :
[1739]139                    try :
140                        pagecounter = int(lines[i])
141                    except (AttributeError, ValueError) :
142                        self.filter.printInfo(_("Line [%s] skipped in accounter's output. Trying again...") % lines[i])
[3413]143                    else :
[1739]144                        break
[3413]145            child.fromchild.close()
[1739]146            child.tochild.close()
147            try :
148                status = child.wait()
[3413]149            except OSError, msg :
[1739]150                self.filter.logdebug("Error while waiting for hardware accounter pid %s : %s" % (child.pid, msg))
[3413]151            else :
[1739]152                if os.WIFEXITED(status) :
153                    status = os.WEXITSTATUS(status)
154                self.filter.printInfo(_("Hardware accounter %s exit code is %s") % (self.arguments, str(status)))
[3413]155
[1739]156            if pagecounter is None :
157                message = _("Unable to query printer %s via HARDWARE(%s)") % (printer, commandline)
158                if self.onerror == "CONTINUE" :
159                    self.filter.printInfo(message, "error")
160                else :
[3413]161                    raise PyKotaAccounterError, message
162            else :
163                return pagecounter
Note: See TracBrowser for help on using the browser.