root / pykota / trunk / bin / pykota @ 1080

Revision 1080, 11.1 kB (checked in by jalet, 21 years ago)

Incorrect documentation string

  • 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 and LPRng
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.36  2003/07/10 06:09:52  jalet
26# Incorrect documentation string
27#
28# Revision 1.35  2003/06/25 14:10:01  jalet
29# Hey, it may work (edpykota --reset excepted) !
30#
31# Revision 1.34  2003/06/13 18:54:17  jalet
32# Bug with remote jobs and LPRng fixed.
33#
34# Revision 1.33  2003/05/28 13:51:38  jalet
35# Better handling of errors
36#
37# Revision 1.32  2003/05/27 23:00:20  jalet
38# Big rewrite of external accounting methods.
39# Should work well now.
40#
41# Revision 1.31  2003/04/30 13:36:39  jalet
42# Stupid accounting method was added.
43#
44# Revision 1.30  2003/04/29 22:03:38  jalet
45# Better error handling.
46#
47# Revision 1.29  2003/04/29 18:37:54  jalet
48# Pluggable accounting methods (actually doesn't support external scripts)
49#
50# Revision 1.28  2003/04/26 08:41:24  jalet
51# Small code reorganisation (UNTESTED) to allow pluggable accounting
52# methods in the future.
53#
54# Revision 1.27  2003/04/25 09:23:47  jalet
55# Debug message passed through !
56#
57# Revision 1.26  2003/04/25 08:23:23  jalet
58# Multiple tries to get the printer's internal page counter, waits for
59# one minute maximum for the printer to warm up, actually.
60#
61# Revision 1.25  2003/04/24 11:53:48  jalet
62# Default policy for unknown users/groups is to DENY printing instead
63# of the previous default to ALLOW printing. This is to solve an accuracy
64# problem. If you set the policy to ALLOW, jobs printed by in nexistant user
65# (from PyKota's POV) will be charged to the next user who prints on the
66# same printer.
67#
68# Revision 1.24  2003/04/23 22:13:56  jalet
69# Preliminary support for LPRng added BUT STILL UNTESTED.
70#
71# Revision 1.23  2003/04/15 11:30:57  jalet
72# More work done on money print charging.
73# Minor bugs corrected.
74# All tools now access to the storage as priviledged users, repykota excepted.
75#
76# Revision 1.22  2003/04/15 11:09:04  jalet
77# Small bug was fixed when a printer was never used and its internal
78# page counter is not accessible.
79#
80# Revision 1.21  2003/04/12 17:20:14  jalet
81# Better formula for HP workaround
82#
83# Revision 1.20  2003/04/12 16:58:28  jalet
84# The workaround for HP printers was not correct, and there's probably no
85# correct way to workaround the problem because we can't save the internal
86# page counter in real time. The last job's size is unconditionnally set to
87# 5 pages in this case.
88#
89# Revision 1.19  2003/04/11 08:56:49  jalet
90# Comment
91#
92# Revision 1.18  2003/04/11 08:50:39  jalet
93# Workaround for the HP "feature" of saving the page counter to NVRAM
94# only every time 10 new pages are printed...
95# Workaround for printers with volatile page counters.
96#
97# Revision 1.17  2003/04/10 21:47:20  jalet
98# Job history added. Upgrade script neutralized for now !
99#
100# Revision 1.16  2003/04/08 20:38:08  jalet
101# The last job Id is saved now for each printer, this will probably
102# allow other accounting methods in the future.
103#
104# Revision 1.15  2003/03/29 13:45:27  jalet
105# GPL paragraphs were incorrectly (from memory) copied into the sources.
106# Two README files were added.
107# Upgrade script for PostgreSQL pre 1.01 schema was added.
108#
109# Revision 1.14  2003/03/07 22:16:57  jalet
110# Algorithmically incorrect : last user quota wasn't updated if current
111# user wasn't allowed to print.
112#
113# Revision 1.13  2003/02/27 23:59:28  jalet
114# Stupid bug wrt exception handlingand value conversion
115#
116# Revision 1.12  2003/02/27 23:48:41  jalet
117# Correctly maps PyKota's log levels to syslog log levels
118#
119# Revision 1.11  2003/02/27 22:55:20  jalet
120# WARN log priority doesn't exist.
121#
122# Revision 1.10  2003/02/27 22:43:21  jalet
123# Missing import
124#
125# Revision 1.9  2003/02/27 22:40:26  jalet
126# Correctly handles cases where the printer is off.
127#
128# Revision 1.8  2003/02/09 12:56:53  jalet
129# Internationalization begins...
130#
131# Revision 1.7  2003/02/07 10:23:48  jalet
132# Avoid a possible future name clash
133#
134# Revision 1.6  2003/02/06 22:54:33  jalet
135# warnpykota should be ok
136#
137# Revision 1.5  2003/02/05 22:45:25  jalet
138# Forgotten import
139#
140# Revision 1.4  2003/02/05 22:42:51  jalet
141# Typo
142#
143# Revision 1.3  2003/02/05 22:38:39  jalet
144# Typo
145#
146# Revision 1.2  2003/02/05 22:16:20  jalet
147# DEVICE_URI is undefined outside of CUPS, i.e. for normal command line tools
148#
149# Revision 1.1  2003/02/05 21:28:17  jalet
150# Initial import into CVS
151#
152#
153#
154
155import sys
156import os
157import time
158
159from pykota.tool import PyKotaTool, PyKotaToolError
160from pykota.config import PyKotaConfigError
161from pykota.storage import PyKotaStorageError
162from pykota.accounter import openAccounter, PyKotaAccounterError
163
164class PyKotaFilter(PyKotaTool) :   
165    """Class for the PyKota filter."""
166    def __init__(self) :
167        PyKotaTool.__init__(self)
168        (self.printingsystem, self.printerhostname, self.printername, self.username, self.jobid, self.inputfile, self.copies) = self.extractInfoFromCupsOrLprng()
169        self.accounter = openAccounter(self)
170   
171    def extractInfoFromCupsOrLprng(self) :   
172        """Returns a tuple (printingsystem, printerhostname, printername, username, jobid, filename) depending on the printing system in use (as seen by the print filter).
173       
174           Returns (None, None, None, None, None, None, None) if no printing system is recognized.
175        """
176        # Try to detect CUPS
177        if os.environ.has_key("CUPS_SERVERROOT") and os.path.isdir(os.environ.get("CUPS_SERVERROOT", "")) :
178            if len(sys.argv) == 7 :
179                inputfile = sys.argv[6]
180            else :   
181                inputfile = None
182               
183            device_uri = os.environ.get("DEVICE_URI", "")
184            # TODO : check this for more complex urls than ipp://myprinter.dot.com:631/printers/lp
185            try :
186                (backend, destination) = device_uri.split(":", 1) 
187            except ValueError :   
188                raise PyKotaToolError, "Invalid DEVICE_URI : %s\n" % device_uri
189            while destination.startswith("/") :
190                destination = destination[1:]
191            printerhostname = destination.split("/")[0].split(":")[0]
192            return ("CUPS", printerhostname, os.environ.get("PRINTER"), sys.argv[2].strip(), sys.argv[1].strip(), inputfile, int(sys.argv[4].strip()))
193        else :   
194            # Try to detect LPRng
195            jseen = Pseen = nseen = rseen = Kseen = None
196            for arg in sys.argv :
197                if arg.startswith("-j") :
198                    jseen = arg[2:].strip()
199                elif arg.startswith("-n") :     
200                    nseen = arg[2:].strip()
201                elif arg.startswith("-P") :   
202                    Pseen = arg[2:].strip()
203                elif arg.startswith("-r") :   
204                    rseen = arg[2:].strip()
205                elif arg.startswith("-K") or arg.startswith("-#") :   
206                    Kseen = int(arg[2:].strip())
207            if Kseen is None :       
208                Kseen = 1       # we assume the user wants at least one copy...
209            if jseen and Pseen and nseen and rseen :       
210                # job is always in stdin (None)
211                return ("LPRNG", rseen, Pseen, nseen, jseen, None, Kseen)
212        return (None, None, None, None, None, None, None)   # Unknown printing system         
213       
214    def acceptJob(self) :       
215        """Returns the exit code needed by the printing backend to accept the job and print it."""
216        if self.printingsystem == "CUPS" :
217            return 0
218        elif self.printingsystem == "LPRNG" :   
219            return 0
220        else :   
221            # UNKNOWN
222            return -1
223           
224    def removeJob(self) :           
225        """Returns the exit code needed by the printing backend to refuse the job and remove it."""
226        if self.printingsystem == "CUPS" :
227            return 1
228        elif self.printingsystem == "LPRNG" :   
229            return 3
230        else :   
231            # UNKNOWN
232            return -1
233           
234def main() :   
235    """Do it, and do it right !"""
236    # Initializes the current tool
237    kotafilter = PyKotaFilter()   
238   
239    #
240    # If this is a CUPS filter, we should act and die like a CUPS filter when needed
241    if kotafilter.printingsystem == "CUPS" :
242        if len(sys.argv) not in (6, 7) :   
243            sys.stderr.write("ERROR: %s job-id user title copies options [file]\n" % sys.argv[0])
244            return kotafilter.removeJob()
245   
246    # Get the last page counter and last username from the Quota Storage backend
247    printer = kotafilter.storage.getPrinter(kotafilter.printername)
248    if not printer.Exists :
249        # The printer is unknown from the Quota Storage perspective
250        # we let the job pass through, but log a warning message
251        kotafilter.logger.log_message(_("Printer %s not registered in the PyKota system") % kotafilter.printername, "warn")
252    else :   
253        user = kotafilter.storage.getUser(kotafilter.username)
254        if not user.Exists :
255            # The user is unknown from the Quota Storage perspective
256            # Depending on the default policy for this printer, we
257            # either let the job pass through or reject it, but we
258            # log a message in any case.
259            policy = kotafilter.config.getPrinterPolicy(kotafilter.printername)
260            if policy == "ALLOW" :
261                action = "POLICY_ALLOW"
262            else :   
263                action = "POLICY_DENY"
264            kotafilter.logger.log_message(_("User %s not registered in the PyKota system, applying default policy (%s) for printer %s") % (kotafilter.username, action, kotafilter.printername), "warn")
265            if action == "POLICY_DENY" :
266                return kotafilter.removeJob()
267        else :
268            # Now does the accounting and act depending on the result
269            action = kotafilter.accounter.doAccounting(printer, user)
270           
271            # if not allowed to print then die, else proceed.
272            if action == "DENY" :
273                # No, just die cleanly
274                return kotafilter.removeJob()
275       
276    # pass the job untouched to the underlying layer
277    kotafilter.accounter.filterInput(kotafilter.inputfile)     
278   
279    return kotafilter.acceptJob()
280
281if __name__ == "__main__" :   
282    retcode = -1
283    try :
284        retcode = main()
285    except (PyKotaToolError, PyKotaConfigError, PyKotaStorageError, PyKotaAccounterError, AttributeError, KeyError, IndexError, ValueError, IOError), msg :
286        sys.stderr.write("ERROR : PyKota filter failed (%s)\n" % msg)
287        sys.stderr.flush()
288    sys.exit(retcode)   
289   
Note: See TracBrowser for help on using the browser.