root / pykota / trunk / bin / pykota @ 1490

Revision 1490, 14.5 kB (checked in by jalet, 20 years ago)

The pykota filter is now deprecated

  • Property svn:eol-style set to native
  • Property svn:executable set to *
  • Property svn:keywords set to Author Date Id Revision
RevLine 
[695]1#! /usr/bin/env python
[1144]2# -*- coding: ISO-8859-15 -*-
[695]3
4# PyKota accounting filter
5#
[952]6# PyKota - Print Quotas for CUPS and LPRng
[695]7#
[1257]8# (c) 2003-2004 Jerome Alet <alet@librelogiciel.com>
[873]9# This program is free software; you can redistribute it and/or modify
10# it under the terms of the GNU General Public License as published by
11# the Free Software Foundation; either version 2 of the License, or
12# (at your option) any later version.
[695]13#
[873]14# This program is distributed in the hope that it will be useful,
15# but WITHOUT ANY WARRANTY; without even the implied warranty of
16# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17# GNU General Public License for more details.
18#
19# You should have received a copy of the GNU General Public License
20# along with this program; if not, write to the Free Software
21# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
[695]22#
23# $Id$
24#
25# $Log$
[1490]26# Revision 1.59  2004/05/21 21:02:56  jalet
27# The pykota filter is now deprecated
28#
[1483]29# Revision 1.58  2004/05/18 14:48:47  jalet
30# Big code changes to completely remove the need for "requester" directives,
31# jsut use "hardware(... your previous requester directive's content ...)"
32#
[1400]33# Revision 1.57  2004/03/15 10:47:56  jalet
34# This time the traceback formatting should be correct !
35#
[1391]36# Revision 1.56  2004/03/05 12:46:08  jalet
37# Improve tracebacks
38#
[1390]39# Revision 1.55  2004/03/05 12:31:35  jalet
40# Now should output full traceback when crashing
41#
[1376]42# Revision 1.54  2004/03/01 15:06:51  jalet
43# Pre and Post hooks should now work in the pykota filter too.
44# The pykota filter doesn't check the last user's quota anymore
45# when delayed hardware accounting is used : this will be checked
46# anyway the next time the last user will print
47#
[1359]48# Revision 1.53  2004/02/25 12:36:34  jalet
49# Avoids a database query even if caching was disabled.
50#
[1292]51# Revision 1.52  2004/01/14 15:57:54  jalet
52# Missing return caused problems with LPRng
53#
[1281]54# Revision 1.51  2004/01/12 18:20:45  jalet
55# Denied jobs weren't added to the history anymore, this is now fixed.
56#
[1271]57# Revision 1.50  2004/01/11 23:22:42  jalet
58# Major code refactoring, it's way cleaner, and now allows automated addition
59# of printers on first print.
60#
[1257]61# Revision 1.49  2004/01/08 14:10:32  jalet
62# Copyright year changed.
63#
[1240]64# Revision 1.48  2003/12/27 16:49:25  uid67467
65# Should be ok now.
66#
[1221]67# Revision 1.47  2003/11/26 19:17:35  jalet
68# Printing on a printer not present in the Quota Storage now results
69# in the job being stopped or cancelled depending on the system.
70#
[1205]71# Revision 1.46  2003/11/24 14:25:02  jalet
72# Missing import in pykota filter
73#
[1196]74# Revision 1.45  2003/11/19 23:19:37  jalet
75# Code refactoring work.
76# Explicit redirection to /dev/null has to be set in external policy now, just
77# like in external mailto.
78#
[1177]79# Revision 1.44  2003/11/08 16:05:31  jalet
80# CUPS backend added for people to experiment.
81#
[1176]82# Revision 1.43  2003/11/06 22:33:25  jalet
83# French variable name
84#
[1152]85# Revision 1.42  2003/10/08 21:41:38  jalet
86# External policies for printers works !
87# We can now auto-add users on first print, and do other useful things if needed.
88#
[1144]89# Revision 1.41  2003/10/07 09:07:27  jalet
90# Character encoding added to please latest version of Python
91#
[1124]92# Revision 1.40  2003/09/04 08:38:56  jalet
93# Added an exception catch to ensure clean close of database even in
94# case of TypeError too.
95#
[1117]96# Revision 1.39  2003/08/18 16:35:28  jalet
97# New pychecker pass, on the tools this time.
98#
[1116]99# Revision 1.38  2003/08/18 16:20:59  jalet
100# Improvement of the printing system detection code.
101#
[1113]102# Revision 1.37  2003/07/29 20:55:17  jalet
103# 1.14 is out !
104#
[1080]105# Revision 1.36  2003/07/10 06:09:52  jalet
106# Incorrect documentation string
107#
[1041]108# Revision 1.35  2003/06/25 14:10:01  jalet
109# Hey, it may work (edpykota --reset excepted) !
110#
[1026]111# Revision 1.34  2003/06/13 18:54:17  jalet
112# Bug with remote jobs and LPRng fixed.
113#
[1004]114# Revision 1.33  2003/05/28 13:51:38  jalet
115# Better handling of errors
116#
[1000]117# Revision 1.32  2003/05/27 23:00:20  jalet
118# Big rewrite of external accounting methods.
119# Should work well now.
120#
[976]121# Revision 1.31  2003/04/30 13:36:39  jalet
122# Stupid accounting method was added.
123#
[975]124# Revision 1.30  2003/04/29 22:03:38  jalet
125# Better error handling.
126#
[973]127# Revision 1.29  2003/04/29 18:37:54  jalet
128# Pluggable accounting methods (actually doesn't support external scripts)
129#
[966]130# Revision 1.28  2003/04/26 08:41:24  jalet
131# Small code reorganisation (UNTESTED) to allow pluggable accounting
132# methods in the future.
133#
[963]134# Revision 1.27  2003/04/25 09:23:47  jalet
135# Debug message passed through !
136#
[962]137# Revision 1.26  2003/04/25 08:23:23  jalet
138# Multiple tries to get the printer's internal page counter, waits for
139# one minute maximum for the printer to warm up, actually.
140#
[956]141# Revision 1.25  2003/04/24 11:53:48  jalet
142# Default policy for unknown users/groups is to DENY printing instead
143# of the previous default to ALLOW printing. This is to solve an accuracy
144# problem. If you set the policy to ALLOW, jobs printed by in nexistant user
145# (from PyKota's POV) will be charged to the next user who prints on the
146# same printer.
147#
[952]148# Revision 1.24  2003/04/23 22:13:56  jalet
149# Preliminary support for LPRng added BUT STILL UNTESTED.
150#
[915]151# Revision 1.23  2003/04/15 11:30:57  jalet
152# More work done on money print charging.
153# Minor bugs corrected.
154# All tools now access to the storage as priviledged users, repykota excepted.
155#
[914]156# Revision 1.22  2003/04/15 11:09:04  jalet
157# Small bug was fixed when a printer was never used and its internal
158# page counter is not accessible.
159#
[909]160# Revision 1.21  2003/04/12 17:20:14  jalet
161# Better formula for HP workaround
162#
[908]163# Revision 1.20  2003/04/12 16:58:28  jalet
164# The workaround for HP printers was not correct, and there's probably no
165# correct way to workaround the problem because we can't save the internal
166# page counter in real time. The last job's size is unconditionnally set to
167# 5 pages in this case.
168#
[902]169# Revision 1.19  2003/04/11 08:56:49  jalet
170# Comment
171#
[901]172# Revision 1.18  2003/04/11 08:50:39  jalet
173# Workaround for the HP "feature" of saving the page counter to NVRAM
174# only every time 10 new pages are printed...
175# Workaround for printers with volatile page counters.
176#
[900]177# Revision 1.17  2003/04/10 21:47:20  jalet
178# Job history added. Upgrade script neutralized for now !
179#
[887]180# Revision 1.16  2003/04/08 20:38:08  jalet
181# The last job Id is saved now for each printer, this will probably
182# allow other accounting methods in the future.
183#
[873]184# Revision 1.15  2003/03/29 13:45:27  jalet
185# GPL paragraphs were incorrectly (from memory) copied into the sources.
186# Two README files were added.
187# Upgrade script for PostgreSQL pre 1.01 schema was added.
188#
[832]189# Revision 1.14  2003/03/07 22:16:57  jalet
190# Algorithmically incorrect : last user quota wasn't updated if current
191# user wasn't allowed to print.
192#
[826]193# Revision 1.13  2003/02/27 23:59:28  jalet
194# Stupid bug wrt exception handlingand value conversion
195#
[825]196# Revision 1.12  2003/02/27 23:48:41  jalet
197# Correctly maps PyKota's log levels to syslog log levels
198#
[824]199# Revision 1.11  2003/02/27 22:55:20  jalet
200# WARN log priority doesn't exist.
201#
[823]202# Revision 1.10  2003/02/27 22:43:21  jalet
203# Missing import
204#
[822]205# Revision 1.9  2003/02/27 22:40:26  jalet
206# Correctly handles cases where the printer is off.
207#
[772]208# Revision 1.8  2003/02/09 12:56:53  jalet
209# Internationalization begins...
210#
[740]211# Revision 1.7  2003/02/07 10:23:48  jalet
212# Avoid a possible future name clash
213#
[728]214# Revision 1.6  2003/02/06 22:54:33  jalet
215# warnpykota should be ok
216#
[704]217# Revision 1.5  2003/02/05 22:45:25  jalet
218# Forgotten import
219#
[703]220# Revision 1.4  2003/02/05 22:42:51  jalet
221# Typo
222#
[701]223# Revision 1.3  2003/02/05 22:38:39  jalet
224# Typo
225#
[699]226# Revision 1.2  2003/02/05 22:16:20  jalet
227# DEVICE_URI is undefined outside of CUPS, i.e. for normal command line tools
228#
[695]229# Revision 1.1  2003/02/05 21:28:17  jalet
230# Initial import into CVS
231#
232#
233#
234
235import sys
[704]236import os
[695]237
[1205]238from pykota.tool import PyKotaFilterOrBackend, PyKotaToolError
[975]239from pykota.config import PyKotaConfigError
[973]240from pykota.storage import PyKotaStorageError
[1196]241from pykota.accounter import PyKotaAccounterError
[695]242
[1196]243class PyKotaFilter(PyKotaFilterOrBackend) :       
244    """A class for the pykota filter."""
[952]245    def acceptJob(self) :       
246        """Returns the exit code needed by the printing backend to accept the job and print it."""
247        if self.printingsystem == "CUPS" :
248            return 0
249        elif self.printingsystem == "LPRNG" :   
250            return 0
251        else :   
252            # UNKNOWN
253            return -1
254           
255    def removeJob(self) :           
256        """Returns the exit code needed by the printing backend to refuse the job and remove it."""
257        if self.printingsystem == "CUPS" :
258            return 1
259        elif self.printingsystem == "LPRNG" :   
260            return 3
261        else :   
262            # UNKNOWN
263            return -1
[1271]264       
265    def doWork(self, policy, printer, user, userpquota) :   
266        """Most of the work is done here."""
267        # Two different values possible for policy here :
268        # ALLOW means : Either printer, user or user print quota doesn't exist,
269        #               but the job should be allowed anyway.
270        # OK means : Both printer, user and user print quota exist, job should
271        #            be allowed if current user is allowed to print on this printer
272        if policy == "OK" :
[1376]273            # exports user information with initial values
274            self.exportUserInfo(userpquota)
275           
276            # enters first phase
277            os.putenv("PYKOTAPHASE", "BEFORE")
278           
[1271]279            self.logdebug("Does accounting for user %s on printer %s." % (user.Name, printer.Name))
280            action = self.accounter.doAccounting(userpquota)
[1376]281           
282            # exports some new environment variables
283            os.putenv("PYKOTAACTION", action)
284           
285            # launches the pre hook
286            self.prehook(userpquota)
[1281]287        else :       
288            action = "ALLOW"
[952]289           
[1271]290        # pass the job's data to the next filter
[1281]291        if action in ["ALLOW", "WARN"] :
292            self.logdebug("Passing input data to next filter.")
293            mustclose = 0   
294            if self.inputfile is not None :   
295                if hasattr(self.inputfile, "read") :
296                    infile = self.inputfile
297                else :   
298                    infile = open(self.inputfile, "rb")
299                mustclose = 1
[952]300            else :   
[1281]301                infile = sys.stdin
302            data = infile.read(256*1024)   
303            while data :
304                sys.stdout.write(data)
305                data = infile.read(256*1024)
306            if mustclose :   
307                infile.close()
308            return self.acceptJob()
309        else :
310            self.logdebug("Printing is denied.")
311            return self.removeJob()
[1152]312       
[1271]313    def mainWork(self) :   
314        # If this is a CUPS filter, we should act and die like a CUPS filter when needed
315        if self.printingsystem == "CUPS" :
316            if len(sys.argv) not in (6, 7) :   
317                sys.stderr.write("ERROR: %s job-id user title copies options [file]\n" % sys.argv[0])
318                return self.removeJob()
319               
320        if self.accounter.isDelayed :       
321            # Here we need to update the last user's print quota       
322            # because hardware accounting is delayed by one print job
323            # in the pykota filter.
324            printer = self.storage.getPrinter(self.printername)       
325            if not printer.Exists :
326                self.logger.log_message(_("Printer %s not registered in the PyKota system") % self.printername, "info")
327            else :   
328                if not printer.LastJob.Exists :
329                    self.logger.log_message(_("Printer %s was never used") % self.printername, "info")
330                else :
331                    self.logdebug("Updating print quota for last user %s on printer %s" % (printer.LastJob.User.Name, printer.Name))
332                    lastuserpquota = self.storage.getUserPQuota(printer.LastJob.User, printer)
333                    self.accounter.counterbefore = printer.LastJob.PrinterPageCounter
334                    self.accounter.counterafter = self.accounter.getPrinterInternalPageCounter() or 0
335                    lastjobsize = self.accounter.getJobSize()
336                    self.logdebug("Last Job size : %i" % lastjobsize)
[1376]337                    lastjobprice = printer.LastJob.setSize(lastuserpquota, lastjobsize)
[1271]338                    self.logdebug("Updating user %s's quota on printer %s" % (lastuserpquota.User.Name, printer.Name))
339                    lastuserpquota.increasePagesUsage(lastjobsize)
340                   
[1376]341                    # exports user information with final values
342                    self.exportUserInfo(lastuserpquota)
343                   
344                    # enters final phase
345                    os.putenv("PYKOTAPHASE", "AFTER")
346                    os.putenv("PYKOTAACTION", printer.LastJob.JobAction)
347                    os.putenv("PYKOTAJOBSIZE", str(lastjobsize))
348                    os.putenv("PYKOTAJOBPRICE", str(lastjobprice))
349                   
350                    # launches the post hook
351                    self.posthook(lastuserpquota)
352                   
353                    # Code below deactivated since this will be checked
354                    # anyway the next time this user prints
355                    # finally check last user's quota
356                    # self.warnUserPQuota(lastuserpquota)
357                   
[1271]358        # then deal with current print job as usual           
[1292]359        return PyKotaFilterOrBackend.mainWork(self)       
[1271]360           
[695]361if __name__ == "__main__" :   
[1490]362    sys.stderr.write("ERROR : pykota is now deprecated. With CUPS use cupspykota instead.\n")
363    sys.stderr.write("ERROR : pykota is now deprecated. With LPRng please wait for a new version.\n")
364    sys.stderr.flush()
365    sys.exit(-1)
366   
367    ##############
368    #            #
369    # DEPRECATED #
370    #            #
371    ##############
[1004]372    retcode = -1
[973]373    try :
[1113]374        # Initializes the current tool
375        kotafilter = PyKotaFilter()   
[1271]376        retcode = kotafilter.mainWork()
[1483]377    except (PyKotaToolError, PyKotaConfigError, PyKotaStorageError, PyKotaAccounterError, AttributeError, KeyError, IndexError, ValueError, TypeError, IOError), msg :
[1390]378        import traceback
[1400]379        mm = [((f.endswith('\n') and f) or (f + '\n')) for f in traceback.format_exception(*sys.exc_info())]
380        sys.stderr.write("ERROR : pykota filter failed (%s)\n%s" % (msg, "ERROR : ".join(mm)))
[973]381        sys.stderr.flush()
[1177]382        try :
383            retcode = kotafilter.removeJob()
384        except :
385            retcode = -1
[1113]386
387    try :
388        kotafilter.storage.close()
389    except (TypeError, NameError, AttributeError) :   
390        pass
391       
[973]392    sys.exit(retcode)   
Note: See TracBrowser for help on using the browser.