root / pykota / trunk / bin / pykota @ 902

Revision 902, 9.7 kB (checked in by jalet, 21 years ago)

Comment

  • Property svn:eol-style set to native
  • Property svn:executable set to *
  • Property svn:keywords set to Author Date Id Revision
Line 
1#! /usr/bin/env python
2
3# PyKota accounting filter
4#
5# PyKota - Print Quotas for CUPS
6#
7# (c) 2003 Jerome Alet <alet@librelogiciel.com>
8# This program is free software; you can redistribute it and/or modify
9# it under the terms of the GNU General Public License as published by
10# the Free Software Foundation; either version 2 of the License, or
11# (at your option) any later version.
12#
13# This program is distributed in the hope that it will be useful,
14# but WITHOUT ANY WARRANTY; without even the implied warranty of
15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16# GNU General Public License for more details.
17#
18# You should have received a copy of the GNU General Public License
19# along with this program; if not, write to the Free Software
20# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
21#
22# $Id$
23#
24# $Log$
25# Revision 1.19  2003/04/11 08:56:49  jalet
26# Comment
27#
28# Revision 1.18  2003/04/11 08:50:39  jalet
29# Workaround for the HP "feature" of saving the page counter to NVRAM
30# only every time 10 new pages are printed...
31# Workaround for printers with volatile page counters.
32#
33# Revision 1.17  2003/04/10 21:47:20  jalet
34# Job history added. Upgrade script neutralized for now !
35#
36# Revision 1.16  2003/04/08 20:38:08  jalet
37# The last job Id is saved now for each printer, this will probably
38# allow other accounting methods in the future.
39#
40# Revision 1.15  2003/03/29 13:45:27  jalet
41# GPL paragraphs were incorrectly (from memory) copied into the sources.
42# Two README files were added.
43# Upgrade script for PostgreSQL pre 1.01 schema was added.
44#
45# Revision 1.14  2003/03/07 22:16:57  jalet
46# Algorithmically incorrect : last user quota wasn't updated if current
47# user wasn't allowed to print.
48#
49# Revision 1.13  2003/02/27 23:59:28  jalet
50# Stupid bug wrt exception handlingand value conversion
51#
52# Revision 1.12  2003/02/27 23:48:41  jalet
53# Correctly maps PyKota's log levels to syslog log levels
54#
55# Revision 1.11  2003/02/27 22:55:20  jalet
56# WARN log priority doesn't exist.
57#
58# Revision 1.10  2003/02/27 22:43:21  jalet
59# Missing import
60#
61# Revision 1.9  2003/02/27 22:40:26  jalet
62# Correctly handles cases where the printer is off.
63#
64# Revision 1.8  2003/02/09 12:56:53  jalet
65# Internationalization begins...
66#
67# Revision 1.7  2003/02/07 10:23:48  jalet
68# Avoid a possible future name clash
69#
70# Revision 1.6  2003/02/06 22:54:33  jalet
71# warnpykota should be ok
72#
73# Revision 1.5  2003/02/05 22:45:25  jalet
74# Forgotten import
75#
76# Revision 1.4  2003/02/05 22:42:51  jalet
77# Typo
78#
79# Revision 1.3  2003/02/05 22:38:39  jalet
80# Typo
81#
82# Revision 1.2  2003/02/05 22:16:20  jalet
83# DEVICE_URI is undefined outside of CUPS, i.e. for normal command line tools
84#
85# Revision 1.1  2003/02/05 21:28:17  jalet
86# Initial import into CVS
87#
88#
89#
90
91import sys
92import os
93
94from pykota.tool import PyKotaTool, PyKotaToolError
95from pykota.requester import openRequester, PyKotaRequesterError
96
97class PyKotaFilter(PyKotaTool) :   
98    """Class for the PyKota filter."""
99    def __init__(self, username) :
100        PyKotaTool.__init__(self, isfilter=1)
101        self.username = username
102        self.requester = openRequester(self.config, self.printername)
103        self.printerhostname = self.getPrinterHostname()
104   
105    def getPrinterHostname(self) :
106        """Returns the printer hostname."""
107        device_uri = os.environ.get("DEVICE_URI", "")
108        # TODO : check this for more complex urls than ipp://myprinter.dot.com:631/printers/lp
109        try :
110            (backend, destination) = device_uri.split(":", 1) 
111        except ValueError :   
112            raise PyKotaToolError, "Invalid DEVICE_URI : %s\n" % device_uri
113        while destination.startswith("/") :
114            destination = destination[1:]
115        return destination.split("/")[0].split(":")[0]
116       
117    def filterInput(self, inputfile) :
118        """Transparent filter."""
119        mustclose = 0   
120        if inputfile is not None :   
121            infile = open(inputfile, "rb")
122            mustclose = 1
123        else :   
124            infile = sys.stdin
125        data = infile.read(256*1024)   
126        while data :
127            sys.stdout.write(data)
128            data = infile.read(256*1024)
129        if mustclose :   
130            infile.close()
131           
132def main() :   
133    """Do it, and do it right !"""
134    #
135    # This is a CUPS filter, so we should act and die like a CUPS filter when needed
136    narg = len(sys.argv)
137    if narg not in (6, 7) :   
138        sys.stderr.write("ERROR: %s job-id user title copies options [file]\n" % sys.argv[0])
139        return 1
140    elif narg == 7 :   
141        # input file
142        inputfile = sys.argv[6]
143    else :   
144        # stdin
145        inputfile = None
146       
147    #   
148    # According to CUPS documentation, the job id is the second command line argument
149    jobid = sys.argv[1].strip()
150   
151    #   
152    # According to CUPS documentation, the username is the third command line argument
153    username = sys.argv[2].strip()   
154   
155    # Initializes the current tool
156    kotafilter = PyKotaFilter(username)   
157   
158    # Get the page counter directly from the printer itself
159    try :
160        counterbeforejob = kotafilter.requester.getPrinterPageCounter(kotafilter.printerhostname) # TODO use printername instead, make them match from CUPS' config files
161    except PyKotaRequesterError, msg :
162        # can't get actual page counter, assume printer is off, but warns in log
163        kotafilter.logger.log_message("%s" % msg, "warn")
164        counterbeforejob = None
165        printerIsOff = 1
166    else :   
167        printerIsOff = 0
168       
169    # Get the last page counter and last username from the Quota Storage backend
170    printerid = kotafilter.storage.getPrinterId(kotafilter.printername)
171    if printerid is None :
172        # The printer is unknown from the Quota Storage perspective
173        # we let the job pass through, but log a warning message
174        kotafilter.logger.log_message(_("Printer %s not registered in the PyKota system") % kotafilter.printername, "warn")
175    else :   
176        userid = kotafilter.storage.getUserId(username)
177        if userid is None :
178            # The user is unknown from the Quota Storage perspective
179            # we let the job pass through, but log a warning message
180            kotafilter.logger.log_message(_("User %s not registered in the PyKota system") % username, "warn")
181        else :
182            # get last job information for this printer
183            pgc = kotafilter.storage.getPrinterPageCounter(printerid)   
184            if pgc is None :
185                # The printer hasn't been used yet, from PyKota's point of view
186                lasthistoryid = None
187                lastjobid = jobid
188                lastuserid = userid
189                lastusername = username
190                lastpagecounter = counterbeforejob
191            else :   
192                # get last values from Quota Storage
193                (lasthistoryid, lastjobid, lastuserid, lastusername, lastpagecounter) = (pgc["id"], pgc["jobid"], pgc["userid"], pgc["username"], pgc["pagecounter"])
194               
195            # if printer is off then we assume the correct counter value is the last one
196            if printerIsOff :
197                counterbeforejob = lastpagecounter
198               
199            # if the internal lifetime page counter for this printer is 0   
200            # then this may be a printer with a volatile counter (never
201            # saved to NVRAM) which has just been switched off and then on
202            # so we use the last page counter from the Quota Storage instead
203            # explanation at : http://web.mit.edu/source/third/lprng/doc/LPRng-HOWTO-15.html
204            if counterbeforejob == 0 :
205                counterbeforejob = lastpagecounter
206               
207            # Computes the last job size as the difference between internal page
208            # counter in the printer and last page counter taken from the Quota
209            # Storage database for this particular printer
210            jobsize = (counterbeforejob - lastpagecounter)   
211            if jobsize < 0 :
212                # Probably an HP printer which was switched off and back on,
213                # its primary counter is only saved in a 10 increment, so
214                # it may be lower than the last page counter saved in the
215                # Quota Storage, we take the absolute value of the difference
216                # this should take care of the "missing" pages.
217                # explanation at : http://web.mit.edu/source/third/lprng/doc/LPRng-HOWTO-15.html
218                kotafilter.logger.log_message(_("Error in page count value %i for user %s on printer %s") % (jobsize, lastusername, kotafilter.printername), "error")
219                jobsize = abs(jobsize)
220               
221            # update the quota for the previous user on this printer
222            kotafilter.storage.updateUserPQuota(lastuserid, printerid, jobsize)
223           
224            # update the last job size in the history
225            kotafilter.storage.updateJobSizeInHistory(lasthistoryid, jobsize)
226           
227            # warns the last user if he is over quota
228            kotafilter.warnUserPQuota(lastusername)
229               
230            # Is the current user allowed to print at all ?
231            action = kotafilter.warnUserPQuota(username)
232           
233            # adds the current job to history   
234            kotafilter.storage.addJobToHistory(jobid, kotafilter.storage.getUserId(username), printerid, counterbeforejob, action)
235           
236            # if not allowed to print then die, else proceed.
237            if action == "DENY" :
238                # No, just die cleanly
239                return 1
240       
241    # pass the job untouched to the underlying layer
242    kotafilter.filterInput(inputfile)     
243   
244    return 0
245
246if __name__ == "__main__" :   
247    sys.exit(main() or 0)
Note: See TracBrowser for help on using the browser.