root / pykota / trunk / bin / pykota @ 887

Revision 887, 7.3 kB (checked in by jalet, 21 years ago)

The last job Id is saved now for each printer, this will probably
allow other accounting methods in the future.

  • 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.16  2003/04/08 20:38:08  jalet
26# The last job Id is saved now for each printer, this will probably
27# allow other accounting methods in the future.
28#
29# Revision 1.15  2003/03/29 13:45:27  jalet
30# GPL paragraphs were incorrectly (from memory) copied into the sources.
31# Two README files were added.
32# Upgrade script for PostgreSQL pre 1.01 schema was added.
33#
34# Revision 1.14  2003/03/07 22:16:57  jalet
35# Algorithmically incorrect : last user quota wasn't updated if current
36# user wasn't allowed to print.
37#
38# Revision 1.13  2003/02/27 23:59:28  jalet
39# Stupid bug wrt exception handlingand value conversion
40#
41# Revision 1.12  2003/02/27 23:48:41  jalet
42# Correctly maps PyKota's log levels to syslog log levels
43#
44# Revision 1.11  2003/02/27 22:55:20  jalet
45# WARN log priority doesn't exist.
46#
47# Revision 1.10  2003/02/27 22:43:21  jalet
48# Missing import
49#
50# Revision 1.9  2003/02/27 22:40:26  jalet
51# Correctly handles cases where the printer is off.
52#
53# Revision 1.8  2003/02/09 12:56:53  jalet
54# Internationalization begins...
55#
56# Revision 1.7  2003/02/07 10:23:48  jalet
57# Avoid a possible future name clash
58#
59# Revision 1.6  2003/02/06 22:54:33  jalet
60# warnpykota should be ok
61#
62# Revision 1.5  2003/02/05 22:45:25  jalet
63# Forgotten import
64#
65# Revision 1.4  2003/02/05 22:42:51  jalet
66# Typo
67#
68# Revision 1.3  2003/02/05 22:38:39  jalet
69# Typo
70#
71# Revision 1.2  2003/02/05 22:16:20  jalet
72# DEVICE_URI is undefined outside of CUPS, i.e. for normal command line tools
73#
74# Revision 1.1  2003/02/05 21:28:17  jalet
75# Initial import into CVS
76#
77#
78#
79
80import sys
81import os
82
83from pykota.tool import PyKotaTool, PyKotaToolError
84from pykota.requester import openRequester, PyKotaRequesterError
85
86class PyKotaFilter(PyKotaTool) :   
87    """Class for the PyKota filter."""
88    def __init__(self, username) :
89        PyKotaTool.__init__(self, isfilter=1)
90        self.username = username
91        self.requester = openRequester(self.config, self.printername)
92        self.printerhostname = self.getPrinterHostname()
93   
94    def getPrinterHostname(self) :
95        """Returns the printer hostname."""
96        device_uri = os.environ.get("DEVICE_URI", "")
97        # TODO : check this for more complex urls than ipp://myprinter.dot.com:631/printers/lp
98        try :
99            (backend, destination) = device_uri.split(":", 1) 
100        except ValueError :   
101            raise PyKotaToolError, "Invalid DEVICE_URI : %s\n" % device_uri
102        while destination.startswith("/") :
103            destination = destination[1:]
104        return destination.split("/")[0].split(":")[0]
105       
106    def filterInput(self, inputfile) :
107        """Transparent filter."""
108        mustclose = 0   
109        if inputfile is not None :   
110            infile = open(inputfile, "rb")
111            mustclose = 1
112        else :   
113            infile = sys.stdin
114        data = infile.read(256*1024)   
115        while data :
116            sys.stdout.write(data)
117            data = infile.read(256*1024)
118        if mustclose :   
119            infile.close()
120           
121def main() :   
122    """Do it, and do it right !"""
123    #
124    # This is a CUPS filter, so we should act and die like a CUPS filter when needed
125    narg = len(sys.argv)
126    if narg not in (6, 7) :   
127        sys.stderr.write("ERROR: %s job-id user title copies options [file]\n" % sys.argv[0])
128        return 1
129    elif narg == 7 :   
130        # input file
131        inputfile = sys.argv[6]
132    else :   
133        # stdin
134        inputfile = None
135       
136    #   
137    # According to CUPS documentation, the job id is the second command line argument
138    jobid = sys.argv[1].strip()
139   
140    #   
141    # According to CUPS documentation, the username is the third command line argument
142    username = sys.argv[2].strip()   
143   
144    # Initializes the current tool
145    kotafilter = PyKotaFilter(username)   
146   
147    # Get the page counter directly from the printer itself
148    try :
149        counterbeforejob = kotafilter.requester.getPrinterPageCounter(kotafilter.printerhostname) # TODO use printername instead, make them match from CUPS' config files
150    except PyKotaRequesterError, msg :
151        # can't get actual page counter, assume printer is off, but warns in log
152        kotafilter.logger.log_message("%s" % msg, "warn")
153        printerIsOff = 1
154    else :   
155        printerIsOff = 0
156       
157    # Get the last page counter and last username from the Quota Storage backend
158    pgc = kotafilter.storage.getPrinterPageCounter(kotafilter.printername)   
159    if pgc is None :
160        # The printer is unknown from the Quota Storage perspective
161        # we let the job pass through, but log a warning message
162        kotafilter.logger.log_message(_("Printer %s not registered in the PyKota system") % kotafilter.printername, "warn")
163    else :   
164        # get last values from Quota Storage
165        (lastpagecounter, lastjobid, lastusername) = (pgc["pagecounter"], pgc["lastjobid"], pgc["lastusername"])
166       
167        # if printer is off then we assume the correct counter value is the last one
168        if printerIsOff :
169            counterbeforejob = lastpagecounter
170           
171        # Update the last page counter and last username in the Quota Storage backend
172        # set them to current user and
173        kotafilter.storage.updatePrinterPageCounter(kotafilter.printername, username, counterbeforejob, jobid)
174       
175        # Was the printer ever used ?
176        if (lastpagecounter is None) or (lastusername is None) :
177            lastusername = username
178            lastpagecounter = counterbeforejob
179           
180        # Update the quota for the previous user on this printer according
181        # to the job size (difference between actual counter and latest one from storage)
182        jobsize = (counterbeforejob - lastpagecounter)   
183        if jobsize >= 0 :
184            kotafilter.storage.updateUserPQuota(lastusername, kotafilter.printername, jobsize)
185            kotafilter.warnUserPQuota(lastusername)
186        else :   
187            kotafilter.logger.log_message(_("Error in page count value %i for user %s on printer %s") % (jobsize, kotafilter.printername, lastusername), "error")
188           
189        # Is the current user allowed to print at all ?
190        # if no then die, else proceed.
191        action = kotafilter.warnUserPQuota(username)
192        if action == "DENY" :
193            # No, just die cleanly
194            return 1
195       
196    # pass the job untouched to the underlying layer
197    kotafilter.filterInput(inputfile)     
198   
199    return 0
200
201if __name__ == "__main__" :   
202    sys.exit(main() or 0)
Note: See TracBrowser for help on using the browser.