root / pykota / trunk / pykota / accounters / external.py @ 1203

Revision 1203, 6.9 kB (checked in by jalet, 20 years ago)

Job price added to history

  • 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 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  2003/11/23 19:01:36  jalet
25# Job price added to history
26#
27# Revision 1.9  2003/11/21 14:28:45  jalet
28# More complete job history.
29#
30# Revision 1.8  2003/11/12 23:29:24  jalet
31# More work on new backend. This commit may be unstable.
32#
33# Revision 1.7  2003/10/07 09:07:28  jalet
34# Character encoding added to please latest version of Python
35#
36# Revision 1.6  2003/09/04 07:57:18  jalet
37# Problem with Python 2.3 fixed : a bug of me.
38#
39# Revision 1.5  2003/07/07 11:49:24  jalet
40# Lots of small fixes with the help of PyChecker
41#
42# Revision 1.4  2003/06/25 14:10:01  jalet
43# Hey, it may work (edpykota --reset excepted) !
44#
45# Revision 1.3  2003/05/27 23:00:21  jalet
46# Big rewrite of external accounting methods.
47# Should work well now.
48#
49# Revision 1.2  2003/05/13 13:54:20  jalet
50# Better handling of broken pipes
51#
52# Revision 1.1  2003/05/07 19:47:06  jalet
53# v1.07 Release of the Shame is out !
54#
55#
56#
57
58import sys
59import os
60import popen2
61import tempfile
62from pykota.accounter import AccounterBase, PyKotaAccounterError
63
64class Accounter(AccounterBase) :
65    def beginJob(self, printer, user) :   
66        """Saves the computed job size."""
67        # computes job's size
68        self.JobSize = self.computeJobSize()
69       
70        # get last job information for this printer
71        if not printer.LastJob.Exists :
72            # The printer hasn't been used yet, from PyKota's point of view
73            self.LastPageCounter = 0
74        else :   
75            # get last job size and page counter from Quota Storage
76            # Last lifetime page counter before actual job is
77            # last page counter + last job size
78            self.LastPageCounter = int(printer.LastJob.PrinterPageCounter or 0) + int(printer.LastJob.JobSize or 0)
79       
80    def endJob(self, printer, user) :   
81        """Do nothing."""
82        pass
83       
84    def getJobSize(self) :   
85        """Returns the actual job size."""
86        try :
87            return self.JobSize
88        except AttributeError :   
89            return 0
90       
91    def doAccounting(self, printer, user) :
92        """Deletgates the computation of the job size to an external command.
93       
94           The command must print the job size on its standard output and exit successfully.
95        """
96        self.beginJob(printer, user)
97       
98        # get the job size, which is real job size * number of copies.
99        jobsize = self.getJobSize() * self.filter.copies
100           
101        # Is the current user allowed to print at all ?
102        userpquota = self.filter.storage.getUserPQuota(user, printer)
103        action = self.filter.warnUserPQuota(userpquota)
104       
105        # update the quota for the current user on this printer, if allowed to print
106        if action == "DENY" :
107            jobsize = 0
108        else :   
109            userpquota.increasePagesUsage(jobsize)
110       
111        # adds the current job to history   
112        jobprice = (float(printer.PricePerPage or 0.0) * jobsize) + float(printer.PricePerJob or 0.0)
113        printer.addJobToHistory(self.filter.jobid, user, self.getLastPageCounter(), action, jobsize, jobprice, self.filter.preserveinputfile, self.filter.title, self.filter.copies, self.filter.options)
114       
115        self.endJob(printer, user)
116           
117        return action
118       
119    def computeJobSize(self) :   
120        """Feeds an external command with our datas to let it compute the job size, and return its value."""
121        temporary = None   
122        if self.filter.inputfile is None :   
123            infile = sys.stdin
124            # we will have to duplicate our standard input
125            temporary = tempfile.TemporaryFile()
126        else :   
127            infile = open(self.filter.inputfile, "rb")
128           
129        # launches external accounter
130        # TODO : USE tempfile.mkstemp() instead ! Needs some work !
131        infilename = tempfile.mktemp()
132        outfilename = tempfile.mktemp()
133        errfilename = tempfile.mktemp()
134       
135        try :
136            # feed it with our data
137            fakeinput = open(infilename, "wb")
138            data = infile.read(256*1024)   
139            while data :
140                fakeinput.write(data)
141                if temporary is not None :
142                    temporary.write(data)
143                data = infile.read(256*1024)
144            fakeinput.close()
145       
146            # launches child process
147            command = "%s <%s >%s 2>%s" % (self.arguments, infilename, outfilename, errfilename)
148            retcode = os.system(command)
149           
150            # check exit status
151            if (os.WIFEXITED(retcode) and not os.WEXITSTATUS(retcode)) or os.stat(errfilename) :
152                # tries to extract the job size from the external accounter's
153                # standard output
154                childoutput = open(outfilename, "r")
155                try :
156                    pagecount = int(childoutput.readline().strip())
157                except (AttributeError, ValueError) :
158                    self.filter.logger.log_message(_("Unable to compute job size with external accounter %s") % self.arguments)
159                    pagecount = 0
160                childoutput.close()   
161            else :
162                self.filter.logger.log_message(_("Unable to compute job size with external accounter %s") % self.arguments)
163                pagecount = 0
164            os.remove(infilename)
165            os.remove(outfilename)
166            os.remove(errfilename)
167        except IOError, msg :   
168            # TODO : temporary files may remain on the filesystem...
169            msg = "%s : %s" % (self.arguments, msg) 
170            self.filter.logger.log_message(_("Unable to compute job size with external accounter %s") % msg)
171            pagecount = 0
172           
173        if temporary is not None :   
174            # this is a copy of our previous standard input
175            # flush, then rewind
176            temporary.flush()
177            temporary.seek(0, 0)
178            # our temporary file will be used later if the
179            # job is allowed.
180            self.filter.inputfile = temporary
181        else :
182            infile.close()
183           
184        return pagecount   
185           
Note: See TracBrowser for help on using the browser.