root / pykota / trunk / bin / pykota @ 1240

Revision 1240, 11.9 kB (checked in by uid67467, 20 years ago)

Should be ok now.

  • 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#
8# (c) 2003 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$
[1240]26# Revision 1.48  2003/12/27 16:49:25  uid67467
27# Should be ok now.
28#
[1221]29# Revision 1.47  2003/11/26 19:17:35  jalet
30# Printing on a printer not present in the Quota Storage now results
31# in the job being stopped or cancelled depending on the system.
32#
[1205]33# Revision 1.46  2003/11/24 14:25:02  jalet
34# Missing import in pykota filter
35#
[1196]36# Revision 1.45  2003/11/19 23:19:37  jalet
37# Code refactoring work.
38# Explicit redirection to /dev/null has to be set in external policy now, just
39# like in external mailto.
40#
[1177]41# Revision 1.44  2003/11/08 16:05:31  jalet
42# CUPS backend added for people to experiment.
43#
[1176]44# Revision 1.43  2003/11/06 22:33:25  jalet
45# French variable name
46#
[1152]47# Revision 1.42  2003/10/08 21:41:38  jalet
48# External policies for printers works !
49# We can now auto-add users on first print, and do other useful things if needed.
50#
[1144]51# Revision 1.41  2003/10/07 09:07:27  jalet
52# Character encoding added to please latest version of Python
53#
[1124]54# Revision 1.40  2003/09/04 08:38:56  jalet
55# Added an exception catch to ensure clean close of database even in
56# case of TypeError too.
57#
[1117]58# Revision 1.39  2003/08/18 16:35:28  jalet
59# New pychecker pass, on the tools this time.
60#
[1116]61# Revision 1.38  2003/08/18 16:20:59  jalet
62# Improvement of the printing system detection code.
63#
[1113]64# Revision 1.37  2003/07/29 20:55:17  jalet
65# 1.14 is out !
66#
[1080]67# Revision 1.36  2003/07/10 06:09:52  jalet
68# Incorrect documentation string
69#
[1041]70# Revision 1.35  2003/06/25 14:10:01  jalet
71# Hey, it may work (edpykota --reset excepted) !
72#
[1026]73# Revision 1.34  2003/06/13 18:54:17  jalet
74# Bug with remote jobs and LPRng fixed.
75#
[1004]76# Revision 1.33  2003/05/28 13:51:38  jalet
77# Better handling of errors
78#
[1000]79# Revision 1.32  2003/05/27 23:00:20  jalet
80# Big rewrite of external accounting methods.
81# Should work well now.
82#
[976]83# Revision 1.31  2003/04/30 13:36:39  jalet
84# Stupid accounting method was added.
85#
[975]86# Revision 1.30  2003/04/29 22:03:38  jalet
87# Better error handling.
88#
[973]89# Revision 1.29  2003/04/29 18:37:54  jalet
90# Pluggable accounting methods (actually doesn't support external scripts)
91#
[966]92# Revision 1.28  2003/04/26 08:41:24  jalet
93# Small code reorganisation (UNTESTED) to allow pluggable accounting
94# methods in the future.
95#
[963]96# Revision 1.27  2003/04/25 09:23:47  jalet
97# Debug message passed through !
98#
[962]99# Revision 1.26  2003/04/25 08:23:23  jalet
100# Multiple tries to get the printer's internal page counter, waits for
101# one minute maximum for the printer to warm up, actually.
102#
[956]103# Revision 1.25  2003/04/24 11:53:48  jalet
104# Default policy for unknown users/groups is to DENY printing instead
105# of the previous default to ALLOW printing. This is to solve an accuracy
106# problem. If you set the policy to ALLOW, jobs printed by in nexistant user
107# (from PyKota's POV) will be charged to the next user who prints on the
108# same printer.
109#
[952]110# Revision 1.24  2003/04/23 22:13:56  jalet
111# Preliminary support for LPRng added BUT STILL UNTESTED.
112#
[915]113# Revision 1.23  2003/04/15 11:30:57  jalet
114# More work done on money print charging.
115# Minor bugs corrected.
116# All tools now access to the storage as priviledged users, repykota excepted.
117#
[914]118# Revision 1.22  2003/04/15 11:09:04  jalet
119# Small bug was fixed when a printer was never used and its internal
120# page counter is not accessible.
121#
[909]122# Revision 1.21  2003/04/12 17:20:14  jalet
123# Better formula for HP workaround
124#
[908]125# Revision 1.20  2003/04/12 16:58:28  jalet
126# The workaround for HP printers was not correct, and there's probably no
127# correct way to workaround the problem because we can't save the internal
128# page counter in real time. The last job's size is unconditionnally set to
129# 5 pages in this case.
130#
[902]131# Revision 1.19  2003/04/11 08:56:49  jalet
132# Comment
133#
[901]134# Revision 1.18  2003/04/11 08:50:39  jalet
135# Workaround for the HP "feature" of saving the page counter to NVRAM
136# only every time 10 new pages are printed...
137# Workaround for printers with volatile page counters.
138#
[900]139# Revision 1.17  2003/04/10 21:47:20  jalet
140# Job history added. Upgrade script neutralized for now !
141#
[887]142# Revision 1.16  2003/04/08 20:38:08  jalet
143# The last job Id is saved now for each printer, this will probably
144# allow other accounting methods in the future.
145#
[873]146# Revision 1.15  2003/03/29 13:45:27  jalet
147# GPL paragraphs were incorrectly (from memory) copied into the sources.
148# Two README files were added.
149# Upgrade script for PostgreSQL pre 1.01 schema was added.
150#
[832]151# Revision 1.14  2003/03/07 22:16:57  jalet
152# Algorithmically incorrect : last user quota wasn't updated if current
153# user wasn't allowed to print.
154#
[826]155# Revision 1.13  2003/02/27 23:59:28  jalet
156# Stupid bug wrt exception handlingand value conversion
157#
[825]158# Revision 1.12  2003/02/27 23:48:41  jalet
159# Correctly maps PyKota's log levels to syslog log levels
160#
[824]161# Revision 1.11  2003/02/27 22:55:20  jalet
162# WARN log priority doesn't exist.
163#
[823]164# Revision 1.10  2003/02/27 22:43:21  jalet
165# Missing import
166#
[822]167# Revision 1.9  2003/02/27 22:40:26  jalet
168# Correctly handles cases where the printer is off.
169#
[772]170# Revision 1.8  2003/02/09 12:56:53  jalet
171# Internationalization begins...
172#
[740]173# Revision 1.7  2003/02/07 10:23:48  jalet
174# Avoid a possible future name clash
175#
[728]176# Revision 1.6  2003/02/06 22:54:33  jalet
177# warnpykota should be ok
178#
[704]179# Revision 1.5  2003/02/05 22:45:25  jalet
180# Forgotten import
181#
[703]182# Revision 1.4  2003/02/05 22:42:51  jalet
183# Typo
184#
[701]185# Revision 1.3  2003/02/05 22:38:39  jalet
186# Typo
187#
[699]188# Revision 1.2  2003/02/05 22:16:20  jalet
189# DEVICE_URI is undefined outside of CUPS, i.e. for normal command line tools
190#
[695]191# Revision 1.1  2003/02/05 21:28:17  jalet
192# Initial import into CVS
193#
194#
195#
196
197import sys
[704]198import os
[695]199
[1205]200from pykota.tool import PyKotaFilterOrBackend, PyKotaToolError
[975]201from pykota.config import PyKotaConfigError
[973]202from pykota.storage import PyKotaStorageError
[1196]203from pykota.accounter import PyKotaAccounterError
204from pykota.requester import PyKotaRequesterError
[695]205
[1196]206class PyKotaFilter(PyKotaFilterOrBackend) :       
207    """A class for the pykota filter."""
[952]208    def acceptJob(self) :       
209        """Returns the exit code needed by the printing backend to accept the job and print it."""
210        if self.printingsystem == "CUPS" :
211            return 0
212        elif self.printingsystem == "LPRNG" :   
213            return 0
214        else :   
215            # UNKNOWN
216            return -1
217           
218    def removeJob(self) :           
219        """Returns the exit code needed by the printing backend to refuse the job and remove it."""
220        if self.printingsystem == "CUPS" :
221            return 1
222        elif self.printingsystem == "LPRNG" :   
223            return 3
224        else :   
225            # UNKNOWN
226            return -1
227           
[1113]228def main(thefilter) :   
[695]229    """Do it, and do it right !"""
[952]230    #
231    # If this is a CUPS filter, we should act and die like a CUPS filter when needed
[1113]232    if thefilter.printingsystem == "CUPS" :
[952]233        if len(sys.argv) not in (6, 7) :   
234            sys.stderr.write("ERROR: %s job-id user title copies options [file]\n" % sys.argv[0])
[1113]235            return thefilter.removeJob()
[695]236   
237    # Get the last page counter and last username from the Quota Storage backend
[1113]238    printer = thefilter.storage.getPrinter(thefilter.printername)
[1041]239    if not printer.Exists :
[1221]240        # The printer is unknown from the Quota Storage perspective.
241        # we just cancel the job.
242        thefilter.logger.log_message(_("Printer %s not registered in the PyKota system") % thefilter.printername, "error")
243        return thefilter.removeJob()
[695]244    else :   
[1176]245        for dummy in range(2) :
[1152]246            user = thefilter.storage.getUser(thefilter.username)
247            if user.Exists :
248                break
[952]249            else :   
[1152]250                # The user is unknown from the Quota Storage perspective
251                # Depending on the default policy for this printer, we
252                # either let the job pass through or reject it, but we
253                # log a message in any case.
254                (policy, args) = thefilter.config.getPrinterPolicy(thefilter.printername)
255                if policy == "ALLOW" :
256                    action = "POLICY_ALLOW"
257                elif policy == "EXTERNAL" :   
[1196]258                    commandline = thefilter.formatCommandLine(args, user, printer)
[1152]259                    thefilter.logger.log_message(_("User %s not registered in the PyKota system, applying external policy (%s) for printer %s") % (thefilter.username, commandline, thefilter.printername), "info")
260                    if os.system(commandline) :
261                        thefilter.logger.log_message(_("External policy %s for printer %s produced an error. Job rejected. Please check PyKota's configuration files.") % (commandline, thefilter.printername), "error")
262                        return thefilter.removeJob()
263                    else :   
264                        # here we try a second time, because the goal
265                        # of the external action was to add the user
266                        # in the database.
267                        continue 
268                else :   
269                    action = "POLICY_DENY"
270                thefilter.logger.log_message(_("User %s not registered in the PyKota system, applying default policy (%s) for printer %s") % (thefilter.username, action, thefilter.printername), "warn")
271                if action == "POLICY_DENY" :
272                    return thefilter.removeJob()
273                # when we get there, the printer policy allows the job to pass
274                break   
275                   
276        # if user exists, do accounting
277        if user.Exists :
[973]278            # Now does the accounting and act depending on the result
[1240]279            thefilter.logdebug("Does accounting for user %s on printer %s." % (user.Name, printer.Name))
[1113]280            action = thefilter.accounter.doAccounting(printer, user)
[1152]281       
[900]282            # if not allowed to print then die, else proceed.
283            if action == "DENY" :
284                # No, just die cleanly
[1240]285                thefilter.logdebug("Printing is denied.")
[1113]286                return thefilter.removeJob()
[1152]287        elif policy == "EXTERNAL" :               
288            thefilter.logger.log_message(_("External policy %s for printer %s couldn't add user %s. Job rejected.") % (commandline, thefilter.printername, thefilter.username), "error")
289            return thefilter.removeJob()
[695]290       
[1221]291        # pass the job untouched to the underlying layer
[1240]292        thefilter.logdebug("Passing input data to next filter.")
[1221]293        thefilter.accounter.filterInput(thefilter.inputfile)     
[695]294   
[1221]295        return thefilter.acceptJob()
[695]296
297if __name__ == "__main__" :   
[1004]298    retcode = -1
[973]299    try :
[1113]300        # Initializes the current tool
301        kotafilter = PyKotaFilter()   
302        retcode = main(kotafilter)
[1196]303    except (PyKotaToolError, PyKotaConfigError, PyKotaStorageError, PyKotaAccounterError, PyKotaRequesterError, AttributeError, KeyError, IndexError, ValueError, TypeError, IOError), msg :
[973]304        sys.stderr.write("ERROR : PyKota filter failed (%s)\n" % msg)
305        sys.stderr.flush()
[1177]306        try :
307            retcode = kotafilter.removeJob()
308        except :
309            retcode = -1
[1113]310
311    try :
312        kotafilter.storage.close()
313    except (TypeError, NameError, AttributeError) :   
314        pass
315       
[973]316    sys.exit(retcode)   
Note: See TracBrowser for help on using the browser.